Refactor radar system
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
"""Run firmware logic on the host; timing and physical I/O still need the board."""
|
||||
|
||||
from pathlib import Path
|
||||
import shutil
|
||||
import subprocess
|
||||
import tempfile
|
||||
import unittest
|
||||
|
||||
PROJECT = Path(__file__).resolve().parents[2]
|
||||
|
||||
ARDUINO_STUB = r'''
|
||||
#pragma once
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
inline uint32_t test_time = 0;
|
||||
inline int transmissions = 0;
|
||||
inline uint32_t millis() { return test_time; }
|
||||
inline int analogRead(uint32_t pin) { return pin == 0 ? 2014 : 1981; }
|
||||
inline void analogReadResolution(int) {}
|
||||
inline void pinMode(uint32_t, int) {}
|
||||
inline float constrain(float v, float lo, float hi) { return std::clamp(v, lo, hi); }
|
||||
struct SerialStub {
|
||||
void begin(int) {}
|
||||
template<class T> void print(T, int = 0) {}
|
||||
template<class T> void println(T) {}
|
||||
};
|
||||
inline SerialStub Serial;
|
||||
struct GPIO_InitTypeDef { int Pin, Mode, Pull, Speed, Alternate; };
|
||||
struct UART_HandleTypeDef {
|
||||
int Instance;
|
||||
struct { int BaudRate, WordLength, StopBits, Parity, Mode, HwFlowCtl, OverSampling; } Init;
|
||||
struct { int AdvFeatureInit, TxPinLevelInvert; } AdvancedInit;
|
||||
};
|
||||
enum { PA0, PA1, GPIO_PIN_9, GPIO_MODE_AF_PP, GPIO_NOPULL, GPIO_SPEED_FREQ_LOW,
|
||||
GPIO_AF7_USART1, GPIOA, USART1, UART_WORDLENGTH_9B, UART_STOPBITS_2,
|
||||
UART_PARITY_EVEN, UART_MODE_TX, UART_HWCONTROL_NONE, UART_OVERSAMPLING_16,
|
||||
UART_ADVFEATURE_TXINVERT_INIT, UART_ADVFEATURE_TXINV_ENABLE, INPUT_ANALOG };
|
||||
inline void __HAL_RCC_GPIOA_CLK_ENABLE() {}
|
||||
inline void __HAL_RCC_USART1_CLK_ENABLE() {}
|
||||
inline void HAL_GPIO_Init(int, GPIO_InitTypeDef*) {}
|
||||
inline void HAL_UART_Init(UART_HandleTypeDef*) {}
|
||||
inline void HAL_UART_Transmit(UART_HandleTypeDef*, uint8_t*, int, int) { ++transmissions; }
|
||||
'''
|
||||
|
||||
|
||||
@unittest.skipUnless(shutil.which('g++'), 'requires a host C++ compiler')
|
||||
class CartFirmwareTest(unittest.TestCase):
|
||||
def test_schedule_rollover_and_sbus_encoding(self) -> None:
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
root = Path(directory)
|
||||
(root / 'Arduino.h').write_text(ARDUINO_STUB)
|
||||
source = root / 'check.cpp'
|
||||
firmware = PROJECT / 'device_firmware/cart_firmware/src/main.cpp'
|
||||
source.write_text(f'#include "{firmware}"\n' + r'''
|
||||
#include <cassert>
|
||||
int main() {
|
||||
test_time = UINT32_MAX - 100;
|
||||
loop(); assert(transmissions == 1);
|
||||
test_time = 1;
|
||||
loop(); assert(transmissions == 2);
|
||||
test_time += 49;
|
||||
loop(); assert(transmissions == 2);
|
||||
++test_time;
|
||||
loop(); assert(transmissions == 3);
|
||||
assert(axisNorm(X_MID, X_FWD, X_MID, X_BACK) == 0);
|
||||
assert(axisNorm(X_FWD, X_FWD, X_MID, X_BACK) == 1);
|
||||
assert(driveToSbus(0, CH2_SPAN, CH2_DB, POWER_FWD, POWER_BACK) == SBUS_MID);
|
||||
uint16_t channels[16];
|
||||
for (int n = 0; n < 16; ++n) channels[n] = n * 127;
|
||||
uint8_t packed[25]; sbusPack(packed, channels);
|
||||
assert(packed[0] == 0x0f && packed[23] == 0 && packed[24] == 0);
|
||||
for (int n = 0; n < 16; ++n) {
|
||||
uint16_t value = 0;
|
||||
for (int b = 0; b < 11; ++b) {
|
||||
const int bit = n * 11 + b;
|
||||
value |= ((packed[1 + bit / 8] >> (bit % 8)) & 1) << b;
|
||||
}
|
||||
assert(value == channels[n]);
|
||||
}
|
||||
}
|
||||
''')
|
||||
binary = root / 'check'
|
||||
built = subprocess.run(['g++', '-std=c++20', '-Wall', '-Wextra', '-Werror', f'-I{root}',
|
||||
str(source), '-o', str(binary)], capture_output=True, text=True, timeout=15)
|
||||
self.assertEqual(built.returncode, 0, built.stderr)
|
||||
subprocess.run([str(binary)], check=True, timeout=5)
|
||||
Reference in New Issue
Block a user