#include #include #include #include #include "uart.h" // which pin is the zener diode connected to #define read_scx_pin() (PINB & _BV(PB2)) // how many consecutive readings have to be the same in order to // accept the pin value #define DENOISE_COUNT 4 #ifndef F_CPU #error "F_CPU not defined. Set F_CPU in Makefile." #endif #define STEP (F_CPU/115200) // duration of one bit #define BYTE_PAUSE_MAX (20*STEP) // inter-packet length threshold void tc1_init() { TCNT1 = 0; TCCR1B = _BV(CS10); // run at F_CPU clock, no prescaling } // read the value until it is stable, i.e. until DENOISE_COUNT consecutive // readings give the same value static unsigned char read_scx_pin_denoised() { unsigned char prev, count; count = 0; prev = read_scx_pin(); while (count < DENOISE_COUNT) { unsigned char curr = read_scx_pin(); if (curr != prev) { count = 0; prev = curr; } else { ++count; } } return prev; } // how long we waited for the start bit static unsigned char long_byte_wait; static unsigned char read_scx_byte() { unsigned short curr_time, prev_time, interval; unsigned char data, i, toolong = 0, step; retry: // wait for 0, distinguish between inter- and intra-packet wait times prev_time = TCNT1; long_byte_wait = 0; while (read_scx_pin_denoised()) { curr_time = TCNT1; if (curr_time - prev_time > BYTE_PAUSE_MAX) long_byte_wait = 1; } ATOMIC_BLOCK(ATOMIC_FORCEON) { // wait for 1 (end of the first start-bit), // remember the length of the start bit // in order to distinguish between car and other packets prev_time = curr_time = TCNT1; interval = 0; while (!read_scx_pin_denoised()) { // wait for 1 curr_time = TCNT1; interval = curr_time - prev_time; if (interval >= 4*STEP) { // start bit too long if (!toolong) { uart_tx_byte(0x12, 0); toolong = 1; } goto retry; } }; toolong = 0; // start bit too short if (interval < 3*STEP/4) { uart_tx_byte(0x10, 0); goto retry; } // car packets are at 57600 baud, start bit is twice as long step = interval > (3*STEP/2) ? 2*STEP : STEP; // advance into the middle of the next bit curr_time += step / 2; // start bit detected, now read the eight data bits data = 0; for (i = 0; i < 8; i++) { data >>= 1; while (TCNT1 - curr_time < step) ; data |= read_scx_pin_denoised() ? 0x80 : 0; curr_time += step; } // read stop bit while (TCNT1 - curr_time < step) ; if (!read_scx_pin_denoised()) // no stop bit? uart_tx_byte(0x13, 0); // report error, but return data anyway }; // ATOMIC return data; } extern unsigned char version[], version_len; static void print_version() { unsigned char i; for (i = 0; i < version_len; i++) uart_tx_byte(version[i], 0); } int main() { unsigned char count = 0, pkt_len = 0; uart_init(); tc1_init(); sei(); _delay_ms(1000); print_version(); _delay_ms(500); // main loop while (1) { unsigned char byte = read_scx_byte(); uart_tx_byte(byte, 0); count++; count &= 0x7F; // avoid overflow // try to synchronize with the packet start // - we need this in order to determine the packet length // and in order to add 0x05 end byte after the packet if (byte == 0x55 && long_byte_wait) count = 1; if (count == 2) { if (byte >= 0x40 && byte <= 0x45) { // car pkt pkt_len = 5; } else { pkt_len = 9; } } if (count == pkt_len) { uart_tx_byte(0x05, 0); // SEB interface compatibility count = 0; } } // NOTREACHED }