Shop OBEX P1 Docs P2 Docs Learn Events
Need help with my code.... — Parallax Forums

Need help with my code....

Don MDon M Posts: 1,652
edited 2012-10-22 20:33 in Propeller 1
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:
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

  • cavelambcavelamb Posts: 720
    edited 2012-10-22 10:58
    Consider launching the parser in a new cog?
  • Don MDon M Posts: 1,652
    edited 2012-10-22 11:27
    I thought that was what I was trying to do with the statement okay := cog := cognew(parse_block, @stack) + 1.

    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.
  • Don MDon M Posts: 1,652
    edited 2012-10-22 15:19
    Ok here's what I don't understand.

    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 
            quit
             
    


    But 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 
            quit
             
    


    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
  • Prophead100Prophead100 Posts: 192
    edited 2012-10-22 16:09
    Another way to do this is with a single a circular buffer like is used for keyboards. I used this in the past (TSR device drivers in DOS) when reading serial ports and writing to databases. The concept is like two cars that are following each other on a windy road speeding up and slowing down but never passing.

    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.
  • kuronekokuroneko Posts: 3,623
    edited 2012-10-22 16:26
    @Don M: The method running in the separate cog attempts to affect output pins but the direction is set in an unrelated cog (main). Which means you wouldn't see any effect. So just move the dira[12..7]~~ into the sniff method so it's called in the right context. HTH
  • Don MDon M Posts: 1,652
    edited 2012-10-22 20:33
    kuroneko wrote: »
    @Don M: The method running in the separate cog attempts to affect output pins but the direction is set in an unrelated cog (main). Which means you wouldn't see any effect. So just move the dira[12..7]~~ into the sniff method so it's called in the right context. HTH

    That was it! Thanks.
Sign In or Register to comment.