Shop OBEX P1 Docs P2 Docs Learn Events
Spinneret server html problem — Parallax Forums

Spinneret server html problem

PodionPodion Posts: 90
edited 2012-09-19 07:28 in Accessories
Hello,
I have a project, my project is to control the lights, doors, temperature and other things .. from anywhere in the world.


You can see the website http://108.171.79.7:5555/index.htm


I have a Proppeler as a client and a Spinneret as a server that communicates via two wire serial RX and TX to the client how control all.


The site works fine but I'd like to see all the states in the same web page. I tried several things but I think my problem is in the html code ... Look at the code and tell me what you think. What can I do to show all the states "On" or "Off" on the same page?

On the Spinneret
{{
───────────────────────────────────────────────── 
Copyright (c) 2011 AgaveRobotics LLC.
See end of file for terms of use.


File....... HTTPServer.spin 
Author..... Mike Gebhard
Company.... Agave Robotics LLC
Email...... mailto:mike.gebhard@agaverobotics.com
Started.... 11/01/2010
Updated.... 07/16/2011        
───────────────────────────────────────────────── 
}}


{
About:
  HTTPServer is the designed for use with the Spinneret Web server manufactured by Parallax Inc.


Usage:
  HTTPServer is the top level object.
  Required objects:
        • Parallax Serial Terminal.spin
        • W5100_Indirect_Driver.spin
        • S35390A_SD-MMC_FATEngineWrapper.spin
        • Request.spin
        • Response.spin
        • StringMethods.spin
        • S35390A_RTCEngine.spin 


Change Log:
 
}




CON
  _clkmode = xtal1 + pll16x     
  _xinfreq = 5_000_000


  MAX_PACKET_SIZE = $5C0 '1472   '$800 = 2048
  RxTx_BUFFER     = $800         '$600 = 1536
  TEMP_BUFFER     = $600         '$5B4 = 1460 
  TCP_PROTOCOL    = %0001        '$300 = 768 
  UDP_PROTOCOL    = %0010        '$200 = 512 
  TCP_CONNECT     = $04          '$100 = 256                 
  DELAY           = $10
  MAX_TRIES       = $25                


  #0, DONE, PUT, CD
                                           
  RX_Pin       = 27
  TX_Pin       = 26
  Command      = %0000  '' Feature not used in this demo
  Offsett       = 0      '' Feature not used in this demo
DAT
  mac                   byte    $00, $08, $DC, $16, $F2, $73
  subnet                byte    255, 255 ,255, 0
  gateway               byte    108,171,79,7  'WAN Default Gateway : 24.230.203.1
  ip                    byte    192,168,0,105  'LAN
  port                  word    5555
  remoteIp              byte    24,230,203,105 'http://www.whatismyip.com
  remotePort            word    80
  uport                 word    5050 
  emailIp               byte    0, 0, 0, 0
  emailPort             word    25
  status                byte    $00, $00, $00, $00   
  rxdata                byte    $0[RxTx_BUFFER]
  txdata                byte    $0[RxTx_BUFFER]
  udpdata               byte    $0[TEMP_BUFFER]
  fileErrorHandle       long    $0
  debug                 byte    $0
  lastFile              byte    $0[12], 0
  closedState           byte    %0000
  openState             byte    %0000
  listenState           byte    %0000
  establishedState      byte    %0000
  closingState          byte    %0000
  closeWaitState        byte    %0000 
  lastEstblState        byte    %0000
  lastEstblStateDebug   byte    %0000
  udpListen             byte    %0000
  tcpMask               byte    %1111
  udpMask               byte    %1000   
  fifoSocketDepth       byte    $0
  fifoSocket            long    $00_00_00_00
  debugSemId            byte    $00
  debugCounter          long    $00
  stringMethods         long    $00
  closingTimeout        long    $00, $00, $00, $00
  udpLen                long    $00
  time                  byte    "00/00/0000 00:00:00", 0
  httpDate              byte    "Wed, 01 Feb 2000 01:00:00 GMT", 0
  globalCache           byte    $1
                 


NB0   BYTE 999,0
NB1   BYTE 1,0
NB2   BYTE 2,0
NB3   BYTE 3,0
NB4   BYTE 4,0
NB5   BYTE 5,0
NB6   BYTE 6,0
NB7   BYTE 7,0
NB8   BYTE 8,0
NB9   BYTE 9,0
NB22    BYTE 22,0              
VAR
  long StackSpace[20]


  BYTE    Buffer[10],Buffer1[10],Pin[10]
OBJ
  pst           : "Parallax Serial Terminal"
  Socket        : "W5100_Indirect_Driver"
  SDCard        : "S35390A_SD-MMC_FATEngineWrapper"
  Request       : "Request"
  Response      : "Response"
  str           : "StringMethods"
  rtc           : "S35390A_RTCEngine"


  hsRX          : "HSp2pRX"                       'High Speed Receive driver
  hsTX          : "HSp2pTX"                       'High Speed Transmit driver
PUB Initialize | id, size, st


  debug := 1    
  SDCard.Start
  stringMethods := str.Start
  Request.Constructor(stringMethods)
  Response.Constructor(stringMethods, @txdata)


  pst.Start(115_200)
  pause(200) 


  'Mount the SD card
  pst.str(string("Mount SD Card - ")) 
  SDCard.mount(fileErrorHandle)
  pst.str(string("OK",13))
  
  pst.str(string("Start RTC: "))
  rtc.RTCEngineStart(29, 28, -1)
  
  pause(200)
  pst.str(FillTime)
    
  'Start the W5100 driver
  if(Socket.Start)
    pst.str(string(13, "W5100 Driver Started", 13))
    pst.str(string(13, "Status Memory Lock ID    : "))
    pst.dec(Socket.GetLockId)
    pst.char(13) 




  if(debugSemId := locknew) == -1
    pst.str(string("Error, no HTTP server locks available", 13))
  else
    pst.str(string("HTTP Server Lock ID      : "))
    pst.dec(debugSemId)
    pst.char(13)
    


  'Set the Socket addresses  
  SetMac(@mac)
  SetGateway(@gateway)
  SetSubnet(@subnet)
  SetIP(@ip)


  ' Initailize TCP sockets (defalut setting; TCP, Port, remote ip and remote port)
  repeat id from 0 to 3
    InitializeSocket(id)
    Request.Release(id)
    pause(50)


  ' Set all TCP sockets to listen
  pst.char(13) 
  repeat id from 0 to 3 
    Socket.Listen(id)
    pst.str(string("TCP Socket Listener ID   : "))
    pst.dec(id)
    pst.char(13)
    pause(50)


  pst.Str(string(13,"Started Socket Monitoring Service", 13))
 
  cognew(StatusMonitor, @StackSpace)
  pause(250)




  pst.Str(string(13, "Initial Socket States",13))
  StackDump


  pst.Str(string(13, "Initial Socket Queue",13))
  QueueDump


  pst.str(string(13,"//////////////////////////////////////////////////////////////",13))
  
  Main


   
