[Contest Entry] Multi-Socket Server
This is my [url=[Contest Entry] Home (garage) automation logger ]original entry[/url]. At that time, I was less knowledgeable then I am now. When I set off to build my project, the existing demo code did not work well for me. So I decided to make a multi-socket server to handle concurrent socket requests. Well, that took me a long time to build. Once I worked out the bugs, I started goofing around with other stuff like sending a binary to the Spinneret and programming a second Propeller, sending email, and HTTP file upload.
Long story short, I did not automate my garage rather I built a Multi-Socket web server. There is no way that I'll be able to write up everything the web server does by by next Sunday. So here is my in progress documentation. Everything is running off the Spinneret.
http://spinneret.servebeer.com:5000/
Reviewers... this is my project submittal. I plan to add more How-To pages this week. Anyway, everything will be on the Spinneret.
EDIT: still need to check spelling and grammar.
Long story short, I did not automate my garage rather I built a Multi-Socket web server. There is no way that I'll be able to write up everything the web server does by by next Sunday. So here is my in progress documentation. Everything is running off the Spinneret.
http://spinneret.servebeer.com:5000/
Reviewers... this is my project submittal. I plan to add more How-To pages this week. Anyway, everything will be on the Spinneret.
EDIT: still need to check spelling and grammar.
Comments
your tutorial is really great, nice job!
I look forward to see more and cannot wait to see the REST of it (no pun intended).
Hope to read the client tutorial soon
How would i run this on my spinneret at home? Is there an archive that rolls it all up nicely?
These are archives stored on the Spinneret SD Card as I build the tutorial. Please be aware that the file locations might change in the future.
LED Example
Begining Examples
http://spinneret.servebeer.com:5000/index.htm
All source files can also be found in the Google repository.
http://code.google.com/p/spinneret-web-server/source/browse/#svn%2Ftrunk%2FMultiSocketServer_MikeG
I setup a web camera so you can interact with the Spinneret.
http://www.agaverobotics.com/spinneret/controlpanel.htm
Open a new browser window and resize the windows so you can see both the video stream and the new browser window.
Feel free to issue the LED services.
Turn on LED connected to PIN 24
http://spinneret.servebeer.com:5000/led/24/on
Turn off the LED connected to PIN 24
http://spinneret.servebeer.com:5000/led/24/off
Available LED pins, 23, 24, 25, 26 , 27.
You can also request the current Spinneret time.
http://spinneret.servebeer.com:5000/xmltime
This project consists
* Motorola phone charger
* 2G SanDisk SD Card
* Servo extension cable
* Cat 5 cable
* Prop Plug
* A lot of coding
I wish I had more time... Didn't get to UDP.
This has been an awesome learning experience.
I'd like to use your server with the SPI driver, can you give it a try if it is working with that setting?
Thanks!
The indirect driver is taking too much pins...
this is problematic if the SPI driver is not working,
I would expect a drop-in replacement for the indirect driver.
Are you wanting for someone to valid the SPI driver before you build your board? Do you have one of those WizNet boards and can valid SPI driver functionality on your own?
If someone could do it I would be very pleased, I don't have any WIZNET module, I would hope that my board works the first time with SPI.
All I want to know is if someone can run your code but by replacing the indirect by the spi driver.
Also, I have left all the indirect addressing pins floating, but I can't validate if this is okay.
Data 0-7,WR,RD,INT,CS floating
Addr 0-1 to ground
How/ where are you setting the time on the RTC?
http://www.agaverobotics.com/spinneret/datetime.aspx
Beau's SNTP object is a better method.
http://forums.parallax.com/showthread.php?129435-DEMO-Using-SNTP-to-sync-the-Spinneret-s-on-board-RTC
CON
'USA Standard Time Zone Abbreviations #-10, HST,AtST,_PST,MST,CST,EST,AlST # -1, GMT {Day light saving time, we don't have dyalight savings time in AZ} 'USA Daylight Time Zone Abbreviations <- No longer used in v1.1 '#-9, HDT,AtDT,PDT,MDT,CDT,EDT,AlDT Zone = GMT '<- Eastern Standard Time = GMT-5 'W5100 Interface #0, W5100_DATA0, W5100_DATA1, W5100_DATA2, W5100_DATA3, W5100_DATA4 #5, W5100_DATA5, W5100_DATA6, W5100_DATA7, W5100_ADDR0, W5100_ADDR1 #10, W5100_WR, W5100_RD, W5100_CS, W5100_INT, W5100_RST, W5100_SEN
DAT
sntpIp byte 69, 25, 96, 13 {San Jose CA} sntpPort word 123
OBJ
OBJ pst : "Parallax Serial Terminal" Socket : "W5100_Indirect_Driver" SDCard : "S35390A_SD-MMC_FATEngineWrapper" Request : "Request" Response : "Response" str : "StringMethods" rtc : "S35390A_RTCEngine" sntp : "SNTP Simple Network Time Protocol v1.1"
Methods added to HTTPServer.spin
PRI GetSntp(id) | tempMask pst.str(string(13, "GET SNTP Time")) tempMask := tcpMask SetTcpSocketMaskById(id, 0) 'wait := 200 Socket.Close(id) pause(delay) pst.str(string(13, "Initialize UDP Socket")) InitializeSntpUdpSocket(id) pause(delay) pst.str(string(13, "Request Time")) if GetSntpTime(id, @tempBuff) ' Decode 64-Bit time from server '≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈ sntp.GetTransmitTimestamp(Zone,@tempBuff,@LongHIGH,@LongLOW) ' Display Reference/Sync TimeZone corrected Time '≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈ 'DisplayHumanTime ' Set RTC to Internet Time pst.str(string(13, "SET RTC")) '≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈ {{ rtc.SetDateTime(byte[@MM_DD_YYYY][3], { <- Month } byte[@MM_DD_YYYY][2], { <- Day } word[@MM_DD_YYYY][0]-2000, { <- Year } byte[@DW_HH_MM_SS][3], { <- (day of week) } byte[@DW_HH_MM_SS][2], { <- Hour } byte[@DW_HH_MM_SS][1], { <- Minutes } byte[@DW_HH_MM_SS][0]) { <- Seconds } }} ''PUB writeTime(second, minute, hour, day, date, month, year) rtc.writeTime(byte[@DW_HH_MM_SS][0], { <- second } byte[@DW_HH_MM_SS][1], { <- minute } byte[@DW_HH_MM_SS][2], { <- hour } (byte[@DW_HH_MM_SS][3] // 6) +1, { <- (day of week) } byte[@MM_DD_YYYY][2], { <- date } byte[@MM_DD_YYYY][3], { <- month } word[@MM_DD_YYYY][0]) { <- year } pst.str(string(13, "Disconnect and reset socket: ")) pst.dec(id) pst.char(13) ' Reset the socket Socket.Disconnect(id) pause(delay) 'Socket.SocketClose(id) 'pause(delay) ' Reset the tcpMask tcpMask := tempMask InitializeSocket(id) pause(delay) return PUB GetSntpTime(id, BufferAddress)|i sntp.CreateUDPtimeheader(BufferAddress,@sntpIp) Socket.txUDP(id, BufferAddress) '<-- Send the UDP packet repeat 100 i := Socket.rxUDP(id, BufferAddress) if i == 56 return 1 Pause(100) '<- if 1000 = 1 sec ; 10 = 1/100th sec X 100 repeats above = 1 sec return 0 PRI InitializeSntpUdpSocket(id) Socket.Initialize(id, UDP_PROTOCOL, uport, sntpPort, @sntpIp) return
Added a filter to the Dispatcher
if(strcomp(Request.GetPathNode(id, 0), string("getsntp"))) GetSntp(3) XmlTime(id) return
Invoking the http://spinneret.servebeer.com:5000/getsntp service will cause the Spinneret to update the RTC. Resetting the Spinnneret also sets the RTC.
DAT OnTimes Zone0OnTime LONG 500,500,500,500,500,700,700 Zone1OnTime long 500,500,500,500,500,700,700 Zone2OnTime long 500,500,500,500,500,700,700 Zone3OnTime long 500,500,500,500,500,700,700 Zone4OnTime long 500,500,500,500,500,700,700 Zone5OnTime long 500,500,500,500,500,700,700 Zone6OnTime long 500,500,500,500,500,700,700 Zone7OnTime long 500,500,500,500,500,700,700 OffTimes Zone0OffTime LONG 730,2230,1654,1409,2034,2301,1551 Zone1OffTime long 730,2230,2230,1410,1835,2308,1551 Zone2OffTime long 730,2230,2230,1002,1636,2352,1552 Zone3OffTime long 2230,2230,2230,800,1437,2200,1552 Zone4OffTime long 2230,2230,2230,800,1438,1800,1551 Zone5OffTime long 2400,2230,2230,800,1430,1800,1800 Zone6OffTime long 2230,2230,2230,800,1141,1800,1551 Zone7OffTime long 2400,2230,2230,800,1800,1800,1800
I kinda doubt you want to create a DAT file. Unless you have a procedure to compile the DAT file.
CON _clkmode = xtal1 + pll16x _xinfreq = 5_000_000 COLUMNS = 7 ROWS = 8 DAT OnTimes Zone0OnTime LONG 500,500,500,500,500,700,700 Zone1OnTime long 500,500,500,500,500,700,700 Zone2OnTime long 500,500,500,500,500,700,700 Zone3OnTime long 500,500,500,500,500,700,700 Zone4OnTime long 500,500,500,500,500,700,700 Zone5OnTime long 500,500,500,500,500,700,700 Zone6OnTime long 500,500,500,500,500,700,700 Zone7OnTime long 500,500,500,500,500,700,700 OffTimes Zone0OffTime LONG 730,2230,1654,1409,2034,2301,1551 Zone1OffTime long 730,2230,2230,1410,1835,2308,1551 Zone2OffTime long 730,2230,2230,1002,1636,2352,1552 Zone3OffTime long 2230,2230,2230,800,1437,2200,1552 Zone4OffTime long 2230,2230,2230,800,1438,1800,1551 Zone5OffTime long 2400,2230,2230,800,1430,1800,1800 Zone6OffTime long 2230,2230,2230,800,1141,1800,1551 Zone7OffTime long 2400,2230,2230,800,1800,1800,1800 OBJ pst : "Parallax Serial Terminal" PUB Main | temp pst.Start(115_200) pause(200) DisplayOnTimerTable pst.char(13) DisplayOffTimerTable pst.char(13) SetOnTime(3,3,100) SetOffTime(3,3,100) DisplayOnTimerTable pst.char(13) DisplayOffTimerTable pst.char(13) PUB DisplayOnTimerTable | x, y, index repeat y from 0 to ROWS - 1 repeat x from 0 to COLUMNS - 1 pst.dec(GetOnTime(x, y)) pst.char($20) pst.char(13) PUB DisplayOffTimerTable | x, y, index repeat y from 0 to ROWS - 1 repeat x from 0 to COLUMNS - 1 pst.dec(GetOffTime(x, y)) pst.char($20) pst.char(13) PUB SetOnTime(column, row, value) | index index := (row-1) * COLUMNS + (column-1) Zone0OnTime[index] := value PUB GetOnTime(column, row) | index index := (row * COLUMNS) + column return Zone0OnTime[index] PUB SetOffTime(column, row, value) | index index := (row-1) * COLUMNS + (column-1) Zone0OffTime[index] := value PUB GetOffTime(column, row) | index index := row * COLUMNS + column return Zone0OffTime[index] PRI Pause(Duration) waitcnt(((clkfreq / 1_000 * Duration - 3932) #> 381) + cnt) return
For more info on DAT structures see http://www.parallaxsemiconductor.com/an003Now you have the ability to index into the tables. All that's left, is sending the data. There are many ways to get the data to the Spinneret. You could send the entire table in a POST or one value at a time.
A RESTfull approach the URL might look like
my.server.ip.address:port\ontime\3\3\100
Set the on-time table, column 3, row 3, with value 100my.server.ip.address:port\ontime\3\3
Get the on-time table, column 3, row 3In your HTTPServer DAT section, what's the use for the remoteIP var?
http://spinneret.servebeer.com:5000/gstart/setup.htm
This IP address is agaverobotics.com which contains several supporting web pages for the client tutorials.
DAT remoteIp byte 65, 98, 8, 151 {65.98.8.151}
You can use any IP you like.