1 /*
2 * Copyright (c) 2015, Freescale Semiconductor, Inc.
3 * Copyright 2016-2017 NXP
4 * All rights reserved.
5 *
6 * SPDX-License-Identifier: BSD-3-Clause
7 */
8
9 /*! \file status.c
10 \brief Application-specific status subsystem
11
12 Applications may change how they choose to display status information.
13 The default implementation here uses LEDs on NXP Freedom boards.
14 You may swap out implementations as long as the "Required" methods and states
15 are retained.
16 */
17
18 #include "board.h" // KSDK HAL
19 #ifndef CPU_LPC54114J256BD64_cm4
20 #include "fsl_port.h" // KSDK Port Module Interface
21 #endif
22 #include "sensor_fusion.h" // Sensor fusion structures and functions
23 #include "drivers.h" // Common driver header file
24 #include "status.h" // Header for this .c file
25
26 // bit-field definitions
27 #define N 0x00 // No color
28 #define R 0x04 // Red LED
29 #define G 0x02 // Green LED
30 #define B 0x01 // Blue LED
31
32 // set RGB LED as a function of bit-field values
ssSetLeds(int8_t RGB)33 void ssSetLeds(int8_t RGB)
34 {
35 if (RGB & R)
36 LED_RED_ON();
37 else
38 LED_RED_OFF();
39 if (RGB & G)
40 LED_GREEN_ON();
41 else
42 LED_GREEN_OFF();
43 if (RGB & B)
44 LED_BLUE_ON();
45 else
46 LED_BLUE_OFF();
47 }
48
49 // Do an immediate status update
ssSetStatusNow(StatusSubsystem * pStatus,fusion_status_t status)50 void ssSetStatusNow(StatusSubsystem *pStatus, fusion_status_t status)
51 {
52 pStatus->status = status;
53 pStatus->next = status;
54
55 uint8_t blink = false;
56 uint8_t RGB = N;
57
58 // This is where we actually change the visual indicator
59 // We are not using the blue LED because it is not available on some
60 // board combinations.
61 switch (status)
62 {
63 case INITIALIZING: // solid GREEN
64 RGB = G;
65 break;
66 case NORMAL: // blinking GREEN
67 RGB = G;
68 blink = true;
69 break;
70 case LOWPOWER: // blinking YELLOW
71 RGB = R|G;
72 blink = true;
73 break;
74 case SOFT_FAULT: // solid RED (usually momentary)
75 case HARD_FAULT: // solid RED
76 RGB = R;
77 break;
78 default: // default = off;
79 RGB = N;
80 }
81
82 if ((!blink) | (status != pStatus->previous))
83 {
84 ssSetLeds(RGB);
85 pStatus->toggle = true;
86 }
87 else
88 {
89 if (pStatus->toggle)
90 {
91 ssSetLeds(N);
92 }
93 else
94 {
95 ssSetLeds(RGB);
96 }
97
98 pStatus->toggle = !pStatus->toggle;
99 }
100 while (status == HARD_FAULT) ; // Never return on hard fault
101 // while (status == SOFT_FAULT) ; // DEBUG ONLY Never return on soft fault
102 }
103
104 // Unit test for status sub-system
ssTest(StatusSubsystem * pStatus)105 void ssTest(StatusSubsystem *pStatus)
106 {
107 switch (pStatus->status)
108 {
109 case OFF:
110 ssSetStatusNow(pStatus, INITIALIZING);
111 break;
112 case INITIALIZING:
113 ssSetStatusNow(pStatus, LOWPOWER);
114 break;
115 case LOWPOWER:
116 ssSetStatusNow(pStatus, NORMAL);
117 break;
118 case NORMAL:
119 ssSetStatusNow(pStatus, RECEIVING_WIRED);
120 break;
121 case RECEIVING_WIRED:
122 ssSetStatusNow(pStatus, RECEIVING_WIRELESS);
123 break;
124 case RECEIVING_WIRELESS:
125 ssSetStatusNow(pStatus, SOFT_FAULT);
126 break;
127 case SOFT_FAULT:
128 ssSetStatusNow(pStatus, HARD_FAULT);
129 break;
130 case HARD_FAULT:
131 ssSetStatusNow(pStatus, OFF);
132 break;
133 }
134 }
135
136 // undefine these just in case some other library needs them
137 #undef N
138 #undef R
139 #undef G
140 #undef B
141
142
143 // queue up a status change (which will take place at the next updateStatus)
ssQueueStatus(StatusSubsystem * pStatus,fusion_status_t status)144 void ssQueueStatus(StatusSubsystem *pStatus, fusion_status_t status)
145 {
146 pStatus->next = status;
147 }
148
149 // promote any previously queued status update
ssUpdateStatus(StatusSubsystem * pStatus)150 void ssUpdateStatus(StatusSubsystem *pStatus)
151 {
152 pStatus->previous = pStatus->status;
153 ssSetStatusNow(pStatus, pStatus->next);
154 }
155
156 // make an immediate update to the system status
ssSetStatus(StatusSubsystem * pStatus,fusion_status_t status)157 void ssSetStatus(StatusSubsystem *pStatus, fusion_status_t status)
158 {
159 pStatus->next = status;
160 ssUpdateStatus(pStatus);
161 }
162
163 /// initializeStatusSubsystem() should be called once at startup to initialize the
164 /// data structure and to put hardware into the proper state for communicating status.
initializeStatusSubsystem(StatusSubsystem * pStatus)165 void initializeStatusSubsystem(StatusSubsystem *pStatus)
166 {
167 pStatus->set = ssSetStatus;
168 pStatus->queue = ssQueueStatus;
169 pStatus->update = ssUpdateStatus;
170 pStatus->test = ssTest;
171 pStatus->previous = OFF;
172 pStatus->set(pStatus, OFF);
173 pStatus->queue(pStatus, OFF);
174 pStatus->toggle = false;
175
176 /* Un-gate the port clocks */
177 CLOCK_EnableClock(RED_LED.clockName);
178 CLOCK_EnableClock(GREEN_LED.clockName);
179 //CLOCK_EnableClock(BLUE_LED.clockName);
180 #ifndef CPU_LPC54114J256BD64_cm4
181 // Not needed for the LPC54114 (done elsewhere)
182 // Led pin mux Configuration
183 PORT_SetPinMux(BOARD_LED_RED_GPIO_PORT, BOARD_LED_RED_GPIO_PIN,
184 kPORT_MuxAsGpio);
185 PORT_SetPinMux(BOARD_LED_GREEN_GPIO_PORT, BOARD_LED_GREEN_GPIO_PIN,
186 kPORT_MuxAsGpio);
187 #endif
188 /* set initial values */
189 LED_RED_INIT(LOGIC_LED_OFF);
190 LED_GREEN_INIT(LOGIC_LED_OFF);
191 }
192