Last active
June 2, 2016 23:13
-
-
Save andrevdm/e05eff7b9e58024caba6 to your computer and use it in GitHub Desktop.
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)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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