Shop OBEX P1 Docs P2 Docs Learn Events
Setting Spinneret time from a web page on the SD Card — Parallax Forums

Setting Spinneret time from a web page on the SD Card

xanatosxanatos Posts: 1,120
edited 2013-06-26 14:13 in Accessories
Here's where I get to show how woefully tiny my knowledge is, despite weeks of messing with this thing.

What I want to do is have a webpage on the SD card that someone can enter in the date and time into the appropriate fields for each element, hit the submit button, and have it change the RTC time & date setting.

My RTC stuff is working well, and I can read the time/date info and put it in an email and send it all along just fine. But here's the latest that I've tried, unsuccessfully - obviously - to enter the time and date, and have it set the RTC:

I have created up in the VAR section my CKSetArray:
VAR
  long StackSpace[20]
  byte EEArray[10]                ' For 24LC256 EEPROM data reads for sending email with data embedded.
  byte CKSetArray[6]              ' For RTC data setting from web interface.


And I'm running this under the Dispatcher:
PRI Dispatcher(id)
    ''Do some processing before sending the response
    if(strcomp(Request.GetName(id), string("led")))
        Led(id)
    if(strcomp(Request.GetName(id), string("post")))
            Post(id)            
    StaticFileHandler(id)
    return

PRI Post(id) | qstr
    '' Get the post value
    CKSetArray[6] :=  Request.Post(id, string("Syear"))
    CKSetArray[5] :=  Request.Post(id, string("Smonth"))
    CKSetArray[4] :=  Request.Post(id, string("Sdate"))
    CKSetArray[3] :=  Request.Post(id, string("Sday"))
    CKSetArray[2] :=  Request.Post(id, string("Shour"))
    CKSetArray[1] :=  Request.Post(id, string("Sminute"))
    CKSetArray[0] :=  Request.Post(id, string("Ssecond"))
    
    pst.str(CKSetArray[6])
    pst.str(CKSetArray[5])
    pst.str(CKSetArray[4])
    pst.str(CKSetArray[3])
    pst.str(CKSetArray[2])
    pst.str(CKSetArray[1])
    pst.str(CKSetArray[6])
    

    'rtc.writeTime(CKSetArray[0], CKSetArray[1], CKSetArray[2], CKSetArray[3], CKSetArray[4], CKSetArray[5], CKSetArray[6]) 'SET THE RTC (second, minute, hour, day, date, month, year)

:

Syear, Smonth, etc., are the variable names (the input tag names) in the hrml file on my SD card.

I have, for now, commented out my rtc.writeTime line - which works well on its own. I've got the variables just outputting to the Parallax Serial Terminal for now, and I've tried pst.str, which yields blank spaces, and pst.dec, which yields all sorts of odd characters, but nothing I've tried so far yields anything close to the characters I'm entering.

ALSO... as a side note - I've discovered that my Spinneret will not find any filename on the SD Card longer than 7 characters. testlog.htm works fine, but testfile.htm will not. I get a 404. I've tried this with several filenames - the only thing in common is the 7 character limitation. Any ideas how I managed that? :-) I found this out while trying to get xmlexample.htm to work. Got a 404. Spent an hour swapping things in and out to get it to find the file, eventually had nothing but html and body tags with the text "test" in it. Still got a 404. Just renamed the file to test.htm, and it found it just fine.

Thanks!

Dave

