├── .gitignore ├── IthoEcoFanRft.atsln ├── Master ├── Itho │ ├── CC1101.cpp │ ├── CC1101.h │ ├── CC1101Packet.h │ ├── IthoCC1101.cpp │ ├── IthoCC1101.h │ └── IthoPacket.h └── IthoEcoFanRFT │ └── IthoEcoFanRFT.ino └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | *.d 2 | Master/Debug/suart/BBuart.o 3 | *.o 4 | Master/Debug/Master.srec 5 | *.atsuo 6 | Master/Debug/Makefile 7 | *.map 8 | Master/Debug/Master.lss 9 | *.eep 10 | *.hex 11 | Master/Debug/Master.elf 12 | Master/Debug/makedep.mk -------------------------------------------------------------------------------- /IthoEcoFanRft.atsln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Atmel Studio Solution File, Format Version 11.00 4 | VisualStudioVersion = 14.0.23107.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{E66E83B9-2572-4076-B26E-6BE79FF3018A}") = "Master", "Master\Master.cppproj", "{FDBDDBF9-5449-4629-93BB-1AD1B03C10C3}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|AVR = Debug|AVR 11 | Release|AVR = Release|AVR 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {FDBDDBF9-5449-4629-93BB-1AD1B03C10C3}.Debug|AVR.ActiveCfg = Debug|AVR 15 | {FDBDDBF9-5449-4629-93BB-1AD1B03C10C3}.Debug|AVR.Build.0 = Debug|AVR 16 | {FDBDDBF9-5449-4629-93BB-1AD1B03C10C3}.Release|AVR.ActiveCfg = Release|AVR 17 | {FDBDDBF9-5449-4629-93BB-1AD1B03C10C3}.Release|AVR.Build.0 = Release|AVR 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /Master/Itho/CC1101.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Klusjesman, modified bij supersjimmie for Arduino/ESP8266 3 | */ 4 | 5 | #include "CC1101.h" 6 | 7 | // default constructor 8 | CC1101::CC1101() 9 | { 10 | SPI.begin(); 11 | #ifdef ESP8266 12 | pinMode(SS, OUTPUT); 13 | #endif 14 | } //CC1101 15 | 16 | // default destructor 17 | CC1101::~CC1101() 18 | { 19 | } //~CC1101 20 | 21 | /***********************/ 22 | // SPI helper functions select() and deselect() 23 | inline void CC1101::select(void) { 24 | digitalWrite(SS, LOW); 25 | } 26 | 27 | inline void CC1101::deselect(void) { 28 | digitalWrite(SS, HIGH); 29 | } 30 | 31 | void CC1101::spi_waitMiso() 32 | { 33 | while(digitalRead(MISO) == HIGH) yield(); 34 | } 35 | 36 | void CC1101::init() 37 | { 38 | reset(); 39 | } 40 | 41 | void CC1101::reset() 42 | { 43 | deselect(); 44 | delayMicroseconds(5); 45 | select(); 46 | delayMicroseconds(10); 47 | deselect(); 48 | delayMicroseconds(45); 49 | select(); 50 | 51 | spi_waitMiso(); 52 | SPI.transfer(CC1101_SRES); 53 | delay(10); 54 | spi_waitMiso(); 55 | deselect(); 56 | } 57 | 58 | uint8_t CC1101::writeCommand(uint8_t command) 59 | { 60 | uint8_t result; 61 | 62 | select(); 63 | spi_waitMiso(); 64 | result = SPI.transfer(command); 65 | deselect(); 66 | 67 | return result; 68 | } 69 | 70 | void CC1101::writeRegister(uint8_t address, uint8_t data) 71 | { 72 | select(); 73 | spi_waitMiso(); 74 | SPI.transfer(address); 75 | SPI.transfer(data); 76 | deselect(); 77 | } 78 | 79 | uint8_t CC1101::readRegister(uint8_t address) 80 | { 81 | uint8_t val; 82 | 83 | select(); 84 | spi_waitMiso(); 85 | SPI.transfer(address); 86 | val = SPI.transfer(0); 87 | deselect(); 88 | 89 | return val; 90 | } 91 | 92 | uint8_t CC1101::readRegisterMedian3(uint8_t address) 93 | { 94 | uint8_t val, val1, val2, val3; 95 | 96 | select(); 97 | spi_waitMiso(); 98 | SPI.transfer(address); 99 | val1 = SPI.transfer(0); 100 | SPI.transfer(address); 101 | val2 = SPI.transfer(0); 102 | SPI.transfer(address); 103 | val3 = SPI.transfer(0); 104 | deselect(); 105 | // reverse sort (largest in val1) because this is te expected order for TX_BUFFER 106 | if (val3 > val2) {val = val3; val3 = val2; val2 = val; } //Swap(val3,val2) 107 | if (val2 > val1) {val = val2; val2 = val1, val1 = val; } //Swap(val2,val1) 108 | if (val3 > val2) {val = val3; val3 = val2, val2 = val; } //Swap(val3,val2) 109 | 110 | return val2; 111 | } 112 | 113 | /* Known SPI/26MHz synchronization bug (see CC1101 errata) 114 | This issue affects the following registers: SPI status byte (fields STATE and FIFO_BYTES_AVAILABLE), 115 | FREQEST or RSSI while the receiver is active, MARCSTATE at any time other than an IDLE radio state, 116 | RXBYTES when receiving or TXBYTES when transmitting, and WORTIME1/WORTIME0 at any time.*/ 117 | //uint8_t CC1101::readRegisterWithSyncProblem(uint8_t address, uint8_t registerType) 118 | uint8_t /* ICACHE_RAM_ATTR */ CC1101::readRegisterWithSyncProblem(uint8_t address, uint8_t registerType) 119 | { 120 | uint8_t value1, value2; 121 | 122 | value1 = readRegister(address | registerType); 123 | 124 | //if two consecutive reads gives us the same result then we know we are ok 125 | do 126 | { 127 | value2 = value1; 128 | value1 = readRegister(address | registerType); 129 | } 130 | while (value1 != value2); 131 | 132 | return value1; 133 | } 134 | 135 | //registerType = CC1101_CONFIG_REGISTER or CC1101_STATUS_REGISTER 136 | uint8_t CC1101::readRegister(uint8_t address, uint8_t registerType) 137 | { 138 | switch (address) 139 | { 140 | case CC1101_FREQEST: 141 | case CC1101_MARCSTATE: 142 | case CC1101_RXBYTES: 143 | case CC1101_TXBYTES: 144 | case CC1101_WORTIME1: 145 | case CC1101_WORTIME0: 146 | return readRegisterWithSyncProblem(address, registerType); 147 | 148 | default: 149 | return readRegister(address | registerType); 150 | } 151 | } 152 | 153 | void CC1101::writeBurstRegister(uint8_t address, uint8_t* data, uint8_t length) 154 | { 155 | uint8_t i; 156 | 157 | select(); 158 | spi_waitMiso(); 159 | SPI.transfer(address | CC1101_WRITE_BURST); 160 | for (i = 0; i < length; i++) { 161 | SPI.transfer(data[i]); 162 | } 163 | deselect(); 164 | } 165 | 166 | void CC1101::readBurstRegister(uint8_t* buffer, uint8_t address, uint8_t length) 167 | { 168 | uint8_t i; 169 | 170 | select(); 171 | spi_waitMiso(); 172 | SPI.transfer(address | CC1101_READ_BURST); 173 | 174 | for (i = 0; i < length; i++) { 175 | buffer[i] = SPI.transfer(0x00); 176 | } 177 | 178 | deselect(); 179 | } 180 | 181 | //wait for fixed length in rx fifo 182 | uint8_t CC1101::receiveData(CC1101Packet* packet, uint8_t length) 183 | { 184 | uint8_t rxBytes = readRegisterWithSyncProblem(CC1101_RXBYTES, CC1101_STATUS_REGISTER); 185 | rxBytes = rxBytes & CC1101_BITS_RX_BYTES_IN_FIFO; 186 | 187 | //check for rx fifo overflow 188 | if ((readRegisterWithSyncProblem(CC1101_MARCSTATE, CC1101_STATUS_REGISTER) & CC1101_BITS_MARCSTATE) == CC1101_MARCSTATE_RXFIFO_OVERFLOW) 189 | { 190 | writeCommand(CC1101_SIDLE); //idle 191 | writeCommand(CC1101_SFRX); //flush RX buffer 192 | writeCommand(CC1101_SRX); //switch to RX state 193 | } 194 | else if (rxBytes == length) 195 | { 196 | readBurstRegister(packet->data, CC1101_RXFIFO, rxBytes); 197 | 198 | //continue RX 199 | writeCommand(CC1101_SIDLE); //idle 200 | writeCommand(CC1101_SFRX); //flush RX buffer 201 | writeCommand(CC1101_SRX); //switch to RX state 202 | 203 | packet->length = rxBytes; 204 | } 205 | else 206 | { 207 | //empty fifo 208 | packet->length = 0; 209 | } 210 | 211 | return packet->length; 212 | } 213 | 214 | //This function is able to send packets bigger then the FIFO size. 215 | void CC1101::sendData(CC1101Packet *packet) 216 | { 217 | uint8_t index = 0; 218 | uint8_t txStatus, MarcState; 219 | uint8_t length; 220 | 221 | writeCommand(CC1101_SIDLE); //idle 222 | 223 | txStatus = readRegisterWithSyncProblem(CC1101_TXBYTES, CC1101_STATUS_REGISTER); 224 | 225 | //clear TX fifo if needed 226 | if (txStatus & CC1101_BITS_TX_FIFO_UNDERFLOW) 227 | { 228 | writeCommand(CC1101_SIDLE); //idle 229 | writeCommand(CC1101_SFTX); //flush TX buffer 230 | } 231 | 232 | writeCommand(CC1101_SIDLE); //idle 233 | 234 | //determine how many bytes to send 235 | length = (packet->length <= CC1101_DATA_LEN ? packet->length : CC1101_DATA_LEN); 236 | 237 | writeBurstRegister(CC1101_TXFIFO, packet->data, length); 238 | 239 | writeCommand(CC1101_SIDLE); 240 | //start sending packet 241 | writeCommand(CC1101_STX); 242 | 243 | //continue sending when packet is bigger than 64 bytes 244 | if (packet->length > CC1101_DATA_LEN) 245 | { 246 | index += length; 247 | 248 | //loop until all bytes are transmitted 249 | while (index < packet->length) 250 | { 251 | //check if there is free space in the fifo 252 | while ((txStatus = (readRegisterMedian3(CC1101_TXBYTES | CC1101_STATUS_REGISTER) & CC1101_BITS_RX_BYTES_IN_FIFO)) > (CC1101_DATA_LEN - 2)); 253 | 254 | //calculate how many bytes we can send 255 | length = (CC1101_DATA_LEN - txStatus); 256 | length = ((packet->length - index) < length ? (packet->length - index) : length); 257 | 258 | //send some more bytes 259 | for (int i=0; idata[index+i]); 261 | 262 | index += length; 263 | } 264 | } 265 | 266 | //wait until transmission is finished (TXOFF_MODE is expected to be set to 0/IDLE or TXFIFO_UNDERFLOW) 267 | do 268 | { 269 | MarcState = (readRegisterWithSyncProblem(CC1101_MARCSTATE, CC1101_STATUS_REGISTER) & CC1101_BITS_MARCSTATE); 270 | // if (MarcState == CC1101_MARCSTATE_TXFIFO_UNDERFLOW) Serial.print(F("TXFIFO_UNDERFLOW occured in sendData() \n")); 271 | } 272 | while((MarcState != CC1101_MARCSTATE_IDLE) && (MarcState != CC1101_MARCSTATE_TXFIFO_UNDERFLOW)); 273 | } 274 | -------------------------------------------------------------------------------- /Master/Itho/CC1101.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Klusjesman, modified bij supersjimmie for Arduino/ESP8266 3 | */ 4 | 5 | #ifndef __CC1101_H__ 6 | #define __CC1101_H__ 7 | 8 | #include 9 | #include "CC1101Packet.h" 10 | #include 11 | // On Arduino, SPI pins are predefined 12 | 13 | /* Type of transfers */ 14 | #define CC1101_WRITE_BURST 0x40 15 | #define CC1101_READ_SINGLE 0x80 16 | #define CC1101_READ_BURST 0xC0 17 | 18 | /* Type of register */ 19 | #define CC1101_CONFIG_REGISTER CC1101_READ_SINGLE 20 | #define CC1101_STATUS_REGISTER CC1101_READ_BURST 21 | 22 | /* PATABLE & FIFO's */ 23 | #define CC1101_PATABLE 0x3E // PATABLE address 24 | #define CC1101_TXFIFO 0x3F // TX FIFO address 25 | #define CC1101_RXFIFO 0x3F // RX FIFO address 26 | #define CC1101_PA_LowPower 0x60 27 | #define CC1101_PA_LongDistance 0xC0 28 | 29 | /* Command strobes */ 30 | #define CC1101_SRES 0x30 // Reset CC1101 chip 31 | #define CC1101_SFSTXON 0x31 // Enable and calibrate frequency synthesizer (if MCSM0.FS_AUTOCAL=1). If in RX (with CCA): Go to a wait state where only the synthesizer is running (for quick RX / TX turnaround). 32 | #define CC1101_SXOFF 0x32 // Turn off crystal oscillator 33 | #define CC1101_SCAL 0x33 // Calibrate frequency synthesizer and turn it off. SCAL can be strobed from IDLE mode without setting manual calibration mode (MCSM0.FS_AUTOCAL=0) 34 | #define CC1101_SRX 0x34 // Enable RX. Perform calibration first if coming from IDLE and MCSM0.FS_AUTOCAL=1 35 | #define CC1101_STX 0x35 // In IDLE state: Enable TX. Perform calibration first if MCSM0.FS_AUTOCAL=1. If in RX state and CCA is enabled: Only go to TX if channel is clear 36 | #define CC1101_SIDLE 0x36 // Exit RX / TX, turn off frequency synthesizer and exit Wake-On-Radio mode if applicable 37 | #define CC1101_SWOR 0x38 // Start automatic RX polling sequence (Wake-on-Radio) as described in Section 19.5 if WORCTRL.RC_PD=0 38 | #define CC1101_SPWD 0x39 // Enter power down mode when CSn goes high 39 | #define CC1101_SFRX 0x3A // Flush the RX FIFO buffer. Only issue SFRX in IDLE or RXFIFO_OVERFLOW states 40 | #define CC1101_SFTX 0x3B // Flush the TX FIFO buffer. Only issue SFTX in IDLE or TXFIFO_UNDERFLOW states 41 | #define CC1101_SWORRST 0x3C // Reset real time clock to Event1 value 42 | #define CC1101_SNOP 0x3D // No operation. May be used to get access to the chip status byte 43 | 44 | /* CC1101 configuration registers */ 45 | #define CC1101_IOCFG2 0x00 // GDO2 Output Pin Configuration 46 | #define CC1101_IOCFG1 0x01 // GDO1 Output Pin Configuration 47 | #define CC1101_IOCFG0 0x02 // GDO0 Output Pin Configuration 48 | #define CC1101_FIFOTHR 0x03 // RX FIFO and TX FIFO Thresholds 49 | #define CC1101_SYNC1 0x04 // Sync Word, High Byte 50 | #define CC1101_SYNC0 0x05 // Sync Word, Low Byte 51 | #define CC1101_PKTLEN 0x06 // Packet Length 52 | #define CC1101_PKTCTRL1 0x07 // Packet Automation Control 53 | #define CC1101_PKTCTRL0 0x08 // Packet Automation Control 54 | #define CC1101_ADDR 0x09 // Device Address 55 | #define CC1101_CHANNR 0x0A // Channel Number 56 | #define CC1101_FSCTRL1 0x0B // Frequency Synthesizer Control 57 | #define CC1101_FSCTRL0 0x0C // Frequency Synthesizer Control 58 | #define CC1101_FREQ2 0x0D // Frequency Control Word, High Byte 59 | #define CC1101_FREQ1 0x0E // Frequency Control Word, Middle Byte 60 | #define CC1101_FREQ0 0x0F // Frequency Control Word, Low Byte 61 | #define CC1101_MDMCFG4 0x10 // Modem Configuration 62 | #define CC1101_MDMCFG3 0x11 // Modem Configuration 63 | #define CC1101_MDMCFG2 0x12 // Modem Configuration 64 | #define CC1101_MDMCFG1 0x13 // Modem Configuration 65 | #define CC1101_MDMCFG0 0x14 // Modem Configuration 66 | #define CC1101_DEVIATN 0x15 // Modem Deviation Setting 67 | #define CC1101_MCSM2 0x16 // Main Radio Control State Machine Configuration 68 | #define CC1101_MCSM1 0x17 // Main Radio Control State Machine Configuration 69 | #define CC1101_MCSM0 0x18 // Main Radio Control State Machine Configuration 70 | #define CC1101_FOCCFG 0x19 // Frequency Offset Compensation Configuration 71 | #define CC1101_BSCFG 0x1A // Bit Synchronization Configuration 72 | #define CC1101_AGCCTRL2 0x1B // AGC Control 73 | #define CC1101_AGCCTRL1 0x1C // AGC Control 74 | #define CC1101_AGCCTRL0 0x1D // AGC Control 75 | #define CC1101_WOREVT1 0x1E // High Byte Event0 Timeout 76 | #define CC1101_WOREVT0 0x1F // Low Byte Event0 Timeout 77 | #define CC1101_WORCTRL 0x20 // Wake On Radio Control 78 | #define CC1101_FREND1 0x21 // Front End RX Configuration 79 | #define CC1101_FREND0 0x22 // Front End TX Configuration 80 | #define CC1101_FSCAL3 0x23 // Frequency Synthesizer Calibration 81 | #define CC1101_FSCAL2 0x24 // Frequency Synthesizer Calibration 82 | #define CC1101_FSCAL1 0x25 // Frequency Synthesizer Calibration 83 | #define CC1101_FSCAL0 0x26 // Frequency Synthesizer Calibration 84 | #define CC1101_RCCTRL1 0x27 // RC Oscillator Configuration 85 | #define CC1101_RCCTRL0 0x28 // RC Oscillator Configuration 86 | #define CC1101_FSTEST 0x29 // Frequency Synthesizer Calibration Control 87 | #define CC1101_PTEST 0x2A // Production Test 88 | #define CC1101_AGCTEST 0x2B // AGC Test 89 | #define CC1101_TEST2 0x2C // Various Test Settings 90 | #define CC1101_TEST1 0x2D // Various Test Settings 91 | #define CC1101_TEST0 0x2E // Various Test Settings 92 | 93 | /* Status registers */ 94 | #define CC1101_PARTNUM 0x30 // Chip ID 95 | #define CC1101_VERSION 0x31 // Chip ID 96 | #define CC1101_FREQEST 0x32 // Frequency Offset Estimate from Demodulator 97 | #define CC1101_LQI 0x33 // Demodulator Estimate for Link Quality 98 | #define CC1101_RSSI 0x34 // Received Signal Strength Indication 99 | #define CC1101_MARCSTATE 0x35 // Main Radio Control State Machine State 100 | #define CC1101_WORTIME1 0x36 // High Byte of WOR Time 101 | #define CC1101_WORTIME0 0x37 // Low Byte of WOR Time 102 | #define CC1101_PKTSTATUS 0x38 // Current GDOx Status and Packet Status 103 | #define CC1101_VCO_VC_DAC 0x39 // Current Setting from PLL Calibration Module 104 | #define CC1101_TXBYTES 0x3A // Underflow and Number of Bytes 105 | #define CC1101_RXBYTES 0x3B // Overflow and Number of Bytes 106 | #define CC1101_RCCTRL1_STATUS 0x3C // Last RC Oscillator Calibration Result 107 | #define CC1101_RCCTRL0_STATUS 0x3D // Last RC Oscillator Calibration Result 108 | 109 | /* Bit fields in the chip status byte */ 110 | #define CC1101_STATUS_CHIP_RDYn_BM 0x80 111 | #define CC1101_STATUS_STATE_BM 0x70 112 | #define CC1101_STATUS_FIFO_BYTES_AVAILABLE_BM 0x0F 113 | 114 | /* Masks to retrieve status bit */ 115 | #define CC1101_BITS_TX_FIFO_UNDERFLOW 0x80 116 | #define CC1101_BITS_RX_BYTES_IN_FIFO 0x7F 117 | #define CC1101_BITS_MARCSTATE 0x1F 118 | 119 | 120 | /* Marc states */ 121 | enum CC1101MarcStates 122 | { 123 | CC1101_MARCSTATE_SLEEP = 0x00, 124 | CC1101_MARCSTATE_IDLE = 0x01, 125 | CC1101_MARCSTATE_XOFF = 0x02, 126 | CC1101_MARCSTATE_VCOON_MC = 0x03, 127 | CC1101_MARCSTATE_REGON_MC = 0x04, 128 | CC1101_MARCSTATE_MANCAL = 0x05, 129 | CC1101_MARCSTATE_VCOON = 0x06, 130 | CC1101_MARCSTATE_REGON = 0x07, 131 | CC1101_MARCSTATE_STARTCAL = 0x08, 132 | CC1101_MARCSTATE_BWBOOST = 0x09, 133 | CC1101_MARCSTATE_FS_LOCK = 0x0A, 134 | CC1101_MARCSTATE_IFADCON = 0x0B, 135 | CC1101_MARCSTATE_ENDCAL = 0x0C, 136 | CC1101_MARCSTATE_RX = 0x0D, 137 | CC1101_MARCSTATE_RX_END = 0x0E, 138 | CC1101_MARCSTATE_RX_RST = 0x0F, 139 | CC1101_MARCSTATE_TXRX_SWITCH = 0x10, 140 | CC1101_MARCSTATE_RXFIFO_OVERFLOW = 0x11, 141 | CC1101_MARCSTATE_FSTXON = 0x12, 142 | CC1101_MARCSTATE_TX = 0x13, 143 | CC1101_MARCSTATE_TX_END = 0x14, 144 | CC1101_MARCSTATE_RXTX_SWITCH = 0x15, 145 | CC1101_MARCSTATE_TXFIFO_UNDERFLOW = 0x16 146 | }; 147 | 148 | 149 | /* Chip states */ 150 | enum CC1101ChipStates 151 | { 152 | CC1101_STATE_MASK = 0x70, 153 | CC1101_STATE_IDLE = 0x00, 154 | CC1101_STATE_RX = 0x10, 155 | CC1101_STATE_TX = 0x20, 156 | CC1101_STATE_FSTXON = 0x30, 157 | CC1101_STATE_CALIBRATE = 0x40, 158 | CC1101_STATE_SETTLING = 0x50, 159 | CC1101_STATE_RX_OVERFLOW = 0x60, 160 | CC1101_STATE_TX_UNDERFLOW = 0x70 161 | }; 162 | 163 | 164 | 165 | class CC1101 166 | { 167 | protected: 168 | 169 | //functions 170 | public: 171 | CC1101(); 172 | ~CC1101(); 173 | 174 | //spi 175 | void spi_waitMiso(); 176 | 177 | //cc1101 178 | void init(); 179 | 180 | uint8_t writeCommand(uint8_t command); 181 | void writeRegister(uint8_t address, uint8_t data); 182 | 183 | uint8_t readRegister(uint8_t address, uint8_t registerType); 184 | 185 | void writeBurstRegister(uint8_t address, uint8_t* data, uint8_t length); 186 | void readBurstRegister(uint8_t* buffer, uint8_t address, uint8_t length); 187 | 188 | void sendData(CC1101Packet *packet); 189 | uint8_t receiveData(CC1101Packet* packet, uint8_t length); 190 | 191 | private: 192 | CC1101( const CC1101 &c ); 193 | CC1101& operator=( const CC1101 &c ); 194 | // SPI helper functions 195 | void select(void); 196 | void deselect(void); 197 | 198 | protected: 199 | uint8_t readRegister(uint8_t address); 200 | uint8_t readRegisterMedian3(uint8_t address); 201 | uint8_t readRegisterWithSyncProblem(uint8_t address, uint8_t registerType); 202 | 203 | void reset(); 204 | 205 | }; //CC1101 206 | 207 | #endif //__CC1101_H__ 208 | -------------------------------------------------------------------------------- /Master/Itho/CC1101Packet.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Klusjesman, modified bij supersjimmie for Arduino/ESP8266 3 | */ 4 | 5 | #ifndef CC1101PACKET_H_ 6 | #define CC1101PACKET_H_ 7 | 8 | #include 9 | #ifdef ESP8266 10 | #include 11 | #endif 12 | 13 | #define CC1101_BUFFER_LEN 64 14 | #define CC1101_DATA_LEN CC1101_BUFFER_LEN - 3 15 | 16 | 17 | class CC1101Packet 18 | { 19 | public: 20 | uint8_t length; 21 | uint8_t data[72]; 22 | }; 23 | 24 | 25 | #endif /* CC1101PACKET_H_ */ -------------------------------------------------------------------------------- /Master/Itho/IthoCC1101.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/supersjimmie/IthoEcoFanRFT/7ae2c9e34e13a628988caa28f975c9929fb9676d/Master/Itho/IthoCC1101.cpp -------------------------------------------------------------------------------- /Master/Itho/IthoCC1101.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Klusjesman, modified bij supersjimmie for Arduino/ESP8266 3 | */ 4 | 5 | #ifndef __ITHOCC1101_H__ 6 | #define __ITHOCC1101_H__ 7 | 8 | #include 9 | #include "CC1101.h" 10 | #include "IthoPacket.h" 11 | 12 | 13 | //pa table settings 14 | const uint8_t ithoPaTableSend[8] = {0x6F, 0x26, 0x2E, 0x8C, 0x87, 0xCD, 0xC7, 0xC0}; 15 | const uint8_t ithoPaTableReceive[8] = {0x6F, 0x26, 0x2E, 0x7F, 0x8A, 0x84, 0xCA, 0xC4}; 16 | 17 | //rft message 1 commands 18 | const uint8_t ithoMessage1HighCommandBytes[] = {1,84,213,85,50,203,52}; 19 | const uint8_t ithoMessage1MediumCommandBytes[] = {1,84,213,85,74,213,52}; 20 | const uint8_t ithoMessage1LowCommandBytes[] = {1,84,213,85,83,83,84}; 21 | const uint8_t ithoMessage1Timer1CommandBytes[] = {1,83,83,84,204,202,180}; 22 | const uint8_t ithoMessage1Timer2CommandBytes[] = {1,83,83,83,53,52,180}; 23 | const uint8_t ithoMessage1Timer3CommandBytes[] = {1,83,83,82,173,82,180}; 24 | const uint8_t ithoMessage1JoinCommandBytes[] = {0,170,171,85,84,202,180}; 25 | const uint8_t ithoMessage1LeaveCommandBytes[] = {0,170,173,85,83,43,84}; 26 | 27 | //duco message1 commands 28 | const uint8_t ducoMessage1HighCommandBytes[] = {1,84,213,85,51,45,52}; 29 | const uint8_t ducoMessage1MediumCommandBytes[] = {1,84,213,85,75,51,52}; 30 | const uint8_t ducoMessage1LowCommandBytes[] = {1,84,213,85,82,181,84}; 31 | const uint8_t ducoMessage1StandByCommandBytes[] = {1,85,53,84,205,85,52}; 32 | const uint8_t ducoMessage1JoinCommandBytes[] = {0,170,171,85,85,44,180}; 33 | const uint8_t ducoMessage1LeaveCommandBytes[] = {0,170,173,85,82,205,84}; 34 | 35 | //message 2 commands 36 | const uint8_t ithoMessage2PowerCommandBytes[] = {6,89,150,170,165,101,90,150,85,149,101,90,102,85,150}; 37 | const uint8_t ithoMessage2HighCommandBytes[] = {6,89,150,170,165,101,90,150,85,149,101,89,102,85,150}; 38 | const uint8_t ithoMessage2MediumCommandBytes[] = {6,89,150,170,165,101,90,150,85,149,101,90,150,85,150}; 39 | const uint8_t ithoMessage2LowCommandBytes[] = {6,89,150,170,165,101,90,150,85,149,101,89,150,85,150}; 40 | const uint8_t ithoMessage2StandByCommandBytes[] = {6,89,150,170,165,101,90,150,85,149,101,90,86,85,150}; 41 | const uint8_t ithoMessage2Timer1CommandBytes[] = {6,89,150,170,169,101,90,150,85,149,101,89,86,85,153}; //10 minutes full speed 42 | const uint8_t ithoMessage2Timer2CommandBytes[] = {6,89,150,170,169,101,90,150,85,149,101,89,86,149,150}; //20 minutes full speed 43 | const uint8_t ithoMessage2Timer3CommandBytes[] = {6,89,150,170,169,101,90,150,85,149,101,89,86,149,154}; //30 minutes full speed 44 | const uint8_t ithoMessage2JoinCommandBytes[] = {9,90,170,90,165,165,89,106,85,149,102,89,150,170,165}; 45 | const uint8_t ithoMessage2LeaveCommandBytes[] = {9,90,170,90,165,165,89,166,85,149,105,90,170,90,165}; 46 | 47 | //message 2, counter 48 | const uint8_t counterBytes24a[] = {1,2}; 49 | const uint8_t counterBytes24b[] = {84,148,100,164,88,152,104,168}; 50 | const uint8_t counterBytes25[] = {149,165,153,169,150,166,154,170}; 51 | const uint8_t counterBytes26[] = {96,160}; 52 | const uint8_t counterBytes41[] = {5, 10, 6, 9}; 53 | const uint8_t counterBytes42[] = {90, 170, 106, 154}; 54 | const uint8_t counterBytes43[] = {154, 90, 166, 102, 150, 86, 170, 106}; 55 | //join/leave 56 | const uint8_t counterBytes64[] = {154,90,166,102,150,86,169,105,153,89,165,101,149,85,170,106}; 57 | const uint8_t counterBytes65[] = {150,169,153,165,149,170,154,166}; 58 | const uint8_t counterBytes66[] = {170,106}; 59 | 60 | 61 | //state machine 62 | typedef enum IthoReceiveStates 63 | { 64 | ExpectMessageStart, 65 | ExpectNormalCommand, 66 | ExpectJoinCommand, 67 | ExpectLeaveCommand 68 | }; 69 | 70 | 71 | 72 | class IthoCC1101 : protected CC1101 73 | { 74 | private: 75 | //receive 76 | IthoReceiveStates receiveState; //state machine receive 77 | unsigned long lastMessage1Received; //used for timeout detection 78 | CC1101Packet inMessage1; //temp storage message1 79 | CC1101Packet inMessage2; //temp storage message2 80 | IthoPacket inIthoPacket; //stores last received message data 81 | 82 | //send 83 | IthoPacket outIthoPacket; //stores state of "remote" 84 | 85 | //settings 86 | uint8_t sendTries; //number of times a command is send at one button press 87 | 88 | //functions 89 | public: 90 | IthoCC1101(uint8_t counter = 0, uint8_t sendTries = 3); //set initial counter value 91 | ~IthoCC1101(); 92 | 93 | //init 94 | void init() { CC1101::init(); } //init,reset CC1101 95 | void initReceive(); 96 | uint8_t getLastCounter() { return outIthoPacket.counter; } //counter is increased before sending a command 97 | void setSendTries(uint8_t sendTries) { this->sendTries = sendTries; } 98 | 99 | //- deviceid should be a setting as well? random gen function? TODO 100 | 101 | //receive 102 | bool checkForNewPacket(); //check RX fifo for new data 103 | IthoPacket getLastPacket() { return inIthoPacket; } //retrieve last received/parsed packet from remote 104 | IthoCommand getLastCommand() { return inIthoPacket.command; } //retrieve last received/parsed command from remote 105 | uint8_t getLastInCounter() { return inIthoPacket.counter; } //retrieve last received/parsed command from remote 106 | uint8_t ReadRSSI(); 107 | bool checkID(const uint8_t *id); 108 | String getLastIDstr(bool ashex=true); 109 | String getLastMessage2str(bool ashex=true); 110 | 111 | 112 | //send 113 | void sendCommand(IthoCommand command); 114 | protected: 115 | private: 116 | IthoCC1101( const IthoCC1101 &c); 117 | IthoCC1101& operator=( const IthoCC1101 &c); 118 | 119 | //init CC1101 for receiving 120 | void initReceiveMessage1(); 121 | void initReceiveMessage2(IthoMessageType expectedMessageType); 122 | 123 | //init CC1101 for sending 124 | void initSendMessage1(); 125 | void initSendMessage2(IthoCommand command); 126 | void finishTransfer(); 127 | 128 | //receive message validation 129 | bool isValidMessageStart(); 130 | bool isValidMessageCommand(); 131 | bool isValidMessageJoin(); 132 | bool isValidMessageLeave(); 133 | 134 | //parse received message 135 | void parseReceivedPackets(); 136 | void parseMessageStart(); 137 | void parseMessageCommand(); 138 | void parseMessageJoin(); 139 | void parseMessageLeave(); 140 | 141 | //send 142 | void createMessageStart(IthoPacket *itho, CC1101Packet *packet); 143 | void createMessageCommand(IthoPacket *itho, CC1101Packet *packet); 144 | void createMessageJoin(IthoPacket *itho, CC1101Packet *packet); 145 | void createMessageLeave(IthoPacket *itho, CC1101Packet *packet); 146 | uint8_t* getMessage1CommandBytes(IthoCommand command); 147 | uint8_t* getMessage2CommandBytes(IthoCommand command); 148 | 149 | //counter bytes calculation (send) 150 | uint8_t getMessage1Byte18(IthoCommand command); 151 | IthoCommand getMessage1PreviousCommand(uint8_t byte18); 152 | uint8_t calculateMessage2Byte24(uint8_t counter); 153 | uint8_t calculateMessage2Byte25(uint8_t counter); 154 | uint8_t calculateMessage2Byte26(uint8_t counter); 155 | uint8_t calculateMessage2Byte41(uint8_t counter, IthoCommand command); 156 | uint8_t calculateMessage2Byte42(uint8_t counter, IthoCommand command); 157 | uint8_t calculateMessage2Byte43(uint8_t counter, IthoCommand command); 158 | uint8_t calculateMessage2Byte49(uint8_t counter); 159 | uint8_t calculateMessage2Byte50(uint8_t counter); 160 | uint8_t calculateMessage2Byte51(uint8_t counter); 161 | uint8_t calculateMessage2Byte64(uint8_t counter); 162 | uint8_t calculateMessage2Byte65(uint8_t counter); 163 | uint8_t calculateMessage2Byte66(uint8_t counter); 164 | 165 | //counter calculation (receive) 166 | uint8_t calculateMessageCounter(uint8_t byte24, uint8_t byte25, uint8_t byte26); 167 | 168 | //general 169 | uint8_t getCounterIndex(const uint8_t *arr, uint8_t length, uint8_t value); 170 | 171 | //test 172 | void testCreateMessage(); 173 | 174 | }; //IthoCC1101 175 | 176 | 177 | extern volatile uint32_t data1[]; 178 | 179 | #endif //__ITHOCC1101_H__ 180 | -------------------------------------------------------------------------------- /Master/Itho/IthoPacket.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Klusjesman, modified bij supersjimmie for Arduino/ESP8266 3 | */ 4 | 5 | #ifndef ITHOPACKET_H_ 6 | #define ITHOPACKET_H_ 7 | 8 | 9 | typedef enum IthoMessageType 10 | { 11 | ithomsg_unknown = 0, 12 | ithomsg_control = 1, 13 | ithomsg_join = 2, 14 | ithomsg_leave = 3 15 | }; 16 | 17 | //do not change enum because they are used in calculations! 18 | enum IthoCommand 19 | { 20 | IthoUnknown = 0, 21 | 22 | IthoJoin = 4, 23 | IthoLeave = 8, 24 | 25 | IthoStandby = 34, 26 | IthoLow = 35, 27 | IthoMedium = 36, 28 | IthoHigh = 37, 29 | IthoFull = 38, 30 | 31 | IthoTimer1 = 41, 32 | IthoTimer2 = 51, 33 | IthoTimer3 = 61, 34 | 35 | //duco c system remote 36 | DucoStandby = 251, 37 | DucoLow = 252, 38 | DucoMedium = 253, 39 | DucoHigh = 254 40 | }; 41 | 42 | 43 | class IthoPacket 44 | { 45 | public: 46 | uint8_t deviceId1[6]; 47 | uint8_t deviceId2[8]; 48 | IthoMessageType messageType; 49 | IthoCommand command; 50 | IthoCommand previous; 51 | 52 | uint8_t counter; //0-255, counter is increased on every remote button press 53 | }; 54 | 55 | 56 | #endif /* ITHOPACKET_H_ */ -------------------------------------------------------------------------------- /Master/IthoEcoFanRFT/IthoEcoFanRFT.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Original Author: Klusjesman 3 | 4 | Tested with STK500 + ATMega328P 5 | GCC-AVR compiler 6 | 7 | Modified by supersjimmie: 8 | Code and libraries made compatible with Arduino and ESP8266 9 | Tested with Arduino IDE v1.6.5 and 1.6.9 10 | For ESP8266 tested with ESP8266 core for Arduino v 2.1.0 and 2.2.0 Stable 11 | (See https://github.com/esp8266/Arduino/ ) 12 | 13 | */ 14 | 15 | /* 16 | CC11xx pins ESP pins Arduino pins Description 17 | 1 - VCC VCC VCC 3v3 18 | 2 - GND GND GND Ground 19 | 3 - MOSI 13=D7 Pin 11 Data input to CC11xx 20 | 4 - SCK 14=D5 Pin 13 Clock pin 21 | 5 - MISO/GDO1 12=D6 Pin 12 Data output from CC11xx / serial clock from CC11xx 22 | 6 - GDO2 04=D2 Pin 2? Serial data to CC11xx 23 | 7 - GDO0 ? Pin ? output as a symbol of receiving or sending data 24 | 8 - CSN 15=D8 Pin 10 Chip select / (SPI_SS) 25 | */ 26 | 27 | #include 28 | #include "IthoCC1101.h" 29 | #include "IthoPacket.h" 30 | #include 31 | 32 | #define ITHO_IRQ_PIN D2 33 | 34 | IthoCC1101 rf; 35 | IthoPacket packet; 36 | Ticker ITHOticker; 37 | 38 | const uint8_t RFTid[] = {106, 170, 106, 101, 154, 107, 154, 86}; // my ID 39 | 40 | bool ITHOhasPacket = false; 41 | IthoCommand RFTcommand[3] = {IthoUnknown, IthoUnknown, IthoUnknown}; 42 | byte RFTRSSI[3] = {0, 0, 0}; 43 | byte RFTcommandpos = 0; 44 | IthoCommand RFTlastCommand = IthoLow; 45 | IthoCommand RFTstate = IthoUnknown; 46 | IthoCommand savedRFTstate = IthoUnknown; 47 | bool RFTidChk[3] = {false, false, false}; 48 | 49 | void setup(void) { 50 | Serial.begin(115200); 51 | delay(500); 52 | Serial.println("setup begin"); 53 | rf.init(); 54 | Serial.println("setup done"); 55 | sendRegister(); 56 | Serial.println("join command sent"); 57 | pinMode(ITHO_IRQ_PIN, INPUT); 58 | attachInterrupt(ITHO_IRQ_PIN, ITHOinterrupt, RISING); 59 | } 60 | 61 | void loop(void) { 62 | // do whatever you want, check (and reset) the ITHOhasPacket flag whenever you like 63 | if (ITHOhasPacket) { 64 | showPacket(); 65 | } 66 | } 67 | 68 | void ITHOinterrupt() { 69 | ITHOticker.once_ms(10, ITHOcheck); 70 | } 71 | 72 | void ITHOcheck() { 73 | if (rf.checkForNewPacket()) { 74 | IthoCommand cmd = rf.getLastCommand(); 75 | if (++RFTcommandpos > 2) RFTcommandpos = 0; // store information in next entry of ringbuffers 76 | RFTcommand[RFTcommandpos] = cmd; 77 | RFTRSSI[RFTcommandpos] = rf.ReadRSSI(); 78 | bool chk = rf.checkID(RFTid); 79 | RFTidChk[RFTcommandpos] = chk; 80 | if ((cmd != IthoUnknown) && chk) { // only act on good cmd and correct id. 81 | ITHOhasPacket = true; 82 | } 83 | } 84 | } 85 | 86 | void showPacket() { 87 | ITHOhasPacket = false; 88 | uint8_t goodpos = findRFTlastCommand(); 89 | if (goodpos != -1) RFTlastCommand = RFTcommand[goodpos]; 90 | else RFTlastCommand = IthoUnknown; 91 | //show data 92 | Serial.print(F("RFT Current Pos: ")); 93 | Serial.print(RFTcommandpos); 94 | Serial.print(F(", Good Pos: ")); 95 | Serial.println(goodpos); 96 | Serial.print(F("Stored 3 commands: ")); 97 | Serial.print(RFTcommand[0]); 98 | Serial.print(F(" ")); 99 | Serial.print(RFTcommand[1]); 100 | Serial.print(F(" ")); 101 | Serial.print(RFTcommand[2]); 102 | Serial.print(F(" / Stored 3 RSSI's: ")); 103 | Serial.print(RFTRSSI[0]); 104 | Serial.print(F(" ")); 105 | Serial.print(RFTRSSI[1]); 106 | Serial.print(F(" ")); 107 | Serial.print(RFTRSSI[2]); 108 | Serial.print(F(" / Stored 3 ID checks: ")); 109 | Serial.print(RFTidChk[0]); 110 | Serial.print(F(" ")); 111 | Serial.print(RFTidChk[1]); 112 | Serial.print(F(" ")); 113 | Serial.print(RFTidChk[2]); 114 | Serial.print(F(" / Last ID: ")); 115 | Serial.print(rf.getLastIDstr()); 116 | 117 | Serial.print(F(" / Command = ")); 118 | //show command 119 | switch (RFTlastCommand) { 120 | case IthoUnknown: 121 | Serial.print("unknown\n"); 122 | break; 123 | case IthoLow: 124 | Serial.print("low\n"); 125 | break; 126 | case IthoMedium: 127 | Serial.print("medium\n"); 128 | break; 129 | case IthoHigh: 130 | Serial.print("high\n"); 131 | break; 132 | case IthoFull: 133 | Serial.print("full\n"); 134 | break; 135 | case IthoTimer1: 136 | Serial.print("timer1\n"); 137 | break; 138 | case IthoTimer2: 139 | Serial.print("timer2\n"); 140 | break; 141 | case IthoTimer3: 142 | Serial.print("timer3\n"); 143 | break; 144 | case IthoJoin: 145 | Serial.print("join\n"); 146 | break; 147 | case IthoLeave: 148 | Serial.print("leave\n"); 149 | break; 150 | } 151 | } 152 | 153 | uint8_t findRFTlastCommand() { 154 | if (RFTcommand[RFTcommandpos] != IthoUnknown) return RFTcommandpos; 155 | if ((RFTcommandpos == 0) && (RFTcommand[2] != IthoUnknown)) return 2; 156 | if ((RFTcommandpos == 0) && (RFTcommand[1] != IthoUnknown)) return 1; 157 | if ((RFTcommandpos == 1) && (RFTcommand[0] != IthoUnknown)) return 0; 158 | if ((RFTcommandpos == 1) && (RFTcommand[2] != IthoUnknown)) return 2; 159 | if ((RFTcommandpos == 2) && (RFTcommand[1] != IthoUnknown)) return 1; 160 | if ((RFTcommandpos == 2) && (RFTcommand[0] != IthoUnknown)) return 0; 161 | return -1; 162 | } 163 | 164 | void sendRegister() { 165 | Serial.println("sending join..."); 166 | rf.sendCommand(IthoJoin); 167 | Serial.println("sending join done."); 168 | } 169 | 170 | void sendStandbySpeed() { 171 | Serial.println("sending standby..."); 172 | rf.sendCommand(IthoStandby); 173 | Serial.println("sending standby done."); 174 | } 175 | 176 | void sendLowSpeed() { 177 | Serial.println("sending low..."); 178 | rf.sendCommand(IthoLow); 179 | Serial.println("sending low done."); 180 | } 181 | 182 | void sendMediumSpeed() { 183 | Serial.println("sending medium..."); 184 | rf.sendCommand(IthoMedium); 185 | Serial.println("sending medium done."); 186 | } 187 | 188 | void sendHighSpeed() { 189 | Serial.println("sending high..."); 190 | rf.sendCommand(IthoHigh); 191 | Serial.println("sending high done."); 192 | } 193 | 194 | void sendFullSpeed() { 195 | Serial.println("sending FullSpeed..."); 196 | rf.sendCommand(IthoFull); 197 | Serial.println("sending FullSpeed done."); 198 | } 199 | 200 | void sendTimer() { 201 | Serial.println("sending timer..."); 202 | rf.sendCommand(IthoTimer1); 203 | Serial.println("sending timer done."); 204 | } 205 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # IthoEcoFanRFT 2 | Cloned from Klusjesman, modified to work on Arduino and ESP8266 with Arduino IDE 3 | 4 | Will work with a 868MHz CC1101 module. 5 | The CC1150 may also work, except for receiving (which is not required for controlling an Itho EcoFan). 6 | A 433MHz CC1101/CC1150 might also work, because it has the same chip. But a 433MHz CC11xx board has a different RF filter, causing a lot less transmission power (and reception). 7 | ``` 8 | Connections between the CC1101 and the ESP8266 or Arduino: 9 | CC11xx pins ESP pins Arduino pins Description 10 | * 1 - VCC VCC VCC 3v3 11 | * 2 - GND GND GND Ground 12 | * 3 - MOSI 13=D7 Pin 11 Data input to CC11xx 13 | * 4 - SCK 14=D5 Pin 13 Clock pin 14 | * 5 - MISO/GDO1 12=D6 Pin 12 Data output from CC11xx / serial clock from CC11xx 15 | * 6 - GDO2 04=D2 Pin 2 Programmable output 16 | * 7 - GDO0 ? Pin ? Programmable output 17 | * 8 - CSN 15=D8 Pin 10 Chip select / (SPI_SS) 18 | ``` 19 | Note that CC11xx pin GDO0 is not used. 20 | Also note that the GDO2 pin connected to pin 2 on an Arduino. Change ```#define ITHO_IRQ_PIN``` in the example ino accordingly. 21 | 22 | You should keep the wires to the CC11xx module as short as possible. 23 | 24 | Beware that the CC11xx modules are 3.3V (3.6V max) on all pins! 25 | This won't be a problem with an ESP8266, but for Arduino you either need to use a 3.3V Arduino or use levelshifters and a separate 3.3V power source. 26 | 27 | For use with an ESP8266, you will need the ESP8266 core for Arduino from https://github.com/esp8266/Arduino 28 | 29 | For SPI, pins 12-15 (aka D5-D8) are used. 30 | A larger ESP8266 model like (but not only) the ESP-03, ESP-07, ESP-12(D, E) or a NodeMCU board is required. 31 | --------------------------------------------------------------------------------