#define _dbg_dump_ret() #define dbg_dump_ret() do { \ union { uint16_t u; void *p; } ret = { .p = __builtin_return_address(0) }; \ _uart_putch('#'); uart_puthex16((ret.u & 0xfff) << 1); _uart_putch('\n'); } while (0) #define F_CPU 8000000 #include #include #include #include #include #include #include #include const uint8_t __signature[3] __attribute__((section (".signature"), used)) = { SIGNATURE_2, SIGNATURE_1, SIGNATURE_0 }; #define B_SCK 5 #define B_MISO 4 #define B_MOSI 3 #define B_SS 2 #define D_TXD 1 #define D_DALII 3 #define D_DALIO 4 #define D_LED1 5 #define D_LED2 6 #define D_TAST 7 static uint8_t target[0x40] = { 0 }; static uint8_t cooldown[0x40] = { 0 }; static void target_set(uint8_t dst, uint8_t val); #define target_get(idx) target[idx] /* [0] bit 0 => addr 0, [0] bit 1 => addr 1, etc. */ static uint8_t dali_map[8]; #define target_present(addr) (dali_map[(addr) >> 3] & (1 << ((addr) & 0x07))) #define target_set_present(addr) dali_map[(addr) >> 3] |= 1 << ((addr) & 0x7) #include "uart.c" #include "tick.c" #include "dali2.c" #include "dali_ctl.c" #include "dim.c" #include "can.c" #include "wdt.c" #include "helpers.c" #define CANA_DALI_BASE 0x440 static uint16_t ctr = 0; #define CTR_SENDT 0x1c0 #define CTR_SENDTARGET 0x1d0 #define CTR_SENDSTATE 0x200 #define CTR_SENDEND 0x230 #define T_EVG_COOLDOWN 200 // * 5ms = 1s cooldown after switchoff static void target_cooldown(void) { for (uint8_t i = 0; i < 0x40; i++) if (cooldown[i]) { cooldown[i]--; if ((cooldown[i] == 0) && target[i]) { uint8_t val = target[i]; if (val == 0xff) val = 0xfe; dali_send((i << 9) | 0x108); dali_send((i << 9) | val); } } } static void target_set(uint8_t dst, uint8_t val) { target[dst] = val; uart_puts("++ SET "); uart_puthex(dst); uart_puts(" = "); uart_puthex(val); uart_puts("\n"); if (!val) { dali_send((dst << 9) | 0x100); cooldown[dst] = T_EVG_COOLDOWN; } else { if (val == 0xff) val = 0xfe; if (!cooldown[dst]) { dali_send((dst << 9) | 0x108); dali_send((dst << 9) | val); } } /* clear timer to trigger immediate updates on CAN */ if (ctr < CTR_SENDT || ctr >= CTR_SENDEND) ctr = CTR_SENDT; } static void can_handle_light(uint16_t sublab_addr) { /* - 7 allows overlapping writes to a nonaligned address. * "base" below will start out at 0xf9~0xff in that case */ if (sublab_addr < CANA_DALI_BASE - 7) return; uint8_t base = sublab_addr - CANA_DALI_BASE, len = can_rx_len(), pos; for (pos = 0; pos < len; pos++) { uint8_t dst = base + pos, val; if (dst >= 0x40) continue; val = can_rx_data[pos]; target_set(dst, val); } } const uint8_t dalidisc_page0[6] PROGMEM = {0x01, 0x01, 0x00, 0x01, 0x00, 0x00}; const uint8_t dalidisc_page8[4] PROGMEM = {'D', 'A', 'L', 'I'}; static uint8_t dali_grab_value(uint8_t busaddr, uint8_t cmd) { dali_send(0x100 | (busaddr << 9) | cmd); return dali_rx_avail ? dali_rx : 0xff; } static void can_handle_disco(uint16_t sublab_addr) { wdt_reset(); if (sublab_addr < CANA_DALI_BASE) return; uint8_t addr = sublab_addr - CANA_DALI_BASE; uint8_t page = can_rx_sublab_disco_page(); uint8_t buf[8]; if (!can_rx_ext_rr()) { uart_puts("nRR\n"); switch (page) { case 5: if (can_rx_len() != 2) return; dali_send((can_rx_data[0] << 8) | can_rx_data[1]); can_send(CANA_DISCOVERY_F(page, sublab_addr), !!dali_rx_avail, (uint8_t *)&dali_rx); return; } return; } #define loadpgm(what) for (uint8_t c = 0; c < sizeof(what); c++) buf[c] = pgm_read_byte(what + c); switch (page) { case 0: loadpgm(dalidisc_page0); can_send(CANA_DISCOVERY_F(page, sublab_addr), sizeof(dalidisc_page0), buf); return; case 6: /* page 6: * VERSION NUMBER * DEVICE TYPE * PHYSICAL MIN LEVEL * RANDOM ADDRESS H * RANDOM ADDRESS M * RANDOM ADDRESS L */ buf[0] = dali_grab_value(addr, 0x97); buf[1] = dali_grab_value(addr, 0x99); buf[2] = dali_grab_value(addr, 0x9a); buf[3] = dali_grab_value(addr, 0xc2); buf[4] = dali_grab_value(addr, 0xc3); buf[5] = dali_grab_value(addr, 0xc4); can_send(CANA_DISCOVERY_F(page, sublab_addr), 6, buf); return; case 7: /* page 7: * ACTUAL DIM LEVEL * MAX LEVEL * MIN LEVEL * POWER ON LEVEL * SYSTEM FAILURE LEVEL * FADE RATE, FADE TIME (2x 4 bit) * STATUS * SHORT ADDRESS (or 0xff if no device) */ for (uint8_t offs = 0; offs < 6; offs++) buf[offs] = dali_grab_value(addr, 0xa0 + offs); buf[6] = dali_grab_value(addr, 0x90); dali_send(0x191 | (addr << 9)); buf[7] = dali_rx_avail ? addr : 0xff; can_send(CANA_DISCOVERY_F(page, sublab_addr), 8, buf); return; case 8: loadpgm(dalidisc_page8); can_send(CANA_DISCOVERY_F(page, sublab_addr), sizeof(dalidisc_page8), buf); return; default: can_send(CANA_DISCOVERY_F(page, sublab_addr), 0, NULL); } } static void can_rx_exec(void) { uint16_t sublab_addr, sublab_proto; if (!can_rx_isext()) return; sublab_addr = can_rx_sublab_addr(); if (sublab_addr >= CANA_DALI_BASE + 64) return; sublab_proto = can_rx_sublab_proto(); switch (sublab_proto) { case 0xcc08: can_handle_light(sublab_addr); return; case 0x4c08: can_handle_disco(sublab_addr); return; } } int main(void) { wdt_init(); DDRD |= (1 << D_LED1) | (1 << D_LED2 ) | (1 << D_TXD) | (1 << D_DALIO); PORTD |= (1 << D_LED1) | (1 << D_TAST); PORTD &= ~(1 << D_LED1); uart_init(); tick_init(); can_preinit(); dali_init(); dim_init(); postinit_slowboot(); dali_buscheck(); can_init(); can_CANSTAT(); wdt_reset(); dali_search(); while (1) { wdt_reset(); if (can_rx_avail()) { can_rx_exec(); can_rx_pop(); } _delay_ms(5); do_tick(); target_cooldown(); ctr++; switch (ctr) { case 2048: ctr = 0; break; case CTR_SENDTARGET + 0: case CTR_SENDTARGET + 4: case CTR_SENDTARGET + 8: case CTR_SENDTARGET + 12: case CTR_SENDTARGET + 16: case CTR_SENDTARGET + 20: case CTR_SENDTARGET + 24: case CTR_SENDTARGET + 28: if (dali_map[(ctr >> 2) & 7]) { uint8_t buffer[8] = {0, 0, 0, 0, 0, 0, 0, 0}; uint8_t base = (ctr << 1) & 070, map = dali_map[(ctr >> 2) & 7], dlc = 0; uart_puttick(); uart_puts("tt"); uart_puthex(base); uart_puts("> "); for (int i = 0; i < 8; i++) if (map & (1 << i)) { buffer[i] = target[base + i]; uart_puthex(dali_rx); uart_puts(" "); dlc = i + 1; } else uart_puts("-- "); uart_puts("\n"); can_send(CANA_LIGHT_F(0, CANA_DALI_BASE + base), dlc, buffer); } break; case CTR_SENDSTATE + 0: case CTR_SENDSTATE + 4: case CTR_SENDSTATE + 8: case CTR_SENDSTATE + 12: case CTR_SENDSTATE + 16: case CTR_SENDSTATE + 20: case CTR_SENDSTATE + 24: case CTR_SENDSTATE + 28: if (dali_map[(ctr >> 2) & 7]) { uint8_t buffer[8] = {0, 0, 0, 0, 0, 0, 0, 0}; uint8_t base = (ctr << 1) & 070, map = dali_map[(ctr >> 2) & 7], dlc = 0; uart_puttick(); uart_puts("ll"); uart_puthex(base); uart_puts("> "); for (int i = 0; i < 8; i++) if (map & (1 << i)) { dali_send(0x1a0 | ((base + i) << 9)); if (dali_rx_avail) { buffer[i] = dali_rx; uart_puthex(dali_rx); uart_puts(" "); } else uart_puts("EE "); dlc = i + 1; } else uart_puts("-- "); uart_puts("\n"); can_send(CANA_SENSOR_F(CANA_DALI_BASE + base), dlc, buffer); } break; case 1024: can_send(CANA_DEBUG, 8, (uint8_t *)&dalistat); uart_puttick(); uart_puts("dali stats: "); uart_puthex16(dalistat.rxok); uart_puts(" ok "); uart_puthex16(dalistat.falsestart); uart_puts(" f-start "); uart_puthex16(dalistat.noise); uart_puts(" noise "); uart_puthex16(dalistat.manchester); uart_puts(" mch-err\n"); break; } } } void __do_copy_data(void) __attribute__((naked, section (".init4"), used)); void __do_copy_data(void) { }