forked from herste/Easy-IoT-Arduino-CC1101-LORA
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcc1101.cpp
1746 lines (1319 loc) · 48.9 KB
/
cc1101.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
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#include "cc1101.h"
#include "cc1101_esp_pin_config.h"
// Do we want the inbuild led to flash when we send or recieve? Useful for diagnostics.
// Comment the below line out to turn this off.
#define ENABLE_BUILTIN_LED 1
/**
Macros
*/
// Select (SPI) CC1101
#define cc1101_Select() digitalWrite(SS, LOW)
// Deselect (SPI) CC1101
#define cc1101_Deselect() digitalWrite(SS, HIGH)
// Wait until SPI MISO line goes low
#define wait_Miso() while(digitalRead(MISO)>0)
// Get GDO0 pin state
#define getGDO0state() digitalRead(CC1101_GDO0)
// Wait until GDO0 line goes high
#define wait_GDO0_high() while(!getGDO0state())
// Wait until GDO0 line goes low
#define wait_GDO0_low() while(getGDO0state())
/**
CC1101
Class constructor
*/
CC1101::CC1101(void)
{
carrierFreq = CFREQ_868;
channel = CC1101_DEFVAL_CHANNR;
devAddress = CC1101_DEFVAL_ADDR;
syncWord[0] = CC1101_DEFVAL_SYNC1;
syncWord[1] = CC1101_DEFVAL_SYNC0;
// for the fifo
memset(cc1101_rx_tx_fifo_buff, 0x00, sizeof(cc1101_rx_tx_fifo_buff)); // flush
// for longer than one packet messages
memset(stream_multi_pkt_buffer, 0x00, sizeof(stream_multi_pkt_buffer)); // flush
// State of CC as told by the CC from the returned status byte from each SPI write transfer
currentState = STATE_UNKNOWN;
last_CCState_check = millis();
}
/* Configure the ESP's GPIO etc */
void CC1101::configureGPIO(void)
{
#ifdef ESP32
pinMode(SS, OUTPUT); // Make sure that the SS Pin is declared as an Output
#endif
// SPI.setFrequency(1000000);
SPI.begin(); // Initialize SPI interface
pinMode(CC1101_GDO0, INPUT); // Config GDO0 as input
#ifdef ENABLE_BUILTIN_LED
pinMode(LED_BUILTIN, OUTPUT); // Led will flash on recieve and send of packet
#endif
if (serialDebug) {
Serial.print(F("Using ESP Pin "));
Serial.print(CC1101_GDO0);
Serial.println(F(" for CC1101 GDO0 / GDO2."));
}
}
/**
begin
Initialize CC1101 radio
@param freq Carrier frequency
@param mode Working mode (speed, ...)
*/
bool CC1101::begin(CFREQ freq, DATA_RATE rate, uint8_t channr, uint8_t addr)
{
carrierFreq = freq;
dataRate = rate;
channel = channr;
devAddress = addr;
configureGPIO();
hardReset(); // Reset CC1101
delay(100);
setCCregs();
attachGDO0Interrupt();
return checkCC();
}
/* Begin function when we're given all the 47 configuration registers in one hit */
bool CC1101::begin(const byte regConfig[NUM_CONFIG_REGISTERS])
{
configureGPIO();
hardReset(); // Reset CC1101
delay(100);
// Go through the array and set
for (uint8_t i = 0; i < NUM_CONFIG_REGISTERS-6; i++)
{
writeReg(i, pgm_read_byte(regConfig + i));
//writeReg(i, regConfig[i]);
_NOP(); _NOP(); _NOP(); _NOP();
}
attachGDO0Interrupt();
return checkCC();
}
/* Check the health of the CC. i.e. The partnum response is OK */
bool CC1101::checkCC(void)
{
// Do a check of the partnum
uint8_t version = readReg(CC1101_VERSION, CC1101_STATUS_REGISTER);
if (version != 20)
{
detachGDO0Interrupt();
setPowerDownState();
// Close the SPI connection
SPI.end();
// ALERT
#ifdef ENABLE_BUILTIN_LED
digitalWrite(LED_BUILTIN, LOW);
#endif
Serial.println(F("CC1101 not detected!"));
return false;
/*
bool led_state = 0;
while (1)
{
Serial.println(F("CC1101 not detected!"));
delay(1000);
digitalWrite(LED_BUILTIN, led_state ^= 1);
}
*/
}
return true;
} // check CC
/* Attach the interrupt from CC1101 when packet recieved */
void CC1101::attachGDO0Interrupt(void)
{
if (serialDebug)
Serial.println(F("Attaching Interrupt to GDO0"));
attachInterrupt(CC1101_GDO0, interupt_packetReceived, FALLING);
}
void CC1101::detachGDO0Interrupt(void)
{
if (serialDebug)
Serial.println(F("Detaching Interrupt to GDO0"));
detachInterrupt(CC1101_GDO0);
}
/**
wakeUp
Wake up CC1101 from Power Down state
*/
void CC1101::wakeUp(void)
{
cc1101_Select(); // Select CC1101
wait_Miso(); // Wait until MISO goes low
cc1101_Deselect(); // Deselect CC1101
}
/**
writeReg
Write single register into the CC1101 IC via SPI
'regAddr' Register address
'value' Value to be writen
*/
void CC1101::writeReg(byte regAddr, byte value)
{
byte status;
_NOP(); _NOP(); _NOP(); _NOP(); _NOP(); _NOP(); _NOP(); _NOP(); _NOP(); // HACK2
// Print extra info when we're writing to CC register
if (regAddr <= CC1101_TEST0) // for some reason when this is disable config writes don't work!!
{
char reg_name[16] = {0};
strcpy_P(reg_name, CC1101_CONFIG_REGISTER_NAME[regAddr]);
Serial.print(F("Writing to CC1101 reg "));
Serial.print(reg_name);
Serial.print(F(" ["));
Serial.print(regAddr, HEX);
Serial.print(F("] "));
Serial.print(F("value (HEX):\t"));
Serial.println(value, HEX);
// Serial.print(F(" value (DEC) "));
// Serial.println(value, DEC);
// Store the configuration state we requested the CC1101 to be
currentConfig[regAddr] = value;
}
cc1101_Select(); // Select CC1101
wait_Miso(); // Wait until MISO goes low
readCCStatus(SPI.transfer(regAddr)); // Send register address
//delayMicroseconds(1); // HACK
_NOP(); _NOP(); _NOP(); _NOP(); _NOP(); _NOP(); _NOP(); _NOP(); _NOP(); // HACK2
readCCStatus(SPI.transfer(value)); // Send value
cc1101_Deselect(); // Deselect CC1101
delay(1);
}
/**
cmdStrobe
Send command strobe to the CC1101 IC via SPI
'cmd' Command strobe
*/
void CC1101::cmdStrobe(byte cmd)
{
if (serialDebug)
{
Serial.print(F("Sending strobe: "));
switch (cmd)
{
case 0x30: Serial.println(F("CC1101_SRES ")); break;
case 0x31: Serial.println(F("CC1101_SFSTXON ")); break;
case 0x32: Serial.println(F("CC1101_SXOFF ")); break;
case 0x33: Serial.println(F("CC1101_SCAL ")); break;
case 0x34: Serial.println(F("CC1101_SRX ")); break;
case 0x35: Serial.println(F("CC1101_STX ")); break;
case 0x36: Serial.println(F("CC1101_SIDLE ")); break;
case 0x38: Serial.println(F("CC1101_SWOR ")); break;
case 0x39: Serial.println(F("CC1101_SPWD ")); break;
case 0x3A: Serial.println(F("CC1101_SFRX ")); break;
case 0x3B: Serial.println(F("CC1101_SFTX ")); break;
case 0x3C: Serial.println(F("CC1101_SWORRST ")); break;
case 0x3D: Serial.println(F("CC1101_SNOP ")); break;
}
}
cc1101_Select(); // Select CC1101
wait_Miso(); // Wait until MISO goes low
readCCStatus(SPI.transfer(cmd)); // Send strobe command
cc1101_Deselect(); // Deselect CC1101
}
/**
readReg
Read CC1101 register via SPI
'regAddr' Register address
'regType' Type of register: CC1101_CONFIG_REGISTER or CC1101_STATUS_REGISTER
Return:
Data byte returned by the CC1101 IC
*/
byte CC1101::readReg(byte regAddr, byte regType)
{
byte addr, val;
addr = regAddr | regType;
cc1101_Select(); // Select CC1101
wait_Miso(); // Wait until MISO goes low
SPI.transfer(addr); // Send register address
//delayMicroseconds(1); // HACK
_NOP(); _NOP(); _NOP(); _NOP();_NOP(); _NOP(); _NOP(); _NOP();_NOP(); _NOP(); _NOP(); _NOP();_NOP(); _NOP(); _NOP(); _NOP(); // HACK2
val = SPI.transfer(0x00); // Read result
cc1101_Deselect(); // Deselect CC1101
return val;
}
/**
*
* readStatusRegSafe(uint8_t regAddr)
* CC1101 bug with SPI and return values of Status Registers
* https://e2e.ti.com/support/wireless-connectivity/sub-1-ghz/f/156/t/570498?CC1101-stuck-waiting-for-CC1101-to-bring-GDO0-low-with-IOCFG0-0x06-why-#
* as per: http://e2e.ti.com/support/wireless-connectivity/other-wireless/f/667/t/334528?CC1101-Random-RX-FIFO-Overflow
*
*/
byte CC1101::readStatusRegSafe(uint8_t regAddr)
{
byte statusRegByte, statusRegByteVerify;
statusRegByte = readReg(regAddr, CC1101_STATUS_REGISTER);
do
{
statusRegByte = statusRegByteVerify;
statusRegByteVerify = readReg(regAddr, CC1101_STATUS_REGISTER);
yield();
}
while(statusRegByte != statusRegByteVerify);
return statusRegByte;
}
/**
hard reset after power on
Ref: http://e2e.ti.com/support/wireless-connectivity/other-wireless/f/667/t/396609
Reset CC1101
*/
void CC1101::hardReset(void)
{
cc1101_Deselect(); // Deselect CC1101
delayMicroseconds(5);
cc1101_Select(); // Select CC1101
delayMicroseconds(10);
cc1101_Deselect(); // Deselect CC1101
delayMicroseconds(41);
cc1101_Select(); // Select CC1101
softReset();
}
/**
soft reset
Reset CC1101
*/
void CC1101::softReset(void)
{
cc1101_Select(); // Select CC1101
wait_Miso(); // Wait until MISO goes low
SPI.transfer(CC1101_SRES); // Send reset command strobe
wait_Miso(); // Wait until MISO goes low
cc1101_Deselect(); // Deselect CC1101
//setCCregs(); // Reconfigure CC1101
}
/**
setCCregs
Configure CC1101 Configuration Registers
*/
void CC1101::setCCregs(void)
{
if (serialDebug)
Serial.println(F("Setting CC Configuration Registers..."));
/* NOTE: Any Configuration registers written here are done so
* because they aren't changed in any of the subroutines.
* i.e. They're the same regardless of channel, frequency, etc.
*/
writeReg(CC1101_IOCFG2, CC1101_DEFVAL_IOCFG2);
writeReg(CC1101_IOCFG1, CC1101_DEFVAL_IOCFG1);
writeReg(CC1101_IOCFG0, CC1101_DEFVAL_IOCFG0);
writeReg(CC1101_FIFOTHR, CC1101_DEFVAL_FIFOTHR);
writeReg(CC1101_PKTLEN, CC1101_DEFVAL_PKTLEN);
writeReg(CC1101_PKTCTRL1, CC1101_DEFVAL_PKTCTRL1);
writeReg(CC1101_PKTCTRL0, CC1101_DEFVAL_PKTCTRL0);
// Set default synchronization word
setSyncWord(syncWord);
// Set default device address
setDevAddress(devAddress);
// Set default frequency channel
setChannel(channel);
// Modem freq. control stuff
//writeReg(CC1101_FSCTRL1, CC1101_DEFVAL_FSCTRL1);
writeReg(CC1101_FSCTRL0, CC1101_DEFVAL_FSCTRL0);
// Set default carrier frequency = 868 MHz
setCarrierFreq(carrierFreq);
// Modem, behaviour
writeReg(CC1101_MCSM2, CC1101_DEFVAL_MCSM2);
writeReg(CC1101_MCSM1, CC1101_DEFVAL_MCSM1);
writeReg(CC1101_MCSM0, CC1101_DEFVAL_MCSM0);
// Stuff that's most certainly going to get overwritten by dataRate specific stuff.
//writeReg(CC1101_MDMCFG3, CC1101_DEFVAL_MDMCFG3);
writeReg(CC1101_MDMCFG2, CC1101_DEFVAL_MDMCFG2);
writeReg(CC1101_MDMCFG1, CC1101_DEFVAL_MDMCFG1);
writeReg(CC1101_MDMCFG0, CC1101_DEFVAL_MDMCFG0);
//writeReg(CC1101_DEVIATN, CC1101_DEFVAL_DEVIATN);
//writeReg(CC1101_FOCCFG, CC1101_DEFVAL_FOCCFG);
writeReg(CC1101_BSCFG, CC1101_DEFVAL_BSCFG);
writeReg(CC1101_AGCCTRL2, CC1101_DEFVAL_AGCCTRL2);
writeReg(CC1101_AGCCTRL1, CC1101_DEFVAL_AGCCTRL1);
writeReg(CC1101_AGCCTRL0, CC1101_DEFVAL_AGCCTRL0);
writeReg(CC1101_FREND1, CC1101_DEFVAL_FREND1);
writeReg(CC1101_FREND0, CC1101_DEFVAL_FREND0);
// Data Rate - details extracted from SmartRF Studio
switch (dataRate)
{
case KBPS_250:
if (serialDebug)
Serial.print(F("250kbps data rate"));
writeReg(CC1101_FSCTRL1, 0x0C); // Frequency Synthesizer Control (optimised for sensitivity)
writeReg(CC1101_MDMCFG4, 0x2D); // Modem Configuration
writeReg(CC1101_MDMCFG3, 0x3B); // Modem Configuration
//writeReg(CC1101_MDMCFG2, 0x93); // Modem Configuration
writeReg(CC1101_DEVIATN, 0x62); // Modem Deviation Setting
writeReg(CC1101_FOCCFG, 0x1D); // Frequency Offset Compensation Configuration
writeReg(CC1101_BSCFG, 0x1C); // Bit Synchronization Configuration
writeReg(CC1101_AGCCTRL2, 0xC7); // AGC Control
writeReg(CC1101_AGCCTRL1, 0x00); // AGC Control
writeReg(CC1101_AGCCTRL0, 0xB0); // AGC Control
writeReg(CC1101_FREND1, 0xB6); // Front End RX Configuration
break;
case KBPS_38:
if (serialDebug)
Serial.print(F("38kbps data rate"));
writeReg(CC1101_FSCTRL1, 0x06); // Frequency Synthesizer Control
writeReg(CC1101_MDMCFG4, 0xCA); // Modem Configuration
writeReg(CC1101_MDMCFG3, 0x83); // Modem Configuration
//writeReg(CC1101_MDMCFG2, 0x93); // Modem Configuration
writeReg(CC1101_DEVIATN, 0x35); // Modem Deviation Setting
writeReg(CC1101_FOCCFG, 0x16); // Frequency Offset Compensation Configuration
writeReg(CC1101_AGCCTRL2, 0x43); // AGC Control
break;
case KBPS_4:
if (serialDebug)
Serial.print(F("4kbps data rate"));
writeReg(CC1101_FSCTRL1, 0x06); // Frequency Synthesizer Control
writeReg(CC1101_MDMCFG4, 0xC7); // Modem Configuration
writeReg(CC1101_MDMCFG3, 0x83); // Modem Configuration
//writeReg(CC1101_MDMCFG2, 0x93); // Modem Configuration
writeReg(CC1101_DEVIATN, 0x40); // Modem Deviation Setting
writeReg(CC1101_FOCCFG, 0x16); // Frequency Offset Compensation Configuration
writeReg(CC1101_AGCCTRL2, 0x43); // AGC Control
break;
}
// Other defaults
writeReg(CC1101_WOREVT1, CC1101_DEFVAL_WOREVT1);
writeReg(CC1101_WOREVT0, CC1101_DEFVAL_WOREVT0);
writeReg(CC1101_WORCTRL, CC1101_DEFVAL_WORCTRL);
writeReg(CC1101_FSCAL3, CC1101_DEFVAL_FSCAL3);
writeReg(CC1101_FSCAL2, CC1101_DEFVAL_FSCAL2);
writeReg(CC1101_FSCAL1, CC1101_DEFVAL_FSCAL1);
writeReg(CC1101_FSCAL0, CC1101_DEFVAL_FSCAL0);
writeReg(CC1101_RCCTRL1, CC1101_DEFVAL_RCCTRL1);
writeReg(CC1101_RCCTRL0, CC1101_DEFVAL_RCCTRL0);
//writeReg(CC1101_FSTEST, CC1101_DEFVAL_FSTEST);
//writeReg(CC1101_PTEST, CC1101_DEFVAL_PTEST);
//writeReg(CC1101_AGCTEST, CC1101_DEFVAL_AGCTEST);
//writeReg(CC1101_TEST2, CC1101_DEFVAL_TEST2);
//writeReg(CC1101_TEST1, CC1101_DEFVAL_TEST1);
//writeReg(CC1101_TEST0, CC1101_DEFVAL_TEST0);
// Send empty packet (which won't actually send a packet, but will flush the Rx FIFO only.)
CCPACKET packet;
packet.payload_size = 0;
sendPacket(packet);
}
/**
setSyncWord
Set synchronization word
'syncH' Synchronization word - High byte
'syncL' Synchronization word - Low byte
*/
void CC1101::setSyncWord(uint8_t syncH, uint8_t syncL)
{
writeReg(CC1101_SYNC1, syncH);
writeReg(CC1101_SYNC0, syncL);
syncWord[0] = syncH;
syncWord[1] = syncL;
}
/**
setSyncWord (overriding method)
Set synchronization word
'syncH' Synchronization word - pointer to 2-byte array
*/
void CC1101::setSyncWord(byte *sync)
{
CC1101::setSyncWord(sync[0], sync[1]);
}
/**
setDevAddress
Set device address
@param addr Device address
*/
void CC1101::setDevAddress(byte addr)
{
writeReg(CC1101_ADDR, addr);
devAddress = addr;
}
/**
setChannel
Set frequency channel
'chnl' Frequency channel
*/
void CC1101::setChannel(byte chnl)
{
writeReg(CC1101_CHANNR, chnl);
channel = chnl;
}
/**
setCarrierFreq
Set carrier frequency
'freq' New carrier frequency
*/
void CC1101::setCarrierFreq(CFREQ freq)
{
switch (freq)
{
case CFREQ_922:
if (serialDebug)
Serial.print(F("922Mhz frequency (Canada, US, Australia)"));
writeReg(CC1101_FREQ2, CC1101_DEFVAL_FREQ2_922);
writeReg(CC1101_FREQ1, CC1101_DEFVAL_FREQ1_922);
writeReg(CC1101_FREQ0, CC1101_DEFVAL_FREQ0_922);
break;
case CFREQ_433:
if (serialDebug)
Serial.print(F("433Mhz frequency"));
writeReg(CC1101_FREQ2, CC1101_DEFVAL_FREQ2_433);
writeReg(CC1101_FREQ1, CC1101_DEFVAL_FREQ1_433);
writeReg(CC1101_FREQ0, CC1101_DEFVAL_FREQ0_433);
break;
default:
if (serialDebug)
Serial.print(F("868Mhz frequency (Europe)"));
writeReg(CC1101_FREQ2, CC1101_DEFVAL_FREQ2_868);
writeReg(CC1101_FREQ1, CC1101_DEFVAL_FREQ1_868);
writeReg(CC1101_FREQ0, CC1101_DEFVAL_FREQ0_868);
break;
}
carrierFreq = freq;
}
/**
setPowerDownState
Put CC1101 into power-down state
*/
void CC1101::setPowerDownState()
{
// Comming from RX state, we need to enter the IDLE state first
cmdStrobe(CC1101_SIDLE);
// Enter Power-down state
cmdStrobe(CC1101_SPWD);
}
/**
sendChars
send a stream of characters, could be greater than one CC1101 underlying ~60 byte packet,
if so, split it up and do what is required.
*/
bool CC1101::sendChars(const char * data, uint8_t cc_dest_address)
{
uint16_t stream_length = strlen(data) + 1; // We also need to include the 0 byte at the end of the string
return sendBytes( (byte *) data, stream_length, cc_dest_address);
}
/**
sendBytes
send a stream of BYTES (unsigned chars), could be greater than one CC1101 underlying packet,
payload limit (STREAM_PKT_MAX_PAYLOAD_SIZE) if so, split it up and do what is required.
*/
bool CC1101::sendBytes(byte * data, uint16_t stream_length, uint8_t cc_dest_address)
{
unsigned long start_tm; start_tm = millis();
bool sendStatus = false;
/*
Serial.println("");
// HACK: REMOVE - FOR VALIDATION TESTING ONLY
Serial.println("");
Serial.print(F("HEX content of data to send:"));
for (int i = 0; i < stream_length; i++)
{
Serial.printf("%02x", data[i]);
}
Serial.println("");
Serial.print(F("CHAR content of data to send:"));
for (int i = 0; i < stream_length; i++)
{
Serial.printf("%c", data[i]);
}
Serial.println("");
*/
detachGDO0Interrupt(); // we don't want to get interrupted at this important moment in history
CCPACKET packet; // create a packet
uint16_t unsent_stream_bytes = stream_length;
if (stream_length > MAX_STREAM_LENGTH) // from ccpacket.h
{
Serial.println(F("Too many bytes to send!"));
return false;
}
Serial.print(F("Sending byte stream of ")); Serial.print(stream_length, DEC); Serial.println(F(" bytes in length."));
uint8_t stream_pkt_seq_num = 1;
uint8_t stream_num_of_pkts = 0; // we have to send at least one!
// calculate number of packets this stream will have
for (int i = 0; i < stream_length; i = i + STREAM_PKT_MAX_PAYLOAD_SIZE)
stream_num_of_pkts++;
while (unsent_stream_bytes > 0)
{
// can't use sizeof
//https://stackoverflow.com/questions/6081842/sizeof-is-not-executed-by-preprocessor
uint8_t payload_size = MIN(STREAM_PKT_MAX_PAYLOAD_SIZE, unsent_stream_bytes);
packet.payload_size = payload_size; // CCPACKET_OVERHEAD_STREAM added in sendPacket
packet.cc_dest_address = cc_dest_address; // probably going to broadcast this most of the time (0x00, or 0xFF)
packet.stream_num_of_pkts = stream_num_of_pkts;
packet.stream_pkt_seq_num = stream_pkt_seq_num++;
// make sure we flush the contents of the packet (otherwise we might append crap from the previous packet in the stream
// if this packet is smaller (i.e. the last packet).
// Not a big issue though as the receiver should only read up until payload_size)
memset(packet.payload, 0x00, sizeof(packet.payload));
uint16_t start_pos = stream_length - unsent_stream_bytes; // (stream_length == unsent_stream_bytes) ? 0:(stream_length-1-unsent_stream_bytes); // because array positions are x-1
//Serial.printf("Packet Start Pos: %d\n", start_pos);
memcpy( (byte *)packet.payload, &data[start_pos], payload_size); // cast as char
/*
// HACK: REMOVE - FOR VALIDATION TESTING ONLY
Serial.println("");
Serial.print("HEX content of packet to send:");
for (uint8_t i = 0; i < packet.payload_size; i++)
{
Serial.printf("%02x", packet.payload[i]);
}
Serial.println("");
*/
// Try and send the packet stream.
uint8_t tries = 0;
// Check that the RX state has been entered
while (tries++ < 3 && ((sendStatus = sendPacket(packet)) != true) )
{
Serial.println(F("Failed to send byte packet. Retrying. "));
delay(99); // random delay interval
}
if ( !sendStatus )
{
Serial.println(F("Failed to send byte stream. Existing."));
break; // Get out of this
}
unsent_stream_bytes -= payload_size;
if (serialDebug)
Serial.printf("%d bytes remain unsent.\n", unsent_stream_bytes);
} // end stream loop
attachGDO0Interrupt();
Serial.printf("Took %d milliseconds to complete sendBytes()\n", (millis() - start_tm));
return sendStatus;
}
/**
sendPacket
Send data packet via RF
'packet' Packet to be transmitted. First byte is the destination address
Return:
True if the transmission succeeds
False otherwise
*/
bool CC1101::sendPacket(CCPACKET packet)
{
byte marcState;
byte txBytes, txOverflow;
bool res = false;
#ifdef ENABLE_BUILTIN_LED
digitalWrite(LED_BUILTIN, LOW);
#endif
/**
* STEP 0: Build the radio packet of stuff to send
*/
// Flush the RX/TX Buffer
memset(cc1101_rx_tx_fifo_buff, 0x00, sizeof(cc1101_rx_tx_fifo_buff));
// Set dest device address as first position of TX FIFO
//writeReg(CC1101_TXFIFO, packet.cc_dest_address); // byte 1
cc1101_rx_tx_fifo_buff[0] = packet.cc_dest_address;
// Set payload size as the second position of the TX FIFO
//writeReg(CC1101_TXFIFO, packet.payload_size); // byte 2
cc1101_rx_tx_fifo_buff[1] = packet.payload_size;
// Stream stuff
//writeReg(CC1101_TXFIFO, packet.stream_num_of_pkts); // byte 3
//writeReg(CC1101_TXFIFO, packet.stream_pkt_seq_num); // byte 4
cc1101_rx_tx_fifo_buff[2] = packet.stream_num_of_pkts;
cc1101_rx_tx_fifo_buff[3] = packet.stream_pkt_seq_num;
// Copy the payload
memcpy( &cc1101_rx_tx_fifo_buff[4], packet.payload, packet.payload_size);
/*
Serial.print("Payload Data: ");
for (int i = 0; i < packet.payload_size; i++)
{
Serial.print(packet.payload[i], HEX);
Serial.print(", ");
}
Serial.println("");
*/
/**
* STEP 1: Check that the marcState of the CC1101 is RX, and that none of the buffers have
* overflowed.
*/
// Enter RX state (we might recieve a packet whilst getting ready to TX)
setRxState();
int tries = 0;
// Check that the RX state has been entered
while (tries++ < 1000 && ((marcState = readStatusReg(CC1101_MARCSTATE)) & 0x1F) != MARCSTATE_RX)
{
if (marcState == MARCSTATE_RXFIFO_OVERFLOW) // RX_OVERFLOW
flushRxFifo(); // flush receive queue
if (marcState == MARCSTATE_TXFIFO_UNDERFLOW) // TX_UNDERFLOW
flushTxFifo(); // flush send queue
/* Page 31, Table 23.
110 RXFIFO_OVERFLOW RX FIFO has overflowed. Read out any useful data, then flush the FIFO with SFRX
111 TXFIFO_UNDERFLOW TX FIFO has underflowed. Acknowledge with SFTX
*/
}
if (tries >= 100)
{
// TODO: MarcState sometimes never enters the expected state; this is a hack workaround.
return false;
}
/*
* Step 2: Check to see if stuff is already in the TX FIFO. If so. Flush it.
*/
txBytes = readStatusRegSafe(CC1101_TXBYTES); // Any left over bytes in the TX FIFO?
// Repurpose these variables
txBytes = txBytes & BYTES_IN_FIFO;
txOverflow = txBytes & OVERFLOW_IN_FIFO;
//Serial.print("TX FIFO bytes already in FIFO (should be zero): ");
//Serial.println(txBytes, DEC);
if (txBytes != 0) // only do this stuff if it's empty already
{
if (serialDebug)
Serial.println(F("TX FIFO is in overflow or contains garbage. Flushing. "));
setIdleState(); // Enter IDLE state
flushTxFifo(); // Flush Tx FIFO
setRxState(); // Back to RX state
return false;
}
/**
* STEP 3: Send the radio packet.
*/
/*
15.4 Packet Handling in Transmit Mode
The payload that is to be transmitted must be
written into the TX FIFO. The first byte written
must be the length byte when variable packet
length is enabled. The length byte has a value
equal to the payload of the packet (including
the optional address byte). If address
recognition is enabled on the receiver, the
second byte written to the TX FIFO must be
the address byte.
If fixed packet length is enabled, the first byte
written to the TX FIFO should be the address
(assuming the receiver uses address
recognition).
*/
/* ISSUE: writeBurstReg doesn't work properly on ESP8266, or perhaps
other microcontrollers... perhaps they are too fast for the CC1101
given it's a 10+ year old chip.
Sending each byte individually works without issue however.
https://e2e.ti.com/support/wireless-connectivity/sub-1-ghz/f/156/t/554535
https://e2e.ti.com/support/microcontrollers/other/f/908/t/217117
*/
// writeBurstReg(CC1101_TXFIFO, packet.data, packet.length);
// Send the contents of th RX/TX buffer to the CC1101, one byte at a time
// the receiving CC1101 will append two bytes for the LQI and RSSI
for (int i = 0; i< CCPACKET_MAX_SIZE; i++)
writeReg(CC1101_TXFIFO, cc1101_rx_tx_fifo_buff[i]);
/*
for (uint8_t len = 0 ; len < packet.payload_size; len++)
writeReg(CC1101_TXFIFO, packet.payload[len]);
// We're using fixed packet size, so need to fill with null until end
for (uint8_t len = packet.payload_size ; len < STREAM_PKT_MAX_PAYLOAD_SIZE; len++)
writeReg(CC1101_TXFIFO, 0x00);
*/
// I assume the CC1101 sends the two extra CRC bytes here somewhere.
if (serialDebug)
{
Serial.print(F("Number of bytes to send: "));
Serial.println(readStatusReg(CC1101_TXBYTES) & 0x7F, DEC);
}
// CCA enabled: will enter TX state only if the channel is clear
setTxState();
// Check that TX state is being entered (state = RXTX_SETTLING)
marcState = readStatusReg(CC1101_MARCSTATE) & 0x1F;
if ((marcState != MARCSTATE_TX) && (marcState != MARCSTATE_TX_END) && (marcState != MARCSTATE_RXTX_SWITCH))
{
//Serial.println("Error: TX Mode was NOT entered");
//Serial.println(marcState, HEX);
setIdleState(); // Enter IDLE state
flushTxFifo(); // Flush Tx FIFO
setRxState(); // Back to RX state
return false;
}
if (currentConfig[CC1101_IOCFG0] == 0x06) //if sync word detect mode is used
{
// Wait for the sync word to be transmitted
wait_GDO0_high();
// Wait until the end of the packet transmission
wait_GDO0_low();
}
// Check that the TX FIFO is empty
if ((readStatusReg(CC1101_TXBYTES) & 0x7F) == 0)
res = true;
setIdleState(); // Enter IDLE state
flushTxFifo(); // Flush Tx FIFO
// Enter back into RX state
setRxState();
#ifdef ENABLE_BUILTIN_LED
digitalWrite(LED_BUILTIN, HIGH);
#endif
return res;
}
/**
dataAvailable
Check the status of the packetReceived and do some processing
to reconstruct the multi-packet 'stream' if required.
There is no state machine here so if multiple packets come from
different sources at once for multiple multi-packet streams,
things will break and/or get corrupted very easily.
*/
bool CC1101::dataAvailable(void)
{
// Any packets?
if (!packetReceived) return false; // just to get that out of the way.
bool _streamReceived = false;
Serial.println(F("---------- START: RX Interrupt Request -------------"));
// We got something
detachGDO0Interrupt(); // we don't want to get interrupted at this important moment in history
packetReceived = false;
CCPACKET packet;