summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Lamparter <equinox@diac24.net>2012-09-20 11:03:21 +0200
committerDavid Lamparter <equinox@diac24.net>2012-09-20 11:03:21 +0200
commit415ca2037b3cefc64ee59279950fe85fa679e3cd (patch)
tree78c0836b73a6d3d642c5d9c6de20fa9a92818885
parent8901251abbec6d08a13912bab774a0b32c05f16f (diff)
lightctrl: implement discovery protocol
-rw-r--r--can.c16
-rw-r--r--lightctrl.c182
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;
}
}