#define DALI_INVALID 0xa0cc enum dali_state { DALI_IDLE = 0, DALI_SPACE, // 1 DALI_DEAD_SPACE, // 2 DALI_RX_SBIT, // 3 DALI_RX_DATA, // 4 DALI_TX_SBIT0, // 5 DALI_TX_SBIT1, // 6 DALI_TX_0, // 7 DALI_TX_1, // 8 DALI_TX_STOP, // 9 }; static volatile uint8_t dali_state; static volatile uint8_t dali_rx; static volatile bool dali_rx_avail; static volatile uint16_t dali_tx; static volatile bool dali_tx_rq; #define XBUF 48 static uint8_t dbuf[XBUF], sbuf[XBUF], dbufpos; #define dali_s_listening() (dali_state <= DALI_SPACE) #define dali_s_cdr() (dali_state == DALI_RX_DATA) #define DEBUG 0 ISR(TIMER0_COMPA_vect) { static uint8_t history = 0; #define hist_size 5 #define hist_mask ((1 << hist_size) - 1) #define hist_majority_1() (((history | (history + 1)) & hist_mask) == hist_mask) #define hist_majority_0() (((history & (history - 1)) & hist_mask) == 0) static uint8_t bitpos = 0; static uint8_t rx_prevstate_errs, rx_data; static uint16_t tx_data; uint8_t bit = 0; static uint8_t subsamp = 0; subsamp++; subsamp &= 7; /* CTC mode didn't work, CBA to debug */ TCNT0 = 0; history <<= 1; history |= (PIND >> D_DALII) & 1; /* * subsamp 1 2 3 4 5 6 7 0 || * ^ state trigger * /edge/ <----------- stable / sample ----------> */ if (dali_s_cdr()) { if (subsamp >= 3 && subsamp <= 5 && ((history & 0x0f) == 0x03 || (history & 0x0f) == 0x0c)) { // uart_puts(""); subsamp = 4; } } if (dali_s_listening() && hist_majority_1()) { rx_prevstate_errs = dali_state; dali_state = DALI_RX_SBIT; subsamp = 1; } if (subsamp) return; if (dali_state != DALI_IDLE && dbufpos < XBUF) { sbuf[dbufpos] = dali_state; dbuf[dbufpos++] = history; } switch (dali_state) { case DALI_SPACE: case DALI_DEAD_SPACE: if (bitpos > 0) { bitpos--; return; } dali_state = DALI_IDLE; case DALI_IDLE: break; case DALI_RX_SBIT: if (!hist_majority_0()) { uart_puts(""); dali_state = rx_prevstate_errs; return; } dali_state = DALI_RX_DATA; rx_prevstate_errs = 0; rx_data = 0; bitpos = 0; break; case DALI_RX_DATA: if (!(hist_majority_1() || hist_majority_0())) { rx_prevstate_errs++; uart_puts(""); bit = 0; } else bit = hist_majority_1(); if (bitpos & 1) { if (bit == (rx_data & 1)) { rx_prevstate_errs++; uart_puts(""); } } else { rx_data <<= 1; rx_data |= bit; } bitpos++; if (bitpos == 16) { bitpos = 20; dali_state = DALI_DEAD_SPACE; if (!rx_prevstate_errs) { dali_rx = rx_data; dali_rx_avail = 1; } } break; case DALI_TX_SBIT0: bit = 1; dali_state = DALI_TX_SBIT1; break; case DALI_TX_SBIT1: bit = 0; dali_state = DALI_TX_0; break; case DALI_TX_0: if (bitpos == 16) { bitpos = 8; dali_state = DALI_TX_STOP; PORTD |= (1 << D_DALIO); } else { bit = (tx_data & (1 << (15 - bitpos))) ? 1 : 0; dali_state = DALI_TX_1; } break; case DALI_TX_1: bit = (tx_data & (1 << (15 - bitpos))) ? 0 : 1; bitpos++; dali_state = DALI_TX_0; break; case DALI_TX_STOP: if (bitpos == 0) { dali_tx_rq = 0; bitpos = 25; dali_state = DALI_SPACE; } else bitpos--; break; } if ((dali_state == DALI_TX_SBIT1) || (dali_state == DALI_TX_0) || (dali_state == DALI_TX_1)) { if (bit) { PORTD &= ~(1 << D_DALIO); } else { PORTD |= (1 << D_DALIO); } } #if DEBUG if (dali_state != DALI_IDLE || bitpos != 0) uart_puts("\n"); #endif if (dali_state == DALI_IDLE && dali_tx_rq) { tx_data = dali_tx; bitpos = 0; dali_tx = DALI_INVALID; dali_tx_rq = 2; dali_state = DALI_TX_SBIT0; subsamp = 7; } } static void dali_send(uint16_t word) { uart_wait(); uart_puts("\n\n\ndali_send "); uart_puthex(word >> 8); uart_puthex(word & 0xff); uart_puts("\n"); uart_wait(); dbufpos = 0; dali_rx_avail = 0; dali_tx = word; asm volatile ("" ::: "memory"); dali_tx_rq = 1; while (dali_tx_rq || dali_state != DALI_IDLE) { asm volatile ("" ::: "memory"); } uart_wait(); uart_puts("dali_sent "); uart_puthex(word >> 8); uart_puthex(word & 0xff); uart_puts(" "); if (dali_rx_avail) uart_puthex(dali_rx); else uart_puts("norx"); uart_puts("\n"); uart_wait(); for (uint8_t x = 0; x < dbufpos; x++) uart_puthex(sbuf[x]); uart_puts("\n"); uart_wait(); for (uint8_t x = 0; x < dbufpos; x++) uart_puthex(dbuf[x]); uart_puts("\n"); uart_wait(); } static void dali_twice(uint16_t word) { dali_send(word); dali_send(word); } static void dali_init(void) { PORTD |= (1 << D_DALII) | (1 << D_DALIO); dali_state = DALI_IDLE; dali_tx_rq = 0; dali_rx_avail = 0; TIFR0 = (1 << OCF0A); TCNT0 = 0; OCR0A = 52; // 8 MHz / 8 / 52 = 19230. asm volatile ("" ::: "memory"); TIMSK0 = (1 << OCIE0A); TCCR0A = 0; asm volatile ("" ::: "memory"); TCCR0B = (0 << CS02) | (1 << CS01) | (0 << CS00); // 8 MHz / 8 = 1MHz }