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@1:319d52b5116b, 2020-07-27 (annotated)
- Committer:
- okini3939
- Date:
- Mon Jul 27 05:53:55 2020 +0000
- Revision:
- 1:319d52b5116b
- Parent:
- 0:6cb7026982fc
bug fix;
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
okini3939 | 0:6cb7026982fc | 1 | /* |
okini3939 | 0:6cb7026982fc | 2 | * DALI send/recv library |
okini3939 | 0:6cb7026982fc | 3 | * Copyright (c) 2020 Hiroshi Suga |
okini3939 | 0:6cb7026982fc | 4 | * Released under the MIT License: http://mbed.org/license/mit |
okini3939 | 0:6cb7026982fc | 5 | */ |
okini3939 | 0:6cb7026982fc | 6 | |
okini3939 | 0:6cb7026982fc | 7 | /** @file |
okini3939 | 0:6cb7026982fc | 8 | * @brief DALI send/recv |
okini3939 | 0:6cb7026982fc | 9 | */ |
okini3939 | 0:6cb7026982fc | 10 | |
okini3939 | 0:6cb7026982fc | 11 | #include "mbed.h" |
okini3939 | 0:6cb7026982fc | 12 | #include "DALI.h" |
okini3939 | 0:6cb7026982fc | 13 | |
okini3939 | 0:6cb7026982fc | 14 | #define BUFFER_SIZE 20 |
okini3939 | 0:6cb7026982fc | 15 | |
okini3939 | 1:319d52b5116b | 16 | #define TIME_BITTIME 833 // us, 1200bps |
okini3939 | 1:319d52b5116b | 17 | #define TIME_BITTIME1p2 417 // us, 1200bps 1/2 |
okini3939 | 0:6cb7026982fc | 18 | #define TIME_BITTIME3p4 625 // us, 1200bps 3/4 |
okini3939 | 1:319d52b5116b | 19 | #define TIME_BETWEEN 10000 // us >22Te |
okini3939 | 0:6cb7026982fc | 20 | |
okini3939 | 0:6cb7026982fc | 21 | |
okini3939 | 0:6cb7026982fc | 22 | DALI::DALI (PinName tx, PinName rx) : _tx(tx), _rx(rx) { |
okini3939 | 0:6cb7026982fc | 23 | _rx.mode(PullUp); |
okini3939 | 0:6cb7026982fc | 24 | _rx.fall(this, &DALI::isr_rx); |
okini3939 | 0:6cb7026982fc | 25 | _rx.rise(this, &DALI::isr_rx); |
okini3939 | 0:6cb7026982fc | 26 | _tx = 0; |
okini3939 | 0:6cb7026982fc | 27 | |
okini3939 | 0:6cb7026982fc | 28 | recv_buf = new CircBuffer<int>(BUFFER_SIZE); |
okini3939 | 0:6cb7026982fc | 29 | send_buf = new CircBuffer<int>(BUFFER_SIZE); |
okini3939 | 0:6cb7026982fc | 30 | |
okini3939 | 0:6cb7026982fc | 31 | mode = 0; |
okini3939 | 0:6cb7026982fc | 32 | count = 0; |
okini3939 | 0:6cb7026982fc | 33 | timeflg = 0; |
okini3939 | 0:6cb7026982fc | 34 | busy = 0; |
okini3939 | 0:6cb7026982fc | 35 | } |
okini3939 | 0:6cb7026982fc | 36 | |
okini3939 | 0:6cb7026982fc | 37 | int DALI::read (enum DALI_FRAME *frame, int *addr, int *value) { |
okini3939 | 0:6cb7026982fc | 38 | int dat; |
okini3939 | 0:6cb7026982fc | 39 | |
okini3939 | 0:6cb7026982fc | 40 | if (recv_buf->dequeue(&dat)) { |
okini3939 | 0:6cb7026982fc | 41 | if (dat & (1<<16)) { |
okini3939 | 1:319d52b5116b | 42 | *frame = BACKWARD; |
okini3939 | 0:6cb7026982fc | 43 | *value = dat & 0xff; |
okini3939 | 0:6cb7026982fc | 44 | } else { |
okini3939 | 0:6cb7026982fc | 45 | if (dat & (1<<15)) { |
okini3939 | 0:6cb7026982fc | 46 | // group |
okini3939 | 0:6cb7026982fc | 47 | if (dat & (1<<8)) { |
okini3939 | 1:319d52b5116b | 48 | *frame = FORWARD_GROUP_IAP; |
okini3939 | 0:6cb7026982fc | 49 | } else { |
okini3939 | 1:319d52b5116b | 50 | *frame = FORWARD_GROUP_DAP; |
okini3939 | 0:6cb7026982fc | 51 | } |
okini3939 | 0:6cb7026982fc | 52 | } else { |
okini3939 | 0:6cb7026982fc | 53 | // short |
okini3939 | 0:6cb7026982fc | 54 | if (dat & (1<<8)) { |
okini3939 | 1:319d52b5116b | 55 | *frame = FORWARD_SHORT_IAP; |
okini3939 | 0:6cb7026982fc | 56 | } else { |
okini3939 | 1:319d52b5116b | 57 | *frame = FORWARD_SHORT_DAP; |
okini3939 | 0:6cb7026982fc | 58 | } |
okini3939 | 0:6cb7026982fc | 59 | } |
okini3939 | 0:6cb7026982fc | 60 | *addr = (dat >> 9) & 0x3f; |
okini3939 | 0:6cb7026982fc | 61 | *value = dat & 0xff; |
okini3939 | 0:6cb7026982fc | 62 | } |
okini3939 | 0:6cb7026982fc | 63 | return 0; |
okini3939 | 0:6cb7026982fc | 64 | } |
okini3939 | 0:6cb7026982fc | 65 | return -1; |
okini3939 | 0:6cb7026982fc | 66 | } |
okini3939 | 0:6cb7026982fc | 67 | |
okini3939 | 0:6cb7026982fc | 68 | int DALI::readable () { |
okini3939 | 0:6cb7026982fc | 69 | return ! recv_buf->isEmpty(); |
okini3939 | 0:6cb7026982fc | 70 | } |
okini3939 | 0:6cb7026982fc | 71 | |
okini3939 | 0:6cb7026982fc | 72 | void DALI::isr_send () { |
okini3939 | 0:6cb7026982fc | 73 | |
okini3939 | 1:319d52b5116b | 74 | if (! busy) { |
okini3939 | 1:319d52b5116b | 75 | if (mode) return; // recv working |
okini3939 | 1:319d52b5116b | 76 | |
okini3939 | 1:319d52b5116b | 77 | _ticker.detach(); |
okini3939 | 1:319d52b5116b | 78 | // next data |
okini3939 | 1:319d52b5116b | 79 | int dat, bit; |
okini3939 | 1:319d52b5116b | 80 | busy = 1; |
okini3939 | 1:319d52b5116b | 81 | send_buf->dequeue(&dat); |
okini3939 | 1:319d52b5116b | 82 | bit = (dat >> 20) & 0x0fff; |
okini3939 | 1:319d52b5116b | 83 | send_bit = (1 << bit) << 2; |
okini3939 | 1:319d52b5116b | 84 | send_data = dat & 0x0fffff; |
okini3939 | 1:319d52b5116b | 85 | halfbit = 0; |
okini3939 | 1:319d52b5116b | 86 | _ticker.attach_us(this, &DALI::isr_send, TIME_BITTIME1p2); |
okini3939 | 1:319d52b5116b | 87 | } |
okini3939 | 1:319d52b5116b | 88 | |
okini3939 | 0:6cb7026982fc | 89 | if (send_bit & 3) { |
okini3939 | 0:6cb7026982fc | 90 | // stop bit |
okini3939 | 0:6cb7026982fc | 91 | _tx = 0; |
okini3939 | 0:6cb7026982fc | 92 | } else |
okini3939 | 0:6cb7026982fc | 93 | if ((halfbit == 0 && (send_data & send_bit)) || (halfbit == 1 && !(send_data & send_bit))) { |
okini3939 | 0:6cb7026982fc | 94 | // low |
okini3939 | 0:6cb7026982fc | 95 | _tx = 1; |
okini3939 | 0:6cb7026982fc | 96 | } else { |
okini3939 | 0:6cb7026982fc | 97 | // high |
okini3939 | 0:6cb7026982fc | 98 | _tx = 0; |
okini3939 | 0:6cb7026982fc | 99 | } |
okini3939 | 0:6cb7026982fc | 100 | |
okini3939 | 0:6cb7026982fc | 101 | if (halfbit) { |
okini3939 | 0:6cb7026982fc | 102 | halfbit = 0; |
okini3939 | 0:6cb7026982fc | 103 | send_bit >>= 1; |
okini3939 | 0:6cb7026982fc | 104 | |
okini3939 | 0:6cb7026982fc | 105 | if (send_bit == 0) { |
okini3939 | 1:319d52b5116b | 106 | // end of data |
okini3939 | 1:319d52b5116b | 107 | _ticker.detach(); |
okini3939 | 1:319d52b5116b | 108 | busy = 0; |
okini3939 | 1:319d52b5116b | 109 | if (! send_buf->isEmpty()) { |
okini3939 | 1:319d52b5116b | 110 | // next data |
okini3939 | 1:319d52b5116b | 111 | _ticker.attach_us(this, &DALI::isr_send, TIME_BETWEEN); |
okini3939 | 0:6cb7026982fc | 112 | } |
okini3939 | 0:6cb7026982fc | 113 | } |
okini3939 | 0:6cb7026982fc | 114 | } else { |
okini3939 | 0:6cb7026982fc | 115 | halfbit = 1; |
okini3939 | 0:6cb7026982fc | 116 | } |
okini3939 | 0:6cb7026982fc | 117 | } |
okini3939 | 0:6cb7026982fc | 118 | |
okini3939 | 1:319d52b5116b | 119 | int DALI::writable () { |
okini3939 | 1:319d52b5116b | 120 | return ! send_buf->isFull(); |
okini3939 | 1:319d52b5116b | 121 | } |
okini3939 | 1:319d52b5116b | 122 | |
okini3939 | 0:6cb7026982fc | 123 | int DALI::write (enum DALI_FRAME frame, int addr, int value) { |
okini3939 | 0:6cb7026982fc | 124 | int dat, bit; |
okini3939 | 0:6cb7026982fc | 125 | |
okini3939 | 0:6cb7026982fc | 126 | switch (frame) { |
okini3939 | 1:319d52b5116b | 127 | case FORWARD_SHORT_DAP: |
okini3939 | 0:6cb7026982fc | 128 | dat = (0<<15) | ((addr & 0x3f) << 9) | (0<<8) | (value & 0xff); |
okini3939 | 0:6cb7026982fc | 129 | bit = 16; |
okini3939 | 0:6cb7026982fc | 130 | break; |
okini3939 | 0:6cb7026982fc | 131 | |
okini3939 | 1:319d52b5116b | 132 | case FORWARD_SHORT_IAP: |
okini3939 | 0:6cb7026982fc | 133 | dat = (0<<15) | ((addr & 0x3f) << 9) | (1<<8) | (value & 0xff); |
okini3939 | 0:6cb7026982fc | 134 | bit = 16; |
okini3939 | 0:6cb7026982fc | 135 | break; |
okini3939 | 0:6cb7026982fc | 136 | |
okini3939 | 1:319d52b5116b | 137 | case FORWARD_GROUP_DAP: |
okini3939 | 0:6cb7026982fc | 138 | dat = (1<<15) | ((addr & 0x3f) << 9) | (0<<8) | (value & 0xff); |
okini3939 | 0:6cb7026982fc | 139 | bit = 16; |
okini3939 | 0:6cb7026982fc | 140 | break; |
okini3939 | 0:6cb7026982fc | 141 | |
okini3939 | 1:319d52b5116b | 142 | case FORWARD_GROUP_IAP: |
okini3939 | 0:6cb7026982fc | 143 | dat = (1<<15) | ((addr & 0x3f) << 9) | (1<<8) | (value & 0xff); |
okini3939 | 0:6cb7026982fc | 144 | bit = 16; |
okini3939 | 0:6cb7026982fc | 145 | break; |
okini3939 | 0:6cb7026982fc | 146 | |
okini3939 | 1:319d52b5116b | 147 | case BACKWARD: |
okini3939 | 0:6cb7026982fc | 148 | dat = (value & 0xff); |
okini3939 | 0:6cb7026982fc | 149 | bit = 8; |
okini3939 | 0:6cb7026982fc | 150 | break; |
okini3939 | 0:6cb7026982fc | 151 | |
okini3939 | 0:6cb7026982fc | 152 | default: |
okini3939 | 0:6cb7026982fc | 153 | return -1; |
okini3939 | 0:6cb7026982fc | 154 | } |
okini3939 | 0:6cb7026982fc | 155 | |
okini3939 | 0:6cb7026982fc | 156 | dat = ((1<<bit) | dat) << 2; // start bit |
okini3939 | 0:6cb7026982fc | 157 | dat |= bit << 20; |
okini3939 | 0:6cb7026982fc | 158 | send_buf->queue(dat); |
okini3939 | 0:6cb7026982fc | 159 | |
okini3939 | 0:6cb7026982fc | 160 | if (! busy) { |
okini3939 | 1:319d52b5116b | 161 | while (mode); // wait recv |
okini3939 | 1:319d52b5116b | 162 | // begin data |
okini3939 | 0:6cb7026982fc | 163 | busy = 1; |
okini3939 | 0:6cb7026982fc | 164 | send_buf->dequeue(&dat); |
okini3939 | 0:6cb7026982fc | 165 | bit = (dat >> 20) & 0x0fff; |
okini3939 | 0:6cb7026982fc | 166 | send_bit = (1 << bit) << 2; |
okini3939 | 0:6cb7026982fc | 167 | send_data = dat & 0x0fffff; |
okini3939 | 0:6cb7026982fc | 168 | halfbit = 0; |
okini3939 | 0:6cb7026982fc | 169 | _ticker.attach_us(this, &DALI::isr_send, TIME_BITTIME1p2); |
okini3939 | 0:6cb7026982fc | 170 | } |
okini3939 | 0:6cb7026982fc | 171 | return 0; |
okini3939 | 0:6cb7026982fc | 172 | } |
okini3939 | 0:6cb7026982fc | 173 | |
okini3939 | 0:6cb7026982fc | 174 | void DALI::isr_rx () { |
okini3939 | 0:6cb7026982fc | 175 | |
okini3939 | 0:6cb7026982fc | 176 | if (timeflg || busy) return; |
okini3939 | 0:6cb7026982fc | 177 | |
okini3939 | 0:6cb7026982fc | 178 | timeflg = 1; |
okini3939 | 0:6cb7026982fc | 179 | _timer.detach(); |
okini3939 | 0:6cb7026982fc | 180 | _timer.attach_us(this, &DALI::isr_timer, TIME_BITTIME3p4); |
okini3939 | 0:6cb7026982fc | 181 | |
okini3939 | 0:6cb7026982fc | 182 | if (_rx.read() && mode == 0) { |
okini3939 | 0:6cb7026982fc | 183 | // start bit |
okini3939 | 0:6cb7026982fc | 184 | mode ++; |
okini3939 | 0:6cb7026982fc | 185 | recv_data = 0; |
okini3939 | 0:6cb7026982fc | 186 | recv_bit = 0x8000; |
okini3939 | 0:6cb7026982fc | 187 | } |
okini3939 | 0:6cb7026982fc | 188 | } |
okini3939 | 0:6cb7026982fc | 189 | |
okini3939 | 0:6cb7026982fc | 190 | void DALI::isr_timer () { |
okini3939 | 0:6cb7026982fc | 191 | timeflg = 0; |
okini3939 | 0:6cb7026982fc | 192 | _timer.detach(); |
okini3939 | 0:6cb7026982fc | 193 | _timer.attach_us(this, &DALI::isr_timeout, TIME_BITTIME); |
okini3939 | 0:6cb7026982fc | 194 | |
okini3939 | 0:6cb7026982fc | 195 | if (recv_bit) { |
okini3939 | 0:6cb7026982fc | 196 | // data bit |
okini3939 | 0:6cb7026982fc | 197 | if (_rx.read()) { |
okini3939 | 0:6cb7026982fc | 198 | // high |
okini3939 | 0:6cb7026982fc | 199 | recv_data |= recv_bit; |
okini3939 | 0:6cb7026982fc | 200 | } else { |
okini3939 | 0:6cb7026982fc | 201 | // low |
okini3939 | 0:6cb7026982fc | 202 | recv_data &= ~recv_bit; |
okini3939 | 0:6cb7026982fc | 203 | } |
okini3939 | 0:6cb7026982fc | 204 | recv_bit >>= 1; |
okini3939 | 0:6cb7026982fc | 205 | } else |
okini3939 | 0:6cb7026982fc | 206 | if (mode == 1) { |
okini3939 | 0:6cb7026982fc | 207 | if (_rx.read()) { |
okini3939 | 0:6cb7026982fc | 208 | // error |
okini3939 | 0:6cb7026982fc | 209 | mode = 0; |
okini3939 | 0:6cb7026982fc | 210 | } else { |
okini3939 | 0:6cb7026982fc | 211 | // stop bit 1 |
okini3939 | 0:6cb7026982fc | 212 | mode ++; |
okini3939 | 0:6cb7026982fc | 213 | } |
okini3939 | 0:6cb7026982fc | 214 | } |
okini3939 | 0:6cb7026982fc | 215 | } |
okini3939 | 0:6cb7026982fc | 216 | |
okini3939 | 0:6cb7026982fc | 217 | void DALI::isr_timeout () { |
okini3939 | 0:6cb7026982fc | 218 | timeflg = 0; |
okini3939 | 0:6cb7026982fc | 219 | _timer.detach(); |
okini3939 | 0:6cb7026982fc | 220 | |
okini3939 | 0:6cb7026982fc | 221 | if (recv_bit) { |
okini3939 | 0:6cb7026982fc | 222 | // Backward frame (8bit) |
okini3939 | 0:6cb7026982fc | 223 | if (mode == 1 && _rx.read() == 0 && !(recv_data & (1<<7))) { |
okini3939 | 0:6cb7026982fc | 224 | // stop bit 2 |
okini3939 | 0:6cb7026982fc | 225 | recv_data = (1<<16) | (recv_data >> 8); |
okini3939 | 0:6cb7026982fc | 226 | recv_buf->queue(recv_data); |
okini3939 | 0:6cb7026982fc | 227 | mode = 0; |
okini3939 | 0:6cb7026982fc | 228 | } else { |
okini3939 | 0:6cb7026982fc | 229 | mode = 0; |
okini3939 | 0:6cb7026982fc | 230 | } |
okini3939 | 0:6cb7026982fc | 231 | } else { |
okini3939 | 0:6cb7026982fc | 232 | // Forward frame (16bit) |
okini3939 | 0:6cb7026982fc | 233 | if (mode == 2 && _rx.read() == 0) { |
okini3939 | 0:6cb7026982fc | 234 | // stop bit 2 |
okini3939 | 0:6cb7026982fc | 235 | recv_buf->queue(recv_data); |
okini3939 | 0:6cb7026982fc | 236 | mode = 0; |
okini3939 | 0:6cb7026982fc | 237 | } else { |
okini3939 | 0:6cb7026982fc | 238 | mode = 0; |
okini3939 | 0:6cb7026982fc | 239 | } |
okini3939 | 0:6cb7026982fc | 240 | } |
okini3939 | 0:6cb7026982fc | 241 | } |