X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=arducontrol%2Fs88.c;fp=arducontrol%2Fs88.c;h=1ce574059fd848082d078e34033efeaa19abdd4d;hb=3bbca0dcce53ff9e2cdaa3d39ae18afcbf627f9d;hp=0000000000000000000000000000000000000000;hpb=cd913ccb15a71d793ccd701d3ab8b39a0efeb23a;p=model-railway-devices.git diff --git a/arducontrol/s88.c b/arducontrol/s88.c new file mode 100644 index 0000000..1ce5740 --- /dev/null +++ b/arducontrol/s88.c @@ -0,0 +1,110 @@ +#include +#include "interface.h" +#include "ringbuffer.h" +#include "s88.h" +#include "serial.h" +#include "timer.h" + +#define RESET PORTD4 +#define LOAD PORTD5 +#define CLOCK PORTD6 +#define DATA PIN7 +#define BIT(x) (1<<(x)) + +volatile uint8_t s88_read_count = 0; +uint8_t s88_read_bit = 0; +volatile uint8_t s88_read_phase = 0; +uint8_t s88_data = 0; +RINGBUFFER(s88_buffer, 8); +uint8_t s88_out_index = 0; + +void s88_init(void) +{ + DDRD = (DDRD&0x0F)|0x70; + PORTD &= 0x0F; + + timer_start_hz(0, 80000, 1); +} + +void s88_check(void) +{ + // Only send one packet per check to avoid blocking + if(ringbuffer_fill(s88_buffer)>0) + { + uint8_t reply[3]; + reply[0] = S88_DATA; + reply[1] = s88_out_index++; + reply[2] = ringbuffer_pop(s88_buffer); + interface_send(reply, sizeof(reply)); + } +} + +uint8_t s88_command(const uint8_t *cmd_buf, uint8_t cmd_length) +{ + if(cmd_buf[0]==S88_READ) + { + if(cmd_length!=2) + return LENGTH_ERROR; + + while(s88_read_count || s88_read_phase) ; + + s88_out_index = 0; + s88_read_phase = 0xF0; + s88_read_count = cmd_buf[1]; + } + else + return INVALID_COMMAND; + + return COMMAND_OK; +} + +static inline void s88_tick(void) +{ + if(s88_read_phase==0) + { + if(!s88_read_count || ringbuffer_space(s88_buffer)==0) + return; + + PORTD |= BIT(CLOCK); + } + else if(s88_read_phase==1) + { + uint8_t bit = (PIND>>7)&1; + s88_data = (s88_data<<1)|bit; + ++s88_read_bit; + if(s88_read_bit==8) + { + ringbuffer_push(s88_buffer, s88_data); + + --s88_read_count; + s88_read_bit = 0; + } + } + else if(s88_read_phase==2) + PORTD &= ~BIT(CLOCK); + else if(s88_read_phase>3) + { + if(s88_read_phase==0xF0) + PORTD |= BIT(LOAD); + else if(s88_read_phase==0xF4) + PORTD |= BIT(CLOCK); + else if(s88_read_phase==0xF6) + PORTD &= ~BIT(CLOCK); + else if(s88_read_phase==0xFA) + PORTD |= BIT(RESET); + else if(s88_read_phase==0xFC) + PORTD &= ~BIT(RESET); + else if(s88_read_phase==0xFF) + { + s88_data = (PIND>>7)&1; + ++s88_read_bit; + PORTD &= ~BIT(LOAD); + } + ++s88_read_phase; + return; + } + + s88_read_phase = (s88_read_phase+1)&3; +} + +TIMER_SET_CALLBACK(0, s88_tick)