]> git.tdb.fi Git - model-railway-devices.git/blob - arducontrol/s88.c
Add support for S88 feedback modules
[model-railway-devices.git] / arducontrol / s88.c
1 #include <avr/io.h>
2 #include "interface.h"
3 #include "ringbuffer.h"
4 #include "s88.h"
5 #include "serial.h"
6 #include "timer.h"
7
8 #define RESET PORTD4
9 #define LOAD PORTD5
10 #define CLOCK PORTD6
11 #define DATA PIN7
12 #define BIT(x) (1<<(x))
13
14 volatile uint8_t s88_read_count = 0;
15 uint8_t s88_read_bit = 0;
16 volatile uint8_t s88_read_phase = 0;
17 uint8_t s88_data = 0;
18 RINGBUFFER(s88_buffer, 8);
19 uint8_t s88_out_index = 0;
20
21 void s88_init(void)
22 {
23         DDRD = (DDRD&0x0F)|0x70;
24         PORTD &= 0x0F;
25
26         timer_start_hz(0, 80000, 1);
27 }
28
29 void s88_check(void)
30 {
31         // Only send one packet per check to avoid blocking
32         if(ringbuffer_fill(s88_buffer)>0)
33         {
34                 uint8_t reply[3];
35                 reply[0] = S88_DATA;
36                 reply[1] = s88_out_index++;
37                 reply[2] = ringbuffer_pop(s88_buffer);
38                 interface_send(reply, sizeof(reply));
39         }
40 }
41
42 uint8_t s88_command(const uint8_t *cmd_buf, uint8_t cmd_length)
43 {
44         if(cmd_buf[0]==S88_READ)
45         {
46                 if(cmd_length!=2)
47                         return LENGTH_ERROR;
48
49                 while(s88_read_count || s88_read_phase) ;
50
51                 s88_out_index = 0;
52                 s88_read_phase = 0xF0;
53                 s88_read_count = cmd_buf[1];
54         }
55         else
56                 return INVALID_COMMAND;
57
58         return COMMAND_OK;
59 }
60
61 static inline void s88_tick(void)
62 {
63         if(s88_read_phase==0)
64         {
65                 if(!s88_read_count || ringbuffer_space(s88_buffer)==0)
66                         return;
67
68                 PORTD |= BIT(CLOCK);
69         }
70         else if(s88_read_phase==1)
71         {
72                 uint8_t bit = (PIND>>7)&1;
73                 s88_data = (s88_data<<1)|bit;
74                 ++s88_read_bit;
75                 if(s88_read_bit==8)
76                 {
77                         ringbuffer_push(s88_buffer, s88_data);
78
79                         --s88_read_count;
80                         s88_read_bit = 0;
81                 }
82         }
83         else if(s88_read_phase==2)
84                 PORTD &= ~BIT(CLOCK);
85         else if(s88_read_phase>3)
86         {
87                 if(s88_read_phase==0xF0)
88                         PORTD |= BIT(LOAD);
89                 else if(s88_read_phase==0xF4)
90                         PORTD |= BIT(CLOCK);
91                 else if(s88_read_phase==0xF6)
92                         PORTD &= ~BIT(CLOCK);
93                 else if(s88_read_phase==0xFA)
94                         PORTD |= BIT(RESET);
95                 else if(s88_read_phase==0xFC)
96                         PORTD &= ~BIT(RESET);
97                 else if(s88_read_phase==0xFF)
98                 {
99                         s88_data = (PIND>>7)&1;
100                         ++s88_read_bit;
101                         PORTD &= ~BIT(LOAD);
102                 }
103                 ++s88_read_phase;
104                 return;
105         }
106
107         s88_read_phase = (s88_read_phase+1)&3;
108 }
109
110 TIMER_SET_CALLBACK(0, s88_tick)