-
Notifications
You must be signed in to change notification settings - Fork 11
/
Copy pathx10rf.cpp
246 lines (218 loc) · 8.47 KB
/
x10rf.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
/*
x10rf.cpp
Library for sending x10 messages by RF.
Created by Pieter Paul Baron (embedded [at] ppbaron.nl), November 2013.
Released into the public domain.
Library to send x10 messages via a cheap 433Mhz OOK device. No X10 Firecracker (CMA17A) necessary.
Decoding messages is not implemented.
This library can emulate x10 switches and security devices and also RFXMeter and RFXSensor devices manufactured by RFXCom. (www.rfxcom.com)
Tested on a TI Stellarpad (LM4F120H5QR) and Energia 0101E0010. This should also work on Arduino (small modifications) or other TI Launchpad devices.
*/
#include <stdlib.h>
#include "x10rf.h"
#define X10_RF_SB_LONG 8960 // Start burts (leader) = 9ms
#define X10_RF_SB_SHORT 4500 //Start silecence (leader) = 4,5 ms
#define X10_RF_BIT_LONG 1120 // Bit 1 pulse length
#define X10_RF_BIT_SHORT 560 // Bit 1 pulse length
#define X10_RF_GAP 40000 // Length between commands
void x10rf::begin()
{
pinMode(_tx_pin, OUTPUT);
if (_led_pin > 0) pinMode(_led_pin, OUTPUT);
}
x10rf::x10rf(uint8_t tx_pin, uint8_t led_pin, uint8_t rf_repeats)
{
_tx_pin = tx_pin;
_led_pin = led_pin;
_rf_repeats = rf_repeats;
}
void x10rf::RFXmeter(uint8_t rfxm_address, uint8_t rfxm_packet_type, long rfxm_value){
uint8_t x10buff[5]; // Set message buffer
x10buff[0] = rfxm_address;
x10buff[1] = (~x10buff[0] & 0xF0) + (x10buff[0] & 0xF); // Calculate byte1 (byte 1 complement upper nibble of byte0)
if (rfxm_value > 0xFFFFFF) rfxm_value = 0; // We only have 3 byte for data. Is overflowed set to 0
// Packet type goed into MSB nibble of byte 5. Max 15 (B1111) allowed
// Use switch case to filter invalid data types
switch(rfxm_packet_type) {
case 0x00: //Normal. Put counter values in byte 4,2 and 3
x10buff[4] = (uint8_t) ((rfxm_value >> 16) & 0xff);
x10buff[2] = (uint8_t) ((rfxm_value >> 8) & 0xff);
x10buff[3] = (uint8_t) (rfxm_value & 0xff);
break;
case 0x01: // New interval time set. Byte 2 should be filled with interval
switch(rfxm_value) {
case 0x01: break; // 30sec
case 0x02: break; // 01min
case 0x04: break; // 06min (RFXpower = 05min)
case 0x08: break; // 12min (RFXpower = 10min)
case 0x10: break; // 15min
case 0x20: break; // 30min
case 0x40: break; // 45min
case 0x80: break; // 60min
default:
rfxm_value = 0x01; // Set to 30 sec if no valid option is found
}
x10buff[2] = rfxm_value;
break;
case 0x02: // calibrate value in <counter value> in µsec.
x10buff[4] = (uint8_t) ((rfxm_value >> 16) & 0xff);
x10buff[2] = (uint8_t) ((rfxm_value >> 8) & 0xff);
x10buff[3] = (uint8_t) (rfxm_value & 0xff);
break;
case 0x03: break;// new address set
case 0x04: break; // counter value reset to zero
case 0x0B: // counter value set
x10buff[4] = (uint8_t) ((rfxm_value >> 16) & 0xff);
x10buff[2] = (uint8_t) ((rfxm_value >> 8) & 0xff);
x10buff[3] = (uint8_t) (rfxm_value & 0xff);
break;
case 0x0C: break; // set interval mode within 5 seconds
case 0x0D: break; // calibration mode within 5 seconds
case 0x0E: break; // set address mode within 5 seconds
case 0x0F: // identification packet (byte 2 = address, byte 3 = interval)
switch(rfxm_value) {
case 0x01: break; //30sec
case 0x02: break; //01min
case 0x04: break; //06min (RFXpower = 05min)
case 0x08: break; //12min (RFXpower = 10min)
case 0x10: break; // 15min1
case 0x20: break; // 30min
case 0x40: break; // 45min
case 0x80: break; // 60min
default:
rfxm_value = 0x01; // Set to 30 sec if no valid option is found
}
x10buff[2] = rfxm_address;
x10buff[3] = rfxm_value;
break;
default: //Unknown packet type. Set packet type to zero and set counter to rfxm_value
rfxm_packet_type = 0;
x10buff[4] = (uint8_t) ((rfxm_value >> 16) & 0xff);
x10buff[2] = (uint8_t) ((rfxm_value >> 8) & 0xff);
x10buff[3] = (uint8_t) (rfxm_value & 0xff);
}
x10buff[5] = (rfxm_packet_type << 4); // Packet type goes into byte 5's upper nibble.
// Calculate parity which
uint8_t parity = ~(((x10buff[0] & 0XF0) >> 4) + (x10buff[0] & 0XF) + ((x10buff[1] & 0XF0) >> 4) + (x10buff[1] & 0XF) + ((x10buff[2] & 0XF0) >> 4) + (x10buff[2] & 0XF) + ((x10buff[3] & 0XF0) >> 4) + (x10buff[3] & 0XF) + ((x10buff[4] & 0XF0) >> 4) + (x10buff[4] & 0XF) + ((x10buff[5] & 0XF0) >> 4));
x10buff[5] = (x10buff[5] & 0xf0) + (parity & 0XF);
SendCommand(x10buff, sizeof(x10buff)); // Send byte to be broadcasted
}
void x10rf::RFXsensor(uint8_t rfxs_address,uint8_t rfxs_type, char rfxs_packet_type, uint8_t rfxs_value){
uint8_t x10buff[3]; // Set message buffer 4 bytes
x10buff[0] = (rfxs_address << 2);
switch (rfxs_type) {
case 't': break; // Temperature (default)
case 'a': // A/D
x10buff[0] = x10buff[0] + B01;
break;
case 'm': // message
x10buff[0] = x10buff[0] + B11;
break;
case 'v': // voltage
x10buff[0] = x10buff[0] + B10;
break;
}
x10buff[1] = (~x10buff[0] & 0xF0) + (x10buff[0] & 0xF); // Calculate byte1 (byte 1 complement MSB nibble of byte0)
x10buff[2] = rfxs_value;
switch(rfxs_packet_type) {
case 't': //temperature sensor (MSB = 0.5 degrees bit off)
x10buff[3] = 0x00;
break;
case 'T': //emperature sensor (MSB = 0.5 degrees bit on)
x10buff[3] = 0x80;
break;
case 'h': //RFU (humidity sensor)
x10buff[3] = 0x20;
break;
case 'p': //RFU (pressure sensor)
x10buff[3] = 0x40;
break;
default:
x10buff[3] = 0x00;
}
x10buff[3] << 4;
uint8_t parity = ~(((x10buff[0] & 0XF0) >> 4) + (x10buff[0] & 0XF) + ((x10buff[1] & 0XF0) >> 4) + (x10buff[1] & 0XF) + ((x10buff[2] & 0XF0) >> 4) + (x10buff[2] & 0XF) + ((x10buff[3] & 0XF0) >> 4));
x10buff[3] = (x10buff[3] & 0xf0) + (parity & 0XF);
SendCommand(x10buff, sizeof(x10buff));
}
void x10rf::x10Switch(char house_code, uint8_t unit_code, uint8_t command){
uint8_t x10buff[3]; // Set message buffer 4 bytes
uint8_t bTmp = 0; // Tmp byte
switch(house_code) {
case 'a': x10buff[0] = B0110; break;
case 'b': x10buff[0] = B0111; break;
case 'c': x10buff[0] = B0100; break;
case 'd': x10buff[0] = B0101; break;
case 'e': x10buff[0] = B1000; break;
case 'f': x10buff[0] = B1001; break;
case 'g': x10buff[0] = B1010; break;
case 'h': x10buff[0] = B1011; break;
case 'i': x10buff[0] = B1110; break;
case 'j': x10buff[0] = B1111; break;
case 'k': x10buff[0] = B1100; break;
case 'l': x10buff[0] = B1101; break;
case 'm': x10buff[0] = B0000; break;
case 'n': x10buff[0] = B0001; break;
case 'o': x10buff[0] = B0010; break;
case 'p': x10buff[0] = B0011; break;
default: x10buff[0] = 0; break;
}
x10buff[0] = x10buff[0] << 4; // House code goes into the upper nibble
switch(command) {
case 0: x10buff[2] = (x10buff[2] | 0x20); break;
case 1: x10buff[2] = (x10buff[2] & 0x20); break;
}
// Set unit number
unit_code = unit_code - 1;
bitWrite(x10buff[2],6,bitRead(unit_code,2));
bitWrite(x10buff[2],3,bitRead(unit_code,1));
bitWrite(x10buff[2],4,bitRead(unit_code,0));
bitWrite(x10buff[0],2,bitRead(unit_code,3));
// Set parity
x10buff[1] = ~x10buff[0];
x10buff[3] = ~x10buff[2];
SendCommand(x10buff, sizeof(x10buff));
}
void x10rf::x10Security(uint8_t address, uint8_t command){
uint8_t x10buff[3]; // Set message buffer 4 bytes
x10buff[0] = address;
x10buff[1] = (~x10buff[0] & 0xF) + (x10buff[0] & 0xF0); // Calculate byte1 (byte 1 complement
x10buff[2] = command;
x10buff[3] = ~x10buff[2];
// x10buff[4] = code; // Couldn't get 48 bit security working.
// if((x10buff[4] % 2) == 0) { x10buff[5] = 0;} //Calc even parity
// else { x10buff[5] = 0x80;}
SendCommand(x10buff, sizeof(x10buff));
}
void x10rf::SendCommand(uint8_t *data, uint8_t size){
if (_led_pin > 0) digitalWrite(_led_pin, HIGH);
for (int i = 0; i < _rf_repeats; i++){
SEND_HIGH();delayMicroseconds(X10_RF_SB_LONG);
SEND_LOW();delayMicroseconds(X10_RF_SB_SHORT);
for(int i=0; i <= size; i++) {
SendX10RfByte(data[i]);
}
SendX10RfBit(1);
delayMicroseconds(X10_RF_GAP);
}
if (_led_pin > 0) digitalWrite(_led_pin, LOW);
}
void x10rf::SendX10RfByte(uint8_t data){
int i = 0;
//Serial.println("\n");
for (int i=7; i >= 0 ; i--){ // send bits from byte
SendX10RfBit((bitRead(data,i)==1));
//Serial.print(bitRead(data,i));
}
}
void x10rf::SendX10RfBit(unsigned int databit){
SEND_HIGH();delayMicroseconds(X10_RF_BIT_SHORT);
SEND_LOW();delayMicroseconds(X10_RF_BIT_SHORT);
if (databit) delayMicroseconds(X10_RF_BIT_LONG);
}
void x10rf::SEND_HIGH() {
digitalWrite(_tx_pin, HIGH);
}
void x10rf::SEND_LOW(){
digitalWrite(_tx_pin, LOW);
}