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