]> git.tdb.fi Git - model-railway-devices.git/blob - arducontrol/s88.c
Drop the pretense of C89, put declarations where they make sense
[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 static volatile uint8_t s88_read_count = 0;
15 static uint8_t s88_read_bit = 0;
16 static volatile uint8_t s88_read_phase = 0;
17 static uint8_t s88_data = 0;
18 static RINGBUFFER(s88_buffer, 8);
19 static 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         uint8_t count = ringbuffer_fill(s88_buffer);
32         if(count>=4 || (count>0 && !s88_read_count))
33         {
34                 uint8_t reply[10];
35
36                 reply[0] = S88_DATA;
37                 reply[1] = s88_out_index;
38                 for(uint8_t i=0; i<count; ++i)
39                         reply[2+i] = ringbuffer_pop(s88_buffer);
40                 interface_send(reply, 2+count);
41                 s88_out_index += count;
42         }
43 }
44
45 uint8_t s88_command(const uint8_t *cmd_buf, uint8_t cmd_length)
46 {
47         if(cmd_buf[0]==S88_READ)
48         {
49                 if(cmd_length!=2)
50                         return LENGTH_ERROR;
51
52                 while(s88_read_count || s88_read_phase) ;
53
54                 s88_out_index = 0;
55                 s88_read_phase = 0xF0;
56                 s88_read_count = cmd_buf[1];
57         }
58         else
59                 return INVALID_COMMAND;
60
61         return COMMAND_OK;
62 }
63
64 static inline void s88_tick(void)
65 {
66         if(s88_read_phase==0)
67         {
68                 if(!s88_read_count || ringbuffer_space(s88_buffer)==0)
69                         return;
70
71                 PORTD |= BIT(CLOCK);
72         }
73         else if(s88_read_phase==1)
74         {
75                 uint8_t bit = (PIND>>7)&1;
76                 s88_data = (s88_data<<1)|bit;
77                 ++s88_read_bit;
78                 if(s88_read_bit==8)
79                 {
80                         ringbuffer_push(s88_buffer, s88_data);
81
82                         --s88_read_count;
83                         s88_read_bit = 0;
84                 }
85         }
86         else if(s88_read_phase==2)
87                 PORTD &= ~BIT(CLOCK);
88         else if(s88_read_phase>3)
89         {
90                 if(s88_read_phase==0xF0)
91                         PORTD |= BIT(LOAD);
92                 else if(s88_read_phase==0xF4)
93                         PORTD |= BIT(CLOCK);
94                 else if(s88_read_phase==0xF6)
95                         PORTD &= ~BIT(CLOCK);
96                 else if(s88_read_phase==0xFA)
97                         PORTD |= BIT(RESET);
98                 else if(s88_read_phase==0xFC)
99                         PORTD &= ~BIT(RESET);
100                 else if(s88_read_phase==0xFF)
101                 {
102                         s88_data = (PIND>>7)&1;
103                         ++s88_read_bit;
104                         PORTD &= ~BIT(LOAD);
105                 }
106                 ++s88_read_phase;
107                 return;
108         }
109
110         s88_read_phase = (s88_read_phase+1)&3;
111 }
112
113 TIMER_SET_CALLBACK(0, s88_tick)