FullDuplexSerial Object Version rr004


******************************************** * Full-Duplex Serial Driver v1.2 * * Author: Chip Gracey, Jeff Martin * * Copyright (c) 2006-2009 Parallax, Inc. * * See end of file for terms of use. * ******************************************** -----------------REVISION HISTORY----------------- v1.2 - 5/7/2009 fixed bug in dec method causing largest negative value (-2,147,483,648) to be output as -0. v1.1 - 3/1/2006 first official release. RR20090815 _rr001 Allow variable buffer size in CON Add rxavail - returns true if received bytes available. RR20090816 _rr002 Add compatable calls from Kye's SerialEngine for testing by Dr_Acula RR20090817 _rr003 Add mode bit 4 (add LF after CR), remove some calls RR20090818 _rr004 Remove mode bit 4 (add LF after CR) as per Dr_Acula

Introduction

This driver, once started, implements a serial port in one cog.

Connection Diagram

┌─────────┐ │ │ │ rxPin├─── TTL level RX line │ txPin├─── TTL level TX line │ │ └─────────┘ Propeller MCU (P8X32A) EXAMPLES: Standard Two-Pin Bi-Directional True/Inverted Modes Standard One-Pin Uni-Directional True/Inverted Mode Ex: serial.init(0, 1, ±9600) Ex: serial.init(0, -1, ±9600) -or- serial.init(-1, 0, ±9600) ┌────────────┐ ┌──────────┐ ┌────────────┐ ┌──────────┐ │Propeller P0├─────────────┤I/O Device│ │Propeller P0├───────────────┤I/O Device│ │ P1├─────────────┤ │ └────────────┘ └──────────┘ └────────────┘ └──────────┘ Same-Pin (Bi-Directional) True Mode Same-Pin (Bi-Directional) Inverted Mode Ex: serial.init(0, 0, 9600) Ex: serial.init(0, 0, -9600)  ┌────────────┐ ┌──────────┐ │ │Propeller P0├─────┳─────┤I/O Device│  4.7 kΩ └────────────┘ │ └──────────┘ ┌────────────┐ │ ┌──────────┐  4.7 kΩ │Propeller P0├─────┻─────┤I/O Device│ │ └────────────┘ └──────────┘ 

Global CONstants


SOURCE CODE...

  bufsiz = 256 '16              'buffer size (16, 32, 64, 128, 256, 512) must be factor of 2, max is 512
  bufmsk = bufsiz - 1           'buffer mask used for wrap-around ($00F, $01F, $03F, $07F, $0FF, $1FF)



here you find CONstants used for the mode-parameter of the Start-method of this object.
These constants can be added to be combined. for example serial#OCTX+serial#NOECHO


SOURCE CODE...
  DEFAULTMODE                   = %000000               ' default mode
  INVERTRX                      = %000001               ' mode bit 0 = invert rx
  INVERTTX                      = %000010               ' mode bit 1 = invert tx
  OCTX                          = %000100               ' mode bit 2 = open-drain/source tx
  NOECHO                        = %001000               ' mode bit 3 = ignore tx echo on rx 
  NOMODE                        = %000000               ' depreciated (msrobots/kurenko)


Global VARiables


SOURCE CODE...

  long  cog                     'cog flag/id

  long  rx_head                 '9 contiguous longs
  long  rx_tail
  long  tx_head
  long  tx_tail
  long  rx_pin
  long  tx_pin
  long  rxtx_mode
  long  bit_ticks
  long  buffer_ptr
                     
  byte  rx_buffer[bufsiz]           'transmit and receive buffers
  byte  tx_buffer[bufsiz]


PUBlic Spin Methods

Start and Stop

Start and Stop methods are used for starting and stopping this object. This uses/frees one cog and the rx/tx-pins used.


Stop

Stop serial driver - frees a cog

SOURCE CODE...
PUB Stop

  if cog
    cogstop(cog~ - 1)
  longfill(@rx_head, 0, 9)


