DALI send/recv library.

Dependents:   dali_sample

DALI send/recv library

lighting control protocol.

設備照明の調光プロトコル DALI を送受信するライブラリです。

DALI インターフェースの回路図などは次を参照。

Revision:
0:6cb7026982fc
Child:
1:319d52b5116b
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/DALI.cpp	Wed Jul 22 03:04:04 2020 +0000
@@ -0,0 +1,228 @@
+/*
+ * DALI send/recv library
+ * Copyright (c) 2020 Hiroshi Suga
+ * Released under the MIT License: http://mbed.org/license/mit
+ */
+
+/** @file
+ * @brief DALI send/recv
+ */
+ 
+#include "mbed.h"
+#include "DALI.h"
+
+#define BUFFER_SIZE 20
+
+#define TIME_BITTIME 833 // us, 1200bps
+#define TIME_BITTIME1p2 417 // us, 1200bps 3/4
+#define TIME_BITTIME3p4 625 // us, 1200bps 3/4
+
+extern Serial pc;
+
+DALI::DALI (PinName tx, PinName rx) : _tx(tx), _rx(rx) {
+    _rx.mode(PullUp);
+    _rx.fall(this, &DALI::isr_rx);
+    _rx.rise(this, &DALI::isr_rx);
+    _tx = 0;
+
+    recv_buf = new CircBuffer<int>(BUFFER_SIZE);
+    send_buf = new CircBuffer<int>(BUFFER_SIZE);
+
+    mode = 0;
+    count = 0;
+    timeflg = 0;
+    busy = 0;
+}
+
+int DALI::read (enum DALI_FRAME *frame, int *addr, int *value) {
+    int dat;
+
+    if (recv_buf->dequeue(&dat)) {
+        if (dat & (1<<16)) {
+            *frame = DALI_BACKWARD;
+            *value = dat & 0xff;
+        } else {
+            if (dat & (1<<15)) {
+                // group
+                if (dat & (1<<8)) {
+                    *frame = DALI_FORWARD_GROUP_IAP;
+                } else {
+                    *frame = DALI_FORWARD_GROUP_DAP;
+                }
+            } else {
+                // short
+                if (dat & (1<<8)) {
+                    *frame = DALI_FORWARD_SHORT_IAP;
+                } else {
+                    *frame = DALI_FORWARD_SHORT_DAP;
+                }
+            }
+            *addr = (dat >> 9) & 0x3f;
+            *value = dat & 0xff;
+        }
+        return 0;
+    }
+    return -1;
+}
+
+int DALI::readable () {
+    return ! recv_buf->isEmpty();
+}
+
+void DALI::isr_send () {
+
+    if (send_bit & 3) {
+        // stop bit
+        _tx = 0;
+    } else
+    if ((halfbit == 0 && (send_data & send_bit)) || (halfbit == 1 && !(send_data & send_bit))) {
+        // low
+        _tx = 1;
+    } else {
+        // high
+        _tx = 0;
+    }
+
+    if (halfbit) {
+        halfbit = 0;
+        send_bit >>= 1;
+
+        if (send_bit == 0) {
+            if (send_buf->isEmpty()) {
+                // end
+                _ticker.detach();
+                busy = 0;
+            } else {
+                // next
+                int dat, bit;
+                send_buf->dequeue(&dat);
+                bit = (dat >> 20) & 0x0fff;
+                send_bit = (1 << bit) << 2;
+                send_data = dat & 0x0fffff;
+                halfbit = 0;
+            }
+        }
+    } else {
+        halfbit = 1;
+    }
+}
+
+int DALI::write (enum DALI_FRAME frame, int addr, int value) {
+    int dat, bit;
+
+    while ((volatile int)send_bit);
+
+    switch (frame) {
+    case DALI_FORWARD_SHORT_DAP:
+        dat = (0<<15) | ((addr & 0x3f) << 9) | (0<<8) | (value & 0xff);
+        bit = 16;
+        break;
+
+    case DALI_FORWARD_SHORT_IAP:
+        dat = (0<<15) | ((addr & 0x3f) << 9) | (1<<8) | (value & 0xff);
+        bit = 16;
+        break;
+
+    case DALI_FORWARD_GROUP_DAP:
+        dat = (1<<15) | ((addr & 0x3f) << 9) | (0<<8) | (value & 0xff);
+        bit = 16;
+        break;
+
+    case DALI_FORWARD_GROUP_IAP:
+        dat = (1<<15) | ((addr & 0x3f) << 9) | (1<<8) | (value & 0xff);
+        bit = 16;
+        break;
+
+    case DALI_BACKWARD:
+        dat = (value & 0xff);
+        bit = 8;
+        break;
+
+    default:
+        return -1;
+    }
+
+    dat = ((1<<bit) | dat) << 2; // start bit
+    dat |= bit << 20;
+    send_buf->queue(dat);
+
+    if (! busy) {
+        busy = 1;
+        send_buf->dequeue(&dat);
+        bit = (dat >> 20) & 0x0fff;
+        send_bit = (1 << bit) << 2;
+        send_data = dat & 0x0fffff;
+        halfbit = 0;
+        _ticker.attach_us(this, &DALI::isr_send, TIME_BITTIME1p2);
+    }
+    return 0;
+}
+
+void DALI::isr_rx () {
+
+    if (timeflg || busy) return;
+
+    timeflg = 1;
+    _timer.detach();
+    _timer.attach_us(this, &DALI::isr_timer, TIME_BITTIME3p4);
+
+    if (_rx.read() && mode == 0) {
+        // start bit
+        mode ++;
+        recv_data = 0;
+        recv_bit = 0x8000;
+    }
+}
+
+void DALI::isr_timer () {
+    timeflg = 0;
+    _timer.detach();
+    _timer.attach_us(this, &DALI::isr_timeout, TIME_BITTIME);
+
+    if (recv_bit) {
+        // data bit
+        if (_rx.read()) {
+            // high
+            recv_data |= recv_bit;
+        } else {
+            // low
+            recv_data &= ~recv_bit;
+        }
+        recv_bit >>= 1;
+    } else
+    if (mode == 1) {
+        if (_rx.read()) {
+            // error
+            mode = 0;
+        } else {
+            // stop bit 1
+            mode ++;
+        }
+    }
+}
+
+void DALI::isr_timeout () {
+    timeflg = 0;
+    _timer.detach();
+
+    if (recv_bit) {
+        // Backward frame (8bit)
+        if (mode == 1 && _rx.read() == 0 && !(recv_data & (1<<7))) {
+            // stop bit 2
+            recv_data = (1<<16) | (recv_data >> 8);
+            recv_buf->queue(recv_data);
+            mode = 0;
+        } else {
+            mode = 0;
+        }
+    } else {
+        // Forward frame (16bit)
+        if (mode == 2 && _rx.read() == 0) {
+            // stop bit 2
+            recv_buf->queue(recv_data);
+            mode = 0;
+        } else {
+            mode = 0;
+        }
+    }
+}