MCCI Trusted Bootloader
Simple trusted bootloader and tools for small embedded systems
mccibootloader_led_annunciator.c
Go to the documentation of this file.
1/*
2
3Module: mccibootloaderboard_led_annunciator.c
4
5Function:
6 Hardaware-independent Annunciator (LED flashing) library functions.
7
8Copyright notice:
9 This file copyright (C) 2026 by
10
11 MCCI Corporation
12 3520 Krums Corners Road
13 Ithaca, NY 14850
14
15 See accompanying LICENSE file for copyright and license information.
16
17Author:
18 Terry Moore, MCCI Corporation March 2026
19
20*/
21
23␌
24/****************************************************************************\
25|
26| Manifest constants & typedefs.
27|
28\****************************************************************************/
29
30/****************************************************************************\
31|
32| Read-only data.
33|
34\****************************************************************************/
35
36/****************************************************************************\
37|
38| Variables.
39|
40\****************************************************************************/
41
42static McciBootloader_LED_Annunciator_t annunciator;
43
44␌
45/*
46
47Name: McciBootloader_LED_annunciatorInit()
48
49Function:
50 Initialize the opt-in annunciator framework.
51
52Definition:
53 void McciBootloader_LED_annunciatorInit(
54 void
55 );
56
57Description:
58 Set up the FSM that can be used to control a LED that displays system
59 boot status.
60
61Returns:
62 No explicit result
63
64Notes:
65 Doesn't actually touch hardware.
66
67*/
68
69#define FUNCTION "McciBootloader_LED_annunciatorInit"
70
71void
73 void
74 )
75 {
76 annunciator.bittime = 100; // 100 ms per bit.
78 }
79
80#undef FUNCTION
81␌
82/*
83
84Name: McciBootloader_LED_annunciatorIndicateState()
85
86Function:
87 Pass the bootloader state to the annunciator FSM.
88
89Definition:
90 void McciBootloader_LED_annunciatorIndicateState(
91 McciBootloaderState_t state
92 );
93
94Description:
95 Boards that use the McciBootloader_LED framework call this function in
96 response to a bootloader state change. This function just modifies
97 software state; hardware updates are done based on systick.
98
99 If state is zero, the LED is turned off. Otherwise, state is interpreted
100 as a number and scheduled for bit-serial display based on clock
101 interrupts. Numbers are displayed using long flashes for 1, short
102 flashes for 0. Leading zeroes are suppressed. The number is displayed
103 over and over until changed by another call to this routine.
104
105Returns:
106 No explicit result.
107
108Notes:
109 Normally this is called as a result of a call to the platform
110 Annunciator.pIndicateState function.
111
112*/
113
114#define FUNCTION "McciBootloader_LED_annunciatorIndicateState"
115
116void
119 )
120 {
121 if (state != 0)
122 {
123 uint32_t display = ((uint32_t)state << 1) | 1;
124 unsigned nBits;
125 // always put at least 2 bits
126 for (nBits = 31; nBits > 2; --nBits)
127 {
128 if (display & (UINT32_C(1) << nBits))
129 break;
130 }
131
132 // if display is 2^k-1, then add a bit, so we have
133 // a time contrast on long pulses.
134 if (((display + 1) & display) == 0)
135 ++nBits;
136
137 annunciator.display = (uint32_t)display << (31 - nBits);
138 }
139 else
140 annunciator.display = 0;
141 }
142
143#undef FUNCTION
144
145///
146/// @brief process the next bit from the current word, and set timers
147/// @return \c true if the there was a next bit to process, otherwise \c false
148///
149/// @details
150/// ::timer is set to go off in either 1 or 3 bit times, depending on
151/// whether the next bit is a 1 or a 0.
152///
153/// If this routine returns true, the caller should light the LED, which
154/// should not be on. Otherwise, leave the LED off.
155///
156static bool
158 {
159 const bool fNextBit = !!(annunciator.value & UINT32_C(0x80000000));
160
161 annunciator.value <<= 1;
162 if (annunciator.value == 0)
163 return false;
164
165 annunciator.timer = annunciator.tick + annunciator.bittime * (1 + 2 * fNextBit);
166 return true;
167 }
168
169bool
171 void
172 )
173 {
174 const uint32_t now = annunciator.tick + 1;
175
176 annunciator.tick = now;
179
180 switch (annunciator.bitState)
181 {
182 default:
186 return false;
187
188 // in this state, nothing is being displayed
190 // if someone sets ::display non zero, we start displayign
191 if (annunciator.display != 0)
192 {
193 annunciator.value = annunciator.display;
194 if (nextBit())
195 {
197 }
198 }
199 break;
200
202 if ((int32_t)(now - annunciator.timer) >= 0)
203 {
204 annunciator.timer = now + annunciator.bittime;
206 }
207 break;
208
210 if ((int32_t)(now - annunciator.timer) >= 0)
211 {
212 if (nextBit())
213 {
215 }
216 else
217 {
219 annunciator.timer = now + 2 * annunciator.bittime;
220 }
221 }
222 break;
223
225 if ((int32_t)(now - annunciator.timer) >= 0)
226 {
227 annunciator.value = annunciator.display;
228 if (nextBit())
230 else
231 {
233 }
234 }
235 break;
236 }
237
239 annunciator.bitState = nextState;
240
242 }
McciBootloader_LED_AnnunciatorBitState_t
The states of the Bootloader LED finite state machine.
@ McciBootloader_LED_Annunciator_stNoChange
internal: don't change state.
@ McciBootloader_LED_Annunciator_stByteGap
displaying byte gap
@ McciBootloader_LED_Annunciator_stInitial
not initialized
@ McciBootloader_LED_Annunciator_stLedOn
light is on
@ McciBootloader_LED_Annunciator_stBitGap
displaying bit gap
@ McciBootloader_LED_Annunciator_stIdle
not displaying
uint32_t McciBootloaderState_t
Current boot system state.
void McciBootloader_LED_annunciatorIndicateState(McciBootloaderState_t state)
static McciBootloader_LED_Annunciator_t annunciator
void McciBootloader_LED_annunciatorInit(void)
static bool nextBit(void)
process the next bit from the current word, and set timers
bool McciBootloader_LED_handleSysTick(void)