PUB Main | packetSize, id, i, reset, j, temp
  ''HTTP Service
  repeat
  
    repeat until fifoSocket == 0
    
      bytefill(@rxdata, 0, RxTx_BUFFER)


      if(debug)
        pst.str(string(13, "----- Start of Request----------------------------",13))
        pause(DELAY)
      else
        pause(DELAY)
        
      ' Pop the next socket handle 
      id := DequeueSocket
      if(id < 0)
        next
      
      if(debug)
        pst.str(string(13,"ID: "))
        pst.dec(id)
        pst.str(string(13, "Request Count     : "))
        pst.dec(debugCounter)
        pst.char(13)


      packetSize := Socket.rxTCP(id, @rxdata)


      reset := false
      if ((packetSize < 12) AND (strsize(@rxdata) < 12))
        repeat i from 0 to MAX_TRIES
           pst.str(string(13,"* Retry *"))
          'Wait for a few moments and try again
          waitcnt((clkfreq/300 ) + cnt)
          packetSize := Socket.rxTCP(id, @rxdata)
          if(packetSize > 12)
            quit
          if(i == MAX_TRIES)
            'Clean up resource request   
            Request.Release(id)
            Socket.Disconnect(id)
            reset := true
            if(debug)
              StackDump
              pst.char(13)
              QueueDump
              pst.str(string(13,"* Timeout *",13))
            
      if(reset)
        next


      Request.InitializeRequest(id, @rxdata)
      
      if(debug)
        pst.char(13)
        HeaderLine1(id)
      else
        pause(DELAY)


      ' Process router
      Dispatcher(id)


      'Clean up request resource
      Request.Release(id)


      ' This starts the close process -> 0x00
      ' use close to force a close
      Socket.Disconnect(id)


      bytefill(@txdata, 0, RxTx_BUFFER)


      debugCounter++


  GotoMain
PUB comm      
    repeat 1
       dira[23]~~
       outa[23]~
      hsTX.TX(TX_Pin,10,@Buffer,Command,Offsett)       '<- Transmit Data to External Propeller
      hsRX.RX(RX_Pin,@Buffer)
       !outa[23]                         '<- Receive Data from External Propeller     
      hsRX.RX(RX_Pin,@Buffer1)
      hsTX.TX(TX_Pin,10,@Buffer1,Command,Offsett)       '<- Transmit Data to External Propeller
       !outa[23]
     return 
PRI SendLedResposne(id) | headerLen, qstr
  '' Get the query string value
  qstr :=  Request.Get(id, string("led"))
   
  '' Exit if there is no querystring
  if(qstr == 0)
    return false
   
  '' Turn the LED on if the led= value is "on"  
  if (strcomp(string("on"), qstr ))
    LedStatus(1)
     Buffer[0] := 1
  if (strcomp(string("off"), qstr )) 
    LedStatus(0)
     Buffer[0] := 0
  if (strcomp(string("what"), qstr ))
    if(pin[0]) == 1
      qstr := string("on")
    else
      qstr := string("off") 
          
        
  '' Build and send the header
  '' Send the value of led= on or off
  headerLen := Response.BuildHeader(Request.GetExtension(id), 200, globalCache)
  Socket.txTCP(id, @txdata, headerLen)
  Socket.txTCP(id, qstr, strsize(qstr))
    comm
  return true
PRI SendLedResposneA(id) | headerLen, qstr
  '' Get the query string value
  qstr :=  Request.Get(id, string("led"))
   
  '' Exit if there is no querystring
  if(qstr == 0)
    return false
   
  '' Turn the LED on if the led= value is "on"  
  if (strcomp(string("on"), qstr ))
    LedStatus1(1)
    Buffer[1] := 1
  if (strcomp(string("off"), qstr )) 
    LedStatus1(0)
     Buffer[1] := 0
  if (strcomp(string("what"), qstr ))
    if(pin[1])== 1
      qstr := string("on")
    else
      qstr := string("off") 
          
        
  '' Build and send the header
  '' Send the value of led= on or off
  headerLen := Response.BuildHeader(Request.GetExtension(id), 200, globalCache)
  Socket.txTCP(id, @txdata, headerLen)
  Socket.txTCP(id, qstr, strsize(qstr))
   comm
  return true
PRI SendLedResposneB(id) | headerLen, qstr
  '' Get the query string value
  qstr :=  Request.Get(id, string("led"))
   
  '' Exit if there is no querystring
  if(qstr == 0)
    return false
   
  '' Turn the LED on if the led= value is "on"  
  if (strcomp(string("on"), qstr ))
    LedStatus2(1)
    Buffer[2] := 1
  if (strcomp(string("off"), qstr )) 
    LedStatus2(0)
     Buffer[2] := 0
  if (strcomp(string("what"), qstr ))
    if(pin[2])==1
      qstr := string("on")
    else
      qstr := string("off") 
          
        
  '' Build and send the header
  '' Send the value of led= on or off
  headerLen := Response.BuildHeader(Request.GetExtension(id), 200, globalCache)
  Socket.txTCP(id, @txdata, headerLen)
  Socket.txTCP(id, qstr, strsize(qstr))
   comm
  return true


PRI SendLedResposneC(id) | headerLen, qstr
  '' Get the query string value
  qstr :=  Request.Get(id, string("led"))
   
  '' Exit if there is no querystring
  if(qstr == 0)
    return false
   
  '' Turn the LED on if the led= value is "on"  
  if (strcomp(string("on"), qstr ))
    LedStatus3(1)
    Buffer[3] := 1
  if (strcomp(string("off"), qstr )) 
    LedStatus3(0)
     Buffer[3] := 0
  if (strcomp(string("what"), qstr ))
    if(pin[3])==1
      qstr := string("on")
    else
      qstr := string("off") 
          
        
  '' Build and send the header
  '' Send the value of led= on or off
  headerLen := Response.BuildHeader(Request.GetExtension(id), 200, globalCache)
  Socket.txTCP(id, @txdata, headerLen)
  Socket.txTCP(id, qstr, strsize(qstr))
   comm
  return true
PRI SendLedResposneD(id) | headerLen, qstr
  '' Get the query string value
  qstr :=  Request.Get(id, string("led"))
   
  '' Exit if there is no querystring
  if(qstr == 0)
    return false
   
  '' Turn the LED on if the led= value is "on"  
  if (strcomp(string("on"), qstr ))
    LedStatus4(1)
    Buffer[4] := 1
  if (strcomp(string("off"), qstr )) 
    LedStatus4(0)
     Buffer[4] := 0
  if (strcomp(string("what"), qstr ))
    if(pin[4])==1
      qstr := string("on")
    else
      qstr := string("off") 
          
        
  '' Build and send the header
  '' Send the value of led= on or off
  headerLen := Response.BuildHeader(Request.GetExtension(id), 200, globalCache)
  Socket.txTCP(id, @txdata, headerLen)
  Socket.txTCP(id, qstr, strsize(qstr))
   comm
  return true
PRI SendLedResposneE(id) | headerLen, qstr
  '' Get the query string value
  qstr :=  Request.Get(id, string("led"))
   
  '' Exit if there is no querystring
  if(qstr == 0)
    return false
   
  '' Turn the LED on if the led= value is "on"  
  if (strcomp(string("on"), qstr ))
    LedStatus5(1)
    Buffer[5] := 1
  if (strcomp(string("off"), qstr )) 
    LedStatus5(0)
     Buffer[5] := 0
  if (strcomp(string("what"), qstr ))
    if(pin[5])==1
      qstr := string("on")
    else
      qstr := string("off") 
          
        
  '' Build and send the header
  '' Send the value of led= on or off
  headerLen := Response.BuildHeader(Request.GetExtension(id), 200, globalCache)
  Socket.txTCP(id, @txdata, headerLen)
  Socket.txTCP(id, qstr, strsize(qstr))
   comm
  return true
