acid-drop- Hacking the planet from a LilyGo T-Deck using custom firmware |
git clone git://git.acid.vegas/acid-drop.git |
Log | Files | Refs | Archive | README | LICENSE |
Si443x.cpp (26036B)
1 #include "Si443x.h" 2 #if !defined(RADIOLIB_EXCLUDE_SI443X) 3 4 Si443x::Si443x(Module* mod) : PhysicalLayer(RADIOLIB_SI443X_FREQUENCY_STEP_SIZE, RADIOLIB_SI443X_MAX_PACKET_LENGTH) { 5 _mod = mod; 6 } 7 8 Module* Si443x::getMod() { 9 return(_mod); 10 } 11 12 int16_t Si443x::begin(float br, float freqDev, float rxBw, uint8_t preambleLen) { 13 // set module properties 14 _mod->init(); 15 _mod->pinMode(_mod->getIrq(), INPUT); 16 _mod->pinMode(_mod->getRst(), OUTPUT); 17 _mod->digitalWrite(_mod->getRst(), LOW); 18 19 // try to find the Si443x chip 20 if(!Si443x::findChip()) { 21 RADIOLIB_DEBUG_PRINTLN(F("No Si443x found!")); 22 _mod->term(); 23 return(RADIOLIB_ERR_CHIP_NOT_FOUND); 24 } else { 25 RADIOLIB_DEBUG_PRINTLN(F("M\tSi443x")); 26 } 27 28 // reset the device 29 _mod->SPIwriteRegister(RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_1, RADIOLIB_SI443X_SOFTWARE_RESET); 30 31 // clear POR interrupt 32 clearIRQFlags(); 33 34 // configure settings not accessible by API 35 int16_t state = config(); 36 RADIOLIB_ASSERT(state); 37 38 // configure publicly accessible settings 39 state = setBitRate(br); 40 RADIOLIB_ASSERT(state); 41 42 state = setFrequencyDeviation(freqDev); 43 RADIOLIB_ASSERT(state); 44 45 state = setRxBandwidth(rxBw); 46 RADIOLIB_ASSERT(state); 47 48 state = setPreambleLength(preambleLen); 49 RADIOLIB_ASSERT(state); 50 51 uint8_t syncWord[] = {0x12, 0xAD}; 52 state = setSyncWord(syncWord, sizeof(syncWord)); 53 RADIOLIB_ASSERT(state); 54 55 state = packetMode(); 56 RADIOLIB_ASSERT(state); 57 58 state = setDataShaping(0); 59 RADIOLIB_ASSERT(state); 60 61 state = setEncoding(0); 62 RADIOLIB_ASSERT(state); 63 64 state = variablePacketLengthMode(); 65 66 return(state); 67 } 68 69 void Si443x::reset() { 70 _mod->pinMode(_mod->getRst(), OUTPUT); 71 _mod->digitalWrite(_mod->getRst(), HIGH); 72 _mod->delay(1); 73 _mod->digitalWrite(_mod->getRst(), LOW); 74 _mod->delay(100); 75 } 76 77 int16_t Si443x::transmit(uint8_t* data, size_t len, uint8_t addr) { 78 // calculate timeout (5ms + 500 % of expected time-on-air) 79 uint32_t timeout = 5000000 + (uint32_t)((((float)(len * 8)) / (_br * 1000.0)) * 5000000.0); 80 81 // start transmission 82 int16_t state = startTransmit(data, len, addr); 83 RADIOLIB_ASSERT(state); 84 85 // wait for transmission end or timeout 86 uint32_t start = _mod->micros(); 87 while(_mod->digitalRead(_mod->getIrq())) { 88 _mod->yield(); 89 if(_mod->micros() - start > timeout) { 90 standby(); 91 clearIRQFlags(); 92 return(RADIOLIB_ERR_TX_TIMEOUT); 93 } 94 } 95 96 // clear interrupt flags 97 clearIRQFlags(); 98 99 // set mode to standby 100 standby(); 101 102 return(state); 103 } 104 105 int16_t Si443x::receive(uint8_t* data, size_t len) { 106 // calculate timeout (500 ms + 400 full 64-byte packets at current bit rate) 107 uint32_t timeout = 500000 + (1.0/(_br*1000.0))*(RADIOLIB_SI443X_MAX_PACKET_LENGTH*400.0); 108 109 // start reception 110 int16_t state = startReceive(); 111 RADIOLIB_ASSERT(state); 112 113 // wait for packet reception or timeout 114 uint32_t start = _mod->micros(); 115 while(_mod->digitalRead(_mod->getIrq())) { 116 if(_mod->micros() - start > timeout) { 117 standby(); 118 clearIRQFlags(); 119 return(RADIOLIB_ERR_RX_TIMEOUT); 120 } 121 } 122 123 // read packet data 124 return(readData(data, len)); 125 } 126 127 int16_t Si443x::sleep() { 128 // set RF switch (if present) 129 _mod->setRfSwitchState(LOW, LOW); 130 131 // disable wakeup timer interrupt 132 int16_t state = _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_INTERRUPT_ENABLE_1, 0x00); 133 RADIOLIB_ASSERT(state); 134 state = _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_INTERRUPT_ENABLE_2, 0x00); 135 RADIOLIB_ASSERT(state); 136 137 // enable wakeup timer to set mode to sleep 138 _mod->SPIwriteRegister(RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_1, RADIOLIB_SI443X_ENABLE_WAKEUP_TIMER); 139 140 return(state); 141 } 142 143 int16_t Si443x::standby() { 144 // set RF switch (if present) 145 _mod->setRfSwitchState(LOW, LOW); 146 147 return(_mod->SPIsetRegValue(RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_1, RADIOLIB_SI443X_XTAL_ON, 7, 0, 10)); 148 } 149 150 int16_t Si443x::transmitDirect(uint32_t frf) { 151 // set RF switch (if present) 152 _mod->setRfSwitchState(LOW, HIGH); 153 154 // user requested to start transmitting immediately (required for RTTY) 155 if(frf != 0) { 156 // convert the 24-bit frequency to the format accepted by the module 157 /// \todo integers only 158 float newFreq = frf / 6400.0; 159 160 // check high/low band 161 uint8_t bandSelect = RADIOLIB_SI443X_BAND_SELECT_LOW; 162 uint8_t freqBand = (newFreq / 10) - 24; 163 if(newFreq >= 480.0) { 164 bandSelect = RADIOLIB_SI443X_BAND_SELECT_HIGH; 165 freqBand = (newFreq / 20) - 24; 166 } 167 168 // calculate register values 169 uint16_t freqCarrier = ((newFreq / (10 * ((bandSelect >> 5) + 1))) - freqBand - 24) * (uint32_t)64000; 170 171 // update registers 172 _mod->SPIwriteRegister(RADIOLIB_SI443X_REG_FREQUENCY_BAND_SELECT, RADIOLIB_SI443X_SIDE_BAND_SELECT_LOW | bandSelect | freqBand); 173 _mod->SPIwriteRegister(RADIOLIB_SI443X_REG_NOM_CARRIER_FREQUENCY_1, (uint8_t)((freqCarrier & 0xFF00) >> 8)); 174 _mod->SPIwriteRegister(RADIOLIB_SI443X_REG_NOM_CARRIER_FREQUENCY_0, (uint8_t)(freqCarrier & 0xFF)); 175 176 // start direct transmission 177 directMode(); 178 _mod->SPIwriteRegister(RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_1, RADIOLIB_SI443X_TX_ON | RADIOLIB_SI443X_XTAL_ON); 179 180 return(RADIOLIB_ERR_NONE); 181 } 182 183 // activate direct mode 184 int16_t state = directMode(); 185 RADIOLIB_ASSERT(state); 186 187 // start transmitting 188 _mod->SPIwriteRegister(RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_1, RADIOLIB_SI443X_TX_ON | RADIOLIB_SI443X_XTAL_ON); 189 return(state); 190 } 191 192 int16_t Si443x::receiveDirect() { 193 // set RF switch (if present) 194 _mod->setRfSwitchState(HIGH, LOW); 195 196 // activate direct mode 197 int16_t state = directMode(); 198 RADIOLIB_ASSERT(state); 199 200 // start receiving 201 _mod->SPIwriteRegister(RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_1, RADIOLIB_SI443X_RX_ON | RADIOLIB_SI443X_XTAL_ON); 202 return(state); 203 } 204 205 int16_t Si443x::packetMode() { 206 int16_t state = _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_2, RADIOLIB_SI443X_MODULATION_FSK, 1, 0); 207 RADIOLIB_ASSERT(state); 208 209 return(_mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_2, RADIOLIB_SI443X_TX_DATA_SOURCE_FIFO, 5, 4)); 210 } 211 212 void Si443x::setIrqAction(void (*func)(void)) { 213 _mod->attachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq()), func, FALLING); 214 } 215 216 void Si443x::clearIrqAction() { 217 _mod->detachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq())); 218 } 219 220 int16_t Si443x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { 221 // check packet length 222 if(len > RADIOLIB_SI443X_MAX_PACKET_LENGTH) { 223 return(RADIOLIB_ERR_PACKET_TOO_LONG); 224 } 225 226 // set mode to standby 227 int16_t state = standby(); 228 RADIOLIB_ASSERT(state); 229 230 // clear Tx FIFO 231 _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_2, RADIOLIB_SI443X_TX_FIFO_RESET, 0, 0); 232 _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_2, RADIOLIB_SI443X_TX_FIFO_CLEAR, 0, 0); 233 234 // clear interrupt flags 235 clearIRQFlags(); 236 237 // set packet length 238 if (_packetLengthConfig == RADIOLIB_SI443X_FIXED_PACKET_LENGTH_OFF) { 239 _mod->SPIwriteRegister(RADIOLIB_SI443X_REG_TRANSMIT_PACKET_LENGTH, len); 240 } 241 242 /// \todo use header as address field? 243 (void)addr; 244 245 // write packet to FIFO 246 _mod->SPIwriteRegisterBurst(RADIOLIB_SI443X_REG_FIFO_ACCESS, data, len); 247 248 // set RF switch (if present) 249 _mod->setRfSwitchState(LOW, HIGH); 250 251 // set interrupt mapping 252 _mod->SPIwriteRegister(RADIOLIB_SI443X_REG_INTERRUPT_ENABLE_1, RADIOLIB_SI443X_PACKET_SENT_ENABLED); 253 _mod->SPIwriteRegister(RADIOLIB_SI443X_REG_INTERRUPT_ENABLE_2, 0x00); 254 255 // set mode to transmit 256 _mod->SPIwriteRegister(RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_1, RADIOLIB_SI443X_TX_ON | RADIOLIB_SI443X_XTAL_ON); 257 258 return(state); 259 } 260 261 int16_t Si443x::startReceive() { 262 // set mode to standby 263 int16_t state = standby(); 264 RADIOLIB_ASSERT(state); 265 266 // clear Rx FIFO 267 _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_2, RADIOLIB_SI443X_RX_FIFO_RESET, 1, 1); 268 _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_2, RADIOLIB_SI443X_RX_FIFO_CLEAR, 1, 1); 269 270 // clear interrupt flags 271 clearIRQFlags(); 272 273 // set RF switch (if present) 274 _mod->setRfSwitchState(HIGH, LOW); 275 276 // set interrupt mapping 277 _mod->SPIwriteRegister(RADIOLIB_SI443X_REG_INTERRUPT_ENABLE_1, RADIOLIB_SI443X_VALID_PACKET_RECEIVED_ENABLED | RADIOLIB_SI443X_CRC_ERROR_ENABLED); 278 _mod->SPIwriteRegister(RADIOLIB_SI443X_REG_INTERRUPT_ENABLE_2, 0x00); 279 280 // set mode to receive 281 _mod->SPIwriteRegister(RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_1, RADIOLIB_SI443X_RX_ON | RADIOLIB_SI443X_XTAL_ON); 282 283 return(state); 284 } 285 286 int16_t Si443x::readData(uint8_t* data, size_t len) { 287 // clear interrupt flags 288 clearIRQFlags(); 289 290 // get packet length 291 size_t length = getPacketLength(); 292 size_t dumpLen = 0; 293 if((len != 0) && (len < length)) { 294 // user requested less data than we got, only return what was requested 295 dumpLen = length - len; 296 length = len; 297 } 298 299 // read packet data 300 _mod->SPIreadRegisterBurst(RADIOLIB_SI443X_REG_FIFO_ACCESS, length, data); 301 302 // dump the bytes that weren't requested 303 if(dumpLen != 0) { 304 clearFIFO(dumpLen); 305 } 306 307 // clear internal flag so getPacketLength can return the new packet length 308 _packetLengthQueried = false; 309 310 // set mode to standby 311 int16_t state = standby(); 312 RADIOLIB_ASSERT(state); 313 314 // clear interrupt flags 315 clearIRQFlags(); 316 317 return(RADIOLIB_ERR_NONE); 318 } 319 320 int16_t Si443x::setBitRate(float br) { 321 RADIOLIB_CHECK_RANGE(br, 0.123, 256.0, RADIOLIB_ERR_INVALID_BIT_RATE); 322 323 // check high data rate 324 uint8_t dataRateMode = RADIOLIB_SI443X_LOW_DATA_RATE_MODE; 325 uint8_t exp = 21; 326 if(br >= 30.0) { 327 // bit rate above 30 kbps 328 dataRateMode = RADIOLIB_SI443X_HIGH_DATA_RATE_MODE; 329 exp = 16; 330 } 331 332 // calculate raw data rate value 333 uint16_t txDr = (br * ((uint32_t)1 << exp)) / 1000.0; 334 335 // update registers 336 int16_t state = _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_1, dataRateMode, 5, 5); 337 _mod->SPIwriteRegister(RADIOLIB_SI443X_REG_TX_DATA_RATE_1, (uint8_t)((txDr & 0xFF00) >> 8)); 338 _mod->SPIwriteRegister(RADIOLIB_SI443X_REG_TX_DATA_RATE_0, (uint8_t)(txDr & 0xFF)); 339 340 if(state == RADIOLIB_ERR_NONE) { 341 _br = br; 342 } 343 RADIOLIB_ASSERT(state); 344 345 // update clock recovery 346 state = updateClockRecovery(); 347 348 return(state); 349 } 350 351 int16_t Si443x::setFrequencyDeviation(float freqDev) { 352 // set frequency deviation to lowest available setting (required for digimodes) 353 float newFreqDev = freqDev; 354 if(freqDev < 0.0) { 355 newFreqDev = 0.625; 356 } 357 358 RADIOLIB_CHECK_RANGE(newFreqDev, 0.625, 320.0, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); 359 360 // calculate raw frequency deviation value 361 uint16_t fdev = (uint16_t)(newFreqDev / 0.625); 362 363 // update registers 364 int16_t state = _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_2, (uint8_t)((fdev & 0x0100) >> 6), 2, 2); 365 _mod->SPIwriteRegister(RADIOLIB_SI443X_REG_FREQUENCY_DEVIATION, (uint8_t)(fdev & 0xFF)); 366 367 if(state == RADIOLIB_ERR_NONE) { 368 _freqDev = newFreqDev; 369 } 370 371 return(state); 372 } 373 374 int16_t Si443x::setRxBandwidth(float rxBw) { 375 RADIOLIB_CHECK_RANGE(rxBw, 2.6, 620.7, RADIOLIB_ERR_INVALID_RX_BANDWIDTH); 376 377 // decide which approximation to use for decimation rate and filter tap calculation 378 uint8_t bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_OFF; 379 uint8_t decRate = RADIOLIB_SI443X_IF_FILTER_DEC_RATE; 380 uint8_t filterSet = RADIOLIB_SI443X_IF_FILTER_COEFF_SET; 381 382 // this is the "well-behaved" section - can be linearly approximated 383 if((rxBw >= 2.6) && (rxBw <= 4.5)) { 384 decRate = 5; 385 filterSet = ((rxBw - 2.1429)/0.3250 + 0.5); 386 } else if((rxBw > 4.5) && (rxBw <= 8.8)) { 387 decRate = 4; 388 filterSet = ((rxBw - 3.9857)/0.6643 + 0.5); 389 } else if((rxBw > 8.8) && (rxBw <= 17.5)) { 390 decRate = 3; 391 filterSet = ((rxBw - 7.6714)/1.3536 + 0.5); 392 } else if((rxBw > 17.5) && (rxBw <= 34.7)) { 393 decRate = 2; 394 filterSet = ((rxBw - 15.2000)/2.6893 + 0.5); 395 } else if((rxBw > 34.7) && (rxBw <= 69.2)) { 396 decRate = 1; 397 filterSet = ((rxBw - 30.2430)/5.3679 + 0.5); 398 } else if((rxBw > 69.2) && (rxBw <= 137.9)) { 399 decRate = 0; 400 filterSet = ((rxBw - 60.286)/10.7000 + 0.5); 401 402 // this is the "Lord help thee who tread 'ere" section - no way to approximate this mess 403 /// \todo float tolerance equality as macro? 404 } else if(fabs(rxBw - 142.8) <= 0.001) { 405 bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON; 406 decRate = 1; 407 filterSet = 4; 408 } else if(fabs(rxBw - 167.8) <= 0.001) { 409 bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON; 410 decRate = 1; 411 filterSet = 5; 412 } else if(fabs(rxBw - 181.1) <= 0.001) { 413 bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON; 414 decRate = 1; 415 filterSet = 6; 416 } else if(fabs(rxBw - 191.5) <= 0.001) { 417 bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON; 418 decRate = 0; 419 filterSet = 15; 420 } else if(fabs(rxBw - 225.1) <= 0.001) { 421 bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON; 422 decRate = 0; 423 filterSet = 1; 424 } else if(fabs(rxBw - 248.8) <= 0.001) { 425 bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON; 426 decRate = 0; 427 filterSet = 2; 428 } else if(fabs(rxBw - 269.3) <= 0.001) { 429 bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON; 430 decRate = 0; 431 filterSet = 3; 432 } else if(fabs(rxBw - 284.8) <= 0.001) { 433 bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON; 434 decRate = 0; 435 filterSet = 4; 436 } else if(fabs(rxBw -335.5) <= 0.001) { 437 bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON; 438 decRate = 0; 439 filterSet = 8; 440 } else if(fabs(rxBw - 391.8) <= 0.001) { 441 bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON; 442 decRate = 0; 443 filterSet = 9; 444 } else if(fabs(rxBw - 420.2) <= 0.001) { 445 bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON; 446 decRate = 0; 447 filterSet = 10; 448 } else if(fabs(rxBw - 468.4) <= 0.001) { 449 bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON; 450 decRate = 0; 451 filterSet = 11; 452 } else if(fabs(rxBw - 518.8) <= 0.001) { 453 bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON; 454 decRate = 0; 455 filterSet = 12; 456 } else if(fabs(rxBw - 577.0) <= 0.001) { 457 bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON; 458 decRate = 0; 459 filterSet = 13; 460 } else if(fabs(rxBw - 620.7) <= 0.001) { 461 bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON; 462 decRate = 0; 463 filterSet = 14; 464 } else { 465 return(RADIOLIB_ERR_INVALID_RX_BANDWIDTH); 466 } 467 468 // shift decimation rate bits 469 decRate <<= 4; 470 471 // update register 472 int16_t state = _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_IF_FILTER_BANDWIDTH, bypass | decRate | filterSet); 473 RADIOLIB_ASSERT(state); 474 475 // update clock recovery 476 state = updateClockRecovery(); 477 478 return(state); 479 } 480 481 int16_t Si443x::setSyncWord(uint8_t* syncWord, size_t len) { 482 RADIOLIB_CHECK_RANGE(len, 1, 4, RADIOLIB_ERR_INVALID_SYNC_WORD); 483 484 // set mode to standby 485 int16_t state = standby(); 486 RADIOLIB_ASSERT(state); 487 488 // set sync word length 489 state = _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_HEADER_CONTROL_2, (uint8_t)(len - 1) << 1, 2, 1); 490 RADIOLIB_ASSERT(state); 491 492 // set sync word bytes 493 _mod->SPIwriteRegisterBurst(RADIOLIB_SI443X_REG_SYNC_WORD_3, syncWord, len); 494 495 return(state); 496 } 497 498 int16_t Si443x::setPreambleLength(uint8_t preambleLen) { 499 // Si443x configures preamble length in 4-bit nibbles 500 if(preambleLen % 4 != 0) { 501 return(RADIOLIB_ERR_INVALID_PREAMBLE_LENGTH); 502 } 503 504 // set default preamble length 505 uint8_t preLenNibbles = preambleLen / 4; 506 int16_t state = _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_PREAMBLE_LENGTH, preLenNibbles); 507 RADIOLIB_ASSERT(state); 508 509 // set default preamble detection threshold to 5/8 of preamble length (in units of 4 bits) 510 uint8_t preThreshold = 5*preLenNibbles / 8; 511 return(_mod->SPIsetRegValue(RADIOLIB_SI443X_REG_PREAMBLE_DET_CONTROL, preThreshold << 3, 7, 3)); 512 } 513 514 size_t Si443x::getPacketLength(bool update) { 515 if(!_packetLengthQueried && update) { 516 if (_packetLengthConfig == RADIOLIB_SI443X_FIXED_PACKET_LENGTH_ON) { 517 _packetLength = _mod->SPIreadRegister(RADIOLIB_SI443X_REG_TRANSMIT_PACKET_LENGTH); 518 } else { 519 _packetLength = _mod->SPIreadRegister(RADIOLIB_SI443X_REG_RECEIVED_PACKET_LENGTH); 520 } 521 _packetLengthQueried = true; 522 } 523 524 return(_packetLength); 525 } 526 527 int16_t Si443x::setEncoding(uint8_t encoding) { 528 // set mode to standby 529 int16_t state = standby(); 530 RADIOLIB_ASSERT(state); 531 532 // set encoding 533 /// \todo - add inverted Manchester? 534 switch(encoding) { 535 case RADIOLIB_ENCODING_NRZ: 536 return(_mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_1, RADIOLIB_SI443X_MANCHESTER_INVERTED_OFF | RADIOLIB_SI443X_MANCHESTER_OFF | RADIOLIB_SI443X_WHITENING_OFF, 2, 0)); 537 case RADIOLIB_ENCODING_MANCHESTER: 538 return(_mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_1, RADIOLIB_SI443X_MANCHESTER_INVERTED_OFF | RADIOLIB_SI443X_MANCHESTER_ON | RADIOLIB_SI443X_WHITENING_OFF, 2, 0)); 539 case RADIOLIB_ENCODING_WHITENING: 540 return(_mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_1, RADIOLIB_SI443X_MANCHESTER_INVERTED_OFF | RADIOLIB_SI443X_MANCHESTER_OFF | RADIOLIB_SI443X_WHITENING_ON, 2, 0)); 541 default: 542 return(RADIOLIB_ERR_INVALID_ENCODING); 543 } 544 } 545 546 int16_t Si443x::setDataShaping(uint8_t sh) { 547 // set mode to standby 548 int16_t state = standby(); 549 RADIOLIB_ASSERT(state); 550 551 // set data shaping 552 switch(sh) { 553 case RADIOLIB_SHAPING_NONE: 554 return(_mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_1, RADIOLIB_SI443X_MANCHESTER_INVERTED_OFF | RADIOLIB_SI443X_MANCHESTER_OFF | RADIOLIB_SI443X_WHITENING_OFF, 2, 0)); 555 case RADIOLIB_SHAPING_0_3: 556 case RADIOLIB_SHAPING_0_5: 557 case RADIOLIB_SHAPING_1_0: 558 /// \todo implement fiter configuration - docs claim this should be possible, but seems undocumented 559 return(_mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_1, RADIOLIB_SI443X_MANCHESTER_INVERTED_OFF | RADIOLIB_SI443X_MANCHESTER_OFF | RADIOLIB_SI443X_WHITENING_ON, 2, 0)); 560 default: 561 return(RADIOLIB_ERR_INVALID_ENCODING); 562 } 563 } 564 565 void Si443x::setRfSwitchPins(RADIOLIB_PIN_TYPE rxEn, RADIOLIB_PIN_TYPE txEn) { 566 _mod->setRfSwitchPins(rxEn, txEn); 567 } 568 569 uint8_t Si443x::randomByte() { 570 // set mode to Rx 571 _mod->SPIwriteRegister(RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_1, RADIOLIB_SI443X_RX_ON | RADIOLIB_SI443X_XTAL_ON); 572 573 // wait a bit for the RSSI reading to stabilise 574 _mod->delay(10); 575 576 // read RSSI value 8 times, always keep just the least significant bit 577 uint8_t randByte = 0x00; 578 for(uint8_t i = 0; i < 8; i++) { 579 randByte |= ((_mod->SPIreadRegister(RADIOLIB_SI443X_REG_RSSI) & 0x01) << i); 580 } 581 582 // set mode to standby 583 standby(); 584 585 return(randByte); 586 } 587 588 int16_t Si443x::getChipVersion() { 589 return(_mod->SPIgetRegValue(RADIOLIB_SI443X_REG_DEVICE_VERSION)); 590 } 591 592 #if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) 593 void Si443x::setDirectAction(void (*func)(void)) { 594 setIrqAction(func); 595 } 596 597 void Si443x::readBit(RADIOLIB_PIN_TYPE pin) { 598 updateDirectBuffer((uint8_t)digitalRead(pin)); 599 } 600 #endif 601 602 int16_t Si443x::fixedPacketLengthMode(uint8_t len) { 603 return(Si443x::setPacketMode(RADIOLIB_SI443X_FIXED_PACKET_LENGTH_ON, len)); 604 } 605 606 int16_t Si443x::variablePacketLengthMode(uint8_t maxLen) { 607 return(Si443x::setPacketMode(RADIOLIB_SI443X_FIXED_PACKET_LENGTH_OFF, maxLen)); 608 } 609 610 int16_t Si443x::setFrequencyRaw(float newFreq) { 611 // set mode to standby 612 int16_t state = standby(); 613 RADIOLIB_ASSERT(state); 614 615 // check high/low band 616 uint8_t bandSelect = RADIOLIB_SI443X_BAND_SELECT_LOW; 617 uint8_t freqBand = (newFreq / 10) - 24; 618 uint8_t afcLimiter = 80; 619 _freq = newFreq; 620 if(newFreq >= 480.0) { 621 bandSelect = RADIOLIB_SI443X_BAND_SELECT_HIGH; 622 freqBand = (newFreq / 20) - 24; 623 afcLimiter = 40; 624 } 625 626 // calculate register values 627 uint16_t freqCarrier = ((newFreq / (10 * ((bandSelect >> 5) + 1))) - freqBand - 24) * (uint32_t)64000; 628 629 // update registers 630 state = _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_FREQUENCY_BAND_SELECT, bandSelect | freqBand, 5, 0); 631 state |= _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_NOM_CARRIER_FREQUENCY_1, (uint8_t)((freqCarrier & 0xFF00) >> 8)); 632 state |= _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_NOM_CARRIER_FREQUENCY_0, (uint8_t)(freqCarrier & 0xFF)); 633 state |= _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_AFC_LIMITER, afcLimiter); 634 635 return(state); 636 } 637 638 int16_t Si443x::setPacketMode(uint8_t mode, uint8_t len) { 639 // check packet length 640 if (len > RADIOLIB_SI443X_MAX_PACKET_LENGTH) { 641 return(RADIOLIB_ERR_PACKET_TOO_LONG); 642 } 643 644 // set to fixed packet length 645 int16_t state = _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_HEADER_CONTROL_2, mode, 3, 3); 646 RADIOLIB_ASSERT(state); 647 648 // set length to register 649 state = _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_TRANSMIT_PACKET_LENGTH, len); 650 RADIOLIB_ASSERT(state); 651 652 // update cached value 653 _packetLengthConfig = mode; 654 return(state); 655 } 656 657 bool Si443x::findChip() { 658 uint8_t i = 0; 659 bool flagFound = false; 660 while((i < 10) && !flagFound) { 661 // reset the module 662 reset(); 663 664 // check version register 665 uint8_t version = _mod->SPIreadRegister(RADIOLIB_SI443X_REG_DEVICE_VERSION); 666 if(version == RADIOLIB_SI443X_DEVICE_VERSION) { 667 flagFound = true; 668 } else { 669 #if defined(RADIOLIB_DEBUG) 670 RADIOLIB_DEBUG_PRINT(F("Si443x not found! (")); 671 RADIOLIB_DEBUG_PRINT(i + 1); 672 RADIOLIB_DEBUG_PRINT(F(" of 10 tries) RADIOLIB_SI443X_REG_DEVICE_VERSION == ")); 673 674 char buffHex[5]; 675 sprintf(buffHex, "0x%02X", version); 676 RADIOLIB_DEBUG_PRINT(buffHex); 677 RADIOLIB_DEBUG_PRINT(F(", expected 0x00")); 678 RADIOLIB_DEBUG_PRINTLN(RADIOLIB_SI443X_DEVICE_VERSION, HEX); 679 #endif 680 _mod->delay(10); 681 i++; 682 } 683 } 684 685 return(flagFound); 686 } 687 688 void Si443x::clearIRQFlags() { 689 uint8_t buff[2]; 690 _mod->SPIreadRegisterBurst(RADIOLIB_SI443X_REG_INTERRUPT_STATUS_1, 2, buff); 691 } 692 693 void Si443x::clearFIFO(size_t count) { 694 while(count) { 695 _mod->SPIreadRegister(RADIOLIB_SI443X_REG_FIFO_ACCESS); 696 count--; 697 } 698 } 699 700 int16_t Si443x::config() { 701 // set mode to standby 702 int16_t state = standby(); 703 RADIOLIB_ASSERT(state); 704 705 // disable POR and chip ready interrupts 706 _mod->SPIwriteRegister(RADIOLIB_SI443X_REG_INTERRUPT_ENABLE_2, 0x00); 707 708 // enable AGC 709 state = _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_AGC_OVERRIDE_1, RADIOLIB_SI443X_AGC_GAIN_INCREASE_ON | RADIOLIB_SI443X_AGC_ON, 6, 5); 710 RADIOLIB_ASSERT(state); 711 712 // disable packet header 713 state = _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_HEADER_CONTROL_2, RADIOLIB_SI443X_SYNC_WORD_TIMEOUT_OFF | RADIOLIB_SI443X_HEADER_LENGTH_HEADER_NONE, 7, 4); 714 RADIOLIB_ASSERT(state); 715 716 // set antenna switching 717 _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_GPIO0_CONFIG, RADIOLIB_SI443X_GPIOX_TX_STATE_OUT, 4, 0); 718 _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_GPIO1_CONFIG, RADIOLIB_SI443X_GPIOX_RX_STATE_OUT, 4, 0); 719 720 // disable packet header checking 721 state = _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_HEADER_CONTROL_1, RADIOLIB_SI443X_BROADCAST_ADDR_CHECK_NONE | RADIOLIB_SI443X_RECEIVED_HEADER_CHECK_NONE); 722 RADIOLIB_ASSERT(state); 723 724 return(state); 725 } 726 727 int16_t Si443x::updateClockRecovery() { 728 // get the parameters 729 uint8_t bypass = _mod->SPIgetRegValue(RADIOLIB_SI443X_REG_IF_FILTER_BANDWIDTH, 7, 7) >> 7; 730 uint8_t decRate = _mod->SPIgetRegValue(RADIOLIB_SI443X_REG_IF_FILTER_BANDWIDTH, 6, 4) >> 4; 731 uint8_t manch = _mod->SPIgetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_1, 1, 1) >> 1; 732 733 // calculate oversampling ratio, NCO offset and clock recovery gain 734 int8_t ndecExp = (int8_t)decRate - 3; 735 float ndec = 0; 736 if(ndecExp > 0) { 737 ndec = (uint16_t)1 << ndecExp; 738 } else { 739 ndecExp *= -1; 740 ndec = 1.0/(float)((uint16_t)1 << ndecExp); 741 } 742 float rxOsr = ((float)(500 * (1 + 2*bypass))) / (ndec * _br * ((float)(1 + manch))); 743 uint32_t ncoOff = (_br * (1 + manch) * ((uint32_t)(1) << (20 + decRate))) / (500 * (1 + 2*bypass)); 744 uint16_t crGain = 2 + (((float)(65536.0 * (1 + manch)) * _br) / (rxOsr * (_freqDev / 0.625))); 745 uint16_t rxOsr_fixed = (uint16_t)rxOsr; 746 747 // print that whole mess 748 RADIOLIB_DEBUG_PRINTLN(bypass, HEX); 749 RADIOLIB_DEBUG_PRINTLN(decRate, HEX); 750 RADIOLIB_DEBUG_PRINTLN(manch, HEX); 751 RADIOLIB_DEBUG_PRINT(rxOsr, 3); 752 RADIOLIB_DEBUG_PRINT('\t'); 753 RADIOLIB_DEBUG_PRINT(rxOsr_fixed); 754 RADIOLIB_DEBUG_PRINT('\t'); 755 RADIOLIB_DEBUG_PRINTLN(rxOsr_fixed, HEX); 756 RADIOLIB_DEBUG_PRINT(ncoOff); 757 RADIOLIB_DEBUG_PRINT('\t'); 758 RADIOLIB_DEBUG_PRINTLN(ncoOff, HEX); 759 RADIOLIB_DEBUG_PRINT(crGain); 760 RADIOLIB_DEBUG_PRINT('\t'); 761 RADIOLIB_DEBUG_PRINTLN(crGain, HEX); 762 763 // update oversampling ratio 764 int16_t state = _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_CLOCK_REC_OFFSET_2, (uint8_t)((rxOsr_fixed & 0x0700) >> 3), 7, 5); 765 RADIOLIB_ASSERT(state); 766 state = _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_CLOCK_REC_OVERSAMP_RATIO, (uint8_t)(rxOsr_fixed & 0x00FF)); 767 RADIOLIB_ASSERT(state); 768 769 // update NCO offset 770 state = _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_CLOCK_REC_OFFSET_2, (uint8_t)((ncoOff & 0x0F0000) >> 16), 3, 0); 771 RADIOLIB_ASSERT(state); 772 state = _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_CLOCK_REC_OFFSET_1, (uint8_t)((ncoOff & 0x00FF00) >> 8)); 773 RADIOLIB_ASSERT(state); 774 state = _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_CLOCK_REC_OFFSET_0, (uint8_t)(ncoOff & 0x0000FF)); 775 RADIOLIB_ASSERT(state); 776 777 // update clock recovery loop gain 778 state = _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_CLOCK_REC_TIMING_LOOP_GAIN_1, (uint8_t)((crGain & 0x0700) >> 8), 2, 0); 779 RADIOLIB_ASSERT(state); 780 state = _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_CLOCK_REC_TIMING_LOOP_GAIN_0, (uint8_t)(crGain & 0x00FF)); 781 RADIOLIB_ASSERT(state); 782 783 return(state); 784 } 785 786 int16_t Si443x::directMode() { 787 int16_t state = _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_2, RADIOLIB_SI443X_TX_DATA_SOURCE_GPIO, 5, 4); 788 RADIOLIB_ASSERT(state); 789 790 state = _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_GPIO1_CONFIG, RADIOLIB_SI443X_GPIOX_TX_RX_DATA_CLK_OUT, 4, 0); 791 RADIOLIB_ASSERT(state); 792 793 state = _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_GPIO2_CONFIG, RADIOLIB_SI443X_GPIOX_TX_DATA_IN, 4, 0); 794 RADIOLIB_ASSERT(state); 795 796 state = _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_2, RADIOLIB_SI443X_MODULATION_FSK, 1, 0); 797 return(state); 798 } 799 800 #endif