Skip to content

Commit ae509f3

Browse files
authored
Merge pull request #1 from MarkJB/test-case-runner
Adding test case runner, test cases and refactoring
2 parents 297f3fe + c889909 commit ae509f3

13 files changed

Lines changed: 770 additions & 267 deletions

File tree

software/firmware/board_check/src/board_check.c

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@
3131

3232
const uint8_t statusLEDs[] = { PIN_INIT, PIN_RDY, PIN_RUN, PIN_IDLE };
3333
const uint8_t cols[] = { PIN_COL_A, PIN_COL_B, PIN_COL_C, PIN_COL_D, PIN_COL_E };
34-
34+
const uint8_t inputPins[] = { PIN_INPUT_A, PIN_INPUT_B, PIN_INPUT_C, PIN_INPUT_D };
35+
const uint8_t inputCols[] = { PIN_COL_A, PIN_COL_B, PIN_COL_C, PIN_COL_D }; // TC1–TC4
3536
typedef enum {
3637
MODE_DEMO,
3738
MODE_INPUT
@@ -62,10 +63,13 @@ void setupPins() {
6263
funPinMode(PIN_ROW_G, GPIO_Speed_10MHz | GPIO_CNF_OUT_PP);
6364
funDigitalWrite(PIN_ROW_R, FUN_HIGH); // Start rows OFF
6465
funDigitalWrite(PIN_ROW_G, FUN_HIGH);
66+
67+
for (int i = 0; i < 4; i++) {
68+
funPinMode(inputPins[i], GPIO_CNF_IN_PUPD);
69+
funDigitalWrite(inputPins[i], FUN_HIGH); // enable pull‑up
6570
}
6671

67-
const uint8_t inputPins[] = { PIN_INPUT_A, PIN_INPUT_B, PIN_INPUT_C, PIN_INPUT_D };
68-
const uint8_t inputCols[] = { PIN_COL_A, PIN_COL_B, PIN_COL_C, PIN_COL_D }; // TC1–TC4
72+
}
6973

7074
bool isAnyButtonPressed() {
7175
for (int i = 0; i < 4; i++) {
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
2+
3+
#include "pins.h"
4+
#include "buttons.h"
5+
#include <stdint.h>
6+
#include <stdbool.h>
7+
#include "ch32fun.h"
8+
#include "hardware.h"
9+
#include "globals.h"
10+
#include "pins.h"
11+
12+
volatile ButtonState buttons[4];
13+
static uint8_t lastButtonSample = 0xFF;
14+
static uint32_t initLedOffAt = 0;
15+
16+
void pollButtons(void) {
17+
uint8_t sample = 0;
18+
for (int i = 0; i < 4; i++) {
19+
if (!gpio_get(BTN[i].port, BTN[i].mask)) {
20+
sample |= (1 << i);
21+
}
22+
}
23+
24+
uint8_t changed = sample ^ lastButtonSample;
25+
if (changed) {
26+
for (int i = 0; i < 4; i++) {
27+
if ((changed & (1 << i)) && (sample & (1 << i))) {
28+
buttons[i].pressed = true;
29+
buttons[i].justPressed = true;
30+
buttons[i].lastPressTime = msTicks;
31+
buttons[i].pressCount++;
32+
gpio_clear(GPIOC, BIT(6));
33+
initLedOffAt = msTicks + 50;
34+
} else if (changed & (1 << i)) {
35+
buttons[i].pressed = false;
36+
buttons[i].lastReleaseTime = msTicks;
37+
}
38+
}
39+
}
40+
41+
if (initLedOffAt && msTicks >= initLedOffAt) {
42+
gpio_set(GPIOC, BIT(6));
43+
initLedOffAt = 0;
44+
}
45+
46+
lastButtonSample = sample;
47+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#ifndef BUTTONS_H
2+
#define BUTTONS_H
3+
4+
#include <stdint.h>
5+
#include <stdbool.h>
6+
7+
typedef struct {
8+
uint32_t lastPressTime;
9+
uint32_t lastReleaseTime;
10+
uint16_t pressCount;
11+
bool pressed;
12+
bool justPressed;
13+
} ButtonState;
14+
15+
extern volatile ButtonState buttons[4];
16+
void pollButtons(void);
17+
18+
#endif // BUTTONS_H

software/firmware/tester_runtime/src/funconfig.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
// you can put various configurations in here, you can see a full list in ch32fun.h
55
// part selection is made in the Makefile
6+
#define FUNCONF_ENABLE_HPE 0
67

78
#endif
89

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#ifndef GLOBALS_H
2+
#define GLOBALS_H
3+
#include <stdint.h>
4+
#include <stdbool.h>
5+
6+
extern volatile uint32_t msTicks;
7+
extern volatile bool flashState;
8+
extern volatile bool rapidFlashState;
9+
extern volatile bool runMode;
10+
extern volatile uint8_t currentCol;
11+
12+
#endif // GLOBALS_H
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
2+
#include <stdint.h>
3+
#include <stdbool.h>
4+
#include "ch32fun.h"
5+
#include "pins.h"
6+
#include "hardware.h"
7+
#include "buttons.h"
8+
#include "leds.h"
9+
#include "globals.h"
10+
#include "pins.h"
11+
12+
// Pin port/mask arrays/structs (define here)
13+
const PinDef COL[5] = {
14+
{GPIOC, 0x01}, {GPIOC, 0x02}, {GPIOC, 0x04}, {GPIOC, 0x08}, {GPIOC, 0x10}
15+
};
16+
const PinDef ROW_RED = { GPIOA, 0x02 };
17+
const PinDef ROW_GREEN = { GPIOA, 0x04 };
18+
const PinDef BTN[4] = {
19+
{GPIOD, 0x04}, {GPIOD, 0x08}, {GPIOD, 0x10}, {GPIOD, 0x20}
20+
};
21+
22+
// Global variables (define here)
23+
volatile uint32_t msTicks = 0;
24+
volatile bool flashState = false;
25+
volatile bool rapidFlashState = false;
26+
volatile bool runMode = false;
27+
volatile uint8_t currentCol = 0;
28+
29+
static const int statusLEDs[] = { PIN_PWR, PIN_INIT, PIN_RDY, PIN_RUN, PIN_IDLE };
30+
static const int testCols[] = { PIN_COL_A, PIN_COL_B, PIN_COL_C, PIN_COL_D, PIN_COL_E };
31+
static const int inputPins[] = { PIN_INPUT_A, PIN_INPUT_B, PIN_INPUT_C, PIN_INPUT_D };
32+
33+
// Timer ISR for 1ms tick, button polling, and LED scan
34+
void TIM1_UP_IRQHandler(void) INTERRUPT_DECORATOR;
35+
void TIM1_UP_IRQHandler(void)
36+
{
37+
if (TIM1->INTFR & TIM_UIF) {
38+
TIM1->INTFR &= ~TIM_UIF;
39+
msTicks++;
40+
pollButtons();
41+
static uint32_t nextFlashAt = 250;
42+
if (msTicks >= nextFlashAt) {
43+
nextFlashAt += 250;
44+
flashState = !flashState;
45+
}
46+
static uint32_t nextRapidFlashAt = 125;
47+
if (msTicks >= nextRapidFlashAt) {
48+
nextRapidFlashAt += 125;
49+
rapidFlashState = !rapidFlashState;
50+
}
51+
scanStep();
52+
}
53+
}
54+
55+
void setupPins(void) {
56+
funGpioInitAll();
57+
RCC->APB2PCENR |= RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD;
58+
for (int i = 0; i < 5; i++) {
59+
funPinMode(statusLEDs[i], GPIO_Speed_10MHz | GPIO_CNF_OUT_PP);
60+
funDigitalWrite(statusLEDs[i], FUN_HIGH);
61+
}
62+
for (int i = 0; i < 5; i++) {
63+
funPinMode(testCols[i], GPIO_Speed_10MHz | GPIO_CNF_OUT_PP);
64+
funDigitalWrite(testCols[i], FUN_LOW);
65+
}
66+
funPinMode(PIN_ROW_R, GPIO_Speed_10MHz | GPIO_CNF_OUT_PP);
67+
funPinMode(PIN_ROW_G, GPIO_Speed_10MHz | GPIO_CNF_OUT_PP);
68+
funDigitalWrite(PIN_ROW_R, FUN_HIGH);
69+
funDigitalWrite(PIN_ROW_G, FUN_HIGH);
70+
for (int i = 0; i < 4; i++) {
71+
funPinMode(inputPins[i], GPIO_CNF_IN_PUPD);
72+
funDigitalWrite(inputPins[i], FUN_HIGH);
73+
}
74+
}
75+
76+
void setupStatusFlasher(void) {
77+
RCC->APB2PCENR |= RCC_APB2Periph_TIM1;
78+
RCC->APB2PRSTR |= RCC_APB2Periph_TIM1;
79+
RCC->APB2PRSTR &= ~RCC_APB2Periph_TIM1;
80+
TIM1->PSC = 48 - 1;
81+
TIM1->ATRLR = 1000 - 1;
82+
TIM1->SWEVGR |= TIM_UG;
83+
TIM1->INTFR &= ~TIM_UIF;
84+
TIM1->DMAINTENR |= TIM_UIE;
85+
NVIC_EnableIRQ(TIM1_UP_IRQn);
86+
TIM1->CTLR1 |= TIM_CEN;
87+
}
88+
89+
void runStatus(bool isRun) {
90+
runMode = isRun;
91+
funDigitalWrite(PIN_RUN, FUN_HIGH);
92+
funDigitalWrite(PIN_IDLE, FUN_HIGH);
93+
}
94+
95+
void waitTicks(uint32_t ticks) {
96+
uint32_t start = msTicks;
97+
while ((uint32_t)(msTicks - start) < ticks) {
98+
__WFI();
99+
}
100+
}
101+
102+
void scanStep(void) {
103+
static int8_t prev = -1;
104+
if (activeStates == NULL) {
105+
gpio_set(ROW_RED.port, ROW_RED.mask);
106+
gpio_set(ROW_GREEN.port, ROW_GREEN.mask);
107+
return;
108+
}
109+
gpio_set(ROW_RED.port, ROW_RED.mask);
110+
gpio_set(ROW_GREEN.port, ROW_GREEN.mask);
111+
if (prev >= 0 && prev < 5) {
112+
if (COL[prev].port != NULL) {
113+
gpio_clear(COL[prev].port, COL[prev].mask);
114+
}
115+
}
116+
if (currentCol >= 0 && currentCol < 5) {
117+
TestCaseState state = activeStates[currentCol];
118+
switch (state) {
119+
case TC_PASS:
120+
gpio_clear(ROW_GREEN.port, ROW_GREEN.mask);
121+
break;
122+
case TC_FAIL:
123+
gpio_clear(ROW_RED.port, ROW_RED.mask);
124+
break;
125+
case TC_IN_PROGRESS:
126+
if (flashState)
127+
gpio_clear(ROW_RED.port, ROW_RED.mask);
128+
else
129+
gpio_clear(ROW_GREEN.port, ROW_GREEN.mask);
130+
break;
131+
case TC_WARNING:
132+
if (flashState)
133+
gpio_clear(ROW_RED.port, ROW_RED.mask);
134+
break;
135+
case TC_RETRY:
136+
if (rapidFlashState)
137+
gpio_clear(ROW_RED.port, ROW_RED.mask);
138+
break;
139+
case TC_NO_RESULT:
140+
default:
141+
break;
142+
}
143+
if (COL[currentCol].port != NULL) {
144+
gpio_set(COL[currentCol].port, COL[currentCol].mask);
145+
}
146+
}
147+
prev = currentCol;
148+
currentCol = (currentCol + 1) % 5;
149+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#ifndef HARDWARE_H
2+
#define HARDWARE_H
3+
4+
#include <stdint.h>
5+
#include <stdbool.h>
6+
#include "ch32fun.h"
7+
#include "test_cases.h"
8+
9+
void setupPins(void);
10+
void setupStatusFlasher(void);
11+
void runStatus(bool isRun);
12+
void waitTicks(uint32_t ticks);
13+
void scanStep(void);
14+
15+
#endif // HARDWARE_H
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
2+
3+
4+
#include <stdint.h>
5+
#include <stdbool.h>
6+
#include "ch32fun.h"
7+
#include "hardware.h"
8+
#include "test_cases.h"
9+
#include "globals.h"
10+
#include "pins.h"
11+
12+
// Double-buffered states (publish by pointer swap)
13+
static TestCaseState bufA[5], bufB[5];
14+
volatile const TestCaseState* activeStates = bufA;
15+
static uint8_t activeIdx = 0;
16+
17+
18+
19+
void initTestCaseStates(void) {
20+
for (int i = 0; i < 5; i++) { bufA[i] = bufB[i] = TC_NO_RESULT; }
21+
activeStates = bufA;
22+
activeIdx = 0;
23+
}
24+
25+
void setTestCaseResult(const TestCaseState states[5]) {
26+
TestCaseState* dst = (activeIdx == 0) ? bufB : bufA;
27+
for (int i = 0; i < 5; i++) dst[i] = states[i];
28+
__disable_irq();
29+
__asm volatile ("" ::: "memory");
30+
activeStates = (volatile const TestCaseState*)dst;
31+
activeIdx ^= 1;
32+
__asm volatile ("" ::: "memory");
33+
__enable_irq();
34+
}
35+
36+
void serviceStatusLeds(void) {
37+
static bool lastFlash = 0, lastMode = 0;
38+
if (flashState != lastFlash || runMode != lastMode) {
39+
uint16_t activePin = runMode ? PIN_RUN : PIN_IDLE;
40+
uint16_t inactivePin = runMode ? PIN_IDLE : PIN_RUN;
41+
funDigitalWrite(activePin, flashState ? FUN_LOW : FUN_HIGH);
42+
funDigitalWrite(inactivePin, FUN_HIGH);
43+
lastFlash = flashState;
44+
lastMode = runMode;
45+
}
46+
}
47+
48+
void testCaseLEDStartupPattern(void) {
49+
static TestCaseState demoStates[5];
50+
for (int k = 0; k < 4; k++) {
51+
for (int i = 0; i < 5; i++) {
52+
for (int j = 0; j < 5; j++) demoStates[j] = TC_NO_RESULT;
53+
demoStates[i] = TC_PASS;
54+
setTestCaseResult(demoStates);
55+
waitTicks(30);
56+
}
57+
for (int i = 4; i >= 0; i--) {
58+
for (int j = 0; j < 5; j++) demoStates[j] = TC_NO_RESULT;
59+
demoStates[i] = TC_FAIL;
60+
setTestCaseResult(demoStates);
61+
waitTicks(30);
62+
}
63+
}
64+
for (int j = 0; j < 5; j++) demoStates[j] = TC_NO_RESULT;
65+
setTestCaseResult(demoStates);
66+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#include <stdint.h>
2+
#include "test_cases.h"
3+
4+
extern volatile const TestCaseState* activeStates;
5+
#ifndef LEDS_H
6+
#define LEDS_H
7+
8+
#include <stdint.h>
9+
#include <stdbool.h>
10+
11+
12+
#include "test_cases.h"
13+
14+
void serviceStatusLeds(void);
15+
void setTestCaseResult(const TestCaseState states[5]);
16+
void initTestCaseStates(void);
17+
void testCaseLEDStartupPattern(void);
18+
19+
#endif // LEDS_H

0 commit comments

Comments
 (0)