Chunking Data transfer
Hello Guys ,
I dont have the exact source code on me its in the office at work but I was having some issues today when trying to chunk data across from Spinneret to another Spinneret. I 'm using one as the Http server. In the ClentGet on the Serve Beer website I'm using the 'GetMyIp' function to contact another spinneret and transfer data. The transfer works fine when the packet is smaller than the rxdata buffer. When the data is larger Im trying to send it in 1k byte chunks cant seem to get it working
I dont have the exact source code on me its in the office at work but I was having some issues today when trying to chunk data across from Spinneret to another Spinneret. I 'm using one as the Http server. In the ClentGet on the Serve Beer website I'm using the 'GetMyIp' function to contact another spinneret and transfer data. The transfer works fine when the packet is smaller than the rxdata buffer. When the data is larger Im trying to send it in 1k byte chunks cant seem to get it working
bytefill(@tempBuff, 0, TEMP_BUFFER) ' Wait for the response
repeat until size := Socket.rxTCP(id, @rxdata) { Here the slave spinneret is sending the data after the connection is established. Obviously the first 1k chunk is getting across and I'm logging it the logfile.}
bytemove(@tempBuff, @rxdata, strsize(@rxdata))
pst.str(@tempBuff)
AppendLog(@logfile)
I need to read in 1k of data into the @rxdata , log it in the AppendLog bytefill the buffer with 0's and keep repeating this until all the data is transferred. I know this is a trivial matter but I cant seem to get it working
Comments
I have to ask, why transfer data from one Spinneret to another? Does the second Spinneret process the data?
Using one spinneret as a expander board to my existed prop devices as all the I/O's are in use , this also enables me to use an Ethernet connection to the device. The httpserver is running a website and requests and view the logs from all the networked prop devices.
I don't know the project requirements and I don't want to tell you how to design a solution but why send logs from one Spinneret to another? I see the multiple Spinneret as an ideal situation because the logs are unique to the Spinneret. Sending files to a centralized Spinneret means extra code to deal with the batch job and logic to identify the file source. The logs are always available via HTTP GET and a browser.
I would stay away from a batch job and send log records via HTTP GET or POST in real-time to whatever server. The out-of-the-box HttpServer can easily handle one record at a time and up to 1k as you have identified in post 1.
Thats a great idea. Thanks
I all for advice Mike and design ideas, you may have guessed but I a bit of novice :P . Do you mean that by having the Http Server running on one spinneret that I can view the logs stored on the sdcards of the networked spinnerets using the HTTP GET and not having to transfer it ?
Ah you mean send the log entries to the server as they happen instead of saving them on the sdcard of the 'slaves' and trying to chunk the data like im doing? And then I can view the Logs on the server?
Any Spinneret running HttpServer and storing logs on an SD Card is accessible by a browser. Moving the files to another Spinneret is extra work unless the target Spinneret is processing the files in some way. Again, I don't know the project specifics but it seems like a lot of extra work for no reason. Is there a reason to batch the log files?
Quick question. Can you tell me why that when I access a file on the Spinneret from my browser sometimes it downloads the file and other times it just is viewed on the window. Is this to do with the html code I'm using or the spinneret. Seems to do one or the other at different times if I change bits of code in my source spin file.
Is the behavior the same in all browsers?
What file content causes the file to download?
What file content causes the file to display in the browser window?
HttpServer looks at the file extension to send the appropriate content-type header. Is the file extension always txt?
What behavior do you want; download or view?
On the sd card are some text file
http://93.107.65.84:5000 and enter the password 'desmond' . If you click on the Logfiles tab at the top . If you click on PROGEN1 (LOGFILE1.TXT) or PROGEN2(LOGFILE2.TXT) on the Left hand side in the logfiles page you will view the .txt files in the browser. If you click on 'VIEW THE LOGFILES' (LOGTEMPS.TXT) you will download the .txt file.
Don't mind my crappy webpages
I want to download the file , not view it
I normally run Chrome but I just checked it with Explorer and its the same outcome and files are always .TXT . Content is always lines of text unless some unprintable characters make there way in there which can happen. I originally thought it was to do with the size of the file but this is not the case
DEs
Content-Disposition: attachment; filename="log.txt"
Or right click and save.
Back again. I've migrated my code from the Http Server to the new WebServer and I have a quick question.
On the old server the Staticfilehandler was called at the end of the Dispatcher(if not returned first). On the new Server RenderFile now does the job of the StaticFilehandler and RenderDynamic handles anything that isnt static. So on the old server from your examples on the ServerBeer it is possible to intercept the RequestLine for the example of turning on and off a LED.
My question is that I want to parse the querysting from a static file? Like if I have in the html code
[COLOR=#370707]<a href="led.htm[/COLOR][B]?led=on[/B][COLOR=#370707]">LED On</a> [/COLOR]
The render file will always return the led.htm and I want to get to the querystringDoes my Question make any sense?
It is located in the HttpHeader in the TokenizeHeader function? How might I extract this and use it?
repeat until IsEndOfLine(byte[ptr]) if(IsStatusLineToken(byte[ptr])) 'Set a pointer to the querystring if one exists if(byte[ptr] == "?") headerSections[QUERYSTRING] := ptr sectionTokenCnt[QUERYSTRING] := tokens-1 byte[ptr++] := 0 isToken := true else if(isToken) tokenPtr[tokens++] := ptr++ isToken := false else ptr++
Des
req.Get(String("led"))
I was making the call from the wrong place.
if(FileExists(fn, pathElements)) if(strcomp(Req.GetFileName, string("delete.htm"))) pst.str(string(13, "Did we Enter the delete? ")) DeleteFile(sockid) if(strcomp(Req.GetFileName, string("Update.htm"))) pst.str(string(13, "Did we Enter? ")) UpDateLog(sockId) 'Update:=1 RenderFile(sockId, fn)
Think this is right, working anyway
Thanks
Do you see the four example filters in RenderDynamic?
maybe.
SO I have a webpage called delete.htm
<html> <head> <title>Deleting the LogFile</title> </head> <body> <div style="width:600px;margin:auto;"> <h1 style="text-align:center;color:blue;">DELETE LOGS</h1> <div style="text-align:center;"><a href="host.htm">Main Menu</a> | <a href="logfile.htm">LOGFILES</a></div> <p style="text-align:center;color:red;font-size:50px;">ARE YOU SURE YOU WANT TO DELETE THE LOGFILES??</p> <p style="text-align:center;color:blue;font-size:20px;"><a href="delete.htm?delete=Yes">YES DELETE</a> :: <a href="delete.htm?delete=no">NO DON'T DELETE</a></p> </div> </body> </html>
The static file delete.htm is returned by the Renderfile which is fine for the initial display . But when I am attempting to get to the querystring on the last line of the html<a href="delete.htm?delete=Yes">YES DELETE</a>
, the Renderfile returns delete.htm due to the If else statement.if(FileExists(fn, pathElements)) RenderFile(sockId, fn) else ifnot(RenderDynamic(sockId)) sock[sockId].Send(@_404, strsize(@_404))
You will to excuse my ignorance on this Mike.i.e. You could create a filter that looks for that returns an XML response to the caller.
http://123.123.123.123:80/log/delete
I need to look more into the XML end of things and the web side based programming. ROLL on the christmas holidays.
Thanks again
Another unrelated Question I came across recently maybe you could shed some light on. If I have a buffer located in the DAT section, say a 1000 bytes and at some point in the Program I do a bytefill of a 1000 0's to clear the buffer , i notice that sometimes this will clear what is located in the DAT section directly below it. Took me a long time to figure out what was happening. e.g below: If I bytefill Logdata with zero's it was also clearing what was in the ENQ location. I noticed this happening also with some elements I had in my VAR section also.
LogData byte $0[LogDatabuff] ENQ byte $05,$0
One of my spinners also sometimes draws an extra 100mA of current after powerOn , program in the eeprom runs but ethernet connections are unresponsive . You ever come across this?
What's the spinneret doing on start up? DHCP, SNTP, initializing hardware???
CON _clkmode = xtal1 + pll16x _xinfreq = 5_000_000 TCP_MTU = 1460 BUFFER_2K = $800 BUFFER_LOG = $80 BUFFER_WS = $20 BUFFER_SNTP = 48+8 LogDatabuff = $3E8 '1000
This is a modified version of GetMyIp (Modifed probably not in a good way but it works ), don't waste much time sifting to my rubbish code
PUB GetLogfiles(id) | size, idx, tempMask,size1,x,a,Unit, Timeout,TimeoutCount,y Unit:=1 LogtransferNo++ 'keep a record of the number of Logtransfers x:=0 'tempMask := tcpMask 'tcpMask := SetTcpSocketMaskById(id, 0) repeat until Unit > NoOfUnits 'or Timeout ==1 if byte[remoteIP][0] <> $C0 '192- First byte of IP will always be 192 pst.str(string(13, "We have No assigned Ip addresses, byte[0]= ")) pst.dec(byte[remoteIP][0]) return Sock[id].Close 'Close the socket number 'id' pause(delay) sock[id].Init(id, WIZ#TCP, CLIENT_PORT) 'Initialize a socket for connecting to Slave Spinnerets sock[id].RemoteIp(byte[remoteIP][0], byte[remoteIP][1], byte[remoteIP][2], byte[remoteIP][3]) 'sock[id].RemoteIp(192,168,1,15) sock[id].RemotePort(CLIENT_PORT) pause(delay) sock[id].Open ' Connect to the remote server Sock[id].Connect pause(delay) repeat while !Sock[id].Connected TimeoutCount++ 'Increment a counter if we are not getting a connection if TimeoutCount==25000 'About 3 seconds 'pst.str(string(13, "We have a Timeout, Progen No. ")) 'pst.dec(unit) 'pst.str(string(" is not online",13)) TimeoutCount:=0 Timeout:=1 if(FileExists(@logfilename,1)) Sd.openFile(@logfilename, "A") else Sd.newFile(@logfilename) Sd.openFile(@logfilename, "W") Sd.writeString(@time) Sd.writebyte(HT) Sd.writeString(@Progen) LOGDEC(Unit) Sd.writeString(@ProgenSpin) Sd.writebyte(CR) Sd.writebyte(LF) Sd.closeFile Quit 'Quit the repeat loop 'repeat if timeout==1 'If we do get a Timeout set x=1 so we can skip the next section 'pst.str(string(13," We here??")) x:=1 Timeout:=0 if x==0 pst.str(string(13, "Connected... Begin Transfer",13)) TimeoutCount:=0 repeat until x==1 'This is where the data transfer occurs, waits for an ENQ, if recieved sends an ACK 'a:=StringSend(id, @Nack) bytefill(@logdata,0,strsize(@logdata)) repeat until size := sock[id].Available if(size =< 0) y:=1 Quit 'pst.str(string(13, "Number of bytes recieved is ")) ' pst.dec(size) sock[id].Receive(@LogData, size) 'pst.str(string(13, "Data in the recieve buffer is hex ")) 'pst.hex(LogData,2) 'pst.str(string(13, "Data string in Ascii is ")) 'pst.str(@LogData) pst.char(CR) Pause(100) Timeoutcount:=0 if y==1 pst.str(string(13,"Attempting another Quit",13)) Quit if strcomp(@ENQ,@Logdata) 'Enquiry is the beginning of the handshake pst.str(string(13,"Recieved a Enq from the slave",13)) elseif strcomp(@Esc,@Logdata) 'Esc is the end of the transmission or there is no Logfile to transmitt. pst.str(string("Recieved an ESC from the Slave ...EJECT",13)) x:=1 Quit else 'Anything else recieved should be dealt with as an Error and system should -working so far. pst.str(string(13,"Did not receive a ENQ from the slave")) if(FileExists(@logfilename,1)) Sd.openFile(@logfilename, "A") else Sd.newFile(@logfilename) Sd.openFile(@logfilename, "W") Sd.writeString(@time) Sd.writebyte(HT) Sd.writeString(@Progen) LOGDEC(Unit) Sd.writebyte(HT) Sd.writeString(@ErrorShake) Sd.writebyte(CR) Sd.writebyte(LF) Sd.closeFile x:=1 Quit bytefill(@Logdata, 0, strsize(@logdata)) Sock[id].Send(@Ack,strsize(@Ack)) 'Send the Ack back so the Slave knows to send the Data Timeoutcount:=0 repeat until size := sock[id].Available 'repeat until size := Sock[id].receive(id, @Logdata) TimeoutCount++ 'Increment a counter if we are not recieving any data. -working so far if TimeoutCount==25000 'About 3 seconds 'pst.str(string(13, "We have a Timeout, Progen No. ")) 'pst.dec(unit) 'pst.str(string(" Did not send the data",13)) TimeoutCount:=0 if(FileExists(@logfilename,1)) Sd.openFile(@logfilename, "A") else Sd.newFile(@logfilename) Sd.openFile(@logfilename, "W") Sd.writeString(@time) Sd.writebyte(HT) Sd.writeString(@Progen) LOGDEC(Unit) Sd.writebyte(HT) Sd.writeString(@ErrorShake) Sd.writebyte(CR) Sd.writebyte(LF) Sd.closeFile x:=1 Quit sock[id].Receive(@LogData, size) Sock[id].Send(@Eot,strsize(@Eot)) 'AppendLog(@Logdata) if(FileExists(@logfilename,1)) Sd.openFile(@logfilename, "A") else Sd.newFile(@logfilename) Sd.openFile(@logfilename, "W") Sd.writeData(@logdata, strsize(@logdata)) Sd.closeFile 'pst.str(string("Are we even in here??????????????")) 'bytemove(@tempBuff, @rxdata, strsize(@rxdata)) 'pst.str(string("Data recieved from the Slave is ..")) pst.str(@Logdata) pst.char(13) 'Sd.openFile(string("LOG_FILE.TXT"),"W") 'AppendLog(@Logdata) ' bytefill(@tempBuff, 0, TEMP_BUFFER) bytefill(@Logdata, 0, strsize(@logdata)) size~ ' pst.str(string("Sending back the EOT..")) 'pst.hex(Eot,2) 'pst.char(13) x:=0 pst.str(string(13, "Disconnect and reset socket: ")) pst.dec(id) pst.char(13) pst.str(string(13, "Transfer No: ")) pst.dec(LogTransferNo) pst.str(string(" Date & Time: ")) pst.str(@time) ' Reset the socket Sock[id].Disconnect pause(delay) Unit++ 'Used for debug-display only remoteIp.byte[3]+=1 'Increase the Ip address octet by one . IP address must be sequential at the minute . Starts at 192.168.1.31 this will make next IP 192.168.1.32 and so on for NoOfUnits. ' Reset the tcpMask 'tcpMask := tempMask Sock[id].Disconnect remoteIp.byte[3]:=15 'Reset the original Ip addresss so the first Unit is contacted again. pause(delay) sock[id].Init(id, WIZ#TCP, HTTP_PORT) sock[id].open sock[id].listen pause(delay) return
Pretty much all of the above. Uses your INIT function from the webserver, Starts 2 more cogs , one using FULLDuplexSerial for Comms with another device and another for handling logEntries.
bytefill(@logdata,0,strsize(@logdata))
This code assumes @logdata has a terminating zero. This would be safer; bytefill(@logdata,0,LogDatabuff) but not ideal. Even better logdata[0] := 0.sock[id].Receive(@LogData, size)
This just takes whatever is in the Rx buffer and plops it into LogData. There no "Size" limit checks.Do ya mind me asking , do you work for Parallax or are ya just really into Parallax devices?
Still running into this problem with the extra current draw. I'm thinking its the Spinneret , all cogs are starting fine i have debugged them 7 in total(4 original from webserver , extra SDcard(5) , comms with another Prop using FullduplexSerial(6) and a LogfileHandler(7) but it will hang at
[/COLOR] [COLOR=#333333]Retrieving Network Parameters .. Please wait Error Code : 1 ''sometimes Error Code 2 Discover Error
when the extra current draw is occurring. This only seems to happen after long stages in Power Down (Overnight) . Could it be related to the charging of the super Capacitor? I also had other code running on this same spinneret a few months ago and it was starting ok but this sporadic probem would occur and could not connect to it when all it was doing was waiting for a connection. Problem only occurs at Startup and seems to be Ethernet related so if it is hardware must be either the Capacitor or the Ethernet PHYI have loaded exact same software (bar the MAC address) onto a different Spinneret and its was working fine and then when I loaded back up the original one that was causing problems starting working again. Its a really sporadic problem.
I remember in one of your posts you mentioned blowing a Spinneret , what was the symptoms do you recall ? I'm just interested to know if you ever had any similar problems and whether I need to bin this spinneret
Des
Anyway, you have the error trapped. Retry the the DHCP process when you get a discovery error. Since the issue is intermittent, it's probably a timeout. Timeouts are configurable in the socket object: TRANS_TIMEOUT.
When the extra current draw is happening I can retry it a 100 times and it makes no difference. I have to start disconnecting Ethernet cable , remove the power cables , restart and eventually it works , might be 1 min might be 3 hrs.
Source to fix the record
[/COLOR]''121217 -- Added a lock to opening the logfile.txt in case there is a collision. ''131213 -- Think this end is working. Main Server still not accepting every call , docklight will so I think problem is on the other end. ''131112 -- Sending 12 bytes to the Main server including the IP. Working sporadically . Investogate-Always sending the data so problem must be on Server side ''131211 -- Removing alot of unused code to make space for new code. Commented out sections. Need to implement a client call to the Main Server for sending Ip address. SendIp not finished. ''131210 -- Contact made with new Main Server.Using Port 5010. Datatransfer is working. Needs collisions testing- Change batch when transferring data. ''131209 -- Working to an extent, just tested with Docklight, opening the log when a connection is recieved , needs some fine tuning with The Main Server. ''131206 -- Attempting to run this server software on the Progen SPinnerets. Logging the entries from the PROGEN, SPace gona be an issue. Need to get rid of some server code. '' -- Removed SMTP will have to set the clock manual or re-enter the SNTP. Space a Priority . Needs a lot of work see MULTISOCKET section. Can write or read to sdcard from this function. CON _clkmode = xtal1 + pll16x _xinfreq = 5_000_000 TCP_MTU = 1460 BUFFER_2K = $800 BUFFER_LOG = $80 BUFFER_WS = $20 BUFFER_SNTP = 48+8 CR = $0D LF = $0A 'NULL = $00 HT = $09 { Web Server Configuration } SOCKETS = 3 DHCP_SOCK = 3 SNTP_SOCK = 2 ATTEMPTS = 5 { Port Configuration } HTTP_PORT = 5010 '80 'This a Slave Spinneret and we dont want this to contact the Outside world or vice versa. SNTP_PORT = 123 CLIENT_PORT = 5005 'This is used to contact the MAIN server to delivier its IP Address { SD IO } DISK_PARTION = 0 SUCCESS = -1 IO_OK = 0 IO_READ = "r" IO_WRITE = "w" '--------------------------------------------------------------------------------------------------------- '--------------------------------------------------------------------------------------------------------- '******************************************************************************************************** ' _____ ' SEE SENDIP(2) FUNCTION THIS MUST BE CONFIGURED. S/N & REMOTE IP OF MAIN SERVER |\ | | | ' | \ | | | '********************************************************************************************************** | \ | |_____|_ '_________________________________________________________________________________________________________ | \ | _ | | '__________________________________________________________________________________________________________ | \| |_| |______| { Serial IO PINs } USB_Rx = 31 USB_Tx = 30 DELAY = $05 {{ Content Types }} #0, CSS, GIF, HTML, ICO, JPG, JS, PDF, PNG, TXT, XML, ZIP {{ USA Standard Time Zone Abbreviations }} #-10, HST,AtST,_PST,MST,CST,EST,AlST GMT = 0 AZ_TIME = 1 {{ USA Daylight Time Zone Abbreviations }} #-9, HDT,AtDT,PDT,MDT,CDT,EDT,AlDT Zone = GMT '<- Insert your timezone RTC_CHECK_DELAY = 4_000_000 '1_000_000 = ~4 minutes VAR long ProGenStack[50], Cardstack[70] long longHIGH, longLOW, MM_DD_YYYY, DW_HH_MM_SS 'Expected 4-contigous variables for SNTP byte Progenflag, HandshakeError , Cardentry, Cardready,DeleteLog, Datatransfer, SocketInit ,sdcardlock , IPsent byte ProgenLog[100] ,bufftemp[300]', IpAddress[4] DAT '64, 147, 116, 229 '<- This SNTP server is on the west coast sntpIp byte 129, 6, 15, 30 '<- NIST, Gaithersburg, Maryland version byte "1.2", $0 hasSd byte $00 approot byte "\", $0 ' _404 byte "HTTP/1.1 404 OK", CR, LF, { '} "Content-Type: text/html", CR, LF, CR, LF, { '} "<html>", { '} "<head>", { '} "<title>Not Found</title><head>", { '} "<body>", { '} "Page not found!", { '} "</body>", { '} "</html>", CR, LF, $0 ' xmlPinState byte "<root>", CR, LF, " <pin>" ' pinNum byte $30, $30, "</pin>", CR, LF, " <value>" ' pinState byte $30, $30, "</value>", CR, LF, " <dir>" ' pinDir byte $30, $30, "</dir>", CR, LF, { '} "</root>", 0 ' xmlTime byte "<root>", CR, LF, " <time>" ' xtime byte "00/00/0000 00:00:00</time>", CR, LF, " <day>" ' xday byte "---","</day>", CR, LF, "</root>", $0 ' _h200 byte "HTTP/1.1 200 OK", CR, LF, $0 ' _h404 byte "HTTP/1.1 404 Not Found", CR, LF, $0 ' _css byte "Content-Type: text/css",CR, LF, $0 ' _gif byte "Content-Type: image/gif",CR, LF, $0 ' _html byte "Content-Type: text/html", CR, LF, $0 ' _ico byte "Content-Type: image/x-icon",CR, LF, $0 ' _jpg byte "Content-Type: image/jpeg",CR, LF, $0 ' _js byte "Content-Type: application/javascript",CR, LF, $0 ' _pdf byte "Content-Type: application/pdf",CR, LF, $0 ' _png byte "Content-Type: image/png",CR, LF, $0 ' _txt byte "Content-Type: text/plain; charset=utf-8",CR, LF, $0 ' _xml byte "Content-Type: text/xml",CR, LF, $0 ' _zip byte "Content-Type: application/zip",CR, LF, $0 ' _contLen byte "Content-Length: ", $0 _newline byte CR, LF, $0 time byte "00/00/0000 00:00:00", 0 sntpBuff byte $0[BUFFER_SNTP] workSpace byte $0[BUFFER_WS] logBuf byte $0[BUFFER_LOG] wizver byte $00 buff byte $0[BUFFER_2K] null long $00 dhcpRenew byte $00 'contentType long @_css, @_gif, @_html, @_ico, @_jpg, @_js, @_pdf, @_png, @_txt, @_xml, @_zip, $0 mtuBuff long TCP_MTU SOH byte $01,$0 Etx byte $03,$0 Eot byte $04,$0 Enq byte $05,$0 ESC byte $1B,$0 Ack byte $06,$0 LogCreated byte "LOG_FILE.TXT was Created for ", 0 ProgenNo byte "ProgenNo. 1 ", 0 Test1 byte "This is a test", 0 ServerShakeErr byte "Handshaking Error when Transferring Logfile, Logfile may not be up to date", 0 HandshakeErr byte " Handshaking Error with Progen, Last Data Entry may have been lost", 0 IP byte "IP", 0 IpAddress byte $00,$00,$00,$00,$00,$00 'IPstring word @IP, @IpAddress , $0 OBJ pst : "Parallax Serial Terminal" wiz : "W5100" dhcp : "Dhcp" sock[SOCKETS] : "Socket" req : "HttpHeader" SDcard : "S35390A_SD-MMC_FATEngineWrapper" SDCard1 : "S35390A_SD-MMC_FATEngineWrapper" '1 Cog sntp : "SNTP Simple Network Time Protocol v2.11" rtc : "S35390A_RTCEngine" Progen : "PropCom" '1 Cog PUB Init | i, t1 ,t2 'A hardware reset can take 1.5 seconds 'before the Sockets are ready to Send/Receive wiz.HardReset(WIZ#WIZ_RESET) pst.Start(115_200) pause(500) '--------------------------------------------------- 'Main COG '--------------------------------------------------- pst.str(string("COG[0]: Spinneret Web Server v")) pst.str(@version) sdcardlock:=locknew '--------------------------------------------------- 'Start the ProGen Communication '--------------------------------------------------- ' pst.str(string(CR, "CP1 in")) cognew(ProgGenCog,@ProGenstack) repeat until ProGenFlag==1 pst.str(string(13,"COG[2]: ProgGenCog Started ")) '--------------------------------------------------- 'Start the Parallax Serial Terminal '--------------------------------------------------- { pst.str(string(CR, "COG[")) i := pst.GetCogId pst.dec(i) pst.str(string("]: Parallax Serial Terminal")) } pst.str(string(CR, "COG[3]: Parallax Serial Terminal")) '--------------------------------------------------- 'Start the SD Driver and Mount the SD card '--------------------------------------------------- ifnot(SDcard.Start) pst.str(string(CR, " Failed to start SD driver!")) else pst.str(string(CR, "COG[")) i := SDcard.GetCogId pst.dec(i) pst.str(string("]: Started SD Driver")) pause(500) pst.str(string(CR," Mount SD Card - ")) t1 := SDcard.mount(DISK_PARTION) t2 := SDCard1.mount(DISK_PARTION) pst.str(t1) pst.str(t2) if(strcomp(t1, string("OK"))) and (strcomp(t2, string("OK"))) hasSd := true else hasSd := false repeat pst.str(string(CR,"SD card Error, check and reboot")) Pause(2000) 'pst.str(string(CR, "CP2 in")) cognew(Cardhandler,@Cardstack) repeat until Cardready==1 '--------------------------------------------------- 'Initialize the Realtime clock library '--------------------------------------------------- pst.str(string(CR," Init RTC: ")) rtc.RTCEngineStart(29, 28, -1) pst.str(FillTime(@time)) '--------------------------------------------------- 'Start the WizNet SPI driver '--------------------------------------------------- wiz.Start(WIZ#SPI_CS, WIZ#SPI_SCK, WIZ#SPI_MOSI, WIZ#SPI_MISO) pst.str(string(CR, "COG[")) i := wiz.GetCogId pst.dec(i) pst.str(string("]: Started W5100 SPI Driver")) 'Verify SPI connectivity by reading the WizNet 5100 version register wizver := GetVersion if(wizver == 0) pst.str(string(CR, CR, "SPI communication failed!", CR, "Check connections", CR)) return else pst.str(string(CR, " WizNet 5100 Connected; Reg(0x19) = ") ) pst.dec(wizver) pst.str(string(CR, "COG[n]: ")) pst.dec(i~ +1) pst.str(string(" COGs in Use")) pst.str(@divider) 'MAC (Source Hardware Address) must be unique 'on the local network 'wiz.SetMac($00, $08, $DC, $16, $F1, $32) '<- My second Spinneret wiz.SetMac($00, $08, $DC, $16, $F6, $71) '<- PROGEN2 Spinneret -this will change for each Unit 'Invoke DHCP to retrived network parameters 'This assumes the WizNet 5100 is connected 'to a router with DHCP support pst.str(string(CR,"Retrieving Network Parameters...Please Wait")) pst.str(@divider) if(InitNetworkParameters) PrintNetworkParams else PrintDhcpError return '--------------------------------------------------- 'Snyc the RTC using SNTP '--------------------------------------------------- pst.str(string(CR, "Sync RTC with Time Server")) pst.str(@divider) if(SyncSntpTime(SNTP_SOCK)) PrintRemoteIp(SNTP_SOCK) pst.str(string("Web time..........")) DisplayHumanTime else pst.str(string(CR, "Sync failed")) '--------------------------------------------------- ' Set DHCP renew -> (Current hour + 12) // 24 '--------------------------------------------------- dhcpRenew := (rtc.clockHour + 12) // 24 pst.str(string("DHCP Renew........")) if(dhcpRenew < 10) pst.char("0") pst.dec(dhcpRenew) pst.str(string(":00:00",CR)) '--------------------------------------------------- 'Start up the web server '--------------------------------------------------- pst.str(string(CR, "Initialize Sockets")) pst.str(@divider) repeat i from 0 to SOCKETS-1 sock[i].Init(i, WIZ#TCP, HTTP_PORT) OpenListeners StartListners 'ResetSntpSock(SNTP_SOCK) pst.str(string(CR, "Start Socket Services", CR)) MultiSocketService pst.str(string("Fatal Error!!!")) CloseAll pst.str(string(CR, "Rebooting...")) pause(1000) reboot PRI MultiSocketService | bytesToRead, sockId, fn, i, pathElements ,Datawrites, Filelength, Overflow, Remainder, BytesSent,Error1, ServerShakeError,x bytesToRead := sockId := i := 0 repeat repeat if IpSent ==0 Pause(1000) if SendIp(2)==0 'Send the Ip address of the unit to the main Server . 0= Logical False repeat until x ==-1 Pause(5000) ' -1 == Logical True , functioned returns true when everything is ok x:=SendIP(2) ' -1 == Logical True , functioned returns true when everything is ok sock[sockId].SetSocketIR($FF) sockId := ++sockId // SOCKETS pst.str(string(CR,"Exited the Send Ip process")) Quit 'If we send an IP we need to quit after it so that we don't semd the logfile, need to close the connection and start the repeat loop again. Overflow:=FileLength:=Remainder:=Error1:=0 bytesToRead~ CloseWait 'Cycle through the sockets one at a time 'looking for a connections 'pst.str(string(CR, "Waiting for a connection", CR)) 'PrintAllStatuses pst.str(string(CR,"Cp0")) repeat until sock[sockId].Connected sockId := ++sockId // SOCKETS if(++i//RTC_CHECK_DELAY == 0) rtc.readTime 'pst.str(string("DHCP Time check: ")) 'pst.dec(rtc.clockHour) 'pst.char(":") 'pst.dec(rtc.clockMinute) 'pst.char(CR) if(rtc.clockHour == dhcpRenew) RenewDhcpLease i~ pst.str(string(CR,"We have a Connection")) 'Repeat until we have data in the buffer 'repeat until bytesToRead := sock[sockId].Available 'pst.str(string(CR,"Cp2")) Datatransfer:=1 Datawrites:=1 'Sdcard.closeFile repeat until not lockset(sdcardlock) if OpenFile(string("LOG_FILE.TXT")) ==-1 'This is logical TRUE pst.str(string(CR,"File is found")) lockclr(sdcardlock) else pst.str(string(CR,"Error with Opening Logfile")) lockclr(sdcardlock) Quit 'not sure what exactly to do here , need to revisit. 'repeat for time being Filelength:=SDcard.getFileSize 'Sdcard.closeFile pst.str(string(CR,"Filesize=")) pst.dec(Filelength) pst.char(13) if Filelength==0 'If no new entries in the logfile then dont do a transfer and send the ESC Sock[sockId].send(@ESC,1) pst.str(string(13,"LogFile is Empty .QUIT")) Datatransfer:=0 sock[sockid].Disconnect Quit if Filelength>1000 'If the Filength is greater than 1500 then we need to do multiple log transfers Datawrites:=(FileLength/1000) 'Find number of times to write full 1500 bytes Overflow:=FileLength//1000 'Find the overflow FileLength:=1000 Remainder:=1 'pst.str(string("Datawrites=")) 'pst.dec(Datawrites) 'pst.char(13) 'pst.str(string("Overflow=")) 'pst.dec(Overflow) ' pst.char(13) 'PrintAllStatuses repeat Datawrites 'pst.str(string("Sending..Byte in Enq buffer is ..")) 'pst.hex(Enq,2) 'pst.char(13) bytesSent:=Sock[sockId].Send(@Enq,1) 'Send an Enq to the Host to begin the Handshake pst.str(string("Numbers of bytes sent is..")) pst.dec(bytesSent) pst.char(13) ByteReturn(@buff) 'Wait for a Response- should be an ACK 'pst.str(string("Byte returned from Bytereturn is")) 'pst.hex(buff.byte[0],2) 'pst.char(13) if strcomp(@buff,@Ack) 'If the response is an ACK , clear the buffer and proceed otherwise stuck in repeat loop. bytefill(@buff, 0, 1) pst.str(string(13,"Found the Ack",13)) else pst.str(string("Didnt find the Ack..Problem ",13)) bytefill(@buff, 0, 1) 'bytefill (@buff,$0,1000) Error1:=ServerShakeError:=1 Remainder:=0 'If there is an error we dont want to enter the reaminder loop. Quit bytefill (@buff,$0,1000) 'Clear the sending data buffer SDCard.readFromFile(@buff, Filelength) 'Read the Filelength from sd card or Max 1000 bytes bytesSent :=Sock[sockId].Send(@buff, Filelength) 'Send the data to the host 'Sock.send(@Etx,1) ByteReturn(@buff) pst.str(string("No of bytes sent....")) pst.dec(bytesSent) pst.char(13) pst.str(@buff) Pause(10) pst.char(13) 'Wait for a response-host should a return a EOT when it has finished receiving data if strcomp(@buff,@Eot) 'If the response is good proceed otherwise stuck in repeat loop pst.str(string(13,"Received an EOT from server",13)) else pst.str(string("Didnt find the Eot ",13)) pst.str(string("Data in the buff buffer is. ")) pst.hex(buff.byte[0],2) pst.char(13) bytefill(@buff, 0, 1) bytefill (@buff,$0,1000) Error1:=ServerShakeError:=1 Remainder:=0 'If there is an error we dont want to enter the reaminder loop. Quit 'pst.str(string(13,"Did we exit this loop",13)) if Remainder==1 'bytefill(@buff, 0, 1) pst.str(string(13,"In the remainder sector",13)) 'bytefill (@buff,$0,1000) bytesSent:=Sock[sockId].Send(@Enq,1) ByteReturn(@buff) 'Wait for a Response- should be an ACK ' pst.str(string("Byte returned from Bytereturn is")) ' pst.hex(buff.byte[0],2) ' pst.char(13) if strcomp(@buff,@Ack) 'If the response is an ACK , clear the buffer and proceed otherwise stuck in repeat loop. bytefill(@buff, 0, 1) pst.str(string(13,"Found the Ack 2",13)) else pst.str(string("Didnt find the Ack 2..Problem ",13)) bytefill(@buff, 0, 1) Error1:=1 ServerShakeError:=1 Quit FileLength:=SDcard.getFileSize Sdcard.fileseek(FileLength-Overflow) SDCard.readFromFile(@buff,Overflow) SDCARD.closefile Sock.Send(@buff,Overflow) Remainder:=0 'pst.str(string(13,"In the remainder sector Data=")) 'pst.str(@buff) 'pst.char(13) SDCARD.closefile if ServerShakeError ==1 FillTime(@time) SDcard.openFile(string("LOG_FILE.TXT"),"A") SDCard.writeString(@time) SDCARD.writebyte(HT) SDCard.writeString(@ProgenNo) SDCARD.writebyte(HT) SDCard.writeString(@ServerShakeErr) SDCARD.writebyte(CR) SDCARD.writebyte(LF) SDCARD.closefile ServerShakeError:=0 'Send an ESC to signify the End of data transfer, host will see this and end close the connection 'pst.str(string("Byte in ESC buffer is ..")) 'pst.hex(ESC,2) 'pst.char(13) if Error1==0 'If there is an error we dont want to delete the Logfile. DeleteLog:=1 Sock[sockid].send(@ESC,1) 'pst.str(string("Did we send the ESC .Yes if in here.")) Datatransfer:=0 sock[sockid].Disconnect 'Check for a timeout error 'Move the Rx buffer into HUB memory 'sock[sockId].Receive(@buff, bytesToRead) 'Display the request header pst.str(@buff) 'Tokenize and index the header { req.TokenizeHeader(@buff, bytesToRead) fn := req.GetFileName pathElements := req.PathElements if(FileExists(fn, pathElements)) RenderFile(sockId, fn) else ifnot(RenderDynamic(sockId)) sock[sockId].Send(@_404, strsize(@_404)) } 'Close the socket and reset the 'interupt register 'sock[sockId].Disconnect sock[sockId].SetSocketIR($FF) sockId := ++sockId // SOCKETS 'pst.str(string(CR,"Cp3")) PUB SendIp(id) |i , strpointer , TimeoutCount 'When a device is connected we want it to communicate with the Main server by sending it its IP address so the Main server can contact it to retrive its Logfiles IPaddress[0] := 0 TimeoutCount:=0 ipaddress.byte[0]:="I" ipaddress.byte[1]:="P" ipaddress.byte[2]:="1" 'This is the serial number of the Unit, This will be Unique for each unit . Sends the string "SNXXXXIP follwed by the IP . 12 bytes in total ipaddress.byte[3]:="8" ipaddress.byte[4]:="3" ipaddress.byte[5]:="2" ' ipaddress.byte[6]:="I" ' ipaddress.byte[7]:="P" 'ipaddress.byte[1]:="" strpointer:=@ipAddress+6 'pst.str(string(CR,"Ip address of this Unit is " )) 'pst.str(dhcp.GetIp) repeat i from 0 to 3 'pst.dec(byte[dhcp.GetIp][i]) byte[strpointer++]:= byte[dhcp.GetIp][i] 'if(i < 3) ' pst.char($2E) 'else ' pst.char($0D) byte[strPointer++]:=0 'pst.dec(dhcp.GetIp) pst.str(string(CR,"Ip String address of this Unit is :" )) repeat i from 0 to 5 pst.dec(ipAddress.byte[i]) if(i >1 and i < 5) pst.char($2E) ' else ' if i>4 ' pst.char($0D) 'repeat 'if SocketInit==0 'If the socket is already Initialized then we dont need to keep repeating this if there is an error Sock[id].Close 'Close the socket number 'id' pause(delay) sock[id].Init(id, WIZ#TCP, CLIENT_PORT) 'Initialize a socket for connecting to Slave Spinnerets 'sock[id].RemoteIp(byte[remoteIP][0], byte[remoteIP][1], byte[remoteIP][2], byte[remoteIP][3]) sock[id].RemoteIp(192,168,1,11) 'This address will need to be fixed , Progen server will always need to initiate contact to this address. sock[id].RemotePort(5000) pause(delay) sock[id].Open ' Connect to the remote server Sock[id].Connect pause(delay) 'SocketInit:=1 pst.str(string(CR,"Contacting the server")) repeat while !Sock[id].Connected TimeoutCount++ 'Increment a counter if we are not getting a connection if TimeoutCount==25000 'About 3 seconds 'bytefill(@IPaddress,0,6) pst.str(string(CR,"Error contacting the Server",CR)) Sock[id].Disconnect pause(delay) sock[id].Init(id, WIZ#TCP, HTTP_PORT) sock[id].open sock[id].listen Return False 'Quit the function pst.str(string(CR,"We have a Connection" )) 'Sock[id].Send(@@IPString,strsize(@IPString)) 'pause(delay) Sock[id].Send(@Ipaddress,strsize(@Ipaddress)) pst.str(string(CR,"Data sent was " )) repeat i from 0 to 5 pst.dec(ipAddress.byte[i]) if(i >1 and i < 5) pst.char($2E) Sock[id].Disconnect pause(delay) sock[id].Init(id, WIZ#TCP, HTTP_PORT) sock[id].open sock[id].listen pause(delay) Ipsent:=1 'Stops us ending the Ip after a Logtransfer return true PUB ByteReturn(strpointer):Timeout |totalbytes,receiving,bytestoread,buffer bytefill(@buff,0,1000) totalBytes := 0 receiving:=true repeat while receiving 'Data in the buffer? 'pst.str(string("CP1")) bytesToRead := sock.Available totalBytes += bytesToRead 'Check for a timeout if(bytesToRead < 0) receiving := false pst.str(string("Timeout", CR)) Timeout:=-1 return if(bytesToRead == 0) receiving := false 'pst.str(string(CR, "Done Receiving Response", CR)) next if(bytesToRead > 0) 'Get the Rx buffer buffer := sock.Receive(strpointer, bytesToRead) ' pst.str(string(CR, "Are we here?")) 'pst.hex(strpointer.byte[0],2) 'pst.char(CR) bytesToRead~ 'pst.str(string("CP2")) 'pst.str(string("Data received from the server is..")) 'pst.hex(server,2) 'pst.char(13) return Timeout PRI RenewDhcpLease | requestIp pst.str(string(CR,"Retrieving Network Parameters...Please Wait")) pst.str(@divider) requestIp := dhcp.GetIp dhcp.SetRequestIp(byte[requestIp][0],byte[requestIp][1],byte[requestIp][2],byte[requestIp][3]) if(InitNetworkParameters) PrintNetworkParams else PrintDhcpError rtc.readTime dhcpRenew := (rtc.clockHour + 12) // 24 pst.str(string("DHCP Renew........")) if(dhcpRenew < 10) pst.char("0") pst.dec(dhcpRenew) pst.str(string(":00:00",CR)) {{ Old root directory structure PRI BuildAndSendHeader(id, contentLength) | dest, src dest := @buff bytemove(dest, @_h200, strsize(@_h200)) dest += strsize(@_h200) src := GetContentType(req.GetFileNameExtension) bytemove(dest, src, strsize(src)) dest += strsize(src) 'Add content-length : value CR, LF if(contentLength > 0) bytemove(dest, @_contLen, strsize(@_contLen)) dest += strsize(@_contLen) src := Dec(contentLength) bytemove(dest, src, strsize(src)) dest += strsize(src) bytemove(dest, @_newline, strsize(@_newline)) dest += strsize(@_newline) 'End the header with a new line bytemove(dest, @_newline, strsize(@_newline)) dest += strsize(@_newline) byte[dest] := 0 sock[id].send(@buff, strsize(@buff)) }} {PRI BuildAndSendHeader(id, contentLength, ext) | dest, src dest := @buff bytemove(dest, @_h200, strsize(@_h200)) dest += strsize(@_h200) src := GetContentType(GetExtension(ext)) bytemove(dest, src, strsize(src)) dest += strsize(src) 'Add content-length : value CR, LF if(contentLength > 0) bytemove(dest, @_contLen, strsize(@_contLen)) dest += strsize(@_contLen) src := Dec(contentLength) bytemove(dest, src, strsize(src)) dest += strsize(src) bytemove(dest, @_newline, strsize(@_newline)) dest += strsize(@_newline) 'End the header with a new line bytemove(dest, @_newline, strsize(@_newline)) dest += strsize(@_newline) byte[dest] := 0 sock[id].send(@buff, strsize(@buff)) } PUB ProgGenCog | Error,locPointer,LocRx,Timeout Progen.start(26,27, 0, 115200) pst.str(string(13,"COG[1]: PropCom Object Started ")) ProGenFlag:=1 repeat repeat until Error ==1 Progen.rxflush 'All this loop does is wait on data from the Progen. If there is a Handshake fail , quits the repeat loop and starts again. locPointer:=0 locPointer:=@ProgenLog 'pst.str(string("Waiting for Data.....",13)) locRx:=0 'pst.str(string(CR, "CP1 out")) repeat until locRx ==$05 'wait for ENQ from Progen locRx:=Progen.rxcheck 'pst.str(string("Found the ENQ",13)) Progen.tx($06) 'If we get a ENQ from the Progen send an ACK repeat until locRx ==$02 'wait for STX from Progen locRx:=Progen.rxtime(100) if locRx == -1 'If no byte is recieved TimeOut := -1 'Timeout has occured pst.str(string("We have a Timeout 0",CR)) 'outa[user]:=0 Error:=1 HandshakeError:=1 Quit 'pst.str(string("CP 1",13)) 'pst.str(string("Did we make it here",13)) if Timeout==0 repeat until locRx==$03 or Timeout==-1 'if we recieve an STX read into the buffer the command locRx:=Progen.rxtime(100) if locRx == -1 'If no byte is recieved TimeOut := -1 'Timeout has occured pst.str(string("We have a Timeout 1",CR)) 'outa[user]:=0 Error:=1 HandshakeError:=1 Quit else byte[locPointer++] := locRx 'Otherwise keep displayed the next byte recieved byte[locPointer-1]:=0 cardentry:=1 'See cardhandler pst.str(@ProgenLog) pst.char(CR) 'pst.str(string("Are we here after an Error??",CR)) 'if Error==1 ' bytefill(@ProgenLog,0,100) 'pst.str(string("Are we here after an Error Part 2??",CR)) Error:=Timeout:=0 'repeat 'Pause(3000) 'pst.str(string("Just hang here for now",CR)) PUB Cardhandler | Templogsize ,TempLog { SDCard.Start pause(100) 'Mount the SD card pst.str(string("Mount SD Card - ")) SDCard.mount(fileErrorHandle) SDCard1.mount(fileErrorHandle) pst.str(string("OK",13)) } CardReady:=1 ifnot\SDCARD.newfile(string("LOG_FILE.TXT")) pst.str(string("LogFile Creation Error ",13)) else pst.str(string("LogFile 1 Created ",13)) SDcard.openFile(string("LOG_FILE.TXT"),"W") SDcard.writeString(@time) SDCARD.writebyte(HT) SDcard.writeString(@LogCreated) SDcard.writeString(@ProGenNo) SDCARD.writebyte(CR) SDCARD.writebyte(LF) SDCARD.closefile repeat 'pst.str(string(CR, "CP2 out")) repeat until CardEntry==1 'Repeat until there is a LOGFILE ENTRY on the PROGEN if DeleteLog==1 SDCARD.deleteEntry(string("LOG_FILE.TXT")) 'Delete the file so the same contents are not resent 'pst.str(string(13,"CP1")) SDcard.newFile(string("LOG_FILE.TXT")) 'Open a new logfile for the next entries 'pst.str(string(13,"CP2")) Sdcard.closeFile 'pst.str(string(13,"CP3")) DeleteLog:=0 if Datatransfer ==0 and TempLog ==1 'If there has been a write to the temporary log it must be transferrred to the main log but only when a data transfer is not in progress SDcard.openFile(string("LOGFILEA.TXT"),"R") Templogsize:=SDcard.getFileSize SDCARD.readFromFile(@bufftemp,Templogsize) Sdcard.closeFile SDcard.openFile(string("LOG_FILE.TXT"),"A") SDCard.writeString(@bufftemp) SDCARD.writebyte(CR) SDCARD.writebyte(LF) SDCARD.closefile SDCARD.deleteEntry(string("LOGFILEA.TXT")) 'Delete the file so the same contents are not resent bytefill(@bufftemp,0,Templogsize) Templogsize:=Templog:=0 FillTime(@time) case Datatransfer 'If there is a log transfer in progress we must write to a temporary logfile 0: repeat until not lockset(sdcardlock) SDcard.openFile(string("LOG_FILE.TXT"),"A") SDCard.writeString(@time) SDCARD.writebyte(HT) if HandshakeError==1 SDCard.writeString(@HandshakeErr) SDCARD.writebyte(CR) SDCARD.writebyte(LF) SDCARD.closefile CardEntry:=HandshakeError:=0 Else SDCard.writeString(@ProgenLog) SDCARD.writebyte(CR) SDCARD.writebyte(LF) SDCARD.closefile bytefill(@ProgenLog,0,100) CardEntry:=0 lockclr(sdcardlock) 'SDCARD.writebyte(CR) 'SDCARD.writebyte(LF) 1: 'pst.str(string(13,"WE in here!!!!!!!!")) ifnot\sdcard1.newfile(string("LOGFILEA.TXT")) pst.str(string(13,"Sdcard ABorted Error")) else 'pst.str(string(13,"Logging in the Temp log",13)) SDcard1.openFile(string("LOGFILEA.TXT"),"A") SDCard1.writeString(@time) SDCARD1.writebyte(HT) if HandshakeError==1 SDCard1.writeString(@HandshakeErr) SDCARD1.writebyte(CR) SDCARD1.writebyte(LF) SDCARD1.closefile CardEntry:=HandshakeError:=0 else SDCard1.writeString(@ProgenLog) SDCARD1.writebyte(CR) SDCARD1.writebyte(LF) SDCARD1.closefile bytefill(@ProgenLog,0,100) CardEntry:=0 TempLog:=1 PRI GetExtension(fn) return fn + (strsize(fn) - 3) {PRI RenderDynamic(id) 'Process pinstate if(strcomp(req.GetFileName, string("pinstate.xml"))) BuildPinStateXml( req.Get(string("led")), req.Get(string("value")) ) BuildAndSendHeader(id, -1, string("xml")) sock[id].Send(@xmlPinState, strsize(@xmlPinState)) return true if(strcomp(req.GetFileName, string("p_encode.xml"))) BuildPinEndcodeStateXml( req.Get(string("value")) ) BuildAndSendHeader(id, -1, string("xml")) sock[id].Send(@xmlPinState, strsize(@xmlPinState)) return true if(strcomp(req.GetFileName, string("time.xml"))) FillTime(@xTime) FillDay(@xday) BuildAndSendHeader(id, -1, string("xml")) sock[id].Send(@xmlTime, strsize(@xmlTime)) return true if(strcomp(req.GetFileName, string("sntptime.xml"))) SyncSntpTime(SNTP_SOCK) FillTime(@xTime) FillDay(@xday) BuildAndSendHeader(id, -1, string("xml")) sock[id].Send(@xmlTime, strsize(@xmlTime)) ResetSntpSock(SNTP_SOCK) return true return false } {PRI BuildPinStateXml(strpin, strvalue) | pin, value, state, dir pin := StrToBase(strpin, 10) value := StrToBase(strvalue, 10) SetPinState(pin, value) state := ReadPinState(pin) 'Write the pin number to the XML doc if(strsize(strpin) > 1) bytemove(@pinNum,strpin, 2) else byte[@pinNum] := $30 byte[@pinNum][1] := byte[strpin] 'Write the pin value value := Dec(ReadPinState(pin)) if(strsize(value) > 1) bytemove(@pinState, value, 2) else byte[@pinState] := $30 byte[@pinState][1] := byte[value] 'Write Pin direction dir := Dec(ReadDirState(pin)) if(strsize(dir) > 1) bytemove(@pinDir, value, 2) else byte[@pinDir] := $30 byte[@pinDir][1] := byte[dir] PRI ReadDirState(pin) return dira[pin] PRI ReadPinState(pin) return outa[pin] | ina[pin] PRI SetPinState(pin, value) if(value == -1) return if(pin < 23 or pin > 27) return dira[pin]~~ outa[pin] := value } {PRI BuildPinEndcodeStateXml(strvalue) | value, state, dir value := StrToBase(strvalue, 10) 'pst.dec(value) if(value > -1) SetEncodedPinstate(value) state := ReadEncodedPinState 'Write the pin number to the XML doc bytemove(@pinNum,string("$F"), 2) 'Write the pin value value := Dec(ReadEncodedPinState) if(strsize(value) > 1) bytemove(@pinState, value, 2) else byte[@pinState] := $30 byte[@pinState][1] := byte[value] 'Write Pin direction dir := Dec(ReadEncodedDirState) if(strsize(dir) > 1) bytemove(@pinDir, value, 2) else byte[@pinDir] := $30 byte[@pinDir][1] := byte[dir] } {PRI ReadEncodedDirState return dira[27..24] PRI ReadEncodedPinState return outa[27..24] | ina[27..24] PRI SetEncodedPinState(value) dira[27..24]~~ outa[27..24] := value } {PRI ValidateParameters(pin, value) if(pin < 23 or pin > 27) return false if(value > 1 or value < -1) return false return true } {{ Old root directory structure PRI RenderFile(id, fn) | fs, bytes 'Render a static file from the SD Card mtuBuff := sock[id].GetMtu OpenFile(fn) fs := SDcard.getFileSize BuildAndSendHeader(id, fs) 'pst.str(string(cr,"Render File",cr)) repeat until fs =< 0 'Writeline(string("Bytes Left"), fs) if(fs < mtuBuff) bytes := fs else bytes := mtuBuff SDcard.readFromFile(@buff, bytes) fs -= sock[id].Send(@buff, bytes) SDcard.closeFile return }} {PRI RenderFile(id, fn) | fs, bytes {{ Render a static file from the SD Card }} mtuBuff := sock[id].GetMtu OpenFile(fn) fs := SDcard.getFileSize BuildAndSendHeader(id, fs, fn) 'pst.str(string(cr,"Render File",cr)) repeat until fs =< 0 'Writeline(string("Bytes Left"), fs) if(fs < mtuBuff) bytes := fs else bytes := mtuBuff SDcard.readFromFile(@buff, bytes) fs -= sock[id].Send(@buff, bytes) SDcard.closeFile return } PRI SyncSntpTime(sockId) | ptr 'Initialize the socket sock[sockId].Init(SNTP_SOCK, WIZ#UDP, SNTP_PORT) 'Initialize the destination paramaters 'sock[sockId].RemoteIp(64, 147, 116, 229) sock[sockId].RemoteIp(sntpIp[0], sntpIp[1], sntpIp[2], sntpIp[3]) sock[sockId].RemotePort(SNTP_PORT) 'Setup the buffer sntp.CreateUDPtimeheader(@sntpBuff) ptr := SntpSendReceive(SNTP_SOCK, @sntpBuff, 48) if(ptr == @null) return false else 'Set the time SNTP.GetTransmitTimestamp(Zone,@sntpBuff,@LongHIGH,@LongLOW) 'PUB writeTime(second, minute, hour, day, date, month, year) rtc.writeTime(byte[@DW_HH_MM_SS][0], { Seconds } byte[@DW_HH_MM_SS][1], { Minutes } byte[@DW_HH_MM_SS][2], { Hour } byte[@DW_HH_MM_SS][3], { Day of week } byte[@MM_DD_YYYY][2], { Day } byte[@MM_DD_YYYY][3], { Month } word[@MM_DD_YYYY][0]) { Year} return true PRI ResetSntpSock(sockId) sock[sockId].Init(sockId, WIZ#TCP, HTTP_PORT) sock[sockId].Open sock[sockId].Listen PUB SntpSendReceive(sockId, buffer, len) | bytesToRead, ptr bytesToRead := 0 'Open socket and Send Message sock[sockId].Open sock[sockId].Send(buffer, len) pause(500) bytesToRead := sock[sockId].Available 'Check for a timeout if(bytesToRead =< 0 ) bytesToRead~ return @null if(bytesToRead > 0) 'Get the Rx buffer ptr := sock[sockId].Receive(buffer, bytesToRead) sock[sockId].Disconnect return ptr {PRI Writeline(label, value) pst.str(label) repeat 25 - strsize(label) pst.char(".") pst.dec(value) pst.char(CR) } PRI OpenFile(filename) | rc {{ Verify if the file exists }} rc := SDcard.listEntry(filename) if(rc == IO_OK) rc := SDcard.openFile(filename, IO_READ) if(rc == SUCCESS) return true return false {{ Single directory PRI FileExists(filename) | rc 'Verify if the file exists ifnot(hasSd) return false rc := SDcard.listEntry(filename) if(rc == IO_OK) rc := SDcard.openFile(filename, IO_READ) if(rc == SUCCESS) SDcard.closeFile return true return false }} PRI FileExists(filename, pathElements) | rc {{ Verify if the file exists }} ifnot(hasSd) return false ChangeDirectory(pathElements) rc := SDcard.listEntry(filename) if(rc == IO_OK) rc := SDcard.openFile(filename, IO_READ) if(rc == SUCCESS) SDcard.closeFile return true return false PRI ChangeDirectory(pathElements) | i SDcard.changeDirectory(@approot) if(req.IsFileRequest) pathElements-- 'Path elements include a file name ' req.IsFileRequest = true if a file is explictly requested if(pathElements =< 0) 'pst.str(string("Root request", CR, CR)) return else 'pst.str(string("Sub dir request", CR, CR)) repeat i from 0 to pathElements-1 'pst.str( req.GetUrlPart(i) ) 'pst.char(CR) SDcard.changeDirectory(req.GetUrlPart(i)) {PRI GetContentType(ext) {{ Determine the content-type }} if(strcomp(ext, string("css")) OR strcomp(ext, string("CSS"))) return @@contentType[CSS] if(strcomp(ext, string("gif")) OR strcomp(ext, string("GIF"))) return @@contentType[GIF] if(strcomp(ext, string("htm")) OR strcomp(ext, string("HTM"))) return @@contentType[HTML] if(strcomp(ext, string("ico")) OR strcomp(ext, string("ICO"))) return @@contentType[ICO] if(strcomp(ext, string("jpg")) OR strcomp(ext, string("JPG"))) return @@contentType[JPG] if(strcomp(ext, string("js")) OR strcomp(ext, string("JS"))) return @@contentType[JS] if(strcomp(ext, string("pdf")) OR strcomp(ext, string("PDF"))) return @@contentType[PDF] if(strcomp(ext, string("png")) OR strcomp(ext, string("PNG"))) return @@contentType[PNG] if(strcomp(ext, string("txt")) OR strcomp(ext, string("TXT"))) return @@contentType[TXT] if(strcomp(ext, string("xml")) OR strcomp(ext, string("XML"))) return @@contentType[XML] if(strcomp(ext, string("zip")) OR strcomp(ext, string("ZIP"))) return @@contentType[ZIP] return @@contentType[HTML] } PRI GetVersion | i i := 0 result := 0 repeat until result > 0 result := wiz.GetVersion if(i++ > ATTEMPTS*5) return 0 pause(250) PRI InitNetworkParameters | i i := 0 'Initialize the DHCP object dhcp.Init(@buff, DHCP_SOCK) 'Request an IP. The requested IP 'might not be assigned by DHCP dhcp.SetRequestIp(192, 168, 1, 120) 'Invoke the SHCP process repeat until dhcp.DoDhcp(true) if(++i > ATTEMPTS) return false return true PRI PrintDhcpError if(dhcp.GetErrorCode > 0) pst.char(CR) pst.str(string(CR, "Error Code: ")) pst.dec(dhcp.GetErrorCode) pst.char(CR) pst.str(dhcp.GetErrorMessage) pst.char(CR) PRI PrintNetworkParams pst.str(string("Assigned IP.......")) PrintIp(dhcp.GetIp) pst.str(string("Lease Time........")) pst.dec(dhcp.GetLeaseTime) pst.str(string(" (seconds)")) pst.char(CR) pst.str(string("DNS Server........")) PrintIp(wiz.GetDns) pst.str(string("DHCP Server.......")) printIp(dhcp.GetDhcpServer) pst.str(string("Router............")) printIp(dhcp.GetRouter) pst.str(string("Gateway...........")) printIp(wiz.GetGatewayIp) PRI PrintRemoteIp(id) pst.str(string("Remote IP.........")) printIp(wiz.GetRemoteIp(id)) PRI OpenListeners | i 'pst.str(string("Open",CR)) repeat i from 0 to SOCKETS-1 sock[i].Open PRI StartListners | i repeat i from 0 to SOCKETS-1 if(sock[i].Listen) pst.str(string("Socket ")) pst.dec(i) pst.str(string(" Port.....")) pst.dec(sock[i].GetPort) pst.str(string("; MTU=")) pst.dec(sock[i].GetMtu) pst.str(string("; TTL=")) pst.dec(sock[i].GetTtl) pst.char(CR) else pst.str(string("Listener failed ",CR)) PRI SetTranactionTimeout(timeout) | i repeat i from 0 to SOCKETS-1 sock[i].SetTransactionTimeout(timeout) PRI CloseWait | i repeat i from 0 to SOCKETS-1 if(sock[i].IsCloseWait) sock[i].Disconnect sock[i].Close if(sock[i].IsClosed) sock[i].Open sock[i].Listen PRI CloseAll | i repeat i from 0 to SOCKETS-1 sock[i].Disconnect sock[i].Close PRI PrintStatus(id) pst.str(string("Status (")) pst.dec(id) pst.str(string(").......")) pst.hex(wiz.GetSocketStatus(id), 2) pst.char(13) PRI PrintAllStatuses | i pst.str(string(CR, "Socket Status", CR)) repeat i from 0 to SOCKETS-1 pst.dec(i) pst.str(string(" ")) pst.char(CR) repeat i from 0 to SOCKETS-1 pst.hex(wiz.GetSocketStatus(i), 2) pst.char($20) pst.char(CR) PRI PrintIp(addr) | i repeat i from 0 to 3 pst.dec(byte[addr][i]) if(i < 3) pst.char($2E) else pst.char($0D) {PRI PrintExtension pst.str(req.GetFileNameExtension) pst.char(CR) PRI PrintRequestedFileName pst.str(req.GetFileName) pst.char(CR) } {PRI PrintTokens | i, tcnt 't1 := req.GetTokens tcnt := req.GetStatusLineTokenCount repeat i from 0 to tcnt-1 pst.str(req.EnumerateHeader(i)) pst.char(CR) } {PUB DisplayUdpHeader(buffer) pst.char(CR) pst.str(string(CR, "Message from.......")) PrintIp(buffer) pst.char(":") pst.dec(DeserializeWord(buffer + 4)) pst.str(string(" (")) pst.dec(DeserializeWord(buffer + 6)) pst.str(string(")", CR)) } PUB DisplayHumanTime if byte[@MM_DD_YYYY][3]<10 pst.Char("0") pst.dec(byte[@MM_DD_YYYY][3]) pst.Char("/") if byte[@MM_DD_YYYY][2]<10 pst.Char("0") pst.dec(byte[@MM_DD_YYYY][2]) pst.Char("/") pst.dec(word[@MM_DD_YYYY][0]) pst.Char($20) if byte[@DW_HH_MM_SS][2]<10 pst.Char("0") pst.dec(byte[@DW_HH_MM_SS][2]) pst.Char(":") if byte[@DW_HH_MM_SS][1]<10 pst.Char("0") pst.dec(byte[@DW_HH_MM_SS][1]) pst.Char(":") if byte[@DW_HH_MM_SS][0]<10 pst.Char("0") pst.dec(byte[@DW_HH_MM_SS][0]) pst.str(string("(GMT ")) if Zone<0 pst.Char("-") else pst.Char("+") pst.str(string(" ",||Zone+48,":00) ")) pst.Char(13) PRI FillTime(ptr) '00/00/0000 00:00:00 rtc.readTime FillTimeHelper(rtc.clockDate, ptr) ptr += 3 FillTimeHelper(rtc.clockMonth, 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 ptr-17 PRI FillDay(ptr) rtc.readTime bytemove(ptr, rtc.getDayString, 3) return ptr PRI FillTimeHelper(value, ptr) | t1 if(value < 10) byte[ptr++] := "0" t1 := Dec(value) bytemove(ptr, t1, strsize(t1)) PUB Dec(value) | i, x, j {{Send value as decimal characters. Parameter: value - byte, word, or long value to send as decimal characters. Note: This source came from the Parallax Serial Termianl library }} j := 0 x := value == NEGX 'Check for max negative if value < 0 value := ||(value+x) 'If negative, make positive; adjust for max negative 'and output sign i := 1_000_000_000 'Initialize divisor repeat 10 'Loop for 10 digits if value => i workspace[j++] := value / i + "0" + x*(i == 1) 'If non-zero digit, output digit; adjust for max negative value //= i 'and digit from value result~~ 'flag non-zero found elseif result or i == 1 workspace[j++] := "0" 'If zero digit (or only digit) output it i /= 10 workspace[j] := 0 return @workspace PRI DeserializeWord(buffer) | value value := byte[buffer++] << 8 value += byte[buffer] return value PRI StrToBase(stringptr, base) : value | chr, index {Converts a zero terminated string representation of a number to a value in the designated base. Ignores all non-digit characters (except negative (-) when base is decimal (10)).} value := index := 0 repeat until ((chr := byte[stringptr][index++]) == 0) chr := -15 + --chr & 011111 + 39*(chr > 56) 'Make "0"-"9","A"-"F","a"-"f" be 0 - 15, others out of range if (chr > -1) and (chr < base) 'Accumulate valid values into result; ignore others value := value * base + chr if (base == 10) and (byte[stringptr] == "-") 'If decimal, address negative sign; ignore otherwise value := - value PRI pause(Duration) waitcnt(((clkfreq / 1_000 * Duration - 3932) #> 381) + cnt) return DAT divider byte CR, "-----------------------------------------------", CR, $0
I can email it to you if you like