PRI SendLedResposneF(id) | headerLen, qstr
  '' Get the query string value
  qstr :=  Request.Get(id, string("led"))
   
  '' Exit if there is no querystring
  if(qstr == 0)
    return false
   
  '' Turn the LED on if the led= value is "on"  
  if (strcomp(string("on"), qstr ))
    LedStatus6(1)
    Buffer[6] := 1
  if (strcomp(string("off"), qstr )) 
    LedStatus6(0)
     Buffer[6] := 0
  if (strcomp(string("what"), qstr ))
    if(pin[6])==1
      qstr := string("on")
    else
      qstr := string("off") 
          
        
  '' Build and send the header
  '' Send the value of led= on or off
  headerLen := Response.BuildHeader(Request.GetExtension(id), 200, globalCache)
  Socket.txTCP(id, @txdata, headerLen)
  Socket.txTCP(id, qstr, strsize(qstr))
   comm
  return true
PRI SendLedResposneG(id) | headerLen, qstr
  '' Get the query string value
  qstr :=  Request.Get(id, string("led"))
   
  '' Exit if there is no querystring
  if(qstr == 0)
    return false
   
  '' Turn the LED on if the led= value is "on"  
  if (strcomp(string("on"), qstr ))
    LedStatus7(1)
    Buffer[7] := 1
  if (strcomp(string("off"), qstr )) 
    LedStatus7(0)
     Buffer[7] := 0
  if (strcomp(string("what"), qstr ))
    if(pin[7])==1
      qstr := string("on")
    else
      qstr := string("off") 
          
        
  '' Build and send the header
  '' Send the value of led= on or off
  headerLen := Response.BuildHeader(Request.GetExtension(id), 200, globalCache)
  Socket.txTCP(id, @txdata, headerLen)
  Socket.txTCP(id, qstr, strsize(qstr))
   comm
  return true
PRI SendLedResposneH(id) | headerLen, qstr
  '' Get the query string value
  qstr :=  Request.Get(id, string("led"))
   
  '' Exit if there is no querystring
  if(qstr == 0)
    return false
   
  '' Turn the LED on if the led= value is "on"  
  if (strcomp(string("on"), qstr ))
    LedStatus8(1)
    Buffer[8] := 1
  if (strcomp(string("off"), qstr )) 
    LedStatus8(0)
     Buffer[8] := 0
  if (strcomp(string("what"), qstr ))
    if(pin[8])==1
      qstr := string("on")
    else
      qstr := string("off") 
          
        
  '' Build and send the header
  '' Send the value of led= on or off
  headerLen := Response.BuildHeader(Request.GetExtension(id), 200, globalCache)
  Socket.txTCP(id, @txdata, headerLen)
  Socket.txTCP(id, qstr, strsize(qstr))
   comm
  return true
PRI SendLedResposneI(id) | headerLen, qstr
  '' Get the query string value
  qstr :=  Request.Get(id, string("led"))
   
  '' Exit if there is no querystring
  if(qstr == 0)
    return false
   
  '' Turn the LED on if the led= value is "on"  
  if (strcomp(string("on"), qstr ))
    LedStatus9(1)
    Buffer[9] := 1
  if (strcomp(string("off"), qstr )) 
    LedStatus9(0)
     Buffer[9] := 0
  if (strcomp(string("what"), qstr ))
    if(pin[9])==1
      qstr := string("on")
    else
      qstr := string("off") 
          
        
  '' Build and send the header
  '' Send the value of led= on or off
  headerLen := Response.BuildHeader(Request.GetExtension(id), 200, globalCache)
  Socket.txTCP(id, @txdata, headerLen)
  Socket.txTCP(id, qstr, strsize(qstr))
   comm
  return true
PRI Dispatcher(id)
  ''Do some processing before sending the response


  Request.Get(id, string("led")) 
        
  if(strcomp(Request.GetFileName(id), string("aled.htm")) AND Request.GetDepth(id) == 1)     
    if(SendLedResposne(id))
      return
  Request.Get(id, string("led"))    
  if(strcomp(Request.GetFileName(id), string("aleda.htm")) AND Request.GetDepth(id) == 1)     
    if(SendLedResposneA(id))
      return
  Request.Get(id, string("led"))    
  if(strcomp(Request.GetFileName(id), string("aledb.htm")) AND Request.GetDepth(id) == 1)     
    if(SendLedResposneB(id))
      return
  Request.Get(id, string("led"))    
  if(strcomp(Request.GetFileName(id), string("aledc.htm")) AND Request.GetDepth(id) == 1)     
    if(SendLedResposneC(id))
      return
  Request.Get(id, string("led"))    
  if(strcomp(Request.GetFileName(id), string("aledd.htm")) AND Request.GetDepth(id) == 1)     
    if(SendLedResposneD(id))
      return
  Request.Get(id, string("led"))    
  if(strcomp(Request.GetFileName(id), string("alede.htm")) AND Request.GetDepth(id) == 1)     
    if(SendLedResposneE(id))
      return
  Request.Get(id, string("led"))    
  if(strcomp(Request.GetFileName(id), string("aledf.htm")) AND Request.GetDepth(id) == 1)     
    if(SendLedResposneF(id))
      return
  Request.Get(id, string("led"))    
  if(strcomp(Request.GetFileName(id), string("aledg.htm")) AND Request.GetDepth(id) == 1)     
    if(SendLedResposneG(id))
      return
  Request.Get(id, string("led"))    
  if(strcomp(Request.GetFileName(id), string("aledh.htm")) AND Request.GetDepth(id) == 1)     
    if(SendLedResposneH(id))
      return
  Request.Get(id, string("led"))    
  if(strcomp(Request.GetFileName(id), string("aledi.htm")) AND Request.GetDepth(id) == 1)     
    if(SendLedResposneI(id))
      return      
  StaticFileHandler(id)
  return


  


PRI LedStatus(state)
  
  pin[0] := state
  return
  
PRI LedStatus1(stateA)
  
  pin[1] := stateA
  return
  
PRI LedStatus2(stateB)
  
  pin[2] := stateB
  return
PRI LedStatus3(stateC)
  
  pin[3] := stateC
  return
PRI LedStatus4(stateD)
  
  pin[4] := stateD
  return
PRI LedStatus5(stateE)
  
  pin[5] := stateE
  return
PRI LedStatus6(stateF)
  
  pin[6] := stateF
  return
PRI LedStatus7(stateG)
  
  pin[7] := stateG
  return
PRI LedStatus8(stateH)
  
  pin[8] := stateH
  return
PRI LedStatus9(stateI)
  
  pin[9] := stateI
  return
PRI GotoMain
  Main
PRI StaticFileHandler(id) | fileSize, i, headerLen, temp, j
  ''Serve up static files from the SDCard
  
  'pst.str(string(13,"Static File Handler",13)) 
  SDCard.changeDirectory(@approot)
  pst.char(13)
  
  'Make sure the directory exists
  ifnot(ChangeDirectory(id))
    'send 404 error
    WriteError(id)
    SDCard.changeDirectory(@approot)
    return
    
  ' Make sure the file exists
  ifnot(FileExists(Request.GetFileName(id)))
    'send 404 error
    WriteError(id)
    SDCard.changeDirectory(@approot)
    return


  ' Open the file for reading
  SDCard.openFile(Request.GetFileName(id), "r")
  fileSize := SDCard.getFileSize


  'WriteResponseHeader(id)
  'BuildHeader(extension, statusCode, expirer)
  headerLen := Response.BuildHeader(Request.GetExtension(id), 200, globalCache)
  Socket.txTCP(id, @txdata, headerLen)
  
  if fileSize < MAX_PACKET_SIZE
    ' send the file in one packet
    SDCard.readFromFile(@txdata, fileSize)
    Socket.txTCP(id, @txdata, fileSize)
  else
    ' send the file in a bunch of packets 
    repeat
      SDCard.readFromFile(@txdata, MAX_PACKET_SIZE)  
      Socket.txTCP(id, @txdata, MAX_PACKET_SIZE)
      fileSize -= MAX_PACKET_SIZE
      ' once the remaining fileSize is less then the max packet size, just send that remaining bit and quit the loop
      if fileSize < MAX_PACKET_SIZE and fileSize > 0
        SDCard.readFromFile(@txdata, fileSize)
        Socket.txTCP(id, @txdata, fileSize)
        quit
   
      ' Bailout
      if(i++ > 1_000_000)
        WriteError(id)
        quit
     
  SDCard.closeFile
  SDCard.changeDirectory(@approot)
  return




  
PRI WriteError(id) | headerOffset
  '' Simple 404 error
  pst.str(string(13, "Write 404 Error",13 ))
  headerOffset := Response.BuildHeader(Request.GetExtension(id), 404, false)
  Socket.txTCP(id, @txdata, headerOffset)
  return




''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'' directory and file handlers
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''  
PRI ChangeDirectory(id) | i, found
  'Handle directory structure for this Request
  if(Request.GetDepth(id) > 1)
    repeat i from 0 to Request.GetDepth(id)-2
      'Return if the directory is not found 
      ifnot(FileExists(Request.GetPathNode(id, i)))
        return false
      found := SDCard.changeDirectory(Request.GetPathNode(id, i))
  return true     




  
PRI FileExists(fileToCompare) | filenamePtr
'Start file find at the top of the list
  SDCard.startFindFile 
  'Verify that the file exists
  repeat while filenamePtr <> 0
    filenamePtr := SDCard.nextFile 
    if(str.MatchPattern(filenamePtr, fileToCompare, 0, false ) == 0 )
      return true


  return false


''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'' Time Methods and Formats
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
PRI GetTime(id) | ptr, headerOffset
  ptr := @udpdata
  FillHttpDate
  
  bytemove(ptr, string("<p>"),3)
  ptr += 3


  bytemove(ptr, @httpDate, strsize(@httpDate))
  ptr += strsize(@httpDate)
  
  bytemove(ptr, string("</p>"),4)
  ptr += 3  


  headerOffset := Response.BuildHeader(Request.GetExtension(id), 200, false)
  Socket.txTCP(id, @txdata, headerOffset)
  StringSend(id, @udpdata)
  bytefill(@udpdata, 0, TEMP_BUFFER)
  
  return
 
 
PRI FillTime | ptr, num
 'ToString(integerToConvert, destinationPointer)
 '00/00/0000 00:00:00
  ptr := @time
  rtc.readTime
  


  FillTimeHelper(rtc.clockMonth, ptr)
  ptr += 3


  FillTimeHelper(rtc.clockDate, ptr)
  ptr += 3


  FillTimeHelper(rtc.clockYear, ptr)
  ptr += 5


  FillTimeHelper(rtc.clockHour , ptr)
  ptr += 3


  FillTimeHelper(rtc.clockMinute , ptr)
  ptr += 3


  FillTimeHelper(rtc.clockSecond, ptr) 
 
  return @time




PRI FillHttpDate | ptr, num, temp
 'ToString(integerToConvert, destinationPointer)
 'Wed, 01 Feb 2000 01:00:00 GMT
  ptr := @httpDate
  rtc.readTime




  temp := rtc.getDayString
  bytemove(ptr, temp, strsize(temp))
  ptr += strsize(temp) + 2


  FillTimeHelper(rtc.clockDate, ptr)
  ptr += 3


  temp := rtc.getMonthString
  bytemove(ptr, temp, strsize(temp))
  ptr += strsize(temp) + 1


  FillTimeHelper(rtc.clockYear, ptr)
  ptr += 5


  FillTimeHelper(rtc.clockHour , ptr)
  ptr += 3


  FillTimeHelper(rtc.clockMinute , ptr)
  ptr += 3


  FillTimeHelper(rtc.clockSecond, ptr)
  
  return @httpDate
 


PRI FillTimeHelper(number, ptr) | offset
  offset := 0
  if(number < 10)
    offset := 1
     
  str.ToString(@number, @tempNum)
  bytemove(ptr+offset, @tempNum, strsize(@tempNum))
  


''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'' SDCard Logger
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
PRI AppendLog(logToAppend)
  '' logToAppend:  Pointer to a string of test we'd like to log
  SDCard.changeDirectory(@approot) 


  if(FileExists(@logfile))
    SDCard.openFile(@logfile, "A")
  else
    SDCard.newFile(@logfile)


  SDCard.writeData(string(13,10,"----- Start "),14)
  SDCard.writeData(FillTime, 19)
  SDCard.writeData(string(" -----"),6)
  SDCard.writeData(@crlf_crlf, 2)


  SDCard.writeData(logToAppend, strsize(logToAppend))
  SDCard.writeData(@crlf_crlf, 2)
  
  SDCard.writeData(string("----- End "),10)
  SDCard.writeData(FillTime, 19)
  SDCard.writeData(string(" -----"),6)
  SDCard.writeData(@crlf_crlf, 2)


  SDCard.closeFile


''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'' Memory Management
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
PRI Set(DestAddress, SrcAddress, Count)
  bytemove(DestAddress, SrcAddress, Count)
  bytefill(DestAddress+Count, $0, 1)
  


''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'' Socekt helpers
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''


PRI GetTcpSocketMask(id)
  return id & tcpMask


  
PRI DecodeId(value) | tmp
    if(%0001 & value)
      return 0
    if(%0010 & value)
      return 1
    if(%0100 & value)
      return 2 
    if(%1000 & value)
      return 3
  return -1




PRI QueueSocket(id) | tmp
  if(fifoSocketDepth > 4)
    return false


  tmp := |< id
  
  'Unique check
  ifnot(IsUnique(tmp))
    return false
    
  tmp <<= (fifoSocketDepth++) * 8
  
  fifoSocket |= tmp


  return true




PRI IsUnique(encodedId) | tmp
  tmp := encodedId & $0F
  repeat 4
    if(encodedId & fifoSocket)
      return false
    encodedId <<= 8
  return true 
    


PRI DequeueSocket | tmp
  if(fifoSocketDepth == 0)
    return -2
  repeat until not lockset(debugSemId) 
  tmp := fifoSocket & $0F
  fifoSocket >>= 8  
  fifoSocketDepth--
  lockclr(debugSemId)
  return DecodeId(tmp)


  
PRI ResetSocket(id)
  Socket.Disconnect(id)                                                                                                                                 
  Socket.Close(id)
  
PRI IsolateTcpSocketById(id) | tmp
  tmp := |< id
  tcpMask &= tmp




PRI SetTcpSocketMaskById(id, state) | tmp
'' The tcpMask contains the socket the the StatusMonitor monitors
  tmp := |< id
  
  if(state == 1)
    tcpMask |= tmp
  else
    tmp := !tmp
    tcpMask &= tmp 
    
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'' W5100 Helper methods
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
PRI GetCommandRegisterAddress(id)
  return Socket#_S0_CR + (id * $0100)


PRI GetStatusRegisterAddress(id)
  return Socket#_S0_SR + (id * $0100)


    
PRI SetMac(_firstOctet)
  Socket.WriteMACaddress(true, _firstOctet)
  return 




PRI SetGateway(_firstOctet)
  Socket.WriteGatewayAddress(true, _firstOctet)
  return 




PRI SetSubnet(_firstOctet)
  Socket.WriteSubnetMask(true, _firstOctet)
  return 




PRI SetIP(_firstOctet)
  Socket.WriteIPAddress(true, _firstOctet)
  return 






PRI StringSend(id, _dataPtr)
  Socket.txTCP(id, _dataPtr, strsize(_dataPtr))
  return 




PRI SendChar(id, _dataPtr)
  Socket.txTCP(id, _dataPtr, 1)
  return 


 
PRI SendChars(id, _dataPtr, _length)
  Socket.txTCP(id, _dataPtr, _length)
  return 
         


PRI InitializeSocket(id)
  Socket.Initialize(id, TCP_PROTOCOL, port, remotePort, @remoteIp)
  return


PRI InitializeSocketForEmail(id)
  Socket.Initialize(id, TCP_PROTOCOL, port, emailPort, @emailIp)
  return
  
PRI InitializeUPDSocket(id)
  Socket.Initialize(id, UDP_PROTOCOL, uport, remotePort, @remoteIp)
  return




''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'' Debug/Display Methods
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
PRI QueueDump
  '' Display socket IDs in the queue
  '' ie 00000401 -> socket Zero is next to pop off
  pst.str(string("FIFO["))
  pst.dec(fifoSocketDepth)
  pst.str(string("] "))
  pst.hex(fifoSocket, 8)


    
PRI StackDump | clsd, open, lstn, estb, clwt, clng, id, ulst
  '' This method is purely for debugging
  '' It displays the status of all socket registers
  repeat until not lockset(debugSemId)
  clsd := closedState
  open := openState
  lstn := listenState
  estb := establishedState
  clwt := closeWaitState
  clng := closingState
  ulst := udpListen
  lockclr(debugSemId)


  pst.char(13) 
  repeat id from 3 to 0
    pst.dec(id)
    pst.str(string("-"))
    pst.hex(status[id], 2)
    pst.str(string(" "))
    pause(1)


  pst.str(string(13,"clsd open lstn estb clwt clng udps", 13))
  pst.bin(clsd, 4)
  pst.str(string("-"))
  pst.bin(open, 4)
  pst.str(string("-"))
  pst.bin(lstn, 4)
  pst.str(string("-"))  
  pst.bin(estb, 4)
  pst.str(string("-"))  
  pst.bin(clwt, 4)
  pst.str(string("-"))  
  pst.bin(clng, 4)
  pst.str(string("-"))  
  pst.bin(ulst, 4)
  pst.char(13)
   
PRI HeaderLine1(id) | i
  pst.str(Request.GetMethod(id))
  pst.char($20)


  i := 0
  repeat Request.GetDepth(id)
    pst.char($2F)
    pst.str(Request.GetPathNode(id, i++))
    
   
