Shop OBEX P1 Docs P2 Docs Learn Events
Help create the Spin Standard Library! - Page 2 — Parallax Forums

Help create the Spin Standard Library!

245

Comments

  • Looks like you're missing a generic I2C and SPI drivers.

    It looks like "storage" might be a better name for your "io" package. I've only ever heard io refer to "input/output" but all of your other packages could be classified as io in that case (com, net, sensor).
  • Hi Cluso, please provide direct links to the objects and versions you'd like to submit.
  • Brett Weir wrote:
    Off the top of your heads, do you guys have any suggestions for any of these?
    I think your object names need to specify particular products. For example, Parallax sells two color sensors, and they interface in drastically different ways. So sensor.color (or sensor.light.color) is too generic. And even the same product might interface in several different ways, requiring several different objects. The TSL1401 linescan module, for example, has an analog output, entailing either an A/D converter (but which one?) or a sigma-delta input circuit. Or ... the analog output can simply be thresholded by driving a logic input pin.

    -Phil

    Sensors are going to get messy very fast, so I am focusing on more general objects first. However, you can see from the current objects that I am trying to be as specific as possible with object names.
    sensor.accel.dual.mxd2125.spin
    sensor.accel.dual.mxd2125.tiny.spin
    sensor.accel.tri.h48c.spin
    sensor.compass.hm55b.spin
    sensor.inductive.spin
    sensor.light2frequency.tsl230.spin
    sensor.ping.spin
    
    display.vga.bitmap.512x384.spin
    display.vga.spin
    display.vga.text.hires.spin
    display.vga.text.spin
    display.vga.tile.1280x1024.spin
    display.vga.tile.1600x1200.spin
    

    This is a learning experience however and the specifics of the naming convention are still being ironed out.
  • DavidZemon wrote: »
    Looks like you're missing a generic I2C and SPI drivers.

    There appears to be an SPI driver but I'm not entirely sure how to test it. I2C, 1-Wire, CAN, and USB are all missing.
    DavidZemon wrote: »
    It looks like "storage" might be a better name for your "io" package. I've only ever heard io refer to "input/output" but all of your other packages could be classified as io in that case (com, net, sensor).

    Haha, yes, good call. Let's call it "storage". There aren't actually any objects named "io" at this point.
  • I would use F32 for math.float

    John Abshier
  • The only good solution I have for testing SPI is with a logic analyzer.

    No generic I2C in the OBEX??? That's awful... is that really true???
  • DavidZemon wrote: »
    The only good solution I have for testing SPI is with a logic analyzer.

    No generic I2C in the OBEX??? That's awful... is that really true???

    No no no no, I didn't mean there wasn't one in the OBEX. I meant not in the Spin library at present, and I don't know which I2C object is good. Any recommendations from anyone?
  • Brett WeirBrett Weir Posts: 288
    edited 2015-12-30 23:13
    I would use F32 for math.float

    John Abshier

    Sweet! Thanks! This looks like it can largely be used as is.

    Not only that, it also comes with a demo! Woohoo!

    I have a question. Can anyone tell me how FFDS1, the serial terminal included with F32, compares with FullDuplexSerial?
  • TV.spin should be used for TV. It works well with graphics.spin too.

    With a little work, VGA.spin also works with graphics.spin.

    These two core drivers, along with graphics.spin do a lot. We have pushed what can be done in all sorts of ways, and that's good. However, the basic capabilities and resolutions in this set of code is well matched to both the overall Propeller capabilities and many projects.

    The drivers are hybrid tile and bitmap capable. Graphics.spin can deliver pixels, text, etc... it can also be used to draw in windows, which can be very useful on mixed displays, where tiles and colors may be used in creative ways to avoid the ram and buffer cost of a full bitmap.

    One can also display the ROM text by using the larger 32 pixel tile size, and TV_Text is a dedicated driver that does this.

    More can be done than most are aware of, IMHO.
  • Brett, also take a look at the Simple IDE libraries to see how they are sorted out with subfolders for different sensors. Andy gave this a lot of thought and it has become very permanent in our code ecosystem, so you might want to mimic it to provide portability for people who know one code system and want to switch to another.

    Ken Gracey
  • potatohead wrote: »
    TV.spin should be used for TV. It works well with graphics.spin too.

    These are currently display.tv and display.tv.graphics in the library.
    potatohead wrote: »
    With a little work, VGA.spin also works with graphics.spin.

    Can you elaborate on "a little work"?
    potatohead wrote: »
    These two core drivers, along with graphics.spin do a lot. We have pushed what can be done in all sorts of ways, and that's good. However, the basic capabilities and resolutions in this set of code is well matched to both the overall Propeller capabilities and many projects.

    The drivers are hybrid tile and bitmap capable. Graphics.spin can deliver pixels, text, etc... it can also be used to draw in windows, which can be very useful on mixed displays, where tiles and colors may be used in creative ways to avoid the ram and buffer cost of a full bitmap.

    One can also display the ROM text by using the larger 32 pixel tile size, and TV_Text is a dedicated driver that does this.

    More can be done than most are aware of, IMHO.

    The TV demo was one of the first ones I ran when I set up my first Propeller. It was awesome! But I had a hard time figuring out how it worked so I stopped playing around with it. >.>
  • potatoheadpotatohead Posts: 10,253
    edited 2015-12-31 02:01
    See my signature for more on that. Honestly, I could write a short book on Chip's really clever driver.... A lot of people have had trouble fully utilizing it.

    So far as I have been able to tell, actually configuring and using the driver is not all that difficult. What is difficult is people unaware of graphics techniques and video basics.

    I'll expand on the other thing in a bit.
  • potatoheadpotatohead Posts: 10,253
    edited 2015-12-31 02:08
    There has definitely been an overreliance on video objects in the demo code.

    Well, to be fair, not everyone uses serial. I frankly do not use it much at all and prefer a character driver most of the time. This depends a lot on how people set up and why they do so.

    I'll run a capture card to get nice output in a window on my laptop, and I do it to get rapid, mixed text, graphics display of program data, vars, etc...

    I've seen others use serial and a scope or blinking lights or sounds to do similar things.



  • Ken Gracey wrote: »
    Brett, also take a look at the Simple IDE libraries to see how they are sorted out with subfolders for different sensors. Andy gave this a lot of thought and it has become very permanent in our code ecosystem, so you might want to mimic it to provide portability for people who know one code system and want to switch to another.

    Ken Gracey

    I think something like that may have already emerged on accident.

    The Spin standard library:
    sensor.accel.dual.mxd2125.spin
    sensor.accel.tri.h48c.spin
    sensor.compass.hm55b.spin
    sensor.inductive.spin
    sensor.light2frequency.tsl230.spin
    sensor.ping.spin
    

    Compared to the Simple libraries:
    sensor/libcolorpal
    sensor/libcompass3d
    sensor/libgps
    sensor/libmma7455
    sensor/libmx2125
    sensor/libping
    sensor/librfidser
    sensor/libsoundimpact
    
  • Cluso99Cluso99 Posts: 18,066
    One of the most frustrating things I found early on was the naming for character outputs.
    IIRC...
    FDX uses .tx(ch)
    TV uses .out(ch)


    In my PropOS I use a stdin and stdout driver via rendezvous locations in hub.
    So standard programs use the stdin and stdout objects and I load drivers such as fdx (serial), tv & kbd, etc.
    However, this might be a little advanced for beginners, but worth mentioning anyway.

    Here are links to some good objects...

    FullDuplexSerial_rr004 http://obex.parallax.com/object/249

    Debug to TV using 1pin (includes 1pin kbd) http://obex.parallax.com/object/196
    1pin TV Text (Eric Ball) http://obex.parallax.com/object/438

    Nokia 5110 for the P1V http://forums.parallax.com/discussion/157003/adding-things-to-your-de0-p1-nokia-5110-lcd-etc
    Nokia 5110 (a few versions on this thread including mine) http://forums.parallax.com/discussion/128736/new-nokia-5110-display-driver-in-the-obex
    and some more info http://forums.parallax.com/discussion/148839/using-the-prop-pins-to-power-ics-modules

    1.44" 128x128 color LCD (often called 5110 color) http://forums.parallax.com/discussion/159911/color-lcd-driver-for-cheap-1-44-spi-128-128-v1-1-red-black-pcbs
  • Off the top of your heads, do you guys have any suggestions for any of these? Can you think of any I haven't listed here that should be covered by this library? -

    Should add ADCs MCP3202, 3204, 3208
  • Re: Graphics.spin with VGA drivers.

    As long as the VGA drivers are of the tile and palette type, like both VGA and TV.spin are, graphics.spin can be set to render into any area of VGA tiles arranged like they are in TV.spin.

    There isn't enough RAM for full screen VGA displays at even 640x480. But, say one wanted a text display, with some graphics in it. Point the tiles to contain text at the internal ROM font, like TV_text.spin does, and stack up some tiles pointed to HUB RAM to serve as mini frame buffers. More than one can be done, just the total of unique bitmap graphics cannot exceed the HUB RAM space available for them.

    From there, you add up your X and Y tile sizes, and call gr.setup with the information needed to point to that tile group, then call graphics methods, until what you want rendered is rendered. If there is more than one buffer area, call gr.setup again, and repeat. This can be done as often as needed to update any bitmap regions of the display.

    IIRC, the 1024x768 VGA driver Chip did shows examples of doing this.

    That's what I meant by, "a little bit of work"
  • Cluso99 wrote: »
    One of the most frustrating things I found early on was the naming for character outputs.
    IIRC...
    FDX uses .tx(ch)
    TV uses .out(ch)

    Yes, that is one gripe I hope to resolve. I will be going through and making the naming uniform. Right now I've settled on Char and CharIn because Spin doesn't support overloading and these make sense if there are commands like Str, Chars, Dec, Hex, etc. in the mix. This may change if it makes sense to do so.
    Cluso99 wrote: »
    In my PropOS I use a stdin and stdout driver via rendezvous locations in hub.
    So standard programs use the stdin and stdout objects and I load drivers such as fdx (serial), tv & kbd, etc.
    However, this might be a little advanced for beginners, but worth mentioning anyway.

    How exactly does that work? How are you attaching objects to other objects? That sounds awesome and I'm not familiar with doing that in Spin.
    Cluso99 wrote: »

    I did some review and it looks like the Parallax Serial Terminal, which is based on FullDuplexSerial, has incorporated this change to allow resizing the buffer. If that is the only change, then I have already incorporated this update into the library (I'll be posting about that shortly).

    Thanks for the links to all the objects! I'll look through them more tomorrow.
  • potatohead wrote: »
    There has definitely been an overreliance on video objects in the demo code.

    Well, to be fair, not everyone uses serial. I frankly do not use it much at all and prefer a character driver most of the time. This depends a lot on how people set up and why they do so.

    I'll run a capture card to get nice output in a window on my laptop, and I do it to get rapid, mixed text, graphics display of program data, vars, etc...

    I've seen others use serial and a scope or blinking lights or sounds to do similar things.

    I know what you mean. I do most development on the LameStation so it's generally easier to just put it on the screen. There just needs to be more examples that don't require a specific hardware setup. Even better, if we put together more "terminal" drivers that are API-compatible with the serial driver, they can just be swapped out. Now that would be nice.
  • Lev wrote: »
    Off the top of your heads, do you guys have any suggestions for any of these? Can you think of any I haven't listed here that should be covered by this library? -

    Should add ADCs MCP3202, 3204, 3208

    Oooh, that would be a good one. Do you know any good drivers for it? Preferably one that can be used for all 3. Then it can be one object called:
    signal.adc.mcp320x
    
  • potatohead wrote: »
    Re: Graphics.spin with VGA drivers.

    As long as the VGA drivers are of the tile and palette type, like both VGA and TV.spin are, graphics.spin can be set to render into any area of VGA tiles arranged like they are in TV.spin.

    There isn't enough RAM for full screen VGA displays at even 640x480. But, say one wanted a text display, with some graphics in it. Point the tiles to contain text at the internal ROM font, like TV_text.spin does, and stack up some tiles pointed to HUB RAM to serve as mini frame buffers. More than one can be done, just the total of unique bitmap graphics cannot exceed the HUB RAM space available for them.

    From there, you add up your X and Y tile sizes, and call gr.setup with the information needed to point to that tile group, then call graphics methods, until what you want rendered is rendered. If there is more than one buffer area, call gr.setup again, and repeat. This can be done as often as needed to update any bitmap regions of the display.

    IIRC, the 1024x768 VGA driver Chip did shows examples of doing this.

    That's what I meant by, "a little bit of work"

    I never did understand how those tiled video drivers work. That's why I was so adamant about giving the LameStation a frame buffer. Have you ever considered writing this book? I'd have a much better case for keeping all these video drivers in the library if I could explain to someone how to use them.
  • Progress Report

    So today I reworked the following objects.
    com.serial.spin
    com.serial.terminal.spin
    string.numbers.spin
    math.float.spin
    

    https://github.com/parallaxinc/spin-standard-library/tree/master/library

    com.serial takes the core of Parallax Serial Terminal (which was basically the upgraded FullDuplexSerial object), and makes it a standalone object. Then com.serial.terminal (which was Parallax Serial Terminal) is just a wrapper around com.serial with some added control functions. The number-to-string functions have been offloaded onto string.numbers. In this way, both the serial core and the conversion functions only have to be maintained in one place for the whole library to be updated. This is a huge time-saver for maintenance.

    I also added/updated the following easy, short demos. I'll be adding more tomorrow, and removing the ones labeled FullDuplexSerial.
    DataBlast.spin
    LoopBack.spin
    HelloWorld.spin
    Terminal.spin
    

    https://github.com/parallaxinc/spin-standard-library/tree/master/library/demos/com/serial

    Finally, the existing floating point libraries have been removed, and F32 has been added as math.float. I still need to rename its functions. With that in mind, does anyone know any good fixed-point math objects? I'd like to have math.fixed as well.

    Hopefully this gives you guys a much better idea of what my expectations are for this library. It's not as hard as you might think to meet the criteria for inclusion. I did all of this in the span of a couple hours.

    Here are the main things I am enforcing.
    • Indent levels
    • Function and constant names
    • Documentation comments in markdown

    Outside of that, it's not as important. Your object doesn't need to be perfect. So for anyone still holding back, don't be shy; give it a try!
  • Brett Weir wrote: »
    Progress Report

    So today I reworked the following objects.
    com.serial.spin
    com.serial.terminal.spin
    string.numbers.spin
    math.float.spin
    

    https://github.com/parallaxinc/spin-standard-library/tree/master/library

    com.serial takes the core of Parallax Serial Terminal (which was basically the upgraded FullDuplexSerial object), and makes it a standalone object. Then com.serial.terminal (which was Parallax Serial Terminal) is just a wrapper around com.serial with some added control functions. The number-to-string functions have been offloaded onto string.numbers. In this way, both the serial core and the conversion functions only have to be maintained in one place for the whole library to be updated. This is a huge time-saver for maintenance.

    I also added/updated the following easy, short demos. I'll be adding more tomorrow, and removing the ones labeled FullDuplexSerial.
    DataBlast.spin
    LoopBack.spin
    HelloWorld.spin
    Terminal.spin
    

    https://github.com/parallaxinc/spin-standard-library/tree/master/library/demos/com/serial

    Finally, the existing floating point libraries have been removed, and F32 has been added as math.float. I still need to rename its functions. With that in mind, does anyone know any good fixed-point math objects? I'd like to have math.fixed as well.

    Hopefully this gives you guys a much better idea of what my expectations are for this library. It's not as hard as you might think to meet the criteria for inclusion. I did all of this in the span of a couple hours.

    Here are the main things I am enforcing.
    • Indent levels
    • Function and constant names
    • Documentation comments in markdown

    Outside of that, it's not as important. Your object doesn't need to be perfect. So for anyone still holding back, don't be shy; give it a try!
    This all sounds great! If you can figure out a way to make use of Cluso99's rendevous console I/O interface to allow the serial driver to be swapped for one of the LCD drivers it would be even better.

  • Brett Weir wrote: »
    Lev wrote: »
    Off the top of your heads, do you guys have any suggestions for any of these? Can you think of any I haven't listed here that should be covered by this library? -

    Should add ADCs MCP3202, 3204, 3208

    Oooh, that would be a good one. Do you know any good drivers for it? Preferably one that can be used for all 3. Then it can be one object called:
    signal.adc.mcp320x
    

    I'd recommend picking your favorite Spin object for any of the MCP3xxx devices and then use my MCP3000 object from PropWare as inspiration for tweaking it.
    https://github.com/DavidZemon/PropWare/blob/release-2.0/PropWare/mcp3000.h

    there is no function difference between an MCP3202, MCP3204 and MCP3208, only how many channels. So, the most you'd want to do is check the channel requested and, if too high, return an error. Other than that, all of the logic remains the same. Then the only difference between MCP300X, MCP320X, and MCP330X is how many bits you shift in. All of the bits are still in the same order, channels are selected in the same way, etc etc.
  • Brett Weir wrote: »

    I went there - looked at some of the work - fantastic!

    Erlend
  • potatoheadpotatohead Posts: 10,253
    edited 2015-12-31 16:39
    Brett, maybe. I've got some stuff written for the Parallax, what I call reference drivers. A lot of that is in the HYDRA book too.

    The other drivers all vary considerably, and some are specific purpose too.

    At this time, I remain unsure just what to put into such a work. Seems like it would have to cover video formats, signals, general graphics concepts, graphics hardware concepts such as tiles, sprites, colors, buffering strategies, etc... along with specific implementation details and math for the various drivers out there. Frankly, the HYDRA book, coupled with one on game design and graphics from the 90's era covers it well. That is for the Parallax drivers, and at least one other high color, game oriented one.

    Andre' and I discussed this some time back. If someone gets "The Black Art of Game design" and the HYDRA book, they can do a lot.

    One exception is tricks for technical, or instrumentation type displays. Game tricks apply, but can be hard to map over to a more industrial application...

    So, I arrived at a place where it is either a real book, like maybe one people pay for, or it won't do too much more good than a forum search and or some time spent with the code would.

    I'm not convinced the audience is all that large too. Could be bigger, build and they will come, but I really don't know.

    So there is the state of it. I really don't know what would make sense, and the effort is non trivial enough to make that an obstacle.
  • Object names could be the model number in some cases.
  • Cluso99Cluso99 Posts: 18,066
    The rendezvous idea is actually quite simple, but it does require a fixed location to pass the data.

    Here is the basis of _hubdef3
    CON
    
    ' OS Hub Definitions...         
    ' ------------------       bytes
      _HubFree      = $7FFC  '    4     ' \ stores total hub available (typ $7800)
                                        ' |  (hub is allocated to the OS above this value)
                                        ' /  (eg $7000 means $0000-$6FFF is available)
    
      _OS_DateTime  = $7FF8  '    4     'Year20xx  Month    Date    Hours   Minutes   Seconds
                                        ' (00-63)  (1-12)  (1-31)  (00-23)  (00-59)   (00-59)                                     
                                        '  000000___0000____00000___00000____000000____000000
                                        'To convert to FAT16/32 format, shift >>1 then add 16<<25
                                        '   --> Y(7)M(4)D(5)H(5)M(6)S*2(5bits) Base=1980
                                        '  (FYI seconds in 4yrs = 126,230,400)
                                                                                                       
      _OS_Rows      = $7FF7  '    1     ' \ combined <lf> and rows
        _LF_MASK      = $80             ' | b7  : 1= <lf> ON; 0= strip <lf>
        _ROW_MASK     = $7F             ' / b0-6: no of rows on screen (0-127)
      _OS_Columns   = $7FF6  '    1     '         no of cols on screen (0-255)
      _OS_Cogs      = $7FF5  '    1     ' stay resident cogs: 1= don't stop on reboot
      _OS_Clkmode   = $7FF4  '    1     ' clkmode: saved fm hub byte $0004
    
      _OS_Clkfreq   = $7FF0  '    4     ' clkfreq(Hz): saved fm hub long $0000
    
      
      _SDpins       = $7FEC  '    4     ' \ sd pins packed 4 bytes
                             '          ' / Byte 3=/CS, 2=DI, 1=CLK, 0=DO
      _SIOpins      = $7FE8  '    4     ' \ serial pins and mode settings (and cog#)
                             '          ' / Byte 3=cog, 2=mode, 1=SO, 0=SI
      _SIObaud      = $7FE4  '    4     ' serial baud (speed typ 115,200)
    
      _Hardware     = $7FE0  '    4     ' \ hardware: hi-word=company, lo-word=config
                                        ' |            $0001 = Cluso99  $0001 = RamBlade 1           
                                        ' |            $0001 = Cluso99  $0002 = TriBlade#2           
                                        ' |            $0001 = Cluso99  $0003 = RamBlade3
                                        ' |            $0001 = Cluso99  $0004 = P8XBlade2
                                        ' /            $0001 = Cluso99  $0007 = CpuBlade7
                                        ' ^^^ may be more valuable for something else??
    
      _AuxIn        = $7FDC  '    4     ' auxilary input  rendezvous
      _AuxOut       = $7FD8  '    4     ' auxilary output rendezvous
      _StdIn        = $7FD4  '    4     ' standard input  rendezvous
      _StdOut       = $7FD0  '    4     ' standard output rendezvous
                             
      _OSreserved   = $7FC8  '    8     ' undefined
      _SDparam      = $7FC4  '    4     ' parameter \ for SD FAT driver
      _SDcommand    = $7FC0  '    4     ' command   /
                             
      _pBuffer_C    = $7F80  '   64  '| ' \ user buffers... 
      _pBuffer_B    = $7F40  '   64  '| ' |   (maybe serial in and serial out buffers?)
      _pBuffer_A    = $7F00  '   64  '| ' /   (used to pass parameters between modules)
      _pBuffer      = $7F00  '  192  '^ ' / ...joins all 3 buffers A+B+C
                             
      _pCogTables   = $7E00  '  256     ' \ 8*32B cog usage tables
                                        ' | TBD
                                        ' |   Current thinking is...
                                        ' |     1 byte for "type"
                                        ' |     1 long for sector address to retrieve filename
                                        ' |   However, could also be used as 2*16byte buffers
                                        ' /     with the head+tail(s) kept in _StdIn & _StdOut
                             
      _pSectorBuf   = $7C00  '  512     ' SD card i/o buffer                 
      _pSpinVector  = $7800  ' 1024     ' vector table for Cluso's faster spin interpreter
                             
      _HUB_RESERVED = $7800             ' $7800-$7FFF currently reserved by the OS
      _HUB_RAMSIZE  = $8000             ' Total hub ram 
    
    

    Note the 4 longs _StdIn, _StdOut, _AuxIn, _AuxOut

    Here is _StdOut.spin
    VAR
      long  pRENDEZVOUS
    
    PUB start(rendezvous)
      pRENDEZVOUS := rendezvous                             'get rendezvous location
    
    PUB out(c)
    '' Print a character
    
      c |= $100   '0.FF -> 100..1FF                         'add bit9=1 (allows $00 to be passed)
      repeat while long[pRENDEZVOUS]                        'wait for mailbox to be empty (=$0)
      long[pRENDEZVOUS] := c                                'place in mailbox for driver to act on
    
    PUB str(stringptr)
    '' Print a zero-terminated string
    
      repeat strsize(stringptr)
        out(byte[stringptr++])
    
    PUB dec(value) | _i
    '' Print a decimal number
    
      if value < 0
        -value
        out("-")
    
      _i := 1_000_000_000
    
      repeat 10
        if value => _i
          out(value / _i + "0")
          value //= _i
          result~~
        elseif result or _i == 1
          out("0")
        _i /= 10
    
    PUB hex(value, digits)
    '' Print a hexadecimal number
    
      value <<= (8 - digits) << 2
      repeat digits
        out(lookupz((value <-= 4) & $F : "0".."9", "A".."F"))
    
    PUB bin(value, digits)
    '' Print a binary number
    
      value <<= 32 - digits
      repeat digits
        out((value <-= 1) & 1 + "0")
    
    and _StdIn.spin
    VAR
      long  pRENDEZVOUS                                     'stores a pointer to the hub mailbox
    
    PUB start(rendezvous)
      pRENDEZVOUS := rendezvous                             'get rendezvous location
    
    PUB in : c
    '' Wait for an input character
    
      repeat until c := long[pRendezvous]                   'wait until the mailbox has a character
      long[pRendezvous]~                                    'clear the mailbox
      c &= $FF                      '$100 -> $00            'extract lower 8 bits (byte)
    
    PUB peek
    '' Returns a 0 if the buffer is empty,
    '' else next character (+$100) but doesn't remove from the buffer.
    '' The user routine must extract the 8 bits as the whole long is passed.
    
      return long[pRendezvous]                              'return ALL bits (long) in the mailbox
    
  • Cluso99Cluso99 Posts: 18,066
    and _PCSIO.spin (how I use FDX as the cog for doing the real serial I/O via _StdIn & _StdOut
    CON
      RX1FIFO_SIZE = 160    '640 bytes
      TX1FIFO_SIZE = 160    '640 bytes
    
    VAR
      long  cog                     'cog flag/id
      long  params[4]               'for passing parameters
    
    PUB start(inRENDEZVOUS, outRENDEZVOUS, serPins, baud) 
    
    '' Start Serial driver - starts a cog if necessary
    '' returns cog+1 if it had to start a cog, false if cog was already running.
    '' serPins = rxPin << 8 | txPin
    '' baud    = baud
    ''
    
    
      long[outRENDEZVOUS] := 4                              'Ping Ser Driver
      waitcnt(clkfreq>>2+cnt)
      if long[outRENDEZVOUS] == 0
        return False                                        'is alive
    
    'else start driver
    
      long[inRENDEZVOUS]  := 0                              'clear the rendezvous locations
      long[outRENDEZVOUS] := ">"
      params[0] := inRENDEZVOUS                             'pass the parameters
      params[1] := outRENDEZVOUS
      params[2] := serPins
      params[3] := clkfreq / baud
      cog := cognew(@entry, @params) + 1                    'Start the cog
    
      repeat while long[outRENDEZVOUS]                      'wait until cleared (ok to go)
    
      return cog                                            'cog+1 (=0=false if failed)
    
    
    DAT
                        ORG     0
    '
    ' Initialisation. 
    '
    
    entry               mov     t1,par              'get the address of the parameter list
                        rdlong  rx1ptr,t1           'inRENDEZVOUS
                        add     t1,#4
                        rdlong  tx1ptr,t1           'outRENDEZVOUS
                        add     t1,#4
                        rdlong  t2,t1               'serPins
                        test    t2,#$80       wz    'if $FF, disable tx
            if_z        mov     tx1mask,#1          '=txmask 
            if_z        shl     tx1mask,t2
                        shr     t2,#8               'rxPin
                        test    t2,#$80       wz    'if $FF, disable rx
            if_z        mov     rx1mask,#1          '=rxmask 
            if_z        shl     rx1mask,t2
                        add     t1,#4
                        rdlong  baud1,t1            'baudticks
    
    '                    wrlong  cNull,rx1ptr       'cleared by spin
                        wrlong  cNull,tx1ptr        'signal OK to go
                        
                        or      OUTA,tx1mask
                        or      DIRA,tx1mask
                        jmp     dRx1
    
    rx1ptr              long    0    
    tx1ptr              long    0 
    rx1mask             long    0
    tx1mask             long    0
    baud1               long    0
    '
    ' Receiver 
    '
    aRx1_Start          mov     rx1bits,#9          '# of bits to receive
                        mov     rx1cnt,baud1
                        shr     rx1cnt,#2           'quarter of a bit tick ...
                        add     rx1cnt,baud1        '... plus a full bit tick
                        mov     dRx1,#aRx1_Wait
                        
    aRx1_Wait           test    rx1mask, INA  WC    'Wait for start bit
        if_c            jmp     #aRx1_Get                                 
                        add     rx1cnt, CNT
                        mov     dRx1,#aRx1_Bits
                        
    aRx1_Bits           mov     t1,rx1cnt           'Check if bit receive period done
                        sub     t1,cnt
                        cmps    t1,#0         WC    'Time to sample yet?
        if_nc           jmp     #aRx1_Get
                        test    rx1mask, INA  WC    'Receive bit into carry
                        rcr     rx1data,#1          'Carry into Rx buffer
                        add     rx1cnt,baud1        'Go to next bit period
                        djnz    rx1bits,#aRx1_Bits  'Get next bit
        if_nc           jmp     #aRx1_Start
                        and     rx1data,cRxAnd      'Mask out the unwanted bits
                        rol     rx1data,rx1rol      'Put the data into the correct byte
                        mov     dRx1,#aRx1_Put
                        jmp     dTx1                'Go do some transmitter code
    
                        'General variables for the receiver
    cRxAnd              long    %0111_1111_1000_0000_0000_0000_0000_0000
    rx1len              long    0
    rx1maxlen           long    (tx1fifo - rx1fifo - 1) * 4
    dRx1                long    aRx1_Start
                        'Variables used to receive a byte into the FIFO
    rx1data             long    0
    rx1bits             long    0
    rx1cnt              long    0
    rx1rol              long    9
    rx1out              long    0
    rx1put              long    rx1fifo
    rx1putb             long    $80
                        'Variables used to grab a byte from the FIFO
    rx1ror              long    0                    
    rx1get              long    rx1fifo
    rx1getb             long    $80
    
    aRx1_Put            cmp     rx1len,rx1maxlen  WZ
        if_z            jmp     #(aRx1_Get+2)
                        mov     dRx1,#aRx1_Start
                        add     rx1len,#1
                        or      rx1out,rx1data      'Merge in the new data byte
    arp1                mov     rx1fifo,rx1out      'Write to the FIFO memory
                        add     rx1rol,#8           'Prapare for the next byte
                        rol     rx1putb,#8  WC      'C true every 4 cycles
        if_nc           jmp     dTx1
                        add     rx1put,#1
                        cmp     rx1put,#tx1fifo   WZ
        if_z            mov     rx1put,#rx1fifo
                        movd    arp1,rx1put         'Set the new FIFO destination 
                        mov     rx1out,#0
                        jmp     dTx1
    
    aRx1_Get            cmp     rx1len,#0  WZ
        if_z            jmp     dTx1
                        rdlong  t1,rx1ptr  WZ       'Is the receive buffer empty?
        if_nz           jmp     dTx1                'Jump if not
                        sub     rx1len,#1
    arg1                mov     t1,rx1fifo
                        ror     t1,rx1ror
                        and     t1,#$ff   WZ
        if_z            or      t1,#$100            '$00=$100
                        wrlong  t1,rx1ptr 
                        add     rx1ror,#8
                        rol     rx1getb,#8  WC      'C true every 4 cycles
        if_nc           jmp     dTx1
                        add     rx1get,#1
                        cmp     rx1get,#tx1fifo  WZ
        if_z            mov     rx1get,#rx1fifo
                        movs    arg1,rx1get
                        jmp     dTx1
    '
    ' Transmitter 
    '
    aTx1_Start          cmp     tx1len,#0   WZ
        if_z            jmp     #aTx1_Put
                        mov     dTx1,#aTx1_Byte
                        sub     tx1len,#1
    atg1                mov     tx1data,tx1fifo
                        ror     tx1data,tx1ror
                        and     tx1data,#$ff
                        add     tx1ror,#8
                        rol     tx1getb,#8  WC
        if_nc           jmp     dRx1     
                        add     tx1get,#1
                        cmp     tx1get,#fifo1end  WZ
        if_z            mov     tx1get,#tx1fifo
                        movs    atg1,tx1get
                        jmp     dRx1
    
    aTx1_Byte           shl     tx1data,#2
                        or      tx1data,cFixedBits  'or in a idle line state and a start bit
                        mov     tx1bits,#11
                        mov     tx1cnt,cnt
    aTx1_Bits           shr     tx1data,#1   WC
                        muxc    OUTA,tx1mask        
                        add     tx1cnt,baud1        'Bit period counter
                        mov     dTx1,#aTx1_Wait
                        jmp     dRx1
    
    aTx1_Wait           mov     t1,tx1cnt           'Check bit period
                        sub     t1,CNT
                        cmps    t1,#0       WC      'Is bit period done yet?
        if_nc           jmp     #aTx1_Put
                        djnz    tx1bits,#aTx1_Bits  'Transmit next bit
                        mov     dTx1,#aTx1_Start
                        jmp     dRx1
    
    aTx1_Put            cmp     tx1len,#(fifo1end-tx1fifo) WZ
        if_z            jmp     dRx1
                        rdlong  t1,tx1ptr  WZ
        if_z            jmp     dRx1
                        wrlong  cNull,tx1ptr
                        add     tx1len,#1
                        and     t1,#$ff
                        shl     t1,tx1rol
                        add     tx1rol,#8
                        or      tx1out,t1
    atp1                mov     tx1fifo,tx1out    
                        rol     tx1putb,#8  WC
        if_nc           jmp     dRx1
                        add     tx1put,#1
                        cmp     tx1put,#fifo1end  WZ
        if_z            mov     tx1put,#tx1fifo
                        movd    atp1,tx1put
                        mov     tx1out,#0
                        jmp     dRx1
             
                        'General variables for the transmitter
    tx1len              long    0
    tx1maxlen           long    (fifo1end - tx1fifo - 1) * 4
    dTx1                long    aTx1_Start
                        'Variables used to grab the transmit a byte from the FIFO
    tx1data             long    0
    tx1bits             long    0
    tx1cnt              long    0
    tx1ror              long    0
    tx1get              long    tx1fifo
    tx1getb             long    $80
                        'Variables used to receive a byte into the FIFO
    tx1rol              long    0
    tx1put              long    tx1fifo
    tx1putb             long    $80
    tx1out              long    0
    
    '
    ' Data
    '
    cFixedBits          long    %1_0000_0000_0_1    'Stop + 8 x Data + Start + Idle bits
    'cMinusOne           long    -1     
    cNull               long    0     
    
    t1                  long    0
    t2                  long    0
    
    '
    ' The buffer sizes may be freely adjusted. As long as the code still compiles
    ' into the cog. The sizes are currently at their maximum, but may be adjusted
    ' to favour either the receiver or tranmitter.
    '
    rx1fifo             res     RX1FIFO_SIZE
    tx1fifo             res     TX1FIFO_SIZE
    fifo1end
    
                        FIT     496
    
  • Cluso99Cluso99 Posts: 18,066
    I interface to these routines using these calls...
    PRI GetKey
        result := stdin.in                                  ' wait for an input char
        if result == _backspaceKeycode     ' backspace keycode is 200 but convert to 8
          result := _backspaceCharacter 
    
    PRI PrintHexadecimal(number, length)
        PrintString(str.integerToHexadecimal(number, length))
    
    PRI PrintDecimal(number)               ' print the decimal value, useful for debugging
        PrintString(str.integerToDecimal(number, 10))    
    
    PRI PrintStringCR(pstring)             ' sends string to output devices (vga/serial) with CRLF
        PrintString(pstring)                            
        crlf
    
    PRI PrintString(pstring)               ' sends string to output devices (vga/serial) without CRLF
        repeat strsize(pstring)
          PrintChar(byte[pstring++])
         
    PRI PrintChar(c)                       ' sends character to output devices (vga/serial)
        if c <> _lineFeedCharacter
          stdout.out(c)                                     ' send char  to output device
        elseif byte[_hub#_OS_Rows] & _hub#_LF_MASK       
          stdout.out(c)                                     ' send <lf>  to output device
           
    PUB CRLF
        PrintChar(_carriageReturnCharacter)                 ' sends <cr> to output device
        PrintChar(_lineFeedCharacter)                       ' sends <lf> to output device
    
    Note the way I use <LF>. I have a flag in the hub rendezvous section that determines whether <LF> is send which can be turned on/off In my OS.

    I use Kye's ASCII0_STREngine.spin for all the main string conversions.
    However, I would change stringConcatenation to stringAppend as it is more meaningful.
Sign In or Register to comment.