Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
F# "logic" parser for rigol oscilloscope CSV files, outputs hex values. Interprets analogue data as 3 state (i.e. two data "lines" on a single channel)
open System
open System.IO
open System.Text
open System.Globalization
open System.Text.RegularExpressions
let l1 = 1.0
let l2 = 2.0
let ttlTrue = 2.3
let getLines (fname:string) = seq{
use stream = new StreamReader( fname )
while not stream.EndOfStream do
yield stream.ReadLine()
}
let parseVoltage (s:string) =
try
System.Double.Parse( (s.Replace( ".", "," )), NumberStyles.Float )
with
| e ->
printfn "%s - %s" s (e.ToString())
0.0
let filterOnClockGoingHigh (s:seq<float * int>) = seq {
let e = s.GetEnumerator()
let last = ref 0
while e.MoveNext() do
if !last <> (snd e.Current) then
last := (snd e.Current)
if !last = 1 then
yield e.Current
}
//from http://fssnip.net/6A
let groupWhen f (input:seq<_>) = seq {
use en = input.GetEnumerator()
let running = ref true
// Generate a group starting with the current element. Stops generating
// when it founds element such that 'f en.Current' is 'true'
let rec group() =
[ yield en.Current
if en.MoveNext() then
if not (f en.Current) then yield! group()
else running := false ]
if en.MoveNext() then
// While there are still elements, start a new group
while running.Value do
yield group() |> Seq.ofList }
let toNum (g:int seq) =
let l = List.ofSeq g
(if l.Length > 0 && l.[0] = 1 then 128uy else 0uy) +
(if l.Length > 1 && l.[1] = 1 then 64uy else 0uy) +
(if l.Length > 2 && l.[2] = 1 then 32uy else 0uy) +
(if l.Length > 3 && l.[3] = 1 then 16uy else 0uy) +
(if l.Length > 4 && l.[4] = 1 then 8uy else 0uy) +
(if l.Length > 5 && l.[5] = 1 then 4uy else 0uy) +
(if l.Length > 6 && l.[6] = 1 then 2uy else 0uy) +
(if l.Length > 7 && l.[7] = 1 then 1uy else 0uy)
let adc (s:float seq) = seq {
let e = s.GetEnumerator()
while e.MoveNext() do
yield
if e.Current >= l1 + l2 then
(1,1)
elif e.Current >= l2 then
(1,0)
elif e.Current >= l1 then
(0,1)
else
(0,0)
}
getLines fsi.CommandLineArgs.[1]
//Skip headers
|> Seq.skip 2
//Split CSV
|> Seq.map (fun l -> l.Split( [|','|] ))
//Ignore empty lines
|> Seq.filter (fun f -> f.Length >= 3)
//Parse the voltages
|> Seq.map (fun f -> (parseVoltage f.[1], parseVoltage f.[2]) )
//Clock from voltage to logic level
|> Seq.map (fun (data,clock) -> (data, (if clock > ttlTrue then 1 else 0)))
//Get data - clock rising edge
|> filterOnClockGoingHigh
//remove the clock data
|> Seq.map (fun f -> fst f)
//ADC - single analogue singnal -> two digital values
|> adc
//Add a count to each item
|> Seq.mapi (fun i v -> (i,v))
//group into chunks of 8
|> groupWhen (fun (i,v) -> i % 8 = 0)
//get only the second item
|> Seq.map (Seq.map snd)
//unzip - get a pair of arrays for each virtual channel of data
|> Seq.map (fun f -> f
|> Array.ofSeq
|> Array.unzip)
//convert each group to a number
|> Seq.map (fun (x,y) -> (toNum x, toNum y))
|> Seq.iter (fun (x,y) -> printfn "%02x %02x %c" x y (if (y >= 0x20uy) && (y <= 0x7euy) then char y else ' ') )
//|> Seq.iter (fun f -> printfn "%A" f)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment