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
Diff: DALI.cpp
- 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; + } + } +}