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
DALI.cpp
- Committer:
- okini3939
- Date:
- 2020-07-27
- Revision:
- 1:319d52b5116b
- Parent:
- 0:6cb7026982fc
File content as of revision 1:319d52b5116b:
/* * 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 1/2 #define TIME_BITTIME3p4 625 // us, 1200bps 3/4 #define TIME_BETWEEN 10000 // us >22Te 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 = BACKWARD; *value = dat & 0xff; } else { if (dat & (1<<15)) { // group if (dat & (1<<8)) { *frame = FORWARD_GROUP_IAP; } else { *frame = FORWARD_GROUP_DAP; } } else { // short if (dat & (1<<8)) { *frame = FORWARD_SHORT_IAP; } else { *frame = 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 (! busy) { if (mode) return; // recv working _ticker.detach(); // next data int dat, bit; 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); } 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) { // end of data _ticker.detach(); busy = 0; if (! send_buf->isEmpty()) { // next data _ticker.attach_us(this, &DALI::isr_send, TIME_BETWEEN); } } } else { halfbit = 1; } } int DALI::writable () { return ! send_buf->isFull(); } int DALI::write (enum DALI_FRAME frame, int addr, int value) { int dat, bit; switch (frame) { case FORWARD_SHORT_DAP: dat = (0<<15) | ((addr & 0x3f) << 9) | (0<<8) | (value & 0xff); bit = 16; break; case FORWARD_SHORT_IAP: dat = (0<<15) | ((addr & 0x3f) << 9) | (1<<8) | (value & 0xff); bit = 16; break; case FORWARD_GROUP_DAP: dat = (1<<15) | ((addr & 0x3f) << 9) | (0<<8) | (value & 0xff); bit = 16; break; case FORWARD_GROUP_IAP: dat = (1<<15) | ((addr & 0x3f) << 9) | (1<<8) | (value & 0xff); bit = 16; break; case 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) { while (mode); // wait recv // begin data 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; } } }