summaryrefslogtreecommitdiff
path: root/firmware/idp8_rx.asm
blob: cad5ae8d34620d27323057a6e2582b8e6d2a835c (plain)
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
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481

; *************************************
; * IDP8 (RX) assembler source        *
; * Written by: Dylan Muller          *
; * Target architecture: AVR ATtiny85 *
; *************************************

; IDP8 = Infrared Data Protocol 8

 .NOLIST
 .INCLUDE "tn85def.inc"
 .LIST 
 
 .equ     CLK_DEL = 99
 .equ     TIM_THRESH = 5 

  ;f(t_timeout) = 25.5ms (25500μs)  * TIM_THRESH
 ; The desired packet timeout time must be multiplied by 25.5ms as a result of register (R25) overflow ,
 ; used in conjunction with R26 to achieve longer time delays (see below) 
 ; and because our clock/counter has a 100us resolution.
 ; The relative time-out delay is achieved by overflowing the 8-bit t_timeout(R25) register and thereafter
 ; incrementing t_timeout_2(R26), continuously comparing R26 with TIM_THRESH, 
 ; until we exceed our delay threshold.

.def     packet_info = R24
.def     dinv_info =   R19
.def     t_timeout =   R25
.def     t_timeout_2 = R26

; Protocol definitions (Specified as a multiple of 100 microseconds)
; This is our chosen timer resolution
.equ      DPACKET_HEADER = 30  ; 3ms (3000μs)
.equ      DPDATA_0 =       20  ; 2ms (2000μs)
.equ      DPDATA_1 =       10  ; 1ms (1000μs)
; Defines pulse delay tolerance 
.equ      SIG_TOLERANCE  = 1   ; +/- 100μs

 ; Reserved registers
 .def     pflags  = R21
 .def     tlapse  = R20
 
 ;TX packet data to be compared with
.equ      I0_PACKET_DATA = 0x1 ; 001  (last bit)(middle bit)(first bit) LSB
; Least significant bit first
.equ      I1_PACKET_DATA = 0x4 ; 100
.equ      I2_PACKET_DATA = 0x5 ; 101
.equ      I3_PACKET_DATA = 0x7 ; 111

; packet_info (R24) register explanation
; 7  6  5  4  3  2  1  0  (bit positions) LSB
; -  -  -  -  -  -  -  -  (packet_info) register
;          -  -  -  -     (packet_info mask bits)
; The packet_info mask bits determine which bit should be validated upon a 
; jump to pk_dtest
; 0 = Packet header validated
; 1 = Data bit 1 validated
; 2 = Data bit 2 validated
; 3 = Data bit 3 validated
; 4 = Data bit 1 value
; 5 = Data bit 2 value
; 6 = Data bit 3 value
; 7 = Reserved

; dinv_info (R19) register explanation
; 7  6  5  4  3  2  1  0  (bit positions) LSB
; -  -  -  -  -  -  -  -  (packet_info) register
; The dinv_info (data inverted) information register is used to
; capture and validate the 3 inverted data bits which are transmitted after
; the 3 normal data bits, this mechanism is used to verify data integrity.

; 0 = INV Data bit 1 validated
; 1 = INV Data bit 2 validated
; 2 = INV Data bit 3 validated
; 3 = Reserved
; 4 = INV Data bit 1 value
; 5 = INV Data bit 2 value
; 6 = INV Data bit 3 value
; 7 = Reserved

; pflags (R21) register explanation
; 7  6  5  4  3  2  1  0  (bit positions) LSB
; -  -  -  -  -  -  -  -  (pflags) register

; 0 = Last pin status of pin 0 (PINB0)
; 1 = tlapse register available for processing
; Status bit 1 is set upon a low-high logic transition on input pin 0 (PINB0)

.CSEG
.ORG      0x00
; Define ISR (Interrupt Service Routine) vectors
; Reset vector
rjmp      reset
reti
; PCINT0 (Pin change interrupt) vector
rjmp      pc_int
reti
reti
reti
reti
reti
reti
reti
;TIMER0_COMPA - Timer 0 (Output Compare Match A) ISR
rjmp      tim0_compa 
;TIMER0_COMPA - Timer 0 (Output Compare Match B) ISR
rjmp      tim0_compb ; Timer compare interrupt

;.org  0xF
; Reset vector sub-routine
reset:
; Stack initialize
ldi      R16,	low(RAMEND) ; 
out      SPL,	R16
; Enable output drivers
ldi      R16,   0x1E
out      DDRB,  R16
; Initialize CTC mode + (CLK/8) prescaler select (TIMER 0)
ldi      R16,   (1 << WGM01)
out      TCCR0A,R16
ldi      R16,   (1 << CS01)
out      TCCR0B,R16
ldi      R16,	CLK_DEL
out      OCR0A, R16
ldi      R16,	CLK_DEL
out      OCR0B,	R16
;Enter power reduction mode | Disable: USI
ldi      R16,   (1 << PRUSI)
out      PRR,   R16
; Enable pin change interrupts for wake up
; Set PCINT masks via PCMSK
ldi      R16,   (1 << PCIE)
out      GIMSK, R16
ldi      R16,   (1 << PCINT0)
out      PCMSK, R16
sei ; Enable interrupts

