DALI send/recv library.

Dependents:   dali_sample

DALI send/recv library

lighting control protocol.

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

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

Files at this revision

API Documentation at this revision

Comitter:
okini3939
Date:
Wed Jul 22 03:04:04 2020 +0000
Child:
1:319d52b5116b
Commit message:
1st build;

Changed in this revision

CBuffer.h Show annotated file Show diff for this revision Revisions of this file
DALI.cpp Show annotated file Show diff for this revision Revisions of this file
DALI.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CBuffer.h	Wed Jul 22 03:04:04 2020 +0000
@@ -0,0 +1,98 @@
+/* Copyright (C) 2012 mbed.org, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+ 
+#ifndef CIRCBUFFER_H_
+#define CIRCBUFFER_H_
+ 
+template <class T>
+class CircBuffer {
+public:
+    CircBuffer(int length, void *addr = NULL) {
+        write = 0;
+        read = 0;
+        size = length + 1;
+        if (addr) {
+            buf = (T *)addr;
+        } else {
+            buf = (T *)malloc(size * sizeof(T));
+        }
+        if (buf == NULL)
+            error("Can't allocate memory");
+    };
+ 
+    bool isFull() {
+        return (((write + 1) % size) == read);
+    };
+ 
+    bool isEmpty() {
+        return (read == write);
+    };
+ 
+    bool queue(T k) {
+        if (isFull()) {
+            return false;
+        }
+        buf[write++] = k;
+        write %= size;
+        return true;
+    }
+    int queue(T *k, int size) {
+        int i;
+        for (i = 0; i < size; i ++) {
+            if (queue(k[i]) == false) break;
+        }
+        return i;
+    }
+    
+    void flush() {
+        read = 0;
+        write = 0;
+    }
+    
+ 
+    uint32_t available() {
+        return (write >= read) ? write - read : size - read + write;
+    };
+    uint32_t free() {
+        return size - available() - 1;
+    };
+ 
+    bool dequeue(T * c) {
+        bool empty = isEmpty();
+        if (!empty) {
+            *c = buf[read++];
+            read %= size;
+        }
+        return(!empty);
+    };
+    int dequeue(T * c, int size) {
+        int i;
+        for (i = 0; i < size; i ++) {
+            if (dequeue(&c[i]) == false) break;
+        }
+        return i;
+    }
+ 
+private:
+    volatile uint32_t write;
+    volatile uint32_t read;
+    uint32_t size;
+    T * buf;
+};
+ 
+#endif
--- /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;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/DALI.h	Wed Jul 22 03:04:04 2020 +0000
@@ -0,0 +1,60 @@
+/*
+ * DALI send/recv library
+ * Copyright (c) 2020 Hiroshi Suga
+ * Released under the MIT License: http://mbed.org/license/mit
+ */
+
+/** @file
+ * @brief DALI send/recv
+ */
+ 
+ #ifndef _DALI_H_
+#define _DALI_H_
+
+#include "CBuffer.h"
+
+class DALI {
+public:
+    enum DALI_FRAME {
+        DALI_FORWARD_SHORT_DAP,
+        DALI_FORWARD_SHORT_IAP,
+        DALI_FORWARD_GROUP_DAP,
+        DALI_FORWARD_GROUP_IAP,
+        DALI_BACKWARD,
+    };
+
+    DALI (PinName tx, PinName rx);
+
+    int read (enum DALI_FRAME *frame, int *addr, int *value);
+    int readable ();
+
+    int write (enum DALI_FRAME frame, int addr, int value);
+
+private:
+    InterruptIn _rx;
+    DigitalOut _tx;
+    Timeout _timer;
+    Ticker _ticker;
+
+    CircBuffer<int> *recv_buf;
+    CircBuffer<int> *send_buf;
+
+    int mode;
+    int count;
+    int timeflg;
+    int recv_bit;
+    int recv_data;
+
+    int send_data;
+    int send_bit;
+    int halfbit;
+    int busy;
+
+    void isr_rx ();
+    void isr_timer ();
+    void isr_timeout ();
+    void isr_send ();
+
+};
+
+#endif