PRI Pause(Duration)  
  waitcnt(((clkfreq / 1_000 * Duration - 3932) #> 381) + cnt)
  return




PRI StatusMonitor | id, tmp, value
'' StatusMonitor is the heartbeat of the project
'' Here we monitor the state of the Wiznet 5100's 4 sockets
  repeat


    Socket.GetStatus32(@status[0])


    ' Encode status register states
    repeat until not lockset(debugSemId)


    closedState := openState := listenState := establishedState := {
     } closeWaitState := closingState := 0
     
    repeat id from 0 to 3
      case(status[id])
        $00: closedState               |= |< id
             closedState               &= tcpMask  
        $13: openState                 |= |< id
             openState                 &= tcpMask                   
        $14: listenState               |= |< id
             listenState               &= tcpMask
        $17: establishedState          |= |< id
             establishedState          &= tcpMask
        $18,$1A,$1B: closingState      |= |< id
                     closingState      &= tcpMask
        $1C: closeWaitState            |= |< id
             closeWaitState            &= tcpMask
        $1D: closingState              |= |< id
             closingState              &= tcpMask
        $22: udpListen                 |= |< id
             udpListen                 &= udpMask 


    if(lastEstblState <> establishedState)
      value := establishedState
      repeat while value > 0
        tmp := DecodeId(value)
        if(tmp > -1)
          QueueSocket(tmp)
          tmp := |< tmp
          tmp := !tmp
          value &= tmp
      lastEstblState := establishedState


    lockclr(debugSemId)
    
    ' Initialize a closed socket 
    if(closedState > 0)
      id := DecodeId(closedState)
      if(id > -1)
        InitializeSocket(id & tcpMask)
    
    'Start a listener on an initialized/open socket   
    if(openState > 0)
      id := DecodeId(openState)
      if(id > -1)
        Socket.Listen(id & tcpMask)


    ' Close the socket if the status is close/wait
    ' response processor should close the socket with disconnect
    ' there could be a timeout so we have a forced close.
    ' TODO: CCheck for a port that gets stuck in a closing state
    'if(closeWaitState > 0)
      'id := DecodeId(closeWaitState)
      'if(id > -1)
        'Socket.Close(id & tcpMask)






    'pause(100)
return
    
DAT
  approot               byte    "\", 0 
  defaultpage           byte    "index.htm", 0
  logfile               byte    "log.txt", 0
  'binFile               byte    "filename.bin", 0
  FS                    byte    "/", 0
  fn                    byte    "filename=", 0
  doublequote           byte    $22, 0
  crlf                  byte    13, 10, 0
  crlf_crlf             byte    13, 10, 13, 10, 0
  uploadfile            byte    $0[12], 0
  uploadfolder          byte    "uploads", 0
  tempNum               byte    "0000",0
  multipart             byte    "Content-Type: multipart/form-data; boundary=",0
  boundary              byte    $2D, $2D
  boundary1             byte    $0[64]
  'loadme                file    "TogglePin0.binary"                 



The Client code
{{
***************************************
*  HighSpeed Client        DEMO v1.0a *
*  Author: Beau Schwabe               *
*  Copyright (c) 2011 Parallax, Inc.  *               
*  See end of file for terms of use.  *               
***************************************


Revision History:
  Version 1.0   - (09/20/2011) initial release
  Version 1.0a  - (09/26/2011) minor change to detect When the USB plug is connected
                               to the PC.  This prevents unwanted resets.


}}
CON
  ' Set up the processor clock in the standard way for 80MHz on DemoBoard
  _CLKMODE      = xtal1 + pll16x
  _XINFREQ      = 5_000_000 + 0000


    RX_Pin       = 26
    TX_Pin       = 27
    Command      = %0000  '' Feature not used in this demo
    Offset       = 0      '' Feature not used in this demo


    USB_Rx       = 31
    USB_Tx       = 30


    RANGE        = 23       'Range is 0 to RANGE.
    SAMPLES      = 2        'Number of samples to pick: 1 to RANGE + 1 
    temps        = 1  
{{  


Round Robin configuration using 2 Propellers:


   &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;//&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
   &#9474; &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;               &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;    &#9474;
   &#9474; &#9474;   Propeller 1   &#9474;               &#9474;   Propeller 2   &#9474;    &#9474;
   &#9507;&#9472;&#9508;RX             TX&#9500;&#9472;&#61629;&#61630;&#9472;&#9523;&#9472;&#9472;&#9472;//&#9472;&#9472;&#9472;&#9523;&#9472;&#9508;RX             TX&#9500;&#9472;&#61629;&#61630;&#9472;&#9515;
   &#61628; &#9474;     Client      &#9474;    &#61628;        &#61628; &#9474;     Server      &#9474;    &#61628;
   &#61464; &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;    &#61464;        &#61464; &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;    &#61464;
  Vss                      Vss      Vss                      Vss
       


Round Robin configuration using 3 or more Propellers:


   &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;/.../&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;/.../&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
   &#9474; &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;                  &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;                  &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;    &#9474;
   &#9474; &#9474;   Propeller 2   &#9474;                  &#9474;   Propeller N   &#9474;                  &#9474;   Propeller 1   &#9474;    &#9474;
   &#9507;&#9472;&#9508;RX             TX&#9500;&#9472;&#61629;&#61630;&#9472;&#9523;&#9472;&#9472;&#9472;/.../&#9472;&#9472;&#9472;&#9523;&#9472;&#9508;RX             TX&#9500;&#9472;&#61629;&#61630;&#9472;&#9523;&#9472;&#9472;&#9472;/.../&#9472;&#9472;&#9472;&#9523;&#9472;&#9508;RX             TX&#9500;&#9472;&#61629;&#61630;&#9472;&#9515;
   &#61628; &#9474;     Client      &#9474;    &#61628;           &#61628; &#9474;     Client      &#9474;    &#61628;           &#61628; &#9474;     Server      &#9474;    &#61628;
   &#61464; &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;    &#61464;           &#61464; &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;    &#61464;           &#61464; &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;    &#61464;
  Vss                      Vss         Vss                      Vss         Vss                      Vss






Note: All resistors tied to Vss are 330 Ohm and are there to establish a transmission line
Note: All resistors between TX and RX are 100 Ohm and are there to current limit the I/O's in the chance
      of a collision.




With round robin, the idea is that you have one buffer that propagated around and around inside the
round robin loop.  To avoid any data collisions, all Propellers are capable of reading any location
within the buffer, however each Propeller has a specific (assigned by the programmer) location that
it can write to.


So in the Demo, there is a 1K long buffer (4K bytes).  As an example Propeller 1 may only write to
locations 0 to 255.  While Propeller 2 can write to locations 256 to 511.  Propellers 3 & 4 depicted
as N because of the expandable nature of round robin would write to the remaining 512 to 1023 locations.
 


}}
VAR


BYTE    Buffer[10],Buffer1[10]
long Stack[400],Stack1[400]


byte    numbers[RANGE + 1]
long    seed
long    keycode                                
OBJ
  hsRX   : "HSp2pRX"                       'High Speed Receive driver
  hsTX   : "HSp2pTX"                       'High Speed Transmit driver
  PST    : "Parallax Serial Terminal"      'RS232 Serial Driver              
PUB Main   
 cognew(start,@Stack1)       
PUB start|debugLED
'-------------------------------------------------------------------------------------------
     if ina[USB_Rx] == 0        '' Check to see if USB port is powered
        outa[USB_Tx] := 0       '' Force Propeller Tx line LOW if USB not connected
     else
        cognew(SerialDisplay,@Stack)    '' Initialize serial communication to the PC


'-------------------------------------------------------------------------------------------                                                        
    dira[16..23]~~                                      '<- I/O direction for debug LEDs  
'-------------------------------------------------------------------------------------------     
    repeat 
      hsRX.RX(RX_Pin,@Buffer)                           '<- Receive Data from External Propeller
      hsTX.TX(TX_Pin,10,@Buffer,Command,Offset)       '<- Transmit Data to External Propeller
      
      
      hsTX.TX(TX_Pin,10,@Buffer1,Command,Offset)       '<- Transmit Data to External Propeller
      hsRX.RX(RX_Pin,@Buffer1)
      
      
      Menu_Principal
'-------------------------------------------------------------------------------------------
     
'-------------------------------------------------------------------------------------------
    
PUB SerialDisplay               'DEBUG ONLY
    PST.Start(19200)
    repeat
      PST.HOME
      PST.dec(Buffer)                                  '<- Display Data
      
PUB Menu_Principal
     
  outa[16] := Buffer[0]  
  outa[17] := Buffer[1]
  outa[18] := Buffer[2]
  outa[19] := Buffer[3]
  outa[20] := Buffer[4]
  outa[21] := Buffer[5]


PUB RANDOM | i, j, sample1, sample2
repeat 10 
   
     
  repeat i from 10 to RANGE                              'Fill numbers array in order.
     numbers[i] := i
     
     
  repeat i from 10 to (SAMPLES - 1)      
    j := ||?seed // (RANGE - i + 1) + i                 'Pick a number at random from the remaining choices.
    sample1 := numbers[j]
    bytemove(@numbers[i + 1], @numbers[i], j - i)       'Shift the values to make room.
    numbers[i] := sample1
     if sample1 < sample2
        sample2 := sample1
        waitcnt( _xinfreq / temps +cnt)
        outa[16..23]~
        waitcnt( _xinfreq / temps +cnt) 
        !outa[sample2]
                   
        next
        
     if sample1 > sample2
        sample2 := sample1
        waitcnt( _xinfreq / temps +cnt)
        outa[16..23]~
        waitcnt( _xinfreq / temps +cnt) 
        !outa[sample2]
                   
        next
     
     if sample1 == sample2
        j := ||?seed // (RANGE - i + 1) + i                 'Pick a number at random from the remaining choices.
        sample1 := numbers[j]
        bytemove(@numbers[i + 1], @numbers[i], j - i)       'Shift the values to make room.
        numbers[i] := sample1                
        next
                                    'Put the selected number in the newly vacated spot.
                    
  bytemove(@Buffer1,@NB1,strsize(@NB1))
   
 
PUB LED
  dira[16..23]~~
  outa[16..23]~ 
repeat 10 
   
   outa[16]~
  !outa[23]
  waitcnt ( _xinfreq  + cnt)
  !outa[23]
  !outa[22]
  waitcnt ( _xinfreq  + cnt)
  !outa[22]
  !outa[21]
  waitcnt ( _xinfreq  + cnt)
  !outa[21]
  !outa[20]
  waitcnt ( _xinfreq  + cnt)
  !outa[20]
  !outa[19]
  waitcnt ( _xinfreq  + cnt)
  !outa[19]
  !outa[18]
  waitcnt ( _xinfreq  + cnt)
  !outa[18]
  !outa[17]
  waitcnt ( _xinfreq  + cnt)
  !outa[17]
  !outa[16]
  waitcnt ( _xinfreq  + cnt)


outa[16]~


bytemove(@Buffer1,@NB2,strsize(@NB2))


DAT
NB1 BYTE 1,0
NB2 BYTE 2,0
CON

RX
{{
**************************************************
* High Speed Prop to Prop Comm Receiver     v1.1 *
*                                                *
* Author: Beau Schwabe                           *
* Copyright (c) 2011 Parallax                    *
* See end of file for terms of use.              *
**************************************************


Revision History:
  Version 1.0   - original file created as a high speed Prop to Prop
  
  Version 1.1   - (03-29-2011) added routines to aid in handshaking
                  as well as data packet re-direction.


&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;


The Anatomy of the packet data:


When Receiving (RX) You must indicate in the PacketHeaderOut where you
want the received data to be stored.


Note: If TX sends a Destination offset value it will be added to the Data Address value
      and the incomming data will be written starting at the new offset location.
 
The Data Ready Flag is automatically set in the RX function.
 
PacketHeaderOut: 32-bit long 
%00000000000000_aaaaaaaaaaaaaa_cccc
 &#61600;            &#61600; &#61600;            &#61600; &#61600;  &#61600; 
 &#9492;&#9472;&#9472;Reserved&#9472;&#9472;&#9496; &#9492;Data Address&#9496; &#9474;  &#9474;
    14-Bits       14-Bits      &#9474;  &#9474;
                               Data Ready Flag ; $0-busy $F-ready ... controlled by RX
                                 4-Bits


After data has been received then PacketHeaderIn contains information from the
transmitter such as Packet Size, Dest Offset (This is the offset value applied to the local
data address), and a Command Packet that provides a way for the transmitter side to send
specific instructions to the receiver side.


PacketHeaderIn: 32-bit long
%ssssssssssssss_aaaaaaaaaaaaaa_cccc
 &#61600;            &#61600; &#61600;            &#61600; &#61600;  &#61600; 
 &#9492; Packet Size&#9496; &#9492; Dest Offset&#9496; &#9474;  &#9474;
    14-Bits       14-Bits      &#9474;  &#9474; 
                              Packet Command
                                 4-Bits


- The data pin is only driven HIGH.  This is similar to an open collector mode with a PNP drive transistor.


- A pull-down resistor of 330 Ohms on both the Server and the Client side of the data pin
  keep the pin LOW.


Schematic:
                22              22
Server &#61609;&#9472;&#9472;&#9523;&#9472;&#9472;&#9472;&#9472;&#9472;&#61629;&#61630;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#61570;&#61570;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#61629;&#61630;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9523;&#9472;&#9472;&#61610; Client
          &#61628; 330                      330 &#61628;
          &#61464;                              &#61464;
         GND                            GND
          
DataPacket dataline:


      Packet Sync    PacketHeader
           &#9474;              &#9474;
           &#9474;              &#9474;        Packet Data #1   Packet Data #N
           &#61602;              &#61602;             &#61602;                &#61602;
         3.3us          3.2us         3.2us            3.2us
TX &#61569;&#61569;&#61569;&#61570;&#61574;&#61574;&#61574;&#61574;&#61574;&#61574;&#61574;&#61574;&#61573;&#61569;&#61569;&#61569;&#61570;&#61573;&#61571;&#61579;&#61579;&#61579;&#61579;&#61579;&#61579;&#61579;&#61579;&#61579;&#61577;&#61569;&#61570;&#61573;&#61571;&#61579;&#61579;&#61579;&#61579;&#61579;&#61579;&#61579;&#61579;&#61579;&#61577;&#61569;...&#61570;&#61573;&#61571;&#61579;&#61579;&#61579;&#61579;&#61579;&#61579;&#61579;&#61579;&#61579;&#61577;&#61569;
RX &#61569;&#61569;&#61569;&#61569;&#61569;&#61569;&#61569;&#61569;&#61569;&#61569;&#61569;&#61569;&#61569;&#61570;&#61573;&#61569;&#61569;&#61569;&#61569;&#61569;&#61569;&#61569;&#61569;&#61569;&#61569;&#61569;&#61569;&#61569;&#61569;&#61569;&#61569;&#61569;&#61569;&#61569;&#61569;&#61569;&#61569;&#61569;&#61569;&#61569;&#61569;&#61569;&#61569;&#61569;...&#61569;&#61569;&#61569;&#61569;&#61569;&#61569;&#61569;&#61569;&#61569;&#61569;&#61569;&#61569;&#61569;&#61569;
                &#61600;     Packet #1     Packet #2        Packet #N
                &#9474;
       'Packet Sync' detected by RX, RX is ready to receive data


       Note: TX monitors the Sync detection from RX and if TX doesn't see the response
             from RX, then the 'Packet Sync' is sent again until it does.


             TX must send at least 2 packets in order to be a valid transmission.
}}


PUB  Stop 'Dumb code to prevent accidental running from this file
PUB RX(_Pin,_DataAddress)|PacketHeaderOut,PacketHeaderIn
    PacketHeaderOut := _DataAddress<<4              'Tell PacketHeader where to put the Data it receives
    Pin := _Pin                                     'Set receive pin to listen on
    cognew(@RX_Propeller,@PacketHeaderOut)          'request data
    repeat until (PacketHeaderOut& $F)==$F          '<-- Trap here until RX is done
    result := PacketHeaderIn                        'return feedback data from transmitter


DAT
' Start RX proceedure &#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;
RX_Propeller  org
' Clear Status Flag &#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;
              rdlong    DataSamples,         par        'read data samples
              andn      DataSamples,         #$F        'clear flag; data packet busy
              wrlong    DataSamples,         par        'update flag status               
' Get Address for Input Packet Header (Contents written here are from TX)
              mov       _PacketHeaderIn,     par        'Read Data Address Location
              add       _PacketHeaderIn,     #4
' Parse Output Packet Header so we know where to write the incomming data              
              rdlong    Buff,                par        'Read PacketHeader contents
              mov       DataIndex,           Buff
              and       DataIndex,           AddressMask 'DataIndex points to data buffer
              shr       DataIndex,           #4              
' Create Pin Mask for data transmission line              
              mov       PinMask,             #1         'Create Pin Mask for Input/Output pin
              shl       PinMask,             Pin
              or        outa,                PinMask    'Preset Pin HIGH
              andn      dira,                PinMask    'Make Pin an INPUT Hi-Z LOW              
' Setup Counter to count during data-pin HIGH times
              movi      ctra,                #%0_11010_000     'LOGIC A
              movs      ctra,                Pin
              mov       frqa,                #1
' Detect 3.3us Packet SYNC
''&#61569;&#61570;&#61574;&#61574;&#61573;&#61569;  ... Detects a LOW-HIGH-LOW transition ; HIGH time must be at least 3.3us
 Packet_SYNC
              waitpne   PinMask,             PinMask            'Wait for LOW
              mov       phsa,                #0    wz           'clear phsa and set Z flag
                                                                'Note: Z flag is used to
                                                                '      Determine DataSamples
                                                                '      further down in code
              waitpeq   PinMask,             PinMask            'Wait for HIGH
              waitpne   PinMask,             PinMask            'Wait for LOW
              mov       temp,                phsa               'read phsa
              cmp       temp,                #262  wc   '<- 264 clocks at 80MHz equals 3.3us
       if_c   jmp       #Packet_SYNC                    'Jump if pulse is less than 3.3us      
'' 3.3us pulse detected...
''&#61569;&#61570;&#61574;&#61574;     ... Respond by making dataline HIGH (Tell TX we're almost ready to receive)
              or        dira,                PinMask    'Make pin HIGH
''&#61574;&#61573;&#61569;&#61569;     ... Respond by making dataline LOW (Tell TX to start sending data)
              andn      dira,                PinMask    'Make Pin an INPUT Hi-Z LOW
'' Detect data long sync
''&#61569;&#61570;&#61573;&#61569;  ... wait for a HIGH of 100ns followed by a LOW of 50ns  
_RX
              waitpeq   PinMask,             PinMask                         'Wait for HIGH                            
              waitpne   PinMask,             PinMask                         'Wait for LOW
' Read 1 LONG after sync &#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;
              test      PinMask,             ina wc     'Read RX pin into "C"
              rcl       Buff,#1                         'Rotate Buff left and place "C" in Bit0
              test      PinMask,             ina wc     'Read RX pin into "C"
              rcl       Buff,#1                         'Rotate Buff left and place "C" in Bit0
              test      PinMask,             ina wc     'Read RX pin into "C"
              rcl       Buff,#1                         'Rotate Buff left and place "C" in Bit0
              test      PinMask,             ina wc     'Read RX pin into "C"
              rcl       Buff,#1                         'Rotate Buff left and place "C" in Bit0
              test      PinMask,             ina wc     'Read RX pin into "C"
              rcl       Buff,#1                         'Rotate Buff left and place "C" in Bit0
              test      PinMask,             ina wc     'Read RX pin into "C"
              rcl       Buff,#1                         'Rotate Buff left and place "C" in Bit0
              test      PinMask,             ina wc     'Read RX pin into "C"
              rcl       Buff,#1                         'Rotate Buff left and place "C" in Bit0
              test      PinMask,             ina wc     'Read RX pin into "C"
              rcl       Buff,#1                         'Rotate Buff left and place "C" in Bit0
              test      PinMask,             ina wc     'Read RX pin into "C"
              rcl       Buff,#1                         'Rotate Buff left and place "C" in Bit0
              test      PinMask,             ina wc     'Read RX pin into "C"
              rcl       Buff,#1                         'Rotate Buff left and place "C" in Bit0
              test      PinMask,             ina wc     'Read RX pin into "C"
              rcl       Buff,#1                         'Rotate Buff left and place "C" in Bit0
              test      PinMask,             ina wc     'Read RX pin into "C"
              rcl       Buff,#1                         'Rotate Buff left and place "C" in Bit0
              test      PinMask,             ina wc     'Read RX pin into "C"
              rcl       Buff,#1                         'Rotate Buff left and place "C" in Bit0
              test      PinMask,             ina wc     'Read RX pin into "C"
              rcl       Buff,#1                         'Rotate Buff left and place "C" in Bit0
              test      PinMask,             ina wc     'Read RX pin into "C"
              rcl       Buff,#1                         'Rotate Buff left and place "C" in Bit0
              test      PinMask,             ina wc     'Read RX pin into "C"
              rcl       Buff,#1                         'Rotate Buff left and place "C" in Bit0
              test      PinMask,             ina wc     'Read RX pin into "C"
              rcl       Buff,#1                         'Rotate Buff left and place "C" in Bit0
              test      PinMask,             ina wc     'Read RX pin into "C"
              rcl       Buff,#1                         'Rotate Buff left and place "C" in Bit0
              test      PinMask,             ina wc     'Read RX pin into "C"
              rcl       Buff,#1                         'Rotate Buff left and place "C" in Bit0
              test      PinMask,             ina wc     'Read RX pin into "C"
              rcl       Buff,#1                         'Rotate Buff left and place "C" in Bit0
              test      PinMask,             ina wc     'Read RX pin into "C"
              rcl       Buff,#1                         'Rotate Buff left and place "C" in Bit0
              test      PinMask,             ina wc     'Read RX pin into "C"
              rcl       Buff,#1                         'Rotate Buff left and place "C" in Bit0
              test      PinMask,             ina wc     'Read RX pin into "C"
              rcl       Buff,#1                         'Rotate Buff left and place "C" in Bit0
              test      PinMask,             ina wc     'Read RX pin into "C"
              rcl       Buff,#1                         'Rotate Buff left and place "C" in Bit0
              test      PinMask,             ina wc     'Read RX pin into "C"
              rcl       Buff,#1                         'Rotate Buff left and place "C" in Bit0
              test      PinMask,             ina wc     'Read RX pin into "C"
              rcl       Buff,#1                         'Rotate Buff left and place "C" in Bit0
              test      PinMask,             ina wc     'Read RX pin into "C"
              rcl       Buff,#1                         'Rotate Buff left and place "C" in Bit0
              test      PinMask,             ina wc     'Read RX pin into "C"
              rcl       Buff,#1                         'Rotate Buff left and place "C" in Bit0
              test      PinMask,             ina wc     'Read RX pin into "C"
              rcl       Buff,#1                         'Rotate Buff left and place "C" in Bit0
              test      PinMask,             ina wc     'Read RX pin into "C"
              rcl       Buff,#1                         'Rotate Buff left and place "C" in Bit0
              test      PinMask,             ina wc     'Read RX pin into "C"
              rcl       Buff,#1                         'Rotate Buff left and place "C" in Bit0
              test      PinMask,             ina wc     'Read RX pin into "C"
              rcl       Buff,#1                         'Rotate Buff left and place "C" in Bit0


' Detect Packet Size with first received long &#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;
        if_z  mov       DataSamples,         Buff       'Set first reading to number of DataSamples
        if_z  shr       DataSamples,         #18        'Clear "Z" flag in the dnjz below, so this
                                                        'only gets executed once.
' Write Data and get next long &#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;
        if_z  wrlong    Buff,          _PacketHeaderIn  'Write received value to Start Address +4


        if_z  and       Buff,                AddressMask 'Parse data and add Dest Offset to Index                   
        if_z  shr       Buff,                #2
        if_z  add       DataIndex,           Buff
         
       if_nz  wrlong    Buff,                DataIndex  'Write received value to Indexed Address


       if_nz  add       DataIndex,           #4         'Increment Index value
              djnz      DataSamples,         #_RX  wz   'Check to see if there are more data samples
' Set Status Flag &#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;
              rdlong    DataSamples,         par        'read data samples
              or        DataSamples,         #$F        'set flag; data packet done
              wrlong    DataSamples,         par        'update flag status               
' Terminate RX proceedure &#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;
              cogid     temp                            'Get this COG ID
              cogstop   temp                            'STOP this COG


Pin           long      0              
PinMask       long      0
Buff          long      0
DataSamples   long      0
DataIndex     long      0
temp          long      0


AddressMask   long      $7FFF0
_PacketHeaderIn long    0
delay         long      0
DestOffset    long      0


CON

TX
[code]{{
*****************************************************
* High Speed Prop to Prop Comm Transmitter v1.1 *
* *
* Author: Beau Schwabe *
* Copyright (c) 2011 Parallax *
* See end of file for terms of use. *
*****************************************************


Revision History:
Version 1.0 - original file created as a high speed Prop to Prop

Version 1.1 - (03-29-2011) added routines to aid in handshaking
as well as data packet re-direction.


≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈


The Anatomy of the packet data:


When Sending (TX) You must indicate in the PacketHeader what address you want the
data to come from. Additionally the Dest Offset tells the receiver the amount of
offset in LONGs of where the data will be written on the receiver side. The Dest
Offset value overwrites the position of the Data Address prior to sending the first
Packet so that the Dest Offset value is sent rather than the Data Address.


The Data Command (Optional) is used to request a specific function from the receiver.
Note: The receiver must be programmed to know what to do with the command value.


Packet Size is also conveyed to the receiver, indicating how many packets the receiver
is to expect.


Note:
- Packet Size, counts as 1 packet itself, so if your packet data is 100 longs, then
the Packet Size should indicate 101.


- You must send at least 2 Packets for a valid transmission.

PacketHeader: 32-bit long
%ssssssssssssss_aaaaaaaaaaaaaa_cccc
     
└ Packet Size┘ └Data Address┘ │ │
14-Bits 14-Bits │ │
Data Command ; $0 - $E command to send to the receiver
4-Bits Note: $F is reserved to indicate Transmission is complete


- The data pin is only driven HIGH.


- A pull-down resistor of 330 Ohms on both the Server and the Client side of the data pin
keep the pin LOW.


Schematic:
22 22
Server ──┳────────────────────────┳── Client
 330 330 
 
GND GND

DataPacket dataline:


Packet Sync PacketHeader
│ │
│ │ Packet Data #1 Packet Data #N
   
3.3us 3.2us 3.2us 3.2us
TX ...&#615

Comments

Sign In or Register to comment.