; Main loop
main:
; Jump if we have a reading
sbrc     pflags,0x1
rjmp     smp_match
rjmp     main

set_packet:
ldi      packet_info, 0x1
rjmp smp_end
packet_reset:
clr      packet_info
rjmp smp_end

smp_match:
cli
in       R22,	SREG
; Has the packet header been validated?
; i.e the packet header validation bit in the packet_header register
; been set?
sbrc     packet_info, 0
rjmp     pd_aquire
; If not test for packet header
pkheader_test:
cpi      tlapse, (DPACKET_HEADER - SIG_TOLERANCE)
brge     pkht_upper
rjmp     smp_end
pkht_upper:
cpi      tlapse, (DPACKET_HEADER + (SIG_TOLERANCE+1))
brlo     set_packet

; Our packet header has been validated at this stage.
pd_aquire:
; Test if any of the 3 data bits in our packet have been processed. 
; If not jump to the respective handler routines
sbrs     packet_info, 1
rjmp     data_1
sbrs     packet_info, 2
rjmp     data_2
sbrs     packet_info, 3
rjmp     data_3
; Testing remaining 3 inverted data bits
sbrs     dinv_info, 0
rjmp     dinv_1
sbrs     dinv_info, 1
rjmp     dinv_2
sbrs     dinv_info, 2
rjmp     dinv_3


; At this stage all the data bits have been
; successfully captured and validated.
; We are ready to process our captured packet
rjmp     data_proc
 

; Handler routines pass the relevant bit mask of the packet_info
; register to the pk_dtest sub-routine. 
; This sub-routine's purpose is to validate the pulse delay
; between high-low and low-high logic transitions (stored in tlapse) 
; on pin 0 (PINB0)
; Furthermore the sub-routine uses this information to differentiate between logic 1
; and logic 0 bit information provided the pulse delay is within configured bounds 
; for those respective logic levels.
; The relevant packet bits are then set accordingly and a jump to smp_end 
; is executed
data_1:
ldi      R23, 0x1
rjmp     pk_dtest
data_2:
ldi      R23, 0x2
rjmp     pk_dtest
data_3:
ldi      R23, 0x4
rjmp     pk_dtest

dinv_1:
ldi      R23, 0x1
rjmp     dinv_test
dinv_2:
ldi      R23, 0x2
rjmp     dinv_test
dinv_3:
ldi      R23, 0x4
rjmp     dinv_test

; Process data packet
data_proc:
; Optional unused status bit. Not needed in this case
;sbr      packet_info, 0x80
;extract data bit values
andi     packet_info, 0x70
ldi      R16, 4
shift_4:
lsr      packet_info
dec      R16
brne     shift_4
; Compare packet data
mov      R16, packet_info
cpi      R16, I0_PACKET_DATA
breq     led
mov      R16, packet_info
cpi      R16, I1_PACKET_DATA
breq     led2
mov      R16, packet_info
cpi      R16, I2_PACKET_DATA
breq     led3
mov      R16, packet_info
cpi      R16, I3_PACKET_DATA
breq     led4
rjmp     smp_clear

;data handler 1
led:
ldi      R16,    0x2
out      PORTB,  R16
rjmp     smp_clear
;data handler 2
led2:
ldi      R16,    0x4
out      PORTB,  R16
rjmp     smp_clear
;data handler 3
led3:
ldi      R16,    0x10
out      PORTB,  R16
rjmp     smp_clear
;data handler 4
led4:
ldi      R16,    0x8
out      PORTB,  R16

smp_clear:
clr      t_timeout
clr      t_timeout_2
; Activate TIMER0_COMPB (tim0_compb) ISR
in       R16,    TIMSK
ori      R16,    (1<< OCIE0B)
out      TIMSK,	 R16
rjmp     packet_reset  

smp_end:  
clr      tlapse
clr      R23
; Clear second bit in pflags
andi     pflags, 0x1
out      SREG,   R22     
sei
rjmp main

; Packet data test sub-routine
; R23 = packet_info bit mask. This mask describes
; which data bit is to be processed if it has not already.
; As noted above, the individual bit meanings in the packet_info register
; are as follows, starting with the least significant bit (LSB)
; 7  6  5  4  3  2  1  0  (bit positions) LSB
; -  -  -  -  -  -  -  -  (packet_info) register
;          -  -  -  -     (packet_info bit mask bits)
; The packet_info mask bits determine which bit should be validated upon a 
; jump to pk_dtest
; 0 = Packet header validated
; 1 = Data bit 1 validated
; 2 = Data bit 2 validated
; 3 = Data bit 3 validated
; 4 = Data bit 1 value
; 5 = Data bit 2 value
; 6 = Data bit 3 value
; 7 = Reserved

