Shop OBEX P1 Docs P2 Docs Learn Events
[Contest Entry] Multi-Socket Server — Parallax Forums

[Contest Entry] Multi-Socket Server

Mike GMike G Posts: 2,702
edited 2013-10-02 03:26 in Accessories
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.
«134

Comments

  • FredBlaisFredBlais Posts: 370
    edited 2011-07-25 07:28
    Hi Mike G,

    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 :)
  • D.PD.P Posts: 790
    edited 2011-07-26 14:44
    Really nice job. This "demo" shows what can be done on this platform. I have a precision ruggedized RH/Temp sensor that I will be "hosting" on the spinneret in the near future and appreciate all the effort you have contributed to the spinneret code base. Hat tip to all the other people not mentioned.
  • Brian CarpenterBrian Carpenter Posts: 728
    edited 2011-07-28 22:46
    Mike,
    How would i run this on my spinneret at home? Is there an archive that rolls it all up nicely?
  • Mike GMike G Posts: 2,702
    edited 2011-07-29 08:28
    How would i run this on my spinneret at home?
    Load HTTPServer
    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
  • Mike GMike G Posts: 2,702
    edited 2011-07-31 15:52
    Here’s my contest entry. The manual and project description is running on the spinneret.
    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
  • JeffaJeffa Posts: 80
    edited 2011-07-31 17:39
    Lookin' good Mike!
  • Mike GMike G Posts: 2,702
    edited 2011-07-31 19:13
    Thanks Jeffa

    I wish I had more time... Didn't get to UDP.

    This has been an awesome learning experience.
  • FredBlaisFredBlais Posts: 370
    edited 2011-08-01 15:17
    Hi Mike,
    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!
  • Mike GMike G Posts: 2,702
    edited 2011-08-02 07:23
    FredBlais, I have never been able to get the default SPI driver working. Do you have a working copy of the SPI driver running on your Spinneret?
  • FredBlaisFredBlais Posts: 370
    edited 2011-08-02 08:16
    In fact, I'm doing my own board based on the spinneret, I don't own one.
    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.
  • Mike GMike G Posts: 2,702
    edited 2011-08-02 10:46
    My SPI driver experience is very limited , just because I had problems does not mean the SPI drive is the issue. I believe other forum members had success with the SPI drive.

    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?
  • FredBlaisFredBlais Posts: 370
    edited 2011-08-02 13:11
    Mike G wrote: »
    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
  • Mike GMike G Posts: 2,702
    edited 2011-08-02 13:26
    FredBlais wrote:
    All I want to know is if someone can run your code but by replacing the indirect by the spi driver.
    No, it's not a simple replace. I modified the base indirect driver; SPIN and PASM. Please see the source code for details.
  • Brian CarpenterBrian Carpenter Posts: 728
    edited 2011-08-05 18:54
    Mike,
    How/ where are you setting the time on the RTC?
  • Mike GMike G Posts: 2,702
    edited 2011-08-05 19:40
    I'm using Kye's S35390A_RTCEngine.
  • Brian CarpenterBrian Carpenter Posts: 728
    edited 2011-08-05 20:33
    ok, but what i dont see is where you are setting the time. Where/ how is that being accomplished and what is providing the information to the object?
  • Mike GMike G Posts: 2,702
    edited 2011-08-05 21:02
    I created a web page that formats the current time so it is easily consumed.
    http://www.agaverobotics.com/spinneret/datetime.aspx
  • Brian CarpenterBrian Carpenter Posts: 728
    edited 2011-08-05 21:07
    So.. you point to it from the spinneret and grab the time and set it into the rtc?
  • Mike GMike G Posts: 2,702
    edited 2011-08-05 21:16
  • Brian CarpenterBrian Carpenter Posts: 728
    edited 2011-08-05 21:28
    i am using his object currently. Sorry it took me so long to get this into my head.
  • Mike GMike G Posts: 2,702
    edited 2011-08-07 08:33
    Integrated Beau's SNTP code into HTTPServer.spin.

    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           
    '&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;       
              sntp.GetTransmitTimestamp(Zone,@tempBuff,@LongHIGH,@LongLOW)
    
    '               Display Reference/Sync TimeZone corrected Time           
    '&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;       
              'DisplayHumanTime
    
    '                         Set RTC to Internet Time
             pst.str(string(13, "SET RTC"))
    '&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;&#8776;
             {{ 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.
  • Brian CarpenterBrian Carpenter Posts: 728
    edited 2011-08-11 23:19
    i want to display and edit in a table a DAT file via an HTTP connection. Is that doable with the framework you have set here?
    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
    
  • Mike GMike G Posts: 2,702
    edited 2011-08-11 23:40
    If you need to update memory values, create SPIN methods to handle the GETs and SETs. From there it's just a matter of sending the data. UDP would probably be the easiest for creating the whole table. Otherwise set a GET like myurl?idx=0&value=500.

    I kinda doubt you want to create a DAT file. Unless you have a procedure to compile the DAT file.
  • Brian CarpenterBrian Carpenter Posts: 728
    edited 2011-08-12 17:22
    that DAT file that i posted is the starting point. I want to be able to adjust those times via a network connections. I guess they will all need to be variable arrays.
  • Mike GMike G Posts: 2,702
    edited 2011-08-13 07:37
    Brian, a DAT block is an array. Here's an example.
    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/an003

    Now 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 100
    my.server.ip.address:port\ontime\3\3
    
    Get the on-time table, column 3, row 3
  • TumblerTumbler Posts: 323
    edited 2011-08-16 00:10
    Mike,

    In your HTTPServer DAT section, what's the use for the remoteIP var?
  • Mike GMike G Posts: 2,702
    edited 2011-08-16 07:01
    The remoteIP var holds the IP address of a remote server.
    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.
  • PaulPaul Posts: 263
    edited 2011-08-19 13:10
    Mike, FYI: Your images on http://spinneret.servebeer.com:5000 are having some problems being shown. Sometimes they start to load and just quit or blink off. Thought you would like to know.
  • Mike GMike G Posts: 2,702
    edited 2011-08-19 13:28
    Thanks Paul, which images are you referring to, the links? What browser are you using and platform?
  • william chanwilliam chan Posts: 1,326
    edited 2011-08-22 17:26
    If a browser tries to make lets say 8 simultaneous socket connections to HTTPServer, will it result in error messages or will the 5-8 connections politely wait their turn for a free wiznet socket each?
Sign In or Register to comment.