DALI send/recv library.
DALI send/recv library
lighting control protocol.
設備照明の調光プロトコル DALI を送受信するライブラリです。
DALI インターフェースの回路図などは次を参照。
- http://ww1.microchip.com/downloads/jp/AppNotes/01465A_JP.pdf
- https://www.mouser.com/pdfdocs/AN11174.pdf
Revision 0:6cb7026982fc, committed 2020-07-22
- Comitter:
- okini3939
- Date:
- Wed Jul 22 03:04:04 2020 +0000
- Child:
- 1:319d52b5116b
- Commit message:
- 1st build;
Changed in this revision
--- /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