Add boot self-test and idle indicator; target the Waveshare RP2350-Plus
The board arriving is a Waveshare RP2350-Plus (4MB, USB-C), which is now the default BOARD. Its pico-sdk header defines neither PICO_DEFAULT_LED_PIN nor PICO_DEFAULT_WS2812_PIN - it has no onboard indicator at all - so a bare board gives no sign of life. The status-LED support added for boards that do have one (zero, one, tiny, usb_a on GPIO16; eth on GPIO25) is kept and compiles out here. That makes feedback on the strip itself the useful path, and it turns out to be the better one anyway: - Boot self-test sweeps one pixel from index 0 to the far end once at startup. It answers in a single glance whether the firmware runs, PIO drives the line, the strip is the length LED_COUNT claims, the far end holds voltage, and - because you see which end it starts from - whether STRIP_REVERSED is right. It runs before USB, so the first test needs nothing but 5V. - Idle indicator holds one dim pixel lit while no host is connected, separating "powered and waiting" from "no power" and from "crashed". Both are platform-independent, so the Circle build gets them too. Verified: tests pass across seventeen configurations, now including the self-test and idle paths on and off. Both platforms build clean with no warnings from project sources. Note on the previous commit's verification: a filtered build log hid a real compile error in the Pico target (sleep_ms takes uint32_t, which is unsigned long here, and did not match the portable void(*)(unsigned) delay callback). The build script now gets an explicit success check rather than a grep. Claude-Session: https://claude.ai/code/session_01TVCB25LBsmeteWvaSMz4Ne
This commit is contained in:
+86
-2
@@ -15,6 +15,60 @@
|
||||
static CPicoLEDStrip s_Strip (LED_COUNT, WS2812_PIN);
|
||||
static CPianoLEDs s_PianoLEDs (s_Strip);
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Status indicator
|
||||
// --------------------------------------------------------------------------
|
||||
//
|
||||
// Most Waveshare RP2350 boards have an onboard WS2812 rather than a plain LED,
|
||||
// and the board header names the pin. Where it exists, it is the only feedback
|
||||
// this headless board has: it answers "did the firmware boot" and "did the host
|
||||
// enumerate us" before the strip is even wired.
|
||||
|
||||
#if STATUS_LED_ENABLED && defined(PICO_DEFAULT_WS2812_PIN)
|
||||
#define HAVE_STATUS_LED 1
|
||||
|
||||
static CPicoLEDStrip s_Status (1, PICO_DEFAULT_WS2812_PIN);
|
||||
|
||||
enum TStatus
|
||||
{
|
||||
StatusFault, // strip did not initialise
|
||||
StatusWaiting, // no USB host yet
|
||||
StatusReady, // enumerated, running normally
|
||||
StatusCalibrating // a calibration pattern is active
|
||||
};
|
||||
|
||||
static TStatus s_LastStatus = StatusFault;
|
||||
static bool s_bStatusValid = false;
|
||||
|
||||
static void ShowStatus (TStatus Status)
|
||||
{
|
||||
if ( s_bStatusValid
|
||||
&& Status == s_LastStatus)
|
||||
{
|
||||
return; // only touch the LED when it changes
|
||||
}
|
||||
|
||||
const uint8_t B = STATUS_LED_BRIGHTNESS;
|
||||
|
||||
switch (Status)
|
||||
{
|
||||
case StatusFault: s_Status.SetLED (0, B, 0, 0); break;
|
||||
case StatusWaiting: s_Status.SetLED (0, B, B / 2, 0); break;
|
||||
case StatusReady: s_Status.SetLED (0, 0, B, 0); break;
|
||||
case StatusCalibrating: s_Status.SetLED (0, 0, 0, B); break;
|
||||
}
|
||||
|
||||
s_Status.Update ();
|
||||
|
||||
s_LastStatus = Status;
|
||||
s_bStatusValid = true;
|
||||
}
|
||||
#else
|
||||
#define HAVE_STATUS_LED 0
|
||||
static void ShowStatus (int) {}
|
||||
enum { StatusFault, StatusWaiting, StatusReady, StatusCalibrating };
|
||||
#endif
|
||||
|
||||
// Number of MIDI bytes carried by a USB MIDI event packet, indexed by its
|
||||
// Code Index Number (USB MIDI 1.0, table 4-1). 0 means "not a message we
|
||||
// forward".
|
||||
@@ -53,6 +107,13 @@ extern "C" void tud_resume_cb (void)
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
// sleep_ms takes uint32_t, which is unsigned long on this target; the portable
|
||||
// header deliberately knows nothing about platform types.
|
||||
static void DelayMs (unsigned nMilliSeconds)
|
||||
{
|
||||
sleep_ms (nMilliSeconds);
|
||||
}
|
||||
|
||||
static void PollMIDI (void)
|
||||
{
|
||||
uint8_t Packet[4];
|
||||
@@ -80,18 +141,26 @@ int main (void)
|
||||
{
|
||||
stdio_init_all ();
|
||||
|
||||
#if HAVE_STATUS_LED
|
||||
s_Status.Initialize ();
|
||||
#endif
|
||||
|
||||
if (!s_Strip.Initialize ())
|
||||
{
|
||||
// Nothing sensible left to do; make the failure visible rather
|
||||
// than sitting dark and looking like a power problem.
|
||||
// Sit here showing red. A dark board would look like a power
|
||||
// problem; this says the firmware ran and the strip did not.
|
||||
while (true)
|
||||
{
|
||||
ShowStatus (StatusFault);
|
||||
tight_loop_contents ();
|
||||
}
|
||||
}
|
||||
|
||||
s_PianoLEDs.Initialize ();
|
||||
|
||||
// Before USB, so the sweep runs on power alone and needs no PC.
|
||||
s_PianoLEDs.RunSelfTest (DelayMs);
|
||||
|
||||
tusb_init ();
|
||||
|
||||
while (true)
|
||||
@@ -104,6 +173,21 @@ int main (void)
|
||||
// rather than in the USB callback. Returns immediately when
|
||||
// nothing has changed.
|
||||
s_PianoLEDs.Update ();
|
||||
|
||||
s_PianoLEDs.SetHostConnected (tud_mounted ());
|
||||
|
||||
if (!tud_mounted ())
|
||||
{
|
||||
ShowStatus (StatusWaiting);
|
||||
}
|
||||
else if (s_PianoLEDs.GetCalibrationPattern () != CALIB_PATTERN_OFF)
|
||||
{
|
||||
ShowStatus (StatusCalibrating);
|
||||
}
|
||||
else
|
||||
{
|
||||
ShowStatus (StatusReady);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
Reference in New Issue
Block a user