Shop OBEX P1 Docs P2 Docs Learn Events
Mike G's WebServer modified to run in a separate cog? — Parallax Forums

Mike G's WebServer modified to run in a separate cog?

neufneuf Posts: 5
edited 2012-05-13 09:51 in Accessories
Has anyone modified Mike G's Multi-socket WebServer code to run in a Cog? I have a hardware-control project that needs (I think) to have the WebServer launched in a cog by the core control code, rather than the WebServer launching the control code in a cog or including the control code in the WebServer's event-loop.

I've done quite a bit, and have some workable results to show for it, but I'm having problems sending out debug-print over the serial line using Parallax Serial Terminal from the WebServer when it's running in a cog.

The impasse I've hit upon at the moment is that the main program can use the serial port just fine, but when the cog-loaded WebServer (actually only the "Main" routine is in a cog) tries to send characters I get cool crashes that stream endless random data out the serial port. I know I'm clobbering the stack, and basically have moved around the WebServer code without understanding some of the basics when moving spin code into cogs - like perhaps needing semaphores and/or exclusivity when accessing the serial port.

The hardware is a Spinneret piggybacked on a board full of DIPSwitches, relays, leds, motor-drivers...all sorts of stuff controlled via SPI and directly connected.

My initial thought was to modify the Server to accept a telnet connection on one of the sockets, and stream the debug-print out that way, so I could at least get a clue what's happening.

Any help appreciated, and of course excuse me for not finding any existing answer or existing code already on the forums - I looked for quite a while before posting.

