Need help with my code....
Don M
Posts: 1,652
I'm trying to make a data sniffer and record the data to an sd card. How it works is I sniff the data, write it to a buffer then when that buffer is full switch to another buffer. While the second buffer is collecting data I run the first buffer through a parser program so that it is formatted in a way that can be easily read with a text editor and then store that text data to the sd card. When the second buffer is full I do the same with that data and just flip back and forth.
The problem I am running into is that the writing to the sd card interferes with the collection of data as it waits to return from that method. So I was thinking that if I put the sd card writing and parsing in its own cog that I could transfer data from the buffers as they are full and then the writing to the sd card wouldn't interfere with the main data collection loop. But I can't get it to work. It waits until it returns from the call to continue.
Don't laugh but here's my main program:
And here is the SD / Parser code that I am trying to get to run independent:
The "outa[x]" bits in the program I use to show "ticks" on the logic analyzer so that I can see what is happening and confirm the data.
Any and all help is greatly appreciated.
Thanks.
Don
The problem I am running into is that the writing to the sd card interferes with the collection of data as it waits to return from that method. So I was thinking that if I put the sd card writing and parsing in its own cog that I could transfer data from the buffers as they are full and then the writing to the sd card wouldn't interfere with the main data collection loop. But I can't get it to work. It waits until it returns from the call to continue.
Don't laugh but here's my main program:
con _clkmode = xtal1 + pll16x _clkfreq = 80_000_000 MS_001 = 80_000_000 / 1_000 MSTR = 6 'M -> S comms on P6 DNA SD card board SLAV = 5 'S -> M comms on P5 DNA SD card board obj serm : "fullduplexserialplus" ' to monitor master comms sers : "fullduplexserialplus" ' to monitor slave comms term : "fullduplexserialplusdecn" ' for terminal output rtc : "jm_softrtc_v2_41_dm" ' used to add millisecond resolution to time parser : "SD_Parser_V1" ' used to parse data and store on SD card var long size word buf1[258], buf2[258], marker byte c, m, mrk, s1, s2, v, close, mount, ropen, stop, wopen pub main | d, l term.start(31, 30, %0000, 115_200) ' start terminal (use PST) pause(1000) term.tx(0) l := \parser.start term.dec(l) term.tx(13) serm.start(MSTR, -1,%10, 9600) ' start receiving master comms sers.start(SLAV, -1,%00, 9600) ' start receiving slave comms rtc.start dira[10..7]~~ repeat d := term.rxcheck case d "s": sd_mount open_write sniff "m": sd_mount "r": read_buffers "f": file_size "c": sd_close "u": sd_unmount "w": open_write "p": sd_mount open_read file_size "o": open_read pub sniff | d, i, j, k, s serm.rxflush sers.rxflush rtc.reset c := 0 ' Flag to reset timer when data is first recieved i := 0 j := 0 v := 0 mrk := 0 ' Time marker flag to only mark once repeat k := term.rxcheck if k == "x" stop := 1 repeat d := \serm.rxcheck if d <> -1 if c == 0 outa[10]~~ rtc.reset outa[10]~ c := 1 if mrk == 0 if d <> $0000 ' Don't write time to Master ACK's if v == 0 outa[9]~~ buf1[i] := (rtc.seconds | $B000) ' Add seconds with $B000 flag i++ outa[9]~ elseif v == 1 outa[9]~~ buf2[j] := (rtc.seconds | $B000) j++ outa[9]~ if v == 0 outa[9]~~ buf1[i] := (rtc.millis | $A000) ' Add milliseconds with $A000 flag i++ outa[9]~ elseif v == 1 outa[9]~~ buf2[j] := (rtc.millis | $A000) j++ outa[9]~ mrk := 1 if v == 0 outa[7]~~ buf1[i] := (d | $8000) i ++ outa[7]~ elseif v == 1 outa[7]~~ buf2[j] := (d | $8000) j++ outa[7]~ repeat d := \serm.rxcheck if(d == -1) serm.rxflush quit s := \sers.rxcheck if s <> -1 if v == 0 outa[8]~~ buf1[i] := (s | $4000) i++ outa[8]~ elseif v == 1 outa[8]~~ buf2[j] := (s | $4000) j++ outa[8]~ mrk := 0 if i => 254 parser.parsedata(@buf1) term.str(string("Switch to buf2", 13)) j := 0 v := 1 i := 0 quit if j => 254 parser.parsedata(@buf2) i := 0 v := 0 term.str(string("Switch to buf1", 13)) j := 0 quit if stop == 1 term.str(string("Sniffer stopped", 13)) outa[10]~~ sd_close outa[10]~ sd_unmount stop := 0 quit term.str(string("Sniffer done", 13)) pub sd_mount | l l := \parser.SDmount if l < 0 term.str(string("SD card failed to mount / not present ")) term.dec(l) term.tx(13) term.str(string("Insert SD card and try again", 13)) mount := 0 else term.str(string("SD card mounted OK ")) term.dec(l) term.tx(13) mount := 1 pub sd_unmount | l l := \parser.SDunmount if l < 0 term.str(string("Failed to unmount ")) term.dec(l) term.tx(13) mount := 1 else term.str(string("Card unmounted ")) term.dec(l) term.tx(13) mount := 0 pub open_write | l l := \parser.SDopen_write if l < 0 term.str(string("File failed to open ")) term.dec(l) term.tx(13) wopen := 0 else term.str(string("sniff.txt file opened ")) term.dec(l) term.tx(13) wopen := 1 pub sd_close | l l := \parser.SDclose if l < 0 term.str(string("File sniff.txt failed to close ")) term.dec(l) term.tx(13) close := 0 else term.str(string("File sniff.txt closed ")) term.dec(l) term.tx(13) close := 1 'pub clear_buffer(buffer, syze) ' ' term.str(string("Clearing bufsdw buffer... ")) ' wordfill(@bufsdw, 0, 8200) ' term.str(string("Done", 13)) pub open_read | l l := \parser.SDopen_read ' open file for writing on sd card called test.txt if l < 0 term.str(string("File sniff.txt failed to open ")) term.dec(l) term.tx(13) ropen := 0 else term.str(string("File sniff.txt opened in read mode ")) term.dec(l) term.tx(13) ropen := 1 pub file_size size := parser.SDfile_size term.str(string("File size is: ")) term.dec(size) term.tx(13) pub read_buffers | i term.str(string("Buf 1", 13)) repeat i from 0 to 256 - 1 ' term.tx(36) term.hex((buf1[i]), 4) ' term.tx(44) term.tx(32) term.tx(13) term.str(string("Buf 2", 13)) repeat i from 0 to 256 - 1 ' term.tx(36) term.hex((buf2[i]), 4) ' term.tx(44) term.tx(32) term.tx(13) pub pause(ms) | t t := cnt repeat ms waitcnt(t += MS_001) dat
And here is the SD / Parser code that I am trying to get to run independent:
con MS_001 = 80_000_000 / 1_000 SD_DO = 0 ' SD card pins SD_CLK = 1 SD_DI = 2 SD_CS = 3 obj sd : "fsrw2_6B" ' SD card routines var long cog, stack[120] word block[258] byte mount, ropen, wopen, close, stop, c, m, mrk, s1, s2, v, p pub Start : okay p := 0 dira[12..11]~~ okay := cog := cognew(parse_block, @stack) + 1 pub parsedata(data) wordmove(@block, data, 258) p := 1 parse_block pub parse_block | chk, d, t, h, i, idx m := 0 ' Slave presence flag s1 := 0 s2 := 0 if p == 1 repeat i from 0 to 256 d := (block[i] & $F000) ' Mask for data logger flags case d $4000: ' Slave data s1 := 1 if m == 1 outa[11]~~ sd.pputc(58) outa[11]~ outa[11]~~ sd.pputc(32) outa[11]~ m := 0 outa[12]~~ sd.SDhex(block[i], 3) outa[12]~ if block[i] == $4100 if s2 == 0 outa[11]~~ sd.pputc(13) outa[11]~ else s2 := 1 m := 0 outa[11]~~ sd.pputc(32) outa[11]~ $8000: ' Master data if block[i] == $8000 if m == 0 if s1 == 1 outa[11]~~ sd.pputc(58) outa[11]~ outa[11]~~ sd.pputc(32) outa[11]~ outa[12]~~ sd.SDhex(block[i], 3) outa[11]~~ sd.pputc(13) outa[11]~ s1 := 0 else outa[12]~~ sd.SDhex(block[i], 3) outa[12]~ outa[11]~~ sd.pputc(32) outa[11]~ else if (block[i] & $0F00) == $0100 if m == 1 outa[12]~~ sd.SDStr(string("** NO RESP **", 13)) outa[12]~ outa[12]~~ sd.SDhex(block[i], 3) outa[12]~ outa[11]~~ sd.pputc(32) outa[11]~ s2 := 0 m := 1 ' Set flag to look for Slave response $A000: outa[11]~~ sd.SDdecn((block[i] & $0FFF), 3) outa[11]~ outa[11]~~ sd.pputc(42) outa[11]~ $B000: if (block[i] & $0FFF) > 0 outa[11]~~ sd.SDdec(block[i] & $0FFF) outa[11]~ outa[11]~~ sd.pputc(46) outa[11]~ p := 0 pub SDmount | l l := \sd.mount(SD_DO) pub SDunmount | l l := \sd.unmount pub SDopen_write | l l := \sd.popen(string("sniff.txt"),"w") pub SDopen_read | l l := \sd.popen(string("sniff.txt"),"r") pub SDclose | l l := \sd.pclose pub SDfile_size | size size := sd.get_filesize return size
The "outa[x]" bits in the program I use to show "ticks" on the logic analyzer so that I can see what is happening and confirm the data.
Any and all help is greatly appreciated.
Thanks.
Don
Comments
I was also thinking about running the sniff method in its own cog and running the parser and sd routines in the main. But am wondering about this scenario first as to why it doesn't work.
If I run this code in an object and call it from my main object it works ok. But if I try and launch a particular method in the object (not the main) into it's own cog it doesn't work right.
This works if called from the main object if I call start at the beginning of my Main and then call "sniff" method:
But if I try to make "sniff" run in its own cog like this it doesn't work right:
Shouldn't this command- okay := cog := cognew(sniff, @stack) + 1 cause sniff to run on its own? I get a response back that a cog has started. I still have to call sniff from my main object for it to run. And then it doesn't run correctly. I've tried making the stack variable as large as I can but it doesn't make any difference. As I was reading in the PEK labs book it sounded to me as though by invoking the cognew command as I have above that it would automatically start that method running.
Can anyone help me out here to understand this?
Thanks.
Don
This approach uses two methods or subroutines. The first method reads the data and places it into a decent size buffer byte by byte, noting the pointer location as it goes. When it reaches the end then it starts over at zero. (a virtual circle). You can use the MOD function to simplify the loop counting process. The second methods follows the progress of the first waits until there is sufficient space between its current pointer and the first method's pointer to process a fixed/variable size chuck of data. It then continues following the first around the virtual circle. You adjust the size of the buffer and data storage chucks to avoid collisions with the first method never stopping and the second method moving in spurts.
You could easily use two cogs as long as they can read each others pointers to avoid collisions. Ideal on a Propeller.
That was it! Thanks.