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
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
|
//*****************************************************************************
//
// qs-logger.c - Data logger Quickstart application for DK-TM4C123G
//
// Copyright (c) 2011-2014 Texas Instruments Incorporated. All rights reserved.
// Software License Agreement
//
// Texas Instruments (TI) is supplying this software for use solely and
// exclusively on TI's microcontroller products. The software is owned by
// TI and/or its suppliers, and is protected under applicable copyright
// laws. You may not combine this software with "viral" open-source
// software in order to form a larger program.
//
// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
// DAMAGES, FOR ANY REASON WHATSOEVER.
//
// This is part of revision 2.1.0.12573 of the DK-TM4C123G Firmware Package.
//
//*****************************************************************************
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <time.h>
#include "driverlib/adc.h"
#include "driverlib/debug.h"
#include "driverlib/fpu.h"
#include "driverlib/gpio.h"
#include "driverlib/hibernate.h"
#include "driverlib/pin_map.h"
#include "driverlib/rom.h"
#include "driverlib/rom_map.h"
#include "driverlib/sysctl.h"
#include "driverlib/systick.h"
#include "driverlib/uart.h"
#include "grlib/grlib.h"
#include "grlib/widget.h"
#include "grlib/canvas.h"
#include "inc/hw_gpio.h"
#include "inc/hw_hibernate.h"
#include "inc/hw_memmap.h"
#include "inc/hw_sysctl.h"
#include "inc/hw_types.h"
#include "usblib/usblib.h"
#include "utils/ustdlib.h"
#include "drivers/cfal96x64x16.h"
#include "drivers/buttons.h"
#include "drivers/slidemenuwidget.h"
#include "drivers/stripchartwidget.h"
#include "clocksetwidget.h"
#include "qs-logger.h"
#include "images.h"
#include "menus.h"
#include "acquire.h"
#include "usbstick.h"
#include "usbserial.h"
#include "flashstore.h"
//*****************************************************************************
//
//! \addtogroup example_list
//! <h1>Data Logger (qs-logger)</h1>
//!
//! This example application is a data logger. It can be configured to collect
//! data from up to 10 data sources. The possible data sources are:
//! - 4 analog inputs, 0-20V
//! - 9-axis I2C fusion data (3axis gyro, 3axis accelorometer, 3axis compass)
//! - internal and external temperature sensors
//! - processor current consumption
//!
//! The data logger provides a menu navigation that is operated by the buttons
//! on the board (up, down, left, right, select). The data logger
//! can be configured by using the menus. The following items can be
//! configured:
//! - data sources to be logged
//! - sample rate
//! - storage location
//! - sleep modes
//! - clock
//!
//! Using the data logger:
//!
//! Use the CONFIG menu to configure the data logger. The following choices
//! are provided:
//!
//! - CHANNELS - enable specific channels of data that will be logged
//! - PERIOD - select the sample period
//! - STORAGE - select where the collected data will be stored:
//! - FLASH - stored in the internal flash memory
//! - USB - stored on a connected USB memory stick
//! - HOST PC - transmitted to a host PC via USB OTG virtual serial port
//! - NONE - the data will only be displayed and not stored
//! - SLEEP - select whether or not the board sleeps between samples. Sleep
//! mode is allowed when storing to flash at with a period of 1 second or
//! longer.
//! - CLOCK - allows setting of internal time-of-day clock that is used for
//! time stamping of the sampled data
//!
//! Use the START menu to start the data logger running. It will begin
//! collecting and storing the data. It will continue to collect data until
//! stopped by pressing the left button or select button.
//!
//! While the data logger is collecting data and it is not configured to
//! sleep, a simple strip chart showing the collected data will appear on the
//! display. If the data logger is configured to sleep, then no strip chart
//! will be shown.
//!
//! If the data logger is storing to internal flash memory, it will overwrite
//! the oldest data. If storing to a USB memory device it will store data
//! until the device is full.
//!
//! The VIEW menu allows viewing the values of the data sources in numerical
//! format. When viewed this way the data is not stored.
//!
//! The SAVE menu allows saving data that was stored in internal flash memory
//! to a USB stick. The data will be saved in a text file in CSV format.
//!
//! The ERASE menu is used to erase the internal memory so more data can be
//! saved.
//!
//! When the board running qs-logger is connected to a host PC via
//! the USB OTG connection for the first time, Windows will prompt for a device
//! driver for the board.
//! This can be found in /ti/TivaWare_C_Series-x.x/windows_drivers
//! assuming you installed the software in the default folder.
//!
//! A companion Windows application, logger, can be found in the
//! /ti/TivaWare_C_Series-x.x/tools/bin directory. When the data logger's
//! STORAGE option is set to "HOST PC" and the board is connected to a PC
//! via the USB OTG connection, captured data will be transfered back to the PC
//! using the virtual serial port that the EK board offers. When the logger
//! application is run, it will search for the first connected board
//! and display any sample data received. The application also offers the
//! option to log the data to a file on the PC.
//!
//! Please note that this code will not run on a EK-LM4F232 board due to
//! hardware differences. If tried an error will be show on the screen.
//! For DK-EM4F232 code please see the examples/boards/ek-lm4f232 directory.
//
//*****************************************************************************
//*****************************************************************************
//
// The clock rate for the SysTick interrupt and a counter of system clock
// ticks. The SysTick interrupt is used for basic timing in the application.
//
//*****************************************************************************
#define CLOCK_RATE 100
#define MS_PER_SYSTICK (1000 / CLOCK_RATE)
static volatile uint32_t g_ui32TickCount;
uint32_t g_ui32LastTick = 0;
//*****************************************************************************
//
// A widget handle of the widget that should receive the focus of any button
// events.
//
//*****************************************************************************
static uint32_t g_ui32KeyFocusWidgetHandle;
//*****************************************************************************
//
// Tracks the data logging state.
//
//*****************************************************************************
typedef enum
{
eSTATE_IDLE,
eSTATE_LOGGING,
eSTATE_VIEWING,
eSTATE_SAVING,
eSTATE_ERASING,
eSTATE_FREEFLASH,
eSTATE_CLOCKSET,
eSTATE_CLOCKEXIT,
} tLoggerState;
static tLoggerState g_iLoggerState = eSTATE_IDLE;
//*****************************************************************************
//
// The configuration of the application. This holds the information that
// will need to be saved if sleeping is used.
//
//*****************************************************************************
static tConfigState g_sConfigState;
//*****************************************************************************
//
// The current state of USB OTG in the system based on the detected mode.
//
//*****************************************************************************
volatile tUSBMode g_iCurrentUSBMode = eUSBModeNone;
//*****************************************************************************
//
// The size of the host controller's memory pool in bytes.
//
//*****************************************************************************
#define HCD_MEMORY_SIZE 128
//*****************************************************************************
//
// The memory pool to provide to the Host controller driver.
//
//*****************************************************************************
uint8_t g_pui8HCDPool[HCD_MEMORY_SIZE];
//*****************************************************************************
//
// Forward declaration of callback function used for clock setter widget.
//
//*****************************************************************************
static void ClockSetOkCallback(tWidget *pWidget, bool bOk);
//*****************************************************************************
//
// The error routine that is called if the driver library encounters an error.
//
//*****************************************************************************
#ifdef DEBUG
void
__error__(char *pcFilename, uint32_t ui32Line)
{
}
#endif
//*****************************************************************************
//
// Provide a simple function so other parts of the application can update
// a status display.
//
//*****************************************************************************
void
SetStatusText(const char *pcTitle, const char *pcLine1, const char *pcLine2,
const char *pcLine3)
{
static const char pcBlankLine[] = " ";
//
// Check to see if each parameter was passed, and if so then update its
// text field on the status dislay.
//
pcTitle = pcTitle ? pcTitle : pcBlankLine;
MenuUpdateText(TEXT_ITEM_STATUS_TITLE, pcTitle);
pcLine1 = pcLine1 ? pcLine1 : pcBlankLine;
MenuUpdateText(TEXT_ITEM_STATUS1, pcLine1);
pcLine2 = pcLine2 ? pcLine2 : pcBlankLine;
MenuUpdateText(TEXT_ITEM_STATUS2, pcLine2);
pcLine3 = pcLine3 ? pcLine3 : pcBlankLine;
MenuUpdateText(TEXT_ITEM_STATUS3, pcLine3);
//
// Force a repaint after all the status text fields have been updated.
//
WidgetPaint(WIDGET_ROOT);
WidgetMessageQueueProcess();
}
//*****************************************************************************
//
// Handles the SysTick timeout interrupt.
//
//*****************************************************************************
void
SysTickIntHandler(void)
{
//
// Increment the tick count.
//
g_ui32TickCount++;
}
//*****************************************************************************
//
// This function returns the number of ticks since the last time this function
// was called.
//
//*****************************************************************************
uint32_t
GetTickms(void)
{
uint32_t ui32RetVal, ui32Saved;
ui32RetVal = g_ui32TickCount;
ui32Saved = ui32RetVal;
if(ui32Saved > g_ui32LastTick)
{
ui32RetVal = ui32Saved - g_ui32LastTick;
}
else
{
ui32RetVal = g_ui32LastTick - ui32Saved;
}
//
// This could miss a few milliseconds but the timings here are on a
// much larger scale.
//
g_ui32LastTick = ui32Saved;
//
// Return the number of milliseconds since the last time this was called.
//
return(ui32RetVal * MS_PER_SYSTICK);
}
//*****************************************************************************
//
// Callback function for USB OTG mode changes.
//
//*****************************************************************************
static void
ModeCallback(uint32_t ui32Index, tUSBMode iMode)
{
//
// Save the new mode.
//
g_iCurrentUSBMode = iMode;
//
// Mode-specific handling code could go here.
//
switch(iMode)
{
case eUSBModeHost:
{
break;
}
case eUSBModeDevice:
{
break;
}
case eUSBModeNone:
{
break;
}
default:
{
break;
}
}
}
//*****************************************************************************
//
// Gets the logger configuration from battery backed memory.
// The configuration is read from the memory in the Hibernate module.
// It is checked for validity. If found to be valid the function returns a
// 0. If not valid, then it returns non-zero.
//
//*****************************************************************************
static int32_t
GetSavedState(tConfigState *psState)
{
uint32_t ui32StateLen;
uint16_t ui16Crc16;
//
// Check the arguments
//
ASSERT(psState);
if(!psState)
{
return(1);
}
//
// Initialize locals.
//
ui32StateLen = sizeof(tConfigState) / 4;
//
// Read a block from hibernation memory into the application state
// structure.
//
HibernateDataGet((uint32_t *)psState, ui32StateLen);
//
// Check first to see if the "cookie" value is correct.
//
if(psState->ui32Cookie != STATE_COOKIE)
{
return(1);
}
//
// Find the 16-bit CRC of the block. The CRC is stored in the last
// location, so subtract 1 word from the count.
//
ui16Crc16 = ROM_Crc16Array(ui32StateLen - 1, (const uint32_t *)psState);
//
// If the CRC does not match, then the block is not good.
//
if(psState->ui32Crc16 != (uint32_t)ui16Crc16)
{
return(1);
}
//
// At this point the state structure that was retrieved from the
// battery backed memory has been validated, so return it as a valid
// logger state configuration.
//
return(0);
}
//*****************************************************************************
//
// Stores the logger configuration to battery backed memory in the
// Hibernation module. The configuration is saved with a cookie value and
// a CRC in order to ensure validity.
//
//*****************************************************************************
static void
SetSavedState(tConfigState *psState)
{
uint32_t ui32StateLen;
uint16_t ui16Crc16;
//
// Check the arguments.
//
ASSERT(psState);
//
// Initialize locals.
//
ui32StateLen = sizeof(tConfigState) / 4;
if(psState)
{
//
// Write the cookie value to the block
//
psState->ui32Cookie = STATE_COOKIE;
//
// Find the 16-bit CRC of the block. The CRC is stored in the last
// location, so subtract 1 word from the count.
//
ui16Crc16 = ROM_Crc16Array(ui32StateLen - 1,
(const uint32_t *)psState);
//
// Save the computed CRC into the structure.
//
psState->ui32Crc16 = (uint32_t)ui16Crc16;
//
// Now write the entire block to the Hibernate memory.
//
HibernateDataSet((uint32_t *)psState, ui32StateLen);
}
}
//*****************************************************************************
//
// Populate the application configuration with default values.
//
//*****************************************************************************
static void
GetDefaultState(tConfigState *psState)
{
//
// Check the arguments
//
ASSERT(psState);
if(psState)
{
//
// get the default values from the menu system
//
MenuGetDefaultState(psState);
//
// Set the filename to a null string
//
psState->pcFilename[0] = 0;
//
// Set bogus address for flash storage
//
psState->ui32FlashStore = 0;
//
// Turn off sleep logging
//
psState->ui32SleepLogging = 0;
}
}
//*****************************************************************************
//
// Sends a button press message to whichever widget has the button focus.
//
//*****************************************************************************
static void
SendWidgetKeyMessage(uint32_t ui32Msg)
{
WidgetMessageQueueAdd(WIDGET_ROOT, ui32Msg, g_ui32KeyFocusWidgetHandle, 0,
1, 1);
}
//*****************************************************************************
//
// Callback function from the menu widget. This function is called whenever
// the menu is used to activate a child widget that is associated with the
// menu. It is also called when the widget is deactivated and control is
// returned to the menu widget. It can be used to trigger different actions
// depending on which menus are chosen, and to track the state of the
// application and control focus for the user interface.
//
// This function is called in the context of widget tree message processing
// so care should be taken if doing any operation that affects the display
// or widget tree.
//
//*****************************************************************************
static void
WidgetActivated(tWidget *psWidget, tSlideMenuItem *psMenuItem, bool bActivated)
{
char *pcMenuText;
uint32_t ui32RTC;
//
// Handle the activation or deactivation of the strip chart. The strip
// chart widget is activated when the user selects the START menu.
//
if(psWidget == &g_sStripChart.sBase)
{
//
// If the strip chart is activated, start the logger running.
//
if(bActivated)
{
//
// Get the current state of the menus
//
MenuGetState(&g_sConfigState);
//
// Save the state in battery backed memory
//
SetSavedState(&g_sConfigState);
//
// Start logger and update the logger state
//
AcquireStart(&g_sConfigState);
g_iLoggerState = eSTATE_LOGGING;
}
else
{
//
// If the strip chart is deactivated, stop the logger.
//
AcquireStop();
g_iLoggerState = eSTATE_IDLE;
}
}
else if((psWidget == &g_sAINContainerCanvas.sBase) ||
(psWidget == &g_sAccelContainerCanvas.sBase) ||
(psWidget == &g_sCurrentContainerCanvas.sBase) ||
(psWidget == &g_sClockContainerCanvas.sBase) ||
(psWidget == &g_sTempContainerCanvas.sBase) ||
(psWidget == &g_sGyroContainerCanvas.sBase) ||
(psWidget == &g_sMagContainerCanvas.sBase))
{
//
// Handle the activation or deactivation of any of the container
// canvas that is used for showing the acquired data as a numerical
// display. This happens when the VIEW menu is used.
//
// A viewer has been activated.
//
if(bActivated)
{
static tConfigState sLocalState;
//
// Get the current menu configuration state and save it in a local
// storage.
//
MenuGetState(&sLocalState);
//
// Modify the state to set values that are suitable for using
// with the viewer. The acquisition rate is set to 1/2 second
// and all channels are selected. The storage medium is set to
// "viewer" so the acquistion module will write the value of
// acquired data to the appropriate viewing canvas.
//
sLocalState.ui8Storage = CONFIG_STORAGE_VIEWER;
sLocalState.ui32Period = 0x00000040;
sLocalState.ui16SelectedMask = 0xffff;
//
// Start the acquisition module running.
//
AcquireStart(&sLocalState);
g_iLoggerState = eSTATE_VIEWING;
}
else
{
//
// The viewer has been deactivated so turn off the acquisition
// module.
//
AcquireStop();
g_iLoggerState = eSTATE_IDLE;
}
}
else if(psWidget == &g_sStatusContainerCanvas.sBase)
{
//
// Handle the case when a status display has been activated. This can
// occur when any of several menu items are selected.
//
// Get pointer to the text of the current menu item.
//
if(psMenuItem)
{
pcMenuText = psMenuItem->pcText;
}
else
{
return;
}
//
// If activated from the SAVE menu, then the flash data needs to be
// saved to USB stick. Enter the saving state.
//
if(!strcmp(pcMenuText, "SAVE"))
{
if(bActivated)
{
g_iLoggerState = eSTATE_SAVING;
}
else
{
g_iLoggerState = eSTATE_IDLE;
}
}
else if(!strcmp(pcMenuText, "ERASE DATA?"))
{
//
// If activated from the ERASE menu, then the flash data needs to
// be erased. Enter the erasing state.
//
if(bActivated)
{
g_iLoggerState = eSTATE_ERASING;
}
else
{
g_iLoggerState = eSTATE_IDLE;
}
}
else if(!strcmp(pcMenuText, "FLASH SPACE"))
{
//
// If activated from the FLASH SPACE menu, then the user will be
// shown a report on the amount of free space in flash. Enter the
// reporting state.
//
if(bActivated)
{
g_iLoggerState = eSTATE_FREEFLASH;
}
else
{
g_iLoggerState = eSTATE_IDLE;
}
}
}
else if(psWidget == &g_sClockSetter.sBase)
{
//
// Handle the activation of the clock setting widget. Deactivation is
// handled through a separate callback.
//
// If the clock setter is activated, load the time structure fields.
//
if(bActivated)
{
//
// Get the current time in seconds from the RTC.
//
ui32RTC = HibernateRTCGet();
//
// Convert the RTC time to a time structure.
//
ulocaltime(ui32RTC, &g_sTimeClock);
//
// Set the callback that will be called when the clock setting
// widget is deactivated. Since the clock setting widget needs
// to take over the focus for button events, it uses a separate
// callback when it is finsihed.
//
ClockSetCallbackSet((tClockSetWidget *)psWidget,
ClockSetOkCallback);
//
// Give the clock setter widget focus for the button events
//
g_ui32KeyFocusWidgetHandle = (uint32_t)psWidget;
g_iLoggerState = eSTATE_CLOCKSET;
}
}
}
//*****************************************************************************
//
// This function is called when the user clicks OK or CANCEL in the clock
// setting widget.
//
//*****************************************************************************
static void
ClockSetOkCallback(tWidget *psWidget, bool bOk)
{
uint32_t ui32RTC;
//
// Only update the RTC if the OK button was selected.
//
if(bOk)
{
//
// Convert the time structure that was altered by the clock setting
// widget into seconds.
//
ui32RTC = umktime(&g_sTimeClock);
//
// If the conversion was valid, then write the updated clock to the
// Hibernate RTC.
//
if(ui32RTC != (uint32_t)(-1))
{
HibernateRTCSet(ui32RTC);
}
}
//
// Set the state to clock exit so some cleanup can be done from the
// main loop.
//
g_iLoggerState = eSTATE_CLOCKEXIT;
}
//*****************************************************************************
//
// CheckBoardRevision uses PD1 with a weak pull down resistor to detect the
// development board hardware revision. Code for the LM4F board can run on the
// TM4C, but not vice versa. This function checks for the board verion and
// warns the user if they are using the wrong board / software.
//
// The EK-LM4F232 (green) board uses an analog accelorometer. The DK-TM4C123G
//(red) board uses a digitial I2C 9 axis accel, mag, gyro.
//
//*****************************************************************************
void
CheckBoardRevision(void)
{
uint32_t ui32BoardType;
tContext sDisplayContext;
//
// Check if board is TM4C123G (red) or LM4F232 (green). This code
// should not be run on green board.
//
MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
MAP_GPIODirModeSet(GPIO_PORTD_BASE, GPIO_PIN_1, GPIO_DIR_MODE_IN);
MAP_GPIOPadConfigSet(GPIO_PORTD_BASE, GPIO_PIN_1,
GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD_WPD);
ui32BoardType=MAP_GPIOPinRead(GPIO_PORTD_BASE, GPIO_PIN_1);
if(ui32BoardType==0)
{
//
// The board is green, print error message and hang.
//
CFAL96x64x16Init();
GrContextInit(&sDisplayContext, &g_sCFAL96x64x16);
GrContextForegroundSet(&sDisplayContext, ClrWhite);
GrContextFontSet(&sDisplayContext, g_psFontFixed6x8);
GrStringDrawCentered(&sDisplayContext, "ERROR:", -1,
GrContextDpyWidthGet(&sDisplayContext) / 2, 4, 0);
GrStringDrawCentered(&sDisplayContext, "Due to different", -1,
GrContextDpyWidthGet(&sDisplayContext) / 2, 20, false);
GrStringDrawCentered(&sDisplayContext, "hardware this", -1,
GrContextDpyWidthGet(&sDisplayContext) / 2, 30, false);
GrStringDrawCentered(&sDisplayContext, "code cannot run", -1,
GrContextDpyWidthGet(&sDisplayContext) / 2, 40, false);
GrStringDrawCentered(&sDisplayContext, "on this board", -1,
GrContextDpyWidthGet(&sDisplayContext) / 2, 50, false);
GrStringDrawCentered(&sDisplayContext, "Try diff code.", -1,
GrContextDpyWidthGet(&sDisplayContext) / 2, 60, false);
while(1)
{
// Hang here.
}
}
else
{
//
// The board is red, exit & continue as normal.
//
return ;
}
}
//*****************************************************************************
//
// Initialize and operate the data logger.
//
//*****************************************************************************
int
main(void)
{
tContext sDisplayContext, sBufferContext;
uint32_t ui32HibIntStatus, ui32SysClock, ui32LastTickCount;
bool bSkipSplash;
uint8_t ui8ButtonState, ui8ButtonChanged;
uint_fast8_t ui8X, ui8Y;
//
// Enable lazy stacking for interrupt handlers. This allows floating-point
// instructions to be used within interrupt handlers, but at the expense of
// extra stack usage.
//
MAP_FPULazyStackingEnable();
//
// Set the clocking to run at 50 MHz.
//
MAP_SysCtlClockSet(SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | SYSCTL_XTAL_16MHZ |
SYSCTL_OSC_MAIN);
ui32SysClock = MAP_SysCtlClockGet();
//
// Initialize locals.
//
bSkipSplash = false;
ui32LastTickCount = 0;
//
// Check Board Revision, report if software / hardware are incompatible
//
CheckBoardRevision();
//
// Initialize the data acquisition module. This initializes the ADC
// hardware.
//
AcquireInit();
// Enable interrupts to the processor.
//
ROM_IntMasterEnable();
//
// Enable access to the hibernate peripheral. If the hibernate peripheral
// was already running then this will have no effect.
//
MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_HIBERNATE);
//
// Check to see if the hiberate module is already active and if so then
// read the saved configuration state. If both are okay, then proceed
// to check and see if we are logging data using sleep mode.
//
if(HibernateIsActive() && !GetSavedState(&g_sConfigState))
{
//
// Read the status of the hibernate module.
//
ui32HibIntStatus = HibernateIntStatus(1);
//
// If this is a pin wake, that means the user pressed the select
// button and we should terminate the sleep logging. In this case
// we will fall out of this conditional section, and go through the
// normal startup below, but skipping the splash screen so the user
// gets immediate response.
//
if(ui32HibIntStatus & HIBERNATE_INT_PIN_WAKE)
{
//
// Clear the interrupt flag so it is not seen again until another
// wake.
//
HibernateIntClear(HIBERNATE_INT_PIN_WAKE);
bSkipSplash = true;
}
//
// Otherwise if we are waking from hibernate and it was not a pin
// wake, then it must be from RTC match. Check to see if we are
// sleep logging and if so then go through an abbreviated startup
// in order to collect the data and go back to sleep.
//
else if(g_sConfigState.ui32SleepLogging &&
(ui32HibIntStatus & HIBERNATE_INT_RTC_MATCH_0))
{
//
// Start logger and pass the configuration. The logger should
// configure itself to take one sample.
//
AcquireStart(&g_sConfigState);
g_iLoggerState = eSTATE_LOGGING;
//
// Enter a forever loop to run the acquisition. This will run
// until a new sample has been taken and stored.
//
while(!AcquireRun())
{
}
//
// Getting here means that a data acquisition was performed and we
// can now go back to sleep. Save the configuration and then
// activate the hibernate.
//
SetSavedState(&g_sConfigState);
//
// Set wake condition on pin-wake or RTC match. Then put the
// processor in hibernation.
//
HibernateWakeSet(HIBERNATE_WAKE_PIN | HIBERNATE_WAKE_RTC);
HibernateRequest();
//
// Hibernating takes a finite amount of time to occur, so wait
// here forever until hibernate activates and the processor
// power is removed.
//
for(;;)
{
}
}
//
// Otherwise, this was not a pin wake, and we were not sleep logging,
// so just fall out of this conditional and go through the normal
// startup below.
//
}
else
{
//
// In this case, either the hibernate module was not already active, or
// the saved configuration was not valid. Initialize the configuration
// to the default state and then go through the normal startup below.
//
GetDefaultState(&g_sConfigState);
}
//
// Enable the Hibernate module to run.
//
HibernateEnableExpClk(SysCtlClockGet());
//
// The hibernate peripheral trim register must be set per silicon
// erratum 2.1
//
HibernateRTCTrimSet(0x7FFF);
//
// Start the RTC running. If it was already running then this will have
// no effect.
//
HibernateRTCEnable();
//
// In case we were sleep logging and are now finished (due to user
// pressing select button), then disable sleep logging so it doesnt
// try to start up again.
//
g_sConfigState.ui32SleepLogging = 0;
SetSavedState(&g_sConfigState);
//
// Initialize the display driver.
//
CFAL96x64x16Init();
//
// Initialize the buttons driver.
//
ButtonsInit();
//
// Pass the restored state to the menu system.
//
MenuSetState(&g_sConfigState);
//
// Enable the USB peripheral
//
MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_USB0);
//
// Configure the required pins for USB operation.
//
MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOG);
MAP_GPIOPinConfigure(GPIO_PG4_USB0EPEN);
MAP_GPIOPinTypeUSBDigital(GPIO_PORTG_BASE, GPIO_PIN_4);
MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOL);
MAP_GPIOPinTypeUSBAnalog(GPIO_PORTL_BASE, GPIO_PIN_6 | GPIO_PIN_7);
MAP_GPIOPinTypeUSBAnalog(GPIO_PORTB_BASE, GPIO_PIN_0 | GPIO_PIN_1);
//
// Erratum workaround for silicon revision A1. VBUS must have pull-down.
//
if(CLASS_IS_TM4C123 && REVISION_IS_A1)
{
HWREG(GPIO_PORTB_BASE + GPIO_O_PDR) |= GPIO_PIN_1;
}
//
// Initialize the USB stack mode and pass in a mode callback.
//
USBStackModeSet(0, eUSBModeOTG, ModeCallback);
//
// Initialize the stack to be used with USB stick.
//
USBStickInit();
//
// Initialize the stack to be used as a serial device.
//
USBSerialInit();
//
// Initialize the USB controller for dual mode operation with a 2ms polling
// rate.
//
USBOTGModeInit(0, 2000, g_pui8HCDPool, HCD_MEMORY_SIZE);
//
// Initialize the menus module. This module will control the user
// interface menuing system.
//
MenuInit(WidgetActivated);
//
// Configure SysTick to periodically interrupt.
//
g_ui32TickCount = 0;
MAP_SysTickPeriodSet(ui32SysClock / CLOCK_RATE);
MAP_SysTickIntEnable();
MAP_SysTickEnable();
//
// Initialize the display context and another context that is used
// as an offscreen drawing buffer for display animation effect
//
GrContextInit(&sDisplayContext, &g_sCFAL96x64x16);
GrContextInit(&sBufferContext, &g_sOffscreenDisplayA);
//
// Show the splash screen if we are not skipping it. The only reason to
// skip it is if the application was in sleep-logging mode and the user
// just waked it up with the select button.
//
if(!bSkipSplash)
{
const uint8_t *pui8SplashLogo = g_pui8Image_TI_Black;
//
// Draw the TI logo on the display. Use an animation effect where the
// logo will "slide" onto the screen. Allow select button to break
// out of animation.
//
for(ui8X = 0; ui8X < 96; ui8X++)
{
if(ButtonsPoll(0, 0) & SELECT_BUTTON)
{
break;
}
GrImageDraw(&sDisplayContext, pui8SplashLogo, 95 - ui8X, 0);
}
//
// Leave the logo on the screen for a long duration. Monitor the
// buttons so that if the user presses the select button, the logo
// display is terminated and the application starts immediately.
//
while(g_ui32TickCount < 400)
{
if(ButtonsPoll(0, 0) & SELECT_BUTTON)
{
break;
}
}
//
// Extended splash sequence
//
if(ButtonsPoll(0, 0) & UP_BUTTON)
{
for(ui8X = 0; ui8X < 96; ui8X += 4)
{
GrImageDraw(&sDisplayContext,
g_ppui8Image_Splash[(ui8X / 4) & 3],
(int32_t)ui8X - 96L, 0);
GrImageDraw(&sDisplayContext, pui8SplashLogo, ui8X, 0);
MAP_SysCtlDelay(ui32SysClock / 12);
}
MAP_SysCtlDelay(ui32SysClock / 3);
pui8SplashLogo = g_ppui8Image_Splash[4];
GrImageDraw(&sDisplayContext, pui8SplashLogo, 0, 0);
MAP_SysCtlDelay(ui32SysClock / 12);
}
//
// Draw the initial menu into the offscreen buffer.
//
SlideMenuDraw(&g_sMenuWidget, &sBufferContext, 0);
//
// Now, draw both the TI logo splash screen (from above) and the initial
// menu on the screen at the same time, moving the coordinates so that
// the logo "slides" off the display and the menu "slides" onto the
// display.
//
for(ui8Y = 0; ui8Y < 64; ui8Y++)
{
GrImageDraw(&sDisplayContext, pui8SplashLogo, 0, -ui8Y);
GrImageDraw(&sDisplayContext, g_pui8OffscreenBufA, 0, 63 - ui8Y);
}
}
//
// Add the menu widget to the widget tree and send an initial paint
// request.
//
WidgetAdd(WIDGET_ROOT, (tWidget *)&g_sMenuWidget);
WidgetPaint(WIDGET_ROOT);
//
// Set the focus handle to the menu widget. Any button events will be
// sent to this widget
//
g_ui32KeyFocusWidgetHandle = (uint32_t)&g_sMenuWidget;
//
// Forever loop to run the application
//
while(1)
{
//
// Each time the timer tick occurs, process any button events.
//
if(g_ui32TickCount != ui32LastTickCount)
{
//
// Remember last tick count
//
ui32LastTickCount = g_ui32TickCount;
//
// Read the debounced state of the buttons.
//
ui8ButtonState = ButtonsPoll(&ui8ButtonChanged, 0);
//
// Pass any button presses through to the widget message
// processing mechanism. The widget that has the button event
// focus (probably the menu widget) will catch these button events.
//
if(BUTTON_PRESSED(SELECT_BUTTON, ui8ButtonState, ui8ButtonChanged))
{
SendWidgetKeyMessage(WIDGET_MSG_KEY_SELECT);
}
if(BUTTON_PRESSED(UP_BUTTON, ui8ButtonState, ui8ButtonChanged))
{
SendWidgetKeyMessage(WIDGET_MSG_KEY_UP);
}
if(BUTTON_PRESSED(DOWN_BUTTON, ui8ButtonState, ui8ButtonChanged))
{
SendWidgetKeyMessage(WIDGET_MSG_KEY_DOWN);
}
if(BUTTON_PRESSED(LEFT_BUTTON, ui8ButtonState, ui8ButtonChanged))
{
SendWidgetKeyMessage(WIDGET_MSG_KEY_LEFT);
}
if(BUTTON_PRESSED(RIGHT_BUTTON, ui8ButtonState, ui8ButtonChanged))
{
SendWidgetKeyMessage(WIDGET_MSG_KEY_RIGHT);
}
}
//
// Tell the OTG library code how much time has passed in milliseconds
// since the last call.
//
USBOTGMain(GetTickms());
//
// Call functions as needed to keep the host or device mode running.
//
if(g_iCurrentUSBMode == eUSBModeDevice)
{
USBSerialRun();
}
else if(g_iCurrentUSBMode == eUSBModeHost)
{
USBStickRun();
}
//
// If in the logging state, then call the logger run function. This
// keeps the data acquisition running.
//
if((g_iLoggerState == eSTATE_LOGGING) ||
(g_iLoggerState == eSTATE_VIEWING))
{
if(AcquireRun() && g_sConfigState.ui32SleepLogging)
{
//
// If sleep logging is enabled, then at this point we have
// stored the first data item, now save the state and start
// hibernation. Wait for the power to be cut.
//
SetSavedState(&g_sConfigState);
HibernateWakeSet(HIBERNATE_WAKE_PIN | HIBERNATE_WAKE_RTC);
HibernateRequest();
for(;;)
{
}
}
//
// If viewing instead of logging then request a repaint to keep
// the viewing window updated.
//
if(g_iLoggerState == eSTATE_VIEWING)
{
WidgetPaint(WIDGET_ROOT);
}
}
//
// If in the saving state, then save data from flash storage to
// USB stick.
//
if(g_iLoggerState == eSTATE_SAVING)
{
//
// Save data from flash to USB
//
FlashStoreSave();
//
// Return to idle state
//
g_iLoggerState = eSTATE_IDLE;
}
//
// If in the erasing state, then erase the data stored in flash.
//
if(g_iLoggerState == eSTATE_ERASING)
{
//
// Save data from flash to USB
//
FlashStoreErase();
//
// Return to idle state
//
g_iLoggerState = eSTATE_IDLE;
}
//
// If in the flash reporting state, then show the report of the amount
// of used and free flash memory.
//
if(g_iLoggerState == eSTATE_FREEFLASH)
{
//
// Report free flash space
//
FlashStoreReport();
//
// Return to idle state
//
g_iLoggerState = eSTATE_IDLE;
}
//
// If we are exiting the clock setting widget, that means that control
// needs to be given back to the menu system.
//
if(g_iLoggerState == eSTATE_CLOCKEXIT)
{
//
// Give the button event focus back to the menu system
//
g_ui32KeyFocusWidgetHandle = (uint32_t)&g_sMenuWidget;
//
// Send a button event to the menu widget that means the left
// key was pressed. This signals the menu widget to deactivate
// the current child widget (which was the clock setting wigdet).
// This will cause the menu widget to slide the clock set widget
// off the screen and resume control of the display.
//
SendWidgetKeyMessage(WIDGET_MSG_KEY_LEFT);
g_iLoggerState = eSTATE_IDLE;
}
//
// Process any new messages that are in the widget queue. This keeps
// the user interface running.
//
WidgetMessageQueueProcess();
}
}
|