]> git.tdb.fi Git - model-railway-devices.git/commitdiff
Add support for S88 feedback modules
authorMikko Rasa <tdb@tdb.fi>
Wed, 23 Oct 2013 21:36:44 +0000 (00:36 +0300)
committerMikko Rasa <tdb@tdb.fi>
Wed, 23 Oct 2013 21:36:44 +0000 (00:36 +0300)
arducontrol/Makefile
arducontrol/arducontrol.c
arducontrol/commands.h
arducontrol/interface.c
arducontrol/s88.c [new file with mode: 0644]
arducontrol/s88.h [new file with mode: 0644]

index b520eb767b1a05eabcd7d88d9442ae621321c73f..a7cb562725e34561feddab560414c594ec50ec10 100644 (file)
@@ -1,3 +1,3 @@
 include ../common/build.mk
 
-arducontrol.elf: adc.o interface.o monitor.o motorola.o output.o serial.o timer.o
+arducontrol.elf: adc.o interface.o monitor.o motorola.o output.o serial.o s88.o timer.o
index 1c8cde9db4830a4e17bcd44726c85fc4e39614d0..8ec27eaf7f291e298f8aa76128883c720c6de504 100644 (file)
@@ -11,6 +11,12 @@ Connections for Pololu high-powered motor driver:
 D2 <-> DIR
 D3 <-> PWM
 
+Connections for S88 bus:
+D4 <-> RESET
+D5 <-> LOAD
+D6 <-> CLOCK
+D7 <-> DATA
+
 ADC connections:
 ADC0 - current sensor (adjusted for 185 mV/A, centered at Vcc/2)
 ADC1 - input voltage (adjusted for divisor of 11)
@@ -38,12 +44,14 @@ its data to the track can start.
 #include "interface.h"
 #include "monitor.h"
 #include "output.h"
+#include "s88.h"
 
 int main(void)
 {
        output_init();
        interface_init();
        monitor_init();
+       s88_init();
 
        sei();
 
@@ -51,6 +59,7 @@ int main(void)
        {
                interface_check();
                monitor_check();
+               s88_check();
        }
 
        return 0;
index 865405d6f9957a6173869d54702abf7617d4ba9b..eae919cee32b0a9778bc4663542248e01ecbd205 100644 (file)
@@ -13,6 +13,7 @@ enum Command
        MOTOROLA_SPEED_DIRECTION = 0x13,
        MOTOROLA_SPEED_FUNCTION = 0x14,
        MOTOROLA_SOLENOID = 0x15,
+       S88_READ = 0x30,
        COMMAND_OK = 0x80,
        RECEIVE_OVERRUN = 0x81,
        FRAMING_ERROR = 0x82,
@@ -21,7 +22,8 @@ enum Command
        INVALID_VALUE = 0x85,
        OVERCURRENT = 0xA0,
        TRACK_CURRENT = 0xC0,
-       INPUT_VOLTAGE = 0xC1
+       INPUT_VOLTAGE = 0xC1,
+       S88_DATA = 0xD0
 };
 
 #endif
index 96baba7f0a4d154110bcf826fd804d5f3e7d0f86..4064120992bd16e4a38e20446f3d98085ff785ba 100644 (file)
@@ -3,6 +3,7 @@
 #include "motorola.h"
 #include "output.h"
 #include "serial.h"
+#include "s88.h"
 
 volatile uint8_t recv_buf[32];
 uint8_t recv_head = 0;
@@ -83,6 +84,8 @@ uint8_t dispatch_command(const uint8_t *cmd, uint8_t length)
        }
        else if(type==1)
                return motorola_command(cmd, length);
+       else if(type==3)
+               return s88_command(cmd, length);
        else
                return INVALID_COMMAND;
 }
diff --git a/arducontrol/s88.c b/arducontrol/s88.c
new file mode 100644 (file)
index 0000000..1ce5740
--- /dev/null
@@ -0,0 +1,110 @@
+#include <avr/io.h>
+#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)
diff --git a/arducontrol/s88.h b/arducontrol/s88.h
new file mode 100644 (file)
index 0000000..b440ebe
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef S88_H_
+#define S88_H_
+
+#include <stdint.h>
+
+void s88_init(void);
+void s88_check(void);
+uint8_t s88_command(const uint8_t *, uint8_t);
+
+#endif