Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 83 additions & 0 deletions software/firmware/tester_runtime/src/leds.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,14 @@ void serviceStatusLeds(void) {
}
}

void turnOffAllStatusLeds(void) {
funDigitalWrite(PIN_PWR, FUN_HIGH);
funDigitalWrite(PIN_INIT, FUN_HIGH);
funDigitalWrite(PIN_RDY, FUN_HIGH);
funDigitalWrite(PIN_RUN, FUN_HIGH);
funDigitalWrite(PIN_IDLE, FUN_HIGH);
}

void testCaseLEDStartupPattern(void) {
static TestCaseState demoStates[5];
for (int k = 0; k < 4; k++) {
Expand All @@ -64,3 +72,78 @@ void testCaseLEDStartupPattern(void) {
for (int j = 0; j < 5; j++) demoStates[j] = TC_NO_RESULT;
setTestCaseResult(demoStates);
}

// Demo Mode: This should show activity on the status LEDs
// and cycle through test case LEDs in a pattern designed
// to catch the eye. Doesn't reflect any real test results.
void demoMode(void) {
// Show sweeping pattern on status LEDs, repeat 5 times
for (int i = 0; i < 10; i++) {
for (int i = 0; i < 5; i++) {
funDigitalWrite(PIN_PWR, (i == 0) ? FUN_LOW : FUN_HIGH);
funDigitalWrite(PIN_INIT, (i == 1) ? FUN_LOW : FUN_HIGH);
funDigitalWrite(PIN_RDY, (i == 2) ? FUN_LOW : FUN_HIGH);
funDigitalWrite(PIN_RUN, (i == 3) ? FUN_LOW : FUN_HIGH);
funDigitalWrite(PIN_IDLE, (i == 4) ? FUN_LOW : FUN_HIGH);
waitTicks(30);
}
}

// Demo mode on test case LEDs
static TestCaseState demoStates[5];
for (int k = 0; k < 4; k++) {
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++) demoStates[j] = TC_NO_RESULT;
demoStates[i] = TC_PASS;
setTestCaseResult(demoStates);
waitTicks(30);
}
for (int i = 4; i >= 0; i--) {
for (int j = 0; j < 5; j++) demoStates[j] = TC_NO_RESULT;
demoStates[i] = TC_FAIL;
setTestCaseResult(demoStates);
waitTicks(30);
}
}
for (int j = 0; j < 5; j++) demoStates[j] = TC_NO_RESULT;
setTestCaseResult(demoStates);

// call testCaseLEDStartupPattern();
testCaseLEDStartupPattern();

// Do 5 sweeps back and forth on status LEDs sweep up then down then repeat
for (int i = 0; i < 5; i++) {
for (int i = 0; i < 5; i++) {
funDigitalWrite(PIN_PWR, (i == 0) ? FUN_LOW : FUN_HIGH);
funDigitalWrite(PIN_INIT, (i == 1) ? FUN_LOW : FUN_HIGH);
funDigitalWrite(PIN_RDY, (i == 2) ? FUN_LOW : FUN_HIGH);
funDigitalWrite(PIN_RUN, (i == 3) ? FUN_LOW : FUN_HIGH);
funDigitalWrite(PIN_IDLE, (i == 4) ? FUN_LOW : FUN_HIGH);
waitTicks(30);
}
for (int i = 4; i >= 0; i--) {
funDigitalWrite(PIN_PWR, (i == 0) ? FUN_LOW : FUN_HIGH);
funDigitalWrite(PIN_INIT, (i == 1) ? FUN_LOW : FUN_HIGH);
funDigitalWrite(PIN_RDY, (i == 2) ? FUN_LOW : FUN_HIGH);
funDigitalWrite(PIN_RUN, (i == 3) ? FUN_LOW : FUN_HIGH);
funDigitalWrite(PIN_IDLE, (i == 4) ? FUN_LOW : FUN_HIGH);
waitTicks(30);
}
}

testCaseLEDStartupPattern();

// Show backwards sweeping pattern on status LEDs, repeat 5 times
for (int i = 0; i < 10; i++) {
for (int i = 4; i >= 0; i--) {
funDigitalWrite(PIN_PWR, (i == 0) ? FUN_LOW : FUN_HIGH);
funDigitalWrite(PIN_INIT, (i == 1) ? FUN_LOW : FUN_HIGH);
funDigitalWrite(PIN_RDY, (i == 2) ? FUN_LOW : FUN_HIGH);
funDigitalWrite(PIN_RUN, (i == 3) ? FUN_LOW : FUN_HIGH);
funDigitalWrite(PIN_IDLE, (i == 4) ? FUN_LOW : FUN_HIGH);
waitTicks(30);
}
}

testCaseLEDStartupPattern();
}
2 changes: 2 additions & 0 deletions software/firmware/tester_runtime/src/leds.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@ extern volatile const TestCaseState* activeStates;
#include "test_cases.h"

