From 415ca2037b3cefc64ee59279950fe85fa679e3cd Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Thu, 20 Sep 2012 11:03:21 +0200 Subject: lightctrl: implement discovery protocol --- can.c | 16 +++++- lightctrl.c | 182 ++++++++++++++++++++++++++++++++++++++++++++++++------------ 2 files changed, 161 insertions(+), 37 deletions(-) diff --git a/can.c b/can.c index 8969b7c..6deff37 100644 --- a/can.c +++ b/can.c @@ -4,10 +4,22 @@ */ #define CANA_TIME 0x10080000 #define CANA_DISCOVERY 0x4c080000 +#define CANA_DISCOVERY_F(pg,dst) (CANA_DISCOVERY | (((uint32_t)(pg) & 0xf) << 12) | ((dst) & 0xfff)) #define CANA_LIGHT 0xcc080000 -#define CANA_LIGHT_F(src,dst) (CANA_LIGHT | (((src) << 12) & 0x3f) | ((dst) & 0xfff)) +#define CANA_LIGHT_F(src,dst) (CANA_LIGHT | (((src) & 0x3f) << 12) | ((dst) & 0xfff)) #define CANA_SENSOR 0xe6080000 #define CANA_SENSOR_F(src) (CANA_SENSOR | ((src) & 0xfff)) +#define CANA_DEBUG 0xe7000000 + +#define CANA_PROTOCOL 0xffe80000 + +#define can_rx_isext() (can_rx_addr.b[1] & 0x08) +#define can_rx_ext_rr() (can_rx_dlc & 0x40) +#define can_rx_len() (can_rx_dlc & 0x0f) + +#define can_rx_sublab_proto() ((can_rx_addr.b[0] << 8) | (can_rx_addr.b[1] & 0xe8)) +#define can_rx_sublab_addr() (((can_rx_addr.b[2] & 0x0f) << 8) | can_rx_addr.b[3]) +#define can_rx_sublab_disco_page() ((can_rx_addr.b[2] & 0xf0) >> 4) #ifndef R0KET #define spi_ss(x) PORTB = ((x) << B_SS) | 0x3; @@ -118,7 +130,7 @@ static uint8_t can_CANSTAT(void) * 15- 8 EID 15:8 * 7- 0 EID 7:0 */ -static void can_send(uint32_t daddr, uint8_t len, uint8_t *data) +static void can_send(uint32_t daddr, uint8_t len, const uint8_t *data) { spi_ss(0); spi_wrrd(MCP2515_WRTXB | MCP2515_WRTXB_TXB0); diff --git a/lightctrl.c b/lightctrl.c index 0a46805..2a82ad3 100644 --- a/lightctrl.c +++ b/lightctrl.c @@ -31,38 +31,152 @@ const uint8_t __signature[3] __attribute__((section (".signature"), used)) = #include "can.c" #include "wdt.c" -static void can_rx_exec(void) +#define CANA_DALI_BASE 0x440 + +static uint16_t ctr = 0; + +static void can_handle_light(uint16_t sublab_addr) { - if (can_rx_addr.b[0] == 0xcc - && (can_rx_addr.b[1] & 0xfb) == 0x08 - && can_rx_addr.b[2] == 0x04) { - - uint8_t base = can_rx_addr.b[3], len = can_rx_dlc & 0x4f, pos; - - for (pos = 0; pos < len; pos++) { - uint8_t dst = base + pos, val; - if (dst < 0x40 || dst >= 0x80) - continue; - dst -= 0x40; - val = can_rx_data[pos]; - if (val == 0xff) - val = 0xfe; - - uart_puts("-- SET "); - uart_puthex(dst); - uart_puts(" = "); - uart_puthex(val); - uart_puts("\n"); - - if (!val) { - // dim_state = 0; - dali_send((dst << 9) | 0x100); - } else { - // if (!dim_state && can_rx_data[0]) - dali_send((dst << 9) | 0x108); - dali_send((dst << 9) | val); - } + /* - 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]; + if (val == 0xff) + val = 0xfe; + + uart_puts("++ SET "); + uart_puthex(dst); + uart_puts(" = "); + uart_puthex(val); + uart_puts("\n"); + + if (!val) { + // dim_state = 0; + dali_send((dst << 9) | 0x100); + } else { + // if (!dim_state && can_rx_data[0]) + dali_send((dst << 9) | 0x108); + dali_send((dst << 9) | val); + } + } + + /* resync clock for immediate ACK */ + ctr = 500; +} + +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; } } @@ -107,8 +221,6 @@ int main(void) dali_search(); - uint16_t ctr = 0; - while (1) { wdt_reset(); if (canint) { @@ -158,11 +270,11 @@ int main(void) } else uart_puts("-- "); uart_puts("\n"); - can_send(0xe6080440 + base, dlc, buffer); + can_send(CANA_SENSOR_F(CANA_DALI_BASE + base), dlc, buffer); } break; case 1024: - can_send(0xe7000000, 8, (uint8_t *)&dalistat); + can_send(CANA_DEBUG, 8, (uint8_t *)&dalistat); uart_puttick(); uart_puts("dali stats: "); @@ -176,7 +288,7 @@ int main(void) uart_puts(" mch-err\n"); break; case 1536: - can_send(0xcc08047f, 1, (uint8_t *)&dim_state); + can_send(CANA_LIGHT_F(0, CANA_DALI_BASE + 0x3f), 1, (uint8_t *)&dim_state); break; } } -- cgit v1.2.1