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