void serviceStatusLeds(void);
void turnOffAllStatusLeds(void);
void setTestCaseResult(const TestCaseState states[5]);
void initTestCaseStates(void);
void testCaseLEDStartupPattern(void);
void demoMode(void);

#endif // LEDS_H
15 changes: 13 additions & 2 deletions software/firmware/tester_runtime/src/main.c
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
#include "utils.h"
// Prototypes for functions used but not declared
bool allTestsPassed(void);
void triggerPOVEasterEgg(void);
#include "ch32fun.h"
#include <stdbool.h>
#include "globals.h"
Expand Down Expand Up @@ -41,10 +45,17 @@ static void startupSequence(void) {
startupSequence();
waitTicks(100);
while (1) {
serviceStatusLeds();
serviceStatusLeds(); ///Update status LEDs
// Check for button combos to start tests, demo mode, or PoV easter egg
if (!testActive && buttons[3].pressed) {
test_cases_start(currentTest);
}
} else if (!testActive && buttons[0].pressed && buttons[2].pressed) {
while(1) {
demoMode();
}
} else if (allTestsPassed() && buttons[1].pressed && buttons[2].pressed) {
triggerPOVEasterEgg();
}
test_cases_monitor_inputs();
__WFI();
}
Expand Down
2 changes: 1 addition & 1 deletion software/firmware/tester_runtime/src/test_cases.c
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,7 @@ static const TestCaseDef testCases[] = {
{ 5000, tc4_init, tc4_update, tc4_eval },
{ 30000, tc5_init, tc5_update, tc5_eval }
};
static const size_t NUM_TEST_CASES = sizeof(testCases) / sizeof(testCases[0]);
const size_t NUM_TEST_CASES = sizeof(testCases) / sizeof(testCases[0]);

// ===== Test Case Runner =====

Expand Down
3 changes: 3 additions & 0 deletions software/firmware/tester_runtime/src/test_cases.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#ifndef TEST_CASES_H
#define TEST_CASES_H

#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>

Expand All @@ -25,4 +26,6 @@ extern TestCaseState tcResults[5];
extern uint8_t currentTest;
extern bool testActive;

extern const size_t NUM_TEST_CASES;

#endif // TEST_CASES_H
183 changes: 183 additions & 0 deletions software/firmware/tester_runtime/src/utils.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
#include <string.h> // For strlen
#include "ch32fun.h"
#include "pins.h"
#include "utils.h"
#include "test_cases.h"
#include "leds.h"

bool allTestsPassed(void) {
for (size_t i = 0; i < NUM_TEST_CASES; i++) {
if (tcResults[i] != TC_PASS) return false;
}
return true;
}

// PoV Easter Egg
// Simple 5x4 font for PoV
// Message shows BUG in simple font using the following 4x5 font data
// B = 11111, 10101, 10101, 01010,
// U = 01111, 10000, 10000, 01111,
// G = 01110, 10001, 11001, 01010,
// Gap = 00000

static const uint8_t pov_font_B[5] = {
0b11111, // Column 0
0b10101, // Column 1
0b10101, // Column 2
0b01010, // Column 3
};

static const uint8_t pov_font_U[5] = {
0b01111, // Column 0
0b10000, // Column 1
0b10000, // Column 2
0b01111, // Column 0
};

static const uint8_t pov_font_G[5] = {
0b01110, // Column 0
0b10001, // Column 1
0b11001, // Column 2
0b01010, // Column 3
};

// M
static const uint8_t pov_font_M[5] = {
0b11111, // Column 0
0b00010, // Column 1
0b00100, // Column 2
0b00010, // Column 1
0b11111, // Column 0
};

