-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathNexaCtrl.cpp
252 lines (213 loc) · 6.46 KB
/
NexaCtrl.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
/**
* NexaCtrl Library v.02 - Nexa/HomeEasy control library with absolute dim support.
* Original author of this library is James Taylor (http://jtlog.wordpress.com/)
*
* Version 02 by Carl Gunnarsson - Refactoring and adding support for absolute dimming
*/
#include "NexaCtrl.h"
extern "C" {
// AVR LibC Includes
#include <inttypes.h>
#include <avr/interrupt.h>
}
const int NexaCtrl::kPulseHigh = 275;
const int NexaCtrl::kPulseLow0 = 275;
const int NexaCtrl::kPulseLow1 = 1225;
const int NexaCtrl::kLowPulseLength = 64;
/*
* The actual message is 32 bits of data:
* bits 0-25: the group code - a 26bit number assigned to controllers.
* bit 26: group flag
* bit 27: on/off/dim flag
* bits 28-31: the device code - 4bit number.
* bits 32-35: the dim level - 4bit number.
*/
const int NexaCtrl::kControllerIdOffset = 0;
const int NexaCtrl::kControllerIdLength = 26;
const int NexaCtrl::kGroupFlagOffset = 26;
const int NexaCtrl::kOnFlagOffset = 27;
const int NexaCtrl::kDeviceIdOffset = 28;
const int NexaCtrl::kDeviceIdLength = 4;
const int NexaCtrl::kDimOffset = 32;
const int NexaCtrl::kDimLength = 4;
NexaCtrl::NexaCtrl(int tx_pin, int rx_pin, int led_pin)
{
led_pin_ = led_pin;
tx_pin_ = tx_pin;
rx_pin_ = rx_pin;
pinMode(tx_pin_, OUTPUT);
if (led_pin_ >= 0) {
pinMode(led_pin_, OUTPUT);
}
if (rx_pin_ >= 0) {
pinMode(rx_pin_, INPUT);
}
// kLowPulseLength + kDimLength because we need room for dim bits if
// we want to transmit a dim signal
low_pulse_array = (int*)calloc((kLowPulseLength + (2 * kDimLength)), sizeof(int));
}
void NexaCtrl::DeviceOn(unsigned long controller_id, unsigned int device_id)
{
SetControllerBits(controller_id);
SetBit(kGroupFlagOffset, 0);
SetBit(kOnFlagOffset, 1);
SetDeviceBits(device_id);
Transmit(kLowPulseLength);
}
void NexaCtrl::DeviceOff(unsigned long controller_id, unsigned int device_id)
{
SetControllerBits(controller_id);
SetBit(kGroupFlagOffset, 0);
SetBit(kOnFlagOffset, 0);
SetDeviceBits(device_id);
Transmit(kLowPulseLength);
}
void NexaCtrl::DeviceDim(unsigned long controller_id, unsigned int device_id, unsigned int dim_level)
{
SetControllerBits(controller_id);
SetBit(kGroupFlagOffset, 0);
// Specific for dim
low_pulse_array[(kOnFlagOffset*2)] = kPulseLow0;
low_pulse_array[(kOnFlagOffset*2) + 1] = kPulseLow0;
SetDeviceBits(device_id);
bool dim_bits[kDimLength];
itob(dim_bits, dim_level, kDimLength);
int bit;
for (bit = 0; bit<kDimLength; bit++) {
SetBit(kDimOffset+bit, dim_bits[bit]);
}
Transmit(kLowPulseLength + (kDimLength * 2));
}
void NexaCtrl::GroupOn(unsigned long controller_id)
{
unsigned int device_id = 0;
SetControllerBits(controller_id);
SetDeviceBits(device_id);
SetBit(kGroupFlagOffset, 1);
SetBit(kOnFlagOffset, 1);
Transmit(kLowPulseLength);
}
void NexaCtrl::GroupOff(unsigned long controller_id)
{
unsigned int device_id = 0;
SetControllerBits(controller_id);
SetDeviceBits(device_id);
SetBit(kGroupFlagOffset, 1);
SetBit(kOnFlagOffset, 0);
Transmit(kLowPulseLength);
}
// Private methods
void NexaCtrl::SetDeviceBits(unsigned int device_id)
{
bool device[kDeviceIdLength];
unsigned long ldevice_id = device_id;
itob(device, ldevice_id, kDeviceIdLength);
int bit;
for (bit=0; bit < kDeviceIdLength; bit++) {
SetBit(kDeviceIdOffset+bit, device[bit]);
}
}
void NexaCtrl::SetControllerBits(unsigned long controller_id)
{
bool controller[kControllerIdLength];
itob(controller, controller_id, kControllerIdLength);
int bit;
for (bit=0; bit < kControllerIdLength; bit++) {
SetBit(kControllerIdOffset+bit, controller[bit]);
}
}
void NexaCtrl::SetBit(unsigned int bit_index, bool value)
{
// Each actual bit of data is encoded as two bits on the wire...
if (!value) {
// Data 0 = Wire 01
low_pulse_array[(bit_index*2)] = kPulseLow0;
low_pulse_array[(bit_index*2) + 1] = kPulseLow1;
} else {
// Data 1 = Wire 10
low_pulse_array[(bit_index*2)] = kPulseLow1;
low_pulse_array[(bit_index*2) + 1] = kPulseLow0;
}
}
void NexaCtrl::Transmit(int pulse_length)
{
int pulse_count;
int transmit_count;
cli(); // disable interupts
for (transmit_count = 0; transmit_count < 2; transmit_count++)
{
if (led_pin_ >= 0) {
digitalWrite(led_pin_, HIGH);
}
TransmitLatch1();
TransmitLatch2();
/*
* Transmit the actual message
* every wire bit starts with the same short high pulse, followed
* by a short or long low pulse from an array of low pulse lengths
*/
for (pulse_count = 0; pulse_count < pulse_length; pulse_count++)
{
digitalWrite(tx_pin_, HIGH);
delayMicroseconds(kPulseHigh);
digitalWrite(tx_pin_, LOW);
delayMicroseconds(low_pulse_array[pulse_count]);
}
TransmitLatch2();
if (led_pin_ >= 0) {
digitalWrite(led_pin_, LOW);
}
delayMicroseconds(10000);
}
sei(); // enable interupts
}
void NexaCtrl::TransmitLatch1(void)
{
// bit of radio shouting before we start
digitalWrite(tx_pin_, HIGH);
delayMicroseconds(kPulseLow0);
// low for 9900 for latch 1
digitalWrite(tx_pin_, LOW);
delayMicroseconds(9900);
}
void NexaCtrl::TransmitLatch2(void)
{
// high for a moment 275
digitalWrite(tx_pin_, HIGH);
delayMicroseconds(kPulseLow0);
// low for 2675 for latch 2
digitalWrite(tx_pin_, LOW);
delayMicroseconds(2675);
}
void itob(bool *bits, unsigned long integer, int length) {
for (int i=0; i<length; i++){
if ((integer / power2(length-1-i))==1){
integer-=power2(length-1-i);
bits[i]=1;
}
else bits[i]=0;
}
}
unsigned long power2(int power){ //gives 2 to the (power)
return (unsigned long) 1 << power;
}
unsigned long htoi (const char *ptr)
{
unsigned long value = 0;
char ch = *ptr;
while (ch == ' ' || ch == '\t') {
ch = *(++ptr);
}
for (;;) {
if (ch >= '0' && ch <= '9') {
value = (value << 4) + (ch - '0');
} else if (ch >= 'A' && ch <= 'F') {
value = (value << 4) + (ch - 'A' + 10);
} else if (ch >= 'a' && ch <= 'f') {
value = (value << 4) + (ch - 'a' + 10);
} else {
return value;
}
ch = *(++ptr);
}
}