; After the sub-routine has finished execution
; the relevant bits in the packet_info register
; would have been set
pk_dtest:

; Shift R23 one bit to the left 
; All bit shifting found in this sub-routine
; is used for setting the correct bits in the
; packet_info register
lsl      R23
; Perform validation via boundary checks,
; taking into account pulse delay tolerances
test_high:
cpi      tlapse, (DPDATA_1 - SIG_TOLERANCE)
brge     dhtest_upper
rjmp     test_low
dhtest_upper:
cpi      tlapse, (DPDATA_1 + (SIG_TOLERANCE+1))
brlo     dset_high
test_low:
cpi      tlapse, (DPDATA_0 - SIG_TOLERANCE)
brge     dltest_upper
rjmp     packet_reset
dltest_upper:
cpi      tlapse, (DPDATA_0 + (SIG_TOLERANCE+1))
brlo     dset_low
rjmp     packet_reset

; The tlapse register (pulse delay) has been validated to logic 1
; the requested validation bit, set by the relevant mask,
; is now set as well as the respective data value bit.
dset_high:
or       packet_info, R23
; shift 3 left
ldi      R16, 3
shift_3:
lsl      R23
dec      R16
brne     shift_3
or       packet_info, R23
rjmp     smp_end

; The tlapse register (pulse delay) has been validated to logic 0
; the requested validation bit, obtained by the relevant mask,
; is now set and the data value bit cleared.
dset_low:
or       packet_info, R23
rjmp     smp_end

dinv_reset:
clr      packet_info
clr      dinv_info
rjmp     smp_end


dinv_test:
dinvtest_high:
cpi      tlapse, (DPDATA_1 - SIG_TOLERANCE)
brge     dhtest_invupper
rjmp     invtest_low
dhtest_invupper:
cpi      tlapse, (DPDATA_1 + (SIG_TOLERANCE+1))
brlo     dinv_hcheck
invtest_low:
cpi      tlapse, (DPDATA_0 - SIG_TOLERANCE)
brge     dltest_invupper
rjmp     dinv_reset
dltest_invupper:
cpi      tlapse, (DPDATA_0 + (SIG_TOLERANCE+1))
brlo     dinv_lcheck
rjmp     dinv_reset

dinv_lcheck:
or       dinv_info, R23
rjmp     dinv_checkl
dinv_hcheck:
or       dinv_info, R23
lsl      R23
ldi      R16, 3
shiftinv_3:
lsl      R23
dec      R16
brne     shiftinv_3
or       dinv_info, R23      
dinv_checkl:
mov      R16, packet_info
andi     R16, 0x70
and      R16, R23
cp       R16, R23
brne     dinvchk_end
rjmp     dinv_reset
dinvchk_end:
rjmp     smp_end


; PCINT0 ISR
; Pin change interrupt service routine
; This ISR is used for timing the delay between
; high-low and low-high state transitions.
; This time delay is then stored in the tlapse register
pc_int:
in       R22,    SREG ; Save SREG
sbrc     pflags, 0
rjmp     pcint_htol

; Status bit 0 in pflags was low before interrupt
pcint_ltoh: 
sbic     PINB,   0
sbr      pflags, 1

sbrs     pflags, 0
rjmp     pcint_ret
in       R16,    TIMSK
andi     R16,    (1 << OCIE0B)
out      TIMSK,	 R16
; Signal reading status
ori      pflags, 0x2
rjmp     pcint_ret

; Status bit 0 in pflags was high before interrupt
pcint_htol: 
sbis     PINB,   0
cbr      pflags, 1

sbrc     pflags, 0
rjmp     pcint_ret
in       R16,    TIMSK
ori      R16,    (1 << OCIE0A)
out      TIMSK,	 R16
clr      R16
clr      tlapse
out      TCNT0,	 R16  

pcint_ret:
out      SREG,   R22
reti 

; TIMER0_COMPA - Timer 0 (Output Compare Match A) ISR
; This ISR is used as the 100μs clock counter
tim0_compa:
inc      tlapse
reti

; TIMER0_COMPB - Timer 0 (Output Compare Match B) ISR
; This ISR is activated upon setting any of the output
; bits in the PORTB register. 
; The ISR serves as a timeout function ,setting all output
; bits in the PORTB register to a logic 0 if a packet is not
; received within the specified time threshold.
; The TIM_THRESH preprocessor definition defines this time threshold.
tim0_compb:
in       R22,    SREG ; Save status register
; Increment until t_timeout overflows
inc      t_timeout
brne     tim0_ret
inc      t_timeout_2
; If t_timeout_2 matches our threshold value carry
; on with execution
cpi      t_timeout_2, TIM_THRESH
brlo     tim0_ret   

; Clear respective registers
clr      R16
out      PORTB,  R16
out      TCNT0,	 R16  
out      TIMSK,	 R16
clr      tlapse
clr      t_timeout
clr      t_timeout_2
clr      pflags
clr      packet_info
clr      dinv_info

tim0_ret:
out      SREG,   R22 ; Restore status register
reti