-
Notifications
You must be signed in to change notification settings - Fork 1
/
tricorder_sense.ino
2661 lines (2357 loc) · 102 KB
/
tricorder_sense.ino
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 <Adafruit_NeoPixel.h>
#include <SPI.h>
#include <Adafruit_GFX.h> // Core graphics library
#include <Adafruit_ST7789.h> // Hardware-specific library for ST7789
#include <string.h>
#include <Adafruit_APDS9960.h> //RGB, light, proximity, gesture sensor
#include <Wire.h>
#include <EasyButton.h>
#include <Adafruit_BMP280.h> //altitude, barometer
#include <Adafruit_SHT31.h> //temp, humidity
#include <Adafruit_Sensor.h> //wtf is this??
#include <PDM.h>
#include <Adafruit_ZeroFFT.h>
#include <MLX90640_API.h>
#include <MLX90640_I2C_Driver.h>
#include <Adafruit_LIS3MDL.h> //magnetometer, for door close detection
#include <Adafruit_LSM6DS33.h>
//full arduino pinout for this board is here:
/*https://github.com/adafruit/Adafruit_nRF52_Arduino/blob/master/variants/feather_nrf52840_sense/variant.h*/
// need to remove hyphens from header filenames or exception will get thrown
#include "Fonts/lcars15pt7b.h"
#include "Fonts/lcars11pt7b.h"
// For the breakout board, you can use any 2 or 3 pins.
// These pins will also work for the 1.8" TFT shield.
//need to use pin 6 for TFT_CS, as pin 20 is analog 7. analog 7 is the only way to get current voltage, which is used for battery %
//MISO is not required for screen to work - this is used by mem card only?
#define TFT_CS (6)
// SD card select pin
//#define SD_CS 11 //- can't use pin 4 as that is for blue connection led
#define TFT_RST -1
#define TFT_DC (5)
#define USE_SD_CARD (0)
//pin 9 is free, as pin_a6 is for vbat and is otherwise known as digital 20
#define VOLT_PIN PIN_A6 //INPUT_POWER_PIN
#define SOUND_TRIGGER_PIN (9)
//buttons, scroller - d2 pin supposed to be pin #2
//button on the board is connected to pin 7. TX is pin 0, RX is pin 1 - these are normally used for serial communication
#define BUTTON_1_PIN PIN_SERIAL1_RX
#define BUTTON_2_PIN PIN_SERIAL1_TX
//adafruit defines physically labeled pin D2 as pin 2 in its header file, but it does not respond when set as an input by default.
//you will need to modify system_nrf52840.c file by adding
//#define CONFIG_NFCT_PINS_AS_GPIOS (1)
//YOU WILL SEE THIS CONSTANT REFERENCED IN THAT FILE, with compiler-conditional logic around it to actually free up the NFC pins, but only if that constant exists in that file
#define BUTTON_3_PIN (2)
//pin 7 is the board button
#define BUTTON_BOARD PIN_BUTTON1
//only need 1 pin for potentiometer / scroller input. both poles need to be wired to GND and 3v - order doesn't matter
#define PIN_SCROLL_INPUT PIN_A0
#define SCAN_LED_PIN_1 PIN_A2
#define SCAN_LED_PIN_2 PIN_A3
#define SCAN_LED_PIN_3 PIN_A4
#define SCAN_LED_PIN_4 PIN_A5
#define SCAN_LED_BRIGHTNESS (32)
//neopixel power LED. must use an unreserved pin for this. PWR, ID, EMRG all use this pin
#define NEOPIXEL_CHAIN_DATAPIN (10)
#define NEOPIXEL_BRIGHTNESS (64)
#define NEOPIXEL_LED_COUNT (6)
// built-in pins: D4 = blue conn LED, 8 = neopixel on board, D13 = red LED next to micro usb port
// commented out lines are pre-defined by the adafruit board firmware
#define NEOPIXEL_BOARD_LED_PIN (8)
//#define PIN_NEOPIXEL 8
//#define BOARD_REDLED_PIN 13
//#define BOARD_BLUELED_PIN 4
//#define LED_RED 13
//#define LED_BLUE 4
//system os version #. max 3 digits
#define DEVICE_VERSION "0.96"
//theme definition: 0 = TNG, 1 = DS9, 2 = VOY
#define UX_THEME (0)
#define THERMAL_CAMERA_PORTRAIT (1)
//uncomment this line to have raw magnetometer z value displayed on home screen
//#define MAGNET_DEBUG (0)
//the -700 threshold was based on resolution of 10, or 1024 max
//-20000 is based on the analog resolution required by battery pin (-32768 to 32768 range)
//this is intended for the z index reading of magnetometer (negative means field is below the board)
int mnMagnetSleepThreshold = -28000;
#if UX_THEME == 0
// TNG colors here
#define color_SWOOP 0xF7B3
#define color_MAINTEXT 0x9E7F
//#define color_MAINTEXT 0xC69F
#define color_LABELTEXT 0x841E
#define color_HEADER 0xFEC8
#define color_TITLETEXT 0xFEC8
//196,187,145
#define color_LABELTEXT2 0xC5D2
//204,174,220
#define color_LABELTEXT3 0xCD7B
#define color_LABELTEXT4 0xEE31
#define color_LEGEND 0x6A62
//210,202,157
#define color_FFT 0xDEB5
#elif UX_THEME == 1
// ds9
#define color_SWOOP 0xD4F0
#define color_MAINTEXT 0xBD19
#define color_LABELTEXT 0x7A8D
#define color_HEADER 0xECA7
#define color_TITLETEXT 0xC3ED
//to-do: find fitting options for these to mesh with ds9
#define color_LABELTEXT2 0xC5D2
#define color_LABELTEXT3 0xCD7B
#define color_LABELTEXT4 0xEE31
#define color_LEGEND 0x6A62
#define color_FFT 0xDEB5
#elif UX_THEME == 2
// voy
#define color_MAINTEXT 0x9E7F
#define color_SWOOP 0x7C34
#define color_LABELTEXT 0x9CDF
#define color_HEADER 0xCB33
#define color_TITLETEXT 0xFFAF
//to-do: find fitting options for these to mesh with voy
#define color_LABELTEXT2 0xC5D2
#define color_LABELTEXT3 0xCD7B
#define color_LABELTEXT4 0xEE31
#define color_LEGEND 0x6A62
#define color_FFT 0xDEB5
#endif
#define color_REDLABELTEXT 0xE000
#define color_REDDARKLABELTEXT 0x9800
#define color_REDDATATEXT 0xDEFB
//use labeltext3 for servo ltpurple
#define color_SERVOPINK 0xFE18
#define color_SERVOPURPLE 0x83B7
#define RGBto565(r,g,b) ((((r) & 0xF8) << 8) | (((g) & 0xFC) << 3) | ((b) >> 3))
Adafruit_NeoPixel ledPwrStrip(NEOPIXEL_LED_COUNT, NEOPIXEL_CHAIN_DATAPIN, NEO_GRB + NEO_KHZ800);
Adafruit_NeoPixel ledBoard(1, NEOPIXEL_BOARD_LED_PIN, NEO_GRB + NEO_KHZ800);
// do not fuck with this. 2.0 IS THE BOARD - this call uses hardware SPI
Adafruit_ST7789 tft = Adafruit_ST7789(TFT_CS, TFT_DC, TFT_RST);
//create sensor objects
Adafruit_APDS9960 oColorSensor;
Adafruit_BMP280 oTempBarom;
Adafruit_SHT31 oHumid;
//power & board color enumerator: blue = 4, green = 3, yellow = 2, orange = 1, red = 0
int mnPowerColor = 4;
bool mbCyclePowerColor = false;
bool mbCycleBoardColor = false;
int mnBoardColor = 4;
//power interval doesn't need to check more than every 30 seconds
unsigned long mnPowerLEDInterval = 30000;
unsigned long mnIDLEDInterval = 1000;
unsigned long mnLastUpdateIDLED = 0;
int mnCurrentProfileRed = 0;
int mnCurrentProfileGreen = 0;
int mnCurrentProfileBlue = 0;
String msCurrentProfileName = "";
unsigned long mnEMRGLEDInterval = 110;
int mnEMRGMinStrength = 8;
int mnEMRGMaxStrength = 212;
int mnEMRGCurrentStrength = 8;
bool mbLEDIDSet = false;
unsigned long mnLastUpdatePower = 0;
unsigned long mnLastUpdateEMRG = 0;
bool mbEMRGdirection = false;
unsigned long mnBoardLEDInterval = 5000;
unsigned long mnLastUpdateBoard = 0;
//left scanner leds
unsigned long mnLeftLEDInterval = 200;
int mnLeftLEDCurrent = 0;
unsigned long mnLastUpdateLeftLED = 0;
unsigned long mnBoardRedLEDInterval = 350;
unsigned long mnBoardBlueLEDInterval = 250;
unsigned long mnLastUpdateBoardRedLED = 0;
unsigned long mnLastUpdateBoardBlueLED = 0;
bool mbBoardRedLED = false;
bool mbBoardBlueLED = false;
//colors range is purple > blue > green > yellow > orange > red > pink > white
const uint32_t mnIDLEDColorscape[] = {0x8010,0x0010,0x0400,0x7C20,0x8300,0x8000,0x8208,0x7C30};
const String marrProfiles[] = {"ALPHA","BETA","GAMMA","DELTA","EPSILON","ZETA","ETA","THETA"};
//reverse order for these makes the scroller show alpha when
//const String marrProfiles[] = {"THETA","ETA","ZETA","EPSILON","DELTA","GAMMA","BETA","ALPHA"};
const uint16_t mnThermalCameraLabels[] = {0xD6BA,0xC0A3,0xD541,0xD660,0x9E02,0x0458,0x89F1};
//color sensor
bool mbColorInitialized = false;
bool mbRGBActive = false;
unsigned long mnRGBScanInterval = 5000;
unsigned long mnRGBCooldown = 0;
unsigned long mnLastRGBScan = 0;
//temperature, humidity, pressure
//Average sea-level pressure is 1013.25 mbar
bool mbTempInitialized = false;
bool mbHumidityInitialized = false;
bool mbTempActive = false;
float mfTempC = 0.0;
float mfTempK = 0.0;
float mfHumid = 0.0;
int mnBarom = 0;
unsigned long mnClimateScanInterval = 2000;
int mnClimateCooldown = 0;
int mnTempTargetBar = 0;
int mnTempCurrentBar = 0;
int mnHumidTargetBar = 0;
int mnHumidCurrentBar = 0;
int mnBaromTargetBar = 0;
int mnBaromCurrentBar = 0;
int mnClimateBarStart = 62;
unsigned long mnLastTempBar = 0;
unsigned long mnLastBaromBar = 0;
unsigned long mnLastHumidBar = 0;
//17 ms is 60fps. setting this to 120fps, at least for initial crawl
unsigned long mnBarDrawInterval = 9;
bool mbHumidBarComplete = false;
bool mbTempBarComplete = false;
bool mbBaromBarComplete = false;
int marrScaleNotches[] = {123, 185, 247};
unsigned long mnLastClimateScan = 0;
bool mbHomeActive = false;
unsigned long mnLastUpdateHome = 0;
unsigned long mnHomeUpdateInterval = 1000;
bool mbMicrophoneStarted = false;
bool mbMicrophoneActive = false;
bool mbMicrophoneRedraw = false;
extern PDMClass PDM;
//mic sample rate is hertz, all samples are stored as 16 bit data.
//number of samples must be double the desired resolution, and be a base 2 number
//16k hertz -> 0-8k hertz max audio range captured
#define MIC_SAMPLESIZE 256
//16k is the ONLY SUPPORTED SAMPLE RATE!
//#define MIC_SAMPLERATE 16000
#define MIC_AMPLITUDE 1000 // Depending on audio source level, you may need to alter this value. Can be used as a 'sensitivity' control.
#define DECIMATION 64
#define FFT_REFERENCELINES 16
//#define FFT_MAX 150
#define FFT_BINCOUNT 16
#define FFT_BARHEIGHTMAX 64
#define GRAPH_OFFSET 10
#define GRAPH_WIDTH (tft.width() - 3)
#define GRAPH_HEIGHT (tft.height() - GRAPH_OFFSET)
#define GRAPH_MIN (tft.height() - 2)
#define GRAPH_MAX (tft.height() - GRAPH_OFFSET)
long MIC_SAMPLERATE = 16000;
int32_t mnMicVal = 0;
bool mbMicMaxRefresh = false;
short mnarrSampleData[MIC_SAMPLESIZE];
// number of samples read
volatile int mnSamplesRead = 0;
double mdarrActual[MIC_SAMPLESIZE];
double mdarrImaginary[MIC_SAMPLESIZE];
int mnMaxDBValue = 0;
// a windowed sinc filter for 44 khz, 64 samples
//uint16_t marrSincFilter[DECIMATION] = {0, 2, 9, 21, 39, 63, 94, 132, 179, 236, 302, 379, 467, 565, 674, 792, 920, 1055, 1196, 1341, 1487, 1633, 1776, 1913, 2042, 2159, 2263, 2352, 2422, 2474, 2506, 2516, 2506, 2474, 2422, 2352, 2263, 2159, 2042, 1913, 1776, 1633, 1487, 1341, 1196, 1055, 920, 792, 674, 565, 467, 379, 302, 236, 179, 132, 94, 63, 39, 21, 9, 2, 0, 0};
unsigned long mnLastMicRead = 0;
//decibel estimation every 3 seconds
unsigned long mnMicReadInterval = 3000;
short mCurrentMicDisplay[FFT_BINCOUNT] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
short mTargetMicDisplay[FFT_BINCOUNT] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
//button functionality
bool mbButton1Flag = false;
bool mbButton2Flag = false;
bool mbButton3Flag = false;
bool mbButton7Flag = false;
EasyButton oButton1(BUTTON_1_PIN);
EasyButton oButton2(BUTTON_2_PIN);
EasyButton oButton3(BUTTON_3_PIN);
//board button digital pin 7 - use for thermal camera toggle
EasyButton oButton7(BUTTON_BOARD);
bool mbSleepMode = false;
Adafruit_LIS3MDL oMagneto;
bool mbMagnetometer = false;
float mfMagnetX, mfMagnetY, mfMagnetz;
unsigned long mnLastMagnetCheck = 0;
unsigned long mnMagnetInterval = 2000;
//if this cutoff is not working, either change where your speaker sits in the shell or add another magnet to your door to force the z-drop
unsigned long mnLastMagnetValue = 0;
//Adafruit_MLX90640 oThermalCamera;
const uint8_t mbCameraAddress = 0x33;
paramsMLX90640 moCameraParams;
#define TA_SHIFT 8
//temperature cutoffs are given in celsius. -12C => -10F
//old cutoffs -> 12C / 35C new are 50F -> 104F
int MIN_CAMERA_TEMP = 10;
int MAX_CAMERA_TEMP = 40;
//need array length of 768 as this is 32*24 resolution
float mfarrTempFrame[768];
float mfTR = 0.0;
float mfTA = 0.0;
float mfCameraEmissivity = 0.95;
bool mbThermalCameraStarted = false;
bool mbThermalActive = false;
//this interval caps draw and thermal data frame rates. camera data will run slower than 30fps, but this throttle is needed to allow button press event polling
//50ms -> 20fps cap
uint8_t mnThermalCameraInterval = 50;
unsigned long mnLastCameraFrame = 0;
//this must be less than 10 for all data to be displayed on 320x240.
//this scales display window to 256 x 192, a border of 24px all around
// if thermal camera is rotated 90 degrees, can change thermal to square viewport
// portrait hardware could be overall benefit, with viewport 216x216 (24*9)
uint16_t mnThermalPixelWidth = (THERMAL_CAMERA_PORTRAIT == 1) ? 9 : 8;
uint16_t mnThermalPixelHeight = (THERMAL_CAMERA_PORTRAIT == 1) ? 9 : 8;
uint8_t mnCameraDisplayStartX = (THERMAL_CAMERA_PORTRAIT == 1) ? 52 : 32;
uint8_t mnCameraDisplayStartY = (THERMAL_CAMERA_PORTRAIT == 1) ? 12 : 24;
//uint8_t mnCameraDisplayStartY = 0;
//16hz ~= 16fps
//while this is editable, it's probably not worth the time to decode and re-encode just to convert it to the desired LCARS color scheme
//lowest value is super dark purple: RGB 78,0,128
//highest value (0xF800) was 255,0,0
//2021.07.26 expanding color map to go from red to white for top-most end of temp range supported
const uint16_t mnarrThermalDisplayColors[] = {0x480F, 0x400F,0x400F,0x400F,0x4010,0x3810,0x3810,0x3810,0x3810,0x3010,0x3010,
0x3010,0x2810,0x2810,0x2810,0x2810,0x2010,0x2010,0x2010,0x1810,0x1810,0x1811,0x1811,0x1011,0x1011,0x1011,0x0811,0x0811,0x0811,0x0011,0x0011,
0x0011,0x0011,0x0011,0x0031,0x0031,0x0051,0x0072,0x0072,0x0092,0x00B2,0x00B2,0x00D2,0x00F2,0x00F2,0x0112,0x0132,0x0152,0x0152,0x0172,0x0192,
0x0192,0x01B2,0x01D2,0x01F3,0x01F3,0x0213,0x0233,0x0253,0x0253,0x0273,0x0293,0x02B3,0x02D3,0x02D3,0x02F3,0x0313,0x0333,0x0333,0x0353,0x0373,
0x0394,0x03B4,0x03D4,0x03D4,0x03F4,0x0414,0x0434,0x0454,0x0474,0x0474,0x0494,0x04B4,0x04D4,0x04F4,0x0514,0x0534,0x0534,0x0554,0x0554,0x0574,
0x0574,0x0573,0x0573,0x0573,0x0572,0x0572,0x0572,0x0571,0x0591,0x0591,0x0590,0x0590,0x058F,0x058F,0x058F,0x058E,0x05AE,0x05AE,0x05AD,0x05AD,
0x05AD,0x05AC,0x05AC,0x05AB,0x05CB,0x05CB,0x05CA,0x05CA,0x05CA,0x05C9,0x05C9,0x05C8,0x05E8,0x05E8,0x05E7,0x05E7,0x05E6,0x05E6,0x05E6,0x05E5,
0x05E5,0x0604,0x0604,0x0604,0x0603,0x0603,0x0602,0x0602,0x0601,0x0621,0x0621,0x0620,0x0620,0x0620,0x0620,0x0E20,0x0E20,0x0E40,0x1640,0x1640,
0x1E40,0x1E40,0x2640,0x2640,0x2E40,0x2E60,0x3660,0x3660,0x3E60,0x3E60,0x3E60,0x4660,0x4660,0x4E60,0x4E80,0x5680,0x5680,0x5E80,0x5E80,0x6680,
0x6680,0x6E80,0x6EA0,0x76A0,0x76A0,0x7EA0,0x7EA0,0x86A0,0x86A0,0x8EA0,0x8EC0,0x96C0,0x96C0,0x9EC0,0x9EC0,0xA6C0,0xAEC0,0xAEC0,0xB6E0,0xB6E0,
0xBEE0,0xBEE0,0xC6E0,0xC6E0,0xCEE0,0xCEE0,0xD6E0,0xD700,0xDF00,0xDEE0,0xDEC0,0xDEA0,0xDE80,0xDE80,0xE660,0xE640,0xE620,0xE600,0xE5E0,0xE5C0,
0xE5A0,0xE580,0xE560,0xE540,0xE520,0xE500,0xE4E0,0xE4C0,0xE4A0,0xE480,0xE460,0xEC40,0xEC20,0xEC00,0xEBE0,0xEBC0,0xEBA0,0xEB80,0xEB60,0xEB40,
0xEB20,0xEB00,0xEAE0,0xEAC0,0xEAA0,0xEA80,0xEA60,0xEA40,0xF220,0xF200,0xF1E0,0xF1C0,0xF1A0,0xF180,0xF160,0xF140,0xF100,0xF0E0,0xF0C0,0xF0A0,
0xF080,0xF060,0xF040,0xF020,0xF800
//};
,0xF841,0xF8A2,0xF8E3,0xF945,0xF986,0xF9E7,0xFA28,0xFA8A,0xFACB,0xFB2C,0xFB6D,0xFBCF,0xFC10,0xFC71,0xFCB2,0xFD14,0xFD55,0xFDB6,0xFDF7,0xFD59
,0xFE9A,0xFEFB,0xFF3C,0xFF9E};
bool mbTomServoActive = false;
unsigned long mnButton2Press = 0;
unsigned long mnButton3Press = 0;
int mnServoButtonWindow = 1500;
//graphs should take 3 seconds for full draw cycle-> 3000 / 80 lines
uint8_t mnServoDrawInterval = 38;
unsigned long mnServoLastDraw = 0;
uint8_t mnCurrentServoGraphPoint = 0;
//establish graph values
const uint8_t mnarrServoGraphData[] = {3,7,10,12,13,14,14,14,13,12,10,7,4,4,6,8,11,13,14,15,15,15,15,14,13,
12,10,8,7,6,4,3,2,2,2,3,4,6,8,9,11,12,12,12,11,10,9,7,5,3,3,3,5,7,10,
11,11,12,12,12,11,11,10,9,9,9,8,8,8,8,7,6,5,5,5,5,4,3,2,2,2};
void setup() {
//NRF_UICR->NFCPINS = 0;
ledPwrStrip.begin();
ledBoard.begin();
// use this initializer for a 2.0" 320x240 TFT. technically this is a rotated 240x320, so declaration is in that order
tft.init(240, 320, SPI_MODE0); // Init ST7789 320x240
tft.setRotation(1);
tft.setFont(&lcars11pt7b);
//these goggles, they do nothing!
tft.setTextWrap(false);
ledPwrStrip.clear();
ledBoard.clear();
// max brightness is 255
// ledStrip.setBrightness(255);
ledPwrStrip.setBrightness(NEOPIXEL_BRIGHTNESS);
ledBoard.setBrightness(NEOPIXEL_BRIGHTNESS);
//set pinmode output for scanner leds
pinMode(SCAN_LED_PIN_1, OUTPUT);
pinMode(SCAN_LED_PIN_2, OUTPUT);
pinMode(SCAN_LED_PIN_3, OUTPUT);
pinMode(SCAN_LED_PIN_4, OUTPUT);
//set output for board non-neopixel LEDs
pinMode(LED_RED, OUTPUT);
pinMode(LED_BLUE, OUTPUT);
pinMode(SOUND_TRIGGER_PIN, OUTPUT);
digitalWrite(SOUND_TRIGGER_PIN, HIGH);
//or it'll be read as low and boot the tricorder into environment section
pinMode(BUTTON_1_PIN, OUTPUT);
pinMode(BUTTON_2_PIN, OUTPUT);
pinMode(BUTTON_3_PIN, OUTPUT);
digitalWrite(BUTTON_1_PIN, HIGH);
digitalWrite(BUTTON_2_PIN, HIGH);
digitalWrite(BUTTON_3_PIN, HIGH);
delay(10);
pinMode(PIN_SCROLL_INPUT, INPUT);
pinMode(BUTTON_1_PIN, INPUT);
pinMode(BUTTON_2_PIN, INPUT);
pinMode(BUTTON_3_PIN, INPUT);
pinMode(VOLT_PIN, INPUT);
pinMode(BUTTON_BOARD, INPUT);
//initialize color sensor, show error if unavailable. sensor hard-coded name is "ADPS"
//begin will return false if initialize failed.
//this shit is super plug & play - library uses i2c address 0x39, same as one used by this board
//DO NOT call any functions before the begin, or you'll lock up the board
mbColorInitialized = oColorSensor.begin();
if (mbColorInitialized) {
//need rgb to cap at 255 for calculations? this isn't limiting shit.
//proximity sensor has a range of 4-8 inches, or 10-20cm
oColorSensor.setIntLimits(0, 255);
oColorSensor.enableColor(true);
oColorSensor.enableProximity(true);
oColorSensor.setADCGain(APDS9960_AGAIN_16X);
oColorSensor.enableColorInterrupt();
oColorSensor.setADCIntegrationTime(50);
}
//temp sensor
mbTempInitialized = oTempBarom.begin();
mbHumidityInitialized = oHumid.begin();
//microphone
PDM.onReceive(PullMicData);
//PDM.setGain(50);
mbMicrophoneStarted = PDM.begin(1, MIC_SAMPLERATE);
PDM.end();
mbMagnetometer = oMagneto.begin_I2C();
//all magnet settings - data rate of 1.25Hz a bit faster than 1 per second
oMagneto.setPerformanceMode(LIS3MDL_MEDIUMMODE);
oMagneto.setOperationMode(LIS3MDL_CONTINUOUSMODE);
//oMagneto.setIntThreshold(500);
//can be 4, 8, 12, 16 - don't need high range here, as magnet in door will be pretty strong and very close
oMagneto.setRange(LIS3MDL_RANGE_8_GAUSS);
/*oMagneto.configInterrupt(false, false, true, true, false, true);
*/
SetThermalClock();
uint16_t oCameraParams[834];
int nStatus = -1;
nStatus = MLX90640_DumpEE(mbCameraAddress, oCameraParams);
if (nStatus == 0) {
mbThermalCameraStarted = true;
nStatus = MLX90640_ExtractParameters(oCameraParams, &moCameraParams);
//start at 1hz
MLX90640_SetRefreshRate(mbCameraAddress, 0x01);
//oThermalCamera.setMode(MLX90640_CHESS);
//oThermalCamera.setResolution(MLX90640_ADC_16BIT);
//minimize refresh rate since we can't turn off the camera?
//refresh rate will be double viable display frame rate, as need 2 data pulls per frame
//1Hz refresh rate works when clock is at 100kHz
//oThermalCamera.setRefreshRate(MLX90640_1_HZ);
//4Hz refresh rate works when clock is at 400kHz - 2fps
//oThermalCamera.setRefreshRate(MLX90640_4_HZ);
//Wire.setClock(1000000); // max 1 MHz gets translated to 400kHz with adafruit "driver"
//TWIM_FREQUENCY_FREQUENCY_K100 is default for board?
//TWIM_FREQUENCY_FREQUENCY_K250
//TWIM_FREQUENCY_FREQUENCY_K400
//8fps for screen is viable if clock speed is 800kHz & camera refresh rate is 16hz
//need to modify wire_nrf52.cpp to support
//TWIM_FREQUENCY_FREQUENCY_K1000
////Wire.setClock(TWIM_FREQUENCY_FREQUENCY_K400);
//Wire.endTransmission(MLX90640_I2CADDR_DEFAULT);
}
ResetWireClock();
oButton2.begin();
oButton2.onPressed(ToggleRGBSensor);
oButton1.begin();
oButton1.onPressed(ToggleClimateSensor);
oButton3.begin();
oButton3.onPressed(ToggleMicrophone);
//oButton3.onPressed(ActivateTomServo);
oButton7.begin();
oButton7.onPressed(ToggleThermal);
//10k potentiometer / scroller should be limited to a readable range of 10-890
//analog write values can go from 0 to 255. analogRead can go from 0 to 2^(analogReadResolution)
//changing this WILL screw with other stuff, like the magnetometer & battery
//analogReadResolution(10);
GoHome();
}
void loop() {
//if magnet read in Z direction is over a threshold, trigger sleep.
//check this first in the loop, as everything else depends on it
//magnet from speaker throws z = ~ +14000, no magnets has z idle at ~ -500
//use z > 5000 ?
//all analogRead actions depend on resolution setting - changing this will screw with battery % readings
//need tests with speaker above and door magnet below - may require testing within assembled shell
#if !defined(MAGNET_DEBUG)
if (mbMagnetometer && (millis() - mnLastMagnetCheck) > mnMagnetInterval) {
oMagneto.read();
//magnet function modification needs to use a massive drop as the sleep trigger.
int nCurrentMagnetZ = oMagneto.y;
if (!mbSleepMode && (nCurrentMagnetZ < mnMagnetSleepThreshold)) {
SleepMode();
} else if (mbSleepMode && (nCurrentMagnetZ > mnMagnetSleepThreshold)) {
ActiveMode();
}
mnLastMagnetCheck = millis();
}
#endif
if (mbSleepMode) {
if (ledPwrStrip.getPixelColor(1) != ST77XX_BLACK) {
ledPwrStrip.clear();
ledPwrStrip.show();
}
return;
}
//toggle climate
oButton1.read();
//this toggles RGB scanner
oButton2.read();
//toggle microphone
oButton3.read();
//toggle thermal camera
oButton7.read();
RunNeoPixelColor(NEOPIXEL_CHAIN_DATAPIN);
RunNeoPixelColor(NEOPIXEL_BOARD_LED_PIN);
RunLeftScanner();
RunHome();
//blink board LEDs
RunBoardLEDs();
RunRGBSensor();
RunClimateSensor();
RunMicrophone();
RunThermal();
RunTomServo();
}
void SleepMode() {
mbSleepMode = true;
//turn off screen
tft.fillScreen(ST77XX_BLACK);
//need wired pin to set backlight low here
//digitalWrite(DISPLAY_BACKLIGHT_PIN, LOW);
tft.enableSleep(true);
//set sound trigger pin HIGH, as low causes playback
digitalWrite(SOUND_TRIGGER_PIN, HIGH);
//board edge LEDs off
digitalWrite(LED_RED, LOW);
digitalWrite(LED_BLUE, LOW);
//board "power" / "camera flash" LED off
ledBoard.setPixelColor(0, 0, 0, 0);
ledBoard.show();
//left scanner LEDs off
analogWrite(SCAN_LED_PIN_1, 0);
analogWrite(SCAN_LED_PIN_2, 0);
analogWrite(SCAN_LED_PIN_3, 0);
analogWrite(SCAN_LED_PIN_4, 0);
//set chained neopixels off - PWR, EMRG, ID
ledPwrStrip.clear();
//ledPwrStrip.show();
mbLEDIDSet = false;
//reset all "status" variables
mnRGBCooldown = 0;
mnClimateCooldown = 0;
mbHomeActive = true;
mbRGBActive = false;
mbTempActive = false;
mbThermalActive = false;
mbTomServoActive = false;
mbMicrophoneActive = false;
mnCurrentServoGraphPoint = 0;
mnServoLastDraw = 0;
SetActiveNeoPixelButton(0);
mbButton1Flag = false;
mbButton2Flag = false;
mbButton3Flag = false;
//reset any bar graph values from climate
mnTempTargetBar = 0;
mnTempCurrentBar = 0;
mnHumidTargetBar = 0;
mnHumidCurrentBar = 0;
mnBaromTargetBar = 0;
mnBaromCurrentBar = 0;
mbHumidBarComplete = false;
mbTempBarComplete = false;
mbBaromBarComplete = false;
}
void ActiveMode() {
mbSleepMode = false;
tft.enableSleep(false);
//tft.enableDisplay(true);
//force immediate refresh of neopixel LEDs
mnLastUpdatePower = 0;
mnLastUpdateIDLED = 0;
mnLastUpdateEMRG = 0;
GoHome();
}
void ActivateSound() {
digitalWrite(SOUND_TRIGGER_PIN, LOW);
}
void DisableSound() {
digitalWrite(SOUND_TRIGGER_PIN, HIGH);
}
void RunNeoPixelColor(int nPin) {
unsigned long lTimer = millis();
if (nPin == NEOPIXEL_CHAIN_DATAPIN) {
if (mnLastUpdatePower == 0 || ((lTimer - mnLastUpdatePower) > mnPowerLEDInterval)) {
//these will need to have their own intervals
//switch should eventually be changed to poll voltage pin - pin#, r,g,b
//cycle order = blue, green, yellow, orange, red
if (mbCyclePowerColor) {
switch (mnPowerColor) {
case 4: ledPwrStrip.setPixelColor(0, 0, 0, 128); mnPowerColor = 3; break;
case 3: ledPwrStrip.setPixelColor(0, 0, 128, 0); mnPowerColor = 2; break;
case 2: ledPwrStrip.setPixelColor(0, 112, 128, 0); mnPowerColor = 1; break;
case 1: ledPwrStrip.setPixelColor(0, 128, 96, 0); mnPowerColor = 0; break;
default: ledPwrStrip.setPixelColor(0, 128, 0, 0); mnPowerColor = 4; break;
}
} else {
int nBattMap = GetBatteryTier();
switch (nBattMap) {
case 5: ledPwrStrip.setPixelColor(0, 0, 0, 128); break;
case 4: ledPwrStrip.setPixelColor(0, 0, 0, 128); break;
case 3: ledPwrStrip.setPixelColor(0, 0, 128, 0); break;
case 2: ledPwrStrip.setPixelColor(0, 112, 128, 0); break;
case 1: ledPwrStrip.setPixelColor(0, 128, 96, 0); break;
default: ledPwrStrip.setPixelColor(0, 128, 0, 0); break;
}
} //end if powercolorCycle
mnLastUpdatePower = lTimer;
ledPwrStrip.show();
}
//need to push ID LED separate from power, as PWR only updates every 30 seconds
if (mnLastUpdateIDLED == 0 || ((lTimer - mnLastUpdateIDLED) > mnIDLEDInterval)) {
//set ID LED color based on value pulled from A0, middle prong of scroll potentiometer
//colors range is purple > blue > green > yellow > orange > red > pink > white
uint16_t nScrollerValue = analogRead(PIN_SCROLL_INPUT);
uint16_t nTempColor = nScrollerValue;
if (nScrollerValue < 110) {
nTempColor = 0;
} else if (nScrollerValue < 220) {
nTempColor = 1;
} else if (nScrollerValue < 330) {
nTempColor = 2;
} else if (nScrollerValue < 440) {
nTempColor = 3;
} else if (nScrollerValue < 550) {
nTempColor = 4;
} else if (nScrollerValue < 660) {
nTempColor = 5;
} else if (nScrollerValue < 770) {
nTempColor = 6;
} else {
nTempColor = 7;
}
msCurrentProfileName = marrProfiles[nTempColor];
//calling uint16 parameter function for set color was not working. converting uint16 to rgb
mnCurrentProfileRed = ((((mnIDLEDColorscape[nTempColor] >> 11) & 0x1F) * 527) + 23) >> 6;
mnCurrentProfileGreen = ((((mnIDLEDColorscape[nTempColor] >> 5) & 0x3F) * 259) + 33) >> 6;
mnCurrentProfileBlue = (((mnIDLEDColorscape[nTempColor] & 0x1F) * 527) + 23) >> 6;
//NEOPIXEL_LED_COUNT
//ledPwrStrip.setPixelColor(1, mnCurrentProfileRed, mnCurrentProfileGreen, mnCurrentProfileBlue);
ledPwrStrip.setPixelColor(NEOPIXEL_LED_COUNT-2, mnCurrentProfileRed, mnCurrentProfileGreen, mnCurrentProfileBlue);
ledPwrStrip.show();
mnLastUpdateIDLED = lTimer;
}
//throb EMRG LED
if ((lTimer - mnLastUpdateEMRG) > mnEMRGLEDInterval) {
int nCurrentEMRG = mnEMRGCurrentStrength;
int nEMRGIncrement = (mnEMRGMaxStrength - mnEMRGMinStrength) / (mnEMRGLEDInterval / 8);
if (nCurrentEMRG >= mnEMRGMaxStrength || nCurrentEMRG <= mnEMRGMinStrength) {
mbEMRGdirection = !mbEMRGdirection;
}
nCurrentEMRG = nCurrentEMRG + ((mbEMRGdirection == true ? 1 : -1) * nEMRGIncrement);
if (nCurrentEMRG > mnEMRGMaxStrength)
nCurrentEMRG = mnEMRGMaxStrength;
if (nCurrentEMRG < mnEMRGMinStrength)
nCurrentEMRG = mnEMRGMinStrength;
mnEMRGCurrentStrength = nCurrentEMRG;
//ledPwrStrip.setPixelColor(2, nCurrentEMRG, 0, 0);
ledPwrStrip.setPixelColor(NEOPIXEL_LED_COUNT-1, nCurrentEMRG, 0, 0);
ledPwrStrip.show();
mnLastUpdateEMRG = lTimer;
}
} else if (nPin == NEOPIXEL_BOARD_LED_PIN) {
//unsure if want to use, as this needs to be sensor flash.
//this has a separate update interval from power because we want this to come back faster than 30 seconds after color scanner is used
if (!mbRGBActive) {
if ((lTimer - mnLastUpdateBoard) > mnBoardLEDInterval) {
if (mbCycleBoardColor == false) {
int nBattMapBoard = GetBatteryTier();
//cycle order = blue, green, yellow, orange, red
switch (nBattMapBoard) {
case 5: ledBoard.setPixelColor(0, 0, 0, 128); break;
case 4: ledBoard.setPixelColor(0, 0, 0, 128); break;
case 3: ledBoard.setPixelColor(0, 0, 128, 0); break;
case 2: ledBoard.setPixelColor(0, 112, 128, 0); break;
case 1: ledBoard.setPixelColor(0, 128, 96, 0); break;
default: ledBoard.setPixelColor(0, 128, 0, 0); break;
}
} else {
switch (mnBoardColor) {
case 4: ledBoard.setPixelColor(0, 0, 0, 128); mnBoardColor = 3; break;
case 3: ledBoard.setPixelColor(0, 0, 128, 0); mnBoardColor = 2; break;
case 2: ledBoard.setPixelColor(0, 112, 128, 0); mnBoardColor = 1; break;
case 1: ledBoard.setPixelColor(0, 128, 96, 0); mnBoardColor = 0; break;
default: ledBoard.setPixelColor(0, 128, 0, 0); mnBoardColor = 4; break;
}
}
mnLastUpdateBoard = lTimer;
ledBoard.show();
}
} else {
//color scanner app running - do nothing
}
}
}
void SetActiveNeoPixelButton(int nButtonID) {
if (NEOPIXEL_LED_COUNT != 6) return;
//if bottom right of screen gets a tiny led board, extend same logic to those?
//NEOPIXEL_LED_COUNT would be 9 in that case
switch (nButtonID) {
//home screen, NO APPS ACTIVE
case 0: ledPwrStrip.setPixelColor(NEOPIXEL_LED_COUNT-5, 0, 128, 0);
ledPwrStrip.setPixelColor(NEOPIXEL_LED_COUNT-4, 0, 128, 0);
ledPwrStrip.setPixelColor(NEOPIXEL_LED_COUNT-3, 0, 128, 0);
break;
//GEO
case 1: ledPwrStrip.setPixelColor(NEOPIXEL_LED_COUNT-5, 128, 96, 0);
ledPwrStrip.setPixelColor(NEOPIXEL_LED_COUNT-4, 0, 128, 0);
ledPwrStrip.setPixelColor(NEOPIXEL_LED_COUNT-3, 0, 128, 0);
break;
//MET
case 2: ledPwrStrip.setPixelColor(NEOPIXEL_LED_COUNT-5, 0, 128, 0);
ledPwrStrip.setPixelColor(NEOPIXEL_LED_COUNT-4, 128, 96, 0);
ledPwrStrip.setPixelColor(NEOPIXEL_LED_COUNT-3, 0, 128, 0);
break;
//BIO
case 3: ledPwrStrip.setPixelColor(NEOPIXEL_LED_COUNT-5, 0, 128, 0);
ledPwrStrip.setPixelColor(NEOPIXEL_LED_COUNT-4, 0, 128, 0);
ledPwrStrip.setPixelColor(NEOPIXEL_LED_COUNT-3, 128, 96, 0);
break;
//CAMERA - all RED
case 4: ledPwrStrip.setPixelColor(NEOPIXEL_LED_COUNT-5, 128, 0, 0);
ledPwrStrip.setPixelColor(NEOPIXEL_LED_COUNT-4, 128, 0, 0);
ledPwrStrip.setPixelColor(NEOPIXEL_LED_COUNT-3, 128, 0, 0);
break;
//TOM SERVO - all BLUE? PURPLE?
case 5: ledPwrStrip.setPixelColor(NEOPIXEL_LED_COUNT-5, 0, 0, 128);
ledPwrStrip.setPixelColor(NEOPIXEL_LED_COUNT-4, 0, 0, 128);
ledPwrStrip.setPixelColor(NEOPIXEL_LED_COUNT-3, 0, 0, 128);
break;
}
ledPwrStrip.show();
}
void RunBoardLEDs() {
unsigned long lTimer = millis();
if ((lTimer - mnLastUpdateBoardRedLED) > mnBoardRedLEDInterval) {
//flip LED state flag, set state based on new flag
mbBoardRedLED = !mbBoardRedLED;
if (mbBoardRedLED) {
digitalWrite(LED_RED, HIGH);
} else {
digitalWrite(LED_RED, LOW);
}
mnLastUpdateBoardRedLED = lTimer;
}
if ((lTimer - mnLastUpdateBoardBlueLED) > mnBoardBlueLEDInterval) {
mbBoardBlueLED = !mbBoardBlueLED;
if (mbBoardRedLED) {
digitalWrite(LED_BLUE, HIGH);
} else {
digitalWrite(LED_BLUE, LOW);
}
mnLastUpdateBoardBlueLED = lTimer;
}
}
void ActivateFlash() {
//all neopixel objects are chains, so have to call it by addr
ledBoard.setPixelColor(0, 255, 255, 255);
ledBoard.show();
}
void DisableFlash() {
ledBoard.setPixelColor(0, 0, 0, 0);
ledBoard.show();
}
//to-do: add parameters to change cycle behavior of LEDs.
//ex: cycled down-> up, stacking, unified blink, KITT ping pong, etc
void RunLeftScanner() {
unsigned long lTimer = millis();
//when color scanner running, use left side lights to convey scan coming soon:
if (!mbRGBActive) {
if ((lTimer - mnLastUpdateLeftLED) > mnLeftLEDInterval) {
//add switch or if/else for different scanner modes
switch (mnLeftLEDCurrent) {
case 1: analogWrite(SCAN_LED_PIN_1, 0); analogWrite(SCAN_LED_PIN_4, SCAN_LED_BRIGHTNESS); mnLeftLEDCurrent = 4; break;
case 2: analogWrite(SCAN_LED_PIN_2, 0); analogWrite(SCAN_LED_PIN_1, SCAN_LED_BRIGHTNESS); mnLeftLEDCurrent = 1; break;
case 3: analogWrite(SCAN_LED_PIN_3, 0); analogWrite(SCAN_LED_PIN_2, SCAN_LED_BRIGHTNESS); mnLeftLEDCurrent = 2; break;
default: analogWrite(SCAN_LED_PIN_4, 0); analogWrite(SCAN_LED_PIN_3, SCAN_LED_BRIGHTNESS); mnLeftLEDCurrent = 3; break;
}
mnLastUpdateLeftLED = lTimer;
}
} else {
//currently stacks "downward" - all on to only alpha on - which is more like a lifting drape
switch (mnRGBCooldown) {
case 1:
analogWrite(SCAN_LED_PIN_1, SCAN_LED_BRIGHTNESS);
analogWrite(SCAN_LED_PIN_2, 0);
analogWrite(SCAN_LED_PIN_3, 0);
analogWrite(SCAN_LED_PIN_4, 0);
break;
case 2:
analogWrite(SCAN_LED_PIN_1, SCAN_LED_BRIGHTNESS);
analogWrite(SCAN_LED_PIN_2, SCAN_LED_BRIGHTNESS);
analogWrite(SCAN_LED_PIN_3, 0);
analogWrite(SCAN_LED_PIN_4, 0);
break;
case 3:
analogWrite(SCAN_LED_PIN_1, SCAN_LED_BRIGHTNESS);
analogWrite(SCAN_LED_PIN_2, SCAN_LED_BRIGHTNESS);
analogWrite(SCAN_LED_PIN_3, SCAN_LED_BRIGHTNESS);
analogWrite(SCAN_LED_PIN_4, 0);
break;
case 4:
analogWrite(SCAN_LED_PIN_1, SCAN_LED_BRIGHTNESS);
analogWrite(SCAN_LED_PIN_2, SCAN_LED_BRIGHTNESS);
analogWrite(SCAN_LED_PIN_3, SCAN_LED_BRIGHTNESS);
analogWrite(SCAN_LED_PIN_4, SCAN_LED_BRIGHTNESS);
break;
default:
analogWrite(SCAN_LED_PIN_1, 0);
analogWrite(SCAN_LED_PIN_2, 0);
analogWrite(SCAN_LED_PIN_3, 0);
analogWrite(SCAN_LED_PIN_4, 0);
break;
}
}
}
//to-do: call scanner clear on any mode change?
void ClearLeftScanner() {
analogWrite(SCAN_LED_PIN_1, 0);
analogWrite(SCAN_LED_PIN_2, 0);
analogWrite(SCAN_LED_PIN_3, 0);
analogWrite(SCAN_LED_PIN_4, 0);
mnLeftLEDCurrent = 1;
}
void GoHome() {
ResetWireClock();
DisableSound();
//if flag set for thermal debug mode, hijack home screen?
//reset any previous sensor statuses
mnRGBCooldown = 0;
mnClimateCooldown = 0;
mbHomeActive = true;
mbRGBActive = false;
mbTempActive = false;
mnCurrentServoGraphPoint = 0;
mnServoLastDraw = 0;
SetActiveNeoPixelButton(0);
mbButton1Flag = false;
mbButton2Flag = false;
mbButton3Flag = false;
//reset any bar graph values from climate
mnTempTargetBar = 0;
mnTempCurrentBar = 0;
mnHumidTargetBar = 0;
mnHumidCurrentBar = 0;
mnBaromTargetBar = 0;
mnBaromCurrentBar = 0;
mbHumidBarComplete = false;
mbTempBarComplete = false;
mbBaromBarComplete = false;
mbThermalActive = false;
mbTomServoActive = false;
//tft.setFont(&lcars11pt7b);
tft.setFont(&lcars15pt7b);
// large block of text
tft.fillScreen(ST77XX_BLACK);
// home screen header is 2 rounded rectangles, lines to cut them, 1 black rect as backing for header text
//fillRoundRect(x,y,width,height,cornerRadius, color)
//top and bottom borders
tft.fillRoundRect(26, 1, 289, 22, 11, color_SWOOP);
tft.fillRoundRect(26, 216, 289, 22, 11, color_SWOOP);
//left side
tft.fillRoundRect(1, 1, 68, 66, 32, color_SWOOP);
tft.fillRoundRect(1, 171, 68, 66, 32, color_SWOOP);
tft.fillRoundRect(59, 23, 24, 193, 11, ST77XX_BLACK);
//middle section - needs to be split for profile name and color
//tft.fillRect(1, 39, 58, 164, color_HEADER);
//dull all LED colors by 50% to lcarsify them
tft.fillRect(1, 39, 58, 76, RGBto565((int)min(mnCurrentProfileRed*1.75, 255), (int)min(mnCurrentProfileGreen*1.75, 255), (int)min(mnCurrentProfileBlue*1.75, 255)));
tft.fillRect(1, 147, 58, 55, RGBto565((int)min(mnCurrentProfileRed*1.75, 255), (int)min(mnCurrentProfileGreen*1.75, 255), (int)min(mnCurrentProfileBlue*1.75, 255)));
//profile label always shows bkg as swoop color
tft.fillRect(1, 119, 58, 24, color_SWOOP);
//middle section black lines
tft.drawFastHLine(1, 35, 58, ST77XX_BLACK);
tft.drawFastHLine(1, 36, 58, ST77XX_BLACK);
tft.drawFastHLine(1, 37, 58, ST77XX_BLACK);
tft.drawFastHLine(1, 38, 58, ST77XX_BLACK);
tft.drawFastHLine(1, 39, 58, ST77XX_BLACK);
tft.drawFastHLine(1, 40, 58, ST77XX_BLACK);
tft.drawFastHLine(1, 201, 58, ST77XX_BLACK);
tft.drawFastHLine(1, 202, 58, ST77XX_BLACK);
tft.drawFastHLine(1, 203, 58, ST77XX_BLACK);
tft.drawFastHLine(1, 204, 58, ST77XX_BLACK);
tft.drawFastHLine(1, 205, 58, ST77XX_BLACK);
tft.drawFastHLine(1, 206, 58, ST77XX_BLACK);
//bottom right
tft.drawFastVLine(296, 216, 22, ST77XX_BLACK);
tft.drawFastVLine(297, 216, 22, ST77XX_BLACK);
tft.drawFastVLine(298, 216, 22, ST77XX_BLACK);
tft.drawFastVLine(299, 216, 22, ST77XX_BLACK);
tft.drawFastVLine(300, 216, 22, ST77XX_BLACK);
tft.drawFastVLine(301, 216, 22, ST77XX_BLACK);
//black section for home screen title
tft.fillRect(232, 1, 69, 22, ST77XX_BLACK);
drawParamText(229, 21, " STATUS", color_MAINTEXT);
//drawParamText(229, 21, " ABOUT", color_MAINTEXT);
tft.fillRoundRect(76, 39, 14, 11, 5, color_LABELTEXT);
tft.fillRoundRect(76, 63, 14, 11, 5, color_LABELTEXT);
tft.fillRoundRect(76, 87, 14, 11, 5, color_LABELTEXT);
tft.fillRoundRect(162, 39, 14, 11, 5, color_MAINTEXT);
tft.fillRoundRect(162, 63, 14, 11, 5, color_MAINTEXT);
tft.fillRoundRect(162, 87, 14, 11, 5, color_MAINTEXT);
tft.fillRoundRect(252, 87, 14, 11, 5, color_MAINTEXT);
//set font to 11pt since header is done
tft.setFont(&lcars11pt7b);
drawParamText(6, 138, msCurrentProfileName, ST77XX_BLACK);
drawParamText(101, 50, "POWER", color_LABELTEXT);
drawParamText(101, 75, "UPTIME", color_LABELTEXT);
drawParamText(101, 100, "CPU", color_LABELTEXT);
//number only for battery level
ShowBatteryLevel(213, 50, color_LABELTEXT, color_MAINTEXT);
//uptime
drawParamText(185, 75, "00:00.00", color_MAINTEXT);
//cpu speed - hz to mhz conversion is to divide by 1 million exactly
drawParamText(204, 100, String((float) F_CPU / 1000000.0), color_MAINTEXT);