Start(rxpin, txpin, mode, baudrate)

Start serial driver - starts a cog
returns false if no cog available

mode bit 0 = invert rx
mode bit 1 = invert tx
mode bit 2 = open-drain/source tx
mode bit 3 = ignore tx echo on rx

SOURCE CODE...
PUB Start(rxpin, txpin, mode, baudrate) : okay

  stop
  longfill(@rx_head, 0, 4)
  longmove(@rx_pin, @rxpin, 3)
  bit_ticks := clkfreq / baudrate
  buffer_ptr := @rx_buffer
  okay := cog := cognew(@entry, @rx_head) + 1


Basic send/receive

Here you find basic send/receive-methods for single bytes.


RxFlush

Flush receive buffer

SOURCE CODE...
PUB RxFlush

  repeat while rxcheck => 0


RxAvail

Check if byte(s) available
returns true (-1) if bytes available

SOURCE CODE...
PUB RxAvail : truefalse

  truefalse := rx_tail <> rx_head


RxCheck

Check if byte received (never waits)
returns -1 if no byte received, $00..$FF if byte

SOURCE CODE...
PUB RxCheck : rxbyte

  rxbyte--
  if rx_tail <> rx_head
    rxbyte := rx_buffer[rx_tail]
    rx_tail := (rx_tail + 1) & bufmsk


RxTime(ms)

Wait ms milliseconds for a byte to be received
returns -1 if no byte received, $00..$FF if byte

SOURCE CODE...
PUB RxTime(ms) : rxbyte | t

  t := cnt
  repeat until (rxbyte := rxcheck) => 0 or (cnt - t) / (clkfreq / 1000) > ms


Rx

Receive byte (may wait for byte)
returns $00..$FF

SOURCE CODE...
PUB Rx : rxbyte

  repeat while (rxbyte := rxcheck) < 0


Tx(txbyte)

Send byte (may wait for room in buffer)

SOURCE CODE...
PUB Tx(txbyte)

  repeat until (tx_tail <> (tx_head + 1) & bufmsk)
  tx_buffer[tx_head] := txbyte
  tx_head := (tx_head + 1) & bufmsk

  if rxtx_mode & %1000
    rx


Extended send/receive

Here you find extended send/receive-methods. This serial object has just extended send-methods.
You can use them for formatted output of numbers and strings.


Str(stringptr)

Send string                    

SOURCE CODE...
PUB Str(stringptr)

  repeat strsize(stringptr)
    tx(byte[stringptr++])


Dec(value)

Print a decimal number

SOURCE CODE...
PUB Dec(value) | i, x

  x := value == NEGX                                                            'Check for max negative
  if value < 0
    value := ||(value+x)                                                        'If negative, make positive; adjust for max negative
    tx("-")                                                                     'and output sign

  i := 1_000_000_000                                                            'Initialize divisor

  repeat 10                                                                     'Loop for 10 digits
    if value => i                                                               
      tx(value / i + "0" + x*(i == 1))                                          'If non-zero digit, output digit; adjust for max negative
      value //= i                                                               'and digit from value
      result~~                                                                  'flag non-zero found
    elseif result or i == 1
      tx("0")                                                                   'If zero digit (or only digit) output it
    i /= 10                                                                     'Update divisor


Hex(value, digits)

Print a hexadecimal number

SOURCE CODE...
PUB Hex(value, digits)

  value <<= (8 - digits) << 2
  repeat digits
    tx(lookupz((value <-= 4) & $F : "0".."9", "A".."F"))


Bin(value, digits)

Print a binary number

SOURCE CODE...
PUB Bin(value, digits)

  value <<= 32 - digits
  repeat digits
    tx((value <-= 1) & 1 + "0")


Generic Interface

this Interface provides generic access with different objects.

I_ReadByteCheck

   Check if a byte is waiting in the receive buffer and return the byte if one is there,
   does NOT block (never waits).
   return:     If no byte, then return(-1).  If byte, then return(byte).

