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 |
RTTY.cpp (13412B)
1 #include "RTTY.h" 2 #if !defined(RADIOLIB_EXCLUDE_RTTY) 3 4 ITA2String::ITA2String(char c) { 5 _len = 1; 6 #if !defined(RADIOLIB_STATIC_ONLY) 7 _str = new char[1]; 8 #endif 9 _str[0] = c; 10 _ita2Len = 0; 11 } 12 13 ITA2String::ITA2String(const char* str) { 14 _len = strlen(str); 15 #if !defined(RADIOLIB_STATIC_ONLY) 16 _str = new char[_len + 1]; 17 #endif 18 strcpy(_str, str); 19 _ita2Len = 0; 20 } 21 22 ITA2String::~ITA2String() { 23 #if !defined(RADIOLIB_STATIC_ONLY) 24 delete[] _str; 25 #endif 26 } 27 28 size_t ITA2String::length() { 29 // length returned by this method is different than the length of ASCII-encoded _str 30 // ITA2-encoded string length varies based on how many number and characters the string contains 31 32 if(_ita2Len == 0) { 33 // ITA2 length wasn't calculated yet, call byteArr() to calculate it 34 byteArr(); 35 } 36 37 return(_ita2Len); 38 } 39 40 uint8_t* ITA2String::byteArr() { 41 // create temporary array 2x the string length (figures may be 3 bytes) 42 #if defined(RADIOLIB_STATIC_ONLY) 43 uint8_t temp[RADIOLIB_STATIC_ARRAY_SIZE*2 + 1]; 44 #else 45 uint8_t* temp = new uint8_t[_len*2 + 1]; 46 #endif 47 48 size_t arrayLen = 0; 49 bool flagFigure = false; 50 for(size_t i = 0; i < _len; i++) { 51 uint16_t code = getBits(_str[i]); 52 uint8_t shift = (code >> 5) & 0b11111; 53 uint8_t character = code & 0b11111; 54 // check if the code is letter or figure 55 if(shift == RADIOLIB_ITA2_FIGS) { 56 // check if this is the first figure in sequence 57 if(!flagFigure) { 58 flagFigure = true; 59 temp[arrayLen++] = RADIOLIB_ITA2_FIGS; 60 } 61 62 // add the character code 63 temp[arrayLen++] = character & 0b11111; 64 65 // check the following character (skip for message end) 66 if(i < (_len - 1)) { 67 uint16_t nextCode = getBits(_str[i+1]); 68 uint8_t nextShift = (nextCode >> 5) & 0b11111; 69 if(nextShift == RADIOLIB_ITA2_LTRS) { 70 // next character is a letter, terminate figure shift 71 temp[arrayLen++] = RADIOLIB_ITA2_LTRS; 72 flagFigure = false; 73 } 74 } else { 75 // reached the end of the message, terminate figure shift 76 temp[arrayLen++] = RADIOLIB_ITA2_LTRS; 77 flagFigure = false; 78 } 79 } else { 80 temp[arrayLen++] = character & 0b11111; 81 } 82 } 83 84 // save ITA2 string length 85 _ita2Len = arrayLen; 86 87 uint8_t* arr = new uint8_t[arrayLen]; 88 memcpy(arr, temp, arrayLen); 89 #if !defined(RADIOLIB_STATIC_ONLY) 90 delete[] temp; 91 #endif 92 93 return(arr); 94 } 95 96 uint16_t ITA2String::getBits(char c) { 97 // search ITA2 table 98 uint16_t code = 0x0000; 99 for(uint8_t i = 0; i < RADIOLIB_ITA2_LENGTH; i++) { 100 if(RADIOLIB_NONVOLATILE_READ_BYTE(&ITA2Table[i][0]) == c) { 101 // character is in letter shift 102 code = (RADIOLIB_ITA2_LTRS << 5) | i; 103 break; 104 } else if(RADIOLIB_NONVOLATILE_READ_BYTE(&ITA2Table[i][1]) == c) { 105 // character is in figures shift 106 code = (RADIOLIB_ITA2_FIGS << 5) | i; 107 break; 108 } 109 } 110 111 return(code); 112 } 113 114 RTTYClient::RTTYClient(PhysicalLayer* phy) { 115 _phy = phy; 116 #if !defined(RADIOLIB_EXCLUDE_AFSK) 117 _audio = nullptr; 118 #endif 119 } 120 121 #if !defined(RADIOLIB_EXCLUDE_AFSK) 122 RTTYClient::RTTYClient(AFSKClient* audio) { 123 _phy = audio->_phy; 124 _audio = audio; 125 } 126 #endif 127 128 int16_t RTTYClient::begin(float base, uint32_t shift, uint16_t rate, uint8_t encoding, uint8_t stopBits) { 129 // save configuration 130 _encoding = encoding; 131 _stopBits = stopBits; 132 _baseHz = base; 133 _shiftHz = shift; 134 135 switch(encoding) { 136 case RADIOLIB_ASCII: 137 _dataBits = 7; 138 break; 139 case RADIOLIB_ASCII_EXTENDED: 140 _dataBits = 8; 141 break; 142 case RADIOLIB_ITA2: 143 _dataBits = 5; 144 break; 145 default: 146 return(RADIOLIB_ERR_UNSUPPORTED_ENCODING); 147 } 148 149 // calculate duration of 1 bit 150 _bitDuration = (uint32_t)1000000/rate; 151 152 // calculate module carrier frequency resolution 153 uint32_t step = round(_phy->getFreqStep()); 154 155 // check minimum shift value 156 if(shift < step / 2) { 157 return(RADIOLIB_ERR_INVALID_RTTY_SHIFT); 158 } 159 160 // round shift to multiples of frequency step size 161 if(shift % step < (step / 2)) { 162 _shift = shift / step; 163 } else { 164 _shift = (shift / step) + 1; 165 } 166 167 // calculate 24-bit frequency 168 _base = (base * 1000000.0) / _phy->getFreqStep(); 169 170 // configure for direct mode 171 return(_phy->startDirect()); 172 } 173 174 void RTTYClient::idle() { 175 mark(); 176 } 177 178 size_t RTTYClient::write(const char* str) { 179 if(str == NULL) { 180 return(0); 181 } 182 return(RTTYClient::write((uint8_t *)str, strlen(str))); 183 } 184 185 size_t RTTYClient::write(uint8_t* buff, size_t len) { 186 size_t n = 0; 187 for(size_t i = 0; i < len; i++) { 188 n += RTTYClient::write(buff[i]); 189 } 190 return(n); 191 } 192 193 size_t RTTYClient::write(uint8_t b) { 194 space(); 195 196 uint16_t maxDataMask = 0x01 << (_dataBits - 1); 197 for(uint16_t mask = 0x01; mask <= maxDataMask; mask <<= 1) { 198 if(b & mask) { 199 mark(); 200 } else { 201 space(); 202 } 203 } 204 205 for(uint8_t i = 0; i < _stopBits; i++) { 206 mark(); 207 } 208 209 return(1); 210 } 211 212 size_t RTTYClient::print(__FlashStringHelper* fstr) { 213 // read flash string length 214 size_t len = 0; 215 PGM_P p = reinterpret_cast<PGM_P>(fstr); 216 while(true) { 217 char c = RADIOLIB_NONVOLATILE_READ_BYTE(p++); 218 len++; 219 if(c == '\0') { 220 break; 221 } 222 } 223 224 // dynamically allocate memory 225 #if defined(RADIOLIB_STATIC_ONLY) 226 char str[RADIOLIB_STATIC_ARRAY_SIZE]; 227 #else 228 char* str = new char[len]; 229 #endif 230 231 // copy string from flash 232 p = reinterpret_cast<PGM_P>(fstr); 233 for(size_t i = 0; i < len; i++) { 234 str[i] = RADIOLIB_NONVOLATILE_READ_BYTE(p + i); 235 } 236 237 size_t n = 0; 238 if(_encoding == RADIOLIB_ITA2) { 239 ITA2String ita2 = ITA2String(str); 240 n = RTTYClient::print(ita2); 241 } else if((_encoding == RADIOLIB_ASCII) || (_encoding == RADIOLIB_ASCII_EXTENDED)) { 242 n = RTTYClient::write((uint8_t*)str, len); 243 } 244 #if !defined(RADIOLIB_STATIC_ONLY) 245 delete[] str; 246 #endif 247 return(n); 248 } 249 250 size_t RTTYClient::print(ITA2String& ita2) { 251 uint8_t* arr = ita2.byteArr(); 252 size_t n = RTTYClient::write(arr, ita2.length()); 253 delete[] arr; 254 return(n); 255 } 256 257 size_t RTTYClient::print(const String& str) { 258 size_t n = 0; 259 if(_encoding == RADIOLIB_ITA2) { 260 ITA2String ita2 = ITA2String(str.c_str()); 261 n = RTTYClient::print(ita2); 262 } else if((_encoding == RADIOLIB_ASCII) || (_encoding == RADIOLIB_ASCII_EXTENDED)) { 263 n = RTTYClient::write((uint8_t*)str.c_str(), str.length()); 264 } 265 return(n); 266 } 267 268 size_t RTTYClient::print(const char str[]) { 269 size_t n = 0; 270 if(_encoding == RADIOLIB_ITA2) { 271 ITA2String ita2 = ITA2String(str); 272 n = RTTYClient::print(ita2); 273 } else if((_encoding == RADIOLIB_ASCII) || (_encoding == RADIOLIB_ASCII_EXTENDED)) { 274 n = RTTYClient::write((uint8_t*)str, strlen(str)); 275 } 276 return(n); 277 } 278 279 size_t RTTYClient::print(char c) { 280 size_t n = 0; 281 if(_encoding == RADIOLIB_ITA2) { 282 ITA2String ita2 = ITA2String(c); 283 n = RTTYClient::print(ita2); 284 } else if((_encoding == RADIOLIB_ASCII) || (_encoding == RADIOLIB_ASCII_EXTENDED)) { 285 n = RTTYClient::write(c); 286 } 287 return(n); 288 } 289 290 size_t RTTYClient::print(unsigned char b, int base) { 291 return(RTTYClient::print((unsigned long)b, base)); 292 } 293 294 size_t RTTYClient::print(int n, int base) { 295 return(RTTYClient::print((long)n, base)); 296 } 297 298 size_t RTTYClient::print(unsigned int n, int base) { 299 return(RTTYClient::print((unsigned long)n, base)); 300 } 301 302 size_t RTTYClient::print(long n, int base) { 303 if(base == 0) { 304 return(RTTYClient::write(n)); 305 } else if(base == DEC) { 306 if (n < 0) { 307 int t = RTTYClient::print('-'); 308 n = -n; 309 return(RTTYClient::printNumber(n, DEC) + t); 310 } 311 return(RTTYClient::printNumber(n, DEC)); 312 } else { 313 return(RTTYClient::printNumber(n, base)); 314 } 315 } 316 317 size_t RTTYClient::print(unsigned long n, int base) { 318 if(base == 0) { 319 return(RTTYClient::write(n)); 320 } else { 321 return(RTTYClient::printNumber(n, base)); 322 } 323 } 324 325 size_t RTTYClient::print(double n, int digits) { 326 return(RTTYClient::printFloat(n, digits)); 327 } 328 329 size_t RTTYClient::println(void) { 330 size_t n = 0; 331 if(_encoding == RADIOLIB_ITA2) { 332 ITA2String lf = ITA2String("\r\n"); 333 n = RTTYClient::print(lf); 334 } else if((_encoding == RADIOLIB_ASCII) || (_encoding == RADIOLIB_ASCII_EXTENDED)) { 335 n = RTTYClient::write("\r\n"); 336 } 337 return(n); 338 } 339 340 size_t RTTYClient::println(__FlashStringHelper* fstr) { 341 size_t n = RTTYClient::print(fstr); 342 n += RTTYClient::println(); 343 return(n); 344 } 345 346 size_t RTTYClient::println(ITA2String& ita2) { 347 size_t n = RTTYClient::print(ita2); 348 n += RTTYClient::println(); 349 return(n); 350 } 351 352 size_t RTTYClient::println(const String& str) { 353 size_t n = RTTYClient::print(str); 354 n += RTTYClient::println(); 355 return(n); 356 } 357 358 size_t RTTYClient::println(const char* str) { 359 size_t n = RTTYClient::print(str); 360 n += RTTYClient::println(); 361 return(n); 362 } 363 364 size_t RTTYClient::println(char c) { 365 size_t n = RTTYClient::print(c); 366 n += RTTYClient::println(); 367 return(n); 368 } 369 370 size_t RTTYClient::println(unsigned char b, int base) { 371 size_t n = RTTYClient::print(b, base); 372 n += RTTYClient::println(); 373 return(n); 374 } 375 376 size_t RTTYClient::println(int num, int base) { 377 size_t n = RTTYClient::print(num, base); 378 n += RTTYClient::println(); 379 return(n); 380 } 381 382 size_t RTTYClient::println(unsigned int num, int base) { 383 size_t n = RTTYClient::print(num, base); 384 n += RTTYClient::println(); 385 return(n); 386 } 387 388 size_t RTTYClient::println(long num, int base) { 389 size_t n = RTTYClient::print(num, base); 390 n += RTTYClient::println(); 391 return(n); 392 } 393 394 size_t RTTYClient::println(unsigned long num, int base) { 395 size_t n = RTTYClient::print(num, base); 396 n += RTTYClient::println(); 397 return(n); 398 } 399 400 size_t RTTYClient::println(double d, int digits) { 401 size_t n = RTTYClient::print(d, digits); 402 n += RTTYClient::println(); 403 return(n); 404 } 405 406 void RTTYClient::mark() { 407 Module* mod = _phy->getMod(); 408 uint32_t start = mod->micros(); 409 transmitDirect(_base + _shift, _baseHz + _shiftHz); 410 while(mod->micros() - start < _bitDuration) { 411 mod->yield(); 412 } 413 } 414 415 void RTTYClient::space() { 416 Module* mod = _phy->getMod(); 417 uint32_t start = mod->micros(); 418 transmitDirect(_base, _baseHz); 419 while(mod->micros() - start < _bitDuration) { 420 mod->yield(); 421 } 422 } 423 424 size_t RTTYClient::printNumber(unsigned long n, uint8_t base) { 425 char buf[8 * sizeof(long) + 1]; 426 char *str = &buf[sizeof(buf) - 1]; 427 428 *str = '\0'; 429 430 if(base < 2) { 431 base = 10; 432 } 433 434 do { 435 char c = n % base; 436 n /= base; 437 438 *--str = c < 10 ? c + '0' : c + 'A' - 10; 439 } while(n); 440 441 size_t l = 0; 442 if(_encoding == RADIOLIB_ITA2) { 443 ITA2String ita2 = ITA2String(str); 444 uint8_t* arr = ita2.byteArr(); 445 l = RTTYClient::write(arr, ita2.length()); 446 delete[] arr; 447 } else if((_encoding == RADIOLIB_ASCII) || (_encoding == RADIOLIB_ASCII_EXTENDED)) { 448 l = RTTYClient::write(str); 449 } 450 451 return(l); 452 } 453 454 /// \todo improve ITA2 float print speed (characters are sent one at a time) 455 size_t RTTYClient::printFloat(double number, uint8_t digits) { 456 size_t n = 0; 457 458 char code[] = {0x00, 0x00, 0x00, 0x00}; 459 if (isnan(number)) strcpy(code, "nan"); 460 if (isinf(number)) strcpy(code, "inf"); 461 if (number > 4294967040.0) strcpy(code, "ovf"); // constant determined empirically 462 if (number <-4294967040.0) strcpy(code, "ovf"); // constant determined empirically 463 464 if(code[0] != 0x00) { 465 if(_encoding == RADIOLIB_ITA2) { 466 ITA2String ita2 = ITA2String(code); 467 uint8_t* arr = ita2.byteArr(); 468 n = RTTYClient::write(arr, ita2.length()); 469 delete[] arr; 470 return(n); 471 } else if((_encoding == RADIOLIB_ASCII) || (_encoding == RADIOLIB_ASCII_EXTENDED)) { 472 return(RTTYClient::write(code)); 473 } 474 } 475 476 // Handle negative numbers 477 if (number < 0.0) { 478 if(_encoding == RADIOLIB_ITA2) { 479 ITA2String ita2 = ITA2String("-"); 480 uint8_t* arr = ita2.byteArr(); 481 n += RTTYClient::write(arr, ita2.length()); 482 delete[] arr; 483 } else if((_encoding == RADIOLIB_ASCII) || (_encoding == RADIOLIB_ASCII_EXTENDED)) { 484 n += RTTYClient::print('-'); 485 } 486 number = -number; 487 } 488 489 // Round correctly so that print(1.999, 2) prints as "2.00" 490 double rounding = 0.5; 491 for(uint8_t i = 0; i < digits; ++i) { 492 rounding /= 10.0; 493 } 494 number += rounding; 495 496 // Extract the integer part of the number and print it 497 unsigned long int_part = (unsigned long)number; 498 double remainder = number - (double)int_part; 499 n += RTTYClient::print(int_part); 500 501 // Print the decimal point, but only if there are digits beyond 502 if(digits > 0) { 503 if(_encoding == RADIOLIB_ITA2) { 504 ITA2String ita2 = ITA2String("."); 505 uint8_t* arr = ita2.byteArr(); 506 n += RTTYClient::write(arr, ita2.length()); 507 delete[] arr; 508 } else if((_encoding == RADIOLIB_ASCII) || (_encoding == RADIOLIB_ASCII_EXTENDED)) { 509 n += RTTYClient::print('.'); 510 } 511 } 512 513 // Extract digits from the remainder one at a time 514 while(digits-- > 0) { 515 remainder *= 10.0; 516 unsigned int toPrint = (unsigned int)(remainder); 517 n += RTTYClient::print(toPrint); 518 remainder -= toPrint; 519 } 520 521 return n; 522 } 523 524 int16_t RTTYClient::transmitDirect(uint32_t freq, uint32_t freqHz) { 525 #if !defined(RADIOLIB_EXCLUDE_AFSK) 526 if(_audio != nullptr) { 527 return(_audio->tone(freqHz)); 528 } 529 #endif 530 return(_phy->transmitDirect(freq)); 531 } 532 533 int16_t RTTYClient::standby() { 534 #if !defined(RADIOLIB_EXCLUDE_AFSK) 535 if(_audio != nullptr) { 536 return(_audio->noTone()); 537 } 538 #endif 539 return(_phy->standby()); 540 } 541 542 #endif