Comments

  • Mike GMike G Posts: 2,702
    edited 2013-06-25 09:45
    I've got the variables just outputting to the Parallax Serial Terminal for now, and I've tried pst.str, which yields blank spaces, and pst.dec, which yields all sorts of odd characters, but nothing I've tried so far yields anything close to the characters I'm entering.
    It is impossible to provide guidance when presented with a small snippet of code. In most cases the error is elsewhere. Please attach the HTML form used to post the data.
    ALSO... as a side note - I've discovered that my Spinneret will not find any filename on the SD Card longer than 7 characters. testlog.htm works fine, but testfile.htm will not. I get a 404. I've tried this with several filenames - the only thing in common is the 7 character limitation. Any ideas how I managed that? :-) I found this out while trying to get xmlexample.htm to work. Got a 404. Spent an hour swapping things in and out to get it to find the file, eventually had nothing but html and body tags with the text "test" in it. Still got a 404. Just renamed the file to test.htm, and it found it just fine.
    I verified HttpServer renders 8 character file names. This is an example straight from the online manual that resides on a Spinneret sitting on my desk. This rig has been running for over two years.
    http://68.99.247.152:5000/images/pstbinup.png
  • xanatosxanatos Posts: 1,120
    edited 2013-06-25 09:55
    Hi Mike,

    Here's the html form I'm using, filename=post.htm
        <html>
        <head>
            <title>POSTing to the Server</title>
        </head>
        <body>
            <div style="width:600px;margin:auto;">
                <h1>System Administrative Functions</h1>
                <form id="post" name="post" method="post">
                <h2>Set the system date and time:</h2>
                
                
                <input id="Smonth" name="Smonth" type="text" size=2><span style="font size:20pt;font-weight:bolder;">/</span><input id="" name="Sdate" type="text" size=2><span style="font size:20pt;font-weight:bolder;">/20</span><input id="Syear" name="Syear" type="text" size=2> - 
                <input id="Sdate" name="Sday" type="hidden" value=0>
                <input id="Shour" name="Shour" type="text" size=2><span style="font size:20pt;font-weight:bolder;">:</span><input id="Sminute" name="Sminute" type="text" size=2><span style="font size:20pt;font-weight:bolder;">:</span><input id="Ssecond" name="Ssecond" type="text" size=2><br>
    			<!-- LED:<input id="led" type="text" name="led" /> -->
                <input type="submit" name="Submit" value="Click to set time and date" />
                </form>
            </div>
        </body>
        </html>       
    
    

    Thanks for helping... I'n so far over my head... but I'm still miles ahead of where I was a few weeks ago, many thanks to you.
  • Mike GMike G Posts: 2,702
    edited 2013-06-25 11:05
    The form POSTs to the current page.
    <form id="post" name="post" method="post">
    

    The Dispatch is looking for "post" so I assume it the file name on the disk is post.htm.
    if(strcomp(Request.GetName(id), string("post")))
                Post(id)
    
    The filter above is true regardless of the HTTP action, GET or POST. You don't want that... this is better
    if(strcomp(Request.GetName(id), string("post")) AND strcomp(Request.GetMethod(id), string("POST")))
    

    I'm not sure how CKSetArray[] is declared but it must be a long. The Request.Post returns a string pointer.
    long CKSetArray[7] 
    

    The entire IF block test should look like the following. I verified this functionality.
      if(strcomp(Request.GetName(id), string("post")) AND strcomp(Request.GetMethod(id), string("POST")))
        pst.char(13)
        pst.str(Request.GetFileName(id))
        pst.char(13)
        CKSetArray[6] :=  Request.Post(id, string("Syear"))
        CKSetArray[5] :=  Request.Post(id, string("Smonth"))
        CKSetArray[4] :=  Request.Post(id, string("Sdate"))
        CKSetArray[3] :=  Request.Post(id, string("Sday"))
        CKSetArray[2] :=  Request.Post(id, string("Shour"))
        CKSetArray[1] :=  Request.Post(id, string("Sminute"))
        CKSetArray[0] :=  Request.Post(id, string("Ssecond"))
    
        pst.str(CKSetArray[6])
        pst.char(13) 
        pst.str(CKSetArray[5])
        pst.char(13) 
        pst.str(CKSetArray[4])
        pst.char(13) 
        pst.str(CKSetArray[3])
        pst.char(13) 
        pst.str(CKSetArray[2])
        pst.char(13) 
        pst.str(CKSetArray[1])
        pst.char(13) 
        pst.str(CKSetArray[6])
    

    In the future, please post all your source code. Otherwise I have to guess which it is a bit of a time blackhole.
  • xanatosxanatos Posts: 1,120
    edited 2013-06-25 11:29
    I had my CKSetArray[x] set as byte, not long. This may explain it - I will be home in a couple of hours and try out what you have shown. I'm happy at least that my attempted code wasn't completely out in left field, I may actually be learning stuff here. Thanks again.
  • xanatosxanatos Posts: 1,120
    edited 2013-06-25 15:48
    That was it. Changing "byte CKSetArray[7]" to "long CKSetArray[7]" made all the difference. The numbers are getting through correctly. THANK YOU!

    For the remaining question here, in the interest of full code disclosure, here is teh full HTTPServer.spin that I am running - but it will be followed by the parts that I am pretty sure are the only ones needed to see where I am in error.

    HTTPServer.spin as I've modified it, in full:
    {{
    &#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; 
    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        
    &#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; 
    }}
    
    {
    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:
            &#8226; Parallax Serial Terminal.spin
            &#8226; W5100_Indirect_Driver.spin
            &#8226; S35390A_SD-MMC_FATEngineWrapper.spin
            &#8226; Request.spin
            &#8226; Response.spin
            &#8226; StringMethods.spin
            &#8226; 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           = $05
      MAX_TRIES       = $05               
    
      #0, DONE, PUT, CD
                                               
    
    DAT
      mac                   byte    $00, $08, $DC, $16, $F3, $D3     
      subnet                byte    255, 255 ,255, 0
      gateway               byte    192, 168, 1, 1 
      ip                    byte    192, 168, 1, 120
      port                  word    5000
      remoteIp              byte    65, 98, 8, 151 {65.98.8.151}
      remotePort            word    80
      uport                 word    5050 
      emailIp               byte    8, 24, 153, 30    
      emailPort             word    587     ''587     ''110       ''25
      port2                 word    5010
      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
      dynamicContentPtr     long    @txdata
      tankfile              byte    "tankfarm.csv", 0
    
                  
    VAR
      long StackSpace[20]
      byte EEArray[10]                ' For 24LC256 EEPROM data reads for sending email with data embedded.
      long CKSetArray[7]              ' For RTC data setting from web interface.
    
    OBJ
      pst           : "Parallax Serial Terminal"
      Socket        : "W5100_Indirect_Driver"
      SDCard        : "S35390A_SD-MMC_FATEngineWrapper"
      Request       : "Request"
      Response      : "Response"
      str           : "StringMethods"
      rtc           : "S35390A_RTCEngine"
      nums          : "Simple_Numbers_plus"    ' "Numbers"
    
    
    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)
    
      'rtc.writeTime(0, 15, 18, 0, 25, 6, 2013)  ' (second, minute, hour, day, date, month, year)
      '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
      ''GetMyIp(3)
      ''clockandemail
      
      repeat
    
          
    
    
          dira[22] := 0  '' Sets 22 to input       ''  This block watches the buffered IO on P22 for a 0 signal, and
          if ina[22] == 0                          ''  it sends the email when there is a low pulse.  It also fires off the LED
             dira[23]~~                            ''  just because... why not.
             outa[23] := 1 ''ina[22]
             'TankLog(string("XTM-MAN,01,G.H. Berlin/Windward,ID1,Manchester NH,001,Product,06/11/2013 19:00:00,000.00,100.00"))
             pause(DELAY)
             SendTestEmail(2)
             outa[23] := 0 ''ina[22] 
      
    
          
      
        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/500) + 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 SendTestEmail(id) | size, tempMask, wait, stringPointer, tankNum, tankStr, Yr, Mo, Dy, Hr, Mn, Sc
        
        tempMask := tcpMask
        SetTcpSocketMaskById(id, 0)
        
        wait := 200
        
        Socket.Close(id)
        pause(delay)
        InitializeSocketForEmail(id)
        pause(delay)
        
        ' Connect to the mail server
        pst.str(string(13, "Connecting to mail server"))
        
        Socket.Connect(id)
        pause(wait)
        repeat while !Socket.Connected(id)
        
        pst.str(string(13,"Connected... Talking with mail server"))
        
        'Send greeting
        StringSend(id, string("EHLO xanatos@xanatos.com", 13, 10))
        pause(wait)
        
    '==============================================================================
        StringSend(id, string("AUTH LOGIN", 13,10))
        pause(wait)
    
    '   'Send user name
        StringSend(id, string("eGFuYXRvc0B4YW5hdG9zLmNvbQ==", 13, 10))   
    '
    '
    '   'Send password
        StringSend(id, string("cGVhY2VhbmR0cmFucXVpbGl0eQ==", 13, 10))  
    '==============================================================================
    
        ' From Address
        StringSend(id, string("MAIL FROM: *******@*******.com", 13, 10))
        pause(wait)
        
        ' To Address
        StringSend(id, string("RCPT TO: *******@*******.com", 13, 10))
        pause(wait)
    
        ' To Address
        'StringSend(id, string("RCPT TO:*******@*******.com", 13, 10))      
        'pause(wait)
    
        'Start of the email content
        StringSend(id, string("DATA", 13, 10))
        pause(wait)
    
        'Visible From line
        StringSend(id, string("From: *******@*******.com", 13, 10))
        pause(wait)
    
        'Visible To line
        StringSend(id, string("To: *******@*******.com", 13, 10))
        pause(wait)
    
        'Subject line
        StringSend(id, string("SUBJECT: Email from the Spinneret", 13, 10))
        pause(wait)
    
        'Mime-Type
        StringSend(id, string("Mime-Version: 1.0", 13, 10))
        pause(wait)
    
        'Content Type
        StringSend(id, string("Content-Type: text/plain; charset=us-ascii", 13, 10, 13, 10))
        pause(wait)
    
        Mo := rtc.clockMonth
        Dy := rtc.clockDate
        Yr := rtc.clockYear
        Hr := rtc.clockHour
        Mn := rtc.clockMinute
        Sc := rtc.clockSecond
        
        repeat tankNum from 1 to 16
    
          StringSend(id, string("XTM-MAN,"))
          StringSend(id, string("01,0,0,0,"))
          StringSend(id, nums.decn(tankNum, 3))
          StringSend(id, string(",0,"))
          StringSend(id, nums.decn(Mo, 2))
          StringSend(id, string("/"))
          StringSend(id, nums.decn(Dy, 2))
          StringSend(id, string("/"))
          StringSend(id, nums.decn(Yr, 4))
          StringSend(id, string(" "))
          StringSend(id, nums.decn(Hr, 2))
          StringSend(id, string(":"))
          StringSend(id, nums.decn(Mn, 2))
          StringSend(id, string(":"))
          StringSend(id, nums.decn(Sc, 2))
          StringSend(id, string(","))
          StringSend(id, string("000.00,"))
          StringSend(id, string("050.00", 13, 10))
          pause(wait)
    
    
    
        'Quit conversation
        StringSend(id, string(".", 13, 10))
        pause(wait)
        
        StringSend(id, string("QUIT", 13, 10))
        pause(wait)
        
        pst.str(string(13,"Done",13))
        pst.str(string(13,"Conversation Log",13))
        
        'Display log
        repeat until size := Socket.rxTCP(id, @rxdata)
        pst.str(@rxdata)
        
        pst.str(string(13, "Disconnect and reset socket: "))
        pst.dec(id)
        pst.char(13)
        
        ' Reset the socket
        Socket.Disconnect(id)
        pause(delay)
        
        ' Reset the tcpMask 
        tcpMask := tempMask
        
        InitializeSocket(id)
        pause(delay)
        
        return
    
    
    
    '=======================================================================================
    PUB clockandemail 
    
      'SET THE CLOCK
      '(second, minute, hour, day, date, month, year)
    
      'rtc.writeTime(00, 10, 20, 2, 10, 6, 2013) 'SET THE RTC    
     
      repeat
                
          waitcnt(clkfreq/5+cnt)         
          rtc.readtime
     
          pst.str(string("            "))   
          pst.dec(rtc.clockHour)
          pst.str(string(":"))    
          pst.dec(rtc.clockMinute)
          pst.str(string(":"))  
          pst.dec(rtc.clockSecond)
          pst.str(string(" ",13 ))
           
    
          if rtc.clockMinute//10 == 0
           
              waitcnt(clkfreq/5+cnt)   'wait for stuff to stop
              SendTestEmail(2)         'INITIALIZES THE SOCKET AND sends the email
              waitcnt(clkfreq/5+cnt)   'wait for stuff to stop
    
    
    '=======================================================================================
    
    
    PRI GotoMain
      Main
    
    
    PRI InitializeSocketForEmail(id)
        Socket.Initialize(id, TCP_PROTOCOL, port2, emailPort, @emailIp)
        return
    
    PRI InitializeSocket2(id)
      Socket.Initialize(id, TCP_PROTOCOL, port2, remotePort, @remoteIp)
      return
    
    PRI Dispatcher(id)
        ''Do some processing before sending the response
        if(strcomp(Request.GetName(id), string("led")))
            Led(id)
        'if(strcomp(Request.GetName(id), string("post")))
        if(strcomp(Request.GetName(id), string("post")) AND strcomp(Request.GetMethod(id), string("POST")))
                Post(id)            
        StaticFileHandler(id)
        return
    
    PRI Post(id) | qstr, Yr, Mo, Dy, Hr, Mn, Sc
        '' Get the post value
        CKSetArray[6] :=  Request.Post(id, string("Syear"))
        CKSetArray[5] :=  Request.Post(id, string("Smonth"))
        CKSetArray[4] :=  Request.Post(id, string("Sdate"))
        CKSetArray[3] :=  Request.Post(id, string("Sday"))
        CKSetArray[2] :=  Request.Post(id, string("Shour"))
        CKSetArray[1] :=  Request.Post(id, string("Smin"))
        CKSetArray[0] :=  Request.Post(id, string("Ssec"))
    
        pst.char(13) 
        pst.str(CKSetArray[5])
        pst.str(string("/"))
        pst.str(CKSetArray[4])
        pst.str(string("/"))
        pst.str(CKSetArray[6])
        pst.char(13)
        pst.str(CKSetArray[2])
        pst.str(string(":"))
        pst.str(CKSetArray[1])
        pst.str(string(":"))
        pst.str(CKSetArray[0])
        pst.char(13)
        pst.str(CKSetArray[3])
        pst.char(13)
        
         
        rtc.writeTime(CKSetArray[0], CKSetArray[1], CKSetArray[2], CKSetArray[3], CKSetArray[4], CKSetArray[5], CKSetArray[6]) 'SET THE RTC (second, minute, hour, day, date, month, year)
        waitcnt(500+cnt)
    
        Mo := rtc.clockMonth
        Dy := rtc.clockDate
        Yr := rtc.clockYear
        Hr := rtc.clockHour
        Mn := rtc.clockMinute
        Sc := rtc.clockSecond
    
    
        pst.char(13)
        
        pst.str(nums.decn(Mo, 2))
        pst.char(13)
        pst.str(nums.decn(Dy, 2))
        pst.char(13)
        pst.str(nums.decn(Yr, 4))
        pst.char(13)
        pst.str(nums.decn(Hr, 2))
        pst.char(13)
        pst.str(nums.decn(Mn, 2))
        pst.char(13)
        pst.str(nums.decn(Sc, 2))
        
        pst.char(13)
    
    
        'qstr :=  Request.Post(id, string("led"))
        'if (strcomp(string("on"), qstr ))
        '    LedStatus(1)
        '    pst.str(string(" - on",13,10))
        'else
        '    LedStatus(0)
        '    pst.str(string(" - off",13,10)) 
        return
            
    PRI Led(id) | qstr
        '' Get the query string value
        qstr :=  Request.Get(id, string("led"))
        if (strcomp(string("on"), qstr ))
            LedStatus(1)
        else
            LedStatus(0)
            pst.str(string(" - off",13,10))   
        return
        
    PRI LedStatus(state)
        dira[23]~~
        outa[23] := state
        return
            
    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
    
    
      
    ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    '' SDCard Logger
    ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    PRI TankLog(logToAppend)
      '' logToAppend:  Pointer to a string of text we'd like to log
      SDCard.changeDirectory(@approot) 
    
      if(FileExists(@tankfile))
        SDCard.openFile(@tankfile, "A")
      else
        SDCard.newFile(@tankfile)
    
      SDCard.writeData(logToAppend, strsize(logToAppend))
      SDCard.writeData(@crlf_crlf, 2)
    
      SDCard.closeFile
    
      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
    
      
    ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    '' Write data to a buffer
    ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    PRI PushDynamicContent(content)
      ' Write the content to memory
      ' and update the pointer
      bytemove(dynamicContentPtr, content, strsize(content))
      dynamicContentPtr := dynamicContentPtr + strsize(content)
      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 text 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)
      
    
    ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    '' Socket 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 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"                 
    
    {{
    &#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;&#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;                                                   TERMS OF USE: MIT License                                                  &#9474;                                                            
    &#9500;&#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;&#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;&#9508;
    &#9474;Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation    &#9474; 
    &#9474;files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,    &#9474;
    &#9474;modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software&#9474;
    &#9474;is furnished to do so, subject to the following conditions:                                                                   &#9474;
    &#9474;                                                                                                                              &#9474;
    &#9474;The above copyright notice and this permission notice shall be included in all copies or substantial ions of the Software.&#9474;
    &#9474;                                                                                                                              &#9474;
    &#9474;THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE          &#9474;
    &#9474;WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR         &#9474;
    &#9474;COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,   &#9474;
    &#9474;ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                         &#9474;
    &#9492;&#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;&#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;&#9496;
    }}
    

    I won't post "post.htm" because we know that's working - the numbers are unquestionably making it into the Propeller on the Spinneret because I can pst.str them to the PST window.

    The question is "What does the rtc.writeTime line expect for data type?"

    I have tried my CKSetArray[x] alone, with string(), and with nums.decn(CKSetArray[x], 2))... and several other things that just didn't work. Here's the code I have where the dispatcher DOES parse the values properly, then I set the time with rtc.writeTime(), then I read the individual variables - and they are NOT what I wrote. First the code - then the next window is the display of the PST output.

    Code of section in question:
    PRI Dispatcher(id)
        ''Do some processing before sending the response
        if(strcomp(Request.GetName(id), string("led")))
            Led(id)
        'if(strcomp(Request.GetName(id), string("post")))
        if(strcomp(Request.GetName(id), string("post")) AND strcomp(Request.GetMethod(id), string("POST")))
                Post(id)            
        StaticFileHandler(id)
        return
    
    PRI Post(id) | qstr, Yr, Mo, Dy, Hr, Mn, Sc
        '' Get the post value
        CKSetArray[6] :=  Request.Post(id, string("Syear"))
        CKSetArray[5] :=  Request.Post(id, string("Smonth"))
        CKSetArray[4] :=  Request.Post(id, string("Sdate"))
        CKSetArray[3] :=  Request.Post(id, string("Sday"))
        CKSetArray[2] :=  Request.Post(id, string("Shour"))
        CKSetArray[1] :=  Request.Post(id, string("Smin"))
        CKSetArray[0] :=  Request.Post(id, string("Ssec"))
    
        pst.char(13) 
        pst.str(CKSetArray[5])
        pst.str(string("/"))
        pst.str(CKSetArray[4])
        pst.str(string("/"))
        pst.str(CKSetArray[6])
        pst.char(13)
        pst.str(CKSetArray[2])
        pst.str(string(":"))
        pst.str(CKSetArray[1])
        pst.str(string(":"))
        pst.str(CKSetArray[0])
        pst.char(13)
        pst.str(CKSetArray[3])
        pst.char(13)
        
         
        rtc.writeTime(CKSetArray[0], CKSetArray[1], CKSetArray[2], CKSetArray[3], CKSetArray[4], CKSetArray[5], CKSetArray[6]) 'SET THE RTC (second, minute, hour, day, date, month, year)
        waitcnt(500+cnt)
    
        Mo := rtc.clockMonth
        Dy := rtc.clockDate
        Yr := rtc.clockYear
        Hr := rtc.clockHour
        Mn := rtc.clockMinute
        Sc := rtc.clockSecond
    
    
        pst.char(13)
        
        pst.str(nums.decn(Mo, 2))
        pst.char(13)
        pst.str(nums.decn(Dy, 2))
        pst.char(13)
        pst.str(nums.decn(Yr, 4))
        pst.char(13)
        pst.str(nums.decn(Hr, 2))
        pst.char(13)
        pst.str(nums.decn(Mn, 2))
        pst.char(13)
        pst.str(nums.decn(Sc, 2))
        
        pst.char(13)
    
        return
    

    And output of the PST window - the first section is entering time values and date values like 01/23/2045 and 12:34:56; the next one I just entered 11/11/11 and 22:22:22. Note that the output obtained after reading the RTC is the same, with a year of 2099, etc. Note ALSO that if I manually set the rtc at the initialization routine of HTTPServer.spin, comment out the setting line in the post handler, and read the values for the time and date, they DO read correctly. It's ONLY when I try to set the rtc with the values obtained from the post that they go to the values indicated:
    ----- Start of Request----------------------------
    
    ID: 0
    Request Count     : 2
    
    POST /post.htm
    12/34/56
    01:23:45
    
    
    12
    31
    2099
    23
    59
    59
    
    
    ----- Start of Request----------------------------
    
    ID: 0
    Request Count     : 3
    
    POST /post.htm
    11/11/11
    22:22:22
    
    
    12
    31
    2099
    23
    59
    59
    
    

    I'm guessing that that 12/31/2099 at 23:59:59 is some sort of value that equates to the max time/date of the Spinneret... and I'm assuming that it's due to my sending the numbers in teh wrong format. Note that the reading and writing of the values I am sending from my post.htm form is fine - only the setting of the rtc and reading those values back creates the error.

    I'm continuing to try sending various data types, but I just don't yet know enough to know everything I should be sending - or that I can send... and I'm not sure yet of where to find that info. A search of "setting RTC time date Spinneret" hasn't yet yielded the nugget I seem to be missing...

    Thanks again...... I hope I can find a way to pay this forward.

    Dave
  • Mike GMike G Posts: 2,702
    edited 2013-06-25 15:56
    Be careful doing this...
    CKSetArray[0] :=  Request.Post(id, string("Ssecond"))
    

    All you're doing is copying a pointer. The pointer is only good for the duration of the request/response. If you need to store the data - so the data persists between requests - then move the bytes to a buffer. Otherwise *poof* unexpected results.

    It is much better to update the RTC using SNTP. There are examples on the forum. The newer driver handles SNTP time automatically [nudge nudge hint hint].
    http://code.google.com/p/propeller-w5200-driver/source/browse/trunk/#trunk%2F%20propeller-w5200-driver%2FSpinneret
  • Mike GMike G Posts: 2,702
    edited 2013-06-25 16:04
    The RTC object contains metadata that describes how the method fucnitons
    PUB writeTime(second, minute, hour, day, date, month, year) | index, information[7] '' 33 Stack Longs
    
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '' // Changes the current real time clock time settings. Returns true on success and false on failure.
    '' //
    '' // Second - Number to set the second to between 0 - 59.
    '' // Minute - Number to set the minute to between 0 - 59.
    '' // Hour - Number to set the hour to between 0 - 23.
    '' // Day - Number to set the day to between 1 - 7.
    '' // Date - Number to set the date to between 1 - 31.
    '' // Month - Number to set the month to between 1 - 12.
    '' // Year - Number to set the year to between 2000 - 2099.
    '' //
    '' // If the real time clock was previously powered on but not initialized this method will initialize the real time clock
    '' // setting all registers to zero and clearing all interrupts. After doing so the time and date will be setup.
    '' //
    '' // If the real time clock previously browned out but was not re-initialized this method will re-initialize the real time
    '' // clock setting all registers to zero and clearing all interrupts. After doing so the time and date will be setup.
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    

    The statement below passes a pointer value to each of the writeTime parameters. The pointer is a string pointer. The string contains ASCII encoded characters which means the values are not numbers. They are codes that represent numbers.
    rtc.writeTime(CKSetArray[0], CKSetArray[1], CKSetArray[2], CKSetArray[3], CKSetArray[4], CKSetArray[5], CKSetArray[6])
    

    What ya need to do is convert the ASCII strings to numbers. Then pass the numbers to the writeTime method.

    It is far easier and less code to use the SNTP object.
  • xanatosxanatos Posts: 1,120
    edited 2013-06-25 16:12
    OK... this I did not know. I *thought* that once I set CKSetArray[x] with the value of the Request.Post, it would persist. It persists long enough for me to write to the screen of the PST. So you're saying that the value of CKSetArray[x} will change after a few clock cycles, despite having been set equal to the value of the Request.Post... but that in reality, the value I'm setting is NOT the actual data I think I'm seeing, but only the value of a pointer TO IT? Have I got this right?

    I have in fact seen the SNTP stuff in the OBEX and in several posts. My question about this - since I saw one post that seemed to indicate that an SNTP server can go down/disappear - is, How reliable is the SNTP setting function over extended time? Once this whole thing is running, I won't have convenient access to it, so I wouldn't want to have to fly out just to change a server address. Can the SNTP functions be relied on over time without worry?

    Lastly - while I am stressing out over when I promised that this would be ready by, I'm really enjoying the learning aspects of all the many areas I'm trying to come up to speed on simultaneously. And while it may turn out that SNTP is the way to go, I still feel there is a lot to learn by completing my understanding of why my time setting routine is not working as expected. I'd like to understand exactly WHAT IS a buffer in this context, and how would I change my CKSetArray[x] values to hold the actual VALUE rather than a pointer to them... this seems to be an important understanding that I feel like I am on the verge of understanding, but I'm just not seeing over that particular hill yet.

    Thanks. I hope I'm not annoying with all my requests, but I do learn well and I'm persistent as hell, which is why I have become so proficient with the Stamps. I really want to be that confident with the Propeller, but I still feel like a preschooler - and as far as I can tell, you're the most knowledgeable in these areas, and I really appreciate your willingness to guide me to understanding what I'm doing...

    Dave

    PS., I posted this while you were responding above... reading now. Can I buy ya a beer or something? :-)
  • xanatosxanatos Posts: 1,120
    edited 2013-06-25 16:21
    Mike G wrote: »

    What ya need to do is convert the ASCII strings to numbers. Then pass the numbers to the writeTime method.

    I thought I did that when I used the format:
    rtc.writeTime(nums.decn(CKSetArray[0], 2), nums.decn(CKSetArray[0], 2), ......................
    
    

    Where nums is the numbers object I'm using and set in my OBJ block shown in my full code in the first post. So if converting my CKSetArray using nums isn't doing the trick - I am obviously not understanding how nums is working either... :-)

    Thanks... feeling way over my depth here.... :-)

    Dave
  • xanatosxanatos Posts: 1,120
    edited 2013-06-25 16:37
    OK... examining the data actually contained in CKSetArray[0], I get this number: 31208

    Is this a pointer to a location in memory?

    So I guess what I'm looking for is how do I specify CKSetArray[0] := "The value stored at Request.Post(id, string("Ssec"))" instead of CKSetArray[0] := "The location of the value stored at Request.Post(id, string("Ssec"))"

    Can you confirm if my understanding of this is correct?
  • Mike GMike G Posts: 2,702
    edited 2013-06-25 17:55
    OK... this I did not know. I *thought* that once I set CKSetArray[x] with the value of the Request.Post, it would persist. It persists long enough for me to write to the screen of the PST. So you're saying that the value of CKSetArray[x} will change after a few clock cycles, despite having been set equal to the value of the Request.Post... but that in reality, the value I'm setting is NOT the actual data I think I'm seeing, but only the value of a pointer TO IT? Have I got this right?
    No - not really. The data is accurate only during the request/response of the current socket. After that the data will be overwritten at some point by another request on the same socket.
    I have in fact seen the SNTP stuff in the OBEX and in several posts. My question about this - since I saw one post that seemed to indicate that an SNTP server can go down/disappear - is, How reliable is the SNTP setting function over extended time? Once this whole thing is running, I won't have convenient access to it, so I wouldn't want to have to fly out just to change a server address. Can the SNTP functions be relied on over time without worry?
    Yes, SNTP is reliable.
    [code]
    rtc.writeTime(nums.decn(CKSetArray[0], 2), nums.decn(CKSetArray[0], 2), ......................
    [code]
    The posted code did not contain a call to nums.decn. I'm not familiar with nums.decn so I can't help you there. You'll have to look at the object.
    So I guess what I'm looking for is how do I specify CKSetArray[0] := "The value stored at Request.Post(id, string("Ssec"))" instead of CKSetArray[0] := "The location of the value stored at Request.Post(id, string("Ssec"))"

    Can you confirm if my understanding of this is correct?
    You're not getting it. The value is a character (byte) array. The pointer is a memory location where the byte array starts. The byte array ends with a zero - zero terminated. That's how strings work.
  • xanatosxanatos Posts: 1,120
    edited 2013-06-25 18:20
    Now I'm even more confused.

    How is it that I can pst.str the data at CKSetArray[5] for example to the PST window, but have it not be able to put that same data into the rtc.writeTime values? You say that CKSetArray[x] contains a pointer to the data, but not the actual data itself. You say the data is a string that is zero-terminated. So my understanding at this point is that the data contained in CKSetArray[x] is a pointer to the location of the actual data I want to use, which begins at the location contained in CKSetArray[x], and ends at the first instance of that zero-terminated string... but it sounds like you are telling me that is wrong. I guess I have no idea what you are saying then - please help me get this....

    Dave
  • xanatosxanatos Posts: 1,120
    edited 2013-06-25 20:12
    OK, after a couple of hours of mainly just blindly stumbling through and trying things, looking at code all over the place and getting lost, the following is setting the clock correctly:
    PRI Post(id) | qstr, Yr, Mo, Dy, Hr, Mn, Sc
        '' Get the post value
        CKSetArray[6] :=  Request.Post(id, string("Syear"))
        CKSetArray[5] :=  Request.Post(id, string("Smonth"))
        CKSetArray[4] :=  Request.Post(id, string("Sdate"))
        CKSetArray[3] :=  Request.Post(id, string("Sday"))
        CKSetArray[2] :=  Request.Post(id, string("Shour"))
        CKSetArray[1] :=  Request.Post(id, string("Smin"))
        CKSetArray[0] :=  Request.Post(id, string("Ssec"))
    
        Sc := str.ToInteger(CKSetArray[0])
        Mn := str.ToInteger(CKSetArray[1])
        Hr := str.ToInteger(CKSetArray[2])
        Dy := str.ToInteger(CKSetArray[4])
        Mo := str.ToInteger(CKSetArray[5])
        Yr := 2000 + str.ToInteger(CKSetArray[6])
        
    
        
        pst.char(13) 
        pst.str(CKSetArray[5])
        pst.str(string("/"))
        pst.str(CKSetArray[4])
        pst.str(string("/"))
        pst.str(CKSetArray[6])
        pst.char(13)
        pst.str(CKSetArray[2])
        pst.str(string(":"))
        pst.str(CKSetArray[1])
        pst.str(string(":"))
        pst.str(CKSetArray[0])
        pst.char(13)
        pst.str(CKSetArray[3])
        pst.char(13)
    
        
         
        rtc.writeTime(Sc, Mn, Hr, 0, Dy, Mo, Yr) 'SET THE RTC (second, minute, hour, day, date, month, year)
    
        waitcnt(500+cnt)
    
    

    It also echoes to the Parallax Serial Terminal properly.

    I must be having some sort of contention going on with some other process in the Propeller's program, since when I set the time, it also stops incrementing. The emails sent out from the unit show the time as it was set, but a few minutes later - same time still shows.

    However - it must still be keeping time somewhere, because if I reload the RAM (F10), and then have it send an email with the timestamp embedded - the time has been updating internally all along.

    I am so far over my head.......
  • Mike GMike G Posts: 2,702
    edited 2013-06-25 20:19
    Your are not first person to struggle with the concept of strings and encoding. You won't be the last. I'll try to explain BUT you have to do work on your end. ASCII is "American Standard Code for Information Interchange, a set of digital codes widely used as a standard format in the transfer of text..." transfer of text mean display on a terminal or print.

    Imagine we have the decimal number 49. 49 fits comfortably in a byte data type being 49 and less than 256. To display 49 on the Parallax Terminal is easy - pst.dec(49).

    What if the number 49 is not a number but a ASCII encoded representation of 49. In other words, a string and the kind of item found in the HTTP protocol when using POST. Well, the ASCII equivalent of 49 requires two bytes. One byte for the number 4 and one byte for the number 9. In memory the string 49 looks like; [52 | 57 | 0]. The zero on the end is the end of the string - zero terminated

    The decimal value 49 prints as the number 1 and pst.dec(49) parses the decimal value 49. Dec first sends the value 52 then 57 out the serial port.

    Code to play with...
    CON
      _clkmode   = xtal1 + pll16x                           
      _xinfreq   = 5_000_000
    
      CR            = 13
    
    VAR
    
    
    DAT
      num           byte  $0
      charArray     byte  $0[10]
     
    OBJ
      pst           : "Parallax Serial Terminal"
    
    
       
    PUB Main | str 
    
      bytefill(@num, 0, 11)
    
      pst.Start(115_200)
      pause(500)
    
      'Assign and print
      num := 49  
      pst.str(string("Print Number...."))
      pst.dec(num)
      pst.char(13)
      pst.str(string("Print Char......"))
      pst.char(num)
      DisplayMemory(@num, 5, true)
      
      'Move num to a char array and view memory
      pst.str(string("Print String...."))
      charArray[0] := 52
      charArray[1] := 57
      pst.str(@charArray)
      DisplayMemory(@charArray, 5, true)
      
    
    
    PUB DisplayMemory(addr, len, isHex) | j
      pst.str(string(13,"-----------------------------------------------------",13))
      pst.str(string(13, "      "))
      repeat j from 0 to $F
        pst.hex(j, 2)
        pst.char($20)
      pst.str(string(13, "      ")) 
      repeat j from 0 to $F
        pst.str(string("-- "))
    
      pst.char(13) 
      repeat j from 0 to len
        if(j == 0)
          pst.hex(0, 4)
          pst.char($20)
          pst.char($20)
          
        if(isHex)
          pst.hex(byte[addr + j], 2)
        else
          if(byte[addr+j] < $20 OR byte[addr+j] > $7E)
            if(byte[addr+j] == 0)
              pst.char($20)
            else
              pst.hex(byte[addr+j], 2)
          else
            pst.char($20)
            pst.char(byte[addr+j])
    
        pst.char($20) 
        if((j+1) // $10 == 0) 
          pst.char($0D)
          pst.hex(j+1, 4)
          pst.char($20)
          pst.char($20)  
      pst.char(13)
      
      pst.char(13)
      pst.str(string("Start: "))
      pst.dec(addr)
      pst.str(string(" Len: "))
      pst.dec(len)
      pst.str(string(13,"-----------------------------------------------------",13,13)) 
    
    PRI pause(Duration)  
      waitcnt(((clkfreq / 1_000 * Duration - 3932) #> 381) + cnt)
      return
      
    
    I must be having some sort of contention going on with some other process in the Propeller's program, since when I set the time, it also stops incrementing. The emails sent out from the unit show the time as it was set, but a few minutes later - same time still shows.
    You must query the RTC when you want to know the current time - readTime. Otherwise you'll get whatever is in the buffer from the last query.
  • xanatosxanatos Posts: 1,120
    edited 2013-06-25 21:15
    Thanks, I'm understanding how the numbers are represented but I'm having issues with what tools and techniques are available in Spin to deal with them - what is frustrating to me is what I do know, and realizing that despite knowing something, I haven't got a clue most of the time how to do anything with that knowledge within the framework of Spin. This is why the Propeller and Spin have come so hard to me, whereas the Stamps were so easy - It was easy to understand the code in PBASIC to the point that I could literally guess - and be correct - at a construction that I had never used before, but that turned out to work well. With Spin, I can be literally looking at the answer to some question, and not see anything in it that I can use as a handle to "get inside it" so to speak.

    An example being your statement in the posts above that "What ya need to do is convert the ASCII strings to numbers. Then pass the numbers to the writeTime method." Since (I thought) that I had already tried that using the nums.decn(x) structure from SimpleNumbers.spin, and it failed completely, it took a while for me to circle back around and try it using the str.toInteger() method on the array variables. My error originally was apparently to apply the method at the wrong point in the process.

    But even now, having found how to make it work, I am still very unclear as to why it would work at one place in the assignment process, but not in the other...

    But I've been on this today now for over nine hours. My brain is fried, and I'm guessing you're probably pretty tired of seeing my name in this forum today, so I'm done for tonight.

    One thing I can assure you of - I've been working at learning this thing for weeks now, non stop, reading literally hundreds of posts, viewing many, many code examples, going through the OBEX, and trying, trying, and trying all sorts of bits of code. I'm not trying to get one thing working - I'm having to get literally dozens of different functions working and tied together in the framework of the Spinneret. And I'm having to do it all at once. If there's one thing I'm doing - and I know you can't see it, and I'm sure it doesn't look like it - but I am doing the work on my end. I have managed to learn an enormous amount in a relatively short period of time - at least comparatively to where I started - but it's still not even close to a beginning with regards to where I need to be with this stuff in about two weeks.

    And I very much recognize the time and effort it takes to help someone learn, especially on a complex subject like Spin and the Propeller. Thank you very much - I hope I can repay the favor some day.

    Dave

    PS., Adding rtc.readTime before the block of rtc.clockMonth, etc., did the trick - but I can't figure out why it was incrementing the time before, without that statement in there. When I'm not under such tight time constraints, I'll go back to that and figure out what of the things I added made the change.
  • Mike GMike G Posts: 2,702
    edited 2013-06-26 07:54
    I was constructing a rather long response but let's do this instead. Give me a call today, 6/26/2013. Hopefully you still have my cell number in your PM.
  • RforbesRforbes Posts: 281
    edited 2013-06-26 09:27
    xanatos,

    To add on to what Mike G. said earlier about ASCII conversion and such, I thought I'd share this chart with you.

    Here is a nice "conversion" chart you can use with Mikes earlier reply about ASCII encoding. This chart shows you the equivalents of several data encoding schemes as well as their binary representation. Copy it and stuff it into a spin file as a commented section for future reference if you'd like. :)
    {
    
    ASCII control characters (character code 0-31)
    The first 32 characters in the ASCII-table are
    unprintable control codes and are used to control
    peripherals such as printers.
    
    ASCII printable characters (character code 32-127)
    Codes 32-127 are common for all the different variations
    of the ASCII table, they are called printable characters,
    represent letters, digits, punctuation marks, and a few
    miscellaneous symbols. You will find almost every character
    on your keyboard. Character 127 represents the command DEL.
    
    The extended ASCII codes (character code 128-255)
    There are several different variations of the 8-bit
    ASCII table. The table below is according to ISO 8859-1,
    also called ISO Latin-1. Codes 129-159 contain the Microsoft®
    Windows Latin-1 extended characters.
    
    
    DEC     OCT     HEX     BIN             Symbol  HTML    HTML    Description
                                                    Number  Name
    ---------------------------------------------------------------------------
    0       000     00      00000000        NUL               Null char
    1       001     01      00000001        SOH               Start of Heading
    2       002     02      00000010        STX               Start of Text
    3       003     03      00000011        ETX               End of Text
    4       004     04      00000100        EOT               End of Transmission
    DEC     OCT     HEX     BIN             Symbol  HTML    HTML    Description
                                                    Number  Name
    ---------------------------------------------------------------------------
    5       005     05      00000101        ENQ               Enquiry
    6       006     06      00000110        ACK               Acknowledgment
    7       007     07      00000111        BEL               Bell
    8       010     08      00001000        BS                Back Space
    9       011     09      00001001        HT                    Horizontal Tab
    10      012     0A      00001010        LF      
              Line Feed
    11      013     0B      00001011        VT                Vertical Tab
    12      014     0C      00001100        FF                Form Feed
    13      015     0D      00001101        CR      
              Carriage Return
    14      016     0E      00001110        SO                Shift Out / X-On
    15      017     0F      00001111        SI                Shift In / X-Off
    16      020     10      00010000        DLE               Data Line Escape
    17      021     11      00010001        DC1               Device Control 1 (oft. XON)
    18      022     12      00010010        DC2               Device Control 2
    19      023     13      00010011        DC3               Device Control 3 (oft. XOFF)
    20      024     14      00010100        DC4               Device Control 4
    21      025     15      00010101        NAK               Negative Acknowledgement
    22      026     16      00010110        SYN               Synchronous Idle
    23      027     17      00010111        ETB               End of Transmit Block
    24      030     18      00011000        CAN               Cancel
    25      031     19      00011001        EM                End of Medium
    26      032     1A      00011010        SUB               Substitute
    27      033     1B      00011011        ESC               Escape
    28      034     1C      00011100        FS                File Separator
    29      035     1D      00011101        GS                Group Separator
    30      036     1E      00011110        RS                Record Separator
    DEC     OCT     HEX     BIN             Symbol  HTML    HTML    Description
                                                    Number  Name
    ---------------------------------------------------------------------------
    31      037     1F      00011111        US                Unit Separator
    32      040     20      00100000                            Space
    33      041     21      00100001        !       !           Exclamation mark
    34      042     22      00100010        "       "   &quot;  Double quotes (or speech marks)
    35      043     23      00100011        #       #           Number
    36      044     24      00100100        $       $           Dollar
    37      045     25      00100101        %       %           Procenttecken
    38      046     26      00100110        &       &   &amp;   Ampersand
    39      047     27      00100111        '       '           Single quote
    40      050     28      00101000        (       (           Open parenthesis (or open bracket)
    41      051     29      00101001        )       )           Close parenthesis (or close bracket)
    42      052     2A      00101010        *       *           Asterisk
    43      053     2B      00101011        +       +           Plus
    44      054     2C      00101100        ,       ,           Comma
    45      055     2D      00101101        -       -           Hyphen
    46      056     2E      00101110        .       .           Period, dot or full stop
    47      057     2F      00101111        /       /           Slash or divide
    48      060     30      00110000        0       0           Zero
    49      061     31      00110001        1       1           One
    50      062     32      00110010        2       2           Two
    51      063     33      00110011        3       3           Three
    52      064     34      00110100        4       4           Four
    53      065     35      00110101        5       5           Five
    54      066     36      00110110        6       6           Six
    55      067     37      00110111        7       7           Seven
    56      070     38      00111000        8       8           Eight
    DEC     OCT     HEX     BIN             Symbol  HTML    HTML    Description
                                                    Number  Name
    ---------------------------------------------------------------------------
    57      071     39      00111001        9       9           Nine
    58      072     3A      00111010        :       :           Colon
    59      073     3B      00111011        ;       ;           Semicolon
    60      074     3C      00111100        <       <   &lt;    Less than (or open angled bracket)
    61      075     3D      00111101        =       =           Equals
    62      076     3E      00111110        >       >   &gt;    Greater than (or close angled bracket)
    63      077     3F      00111111        ?       ?           Question mark
    64      100     40      01000000        @       @           At symbol
    65      101     41      01000001        A       A           Uppercase A
    66      102     42      01000010        B       B           Uppercase B
    67      103     43      01000011        C       C           Uppercase C
    68      104     44      01000100        D       D           Uppercase D
    69      105     45      01000101        E       E           Uppercase E
    70      106     46      01000110        F       F           Uppercase F
    71      107     47      01000111        G       G           Uppercase G
    72      110     48      01001000        H       H           Uppercase H
    73      111     49      01001001        I       I           Uppercase I
    74      112     4A      01001010        J       J           Uppercase J
    75      113     4B      01001011        K       K           Uppercase K
    76      114     4C      01001100        L       L           Uppercase L
    77      115     4D      01001101        M       M           Uppercase M
    78      116     4E      01001110        N       N           Uppercase N
    79      117     4F      01001111        O       O           Uppercase O
    80      120     50      01010000        P       P           Uppercase P
    81      121     51      01010001        Q       Q           Uppercase Q
    82      122     52      01010010        R       R           Uppercase R
    DEC     OCT     HEX     BIN             Symbol  HTML    HTML    Description
                                                    Number  Name
    ---------------------------------------------------------------------------
    83      123     53      01010011        S       S           Uppercase S
    84      124     54      01010100        T       T           Uppercase T
    85      125     55      01010101        U       U           Uppercase U
    86      126     56      01010110        V       V           Uppercase V
    87      127     57      01010111        W       W           Uppercase W
    88      130     58      01011000        X       X           Uppercase X
    89      131     59      01011001        Y       Y           Uppercase Y
    90      132     5A      01011010        Z       Z           Uppercase Z
    91      133     5B      01011011        [       [           Opening bracket
    92      134     5C      01011100        \       \           Backslash
    93      135     5D      01011101        ]       ]           Closing bracket
    94      136     5E      01011110        ^       ^           Caret - circumflex
    95      137     5F      01011111        _       _           Underscore
    96      140     60      01100000        `       `           Grave accent
    97      141     61      01100001        a       a           Lowercase a
    98      142     62      01100010        b       b           Lowercase b
    99      143     63      01100011        c       c           Lowercase c
    100     144     64      01100100        d       d          Lowercase d
    101     145     65      01100101        e       e          Lowercase e
    102     146     66      01100110        f       f          Lowercase f
    103     147     67      01100111        g       g          Lowercase g
    104     150     68      01101000        h       h          Lowercase h
    105     151     69      01101001        i       i          Lowercase i
    106     152     6A      01101010        j       j          Lowercase j
    107     153     6B      01101011        k       k          Lowercase k
    108     154     6C      01101100        l       l          Lowercase l
    DEC     OCT     HEX     BIN             Symbol  HTML    HTML    Description
                                                    Number  Name
    ---------------------------------------------------------------------------
    109     155     6D      01101101        m       m          Lowercase m
    110     156     6E      01101110        n       n          Lowercase n
    111     157     6F      01101111        o       o          Lowercase o
    112     160     70      01110000        p       p          Lowercase p
    113     161     71      01110001        q       q          Lowercase q
    114     162     72      01110010        r       r          Lowercase r
    115     163     73      01110011        s       s          Lowercase s
    116     164     74      01110100        t       t          Lowercase t
    117     165     75      01110101        u       u          Lowercase u
    118     166     76      01110110        v       v          Lowercase v
    119     167     77      01110111        w       w          Lowercase w
    120     170     78      01111000        x       x          Lowercase x
    121     171     79      01111001        y       y          Lowercase y
    122     172     7A      01111010        z       z          Lowercase z
    123     173     7B      01111011        {       {          Opening brace
    124     174     7C      01111100        |       |          Vertical bar
    125     175     7D      01111101        }       }          Closing brace
    126     176     7E      01111110        ~       ~          Equivalency sign - tilde
    127     177     7F      01111111                          Delete
    128     200     80      10000000        €       €  &euro;  Euro sign
    129     201     81      10000001                                 
    130     202     82      10000010        ‚       ‚  &sbquo; Single low-9 quotation mark
    131     203     83      10000011        ƒ       ƒ  &fnof;  Latin small letter f with hook
    132     204     84      10000100        „       „  &bdquo; Double low-9 quotation mark
    133     205     85      10000101        …       …  &hellip;Horizontal ellipsis
    134     206     86      10000110        †       †  &dagger;Dagger
    DEC     OCT     HEX     BIN             Symbol  HTML    HTML    Description
                                                    Number  Name
    ---------------------------------------------------------------------------
    135     207     87      10000111        ‡       ‡  &Dagger;Double dagger
    136     210     88      10001000        ˆ       ˆ  &circ;  Modifier letter circumflex accent
    137     211     89      10001001        ‰       ‰  &permil;Per mille sign
    138     212     8A      10001010        Š       Š  &Scaron;Latin capital letter S with caron
    139     213     8B      10001011        ‹       ‹  &lsaquo;Single left-pointing angle quotation
    140     214     8C      10001100        Π      Π &OElig; Latin capital ligature OE
    141     215     8D      10001101                                 
    142     216     8E      10001110        Ž       Ž          Latin captial letter Z with caron
    143     217     8F      10001111                                 
    144     220     90      10010000                                 
    145     221     91      10010001        ‘       ‘  &lsquo; Left single quotation mark
    146     222     92      10010010        ’       ’  &rsquo; Right single quotation mark
    147     223     93      10010011        “       “  &ldquo; Left double quotation mark
    148     224     94      10010100        ”       ”  &rdquo; Right double quotation mark
    149     225     95      10010101        •       •  &bull;  Bullet
    150     226     96      10010110        –       –  &ndash; En dash
    151     227     97      10010111        —       —  &mdash; Em dash
    152     230     98      10011000        ˜       ˜  &tilde; Small tilde
    153     231     99      10011001        ™       ™  &trade; Trade mark sign
    154     232     9A      10011010        š       š  &scaron;Latin small letter S with caron
    155     233     9B      10011011        ›       ›  &rsaquo;Single right-pointing angle quotation mark
    156     234     9C      10011100        œ       œ  &oelig; Latin small ligature oe
    157     235     9D      10011101                                 
    158     236     9E      10011110        ž       ž          Latin small letter z with caron
    159     237     9F      10011111        Ÿ       Ÿ  &yuml;  Latin capital letter Y with diaeresis
    160     240     A0      10100000                *  &nbsp;  Non-breaking space
    161     241     A1      10100001        ¡       ¡  &iexcl; Inverted exclamation mark
    162     242     A2      10100010        ¢       ¢  &cent;  Cent sign
    163     243     A3      10100011        £       £  &pound; Pound sign
    164     244     A4      10100100        ¤       ¤  &curren;Currency sign
    165     245     A5      10100101        ¥       ¥  &yen;   Yen sign
    166     246     A6      10100110        ¦       ¦  &brvbar;Pipe, Broken vertical bar
    167     247     A7      10100111        §       §  &sect;  Section sign
    168     250     A8      10101000        ¨       ¨  &uml;   Spacing diaeresis - umlaut
    169     251     A9      10101001        ©       ©  &copy;  Copyright sign
    170     252     AA      10101010        ª       ª  &ordf;  Feminine ordinal indicator
    171     253     AB      10101011        «       «  &laquo; Left double angle quotes
    172     254     AC      10101100        ¬       ¬  &not;   Not sign
    173     255     AD      10101101        *       *  *   Soft hyphen
    174     256     AE      10101110        ®       ®  &reg;   Registered trade mark sign
    175     257     AF      10101111        ¯       ¯  &macr;  Spacing macron - overline
    176     260     B0      10110000        °       °  &deg;   Degree sign
    177     261     B1      10110001        ±       ±  &plusmn;Plus-or-minus sign
    178     262     B2      10110010        ²       ²  ²  Superscript two - squared
    179     263     B3      10110011        ³       ³  ³  Superscript three - cubed
    180     264     B4      10110100        ´       ´  &acute; Acute accent - spacing acute
    181     265     B5      10110101        µ       µ  &micro; Micro sign
    182     266     B6      10110110        ¶       ¶  &para;  Pilcrow sign - paragraph sign
    183     267     B7      10110111        ·       ·  &middot;Middle dot - Georgian comma
    184     270     B8      10111000        ¸       ¸  &cedil; Spacing cedilla
    185     271     B9      10111001        ¹       ¹  ¹  Superscript one
    186     272     BA      10111010        º       º  &ordm;  Masculine ordinal indicator
    187     273     BB      10111011        »       »  &raquo; Right double angle quotes
    DEC     OCT     HEX     BIN             Symbol  HTML    HTML    Description
                                                    Number  Name
    ---------------------------------------------------------------------------
    188     274     BC      10111100        ¼       ¼  ¼Fraction one quarter
    189     275     BD      10111101        ½       ½  ½Fraction one half
    190     276     BE      10111110        ¾       ¾  ¾Fraction three quarters
    191     277     BF      10111111        ¿       ¿  &iquest;Inverted question mark
    192     300     C0      11000000        À       À  &Agrave;Latin capital letter A with grave
    193     301     C1      11000001        Á       Á  &Aacute;Latin capital letter A with acute
    194     302     C2      11000010        Â       Â  &Acirc; Latin capital letter A with circumflex
    195     303     C3      11000011        Ã       Ã  &Atilde;Latin capital letter A with tilde
    196     304     C4      11000100        Ä       Ä  &Auml;  Latin capital letter A with diaeresis
    197     305     C5      11000101        Å       Å  &Aring; Latin capital letter A with ring above
    198     306     C6      11000110        Æ       Æ  &AElig; Latin capital letter AE
    199     307     C7      11000111        Ç       Ç  &Ccedil;Latin capital letter C with cedilla
    200     310     C8      11001000        È       È  &Egrave;Latin capital letter E with grave
    201     311     C9      11001001        É       É  &Eacute;Latin capital letter E with acute
    202     312     CA      11001010        Ê       Ê  &Ecirc; Latin capital letter E with circumflex
    203     313     CB      11001011        Ë       Ë  &Euml;  Latin capital letter E with diaeresis
    204     314     CC      11001100        Ì       Ì  &Igrave;Latin capital letter I with grave
    205     315     CD      11001101        Í       Í  &Iacute;Latin capital letter I with acute
    206     316     CE      11001110        Î       Î  &Icirc; Latin capital letter I with circumflex
    207     317     CF      11001111        Ï       Ï  &Iuml;  Latin capital letter I with diaeresis
    208     320     D0      11010000        Ð       Ð  &ETH;   Latin capital letter ETH
    209     321     D1      11010001        Ñ       Ñ  &Ntilde;Latin capital letter N with tilde
    210     322     D2      11010010        Ò       Ò  &Ograve;Latin capital letter O with grave
    211     323     D3      11010011        Ó       Ó  &Oacute;Latin capital letter O with acute
    212     324     D4      11010100        Ô       Ô  &Ocirc; Latin capital letter O with circumflex
    213     325     D5      11010101        Õ       Õ  &Otilde;Latin capital letter O with tilde
    214     326     D6      11010110        Ö       Ö  &Ouml;  Latin capital letter O with diaeresis
    215     327     D7      11010111        ×       ×  &times; Multiplication sign
    216     330     D8      11011000        Ø       Ø  &Oslash;Latin capital letter O with slash
    217     331     D9      11011001        Ù       Ù  &Ugrave;Latin capital letter U with grave
    DEC     OCT     HEX     BIN             Symbol  HTML    HTML    Description
                                                    Number  Name
    ---------------------------------------------------------------------------
    218     332     DA      11011010        Ú       Ú  &Uacute;Latin capital letter U with acute
    219     333     DB      11011011        Û       Û  &Ucirc; Latin capital letter U with circumflex
    220     334     DC      11011100        Ü       Ü  &Uuml;  Latin capital letter U with diaeresis
    221     335     DD      11011101        Ý       Ý  &Yacute;Latin capital letter Y with acute
    222     336     DE      11011110        Þ       Þ  &THORN; Latin capital letter THORN
    223     337     DF      11011111        ß       ß  &szlig; Latin small letter sharp s - ess-zed
    224     340     E0      11100000        à       à  &agrave;Latin small letter a with grave
    225     341     E1      11100001        á       á  &aacute;Latin small letter a with acute
    226     342     E2      11100010        â       â  &acirc; Latin small letter a with circumflex
    227     343     E3      11100011        ã       ã  &atilde;Latin small letter a with tilde
    228     344     E4      11100100        ä       ä  &auml;  Latin small letter a with diaeresis
    229     345     E5      11100101        å       å  &aring; Latin small letter a with ring above
    230     346     E6      11100110        æ       æ  &aelig; Latin small letter ae
    231     347     E7      11100111        ç       ç  &ccedil;Latin small letter c with cedilla
    232     350     E8      11101000        è       è  &egrave;Latin small letter e with grave
    233     351     E9      11101001        é       é  &eacute;Latin small letter e with acute
    234     352     EA      11101010        ê       ê  &ecirc; Latin small letter e with circumflex
    235     353     EB      11101011        ë       ë  &euml;  Latin small letter e with diaeresis
    236     354     EC      11101100        ì       ì  &igrave;Latin small letter i with grave
    237     355     ED      11101101        í       í  &iacute;Latin small letter i with acute
    238     356     EE      11101110        î       î  &icirc; Latin small letter i with circumflex
    239     357     EF      11101111        ï       ï  &iuml;  Latin small letter i with diaeresis
    240     360     F0      11110000        ð       ð  &eth;   Latin small letter eth
    241     361     F1      11110001        ñ       ñ  &ntilde;Latin small letter n with tilde
    242     362     F2      11110010        ò       ò  &ograve;Latin small letter o with grave
    243     363     F3      11110011        ó       ó  &oacute;Latin small letter o with acute
    244     364     F4      11110100        ô       ô  &ocirc; Latin small letter o with circumflex
    245     365     F5      11110101        õ       õ  &otilde;Latin small letter o with tilde
    246     366     F6      11110110        ö       ö  &ouml;  Latin small letter o with diaeresis
    247     367     F7      11110111        ÷       ÷  &divide;Division sign
    DEC     OCT     HEX     BIN             Symbol  HTML    HTML    Description
                                                    Number  Name
    ---------------------------------------------------------------------------
    248     370     F8      11111000        ø       ø  &oslash;Latin small letter o with slash
    249     371     F9      11111001        ù       ù  &ugrave;Latin small letter u with grave
    250     372     FA      11111010        ú       ú  &uacute;Latin small letter u with acute
    251     373     FB      11111011        û       û  &ucirc; Latin small letter u with circumflex
    252     374     FC      11111100        ü       ü  &uuml;  Latin small letter u with diaeresis
    253     375     FD      11111101        ý       ý  &yacute;Latin small letter y with acute
    254     376     FE      11111110        þ       þ  &thorn; Latin small letter thorn
    255     377     FF      11111111        ÿ       ÿ  &yuml;  Latin small letter y with diaeresis
    }
    

    The key to remember (using Mike's reply with 49 decimal as the example) is that ASCII characters are SINGLE characters. If it's an ASCII value, it's ONE character, and ALWAYS AND ONLY ONE character. EACH of these characters is represented by ONE byte of data. That's why there are only 256 ASCII characters (8 bits in 1 byte only has 256 possible combinations)

    So... as Mike said, the DECIMAL value 49 requires TWO ASCII characters. The first is a 4 and the next is a 9.

    If you look at the chart, the DECIMAL value 49 has a binary value of 00110001 which is 8 bits (1 byte) of data. But this binary value equals the character 1 in ASCII. Since ASCII needs 1 byte of data PER CHARACTER, we have to convert between data types to make everything correct.

    To create the ASCII value of "49" we actually have to have TWO bytes of data. The first byte would be for the ASCII character 4, which is a binary value of 00110100 when you look up the ASCII value 4. The second byte is ASCII value 9 which is a binary value of 00111001 when you look up the ASCII value of 9.

    The same principle applies to all ASCII values equally.

    If you wanted to create the ASCII string of characters x a n a t o s you would need to use 7 bytes of data. The first would be the ASCII value x which is binary value 01111000 ... which is 8 bits (1 byte) of data... and on and on.

    Now, look at the chart one more time. If you want to convert the ASCII value to the decimal equivalent, look at the chart really closely. Look at the ASCII value 4. Then look at the DECIMAL EQUIVALENT of it. You'll see the DECIMAL EQUIVALENT is 52... which is 48 more than 4. Now look at the rest of the ASCII number characters and their decimal equivalents... (hint, hint)

    You can build your own conversion methods to convert from ASCII characters to the corresponding DECIMAL value, and vice versa. However, Mike has an object in HTTPServ for the spinneret called StringMethods which has methods that do this already and they work perfectly. Also, there are other objects on the OBEX that do tasks like this for you.

    I hope this'll help you a bit. Hang in there! :)

    Robert
  • xanatosxanatos Posts: 1,120
    edited 2013-06-26 10:19
    Mike - Thanks again very much for your generous time on the phone today, very helpful and much more time-efficient that back & forth via the forum. VERY helpful!

    Robert - thank YOU for this - visualization of the data works really well for me and this does that very well. I have a chart similar to this for my web stuff, but it is only for the &#xxx; style encoding - not hex and binary! This is great.

    To follow along further in this, I could also look at the high-byte of the string "49", and just take the least significant 4 bits - which is 0100, or 4... and then go to the next byte, and take those LSBs, which are 1001, or 9. So I can either subtract 48, or take the 4 LSBs - if I'm only interested in turning an ASCII number into a DEC anyway - correct?

    And lastly, from what I'm understanding now, and to use your example above, if I had x a n a t o s as a STRING - it would really be eight bytes - seven for the ASCII characters, and one byte of all zeros - am I correct on that count?

    Now applying this to my understanding for setting my RTC, for example (and yes, I will be using SNTP, but this RTC setting thing has really helped me to understand how to get data from the user into the Spinneret/Propeller via a web page, so it remains a useful training aid for me here) - here's the code line that takes the input fields from my HTML form and places that string into my variable array (or one line of it in this case):
    CKSetArray[6] :=  Request.Post(id, string("Syear"))
    

    So if the user entered 13 for the year, the actual data being held in CKSetArray[6] (specified as a long in my VAR block) would actually be an ASCII "1" and an ASCII "3", plus a byte of all zeros - am I still correct there?

    Then, I'm using one of the StringMethods to convert those strings to integers:
    Yr := 2000 + str.ToInteger(CKSetArray[6])
    

    And this works well now. Now StringMethods.spin is written in PASM, and after speaking with Mike this morning, I was able to understand what's happening in that PASM section a bit more (no pun intended...), but if you can bear with my long-winded post just another second - would I be correct that A routine to convert (not necessarily THE routine), would be for the program to take the string value, go to the first character (ASCII character), and either subtract 48, or alternately take the LS 4 Bits, get that number, and multiply it by 10, then go to the next number, take those LS 4 bits, add them to the result of the operation on the previous number, and if there were no subsequent numbers, then that's the answer. If there was another number, it would multiply by 10 again, get the next number, add that in, and so forth, until it finally encountered that terminal 0, correct?? Have I got this finally???? :-)

    0

    (That's a terminal zero for this post)
  • RforbesRforbes Posts: 281
    edited 2013-06-26 13:39
    xanatos,
    To follow along further in this, I could also look at the high-byte of the string "49", and just take the least significant 4 bits - which is 0100, or 4... and then go to the next byte, and take those LSBs, which are 1001, or 9. So I can either subtract 48, or take the 4 LSBs - if I'm only interested in turning an ASCII number into a DEC anyway - correct?
    Yes.
    And lastly, from what I'm understanding now, and to use your example above, if I had x a n a t o s as a STRING - it would really be eight bytes - seven for the ASCII characters, and one byte of all zeros - am I correct on that count?
    Yes. You would use 7 bytes for the xanatos characters and then a zero-termination byte, which is simply a byte at the end of the string with a binary value of 0000_0000 (decimal value of 0)
    So if the user entered 13 for the year, the actual data being held in CKSetArray[6] (specified as a long in my VAR block) would actually be an ASCII "1" and an ASCII "3", plus a byte of all zeros - am I still correct there?

    I'm not sure about this one, but it sounds almost correct. I think the actual binary value placed in CKSetArray[6] from this would be 0011_0001 0011_0011 0000_0000 0000_0000 which basically should be fine. One way to find out would be use PST to display the value in binary for you once like this:
    Yr := 2000 + str.ToInteger(CKSetArray[6])
    pst.Bin(CKSetArray[6],32)
    

    But, Mike or someone else might be able to answer this one more accurately. Sorry!
    And this works well now. Now StringMethods.spin is written in PASM, and after speaking with Mike this morning, I was able to understand what's happening in that PASM section a bit more (no pun intended...), but if you can bear with my long-winded post just another second - would I be correct that A routine to convert (not necessarily THE routine), would be for the program to take the string value, go to the first character (ASCII character), and either subtract 48, or alternately take the LS 4 Bits, get that number, and multiply it by 10, then go to the next number, take those LS 4 bits, add them to the result of the operation on the previous number, and if there were no subsequent numbers, then that's the answer. If there was another number, it would multiply by 10 again, get the next number, add that in, and so forth, until it finally encountered that terminal 0, correct?? Have I got this finally???? :-)

    Well, there are many ways to do this. But trying to following your strategy, you could do the following:
    Let's say you set up an array of BYTES (not longs) to hold a 4 digit number where each byte is actually an ASCII character, and you do so using your VAR section. You'd want to declare 5 bytes, so that your first 4 bytes hold the data and the last byte is always going to be zero (your zero termination byte.)

    You'd use something like this:
    VAR
    byte my_number[5]
    

    Or you could use your DAT section a couple different ways, like this:
    DAT
    my_number     byte "0","0","0","0",0
    'or
    my_number     byte $0[4],0
    'or
    my_number     byte 0[5]
    'or
    my_number     byte 0[4],0
    

    One way or another, you've just set aside a "place holder" for 4 bytes of data where each byte will contain an ASCII characters binary value. You've also set up a zero-termination byte.
    So, let's suppose the number you want to place into these bytes is "1234" where each digit is actually the ASCII value of that digit.

    byte 0 = 0011_0001 = ASCII 1 = DEC 49 (left most byte)
    byte 1 = 0011_0010 = ASCII 2 = DEC 50
    byte 2 = 0011_0011 = ASCII 3 = DEC 51
    byte 3 = 0011_0100 = ASCII 4 = DEC 52
    byte 4 = 0000_0000 = zero.

    Since it's a 4 digit number, the first byte (byte 0) represents the ASCII value of the digit 1, which is in the the 1000's place. So... subtract 48 decimal from this ASCII value to get the DECIMAL value. Then multiply by 1000.
    Do the same for byte 1... subract 48 and multiply by 100.
    Do the same for byte 2... subract 48 and multiply by 10.
    Do the same for byte 3... subract 48 and multiply by 1. Or not. :lol:

    Add 'em all together and you've got your brand new shiny decimal value.

    Note- to do it this way, you don't actually *need* a terminating zero because we don't actually do anything with it. But if you use Mikes object (which I strongly recommend) like you wrote above with
    Yr := 2000 + str.ToInteger(CKSetArray[6]), you DO need the terminating zero because his method requires it. It uses it to say "oh, I've got to the end of the ASCII bytes, so I'm done now."
  • xanatosxanatos Posts: 1,120
    edited 2013-06-26 14:13
    Yes! I DO have it finally! Your explanation confirmed my thinking, although I may or may not have expressed it perfectly, the mental "movie" I have of what's happening is correct. :victory dance:

    Thank you for that. I really needed to feel like I was understanding SOMETHING on more than just a superficial level...

    And that VAR vs DAT block example of the many different but equivalent ways to set up my byte arrays (or long arrays too I would guess) was very helpful. If I had encountered those different configurations in different programs it would have taken me quite a while to realize they were all saying the same thing.

    Unfortunately I can't spend much time to bask in the glory of having finally understood how to work with these items in Spin, because I am trying to figure out why the RESTful Services example isn't working on my Spinneret - when I go to aled.htm, I get redirected to led.htm immediately, and clicking the led on/off links does nothing...

    This whole process has been like pulling teeth for me... but it sure feels good when I finally do get some piece of it working well - not just because of a happy accident, but because I genuinely understand it.

    Thank you both for your help - very much.

    Dave
Sign In or Register to comment.