SOURCE CODE...
PUB I_ReadByteCheck
RETURN RxCheck


I_ReadByte

reads a byte

SOURCE CODE...
PUB I_ReadByte
RETURN Rx


I_WriteByte(outByte)

writes a byte

SOURCE CODE...
PUB I_WriteByte(outByte)
RETURN Tx(outByte.Byte[0])


I_ReadWord

reads a word

SOURCE CODE...
PUB I_ReadWord
RESULT.Byte[0]:=Rx
RESULT.Byte[1]:=Rx


I_WriteWord(outWord)

writes a word

SOURCE CODE...
PUB I_WriteWord(outWord)
Tx(outWord.Byte[0])
RETURN Tx(outWord.Byte[1])


I_ReadLong

reads a long

SOURCE CODE...
PUB I_ReadLong
RESULT.Byte[0]:=Rx
RESULT.Byte[1]:=Rx
RESULT.Byte[2]:=Rx
RESULT.Byte[3]:=Rx


I_WriteLong(outLong)

writes a long

SOURCE CODE...
PUB I_WriteLong(outLong)
Tx(outLong.Byte[0])
Tx(outLong.Byte[1])
Tx(outLong.Byte[2])
RETURN Tx(outLong.Byte[3])


I_ReadString(addressToPut, terminator)

reads a string terminated by terminator to addressToPut - terminator not added - returns bytes read

SOURCE CODE...
PUB I_ReadString(addressToPut, terminator) | inByte
  repeat while ((inByte:=Rx)<>terminator)
    byte[addressToPut++]:=inByte
    RESULT++


I_WriteString(addressToGet, terminator)

writes a string terminated by terminator from addressToGet - terminator not added - returns bytes written

SOURCE CODE...
PUB I_WriteString(addressToGet, terminator) | outByte
  repeat while ((outByte:=byte[addressToGet++])<>terminator)
    Tx(outByte)
    RESULT++


I_ReadBlock(addressToPut, count)

reads count bytes to addressToPut - returns bytes read

SOURCE CODE...
PUB I_ReadBlock(addressToPut, count)
  repeat count
    byte[addressToPut++]:=Rx   
RETURN count


I_WriteBlock(addressToGet, count)

writes count bytes from addressToGet- returns bytes written

SOURCE CODE...
PUB I_WriteBlock(addressToGet, count)
  repeat count
    Tx(byte[addressToGet++])   
RETURN count


Assembly Cog


SOURCE CODE...

'***********************************
'* Assembly language serial driver *
'***********************************

                        org     0
'
'
' Entry
'
entry                   mov     t1,par                'get structure address
                        add     t1,#4 << 2            'skip past heads and tails

                        rdlong  t2,t1                 'get rx_pin
                        mov     rxmask,#1
                        shl     rxmask,t2

                        add     t1,#4                 'get tx_pin
                        rdlong  t2,t1
                        mov     txmask,#1
                        shl     txmask,t2

                        add     t1,#4                 'get rxtx_mode
                        rdlong  rxtxmode,t1

                        add     t1,#4                 'get bit_ticks
                        rdlong  bitticks,t1

                        add     t1,#4                 'get buffer_ptr
                        rdlong  rxbuff,t1
                        mov     txbuff,rxbuff
                        add     txbuff,#bufsiz

                        test    rxtxmode,#%100  wz    'init tx pin according to mode
                        test    rxtxmode,#%010  wc
        if_z_ne_c       or      outa,txmask
        if_z            or      dira,txmask

                        mov     txcode,#transmit      'initialize ping-pong multitasking
'
'
' Receive
'
receive                 jmpret  rxcode,txcode         'run a chunk of transmit code, then return

                        test    rxtxmode,#%001  wz    'wait for start bit on rx pin
                        test    rxmask,ina      wc
        if_z_eq_c       jmp     #receive

                        mov     rxbits,#9             'ready to receive byte
                        mov     rxcnt,bitticks
                        shr     rxcnt,#1
                        add     rxcnt,cnt                          

