-
Notifications
You must be signed in to change notification settings - Fork 1
/
packet_driver.spin
409 lines (355 loc) · 15.3 KB
/
packet_driver.spin
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
''*********************************************
''* Bidirectional Packet Driver *
''* (C) 2011-2015 David Betz *
''* Based on: *
''* Full-Duplex Serial Driver v1.1 Extended *
''* (C) 2006 Parallax, Inc. *
''*********************************************
CON
' command codes
#0
CMD_IDLE ' must be zero
CMD_RXPACKET
CMD_TXPACKET
' status codes
#0
STATUS_OK
STATUS_ERROR
' init offsets
#0
INIT_MBOX ' zeroed by driver after init is done
INIT_RXPIN
INIT_TXPIN
INIT_BAUDRATE
_INIT_SIZE
' mailbox offsets
#0
MBOX_CMD
MBOX_TYPE ' or pointer to type on rx
MBOX_BUFFER
MBOX_LENGTH ' or pointer to length on rx
MBOX_STATUS
MBOX_COG ' not really part of the mailbox
_MBOX_SIZE
' character codes
SOH = $01 ' start of a packet
VAR
long mbox[_MBOX_SIZE]
PUB start(rxpin, txpin, baudrate) | init[_INIT_SIZE], cogn
'' Start packet driver - starts a cog
'' returns zero on success and non-zero if no cog is available
''
' stop the driver if it's already running
stop
' start the driver cog
init[INIT_MBOX] := @mbox
init[INIT_RXPIN] := rxpin
init[INIT_TXPIN] := txpin
init[INIT_BAUDRATE] := clkfreq / baudrate
cogn := mbox[MBOX_COG] := cognew(@entry, @init) + 1
' if the cog started okay wait for it to finish initializing
if cogn
repeat while init[INIT_MBOX] <> 0
return !cogn
PUB stop
if mbox[MBOX_COG]
cogstop(mbox[MBOX_COG]~ - 1)
PUB rx(ptype, buffer, plength)
mbox[MBOX_BUFFER] := buffer
mbox[MBOX_LENGTH] := long[plength]
mbox[MBOX_CMD] := CMD_RXPACKET
repeat while mbox[MBOX_CMD] <> CMD_IDLE
long[ptype] := mbox[MBOX_TYPE]
long[plength] := mbox[MBOX_LENGTH]
return mbox[MBOX_STATUS]
PUB tx(type, buffer, length)
mbox[MBOX_TYPE] := type
mbox[MBOX_BUFFER] := buffer
mbox[MBOX_LENGTH] := length
mbox[MBOX_CMD] := CMD_TXPACKET
repeat while mbox[MBOX_CMD] <> CMD_IDLE
return mbox[MBOX_STATUS]
DAT
'***********************************
'* Assembly language serial driver *
'***********************************
org
'
'
' Entry
'
entry mov t1, par 'get init structure address
rdlong t2, t1 'get the mailbox address
mov cmd_ptr, t2 'offset 0 - cmd
add t2, #4
mov pkt_type_ptr, t2 'offset 1 - type
add t2, #4
mov pkt_buffer_ptr, t2 'offset 2 - buffer
add t2, #4
mov pkt_length_ptr, t2 'offset 3 - length
add t2, #4
mov pkt_status_ptr, t2 'offset 4 - status
add t1, #4 'get rx_pin
rdlong t2, t1
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 bit_ticks
rdlong bitticks, t1
or outa, txmask 'initialize the tx pin
or dira, txmask
andn dira, rxmask 'initialize the rx pin
rdlong t1, #0
add t1, cnt
waitcnt t1, #0
mov t1, #CMD_IDLE 'no command in progress
wrlong t1, cmd_ptr
mov t1, #0 'signal end of initialization
wrlong t1, par
next_cmd mov t1, #CMD_IDLE 'no command in progress
wrlong t1, cmd_ptr
:wait rdlong t1, cmd_ptr wz 'wait for a command
if_z jmp #:wait
add t1, #dispatch
jmp t1
dispatch jmp #next_cmd 'should never happen
jmp #do_rxpacket
jmp #do_txpacket
' receive a packet
do_rxpacket rdlong rcv_ptr, pkt_buffer_ptr
rdlong t1, pkt_length_ptr
rdlong rcv_max, t1
call #rxpacket
if_c wrlong ok_status, pkt_status_ptr
if_c wrlong rcv_type, pkt_type_ptr
if_c wrlong rcv_length, pkt_length_ptr
if_nc wrlong error_status, pkt_status_ptr
jmp #next_cmd
' send a packet
do_txpacket rdlong xmt_type, pkt_type_ptr
rdlong xmt_ptr, pkt_buffer_ptr
rdlong xmt_length, pkt_length_ptr
call #txpacket
if_c wrlong ok_status, pkt_status_ptr
if_nc wrlong error_status, pkt_status_ptr
jmp #next_cmd
ok_status long STATUS_OK
error_status long STATUS_ERROR
' receive a packet
' input:
' rcv_ptr points to the receive buffer
' rcv_max is the maximum number of bytes to receive
' output:
' rcv_type is the packet type
' rcv_length is the length of the packet received
' C is set on return if the packet was received successfully
' C is clear on return if there was an error
rxpacket call #rxbyte
cmp rxdata, #SOH wz
if_nz jmp #rxpacket
call #rxbyte ' receive packet type
mov rcv_type, rxdata
mov rcv_chk, rxdata
call #rxbyte ' receive hi byte of packet length
mov rcv_length, rxdata
shl rcv_length, #8
add rcv_chk, rxdata
call #rxbyte ' receive lo byte of packet length
or rcv_length, rxdata
add rcv_chk, rxdata
call #rxbyte ' receive header checksum
and rcv_chk, #$ff
cmp rxdata, rcv_chk wz
if_nz jmp #rxerror
cmp rcv_length, rcv_max wz, wc
if_a jmp #rxerror
mov crc, #0
mov rcv_cnt, rcv_length wz
if_z jmp #:crc
:next call #rxbyte ' receive the next data byte
mov crcdata, rxdata
call #updcrc ' update the crc
wrbyte rxdata, rcv_ptr
add rcv_ptr, #1
djnz rcv_cnt, #:next
:crc call #rxbyte
mov crcdata, rxdata
call #updcrc ' update the crc
call #rxbyte
mov crcdata, rxdata
call #updcrc ' update the crc
cmp crc, #0 wz ' check the crc
if_nz jmp #rxerror
test $, #1 wc ' set c to indicate success
rxpacket_ret ret
rxerror test $, #0 wc ' clear c to indicate failure
jmp rxpacket_ret
' transmit a packet
' input:
' xmt_type is the packet type
' xmt_ptr points to the packet data
' xmt_length is the number of bytes of data
' output:
' C is set on return if the packet was received successfully
' C is clear on return if there was an error
txpacket mov txdata, #SOH
call #txbyte
mov txdata, xmt_type
mov xmt_chk, txdata
call #txbyte
mov txdata, xmt_length
shr txdata, #8
add xmt_chk, txdata
call #txbyte
mov txdata, xmt_length
and txdata, #$ff
add xmt_chk, txdata
call #txbyte
mov txdata, xmt_chk
and txdata, #$ff
call #txbyte
mov crc, #0
mov xmt_cnt, xmt_length wz
if_z jmp #:crc
:next rdbyte txdata, xmt_ptr
add xmt_ptr, #1
mov crcdata, txdata
call #updcrc
call #txbyte
djnz xmt_cnt, #:next
:crc mov crcdata, #0
call #updcrc
call #updcrc
mov txdata, crc
shr txdata, #8
call #txbyte
mov txdata, crc
and txdata, #$ff
call #txbyte
test $, #1 wc ' set c to indicate success
txpacket_ret ret
' receive a byte
' output:
' rxdata is the byte received
rxbyte waitpne rxmask, rxmask ' wait for a start bit
mov rxcnt, bitticks ' wait until half way through the bit time
shr rxcnt, #1
add rxcnt, bitticks
add rxcnt, cnt
mov rxbits, #9 ' receive 8 data bits and the stop bit
:next waitcnt rxcnt, bitticks ' wait until the center of the next bit
test rxmask, ina wc ' sample the rx pin
rcr rxdata, #1 ' add to the byte being received
djnz rxbits, #:next
shr rxdata, #32-9 ' shift the received data to the low bits
and rxdata, #$ff ' mask off the stop bit
waitpeq rxmask, rxmask ' wait for the end of the stop bit
rxbyte_ret ret
' transmit a byte
' input:
' txdata is the byte to send (destroyed on return)
txbyte or txdata, #$100 ' or in a stop bit
shl txdata, #1 ' shift in a start bit
mov txcnt, cnt
add txcnt, bitticks
mov txbits, #10
:next shr txdata, #1 wc
muxc outa, txmask
waitcnt txcnt, bitticks
djnz txbits, #:next
waitcnt txcnt, bitticks
txbyte_ret ret
bitticks long 0
rxmask long 0
rxdata long 0
rxbits long 0
rxcnt long 0
txmask long 0
txdata long 0
txbits long 0
txcnt long 0
' update the crc
' input:
' crc the current crc
' crcdata the data to add to the crc
' output:
' crc the updated crc
updcrc mov t1, crc
test t1, #$100 wz
shr t1, #9
add t1, #crctab
movs :load, t1
shl crc, #8
:load mov t1, 0-0
if_nz shr t1, #16
xor crc, t1
xor crc, crcdata
and crc, word_mask
updcrc_ret ret
crc long 0
crcdata long 0
'
'
' Initialized data
'
'
zero long 0
word_mask long $ffff
crctab
word $0000, $1021, $2042, $3063, $4084, $50a5, $60c6, $70e7
word $8108, $9129, $a14a, $b16b, $c18c, $d1ad, $e1ce, $f1ef
word $1231, $0210, $3273, $2252, $52b5, $4294, $72f7, $62d6
word $9339, $8318, $b37b, $a35a, $d3bd, $c39c, $f3ff, $e3de
word $2462, $3443, $0420, $1401, $64e6, $74c7, $44a4, $5485
word $a56a, $b54b, $8528, $9509, $e5ee, $f5cf, $c5ac, $d58d
word $3653, $2672, $1611, $0630, $76d7, $66f6, $5695, $46b4
word $b75b, $a77a, $9719, $8738, $f7df, $e7fe, $d79d, $c7bc
word $48c4, $58e5, $6886, $78a7, $0840, $1861, $2802, $3823
word $c9cc, $d9ed, $e98e, $f9af, $8948, $9969, $a90a, $b92b
word $5af5, $4ad4, $7ab7, $6a96, $1a71, $0a50, $3a33, $2a12
word $dbfd, $cbdc, $fbbf, $eb9e, $9b79, $8b58, $bb3b, $ab1a
word $6ca6, $7c87, $4ce4, $5cc5, $2c22, $3c03, $0c60, $1c41
word $edae, $fd8f, $cdec, $ddcd, $ad2a, $bd0b, $8d68, $9d49
word $7e97, $6eb6, $5ed5, $4ef4, $3e13, $2e32, $1e51, $0e70
word $ff9f, $efbe, $dfdd, $cffc, $bf1b, $af3a, $9f59, $8f78
word $9188, $81a9, $b1ca, $a1eb, $d10c, $c12d, $f14e, $e16f
word $1080, $00a1, $30c2, $20e3, $5004, $4025, $7046, $6067
word $83b9, $9398, $a3fb, $b3da, $c33d, $d31c, $e37f, $f35e
word $02b1, $1290, $22f3, $32d2, $4235, $5214, $6277, $7256
word $b5ea, $a5cb, $95a8, $8589, $f56e, $e54f, $d52c, $c50d
word $34e2, $24c3, $14a0, $0481, $7466, $6447, $5424, $4405
word $a7db, $b7fa, $8799, $97b8, $e75f, $f77e, $c71d, $d73c
word $26d3, $36f2, $0691, $16b0, $6657, $7676, $4615, $5634
word $d94c, $c96d, $f90e, $e92f, $99c8, $89e9, $b98a, $a9ab
word $5844, $4865, $7806, $6827, $18c0, $08e1, $3882, $28a3
word $cb7d, $db5c, $eb3f, $fb1e, $8bf9, $9bd8, $abbb, $bb9a
word $4a75, $5a54, $6a37, $7a16, $0af1, $1ad0, $2ab3, $3a92
word $fd2e, $ed0f, $dd6c, $cd4d, $bdaa, $ad8b, $9de8, $8dc9
word $7c26, $6c07, $5c64, $4c45, $3ca2, $2c83, $1ce0, $0cc1
word $ef1f, $ff3e, $cf5d, $df7c, $af9b, $bfba, $8fd9, $9ff8
word $6e17, $7e36, $4e55, $5e74, $2e93, $3eb2, $0ed1, $1ef0
'
' Uninitialized data
'
t1 res 1
t2 res 1
xmt_type res 1
xmt_length res 1
xmt_chk res 1
xmt_ptr res 1
xmt_cnt res 1
rcv_type res 1
rcv_length res 1 'packet length
rcv_chk res 1 'header checksum
rcv_max res 1 'maximum packet data length
rcv_ptr res 1 'data buffer pointer
rcv_cnt res 1 'data buffer count
cmd_ptr res 1
pkt_type_ptr res 1
pkt_buffer_ptr res 1
pkt_length_ptr res 1
pkt_status_ptr res 1
fit 496