'' From Parallax Inc. Propeller Education Kit - 6: Objects Lab {{ ──────────────────────────────────────────────────────────────────────────────────────── File: FullDuplexSerialPlus.spin Version: 1.1 Copyright (c) 2008 Parallax, Inc. See end of file for terms of use. This is the FullDuplexSerial object v1.1 from the Propeller Tool's Library folder with modified documentation and methods for converting text strings into numeric values in several bases. ──────────────────────────────────────────────────────────────────────────────────────── }} CON '' ''Parallax Serial Terminal Control Character Constants ''──────────────────────────────────────────────────── HOME = 1 ''HOME = 1 CRSRXY = 2 ''CRSRXY = 2 CRSRLF = 3 ''CRSRLF = 3 CRSRRT = 4 ''CRSRRT = 4 CRSRUP = 5 ''CRSRUP = 5 CRSRDN = 6 ''CRSRDN = 6 BELL = 7 ''BELL = 7 BKSP = 8 ''BKSP = 8 TAB = 9 ''TAB = 9 LF = 10 ''LF = 10 CLREOL = 11 ''CLREOL = 11 CLRDN = 12 ''CLRDN = 12 CR = 13 ''CR = 13 CRSRX = 14 ''CRSRX = 14 CRSRY = 15 ''CRSRY = 15 CLS = 16 ''CLS = 16 BUFFER_SIZE = 32 ' must be a power of two MAX_BUFFER_INDEX = BUFFER_SIZE - 1 DAT cog long 0 'cog flag/id rx_head long 0 '9 contiguous longs rx_tail long 0 tx_head long 0 tx_tail long 0 rx_pin long 0 tx_pin long 0 rxtx_mode long 0 bit_ticks long 0 buffer_ptr long 0 debugLock long 0 rx_buffer byte 0[BUFFER_SIZE] 'transmit and receive buffers tx_buffer byte 0[BUFFER_SIZE] PUB start(rxpin, txpin, mode, baudrate) : okay {{ Starts serial driver in a new cog rxpin - input receives signals from peripheral's TX pin txpin - output sends signals to peripheral's RX pin mode - bits in this variable configure signaling bit 0 inverts rx bit 1 inverts tx bit 2 open drain/source tx bit 3 ignore tx echo on rx baudrate - bits per second okay - returns false if no cog is available. }} stop longfill(@rx_head, 0, 4) longmove(@rx_pin, @rxpin, 3) bit_ticks := clkfreq / baudrate buffer_ptr := @rx_buffer debugLock := locknew okay := cog := cognew(@entry, @rx_head) + 1 PUB stop '' Stops serial driver - frees a cog if cog cogstop(cog~ - 1) longfill(@rx_head, 0, 9) PUB tx(txbyte) '' Sends byte (may wait for room in buffer) repeat until (tx_tail <> (tx_head + 1) & MAX_BUFFER_INDEX) tx_buffer[tx_head] := txbyte tx_head := (tx_head + 1) & MAX_BUFFER_INDEX if rxtx_mode & %1000 rx PUB txs(txbyte) DebugCog if txbyte <> 13 tx(txbyte) PUB txe(txbyte) tx(txbyte) lockclr(debugLock) PUB txse(txbyte) txs(txbyte) lockclr(debugLock) PUB DebugCog '' display cog ID at the beginning of debug statements repeat until not lockset(debugLock) tx(13) dec(cogid) tx(":") tx(32) PUB rx : rxbyte '' Receives byte (may wait for byte) '' rxbyte returns $00..$FF repeat while (rxbyte := rxcheck) < 0 PUB rxs : rxbyte strs(string("(rx)")) rx PUB rxe : rxbyte rx lockclr(debugLock) PUB rxse : rxbyte rxs lockclr(debugLock) PUB rxflush '' Flush receive buffer repeat while rxcheck => 0 PUB rxcheck : rxbyte '' Check if byte received (never waits) '' rxbyte returns -1 if no byte received, $00..$FF if byte rxbyte-- if rx_tail <> rx_head rxbyte := rx_buffer[rx_tail] rx_tail := (rx_tail + 1) & MAX_BUFFER_INDEX PUB rxcheckse : rxbyte repeat until not lockset(debugLock) rxcheck lockclr(debugLock) PUB rxtime(ms) : rxbyte | t '' Wait ms milliseconds for a byte to be received '' returns -1 if no byte received, $00..$FF if byte t := cnt repeat until (rxbyte := rxcheck) => 0 or (cnt - t) / (clkfreq / 1000) > ms PUB rxtimese(ms) : rxbyte | t repeat until not lockset(debugLock) rxtime(ms) lockclr(debugLock) PUB str(stringptr) '' Send zero terminated string that starts at the stringptr memory address repeat strsize(stringptr) tx(byte[stringptr++]) PUB strs(stringptr) DebugCog if byte[stringptr] == 13 stringptr++ if strsize(stringptr) str(stringptr) PUB stre(stringptr) str(stringptr) lockclr(debugLock) PUB strse(stringptr) strs(stringptr) lockclr(debugLock) PUB getstr(stringptr) | index '' Gets zero terminated string and stores it, starting at the stringptr memory address index~ repeat until ((byte[stringptr][index++] := rx) == 13) byte[stringptr][--index]~ PUB dec(value) | i '' Prints a decimal number if value < 0 -value tx("-") i := 1_000_000_000 repeat 10 if value => i tx(value / i + "0") value //= i result~~ elseif result or i == 1 tx("0") i /= 10 PUB decs(value) | i DebugCog dec(value) PUB dece(value) | i dec(value) lockclr(debugLock) PUB decse(value) | i DebugCog dec(value) lockclr(debugLock) PUB GetDec : value | tempstr[11] '' Gets decimal character representation of a number from the terminal '' Returns the corresponding value GetStr(@tempstr) value := StrToDec(@tempstr) PUB StrToDec(stringptr) : value | char, index, multiply '' Converts a zero terminated string representation of a decimal number to a value value := index := 0 repeat until ((char := byte[stringptr][index++]) == 0) if char => "0" and char =< "9" value := value * 10 + (char - "0") if byte[stringptr] == "-" value := - value PUB bin(value, digits) '' Sends the character representation of a binary number to the terminal. value <<= 32 - digits repeat digits tx((value <-= 1) & 1 + "0") PUB bine(value, digits) bin(value, digits) lockclr(debugLock) PUB GetBin : value | tempstr[11] '' Gets binary character representation of a number from the terminal '' Returns the corresponding value GetStr(@tempstr) value := StrToBin(@tempstr) PUB StrToBin(stringptr) : value | char, index '' Converts a zero terminated string representaton of a binary number to a value value := index := 0 repeat until ((char := byte[stringptr][index++]) == 0) if char => "0" and char =< "1" value := value * 2 + (char - "0") if byte[stringptr] == "-" value := - value PUB hex(value, digits) '' Print a hexadecimal number value <<= (8 - digits) << 2 repeat digits tx(lookupz((value <-= 4) & $F : "0".."9", "A".."F")) PUB hexe(value, digits) hex(value, digits) lockclr(debugLock) PUB GetHex : value | tempstr[11] '' Gets hexadecimal character representation of a number from the terminal '' Returns the corresponding value GetStr(@tempstr) value := StrToHex(@tempstr) PUB StrToHex(stringptr) : value | char, index '' Converts a zero terminated string representaton of a hexadecimal number to a value value := index := 0 repeat until ((char := byte[stringptr][index++]) == 0) if (char => "0" and char =< "9") value := value * 16 + (char - "0") elseif (char => "A" and char =< "F") value := value * 16 + (10 + char - "A") elseif(char => "a" and char =< "f") value := value * 16 + (10 + char - "a") if byte[stringptr] == "-" value := - value DAT '*********************************** '* Assembly language serial driver * '*********************************** org ' ' ' 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,#BUFFER_SIZE '16 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 chunk of tx 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 chunk of tx 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,#MAX_BUFFER_INDEX wrlong t2,par jmp #receive 'byte done, receive next byte ' ' ' Transmit ' transmit jmpret txcode,rxcode 'run chunk of rx 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,#MAX_BUFFER_INDEX 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 test rxtxmode,#%010 wc 'according to mode 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 chunk of rx 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 {{ ┌──────────────────────────────────────────────────────────────────────────────────────┐ │ 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. │ └──────────────────────────────────────────────────────────────────────────────────────┘ }}