:bit                    add     rxcnt,bitticks        'ready next bit period

:wait                   jmpret  rxcode,txcode         'run a chuck of transmit code, then return

                        mov     t1,rxcnt              'check if bit receive period done
                        sub     t1,cnt
                        cmps    t1,#0           wc
        if_nc           jmp     #:wait

                        test    rxmask,ina      wc    'receive bit on rx pin
                        rcr     rxdata,#1
                        djnz    rxbits,#:bit

                        shr     rxdata,#32-9          'justify and trim received byte
                        and     rxdata,#$FF
                        test    rxtxmode,#%001  wz    'if rx inverted, invert byte
        if_nz           xor     rxdata,#$FF

                        rdlong  t2,par                'save received byte and inc head
                        add     t2,rxbuff
                        wrbyte  rxdata,t2
                        sub     t2,rxbuff
                        add     t2,#1
                        and     t2,#bufmsk
                        wrlong  t2,par

                        jmp     #receive              'byte done, receive next byte
'
'
' Transmit
'
transmit                jmpret  txcode,rxcode         'run a chunk of receive code, then return

                        mov     t1,par                'check for head <> tail
                        add     t1,#2 << 2
                        rdlong  t2,t1
                        add     t1,#1 << 2
                        rdlong  t3,t1
                        cmp     t2,t3           wz
        if_z            jmp     #transmit

                        add     t3,txbuff             'get byte and inc tail
                        rdbyte  txdata,t3
                        sub     t3,txbuff
                        add     t3,#1
                        and     t3,#bufmsk
                        wrlong  t3,t1

                        or      txdata,#$100          'ready byte to transmit
                        shl     txdata,#2
                        or      txdata,#1
                        mov     txbits,#11
                        mov     txcnt,cnt

:bit                    test    rxtxmode,#%100  wz    'output bit on tx pin according to mode
                        test    rxtxmode,#%010  wc
        if_z_and_c      xor     txdata,#1
                        shr     txdata,#1       wc
        if_z            muxc    outa,txmask        
        if_nz           muxnc   dira,txmask
                        add     txcnt,bitticks        'ready next cnt

:wait                   jmpret  txcode,rxcode         'run a chunk of receive code, then return

                        mov     t1,txcnt              'check if bit transmit period done
                        sub     t1,cnt
                        cmps    t1,#0           wc
        if_nc           jmp     #:wait

                        djnz    txbits,#:bit          'another bit to transmit?

                        jmp     #transmit             'byte done, transmit next byte
'
'
' Uninitialized data
'
t1                      res     1
t2                      res     1
t3                      res     1

rxtxmode                res     1
bitticks                res     1

rxmask                  res     1
rxbuff                  res     1
rxdata                  res     1
rxbits                  res     1
rxcnt                   res     1
rxcode                  res     1

txmask                  res     1
txbuff                  res     1
txdata                  res     1
txbits                  res     1
txcnt                   res     1
txcode                  res     1


License

┌──────────────────────────────────────────────────────────────────────────────────────┐
│                            TERMS OF USE: MIT License                                 │                                                            
├──────────────────────────────────────────────────────────────────────────────────────┤
│Permission is hereby granted, free of charge, to any person obtaining a copy of this  │
│software and associated documentation files (the "Software"), to deal in the Software │
│without restriction, including without limitation the rights to use, copy, modify,    │
│merge, publish, distribute, sublicense, and/or sell copies of the Software, and to    │
│permit persons to whom the Software is furnished to do so, subject to the following   │
│conditions:                                                                           │
│                                                                                      │
│The above copyright notice and this permission notice shall be included in all copies │
│or substantial portions of the Software.                                              │
│                                                                                      │
│THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,   │
│INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A         │
│PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT    │
│HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF  │
│CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE  │
│OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                                         │
└──────────────────────────────────────────────────────────────────────────────────────┘