Need help with my code....
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:
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 rtc : "jm_softrtc_v2_41" ' used to add millisecond resolution to time var long cog, stack[6000] word buf1[258], buf2[258], marker byte stop, c, m, mrk, s1, s2, v pub start : okay serm.start(MSTR, -1,%10, 9600) ' start receiving master comms sers.start(SLAV, -1,%00, 9600) ' start receiving slave comms rtc.start dira[12..7]~~ pub sniff | d, i, j, k, s, count 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 stop := 0 repeat if stop == 1 quit repeat d := \serm.rxcheck if d <> -1 if c == 0 outa[12]~~ rtc.reset outa[12]~ c := 1 if mrk == 0 if d <> $0000 ' Don't write time to Master ACK's if v == 0 outa[12]~~ buf1[i] := (rtc.seconds | $B000) ' Add seconds with $B000 flag i++ outa[12]~ elseif v == 1 outa[12]~~ buf2[j] := (rtc.seconds | $B000) j++ outa[12]~ if v == 0 outa[12]~~ buf1[i] := (rtc.millis | $A000) ' Add milliseconds with $A000 flag i++ outa[12]~ elseif v == 1 outa[12]~~ buf2[j] := (rtc.millis | $A000) j++ outa[12]~ mrk := 1 if v == 0 outa[7]~~ buf1[i] := (d | $8000) i ++ outa[7]~ elseif v == 1 outa[9]~~ buf2[j] := (d | $8000) j++ outa[9]~ 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[10]~~ buf2[j] := (s | $4000) j++ outa[10]~ mrk := 0 repeat s := \sers.rxcheck if(s == -1) sers.rxflush quit if i => 254 outa[11]~~ j := 0 v := 1 i := 0 quit if j => 254 outa[11]~ i := 0 v := 0 j := 0 quitBut if I try to make "sniff" run in its own cog like this it doesn't work right:
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 rtc : "jm_softrtc_v2_41" ' used to add millisecond resolution to time var long cog, stack[6000] word buf1[258], buf2[258], marker byte stop, c, m, mrk, s1, s2, v pub start : okay serm.start(MSTR, -1,%10, 9600) ' start receiving master comms sers.start(SLAV, -1,%00, 9600) ' start receiving slave comms rtc.start dira[12..7]~~ okay := cog := cognew(sniff, @stack) + 1 pub sniff | d, i, j, k, s, count 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 stop := 0 repeat if stop == 1 quit repeat d := \serm.rxcheck if d <> -1 if c == 0 outa[12]~~ rtc.reset outa[12]~ c := 1 if mrk == 0 if d <> $0000 ' Don't write time to Master ACK's if v == 0 outa[12]~~ buf1[i] := (rtc.seconds | $B000) ' Add seconds with $B000 flag i++ outa[12]~ elseif v == 1 outa[12]~~ buf2[j] := (rtc.seconds | $B000) j++ outa[12]~ if v == 0 outa[12]~~ buf1[i] := (rtc.millis | $A000) ' Add milliseconds with $A000 flag i++ outa[12]~ elseif v == 1 outa[12]~~ buf2[j] := (rtc.millis | $A000) j++ outa[12]~ mrk := 1 if v == 0 outa[7]~~ buf1[i] := (d | $8000) i ++ outa[7]~ elseif v == 1 outa[9]~~ buf2[j] := (d | $8000) j++ outa[9]~ 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[10]~~ buf2[j] := (s | $4000) j++ outa[10]~ mrk := 0 repeat s := \sers.rxcheck if(s == -1) sers.rxflush quit if i => 254 outa[11]~~ j := 0 v := 1 i := 0 quit if j => 254 outa[11]~ i := 0 v := 0 j := 0 quitShouldn'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.