Comments

  • G McMurryG McMurry Posts: 134
    edited 2012-05-11 20:40
    PING I want to watch this post.

    Greg
  • Mike GMike G Posts: 2,702
    edited 2012-05-12 09:32
    Welcome to the forum neuf.

    HTTPServer is already running in a COG and globally available. The Main method just processes queued sockets. Replace the Main method with your core control code or roll the core control code into it's own COG process.
  • neufneuf Posts: 5
    edited 2012-05-12 12:28
    Thanks so much for your reply!

    So...I've made HTTPServer run in *two* cogs? Talk about contention! Although all I really did was make HTTPServer's "Main" run in a cog.

    I must be using HTTPServer incorrectly. Let's say I have my own top-level .spin file. How would I launch the HTTPServer?
    OBJ
    
    [...snip...]
    
      server         : "HTTPServer.spin"
    
     [...snip...]
    
    PUB Main
    
     [...snip...]
    
      server.Initialize
      cognew(server.Main, @SomeStackSpace)
    
     [...snip...]
    

    But...the Initialize spin code never returns to my code. Right? It jumps to Main. So...my code never gets to "cognew".

    Feeling a bit dumb here.

    So, let me back up and make sure where I am: Is the latest version of the HTTPServer the one in the Google code repository? That's the version I'm using. I think. :confused:
    ───────────────────────────────────────────────── 
    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        
    ─────────────────────────────────────────────────
    
    I have a feeling maybe I'm not using the latest version. The one I am using starts the W5100 Driver in a cog, then starts the W5100 StatusMonitor in a cog, and then loops in Main (actually executes "Main", which then Jumps to "GotoMain", which then Jumps to "Main") - "HTTPServer.spin", I believe.

    I see that my SVN checkout of spinneret-web-server-read-only also contains HTTPServerBase.spin and HTTPServerMinimal.spin. I have to examine those two again - maybe I'm using the wrong starting point.

    Forgive me for not figuring this out quicker - I'm still a little confused from flailing at it for the last few nights....
  • Mike GMike G Posts: 2,702
    edited 2012-05-12 15:04
    neuf, HTTPServer is an application not an object.
  • Mike GMike G Posts: 2,702
    edited 2012-05-12 16:45
    Also cognew(server.Main, @SomeStackSpace) will produce unexpected results.
    Spin Code Can Only be Launched by its Containing Object
    In the Spin language, by design, objects must intelligently manage their own data, the methods that operate on that data, the cogs that execute those methods, and the interface that other objects use to affect it. These are all aspects that serve to maintain the integrity of the object and increase its useful and reliable nature.
    For these reasons, the object and its designer are notably the best equipped to provide the proper stack space that is required for Spin code being launched into another cog.
    To enforce this principle, the COGNEW and COGINIT commands cannot launch Spin code outside of its containing object. This means that a statement like the following will not work as expected.

    cognew(SomeObject.Method, @StackSpace)

    Instead of launching SomeObject.Method into another cog, the Propeller will instead execute SomeObject.Method within the current cog and if that method returns a value, the Propeller will take that value and use it as the address of code to launch with the COGNEW command. This will not result in the code writer’s intended effect.

    If you have a process to run, then do so in the HTTPServer application.
  • neufneuf Posts: 5
    edited 2012-05-12 20:10
    That exact passage was where I learned why my original attempts to run the Webserver in it's own cog failed. And I think I understand why this is and how it *should* work.

    Here's how I've currently got it arranged - I modified the HTTPServer application into HTTPServerClass "module" (wrong terminology, but you get the idea) by adding methods that launch the Main routine in it's own cog from within HTTPServerClass - a "Start" routine and a "Stop" routine.

    "Initialize" is modified so that it doesn't call "Main" at the end of initialization. "Main" is modified to repeat infinitely, rather than call GotoMain. The rest of the code is largely unchanged.
    PUB Start
      Stop 'Prevent multiple starts
    '  pst.str(string("INIT! "))
      Initialize
    '  pst.str(string("COG! "))
      daCogID := cognew(Main, @WebStackSpace) 'Launch method in another cog
    
    PUB Stop
      if daCogID > -1
        cogstop(daCogID) 'Stop previously launched cog
    
    To fire up the Webserver, the Top-level spin file ("SwitchBoard") does
    server.Start
    
    And it works - my pages get served out, and my added Dispatcher routines work as expected. I just can't send debug data out the serial line.

    But...none of the pst.str statements produce any serial output.

    I'll try to restructure the code of my top-level file ("Switchboard") into HTTPServer as you suggested and see if that fixes the problem with serial output...
  • Mike GMike G Posts: 2,702
    edited 2012-05-12 20:30
    nuef, Main repeats infinitely. GotoMain is at the same level as the main repeat loop. It's only there in case the main repeat loop falls through.

    Consider keeping the PST object in the top level object. Use the AppendLog method for debug trace in the server.

    Nice work! Looking forward to the finished product.
  • neufneuf Posts: 5
    edited 2012-05-12 21:03
    Yah - I just realized the existing HTTPServer Main loop can terminate under less-than ideal circumstances (the "quit" when packetSize grows greater than 12), and GotoMain is there for that. %^>

    What's the right way for a SubObject to use a parent object's PST object - if there is one? e.g. if "SwitchBoard" inits the PST object, how can HTTPServerClass use it? Do I pass in the address of the PST object and use it indirect, or is there another way?

    That would solve the immediate problem of no realtime debug output within the WebServer. In the meantime I'll add more AppendLogs before doing the rewrite to see if there's something obvious tripping me up.

    Thanks for taking the time to address this - I'll post again when I figure out the immediate error, or execute the rewrite..
  • Mike GMike G Posts: 2,702
    edited 2012-05-13 07:16
    What's the right way for a SubObject to use a parent object's PST object - if there is one? e.g. if "SwitchBoard" inits the PST object, how can HTTPServerClass use it? Do I pass in the address of the PST object and use it indirect, or is there another way?
    PST methods are not static. It can be done but I'm not sure it is worth the effort. Take a look at StringMethods.spin for an example. My first attempt to create static methods.

    I'll say this one more time. Why not simply use the HTTPServer top level object to start the control code? Then you have access to all resources. Rename HTTPSErver to whatever you like.

    I realize the urge to encapsulate the web server but 1) HTTPServer is an application not an object. 2) Spin is not like a high level OOP language.
  • neufneuf Posts: 5
    edited 2012-05-13 09:51
    Right you are! I'm listening! Rewriting the code! And thanks again...
Sign In or Register to comment.