// O is also used for 0
static const uint8_t pov_font_O[5] = {
0b01110, // Column 0
0b10001, // Column 1
0b10001, // Column 2
0b01110, // Column 3
};

// T
static const uint8_t pov_font_T[5] = {

0b00001, // Column 1
0b00001, // Column 2
0b11111, // Column 3
0b00001, // Column 4
0b00001, // Column 5
};

// 2
static const uint8_t pov_font_2[5] = {
0b11010, // Column 0
0b11001, // Column 1
0b11101, // Column 2
0b10110, // Column 3
};

// 5
static const uint8_t pov_font_5[5] = {
0b10111, // Column 0
0b10101, // Column 1
0b10101, // Column 2
0b01001, // Column 3
};

// Space is a special case
static const uint8_t pov_font_space[1] = {
0b00000, // Column 0
};

static const char* povMessage = "MOT 2025 ";

void displayPOVChar(char c) {
const uint8_t* pattern = NULL;
int numCols = 0;
// Select pattern and number of columns for each character
switch (c) {
case 'B':
pattern = pov_font_B;
numCols = 4;
break;
case 'U':
pattern = pov_font_U;
numCols = 4;
break;
case 'G':
pattern = pov_font_G;
numCols = 4;
break;
case 'M':
pattern = pov_font_M;
numCols = 5;
break;
case 'O':
pattern = pov_font_O;
numCols = 4;
break;
case 'T':
pattern = pov_font_T;
numCols = 5;
break;
case '0':
pattern = pov_font_O;
numCols = 4;
break;
case '2':
pattern = pov_font_2;
numCols = 4;
break;
case '5':
pattern = pov_font_5;
numCols = 4;
break;
case ' ': // gap/space
pattern = pov_font_space;
numCols = 1;
break;
default:
pattern = pov_font_space;
numCols = 1;
break;
}
// Display each column of the character using status LEDs (active low)
for (int col = 0; col < numCols; col++) {
// Set all status LEDs OFF (inactive/high)
funDigitalWrite(PIN_PWR, 1);
funDigitalWrite(PIN_INIT, 1);
funDigitalWrite(PIN_RDY, 1);
funDigitalWrite(PIN_RUN, 1);
funDigitalWrite(PIN_IDLE, 1);

if (pattern && (pattern[col] & 0x1F)) {
if (pattern[col] & (1 << 0)) funDigitalWrite(PIN_PWR, 0); // ON (active low)
if (pattern[col] & (1 << 1)) funDigitalWrite(PIN_INIT, 0);
if (pattern[col] & (1 << 2)) funDigitalWrite(PIN_RDY, 0);
if (pattern[col] & (1 << 3)) funDigitalWrite(PIN_RUN, 0);
if (pattern[col] & (1 << 4)) funDigitalWrite(PIN_IDLE, 0);
}
Delay_Ms(2); // Adjust timing for PoV effect
}
// Always add a 1-column gap after each character
funDigitalWrite(PIN_PWR, 1);
funDigitalWrite(PIN_INIT, 1);
funDigitalWrite(PIN_RDY, 1);
funDigitalWrite(PIN_RUN, 1);
funDigitalWrite(PIN_IDLE, 1);
Delay_Ms(2);
}

void triggerPOVEasterEgg(void) {
// turn off all other LEDs including PWR, INIT, RDY
turnOffAllStatusLeds();
// turn off test case LEDs
setTestCaseResult((TestCaseState[5]){ TC_NO_RESULT, TC_NO_RESULT, TC_NO_RESULT, TC_NO_RESULT, TC_NO_RESULT });

while (1) {
for (size_t i = 0; i < strlen(povMessage); i++) {
displayPOVChar(povMessage[i]);
}
}

}
19 changes: 19 additions & 0 deletions software/firmware/tester_runtime/src/utils.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// utils.h – Easter egg and POV rendering utilities
// Exposes functions for test result checking and LED-based message display

#ifndef UTILS_H
#define UTILS_H

#include <stdbool.h> // For bool
#include <stddef.h> // For size_t
#include "test_cases.h" // For TestCaseState

extern const size_t NUM_TEST_CASES;
extern TestCaseState tcResults[];

// Public function declarations
bool allTestsPassed(void);
void displayPOVChar(char c);
void triggerPOVEasterEgg(void);

#endif // UTILS_H
Loading