diff --git a/libs/can/can.c b/libs/can/can.c index 6acb78d..0dd1b83 100644 --- a/libs/can/can.c +++ b/libs/can/can.c @@ -2,84 +2,81 @@ #include void can_frame_init(can_frame_t *f, can_priority_t prio, can_source_t src, - uint8_t type, uint8_t dlc) -{ + uint8_t type, uint8_t dlc) { memset(f, 0, sizeof(*f)); - f->id = can_make_id(prio, src, type); + f->id = can_make_id(prio, src, type); f->dlc = (dlc > CAN_MAX_DLC) ? (uint8_t)CAN_MAX_DLC : dlc; } -void can_put_u16(uint8_t *buf, uint16_t v) -{ +void can_put_u16(uint8_t *buf, uint16_t v) { buf[0] = (uint8_t)(v & 0xFFu); buf[1] = (uint8_t)(v >> 8); } void can_put_i16(uint8_t *buf, int16_t v) { can_put_u16(buf, (uint16_t)v); } -void can_put_u32(uint8_t *buf, uint32_t v) -{ +void can_put_u32(uint8_t *buf, uint32_t v) { buf[0] = (uint8_t)(v & 0xFFu); buf[1] = (uint8_t)((v >> 8) & 0xFFu); buf[2] = (uint8_t)((v >> 16) & 0xFFu); buf[3] = (uint8_t)(v >> 24); } -uint16_t can_get_u16(const uint8_t *buf) -{ +uint16_t can_get_u16(const uint8_t *buf) { return (uint16_t)((uint16_t)buf[0] | (uint16_t)((uint16_t)buf[1] << 8)); } int16_t can_get_i16(const uint8_t *buf) { return (int16_t)can_get_u16(buf); } -uint32_t can_get_u32(const uint8_t *buf) -{ - return (uint32_t)buf[0] | ((uint32_t)buf[1] << 8) | - ((uint32_t)buf[2] << 16) | ((uint32_t)buf[3] << 24); +uint32_t can_get_u32(const uint8_t *buf) { + return (uint32_t)buf[0] | ((uint32_t)buf[1] << 8) | ((uint32_t)buf[2] << 16) | ((uint32_t)buf[3] << 24); } #define HEARTBEAT_DLC 5u -void can_encode_heartbeat(can_frame_t *f, const can_heartbeat_t *hb) -{ +void can_encode_heartbeat(can_frame_t *f, const can_heartbeat_t *hb) { can_frame_init(f, CAN_PRIO_INFO, hb->source, CAN_MSG_HEARTBEAT, HEARTBEAT_DLC); f->data[0] = hb->state; can_put_u32(&f->data[1], hb->uptime_s); } -bool can_decode_heartbeat(const can_frame_t *f, can_heartbeat_t *out) -{ - if (f == NULL || out == NULL) return false; +bool can_decode_heartbeat(const can_frame_t *f, can_heartbeat_t *out) { + if (f == NULL || out == NULL) + return false; can_source_t src = can_id_source(f->id); - if (can_id_priority(f->id) != CAN_PRIO_INFO) return false; - if (can_id_type(f->id) != CAN_MSG_HEARTBEAT) return false; - if (src == CAN_SRC_GROUND || src == CAN_SRC_BROADCAST) return false; - if (f->dlc < HEARTBEAT_DLC) return false; - - out->source = src; - out->state = f->data[0]; + if (can_id_priority(f->id) != CAN_PRIO_INFO) + return false; + if (can_id_type(f->id) != CAN_MSG_HEARTBEAT) + return false; + if (src == CAN_SRC_GROUND || src == CAN_SRC_BROADCAST) + return false; + if (f->dlc < HEARTBEAT_DLC) + return false; + + out->source = src; + out->state = f->data[0]; out->uptime_s = can_get_u32(&f->data[1]); return true; } typedef struct { can_priority_t prio; - uint8_t all_type; - uint8_t node_type; + uint8_t all_type; + uint8_t node_type; } sys_cmd_def_t; static const sys_cmd_def_t SYS_CMDS[] = { [CAN_SYS_UNLOCK] = { CAN_PRIO_IMPORTANT, CAN_CMD_UNLOCK_ALL, CAN_CMD_UNLOCK_NODE }, - [CAN_SYS_SLEEP] = { CAN_PRIO_IMPORTANT, CAN_CMD_SLEEP_ALL, CAN_CMD_SLEEP_NODE }, - [CAN_SYS_RESET] = { CAN_PRIO_CRITICAL, CAN_CMD_RESET_ALL, CAN_CMD_RESET_NODE }, + [CAN_SYS_SLEEP] = { CAN_PRIO_IMPORTANT, CAN_CMD_SLEEP_ALL, CAN_CMD_SLEEP_NODE }, + [CAN_SYS_RESET] = { CAN_PRIO_CRITICAL, CAN_CMD_RESET_ALL, CAN_CMD_RESET_NODE }, }; #define SYS_CMD_COUNT (sizeof(SYS_CMDS) / sizeof(SYS_CMDS[0])) -bool can_encode_sys_cmd(can_frame_t *f, can_sys_cmd_t cmd, can_source_t target) -{ - if (cmd <= CAN_SYS_NONE || (size_t)cmd >= SYS_CMD_COUNT) return false; +bool can_encode_sys_cmd(can_frame_t *f, can_sys_cmd_t cmd, can_source_t target) { + if (cmd <= CAN_SYS_NONE || (size_t)cmd >= SYS_CMD_COUNT) + return false; const sys_cmd_def_t *d = &SYS_CMDS[cmd]; if (target == CAN_SRC_BROADCAST) { @@ -91,9 +88,9 @@ bool can_encode_sys_cmd(can_frame_t *f, can_sys_cmd_t cmd, can_source_t target) return true; } -can_sys_cmd_t can_decode_sys_cmd(const can_frame_t *f, can_source_t me) -{ - if (f == NULL) return CAN_SYS_NONE; +can_sys_cmd_t can_decode_sys_cmd(const can_frame_t *f, can_source_t me) { + if (f == NULL) + return CAN_SYS_NONE; for (size_t i = 1; i < SYS_CMD_COUNT; i++) { const sys_cmd_def_t *d = &SYS_CMDS[i]; @@ -101,8 +98,7 @@ can_sys_cmd_t can_decode_sys_cmd(const can_frame_t *f, can_source_t me) if (f->id == can_make_id(d->prio, CAN_SRC_BROADCAST, d->all_type)) { return (can_sys_cmd_t)i; } - if (f->id == can_make_id(d->prio, CAN_SRC_MASTER, d->node_type) && - f->dlc >= 1 && f->data[0] == (uint8_t)me) { + if (f->id == can_make_id(d->prio, CAN_SRC_MASTER, d->node_type) && f->dlc >= 1 && f->data[0] == (uint8_t)me) { return (can_sys_cmd_t)i; } } diff --git a/libs/can/can.h b/libs/can/can.h index 7d659ac..8b17857 100644 --- a/libs/can/can.h +++ b/libs/can/can.h @@ -20,9 +20,9 @@ extern "C" { /** @brief Abstract CAN frame without any driver shit (Standard CAN; not FD)*/ typedef struct { - uint32_t id; /**< 11-bit ID, see can_make_id() */ - uint8_t dlc; /**< Payload length, 0-8 */ - uint8_t data[CAN_MAX_DLC]; + uint32_t id; /**< 11-bit ID, see can_make_id() */ + uint8_t dlc; /**< Payload length, 0-8 */ + uint8_t data[CAN_MAX_DLC]; } can_frame_t; /** @@ -30,23 +30,23 @@ typedef struct { * @param dlc Payload length; values above 8 are clamped to 8 */ void can_frame_init(can_frame_t *f, can_priority_t prio, can_source_t src, - uint8_t type, uint8_t dlc); + uint8_t type, uint8_t dlc); /** @name Utility functions for little endian byte packing */ /**@{*/ -void can_put_u16(uint8_t *buf, uint16_t v); -void can_put_i16(uint8_t *buf, int16_t v); -void can_put_u32(uint8_t *buf, uint32_t v); +void can_put_u16(uint8_t *buf, uint16_t v); +void can_put_i16(uint8_t *buf, int16_t v); +void can_put_u32(uint8_t *buf, uint32_t v); uint16_t can_get_u16(const uint8_t *buf); -int16_t can_get_i16(const uint8_t *buf); +int16_t can_get_i16(const uint8_t *buf); uint32_t can_get_u32(const uint8_t *buf); /**@}*/ /** @brief Heartbeat contents, Payload: [state u8][uptime_s u32] = 5 bytes. */ typedef struct { - can_source_t source; /**< Which node sent it (from the ID) */ - uint8_t state; /**< Sender's fsm_state_t, as a byte */ - uint32_t uptime_s; /**< Seconds since boot, if this is lower than the prior log it means the node rebooted! */ + can_source_t source; /**< Which node sent it (from the ID) */ + uint8_t state; /**< Sender's fsm_state_t, as a byte */ + uint32_t uptime_s; /**< Seconds since boot, if this is lower than the prior log it means the node rebooted! */ } can_heartbeat_t; /** @brief Build a heartbeat frame (INFO priority, type 0x00) */ @@ -55,7 +55,7 @@ void can_encode_heartbeat(can_frame_t *f, const can_heartbeat_t *hb); /** * @brief Decode a heartbeat * @return false if the frame is not a well-formed heartbeat (wrong priority, - * wrong type, command-only source, or too short, etc + * wrong type, command-only source, or too short, etc * @p out is usuallyuntouched */ bool can_decode_heartbeat(const can_frame_t *f, can_heartbeat_t *out); diff --git a/libs/can/can_eps.c b/libs/can/can_eps.c index 3f69fa6..36bb4d4 100644 --- a/libs/can/can_eps.c +++ b/libs/can/can_eps.c @@ -2,22 +2,23 @@ #define STATUS_DLC 6u -void can_encode_eps_status(can_frame_t *f, const can_eps_status_t *s) -{ +void can_encode_eps_status(can_frame_t *f, const can_eps_status_t *s) { can_frame_init(f, CAN_PRIO_INFO, CAN_SRC_EPS, CAN_EPS_STATUS, STATUS_DLC); can_put_i16(&f->data[0], s->current_ma); can_put_i16(&f->data[2], s->shunt_mv_x100); can_put_i16(&f->data[4], s->temp_c_x10); } -bool can_decode_eps_status(const can_frame_t *f, can_eps_status_t *out) -{ - if (f == NULL || out == NULL) return false; - if (f->id != can_make_id(CAN_PRIO_INFO, CAN_SRC_EPS, CAN_EPS_STATUS)) return false; - if (f->dlc < STATUS_DLC) return false; +bool can_decode_eps_status(const can_frame_t *f, can_eps_status_t *out) { + if (f == NULL || out == NULL) + return false; + if (f->id != can_make_id(CAN_PRIO_INFO, CAN_SRC_EPS, CAN_EPS_STATUS)) + return false; + if (f->dlc < STATUS_DLC) + return false; - out->current_ma = can_get_i16(&f->data[0]); + out->current_ma = can_get_i16(&f->data[0]); out->shunt_mv_x100 = can_get_i16(&f->data[2]); - out->temp_c_x10 = can_get_i16(&f->data[4]); + out->temp_c_x10 = can_get_i16(&f->data[4]); return true; } \ No newline at end of file diff --git a/libs/can/can_instr.c b/libs/can/can_instr.c index 4885a3a..f89febc 100644 --- a/libs/can/can_instr.c +++ b/libs/can/can_instr.c @@ -2,134 +2,129 @@ #include "protocol.h" /* Little-endian packing helpers, explicit rather than memcpy'ing */ -static void put_i16(uint8_t *p, int16_t v) { p[0] = (uint8_t)(v & 0xFF); p[1] = (uint8_t)((v >> 8) & 0xFF); } -static void put_u16(uint8_t *p, uint16_t v) { p[0] = (uint8_t)(v & 0xFF); p[1] = (uint8_t)((v >> 8) & 0xFF); } -static void put_i32(uint8_t *p, int32_t v) -{ +static void put_i16(uint8_t *p, int16_t v) { + p[0] = (uint8_t)(v & 0xFF); + p[1] = (uint8_t)((v >> 8) & 0xFF); +} +static void put_u16(uint8_t *p, uint16_t v) { + p[0] = (uint8_t)(v & 0xFF); + p[1] = (uint8_t)((v >> 8) & 0xFF); +} +static void put_i32(uint8_t *p, int32_t v) { p[0] = (uint8_t)(v & 0xFF); p[1] = (uint8_t)((v >> 8) & 0xFF); p[2] = (uint8_t)((v >> 16) & 0xFF); p[3] = (uint8_t)((v >> 24) & 0xFF); } -static int16_t get_i16(const uint8_t *p) { return (int16_t)((uint16_t)p[0] | ((uint16_t)p[1] << 8)); } +static int16_t get_i16(const uint8_t *p) { return (int16_t)((uint16_t)p[0] | ((uint16_t)p[1] << 8)); } static uint16_t get_u16(const uint8_t *p) { return (uint16_t)((uint16_t)p[0] | ((uint16_t)p[1] << 8)); } -static int32_t get_i32(const uint8_t *p) -{ +static int32_t get_i32(const uint8_t *p) { return (int32_t)((uint32_t)p[0] | ((uint32_t)p[1] << 8) | ((uint32_t)p[2] << 16) | ((uint32_t)p[3] << 24)); } -static void make_frame(can_frame_t *f, uint32_t type, uint8_t dlc) -{ - f->id = can_make_id(CAN_PRIO_INFO, CAN_SRC_INSTRUMENTATION, type); +static void make_frame(can_frame_t *f, uint32_t type, uint8_t dlc) { + f->id = can_make_id(CAN_PRIO_INFO, CAN_SRC_INSTRUMENTATION, type); f->dlc = dlc; } -static bool frame_is(const can_frame_t *f, uint32_t type, uint8_t min_dlc) -{ +static bool frame_is(const can_frame_t *f, uint32_t type, uint8_t min_dlc) { return can_id_type(f->id) == type && f->dlc >= min_dlc; } -void can_encode_pressure(can_frame_t *f, const can_instr_pressure_t *s) -{ +void can_encode_pressure(can_frame_t *f, const can_instr_pressure_t *s) { make_frame(f, CAN_MSG_PRESSURE, 4); put_i32(&f->data[0], s->pressure_mbar_x10); } -bool can_decode_pressure(const can_frame_t *f, can_instr_pressure_t *out) -{ - if (!frame_is(f, CAN_MSG_PRESSURE, 4)) return false; +bool can_decode_pressure(const can_frame_t *f, can_instr_pressure_t *out) { + if (!frame_is(f, CAN_MSG_PRESSURE, 4)) + return false; out->pressure_mbar_x10 = get_i32(&f->data[0]); return true; } -void can_encode_altitude(can_frame_t *f, const can_instr_altitude_t *s) -{ +void can_encode_altitude(can_frame_t *f, const can_instr_altitude_t *s) { make_frame(f, CAN_MSG_ALTITUDE, 4); put_i32(&f->data[0], s->altitude_m_x10); } -bool can_decode_altitude(const can_frame_t *f, can_instr_altitude_t *out) -{ - if (!frame_is(f, CAN_MSG_ALTITUDE, 4)) return false; +bool can_decode_altitude(const can_frame_t *f, can_instr_altitude_t *out) { + if (!frame_is(f, CAN_MSG_ALTITUDE, 4)) + return false; out->altitude_m_x10 = get_i32(&f->data[0]); return true; } -void can_encode_housekeeping(can_frame_t *f, const can_instr_housekeeping_t *s) -{ +void can_encode_housekeeping(can_frame_t *f, const can_instr_housekeeping_t *s) { make_frame(f, CAN_MSG_HOUSEKEEPING, 8); put_i32(&f->data[0], s->pressure_mbar_x10); put_i32(&f->data[4], s->altitude_m_x10); } -bool can_decode_housekeeping(const can_frame_t *f, can_instr_housekeeping_t *out) -{ - if (!frame_is(f, CAN_MSG_HOUSEKEEPING, 8)) return false; +bool can_decode_housekeeping(const can_frame_t *f, can_instr_housekeeping_t *out) { + if (!frame_is(f, CAN_MSG_HOUSEKEEPING, 8)) + return false; out->pressure_mbar_x10 = get_i32(&f->data[0]); - out->altitude_m_x10 = get_i32(&f->data[4]); + out->altitude_m_x10 = get_i32(&f->data[4]); return true; } -void can_encode_humidity(can_frame_t *f, const can_instr_humidity_t *s) -{ +void can_encode_humidity(can_frame_t *f, const can_instr_humidity_t *s) { make_frame(f, CAN_MSG_HUMIDITY, 4); put_i16(&f->data[0], s->temp_c_x10); put_i16(&f->data[2], s->rh_pct_x10); } -bool can_decode_humidity(const can_frame_t *f, can_instr_humidity_t *out) -{ - if (!frame_is(f, CAN_MSG_HUMIDITY, 4)) return false; +bool can_decode_humidity(const can_frame_t *f, can_instr_humidity_t *out) { + if (!frame_is(f, CAN_MSG_HUMIDITY, 4)) + return false; out->temp_c_x10 = get_i16(&f->data[0]); out->rh_pct_x10 = get_i16(&f->data[2]); return true; } -void can_encode_gas(can_frame_t *f, const can_instr_gas_t *s) -{ +void can_encode_gas(can_frame_t *f, const can_instr_gas_t *s) { make_frame(f, CAN_MSG_GAS, 6); put_u16(&f->data[0], s->co2_ppm); put_i16(&f->data[2], s->temp_c_x10); put_i16(&f->data[4], s->rh_pct_x10); } -bool can_decode_gas(const can_frame_t *f, can_instr_gas_t *out) -{ - if (!frame_is(f, CAN_MSG_GAS, 6)) return false; - out->co2_ppm = get_u16(&f->data[0]); +bool can_decode_gas(const can_frame_t *f, can_instr_gas_t *out) { + if (!frame_is(f, CAN_MSG_GAS, 6)) + return false; + out->co2_ppm = get_u16(&f->data[0]); out->temp_c_x10 = get_i16(&f->data[2]); out->rh_pct_x10 = get_i16(&f->data[4]); return true; } -void can_encode_accel(can_frame_t *f, const can_instr_accel_t *s) -{ +void can_encode_accel(can_frame_t *f, const can_instr_accel_t *s) { make_frame(f, CAN_MSG_ACCEL, 6); put_i16(&f->data[0], s->ax_mmss); put_i16(&f->data[2], s->ay_mmss); put_i16(&f->data[4], s->az_mmss); } -bool can_decode_accel(const can_frame_t *f, can_instr_accel_t *out) -{ - if (!frame_is(f, CAN_MSG_ACCEL, 6)) return false; +bool can_decode_accel(const can_frame_t *f, can_instr_accel_t *out) { + if (!frame_is(f, CAN_MSG_ACCEL, 6)) + return false; out->ax_mmss = get_i16(&f->data[0]); out->ay_mmss = get_i16(&f->data[2]); out->az_mmss = get_i16(&f->data[4]); return true; } -void can_encode_status(can_frame_t *f, const can_instr_status_t *s) -{ +void can_encode_status(can_frame_t *f, const can_instr_status_t *s) { make_frame(f, CAN_MSG_STATUS, 3); f->data[0] = s->sensor_status; put_i16(&f->data[1], s->board_temp_c_x10); } -bool can_decode_status(const can_frame_t *f, can_instr_status_t *out) -{ - if (!frame_is(f, CAN_MSG_STATUS, 3)) return false; - out->sensor_status = f->data[0]; +bool can_decode_status(const can_frame_t *f, can_instr_status_t *out) { + if (!frame_is(f, CAN_MSG_STATUS, 3)) + return false; + out->sensor_status = f->data[0]; out->board_temp_c_x10 = get_i16(&f->data[1]); return true; } \ No newline at end of file diff --git a/libs/can/can_instr.h b/libs/can/can_instr.h index cec674c..cda9854 100644 --- a/libs/can/can_instr.h +++ b/libs/can/can_instr.h @@ -14,21 +14,21 @@ extern "C" { #endif -#define CAN_MSG_PRESSURE 0x01u -#define CAN_MSG_ALTITUDE 0x02u -#define CAN_MSG_HOUSEKEEPING 0x03u +#define CAN_MSG_PRESSURE 0x01u +#define CAN_MSG_ALTITUDE 0x02u +#define CAN_MSG_HOUSEKEEPING 0x03u // New (not in SED) messages for sensing -#define CAN_MSG_HUMIDITY 0x04u -#define CAN_MSG_GAS 0x05u -#define CAN_MSG_ACCEL 0x06u -#define CAN_MSG_STATUS 0x07u +#define CAN_MSG_HUMIDITY 0x04u +#define CAN_MSG_GAS 0x05u +#define CAN_MSG_ACCEL 0x06u +#define CAN_MSG_STATUS 0x07u #define CAN_INSTR_STATUS_BARO (1u << 0) /**< MS5611 */ -#define CAN_INSTR_STATUS_SHT (1u << 1) /**< SHT45 */ -#define CAN_INSTR_STATUS_GAS (1u << 2) /**< SCD41 */ -#define CAN_INSTR_STATUS_IMU (1u << 3) /**< BNO08x */ -#define CAN_INSTR_STATUS_ADS (1u << 4) /**< ADS1115 */ +#define CAN_INSTR_STATUS_SHT (1u << 1) /**< SHT45 */ +#define CAN_INSTR_STATUS_GAS (1u << 2) /**< SCD41 */ +#define CAN_INSTR_STATUS_IMU (1u << 3) /**< BNO08x */ +#define CAN_INSTR_STATUS_ADS (1u << 4) /**< ADS1115 */ typedef struct { int32_t pressure_mbar_x10; @@ -50,8 +50,8 @@ typedef struct { typedef struct { uint16_t co2_ppm; - int16_t temp_c_x10; - int16_t rh_pct_x10; + int16_t temp_c_x10; + int16_t rh_pct_x10; } can_instr_gas_t; typedef struct { @@ -61,8 +61,8 @@ typedef struct { } can_instr_accel_t; typedef struct { - uint8_t sensor_status; /**< bitmask, CAN_INSTR_STATUS_* */ - int16_t board_temp_c_x10; + uint8_t sensor_status; /**< bitmask, CAN_INSTR_STATUS_* */ + int16_t board_temp_c_x10; } can_instr_status_t; void can_encode_pressure(can_frame_t *f, const can_instr_pressure_t *s); diff --git a/libs/can/can_master.c b/libs/can/can_master.c index 79d669b..b22795b 100644 --- a/libs/can/can_master.c +++ b/libs/can/can_master.c @@ -2,8 +2,7 @@ #define STATUS_DLC 8u -void can_encode_master_status(can_frame_t *f, const can_master_status_t *s) -{ +void can_encode_master_status(can_frame_t *f, const can_master_status_t *s) { can_frame_init(f, CAN_PRIO_INFO, CAN_SRC_MASTER, CAN_MSG_MASTER_STATUS, STATUS_DLC); can_put_u32(&f->data[0], s->uptime_s); can_put_u16(&f->data[4], s->uplink_cmds); @@ -11,15 +10,17 @@ void can_encode_master_status(can_frame_t *f, const can_master_status_t *s) f->data[7] = s->dl_drops; } -bool can_decode_master_status(const can_frame_t *f, can_master_status_t *out) -{ - if (f == NULL || out == NULL) return false; - if (f->id != can_make_id(CAN_PRIO_INFO, CAN_SRC_MASTER, CAN_MSG_MASTER_STATUS)) return false; - if (f->dlc < STATUS_DLC) return false; +bool can_decode_master_status(const can_frame_t *f, can_master_status_t *out) { + if (f == NULL || out == NULL) + return false; + if (f->id != can_make_id(CAN_PRIO_INFO, CAN_SRC_MASTER, CAN_MSG_MASTER_STATUS)) + return false; + if (f->dlc < STATUS_DLC) + return false; - out->uptime_s = can_get_u32(&f->data[0]); + out->uptime_s = can_get_u32(&f->data[0]); out->uplink_cmds = can_get_u16(&f->data[4]); out->chip_temp_c = (int8_t)f->data[6]; - out->dl_drops = f->data[7]; + out->dl_drops = f->data[7]; return true; } \ No newline at end of file diff --git a/libs/can/can_master.h b/libs/can/can_master.h index 1df7031..b3f4c21 100644 --- a/libs/can/can_master.h +++ b/libs/can/can_master.h @@ -16,10 +16,10 @@ extern "C" { /** @brief MASTER_STATUS contents. */ typedef struct { - uint32_t uptime_s; /**< Seconds since boot */ - uint16_t uplink_cmds; /**< TT&C uplink commands processed since boot */ - int8_t chip_temp_c; /**< Whole degrees C not floating */ - uint8_t dl_drops; /**< Downlink queue-overflow + no-link drops... Note this can saturate if errors enough */ + uint32_t uptime_s; /**< Seconds since boot */ + uint16_t uplink_cmds; /**< TT&C uplink commands processed since boot */ + int8_t chip_temp_c; /**< Whole degrees C not floating */ + uint8_t dl_drops; /**< Downlink queue-overflow + no-link drops... Note this can saturate if errors enough */ } can_master_status_t; /** @brief Encode MASTER_STATUS (INFO priority, source Master) */ diff --git a/libs/can/can_photonics.c b/libs/can/can_photonics.c index 3490758..655d6b8 100644 --- a/libs/can/can_photonics.c +++ b/libs/can/can_photonics.c @@ -3,63 +3,59 @@ /* Little-endian packing helpers, same approach as can_instr.c/can_master.c */ -static void put_i16(uint8_t *p, int16_t v) { p[0] = (uint8_t)(v & 0xFF); p[1] = (uint8_t)((v >> 8) & 0xFF); } -static void put_i32(uint8_t *p, int32_t v) -{ +static void put_i16(uint8_t *p, int16_t v) { + p[0] = (uint8_t)(v & 0xFF); + p[1] = (uint8_t)((v >> 8) & 0xFF); +} +static void put_i32(uint8_t *p, int32_t v) { p[0] = (uint8_t)(v & 0xFF); p[1] = (uint8_t)((v >> 8) & 0xFF); p[2] = (uint8_t)((v >> 16) & 0xFF); p[3] = (uint8_t)((v >> 24) & 0xFF); } static int16_t get_i16(const uint8_t *p) { return (int16_t)((uint16_t)p[0] | ((uint16_t)p[1] << 8)); } -static int32_t get_i32(const uint8_t *p) -{ +static int32_t get_i32(const uint8_t *p) { return (int32_t)((uint32_t)p[0] | ((uint32_t)p[1] << 8) | ((uint32_t)p[2] << 16) | ((uint32_t)p[3] << 24)); } -static void make_frame(can_frame_t *f, uint32_t type, uint8_t dlc) -{ - f->id = can_make_id(CAN_PRIO_INFO, CAN_SRC_PHOTONICS, type); +static void make_frame(can_frame_t *f, uint32_t type, uint8_t dlc) { + f->id = can_make_id(CAN_PRIO_INFO, CAN_SRC_PHOTONICS, type); f->dlc = dlc; } -static bool frame_is(const can_frame_t *f, uint32_t type, uint8_t min_dlc) -{ +static bool frame_is(const can_frame_t *f, uint32_t type, uint8_t min_dlc) { return can_id_type(f->id) == type && f->dlc >= min_dlc; } -void can_encode_uv0(can_frame_t *f, const can_photonics_uv_t *s) -{ +void can_encode_uv0(can_frame_t *f, const can_photonics_uv_t *s) { make_frame(f, CAN_MSG_UV0, 8); put_i32(&f->data[0], s->lux_x10); put_i32(&f->data[4], s->uvi_x1000); } -bool can_decode_uv0(const can_frame_t *f, can_photonics_uv_t *out) -{ - if (!frame_is(f, CAN_MSG_UV0, 8)) return false; - out->lux_x10 = get_i32(&f->data[0]); +bool can_decode_uv0(const can_frame_t *f, can_photonics_uv_t *out) { + if (!frame_is(f, CAN_MSG_UV0, 8)) + return false; + out->lux_x10 = get_i32(&f->data[0]); out->uvi_x1000 = get_i32(&f->data[4]); return true; } -void can_encode_uv1(can_frame_t *f, const can_photonics_uv_t *s) -{ +void can_encode_uv1(can_frame_t *f, const can_photonics_uv_t *s) { make_frame(f, CAN_MSG_UV1, 8); put_i32(&f->data[0], s->lux_x10); put_i32(&f->data[4], s->uvi_x1000); } -bool can_decode_uv1(const can_frame_t *f, can_photonics_uv_t *out) -{ - if (!frame_is(f, CAN_MSG_UV1, 8)) return false; - out->lux_x10 = get_i32(&f->data[0]); +bool can_decode_uv1(const can_frame_t *f, can_photonics_uv_t *out) { + if (!frame_is(f, CAN_MSG_UV1, 8)) + return false; + out->lux_x10 = get_i32(&f->data[0]); out->uvi_x1000 = get_i32(&f->data[4]); return true; } -void can_encode_adc(can_frame_t *f, const can_photonics_adc_t *s) -{ +void can_encode_adc(can_frame_t *f, const can_photonics_adc_t *s) { make_frame(f, CAN_MSG_ADC, 8); put_i16(&f->data[0], s->mv[0]); put_i16(&f->data[2], s->mv[1]); @@ -67,9 +63,9 @@ void can_encode_adc(can_frame_t *f, const can_photonics_adc_t *s) put_i16(&f->data[6], s->mv[3]); } -bool can_decode_adc(const can_frame_t *f, can_photonics_adc_t *out) -{ - if (!frame_is(f, CAN_MSG_ADC, 8)) return false; +bool can_decode_adc(const can_frame_t *f, can_photonics_adc_t *out) { + if (!frame_is(f, CAN_MSG_ADC, 8)) + return false; out->mv[0] = get_i16(&f->data[0]); out->mv[1] = get_i16(&f->data[2]); out->mv[2] = get_i16(&f->data[4]); diff --git a/libs/can/can_photonics.h b/libs/can/can_photonics.h index d521345..6f05730 100644 --- a/libs/can/can_photonics.h +++ b/libs/can/can_photonics.h @@ -24,12 +24,12 @@ extern "C" { #endif -#define CAN_MSG_UV0 0x07u -#define CAN_MSG_UV1 0x08u -#define CAN_MSG_ADC 0x09u +#define CAN_MSG_UV0 0x07u +#define CAN_MSG_UV1 0x08u +#define CAN_MSG_ADC 0x09u typedef struct { - int32_t lux_x10; + int32_t lux_x10; int32_t uvi_x1000; /**< units of 0.001. */ } can_photonics_uv_t; diff --git a/libs/can/esp32/can_bus_twai.c b/libs/can/esp32/can_bus_twai.c index c46cd09..ade7e04 100644 --- a/libs/can/esp32/can_bus_twai.c +++ b/libs/can/esp32/can_bus_twai.c @@ -17,19 +17,18 @@ static const char *TAG = "can_bus"; #define CAN_RX_QUEUE_LEN 64u #define CAN_TX_QUEUE_LEN 16u -#define CAN_ALERTS (TWAI_ALERT_RX_QUEUE_FULL | TWAI_ALERT_BUS_OFF | \ - TWAI_ALERT_BUS_RECOVERED | TWAI_ALERT_ERR_PASS) +#define CAN_ALERTS (TWAI_ALERT_RX_QUEUE_FULL | TWAI_ALERT_BUS_OFF | TWAI_ALERT_BUS_RECOVERED | TWAI_ALERT_ERR_PASS) static uint32_t s_rx_dropped; /* frames lost to RX_QUEUE_FULL since boot */ -static void check_rx_line(int rx_gpio) -{ +static void check_rx_line(int rx_gpio) { gpio_config_t cfg = { .pin_bit_mask = 1ULL << rx_gpio, .mode = GPIO_MODE_INPUT, .pull_up_en = GPIO_PULLUP_ENABLE, }; - if (gpio_config(&cfg) != ESP_OK) return; + if (gpio_config(&cfg) != ESP_OK) + return; int high = 0; const int samples = 200; /* 200 x 50 us = 10 ms, ~5 frame times at 500 kbit/s */ @@ -40,7 +39,8 @@ static void check_rx_line(int rx_gpio) if (high == 0) { ESP_LOGE(TAG, "RX (GPIO%d) stuck LOW: bus held dominant. Check the transceiver " - "(powered? TX/RX swapped?) and CANH/CANL for a short.", rx_gpio); + "(powered? TX/RX swapped?) and CANH/CANL for a short.", + rx_gpio); } else if (high == samples) { ESP_LOGI(TAG, "bus idle before start (no traffic in 10 ms)"); } else { @@ -48,8 +48,7 @@ static void check_rx_line(int rx_gpio) } } -bool can_bus_init(int tx_gpio, int rx_gpio) -{ +bool can_bus_init(int tx_gpio, int rx_gpio) { check_rx_line(rx_gpio); twai_general_config_t g = TWAI_GENERAL_CONFIG_DEFAULT( @@ -67,14 +66,13 @@ bool can_bus_init(int tx_gpio, int rx_gpio) } s_rx_dropped = 0; ESP_LOGI(TAG, "CAN up, TX=%d RX=%d, rx_queue=%u%s", tx_gpio, rx_gpio, CAN_RX_QUEUE_LEN, - TWAI_MODE == TWAI_MODE_NO_ACK ? " (SELF-TEST, no ACK needed)" : ""); + TWAI_MODE == TWAI_MODE_NO_ACK ? " (SELF-TEST, no ACK needed)" : ""); return true; } -bool can_bus_send(const can_frame_t *f, uint32_t timeout_ms) -{ - twai_message_t m = {0}; - m.identifier = f->id; +bool can_bus_send(const can_frame_t *f, uint32_t timeout_ms) { + twai_message_t m = { 0 }; + m.identifier = f->id; m.data_length_code = f->dlc; memcpy(m.data, f->data, f->dlc); #ifdef HELIA_CAN_SELF_TEST @@ -83,20 +81,20 @@ bool can_bus_send(const can_frame_t *f, uint32_t timeout_ms) return twai_transmit(&m, pdMS_TO_TICKS(timeout_ms)) == ESP_OK; } -bool can_bus_recv(can_frame_t *f, uint32_t timeout_ms) -{ +bool can_bus_recv(can_frame_t *f, uint32_t timeout_ms) { twai_message_t m; - if (twai_receive(&m, pdMS_TO_TICKS(timeout_ms)) != ESP_OK) return false; - if (m.extd || m.rtr) return false; /* HELIA only uses standard data frames */ + if (twai_receive(&m, pdMS_TO_TICKS(timeout_ms)) != ESP_OK) + return false; + if (m.extd || m.rtr) + return false; /* HELIA only uses standard data frames */ - f->id = m.identifier; + f->id = m.identifier; f->dlc = (m.data_length_code > CAN_MAX_DLC) ? (uint8_t)CAN_MAX_DLC : m.data_length_code; memcpy(f->data, m.data, f->dlc); return true; } -void can_bus_poll_recovery(void) -{ +void can_bus_poll_recovery(void) { uint32_t alerts; if (twai_read_alerts(&alerts, 0) == ESP_OK) { if (alerts & TWAI_ALERT_RX_QUEUE_FULL) { @@ -112,7 +110,8 @@ void can_bus_poll_recovery(void) } twai_status_info_t s; - if (twai_get_status_info(&s) != ESP_OK) return; + if (twai_get_status_info(&s) != ESP_OK) + return; if (s.state == TWAI_STATE_BUS_OFF) { ESP_LOGW(TAG, "bus-off, recovering"); @@ -124,13 +123,11 @@ void can_bus_poll_recovery(void) } /** @brief Frames lost to RX_QUEUE_FULL since can_bus_init(). */ -uint32_t can_bus_dropped_frames(void) -{ +uint32_t can_bus_dropped_frames(void) { return s_rx_dropped; } -void can_bus_log_status(void) -{ +void can_bus_log_status(void) { static const char *const NAMES[] = { "STOPPED", "RUNNING", "BUS_OFF", "RECOVERING" }; twai_status_info_t s; if (twai_get_status_info(&s) != ESP_OK) { @@ -138,9 +135,9 @@ void can_bus_log_status(void) return; } ESP_LOGW(TAG, "state=%s tx_err=%lu rx_err=%lu waiting_to_send=%lu bus_errors=%lu arb_lost=%lu received=%lu rx_dropped=%lu", - (unsigned)s.state < 4 ? NAMES[s.state] : "?", - (unsigned long)s.tx_error_counter, (unsigned long)s.rx_error_counter, - (unsigned long)s.msgs_to_tx, (unsigned long)s.bus_error_count, - (unsigned long)s.arb_lost_count, (unsigned long)s.msgs_to_rx, - (unsigned long)s_rx_dropped); + (unsigned)s.state < 4 ? NAMES[s.state] : "?", + (unsigned long)s.tx_error_counter, (unsigned long)s.rx_error_counter, + (unsigned long)s.msgs_to_tx, (unsigned long)s.bus_error_count, + (unsigned long)s.arb_lost_count, (unsigned long)s.msgs_to_rx, + (unsigned long)s_rx_dropped); } \ No newline at end of file diff --git a/libs/can/protocol.h b/libs/can/protocol.h index 5200139..180798f 100644 --- a/libs/can/protocol.h +++ b/libs/can/protocol.h @@ -2,7 +2,7 @@ * @file protocol.h * @brief HELIA CAN protocol constants: the SED's 11-bit ID scheme and message * dictionary - * This is supposed to be the single source of truth for the entire CAN protocol. + * This is supposed to be the single source of truth for the entire CAN protocol. * If anything changes in here then all codes should be recompiled to match! Any SEDS changes should be reflected here also */ #ifndef HELIA_CAN_PROTOCOL_H @@ -28,42 +28,42 @@ extern "C" { /** @brief Message priority (2 bits), lower value = higher priority */ typedef enum { - CAN_PRIO_CRITICAL = 0x0, + CAN_PRIO_CRITICAL = 0x0, CAN_PRIO_IMPORTANT = 0x1, - CAN_PRIO_WARNING = 0x2, - CAN_PRIO_INFO = 0x3, + CAN_PRIO_WARNING = 0x2, + CAN_PRIO_INFO = 0x3, } can_priority_t; /** @brief Message source (3 bits) */ typedef enum { - CAN_SRC_GROUND = 0x0, /**< Manual command from ground support. */ - CAN_SRC_MASTER = 0x1, /**< OBDH/TT&C */ - CAN_SRC_BROADCAST = 0x2, /**< Commands every node acts on */ - CAN_SRC_MECHANISMS = 0x3, - CAN_SRC_PHOTONICS = 0x4, + CAN_SRC_GROUND = 0x0, /**< Manual command from ground support. */ + CAN_SRC_MASTER = 0x1, /**< OBDH/TT&C */ + CAN_SRC_BROADCAST = 0x2, /**< Commands every node acts on */ + CAN_SRC_MECHANISMS = 0x3, + CAN_SRC_PHOTONICS = 0x4, CAN_SRC_INSTRUMENTATION = 0x5, - CAN_SRC_EPS = 0x6, - CAN_SRC_THERMAL = 0x7, // TODO(hrs) These might need to be reordered in the future + CAN_SRC_EPS = 0x6, + CAN_SRC_THERMAL = 0x7, // TODO(hrs) These might need to be reordered in the future } can_source_t; /** @name Every node */ /**@{*/ -#define CAN_MSG_HEARTBEAT 0x00u +#define CAN_MSG_HEARTBEAT 0x00u /**@}*/ /** @name Broadcast commands (source 0x2) */ /**@{*/ -#define CAN_CMD_UNLOCK_ALL 0x00u /**< IMPORTANT */ -#define CAN_CMD_SLEEP_ALL 0x01u /**< IMPORTANT */ -#define CAN_CMD_RESET_ALL 0x02u /**< CRITICAL */ +#define CAN_CMD_UNLOCK_ALL 0x00u /**< IMPORTANT */ +#define CAN_CMD_SLEEP_ALL 0x01u /**< IMPORTANT */ +#define CAN_CMD_RESET_ALL 0x02u /**< CRITICAL */ #define CAN_CMD_FLIGHT_PHASE 0x03u /**< IMPORTANT */ /**@}*/ /** @name Master per-node commands (source 0x1) */ /**@{*/ #define CAN_CMD_UNLOCK_NODE 0x00u /**< IMPORTANT. Same type as Master HEARTBEAT: priority tells them apart, it works in practice is a bit weird conceptually I might change this later */ -#define CAN_CMD_SLEEP_NODE 0x01u /**< IMPORTANT */ -#define CAN_CMD_RESET_NODE 0x02u /**< CRITICAL */ +#define CAN_CMD_SLEEP_NODE 0x01u /**< IMPORTANT */ +#define CAN_CMD_RESET_NODE 0x02u /**< CRITICAL */ /**@}*/ /** @name Master telemetry (source 0x1), see can_master.h for payload */ @@ -83,8 +83,7 @@ typedef enum { * @brief Pack an 11-bit CAN ID, * Out-of-range inputs are masked so the result is always a valid ID */ -static inline uint32_t can_make_id(can_priority_t prio, can_source_t src, uint8_t type) -{ +static inline uint32_t can_make_id(can_priority_t prio, can_source_t src, uint8_t type) { return (((uint32_t)prio & 0x3u) << 9) | (((uint32_t)src & 0x7u) << 6) | ((uint32_t)type & 0x3Fu); } diff --git a/libs/fsm/fsm.c b/libs/fsm/fsm.c index 526a598..910e3b3 100644 --- a/libs/fsm/fsm.c +++ b/libs/fsm/fsm.c @@ -1,14 +1,15 @@ #include "fsm.h" -fsm_state_t fsm_next(fsm_state_t cur, fsm_event_t evt) -{ +fsm_state_t fsm_next(fsm_state_t cur, fsm_event_t evt) { switch (cur) { case FSM_INIT: return (evt == FSM_EVT_INIT_OK) ? FSM_SAFE : FSM_INIT; case FSM_SAFE: - if (evt == FSM_EVT_UNLOCK) return FSM_ACTIVE; - if (evt == FSM_EVT_SLEEP) return FSM_SLEEP; + if (evt == FSM_EVT_UNLOCK) + return FSM_ACTIVE; + if (evt == FSM_EVT_SLEEP) + return FSM_SLEEP; return FSM_SAFE; case FSM_ACTIVE: @@ -18,17 +19,21 @@ fsm_state_t fsm_next(fsm_state_t cur, fsm_event_t evt) return FSM_SLEEP; /* only a reboot (GPIO wake) leaves SLEEP */ default: - return FSM_SAFE; /* corrupted state: fail safe */ + return FSM_SAFE; /* corrupted state: fail safe */ } } -const char *fsm_state_name(fsm_state_t s) -{ +const char *fsm_state_name(fsm_state_t s) { switch (s) { - case FSM_INIT: return "INIT"; - case FSM_SAFE: return "SAFE"; - case FSM_ACTIVE: return "ACTIVE"; - case FSM_SLEEP: return "SLEEP"; - default: return "UNKNOWN"; + case FSM_INIT: + return "INIT"; + case FSM_SAFE: + return "SAFE"; + case FSM_ACTIVE: + return "ACTIVE"; + case FSM_SLEEP: + return "SLEEP"; + default: + return "UNKNOWN"; } } \ No newline at end of file diff --git a/libs/libs.cmake b/libs/libs.cmake index 8607507..dda0e4a 100644 --- a/libs/libs.cmake +++ b/libs/libs.cmake @@ -10,4 +10,4 @@ file(GLOB HELIA_LIB_SIM_SRCS CONFIGURE_DEPENDS ${HELIA_LIB_DIR}/*/sim/*.c) set(HELIA_LIB_INCS ${HELIA_LIB_DIR}/fsm ${HELIA_LIB_DIR}/can - ${HELIA_LIB_DIR}/utilities) // Add more here as they're implemented :> \ No newline at end of file + ${HELIA_LIB_DIR}/utilities) # Add more here as they're implemented :> \ No newline at end of file diff --git a/libs/utilities/util_control.c b/libs/utilities/util_control.c index 86d9470..5f48c09 100644 --- a/libs/utilities/util_control.c +++ b/libs/utilities/util_control.c @@ -1,15 +1,13 @@ #include "util_control.h" #include -void util_bangbang_init(util_bangbang_t *c, float setpoint, float hysteresis) -{ - c->setpoint = setpoint; +void util_bangbang_init(util_bangbang_t *c, float setpoint, float hysteresis) { + c->setpoint = setpoint; c->hysteresis = (hysteresis > 0.0f) ? hysteresis : 0.0f; - c->on = false; + c->on = false; } -bool util_bangbang_update(util_bangbang_t *c, float measured) -{ +bool util_bangbang_update(util_bangbang_t *c, float measured) { if (isnan(measured)) { c->on = false; } else if (measured <= c->setpoint - c->hysteresis) { diff --git a/libs/utilities/util_control.h b/libs/utilities/util_control.h index 84a9f27..39b4ae2 100644 --- a/libs/utilities/util_control.h +++ b/libs/utilities/util_control.h @@ -19,7 +19,7 @@ extern "C" { typedef struct { float setpoint; /**< Target value, e.g. 35.0 degC */ float hysteresis; /**< Half-width of the dead band, e.g. 0.5 degC */ - bool on; /**< Current output. */ + bool on; /**< Current output. */ } util_bangbang_t; /** @brief Set up a controller diff --git a/libs/utilities/util_filter.c b/libs/utilities/util_filter.c index 1c90535..137aa81 100644 --- a/libs/utilities/util_filter.c +++ b/libs/utilities/util_filter.c @@ -1,16 +1,14 @@ #include "util_filter.h" -void util_ema_init(util_ema_t *f, float alpha) -{ - f->alpha = (alpha > 0.0f && alpha <= 1.0f) ? alpha : 1.0f; /* NaN fails both */ - f->value = 0.0f; +void util_ema_init(util_ema_t *f, float alpha) { + f->alpha = (alpha > 0.0f && alpha <= 1.0f) ? alpha : 1.0f; /* NaN fails both */ + f->value = 0.0f; f->seeded = false; } -float util_ema_update(util_ema_t *f, float sample) -{ +float util_ema_update(util_ema_t *f, float sample) { if (!f->seeded) { - f->value = sample; + f->value = sample; f->seeded = true; } else { f->value += f->alpha * (sample - f->value); diff --git a/libs/utilities/util_filter.h b/libs/utilities/util_filter.h index cfd2237..ae3c10e 100644 --- a/libs/utilities/util_filter.h +++ b/libs/utilities/util_filter.h @@ -13,20 +13,20 @@ extern "C" { /** @brief EMA state. */ typedef struct { - float alpha; /**< Smoothing factor, (0, 1) */ - float value; /**< Current filtered output */ - bool seeded; /**< False until the first sample arrives */ + float alpha; /**< Smoothing factor, (0, 1) */ + float value; /**< Current filtered output */ + bool seeded; /**< False until the first sample arrives */ } util_ema_t; /** - * @brief Set up a filter. + * @brief Set up a filter. * An alpha outside (0, 1] (or NaN) becomes 1.0, * i.e. no filtering, rather than a filter that never moves */ void util_ema_init(util_ema_t *f, float alpha); /** - * @brief Add a sample and return the new filtered value. + * @brief Add a sample and return the new filtered value. * The first sample is taken as-is, so the output doesn't ramp up from zero * Range-check samples with util_in_range() before calling this just ot be sure */ diff --git a/libs/utilities/util_math.c b/libs/utilities/util_math.c index 9affa4f..544814b 100644 --- a/libs/utilities/util_math.c +++ b/libs/utilities/util_math.c @@ -1,30 +1,30 @@ #include "util_math.h" #include -bool util_in_range(float v, float lo, float hi) -{ +bool util_in_range(float v, float lo, float hi) { return v >= lo && v <= hi; /* every comparison with NaN is false */ } -float util_clampf(float v, float lo, float hi) -{ - if (!(v >= lo)) return lo; /* also catches NaN */ - if (v > hi) return hi; +float util_clampf(float v, float lo, float hi) { + if (!(v >= lo)) + return lo; /* also catches NaN */ + if (v > hi) + return hi; return v; } -int16_t util_to_i16(float value, float scale) -{ +int16_t util_to_i16(float value, float scale) { float scaled = value * scale; - if (isnan(scaled)) return UTIL_I16_INVALID; + if (isnan(scaled)) + return UTIL_I16_INVALID; /* Clamp BEFORE casting: casting an out-of-range float to int is undefined */ scaled = util_clampf(roundf(scaled), (float)(INT16_MIN + 1), (float)INT16_MAX); return (int16_t)scaled; } -float util_from_i16(int16_t raw, float scale) -{ - if (raw == UTIL_I16_INVALID || scale == 0.0f) return NAN; +float util_from_i16(int16_t raw, float scale) { + if (raw == UTIL_I16_INVALID || scale == 0.0f) + return NAN; return (float)raw / scale; } \ No newline at end of file diff --git a/libs/utilities/util_math.h b/libs/utilities/util_math.h index ac38b84..def2a0f 100644 --- a/libs/utilities/util_math.h +++ b/libs/utilities/util_math.h @@ -18,7 +18,7 @@ extern "C" { #define UTIL_I16_INVALID INT16_MIN /** - * @brief True if lo <= v <= hi. + * @brief True if lo <= v <= hi. * False for NaN, so a broken sensor fails the check * I know what you're thinking, this is a pretty dumb function. The thought behind it is readability but also to avoid common mistakes with comparisons that could risk fucking over the project. */ diff --git a/libs/utilities/util_thermistor.c b/libs/utilities/util_thermistor.c index b5397d5..efb8941 100644 --- a/libs/utilities/util_thermistor.c +++ b/libs/utilities/util_thermistor.c @@ -4,14 +4,15 @@ #define KELVIN 273.15f -float util_ntc_temp_c(const util_ntc_cfg_t *cfg, float adc_mv) -{ - if (cfg == NULL) return NAN; - if (!(cfg->supply_mv > 0.0f && cfg->r_fixed_ohm > 0.0f && - cfg->r0_ohm > 0.0f && cfg->beta > 0.0f)) return NAN; +float util_ntc_temp_c(const util_ntc_cfg_t *cfg, float adc_mv) { + if (cfg == NULL) + return NAN; + if (!(cfg->supply_mv > 0.0f && cfg->r_fixed_ohm > 0.0f && cfg->r0_ohm > 0.0f && cfg->beta > 0.0f)) + return NAN; /* At either rail the thermistor is open or shorted: no information */ - if (!(adc_mv > 0.0f && adc_mv < cfg->supply_mv)) return NAN; + if (!(adc_mv > 0.0f && adc_mv < cfg->supply_mv)) + return NAN; /* Solve the divider for the NTC's resistance */ float r_ntc = cfg->ntc_on_top diff --git a/libs/utilities/util_thermistor.h b/libs/utilities/util_thermistor.h index 93465a0..a73c03d 100644 --- a/libs/utilities/util_thermistor.h +++ b/libs/utilities/util_thermistor.h @@ -15,16 +15,16 @@ extern "C" { #endif -/** @brief Describes one thermistor circuit. +/** @brief Describes one thermistor circuit. * Values are random bullshit AI made up because there's alike 5 different thermistors on the procurement sheet and none of them are right * */ typedef struct { - float supply_mv; - float r_fixed_ohm; - float r0_ohm; - float t0_c; - float beta; - bool ntc_on_top; + float supply_mv; + float r_fixed_ohm; + float r0_ohm; + float t0_c; + float beta; + bool ntc_on_top; } util_ntc_cfg_t; /** diff --git a/libs/utilities/util_timer.c b/libs/utilities/util_timer.c index 6f45d37..748da06 100644 --- a/libs/utilities/util_timer.c +++ b/libs/utilities/util_timer.c @@ -1,8 +1,8 @@ #include "util_timer.h" -bool util_every(uint32_t now_ms, uint32_t *next_ms, uint32_t period_ms) -{ - if ((int32_t)(now_ms - *next_ms) < 0) return false; +bool util_every(uint32_t now_ms, uint32_t *next_ms, uint32_t period_ms) { + if ((int32_t)(now_ms - *next_ms) < 0) + return false; *next_ms = now_ms + period_ms; return true; } \ No newline at end of file diff --git a/src/EPS/HAL/esp32/hal_esp32.c b/src/EPS/HAL/esp32/hal_esp32.c index d881816..e720f82 100644 --- a/src/EPS/HAL/esp32/hal_esp32.c +++ b/src/EPS/HAL/esp32/hal_esp32.c @@ -14,23 +14,24 @@ static const char *TAG = "eps_hal"; // https://www.ti.com/lit/ds/symlink/ina226.pdf #define INA_REG_CONFIG 0x00 -#define INA_REG_SHUNT 0x01 /* signed, 2.5 uV per bit */ +#define INA_REG_SHUNT 0x01 /* signed, 2.5 uV per bit */ #define INA_REG_MFR_ID 0xFE -#define INA_MFR_ID_TI 0x5449 /* "TI" */ +#define INA_MFR_ID_TI 0x5449 /* "TI" */ #define INA_CONFIG_AVG16 0x4527 #define I2C_TIMEOUT_MS 20 -#define I2C_SPEED_HZ 100000 +#define I2C_SPEED_HZ 100000 static i2c_master_bus_handle_t s_bus; static i2c_master_dev_handle_t s_ina; -static bool s_ina_ok; /* false: skip reads instead of logging an I2C error every 100 ms */ +static bool s_ina_ok; /* false: skip reads instead of logging an I2C error every 100 ms */ static bool ina_read(uint8_t reg, uint16_t *out) { uint8_t buf[2]; - if (i2c_master_transmit_receive(s_ina, ®, 1, buf, 2, I2C_TIMEOUT_MS) != ESP_OK) return false; + if (i2c_master_transmit_receive(s_ina, ®, 1, buf, 2, I2C_TIMEOUT_MS) != ESP_OK) + return false; *out = (uint16_t)((buf[0] << 8) | buf[1]); /* INA226 registers are big-endian ESP32s ain't */ return true; @@ -41,9 +42,8 @@ static bool ina_write(uint8_t reg, uint16_t v) { return i2c_master_transmit(s_ina, buf, sizeof buf, I2C_TIMEOUT_MS) == ESP_OK; } -// -static void i2c_scan(void) -{ +// +static void i2c_scan(void) { int found = 0; for (uint16_t addr = 0x08; addr < 0x78; addr++) { if (i2c_master_probe(s_bus, addr, I2C_TIMEOUT_MS) == ESP_OK) { @@ -53,7 +53,7 @@ static void i2c_scan(void) } if (found == 0) { ESP_LOGW(TAG, "> nothing answered: check SDA=%d SCL=%d, don't trust sensor values", - PIN_I2C_SDA, PIN_I2C_SCL); + PIN_I2C_SDA, PIN_I2C_SCL); } } @@ -73,12 +73,14 @@ static bool ina_init(void) { }; uint16_t id = 0; - if (i2c_new_master_bus(&bus_cfg, &s_bus) != ESP_OK) return false; - if (i2c_master_bus_add_device(s_bus, &dev_cfg, &s_ina) != ESP_OK) return false; + if (i2c_new_master_bus(&bus_cfg, &s_bus) != ESP_OK) + return false; + if (i2c_master_bus_add_device(s_bus, &dev_cfg, &s_ina) != ESP_OK) + return false; if (!ina_read(INA_REG_MFR_ID, &id) || id != INA_MFR_ID_TI) { ESP_LOGE(TAG, "INA226 not found at 0x%02X (SDA=%d SCL=%d), scanning I2C bus:", - INA226_ADDR, PIN_I2C_SDA, PIN_I2C_SCL); + INA226_ADDR, PIN_I2C_SDA, PIN_I2C_SCL); i2c_scan(); return false; } @@ -86,54 +88,62 @@ static bool ina_init(void) { } static adc_oneshot_unit_handle_t s_adc; -static adc_cali_handle_t s_cali; -static adc_channel_t s_chan; +static adc_cali_handle_t s_cali; +static adc_channel_t s_chan; -static bool adc_init(void) -{ +static bool adc_init(void) { adc_unit_t unit; - if (adc_oneshot_io_to_channel(PIN_THERMISTOR, &unit, &s_chan) != ESP_OK) return false; + if (adc_oneshot_io_to_channel(PIN_THERMISTOR, &unit, &s_chan) != ESP_OK) + return false; adc_oneshot_unit_init_cfg_t unit_cfg = { .unit_id = unit }; adc_oneshot_chan_cfg_t chan_cfg = { .atten = ADC_ATTEN_DB_12, .bitwidth = ADC_BITWIDTH_DEFAULT }; adc_cali_curve_fitting_config_t cali_cfg = { - .unit_id = unit, .chan = s_chan, .atten = ADC_ATTEN_DB_12, .bitwidth = ADC_BITWIDTH_DEFAULT, + .unit_id = unit, + .chan = s_chan, + .atten = ADC_ATTEN_DB_12, + .bitwidth = ADC_BITWIDTH_DEFAULT, }; - return adc_oneshot_new_unit(&unit_cfg, &s_adc) == ESP_OK && - adc_oneshot_config_channel(s_adc, s_chan, &chan_cfg) == ESP_OK && - adc_cali_create_scheme_curve_fitting(&cali_cfg, &s_cali) == ESP_OK; + return adc_oneshot_new_unit(&unit_cfg, &s_adc) == ESP_OK && adc_oneshot_config_channel(s_adc, s_chan, &chan_cfg) == ESP_OK && adc_cali_create_scheme_curve_fitting(&cali_cfg, &s_cali) == ESP_OK; } -bool hal_init(void) -{ +bool hal_init(void) { bool ok = true; - if (!can_bus_init(PIN_CAN_TX, PIN_CAN_RX)) { ESP_LOGE(TAG, "CAN init failed"); ok = false; } + if (!can_bus_init(PIN_CAN_TX, PIN_CAN_RX)) { + ESP_LOGE(TAG, "CAN init failed"); + ok = false; + } s_ina_ok = ina_init(); - if (!s_ina_ok) ok = false; - if (!adc_init()) { ESP_LOGE(TAG, "thermistor ADC init failed"); ok = false; } + if (!s_ina_ok) + ok = false; + if (!adc_init()) { + ESP_LOGE(TAG, "thermistor ADC init failed"); + ok = false; + } return ok; } -bool hal_get_shunt_mv(float *out) -{ +bool hal_get_shunt_mv(float *out) { uint16_t raw; - if (!s_ina_ok) return false; /* aa */ - if (!ina_read(INA_REG_SHUNT, &raw)) return false; + if (!s_ina_ok) + return false; /* aa */ + if (!ina_read(INA_REG_SHUNT, &raw)) + return false; *out = (float)(int16_t)raw * 0.0025f; /* 2.5 uV per bit */ return true; } -bool hal_get_thermistor_mv(float *out) -{ +bool hal_get_thermistor_mv(float *out) { int raw, mv; - if (adc_oneshot_read(s_adc, s_chan, &raw) != ESP_OK) return false; - if (adc_cali_raw_to_voltage(s_cali, raw, &mv) != ESP_OK) return false; + if (adc_oneshot_read(s_adc, s_chan, &raw) != ESP_OK) + return false; + if (adc_cali_raw_to_voltage(s_cali, raw, &mv) != ESP_OK) + return false; *out = (float)mv; return true; } -void hal_restart(void) -{ +void hal_restart(void) { esp_restart(); } \ No newline at end of file diff --git a/src/EPS/HAL/esp32/pins.h b/src/EPS/HAL/esp32/pins.h index 01ed517..921e8c5 100644 --- a/src/EPS/HAL/esp32/pins.h +++ b/src/EPS/HAL/esp32/pins.h @@ -7,8 +7,8 @@ #define PIN_I2C_SDA 9 #define PIN_I2C_SCL 8 -#define INA226_ADDR 0x40 +#define INA226_ADDR 0x40 -#define PIN_THERMISTOR 13 +#define PIN_THERMISTOR 13 #endif /* HELIA_EPS_PINS_H */ \ No newline at end of file diff --git a/src/EPS/HAL/sim/hal_sim.c b/src/EPS/HAL/sim/hal_sim.c index 215a439..feb5c2d 100644 --- a/src/EPS/HAL/sim/hal_sim.c +++ b/src/EPS/HAL/sim/hal_sim.c @@ -6,7 +6,7 @@ #include #include -#define SIM_SHUNT_MV 35.0f /* ~350 mA through 0.1 ohm */ +#define SIM_SHUNT_MV 35.0f /* ~350 mA through 0.1 ohm */ #define SIM_PCB_TEMP_C 30.0f static unsigned s_tick; @@ -17,34 +17,29 @@ static float wobble(void) /* repeating -0.5% .. +0.5% */ } /* The divider voltage the real circuit would produce at temp_c */ -static float divider_mv(float temp_c) -{ +static float divider_mv(float temp_c) { const util_ntc_cfg_t c = EPS_NTC_CFG; float r_ntc = c.r0_ohm * expf(c.beta * (1.0f / (temp_c + 273.15f) - 1.0f / (c.t0_c + 273.15f))); return c.ntc_on_top ? c.supply_mv * c.r_fixed_ohm / (r_ntc + c.r_fixed_ohm) : c.supply_mv * r_ntc / (r_ntc + c.r_fixed_ohm); } -bool hal_init(void) -{ +bool hal_init(void) { /* The simulated CAN bus is added with the simulator step. */ return true; } -bool hal_get_shunt_mv(float *out) -{ +bool hal_get_shunt_mv(float *out) { *out = SIM_SHUNT_MV * (1.0f + wobble()); return true; } -bool hal_get_thermistor_mv(float *out) -{ +bool hal_get_thermistor_mv(float *out) { *out = divider_mv(SIM_PCB_TEMP_C) * (1.0f + wobble()); return true; } -void hal_restart(void) -{ +void hal_restart(void) { printf("[sim] restart requested\n"); exit(0); } \ No newline at end of file diff --git a/src/EPS/comms.c b/src/EPS/comms.c index 71f88c8..7503ec1 100644 --- a/src/EPS/comms.c +++ b/src/EPS/comms.c @@ -4,34 +4,37 @@ #define ME CAN_SRC_EPS -void eps_comms_init(eps_comms_t *c, uint32_t now_ms) -{ - c->state = FSM_INIT; +void eps_comms_init(eps_comms_t *c, uint32_t now_ms) { + c->state = FSM_INIT; c->next_heartbeat_ms = now_ms; - c->next_status_ms = now_ms; - c->reset_requested = false; + c->next_status_ms = now_ms; + c->reset_requested = false; } -void eps_comms_boot_done(eps_comms_t *c) -{ +void eps_comms_boot_done(eps_comms_t *c) { c->state = fsm_next(c->state, FSM_EVT_INIT_OK); } -void eps_comms_on_frame(eps_comms_t *c, const can_frame_t *rx) -{ +void eps_comms_on_frame(eps_comms_t *c, const can_frame_t *rx) { switch (can_decode_sys_cmd(rx, ME)) { - case CAN_SYS_UNLOCK: c->state = fsm_next(c->state, FSM_EVT_UNLOCK); break; - case CAN_SYS_SLEEP: c->state = fsm_next(c->state, FSM_EVT_SLEEP); break; - case CAN_SYS_RESET: c->reset_requested = true; break; + case CAN_SYS_UNLOCK: + c->state = fsm_next(c->state, FSM_EVT_UNLOCK); + break; + case CAN_SYS_SLEEP: + c->state = fsm_next(c->state, FSM_EVT_SLEEP); + break; + case CAN_SYS_RESET: + c->reset_requested = true; + break; // base case - case CAN_SYS_NONE: break; + case CAN_SYS_NONE: + break; } } size_t eps_comms_on_tick(eps_comms_t *c, uint32_t now_ms, - const eps_data_t *latest, can_frame_t tx[EPS_COMMS_MAX_TX]) -{ + const eps_data_t *latest, can_frame_t tx[EPS_COMMS_MAX_TX]) { size_t n = 0; if (util_every(now_ms, &c->next_heartbeat_ms, CAN_HEARTBEAT_PERIOD_MS)) { diff --git a/src/EPS/comms.h b/src/EPS/comms.h index c1f1046..b03a6f0 100644 --- a/src/EPS/comms.h +++ b/src/EPS/comms.h @@ -16,24 +16,23 @@ extern "C" { #endif -#define EPS_COMMS_MAX_TX 2 +#define EPS_COMMS_MAX_TX 2 #define EPS_STATUS_PERIOD_MS 1000u typedef struct { fsm_state_t state; - uint32_t next_heartbeat_ms; - uint32_t next_status_ms; - bool reset_requested; // shit + uint32_t next_heartbeat_ms; + uint32_t next_status_ms; + bool reset_requested; // shit } eps_comms_t; - void eps_comms_init(eps_comms_t *c, uint32_t now_ms); // Double checks we're in SAFE after boot void eps_comms_boot_done(eps_comms_t *c); void eps_comms_on_frame(eps_comms_t *c, const can_frame_t *rx); size_t eps_comms_on_tick(eps_comms_t *c, uint32_t now_ms, - const eps_data_t *latest, can_frame_t tx[EPS_COMMS_MAX_TX]); + const eps_data_t *latest, can_frame_t tx[EPS_COMMS_MAX_TX]); #ifdef __cplusplus } diff --git a/src/EPS/control.c b/src/EPS/control.c index 29153f7..4c32c2a 100644 --- a/src/EPS/control.c +++ b/src/EPS/control.c @@ -1,27 +1,24 @@ #include "control.h" #include "util_math.h" -void eps_control_init(eps_control_t *c) -{ +void eps_control_init(eps_control_t *c) { c->ntc = (util_ntc_cfg_t)EPS_NTC_CFG; util_ema_init(&c->temp_filter, EPS_TEMP_ALPHA); } -void eps_data_init(eps_data_t *d) -{ - d->current_ma = UTIL_I16_INVALID; +void eps_data_init(eps_data_t *d) { + d->current_ma = UTIL_I16_INVALID; d->shunt_mv_x100 = UTIL_I16_INVALID; - d->temp_c_x10 = UTIL_I16_INVALID; + d->temp_c_x10 = UTIL_I16_INVALID; } -void eps_control_step(eps_control_t *c, const eps_raw_t *raw, eps_data_t *out) -{ +void eps_control_step(eps_control_t *c, const eps_raw_t *raw, eps_data_t *out) { eps_data_init(out); - // Filter isn't needed + // Filter isn't needed if (raw->shunt_ok && util_in_range(raw->shunt_mv, -EPS_SHUNT_MV_MAX, EPS_SHUNT_MV_MAX)) { out->shunt_mv_x100 = util_to_i16(raw->shunt_mv, 100.0f); - out->current_ma = util_to_i16(raw->shunt_mv / EPS_SHUNT_OHMS, 1.0f); /* mV / ohm = mA */ + out->current_ma = util_to_i16(raw->shunt_mv / EPS_SHUNT_OHMS, 1.0f); /* mV / ohm = mA */ } if (raw->therm_ok && raw->therm_mv < EPS_ADC_MAX_MV) { diff --git a/src/EPS/control.h b/src/EPS/control.h index 70a7ca9..9400623 100644 --- a/src/EPS/control.h +++ b/src/EPS/control.h @@ -14,25 +14,24 @@ extern "C" { #endif -#define EPS_SHUNT_OHMS 0.1f // Resistor value in ohms: shunt voltage / shunt resistance = current in amps (pookie recommended) -#define EPS_SHUNT_MV_MAX 81.9f - -#define EPS_NTC_CFG { .supply_mv = 5000.0f, .r_fixed_ohm = 10000.0f, .r0_ohm = 10000.0f, \ - .t0_c = 25.0f, .beta = 3950.0f, .ntc_on_top = true } +#define EPS_SHUNT_OHMS 0.1f // Resistor value in ohms: shunt voltage / shunt resistance = current in amps (pookie recommended) +#define EPS_SHUNT_MV_MAX 81.9f +#define EPS_NTC_CFG \ + { .supply_mv = 5000.0f, .r_fixed_ohm = 10000.0f, .r0_ohm = 10000.0f, \ + .t0_c = 25.0f, .beta = 3950.0f, .ntc_on_top = true } #define EPS_ADC_MAX_MV 3000.0f -#define EPS_TEMP_MIN_C -40.0f -#define EPS_TEMP_MAX_C 125.0f // double check - -#define EPS_TEMP_ALPHA 0.2f +#define EPS_TEMP_MIN_C -40.0f +#define EPS_TEMP_MAX_C 125.0f // double check +#define EPS_TEMP_ALPHA 0.2f typedef struct { - bool shunt_ok; + bool shunt_ok; float shunt_mv; - bool therm_ok; + bool therm_ok; float therm_mv; } eps_raw_t; @@ -44,10 +43,9 @@ typedef struct { typedef struct { util_ntc_cfg_t ntc; - util_ema_t temp_filter; + util_ema_t temp_filter; } eps_control_t; - void eps_control_init(eps_control_t *c); void eps_data_init(eps_data_t *d); diff --git a/src/EPS/setup.c b/src/EPS/setup.c index 4caad1b..ce62c8d 100644 --- a/src/EPS/setup.c +++ b/src/EPS/setup.c @@ -13,18 +13,16 @@ static const char *TAG = "eps"; #define CONTROL_PERIOD_MS 100u /* 10 Hz sampling */ -#define RX_TIMEOUT_MS 20u /* how long comms waits for a frame each loop */ -#define TX_TIMEOUT_MS 10u +#define RX_TIMEOUT_MS 20u /* how long comms waits for a frame each loop */ +#define TX_TIMEOUT_MS 10u /* Length-1 queue used as a mailbox: control overwrites, comms peeks the latest. */ static QueueHandle_t s_latest; -static uint32_t now_ms(void) -{ +static uint32_t now_ms(void) { return (uint32_t)pdTICKS_TO_MS(xTaskGetTickCount()); } -static void control_task(void *arg) -{ +static void control_task(void *arg) { (void)arg; eps_control_t ctl; eps_control_init(&ctl); @@ -43,8 +41,7 @@ static void control_task(void *arg) } } -static void comms_task(void *arg) -{ +static void comms_task(void *arg) { (void)arg; eps_comms_t comms; uint32_t last_status_log_ms = 0; @@ -62,7 +59,8 @@ static void comms_task(void *arg) eps_comms_on_frame(&comms, &rx); } - if (xQueuePeek(s_latest, &latest, 0) != pdTRUE) eps_data_init(&latest); + if (xQueuePeek(s_latest, &latest, 0) != pdTRUE) + eps_data_init(&latest); size_t n = eps_comms_on_tick(&comms, now_ms(), &latest, tx); for (size_t i = 0; i < n; i++) { if (!can_bus_send(&tx[i], TX_TIMEOUT_MS)) { @@ -74,20 +72,21 @@ static void comms_task(void *arg) } } - if (comms.state != before) ESP_LOGI(TAG, "state %s -> %s", fsm_state_name(before), fsm_state_name(comms.state)); - if (comms.reset_requested) hal_restart(); + if (comms.state != before) + ESP_LOGI(TAG, "state %s -> %s", fsm_state_name(before), fsm_state_name(comms.state)); + if (comms.reset_requested) + hal_restart(); can_bus_poll_recovery(); } } - -void app_main(void) -{ +void app_main(void) { ESP_LOGI(TAG, "boot"); - if (!hal_init()) ESP_LOGE(TAG, "hardware init incomplete; affected readings will be sent as invalid"); + if (!hal_init()) + ESP_LOGE(TAG, "hardware init incomplete; affected readings will be sent as invalid"); s_latest = xQueueCreate(1, sizeof(eps_data_t)); - xTaskCreatePinnedToCore(comms_task, "eps_comms", 4096, NULL, 10, NULL, 0); - xTaskCreatePinnedToCore(control_task, "eps_control", 4096, NULL, 5, NULL, 1); + xTaskCreatePinnedToCore(comms_task, "eps_comms", 4096, NULL, 10, NULL, 0); + xTaskCreatePinnedToCore(control_task, "eps_control", 4096, NULL, 5, NULL, 1); } \ No newline at end of file diff --git a/src/Instrumentation/HAL/esp32/hal_esp32.c b/src/Instrumentation/HAL/esp32/hal_esp32.c index bb48da6..a7368ba 100644 --- a/src/Instrumentation/HAL/esp32/hal_esp32.c +++ b/src/Instrumentation/HAL/esp32/hal_esp32.c @@ -2,7 +2,7 @@ * ESP32 HAL instrumentation * Fair warning: this is a bit of a mess, some sensors work and others dont * it needs a proper debugging session to iron out issues, might delegate it to an intern >:) -*/ + */ #include "hal.h" #include @@ -14,30 +14,29 @@ #include "driver/i2c.h" #include "can_bus.h" -#include "pins.h" +#include "pins.h" static const char *TAG = "instr_hal"; -// I've double checked these should be right, might move to pins.h later? +// I've double checked these should be right, might move to pins.h later? #define SDA_GPIO 8 #define SCL_GPIO 9 -#define I2C_HZ 100000 +#define I2C_HZ 100000 #define I2C_PORT I2C_NUM_0 -#define ADDR_SHT45 0x44 -#define ADDR_ADS1115 0x48 -#define ADDR_FSP201 0x4C -#define ADDR_SCD41 0x62 -#define ADDR_MS5611_A 0x76 -#define ADDR_MS5611_B 0x77 +#define ADDR_SHT45 0x44 +#define ADDR_ADS1115 0x48 +#define ADDR_FSP201 0x4C +#define ADDR_SCD41 0x62 +#define ADDR_MS5611_A 0x76 +#define ADDR_MS5611_B 0x77 static bool s_ok_sht45, s_ok_ads1115, s_ok_imu, s_ok_scd41, s_ok_ms5611; static uint8_t s_ms5611_addr; -static uint16_t s_ms5611_c[6]; +static uint16_t s_ms5611_c[6]; static hal_imu_t s_imu_latest; - static bool i2c_probe(uint8_t addr) { i2c_cmd_handle_t cmd = i2c_cmd_link_create(); i2c_master_start(cmd); @@ -52,7 +51,8 @@ static bool i2c_write(uint8_t addr, const uint8_t *data, size_t len) { i2c_cmd_handle_t cmd = i2c_cmd_link_create(); i2c_master_start(cmd); i2c_master_write_byte(cmd, (uint8_t)((addr << 1) | I2C_MASTER_WRITE), true); - if (len) i2c_master_write(cmd, (uint8_t *)data, len, true); + if (len) + i2c_master_write(cmd, (uint8_t *)data, len, true); i2c_master_stop(cmd); esp_err_t err = i2c_master_cmd_begin(I2C_PORT, cmd, pdMS_TO_TICKS(100)); @@ -62,13 +62,15 @@ static bool i2c_write(uint8_t addr, const uint8_t *data, size_t len) { } static bool i2c_read(uint8_t addr, uint8_t *data, size_t len) { - if (len == 0) return true; + if (len == 0) + return true; i2c_cmd_handle_t cmd = i2c_cmd_link_create(); i2c_master_start(cmd); i2c_master_write_byte(cmd, (uint8_t)((addr << 1) | I2C_MASTER_READ), true); - if (len > 1) i2c_master_read(cmd, data, len - 1, I2C_MASTER_ACK); + if (len > 1) + i2c_master_read(cmd, data, len - 1, I2C_MASTER_ACK); i2c_master_read_byte(cmd, data + len - 1, I2C_MASTER_NACK); i2c_master_stop(cmd); @@ -78,17 +80,18 @@ static bool i2c_read(uint8_t addr, uint8_t *data, size_t len) { return err == ESP_OK; } - static bool i2c_write_read(uint8_t addr, const uint8_t *wr, size_t wr_len, uint8_t *rd, size_t rd_len) { i2c_cmd_handle_t cmd = i2c_cmd_link_create(); i2c_master_start(cmd); i2c_master_write_byte(cmd, (uint8_t)((addr << 1) | I2C_MASTER_WRITE), true); - if (wr_len) i2c_master_write(cmd, (uint8_t *)wr, wr_len, true); + if (wr_len) + i2c_master_write(cmd, (uint8_t *)wr, wr_len, true); i2c_master_start(cmd); i2c_master_write_byte(cmd, (uint8_t)((addr << 1) | I2C_MASTER_READ), true); - if (rd_len > 1) i2c_master_read(cmd, rd, rd_len - 1, I2C_MASTER_ACK); + if (rd_len > 1) + i2c_master_read(cmd, rd, rd_len - 1, I2C_MASTER_ACK); i2c_master_read_byte(cmd, rd + rd_len - 1, I2C_MASTER_NACK); i2c_master_stop(cmd); @@ -109,31 +112,35 @@ static uint8_t sensirion_crc8(const uint8_t *data, size_t len) { return crc; } - - hal_sht45_t hal_read_sht45(void) { - hal_sht45_t r = {0}; - if (!s_ok_sht45) return r; + hal_sht45_t r = { 0 }; + if (!s_ok_sht45) + return r; - uint8_t cmd = 0xFD; - if (!i2c_write(ADDR_SHT45, &cmd, 1)) return r; - vTaskDelay(pdMS_TO_TICKS(10)); / + uint8_t cmd = 0xFD; + if (!i2c_write(ADDR_SHT45, &cmd, 1)) + return r; + vTaskDelay(pdMS_TO_TICKS(10)); + / - uint8_t buf[6]; - if (!i2c_read(ADDR_SHT45, buf, sizeof buf)) return r; + uint8_t buf[6]; + if (!i2c_read(ADDR_SHT45, buf, sizeof buf)) + return r; if (sensirion_crc8(&buf[0], 2) != buf[2] || sensirion_crc8(&buf[3], 2) != buf[5]) { ESP_LOGW(TAG, "SHT45 CRC mismatch"); return r; } - uint16_t raw_t = ((uint16_t)buf[0] << 8) | buf[1]; + uint16_t raw_t = ((uint16_t)buf[0] << 8) | buf[1]; uint16_t raw_rh = ((uint16_t)buf[3] << 8) | buf[4]; float temp_c = -45.0f + 175.0f * ((float)raw_t / 65535.0f); float rh_pct = -6.0f + 125.0f * ((float)raw_rh / 65535.0f); - if (rh_pct < 0.0f) rh_pct = 0.0f; - if (rh_pct > 100.0f) rh_pct = 100.0f; + if (rh_pct < 0.0f) + rh_pct = 0.0f; + if (rh_pct > 100.0f) + rh_pct = 100.0f; - r.ok = true; + r.ok = true; r.temp_c_x10 = (int16_t)lroundf(temp_c * 10.0f); r.rh_pct_x10 = (int16_t)lroundf(rh_pct * 10.0f); @@ -141,20 +148,20 @@ hal_sht45_t hal_read_sht45(void) { } hal_ads1115_t hal_read_ads1115(void) { - hal_ads1115_t r = {0}; - if (!s_ok_ads1115) return r; + hal_ads1115_t r = { 0 }; + if (!s_ok_ads1115) + return r; r.ok = true; for (int ch = 0; ch < 4; ch++) { uint16_t mux = (uint16_t)(0x4 + ch); - uint16_t config = (uint16_t)( - (1u << 15) | (mux << 12) | (0x1u << 9) | (1u << 8) | (0x4u << 5) | 0x3u); - uint8_t wr[3] = {0x01, (uint8_t)(config >> 8), (uint8_t)(config & 0xFF)}; + uint16_t config = (uint16_t)((1u << 15) | (mux << 12) | (0x1u << 9) | (1u << 8) | (0x4u << 5) | 0x3u); + uint8_t wr[3] = { 0x01, (uint8_t)(config >> 8), (uint8_t)(config & 0xFF) }; if (!i2c_write(ADDR_ADS1115, wr, sizeof wr)) { r.ok = false; continue; } - vTaskDelay(pdMS_TO_TICKS(10)); + vTaskDelay(pdMS_TO_TICKS(10)); uint8_t ptr = 0x00, rd[2]; if (!i2c_write_read(ADDR_ADS1115, &ptr, 1, rd, sizeof rd)) { @@ -162,12 +169,11 @@ hal_ads1115_t hal_read_ads1115(void) { continue; } int16_t raw = (int16_t)(((uint16_t)rd[0] << 8) | rd[1]); - r.mv[ch] = (int16_t)lroundf(raw * 0.125f); + r.mv[ch] = (int16_t)lroundf(raw * 0.125f); } return r; } - static bool ms5611_read_adc(uint8_t convert_cmd, uint32_t *out) { // TODO(remy): double check with Chrysler } @@ -176,43 +182,45 @@ hal_ms5611_t hal_read_ms5611(void) { // TODO } -static bool scd41_send_cmd(uint16_t cmd) -{ - uint8_t wr[2] = {(uint8_t)(cmd >> 8), (uint8_t)(cmd & 0xFF)}; +static bool scd41_send_cmd(uint16_t cmd) { + uint8_t wr[2] = { (uint8_t)(cmd >> 8), (uint8_t)(cmd & 0xFF) }; return i2c_write(ADDR_SCD41, wr, sizeof wr); } -hal_scd41_t hal_read_scd41(void) -{ - hal_scd41_t r = {0}; - if (!s_ok_scd41) return r; +hal_scd41_t hal_read_scd41(void) { + hal_scd41_t r = { 0 }; + if (!s_ok_scd41) + return r; - if (!scd41_send_cmd(0xE4B8)) return r; /* get_data_ready_status */ + if (!scd41_send_cmd(0xE4B8)) + return r; /* get_data_ready_status */ vTaskDelay(pdMS_TO_TICKS(2)); uint8_t rdy[3]; - if (!i2c_read(ADDR_SCD41, rdy, sizeof rdy)) return r; + if (!i2c_read(ADDR_SCD41, rdy, sizeof rdy)) + return r; uint16_t status = ((uint16_t)rdy[0] << 8) | rdy[1]; - if ((status & 0x07FFu) == 0) return r; /* not ready yet - not an error */ + if ((status & 0x07FFu) == 0) + return r; /* not ready yet - not an error */ - if (!scd41_send_cmd(0xEC05)) return r; /* read_measurement */ + if (!scd41_send_cmd(0xEC05)) + return r; /* read_measurement */ vTaskDelay(pdMS_TO_TICKS(2)); uint8_t buf[9]; - if (!i2c_read(ADDR_SCD41, buf, sizeof buf)) return r; - if (sensirion_crc8(&buf[0], 2) != buf[2] || - sensirion_crc8(&buf[3], 2) != buf[5] || - sensirion_crc8(&buf[6], 2) != buf[8]) { + if (!i2c_read(ADDR_SCD41, buf, sizeof buf)) + return r; + if (sensirion_crc8(&buf[0], 2) != buf[2] || sensirion_crc8(&buf[3], 2) != buf[5] || sensirion_crc8(&buf[6], 2) != buf[8]) { ESP_LOGW(TAG, "SCD41 CRC mismatch"); return r; } - uint16_t co2 = ((uint16_t)buf[0] << 8) | buf[1]; - uint16_t raw_t = ((uint16_t)buf[3] << 8) | buf[4]; + uint16_t co2 = ((uint16_t)buf[0] << 8) | buf[1]; + uint16_t raw_t = ((uint16_t)buf[3] << 8) | buf[4]; uint16_t raw_rh = ((uint16_t)buf[6] << 8) | buf[7]; float temp_c = -45.0f + 175.0f * ((float)raw_t / 65535.0f); float rh_pct = 100.0f * ((float)raw_rh / 65535.0f); - r.ok = true; - r.co2_ppm = co2; + r.ok = true; + r.co2_ppm = co2; r.temp_c_x10 = (int16_t)lroundf(temp_c * 10.0f); r.rh_pct_x10 = (int16_t)lroundf(rh_pct * 10.0f); return r; @@ -224,13 +232,12 @@ hal_scd41_t hal_read_scd41(void) #define SHTP_MAX_PACKET 64 #define SH2_CHAN_CONTROL 2 -#define SH2_CHAN_INPUT 3 +#define SH2_CHAN_INPUT 3 #define SH2_REPORT_SET_FEATURE 0xFD #define SH2_SENSOR_ACCELEROMETER 0x01 -static bool imu_send_set_feature(uint8_t report_id, uint32_t interval_us) -{ - uint8_t payload[17] = {0}; +static bool imu_send_set_feature(uint8_t report_id, uint32_t interval_us) { + uint8_t payload[17] = { 0 }; payload[0] = SH2_REPORT_SET_FEATURE; payload[1] = report_id; payload[5] = (uint8_t)(interval_us & 0xFF); @@ -256,12 +263,12 @@ static bool imu_send_set_feature(uint8_t report_id, uint32_t interval_us) * confirmed working against real hardware. */ static int s_imu_dump_budget = 8; -static void imu_dump_packet(const uint8_t *buf, uint16_t len, uint8_t channel) -{ - if (s_imu_dump_budget <= 0) return; +static void imu_dump_packet(const uint8_t *buf, uint16_t len, uint8_t channel) { + if (s_imu_dump_budget <= 0) + return; s_imu_dump_budget--; - char hex[3 * 20 + 1] = {0}; + char hex[3 * 20 + 1] = { 0 }; int n = (len < 20) ? len : 20; for (int i = 0; i < n; i++) { snprintf(&hex[i * 3], 4, "%02X ", buf[i]); @@ -269,28 +276,32 @@ static void imu_dump_packet(const uint8_t *buf, uint16_t len, uint8_t channel) ESP_LOGI(TAG, "IMU pkt: len=%u chan=%u bytes=%s", len, channel, hex); } -static void hal_poll_imu(void) -{ - if (!s_ok_imu) return; +static void hal_poll_imu(void) { + if (!s_ok_imu) + return; uint8_t buf[SHTP_MAX_PACKET]; - if (!i2c_read(ADDR_FSP201, buf, sizeof buf)) return; + if (!i2c_read(ADDR_FSP201, buf, sizeof buf)) + return; uint16_t len = (uint16_t)(buf[0] | ((buf[1] & 0x7Fu) << 8)); if (len < 4 || len > sizeof buf) { - if (len != 0) imu_dump_packet(buf, sizeof buf, buf[2]); /* garbage/oversized - still worth seeing */ - return; /* nothing pending / garbage */ + if (len != 0) + imu_dump_packet(buf, sizeof buf, buf[2]); /* garbage/oversized - still worth seeing */ + return; /* nothing pending / garbage */ } uint8_t channel = buf[2]; imu_dump_packet(buf, len, channel); - if (channel != SH2_CHAN_INPUT) return; + if (channel != SH2_CHAN_INPUT) + return; for (uint16_t i = 4; i + 10 <= len; i++) { - if (buf[i] != SH2_SENSOR_ACCELEROMETER) continue; + if (buf[i] != SH2_SENSOR_ACCELEROMETER) + continue; int16_t x = (int16_t)(buf[i + 4] | (buf[i + 5] << 8)); int16_t y = (int16_t)(buf[i + 6] | (buf[i + 7] << 8)); int16_t z = (int16_t)(buf[i + 8] | (buf[i + 9] << 8)); - s_imu_latest.ok = true; + s_imu_latest.ok = true; s_imu_latest.ax_mmss = (int16_t)lroundf(x * 3.90625f); /* Q8: raw/256 m/s^2 -> mm/s^2 */ s_imu_latest.ay_mmss = (int16_t)lroundf(y * 3.90625f); s_imu_latest.az_mmss = (int16_t)lroundf(z * 3.90625f); @@ -298,28 +309,26 @@ static void hal_poll_imu(void) } } -hal_imu_t hal_read_imu(void) -{ +hal_imu_t hal_read_imu(void) { hal_poll_imu(); return s_imu_latest; } /* ---- init / restart ------------------------------------------------------ */ -bool hal_init(void) -{ - if (!can_bus_init(PIN_CAN_TX, PIN_CAN_RX)) return false; +bool hal_init(void) { + if (!can_bus_init(PIN_CAN_TX, PIN_CAN_RX)) + return false; i2c_config_t conf = { - .mode = I2C_MODE_MASTER, - .sda_io_num = SDA_GPIO, - .scl_io_num = SCL_GPIO, - .sda_pullup_en = GPIO_PULLUP_DISABLE, /* breakouts have their own external pull-ups */ - .scl_pullup_en = GPIO_PULLUP_DISABLE, + .mode = I2C_MODE_MASTER, + .sda_io_num = SDA_GPIO, + .scl_io_num = SCL_GPIO, + .sda_pullup_en = GPIO_PULLUP_DISABLE, /* breakouts have their own external pull-ups */ + .scl_pullup_en = GPIO_PULLUP_DISABLE, .master.clk_speed = I2C_HZ, }; - if (i2c_param_config(I2C_PORT, &conf) != ESP_OK || - i2c_driver_install(I2C_PORT, conf.mode, 0, 0, 0) != ESP_OK) { + if (i2c_param_config(I2C_PORT, &conf) != ESP_OK || i2c_driver_install(I2C_PORT, conf.mode, 0, 0, 0) != ESP_OK) { ESP_LOGE(TAG, "I2C bus init failed - sensors unavailable this boot"); return true; /* CAN is up, which is what's fatal */ } @@ -344,10 +353,10 @@ bool hal_init(void) } } - s_ok_sht45 = i2c_probe(ADDR_SHT45); + s_ok_sht45 = i2c_probe(ADDR_SHT45); s_ok_ads1115 = i2c_probe(ADDR_ADS1115); - s_ok_imu = i2c_probe(ADDR_FSP201); - s_ok_scd41 = i2c_probe(ADDR_SCD41); + s_ok_imu = i2c_probe(ADDR_FSP201); + s_ok_scd41 = i2c_probe(ADDR_SCD41); /* MS5611's address depends on how its CSB pin is wired (0x76 if tied * high, 0x77 if tied low) - try both rather than assuming. */ @@ -389,20 +398,19 @@ bool hal_init(void) s_ok_imu = imu_send_set_feature(SH2_SENSOR_ACCELEROMETER, 100000 /* 10 Hz */); } - ESP_LOGI(TAG, "SHT45 %s", s_ok_sht45 ? "OK" : "NOT FOUND"); + ESP_LOGI(TAG, "SHT45 %s", s_ok_sht45 ? "OK" : "NOT FOUND"); ESP_LOGI(TAG, "ADS1115 %s", s_ok_ads1115 ? "OK" : "NOT FOUND"); - ESP_LOGI(TAG, "SCD41 %s", s_ok_scd41 ? "OK" : "NOT FOUND"); + ESP_LOGI(TAG, "SCD41 %s", s_ok_scd41 ? "OK" : "NOT FOUND"); if (s_ok_ms5611) { ESP_LOGI(TAG, "MS5611 OK (0x%02X)", s_ms5611_addr); } else { ESP_LOGI(TAG, "MS5611 NOT FOUND"); } - ESP_LOGI(TAG, "FSP201 %s", s_ok_imu ? "OK" : "NOT FOUND"); + ESP_LOGI(TAG, "FSP201 %s", s_ok_imu ? "OK" : "NOT FOUND"); return true; } -void hal_restart(void) -{ +void hal_restart(void) { esp_restart(); } \ No newline at end of file diff --git a/src/Instrumentation/HAL/hal.h b/src/Instrumentation/HAL/hal.h index 5991455..499a62a 100644 --- a/src/Instrumentation/HAL/hal.h +++ b/src/Instrumentation/HAL/hal.h @@ -7,8 +7,8 @@ * - SCD41 (CO2) * - MS5611 (pressure) * - FSP201 (accelerometer) - * - * + * + * */ #ifndef HELIA_INSTRUMENTATION_HAL_H #define HELIA_INSTRUMENTATION_HAL_H @@ -20,46 +20,45 @@ extern "C" { #endif - bool hal_init(void); void hal_restart(void); typedef struct { - bool ok; - int16_t temp_c_x10; - int16_t rh_pct_x10; + bool ok; + int16_t temp_c_x10; + int16_t rh_pct_x10; } hal_sht45_t; typedef struct { - bool ok; + bool ok; int16_t mv[4]; } hal_ads1115_t; typedef struct { - bool ok; + bool ok; uint16_t co2_ppm; - int16_t temp_c_x10; - int16_t rh_pct_x10; + int16_t temp_c_x10; + int16_t rh_pct_x10; } hal_scd41_t; typedef struct { - bool ok; + bool ok; int32_t pressure_mbar_x10; int16_t temp_c_x10; } hal_ms5611_t; typedef struct { - bool ok; - int16_t ax_mmss; + bool ok; + int16_t ax_mmss; int16_t ay_mmss; int16_t az_mmss; } hal_imu_t; // Multiple of these don't work, needs debugging, but the code works for now -hal_sht45_t hal_read_sht45(void); +hal_sht45_t hal_read_sht45(void); hal_ads1115_t hal_read_ads1115(void); -hal_scd41_t hal_read_scd41(void); -hal_ms5611_t hal_read_ms5611(void); // Not working +hal_scd41_t hal_read_scd41(void); +hal_ms5611_t hal_read_ms5611(void); // Not working hal_imu_t hal_read_imu(void); diff --git a/src/Instrumentation/HAL/sim/hal_sim.c b/src/Instrumentation/HAL/sim/hal_sim.c index a9c3977..93451c9 100644 --- a/src/Instrumentation/HAL/sim/hal_sim.c +++ b/src/Instrumentation/HAL/sim/hal_sim.c @@ -3,14 +3,12 @@ #include #include -bool hal_init(void) -{ +bool hal_init(void) { /* The simulated CAN bus is added with the simulator step. */ return true; } -void hal_restart(void) -{ +void hal_restart(void) { printf("[sim] restart requested\n"); exit(0); } \ No newline at end of file diff --git a/src/Instrumentation/comms.c b/src/Instrumentation/comms.c index c38517c..48b3b68 100644 --- a/src/Instrumentation/comms.c +++ b/src/Instrumentation/comms.c @@ -4,9 +4,9 @@ #define ME CAN_SRC_INSTRUMENTATION void instr_comms_init(instr_comms_t *c, uint32_t now_ms) { - c->state = FSM_INIT; + c->state = FSM_INIT; c->next_heartbeat_ms = now_ms; - c->reset_requested = false; + c->reset_requested = false; } void instr_comms_boot_done(instr_comms_t *c) { @@ -15,17 +15,25 @@ void instr_comms_boot_done(instr_comms_t *c) { void instr_comms_on_frame(instr_comms_t *c, const can_frame_t *rx) { switch (can_decode_sys_cmd(rx, ME)) { - case CAN_SYS_UNLOCK: c->state = fsm_next(c->state, FSM_EVT_UNLOCK); break; - case CAN_SYS_SLEEP: c->state = fsm_next(c->state, FSM_EVT_SLEEP); break; - case CAN_SYS_RESET: c->reset_requested = true; break; + case CAN_SYS_UNLOCK: + c->state = fsm_next(c->state, FSM_EVT_UNLOCK); + break; + case CAN_SYS_SLEEP: + c->state = fsm_next(c->state, FSM_EVT_SLEEP); + break; + case CAN_SYS_RESET: + c->reset_requested = true; + break; // SKIP SKIP When does this game get good - case CAN_SYS_NONE: break; + case CAN_SYS_NONE: + break; } } size_t instr_comms_on_tick(instr_comms_t *c, uint32_t now_ms, can_frame_t tx[INSTR_COMMS_MAX_TX]) { - if (!util_every(now_ms, &c->next_heartbeat_ms, CAN_HEARTBEAT_PERIOD_MS)) return 0; + if (!util_every(now_ms, &c->next_heartbeat_ms, CAN_HEARTBEAT_PERIOD_MS)) + return 0; can_heartbeat_t hb = { ME, (uint8_t)c->state, now_ms / 1000u }; can_encode_heartbeat(&tx[0], &hb); diff --git a/src/Instrumentation/comms.h b/src/Instrumentation/comms.h index 96e23f6..df18cc1 100644 --- a/src/Instrumentation/comms.h +++ b/src/Instrumentation/comms.h @@ -15,15 +15,14 @@ extern "C" { #endif -#define INSTR_COMMS_MAX_TX 1 +#define INSTR_COMMS_MAX_TX 1 typedef struct { fsm_state_t state; - uint32_t next_heartbeat_ms; - bool reset_requested; + uint32_t next_heartbeat_ms; + bool reset_requested; } instr_comms_t; - void instr_comms_init(instr_comms_t *c, uint32_t now_ms); void instr_comms_boot_done(instr_comms_t *c); void instr_comms_on_frame(instr_comms_t *c, const can_frame_t *rx); diff --git a/src/Instrumentation/control.c b/src/Instrumentation/control.c index 48daa8a..4cdd83e 100644 --- a/src/Instrumentation/control.c +++ b/src/Instrumentation/control.c @@ -14,7 +14,7 @@ static const char *TAG = "instr_ctrl"; #define TX_TIMEOUT_MS 10u -#define POLL_PERIOD_MS 1000u +#define POLL_PERIOD_MS 1000u /* TODO(remy): update this to be an accurate atmospheric reference */ #define SEA_LEVEL_MBAR 1013.25f @@ -22,22 +22,19 @@ static const char *TAG = "instr_ctrl"; /* * This entire file needs debugging and testing, some sensors are missing from the original set up and can be removed too. * TODO(remy): do that -*/ + */ -static uint32_t now_ms(void) -{ +static uint32_t now_ms(void) { return (uint32_t)pdTICKS_TO_MS(xTaskGetTickCount()); } -static void send(const can_frame_t *f, const char *what) -{ +static void send(const can_frame_t *f, const char *what) { if (!can_bus_send(f, TX_TIMEOUT_MS)) { ESP_LOGW(TAG, "%s send failed, id=0x%03lX", what, (unsigned long)f->id); } } -void instr_control_task(void *arg) -{ +void instr_control_task(void *arg) { (void)arg; uint32_t next_poll_ms = now_ms(); @@ -56,13 +53,13 @@ void instr_control_task(void *arg) if (baro.ok) { sent_baro = true; status |= CAN_INSTR_STATUS_BARO; - board_temp_c_x10 = baro.temp_c_x10; + board_temp_c_x10 = baro.temp_c_x10; float pressure_mbar = baro.pressure_mbar_x10 / 10.0f; float altitude_m = 44330.0f * (1.0f - powf(pressure_mbar / SEA_LEVEL_MBAR, 1.0f / 5.255f)); can_instr_housekeeping_t hk = { .pressure_mbar_x10 = baro.pressure_mbar_x10, - .altitude_m_x10 = (int32_t)lroundf(altitude_m * 10.0f), + .altitude_m_x10 = (int32_t)lroundf(altitude_m * 10.0f), }; can_encode_housekeeping(&f, &hk); send(&f, "housekeeping"); @@ -95,19 +92,20 @@ void instr_control_task(void *arg) send(&f, "accel"); } hal_ads1115_t ads = hal_read_ads1115(); - if (ads.ok) status |= CAN_INSTR_STATUS_ADS; + if (ads.ok) + status |= CAN_INSTR_STATUS_ADS; can_instr_status_t st = { .sensor_status = status, .board_temp_c_x10 = board_temp_c_x10 }; can_encode_status(&f, &st); send(&f, "status"); if (util_every(now_ms(), &next_summary_ms, 5000u)) { - + // Log a summary every 5 seconds, useful for debugging, might remove later ESP_LOGI(TAG, "sensors: baro=%s sht=%s gas=%s imu=%s ads=%s", - sent_baro ? "ok" : "-", sent_sht ? "ok" : "-", - sent_gas ? "ok" : "-", sent_imu ? "ok" : "-", - (status & CAN_INSTR_STATUS_ADS) ? "ok" : "-"); + sent_baro ? "ok" : "-", sent_sht ? "ok" : "-", + sent_gas ? "ok" : "-", sent_imu ? "ok" : "-", + (status & CAN_INSTR_STATUS_ADS) ? "ok" : "-"); } } diff --git a/src/Instrumentation/setup.c b/src/Instrumentation/setup.c index e8b0c71..3e59a5a 100644 --- a/src/Instrumentation/setup.c +++ b/src/Instrumentation/setup.c @@ -12,13 +12,11 @@ static const char *TAG = "instr"; #define RX_TIMEOUT_MS 20u #define TX_TIMEOUT_MS 10u -static uint32_t now_ms(void) -{ +static uint32_t now_ms(void) { return (uint32_t)pdTICKS_TO_MS(xTaskGetTickCount()); } -static void comms_task(void *arg) -{ +static void comms_task(void *arg) { (void)arg; instr_comms_t comms; uint32_t last_status_log_ms = 0; @@ -30,7 +28,8 @@ static void comms_task(void *arg) can_frame_t rx, tx[INSTR_COMMS_MAX_TX]; fsm_state_t before = comms.state; - if (can_bus_recv(&rx, RX_TIMEOUT_MS)) instr_comms_on_frame(&comms, &rx); + if (can_bus_recv(&rx, RX_TIMEOUT_MS)) + instr_comms_on_frame(&comms, &rx); size_t n = instr_comms_on_tick(&comms, now_ms(), tx); for (size_t i = 0; i < n; i++) { @@ -43,16 +42,18 @@ static void comms_task(void *arg) } } - if (comms.state != before) ESP_LOGI(TAG, "state %s -> %s", fsm_state_name(before), fsm_state_name(comms.state)); - if (comms.reset_requested) hal_restart(); + if (comms.state != before) + ESP_LOGI(TAG, "state %s -> %s", fsm_state_name(before), fsm_state_name(comms.state)); + if (comms.reset_requested) + hal_restart(); can_bus_poll_recovery(); } } -void app_main(void) -{ +void app_main(void) { ESP_LOGI(TAG, "boot"); - if (!hal_init()) ESP_LOGE(TAG, "CAN init failed"); + if (!hal_init()) + ESP_LOGE(TAG, "CAN init failed"); xTaskCreatePinnedToCore(comms_task, "instr_comms", 4096, NULL, 10, NULL, 0); xTaskCreatePinnedToCore(instr_control_task, "instr_ctrl", 4096, NULL, 5, NULL, 1); diff --git a/src/Master/HAL/esp32/eth_w5500.c b/src/Master/HAL/esp32/eth_w5500.c index 04d8da0..cda0e64 100644 --- a/src/Master/HAL/esp32/eth_w5500.c +++ b/src/Master/HAL/esp32/eth_w5500.c @@ -20,24 +20,23 @@ static const char *TAG = "eth"; #define BIT_LINK BIT0 -#define BIT_IP BIT1 +#define BIT_IP BIT1 static EventGroupHandle_t s_eg; static esp_netif_t *s_netif; #if CONFIG_TTC_USE_STATIC_IP -static void apply_static_ip(void) -{ +static void apply_static_ip(void) { esp_err_t err = esp_netif_dhcpc_stop(s_netif); if (err != ESP_OK && err != ESP_ERR_ESP_NETIF_DHCP_ALREADY_STOPPED) { ESP_LOGE(TAG, "dhcpc_stop failed: %s", esp_err_to_name(err)); return; } - esp_netif_ip_info_t ip = {0}; - ip.ip.addr = ipaddr_addr(CONFIG_TTC_STATIC_IP); + esp_netif_ip_info_t ip = { 0 }; + ip.ip.addr = ipaddr_addr(CONFIG_TTC_STATIC_IP); ip.netmask.addr = ipaddr_addr(CONFIG_TTC_STATIC_NETMASK); - ip.gw.addr = ipaddr_addr(CONFIG_TTC_STATIC_GW); + ip.gw.addr = ipaddr_addr(CONFIG_TTC_STATIC_GW); err = esp_netif_set_ip_info(s_netif, &ip); if (err != ESP_OK) { @@ -49,45 +48,42 @@ static void apply_static_ip(void) } #endif -static void eth_event_handler(void *arg, esp_event_base_t base, int32_t id, void *data) -{ +static void eth_event_handler(void *arg, esp_event_base_t base, int32_t id, void *data) { esp_eth_handle_t h = *(esp_eth_handle_t *)data; - uint8_t mac[6] = {0}; + uint8_t mac[6] = { 0 }; switch (id) { - case ETHERNET_EVENT_CONNECTED: - esp_eth_ioctl(h, ETH_CMD_G_MAC_ADDR, mac); - ESP_LOGI(TAG, "link UP mac %02x:%02x:%02x:%02x:%02x:%02x", - mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); - xEventGroupSetBits(s_eg, BIT_LINK); + case ETHERNET_EVENT_CONNECTED: + esp_eth_ioctl(h, ETH_CMD_G_MAC_ADDR, mac); + ESP_LOGI(TAG, "link UP mac %02x:%02x:%02x:%02x:%02x:%02x", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + xEventGroupSetBits(s_eg, BIT_LINK); #if CONFIG_TTC_USE_STATIC_IP - apply_static_ip(); + apply_static_ip(); #endif - break; - case ETHERNET_EVENT_DISCONNECTED: - ESP_LOGW(TAG, "link DOWN"); - xEventGroupClearBits(s_eg, BIT_LINK | BIT_IP); - break; - case ETHERNET_EVENT_START: - ESP_LOGI(TAG, "driver started"); - break; - case ETHERNET_EVENT_STOP: - ESP_LOGW(TAG, "driver stopped"); - break; - default: - break; + break; + case ETHERNET_EVENT_DISCONNECTED: + ESP_LOGW(TAG, "link DOWN"); + xEventGroupClearBits(s_eg, BIT_LINK | BIT_IP); + break; + case ETHERNET_EVENT_START: + ESP_LOGI(TAG, "driver started"); + break; + case ETHERNET_EVENT_STOP: + ESP_LOGW(TAG, "driver stopped"); + break; + default: + break; } } -static void got_ip_handler(void *arg, esp_event_base_t base, int32_t id, void *data) -{ +static void got_ip_handler(void *arg, esp_event_base_t base, int32_t id, void *data) { const ip_event_got_ip_t *e = (const ip_event_got_ip_t *)data; ESP_LOGI(TAG, "got IP " IPSTR, IP2STR(&e->ip_info.ip)); xEventGroupSetBits(s_eg, BIT_IP); } -esp_err_t ttc_eth_init(void) -{ +esp_err_t ttc_eth_init(void) { s_eg = xEventGroupCreate(); esp_netif_config_t netif_cfg = ESP_NETIF_DEFAULT_ETH(); @@ -98,22 +94,23 @@ esp_err_t ttc_eth_init(void) /* ISR service is needed for the W5500 INT line */ esp_err_t err = gpio_install_isr_service(0); - if (err != ESP_OK && err != ESP_ERR_INVALID_STATE) return err; + if (err != ESP_OK && err != ESP_ERR_INVALID_STATE) + return err; spi_bus_config_t bus = { - .miso_io_num = CONFIG_TTC_ETH_MISO_GPIO, - .mosi_io_num = CONFIG_TTC_ETH_MOSI_GPIO, - .sclk_io_num = CONFIG_TTC_ETH_SCLK_GPIO, + .miso_io_num = CONFIG_TTC_ETH_MISO_GPIO, + .mosi_io_num = CONFIG_TTC_ETH_MOSI_GPIO, + .sclk_io_num = CONFIG_TTC_ETH_SCLK_GPIO, .quadwp_io_num = -1, .quadhd_io_num = -1, }; ESP_ERROR_CHECK(spi_bus_initialize(SPI2_HOST, &bus, SPI_DMA_CH_AUTO)); spi_device_interface_config_t dev = { - .mode = 0, + .mode = 0, .clock_speed_hz = CONFIG_TTC_ETH_SPI_CLOCK_MHZ * 1000 * 1000, - .queue_size = 20, - .spics_io_num = CONFIG_TTC_ETH_CS_GPIO, + .queue_size = 20, + .spics_io_num = CONFIG_TTC_ETH_CS_GPIO, }; eth_w5500_config_t w5500_cfg = ETH_W5500_DEFAULT_CONFIG(SPI2_HOST, &dev); @@ -135,13 +132,13 @@ esp_err_t ttc_eth_init(void) return ESP_FAIL; } - static esp_eth_handle_t handle; /* static: referenced by event data */ + static esp_eth_handle_t handle; /* static: referenced by event data */ esp_eth_config_t eth_cfg = ETH_DEFAULT_CONFIG(mac, phy); err = esp_eth_driver_install(ð_cfg, &handle); if (err != ESP_OK) { /* Most common cause on bring-up: wrong SPI pins / no power to W5500 */ ESP_LOGE(TAG, "driver install failed (%s) - check SPI wiring and pins", - esp_err_to_name(err)); + esp_err_to_name(err)); return err; } @@ -154,20 +151,18 @@ esp_err_t ttc_eth_init(void) ESP_ERROR_CHECK(esp_eth_start(handle)); ESP_LOGI(TAG, "W5500 up: SCLK=%d MOSI=%d MISO=%d CS=%d INT=%d RST=%d @ %d MHz", - CONFIG_TTC_ETH_SCLK_GPIO, CONFIG_TTC_ETH_MOSI_GPIO, CONFIG_TTC_ETH_MISO_GPIO, - CONFIG_TTC_ETH_CS_GPIO, CONFIG_TTC_ETH_INT_GPIO, CONFIG_TTC_ETH_RST_GPIO, - CONFIG_TTC_ETH_SPI_CLOCK_MHZ); + CONFIG_TTC_ETH_SCLK_GPIO, CONFIG_TTC_ETH_MOSI_GPIO, CONFIG_TTC_ETH_MISO_GPIO, + CONFIG_TTC_ETH_CS_GPIO, CONFIG_TTC_ETH_INT_GPIO, CONFIG_TTC_ETH_RST_GPIO, + CONFIG_TTC_ETH_SPI_CLOCK_MHZ); return ESP_OK; } -bool ttc_eth_ready(void) -{ +bool ttc_eth_ready(void) { const EventBits_t need = BIT_LINK | BIT_IP; return (xEventGroupGetBits(s_eg) & need) == need; } -bool ttc_eth_wait_ready(TickType_t timeout) -{ +bool ttc_eth_wait_ready(TickType_t timeout) { const EventBits_t need = BIT_LINK | BIT_IP; EventBits_t b = xEventGroupWaitBits(s_eg, need, pdFALSE, pdTRUE, timeout); return (b & need) == need; diff --git a/src/Master/HAL/esp32/hal_esp32.c b/src/Master/HAL/esp32/hal_esp32.c index 8d489c2..58115ee 100644 --- a/src/Master/HAL/esp32/hal_esp32.c +++ b/src/Master/HAL/esp32/hal_esp32.c @@ -10,9 +10,9 @@ static const char *TAG = "master_hal"; -bool hal_init(void) -{ - if (!can_bus_init(PIN_CAN_TX, PIN_CAN_RX)) return false; +bool hal_init(void) { + if (!can_bus_init(PIN_CAN_TX, PIN_CAN_RX)) + return false; /* esp_netif/esp_event are process-wide singletons; ESP_ERR_INVALID_STATE * just means something else already brought them up, which is fine. */ @@ -24,7 +24,7 @@ bool hal_init(void) err = esp_event_loop_create_default(); if (err != ESP_OK && err != ESP_ERR_INVALID_STATE) { ESP_LOGE(TAG, "esp_event_loop_create_default failed: %s - continuing without TT&C", - esp_err_to_name(err)); + esp_err_to_name(err)); return true; } @@ -34,7 +34,6 @@ bool hal_init(void) return true; } -void hal_restart(void) -{ +void hal_restart(void) { esp_restart(); } \ No newline at end of file diff --git a/src/Master/HAL/sim/hal_sim.c b/src/Master/HAL/sim/hal_sim.c index 882ebff..c6ca6c6 100644 --- a/src/Master/HAL/sim/hal_sim.c +++ b/src/Master/HAL/sim/hal_sim.c @@ -3,14 +3,12 @@ #include #include -bool hal_init(void) -{ +bool hal_init(void) { /* The simulated CAN bus is added with the simulator step. */ return true; } -void hal_restart(void) -{ +void hal_restart(void) { printf("[sim] restart requested\n"); exit(0); } \ No newline at end of file diff --git a/src/Master/comms.c b/src/Master/comms.c index 3c08796..5778e05 100644 --- a/src/Master/comms.c +++ b/src/Master/comms.c @@ -4,37 +4,45 @@ #include "util_math.h" #include "util_timer.h" -const char *master_node_name(can_source_t s) -{ +const char *master_node_name(can_source_t s) { switch (s) { - case CAN_SRC_GROUND: return "GROUND"; - case CAN_SRC_MASTER: return "MASTER"; - case CAN_SRC_BROADCAST: return "BROADCAST"; - case CAN_SRC_MECHANISMS: return "MECHANISMS"; - case CAN_SRC_PHOTONICS: return "PHOTONICS"; - case CAN_SRC_INSTRUMENTATION: return "INSTRUMENTATION"; - case CAN_SRC_EPS: return "EPS"; - case CAN_SRC_THERMAL: return "THERMAL"; - default: return "?"; + case CAN_SRC_GROUND: + return "GROUND"; + case CAN_SRC_MASTER: + return "MASTER"; + case CAN_SRC_BROADCAST: + return "BROADCAST"; + case CAN_SRC_MECHANISMS: + return "MECHANISMS"; + case CAN_SRC_PHOTONICS: + return "PHOTONICS"; + case CAN_SRC_INSTRUMENTATION: + return "INSTRUMENTATION"; + case CAN_SRC_EPS: + return "EPS"; + case CAN_SRC_THERMAL: + return "THERMAL"; + default: + return "?"; } } -void master_comms_init(master_comms_t *c, uint32_t now_ms) -{ +void master_comms_init(master_comms_t *c, uint32_t now_ms) { /* Master has no one to unlock it, so it takes itself INIT -> SAFE -> ACTIVE. * TODO: gate the unlock on a ground command once TT&C exists. */ c->state = fsm_next(FSM_INIT, FSM_EVT_INIT_OK); c->state = fsm_next(c->state, FSM_EVT_UNLOCK); c->next_heartbeat_ms = now_ms; - for (int i = 0; i < MASTER_NODE_SLOTS; i++) c->last_seen_ms[i] = 0; + for (int i = 0; i < MASTER_NODE_SLOTS; i++) + c->last_seen_ms[i] = 0; c->alive_mask = 0; } size_t master_comms_on_frame(master_comms_t *c, uint32_t now_ms, const can_frame_t *rx, - can_frame_t tx[MASTER_COMMS_MAX_TX]) -{ + can_frame_t tx[MASTER_COMMS_MAX_TX]) { can_heartbeat_t hb; - if (!can_decode_heartbeat(rx, &hb) || hb.source == CAN_SRC_MASTER) return 0; + if (!can_decode_heartbeat(rx, &hb) || hb.source == CAN_SRC_MASTER) + return 0; c->last_seen_ms[hb.source] = now_ms; c->alive_mask |= (uint8_t)(1u << hb.source); @@ -47,14 +55,14 @@ size_t master_comms_on_frame(master_comms_t *c, uint32_t now_ms, const can_frame } size_t master_comms_on_tick(master_comms_t *c, uint32_t now_ms, - can_frame_t tx[MASTER_COMMS_MAX_TX]) -{ + can_frame_t tx[MASTER_COMMS_MAX_TX]) { for (unsigned i = 0; i < MASTER_NODE_SLOTS; i++) { if ((c->alive_mask & (1u << i)) && now_ms - c->last_seen_ms[i] > CAN_HEARTBEAT_TIMEOUT_MS) { - c->alive_mask &= (uint8_t)~(1u << i); + c->alive_mask &= (uint8_t) ~(1u << i); } } - if (!util_every(now_ms, &c->next_heartbeat_ms, CAN_HEARTBEAT_PERIOD_MS)) return 0; + if (!util_every(now_ms, &c->next_heartbeat_ms, CAN_HEARTBEAT_PERIOD_MS)) + return 0; can_heartbeat_t hb = { CAN_SRC_MASTER, (uint8_t)c->state, now_ms / 1000u }; can_encode_heartbeat(&tx[0], &hb); @@ -62,31 +70,31 @@ size_t master_comms_on_tick(master_comms_t *c, uint32_t now_ms, } /* Scaled value as text, or "invalid" for UTIL_I16_INVALID */ -static const char *fmt_scaled(char *buf, size_t len, int16_t raw, float scale, const char *unit) -{ - if (raw == UTIL_I16_INVALID) snprintf(buf, len, "invalid"); - else snprintf(buf, len, "%.2f %s", (double)util_from_i16(raw, scale), unit); +static const char *fmt_scaled(char *buf, size_t len, int16_t raw, float scale, const char *unit) { + if (raw == UTIL_I16_INVALID) + snprintf(buf, len, "invalid"); + else + snprintf(buf, len, "%.2f %s", (double)util_from_i16(raw, scale), unit); return buf; } -const char *master_describe_frame(const can_frame_t *f, char *buf, size_t len) -{ - can_heartbeat_t hb; +const char *master_describe_frame(const can_frame_t *f, char *buf, size_t len) { + can_heartbeat_t hb; can_eps_status_t eps; char a[24], b[24], t[24]; if (can_decode_heartbeat(f, &hb)) { snprintf(buf, len, "%s heartbeat: %s, up %lu s", master_node_name(hb.source), - fsm_state_name((fsm_state_t)hb.state), (unsigned long)hb.uptime_s); + fsm_state_name((fsm_state_t)hb.state), (unsigned long)hb.uptime_s); } else if (can_decode_eps_status(f, &eps)) { snprintf(buf, len, "EPS status: current %s, shunt %s, PCB %s", - fmt_scaled(a, sizeof a, eps.current_ma, 1.0f, "mA"), - fmt_scaled(b, sizeof b, eps.shunt_mv_x100, 100.0f, "mV"), - fmt_scaled(t, sizeof t, eps.temp_c_x10, 10.0f, "C")); + fmt_scaled(a, sizeof a, eps.current_ma, 1.0f, "mA"), + fmt_scaled(b, sizeof b, eps.shunt_mv_x100, 100.0f, "mV"), + fmt_scaled(t, sizeof t, eps.temp_c_x10, 10.0f, "C")); } else { snprintf(buf, len, "%s frame: prio %u, type 0x%02X, %u bytes (id 0x%03lX)", - master_node_name(can_id_source(f->id)), (unsigned)can_id_priority(f->id), - can_id_type(f->id), f->dlc, (unsigned long)f->id); + master_node_name(can_id_source(f->id)), (unsigned)can_id_priority(f->id), + can_id_type(f->id), f->dlc, (unsigned long)f->id); } return buf; } \ No newline at end of file diff --git a/src/Master/comms.h b/src/Master/comms.h index bd48a28..47603c3 100644 --- a/src/Master/comms.h +++ b/src/Master/comms.h @@ -6,7 +6,6 @@ * - unlocks any node whose heartbeat says it is in SAFE * - turns every received frame into a readable log line * - * Pure: the task loop in setup.c does the actual sending and receiving. */ #ifndef HELIA_MASTER_COMMS_H #define HELIA_MASTER_COMMS_H @@ -22,7 +21,7 @@ extern "C" { #endif #define MASTER_COMMS_MAX_TX 1 /**< Most frames one call can ask to send. */ -#define MASTER_NODE_SLOTS 8 /**< One per CAN source ID (3 bits). */ +#define MASTER_NODE_SLOTS 8 /**< One per CAN source ID (3 bits). */ /** * @brief Unlock nodes automatically when they report SAFE. @@ -34,9 +33,9 @@ extern "C" { /** @brief Comms state. Owned by the comms task. */ typedef struct { fsm_state_t state; - uint32_t next_heartbeat_ms; - uint32_t last_seen_ms[MASTER_NODE_SLOTS]; /**< Last heartbeat time per source. */ - uint8_t alive_mask; /**< Bit n set = source n heard within the timeout. */ + uint32_t next_heartbeat_ms; + uint32_t last_seen_ms[MASTER_NODE_SLOTS]; /**< Last heartbeat time per source. */ + uint8_t alive_mask; /**< Bit n set = source n heard within the timeout. */ } master_comms_t; /** @brief Start up. Master has no one to unlock it, so it goes straight to ACTIVE. */ @@ -47,7 +46,7 @@ void master_comms_init(master_comms_t *c, uint32_t now_ms); * @return Frames to send in reply. */ size_t master_comms_on_frame(master_comms_t *c, uint32_t now_ms, const can_frame_t *rx, - can_frame_t tx[MASTER_COMMS_MAX_TX]); + can_frame_t tx[MASTER_COMMS_MAX_TX]); /** * @brief Periodic work: Master's heartbeat, and dropping nodes silent for @@ -55,7 +54,7 @@ size_t master_comms_on_frame(master_comms_t *c, uint32_t now_ms, const can_frame * @return Frames written to @p tx. */ size_t master_comms_on_tick(master_comms_t *c, uint32_t now_ms, - can_frame_t tx[MASTER_COMMS_MAX_TX]); + can_frame_t tx[MASTER_COMMS_MAX_TX]); /** @brief Node name for logs, e.g. "EPS". */ const char *master_node_name(can_source_t s); diff --git a/src/Master/control.c b/src/Master/control.c index 70bf3aa..1f6170b 100644 --- a/src/Master/control.c +++ b/src/Master/control.c @@ -27,11 +27,10 @@ static const char *TAG = "master_ctrl"; #define TX_TIMEOUT_MS 10u -static master_flight_t s_flight; +static master_flight_t s_flight; static SemaphoreHandle_t s_flight_mutex; -static uint32_t now_ms(void) -{ +static uint32_t now_ms(void) { return (uint32_t)pdTICKS_TO_MS(xTaskGetTickCount()); } @@ -39,10 +38,9 @@ static uint32_t now_ms(void) * SED's Broadcast CAN Message Dictionary (source BROADCAST, type 0x03). * Payload: 1 byte, the new master_phase_t value. Called with s_flight_mutex * already held so the logged phase name matches what was just applied. */ -static void broadcast_phase(master_phase_t phase, master_flight_result_t result) -{ +static void broadcast_phase(master_phase_t phase, master_flight_result_t result) { can_frame_t f = { - .id = can_make_id(CAN_PRIO_IMPORTANT, CAN_SRC_BROADCAST, CAN_CMD_FLIGHT_PHASE), + .id = can_make_id(CAN_PRIO_IMPORTANT, CAN_SRC_BROADCAST, CAN_CMD_FLIGHT_PHASE), .dlc = 1, }; f.data[0] = (uint8_t)phase; @@ -58,14 +56,12 @@ static void broadcast_phase(master_phase_t phase, master_flight_result_t result) } } -void master_control_init(void) -{ +void master_control_init(void) { s_flight_mutex = xSemaphoreCreateMutex(); master_flight_init(&s_flight, now_ms()); } -master_flight_result_t master_control_set_phase(master_phase_t next) -{ +master_flight_result_t master_control_set_phase(master_phase_t next) { xSemaphoreTake(s_flight_mutex, portMAX_DELAY); master_flight_result_t result = master_flight_set_phase(&s_flight, next, now_ms()); if (result != MASTER_FLIGHT_REJECTED) { @@ -75,16 +71,14 @@ master_flight_result_t master_control_set_phase(master_phase_t next) return result; } -master_phase_t master_control_get_phase(void) -{ +master_phase_t master_control_get_phase(void) { xSemaphoreTake(s_flight_mutex, portMAX_DELAY); master_phase_t p = master_flight_phase(&s_flight); xSemaphoreGive(s_flight_mutex); return p; } -void master_control_task(void *arg) -{ +void master_control_task(void *arg) { (void)arg; ESP_LOGI(TAG, "control core up, flight phase %s", master_phase_name(master_flight_phase(&s_flight))); diff --git a/src/Master/flight_phase.c b/src/Master/flight_phase.c index fb6b868..d992917 100644 --- a/src/Master/flight_phase.c +++ b/src/Master/flight_phase.c @@ -1,57 +1,56 @@ #include "flight_phase.h" static const char *PHASE_NAMES[MASTER_PHASE_COUNT] = { - [MASTER_PHASE_TESTING] = "TESTING", - [MASTER_PHASE_STANDBY] = "STANDBY", - [MASTER_PHASE_ASCENDING] = "ASCENDING", - [MASTER_PHASE_FLOAT] = "FLOAT", + [MASTER_PHASE_TESTING] = "TESTING", + [MASTER_PHASE_STANDBY] = "STANDBY", + [MASTER_PHASE_ASCENDING] = "ASCENDING", + [MASTER_PHASE_FLOAT] = "FLOAT", [MASTER_PHASE_DESCENDING] = "DESCENDING", - [MASTER_PHASE_LANDED] = "LANDED", + [MASTER_PHASE_LANDED] = "LANDED", }; -void master_flight_init(master_flight_t *f, uint32_t now_ms) -{ - f->phase = MASTER_PHASE_TESTING; +void master_flight_init(master_flight_t *f, uint32_t now_ms) { + f->phase = MASTER_PHASE_TESTING; f->phase_entered_ms = now_ms; - f->last_motion_ms = now_ms; + f->last_motion_ms = now_ms; } -master_phase_t master_flight_phase(const master_flight_t *f) -{ +master_phase_t master_flight_phase(const master_flight_t *f) { return f->phase; } -const char *master_phase_name(master_phase_t p) -{ - if ((unsigned)p >= MASTER_PHASE_COUNT) return "UNKNOWN"; +const char *master_phase_name(master_phase_t p) { + if ((unsigned)p >= MASTER_PHASE_COUNT) + return "UNKNOWN"; return PHASE_NAMES[p]; } -master_flight_result_t master_flight_set_phase(master_flight_t *f, master_phase_t next, uint32_t now_ms) -{ - if ((unsigned)next >= MASTER_PHASE_COUNT) return MASTER_FLIGHT_REJECTED; - if (next == f->phase) return MASTER_FLIGHT_REJECTED; /* no-op */ +master_flight_result_t master_flight_set_phase(master_flight_t *f, master_phase_t next, uint32_t now_ms) { + if ((unsigned)next >= MASTER_PHASE_COUNT) + return MASTER_FLIGHT_REJECTED; + if (next == f->phase) + return MASTER_FLIGHT_REJECTED; /* no-op */ const bool sequential = ((unsigned)next == (unsigned)f->phase + 1u); - f->phase = next; + f->phase = next; f->phase_entered_ms = now_ms; - f->last_motion_ms = now_ms; /* fresh phase, fresh no-motion window */ + f->last_motion_ms = now_ms; /* fresh phase, fresh no-motion window */ return sequential ? MASTER_FLIGHT_OK : MASTER_FLIGHT_OVERRIDE; } -void master_flight_tick(master_flight_t *f, uint32_t now_ms) -{ - if (f->phase != MASTER_PHASE_DESCENDING) return; - if (now_ms - f->last_motion_ms < MASTER_LANDING_NO_MOTION_MS) return; +void master_flight_tick(master_flight_t *f, uint32_t now_ms) { + if (f->phase != MASTER_PHASE_DESCENDING) + return; + if (now_ms - f->last_motion_ms < MASTER_LANDING_NO_MOTION_MS) + return; - f->phase = MASTER_PHASE_LANDED; + f->phase = MASTER_PHASE_LANDED; f->phase_entered_ms = now_ms; - f->last_motion_ms = now_ms; + f->last_motion_ms = now_ms; } -void master_flight_note_motion(master_flight_t *f, uint32_t now_ms) -{ +void master_flight_note_motion(master_flight_t *f, uint32_t now_ms) { f->last_motion_ms = now_ms; } \ No newline at end of file diff --git a/src/Master/setup.c b/src/Master/setup.c index 6200ce8..0650f9b 100644 --- a/src/Master/setup.c +++ b/src/Master/setup.c @@ -36,13 +36,11 @@ static const char *TAG = "master"; #define RX_TIMEOUT_MS 20u #define TX_TIMEOUT_MS 10u -static uint32_t now_ms(void) -{ +static uint32_t now_ms(void) { return (uint32_t)pdTICKS_TO_MS(xTaskGetTickCount()); } -static void send_all(const can_frame_t *tx, size_t n) -{ +static void send_all(const can_frame_t *tx, size_t n) { char text[96]; for (size_t i = 0; i < n; i++) { if (!can_bus_send(&tx[i], TX_TIMEOUT_MS)) { @@ -54,13 +52,14 @@ static void send_all(const can_frame_t *tx, size_t n) } /* "EPS online" / "EPS LOST" whenever a node appears or goes silent */ -static void log_presence_changes(uint8_t before, uint8_t after) -{ +static void log_presence_changes(uint8_t before, uint8_t after) { for (unsigned i = 0; i < MASTER_NODE_SLOTS; i++) { uint8_t bit = (uint8_t)(1u << i); - if ((after & bit) && !(before & bit)) ESP_LOGI(TAG, "%s online", master_node_name((can_source_t)i)); - if ((before & bit) && !(after & bit)) ESP_LOGW(TAG, "%s LOST (no heartbeat for %u ms)", - master_node_name((can_source_t)i), (unsigned)CAN_HEARTBEAT_TIMEOUT_MS); + if ((after & bit) && !(before & bit)) + ESP_LOGI(TAG, "%s online", master_node_name((can_source_t)i)); + if ((before & bit) && !(after & bit)) + ESP_LOGW(TAG, "%s LOST (no heartbeat for %u ms)", + master_node_name((can_source_t)i), (unsigned)CAN_HEARTBEAT_TIMEOUT_MS); } } @@ -69,16 +68,16 @@ static void log_presence_changes(uint8_t before, uint8_t after) * same as ground not being switched on" philosophy as before. Pulled out * to a helper because it's now called for every frame Master sees on the * bus, not just its own outgoing ones - see comms_task. */ -static void downlink_frame(int sock, const struct sockaddr_in *ground, uint8_t *seq, const can_frame_t *f) -{ - if (sock < 0 || !ttc_eth_ready()) return; +static void downlink_frame(int sock, const struct sockaddr_in *ground, uint8_t *seq, const can_frame_t *f) { + if (sock < 0 || !ttc_eth_ready()) + return; uint8_t pkt[TTC_DL_PACKET_LEN]; size_t plen = ttc_pack_downlink(pkt, sizeof pkt, (*seq)++, f); - if (plen) sendto(sock, pkt, plen, 0, (const struct sockaddr *)ground, sizeof *ground); + if (plen) + sendto(sock, pkt, plen, 0, (const struct sockaddr *)ground, sizeof *ground); } -static void comms_task(void *arg) -{ +static void comms_task(void *arg) { (void)arg; master_comms_t comms; uint32_t last_status_log_ms = 0; @@ -94,12 +93,12 @@ static void comms_task(void *arg) * switched on. */ int dl_sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); struct sockaddr_in ground = { - .sin_family = AF_INET, - .sin_port = htons(CONFIG_TTC_UDP_DOWNLINK_PORT), + .sin_family = AF_INET, + .sin_port = htons(CONFIG_TTC_UDP_DOWNLINK_PORT), .sin_addr.s_addr = inet_addr(CONFIG_TTC_GROUND_IP), }; uint8_t dl_seq = 0; /* one running counter across everything mirrored down, - * so ground can spot drops in the combined stream */ + * so ground can spot drops in the combined stream */ for (;;) { can_frame_t rx, tx[MASTER_COMMS_MAX_TX]; @@ -133,10 +132,10 @@ static void comms_task(void *arg) } } -void app_main(void) -{ +void app_main(void) { ESP_LOGI(TAG, "boot"); - if (!hal_init()) ESP_LOGE(TAG, "CAN init failed"); + if (!hal_init()) + ESP_LOGE(TAG, "CAN init failed"); /* Must run before ttc_uplink_task is created: that task can call * master_control_set_phase() as soon as a ground command arrives, and diff --git a/src/Master/ttc.c b/src/Master/ttc.c index 0bfd2ca..49ce6bf 100644 --- a/src/Master/ttc.c +++ b/src/Master/ttc.c @@ -4,12 +4,12 @@ /* Wire format constants (SED "Downlink (UDP)" proposal). Needed on host too, * since ttc_pack_downlink() is pure byte-packing and is built there. */ -#define TTC_DL_HDR_LEN 4 +#define TTC_DL_HDR_LEN 4 #define TTC_DL_FRAME_LEN 11 -size_t ttc_pack_downlink(uint8_t *pkt, size_t pkt_len, uint8_t seq, const can_frame_t *f) -{ - if (pkt_len < TTC_DL_HDR_LEN + TTC_DL_FRAME_LEN) return 0; +size_t ttc_pack_downlink(uint8_t *pkt, size_t pkt_len, uint8_t seq, const can_frame_t *f) { + if (pkt_len < TTC_DL_HDR_LEN + TTC_DL_FRAME_LEN) + return 0; const uint8_t dlc = f->dlc > 8 ? 8 : f->dlc; pkt[0] = seq; @@ -46,21 +46,21 @@ static const char *TAG = "master_ttc"; #define RX_BUF_LEN 64 /* Wire format constants (SED "Uplink (TCP)" proposal - see ttc_ground.py). */ -#define TTC_UL_SYNC 0xA5 -#define TTC_UL_HDR_LEN 4 +#define TTC_UL_SYNC 0xA5 +#define TTC_UL_HDR_LEN 4 #define TTC_UL_MAX_PAYLOAD 8 -#define TTC_ACK_HDR_LEN 5 -#define TTC_UL_FLAG_TEST 0x80 -#define TTC_TEST_PING 0x01 -#define TTC_ACK_OK 0x00 -#define TTC_ACK_BAD_LEN 0x01 -#define TTC_ACK_BAD_PHASE 0x02 - -static bool send_all(int sock, const uint8_t *buf, size_t len) -{ +#define TTC_ACK_HDR_LEN 5 +#define TTC_UL_FLAG_TEST 0x80 +#define TTC_TEST_PING 0x01 +#define TTC_ACK_OK 0x00 +#define TTC_ACK_BAD_LEN 0x01 +#define TTC_ACK_BAD_PHASE 0x02 + +static bool send_all(int sock, const uint8_t *buf, size_t len) { while (len) { int n = send(sock, buf, len, 0); - if (n <= 0) return false; + if (n <= 0) + return false; buf += n; len -= (size_t)n; } @@ -68,16 +68,17 @@ static bool send_all(int sock, const uint8_t *buf, size_t len) } static void send_ack(int sock, uint8_t cmd, uint8_t flags, uint8_t status, - const uint8_t *payload, uint8_t len) -{ + const uint8_t *payload, uint8_t len) { uint8_t ack[TTC_ACK_HDR_LEN + TTC_UL_MAX_PAYLOAD]; - if (len > TTC_UL_MAX_PAYLOAD) len = TTC_UL_MAX_PAYLOAD; + if (len > TTC_UL_MAX_PAYLOAD) + len = TTC_UL_MAX_PAYLOAD; ack[0] = TTC_UL_SYNC; ack[1] = cmd; ack[2] = flags; ack[3] = status; ack[4] = len; - if (len) memcpy(&ack[TTC_ACK_HDR_LEN], payload, len); + if (len) + memcpy(&ack[TTC_ACK_HDR_LEN], payload, len); send_all(sock, ack, TTC_ACK_HDR_LEN + len); } @@ -91,8 +92,7 @@ static void send_ack(int sock, uint8_t cmd, uint8_t flags, uint8_t status, * command will eventually follow. * Everything else is still just logged and ACKed OK, which is enough to * prove ground's command reached the board. */ -static void handle_command(int sock, uint8_t cmd, uint8_t flags, const uint8_t *p, uint8_t len) -{ +static void handle_command(int sock, uint8_t cmd, uint8_t flags, const uint8_t *p, uint8_t len) { if ((flags & TTC_UL_FLAG_TEST) && cmd == TTC_TEST_PING) { send_ack(sock, cmd, flags, TTC_ACK_OK, p, len); return; @@ -116,29 +116,31 @@ static void handle_command(int sock, uint8_t cmd, uint8_t flags, const uint8_t * } ESP_LOGI(TAG, "uplink cmd 0x%02X flags 0x%02X len=%u (not forwarded to CAN yet)", - cmd, flags, len); + cmd, flags, len); send_ack(sock, cmd, flags, TTC_ACK_OK, p, len); } /* Parse as many complete commands as the buffer holds; keep the remainder. */ -static void process_stream(int sock, uint8_t *buf, size_t *fill) -{ +static void process_stream(int sock, uint8_t *buf, size_t *fill) { size_t pos = 0; for (;;) { - while (pos < *fill && buf[pos] != TTC_UL_SYNC) pos++; - if (*fill - pos < TTC_UL_HDR_LEN) break; + while (pos < *fill && buf[pos] != TTC_UL_SYNC) + pos++; + if (*fill - pos < TTC_UL_HDR_LEN) + break; - const uint8_t cmd = buf[pos + 1]; + const uint8_t cmd = buf[pos + 1]; const uint8_t flags = buf[pos + 2]; - const uint8_t len = buf[pos + 3]; + const uint8_t len = buf[pos + 3]; if (len > TTC_UL_MAX_PAYLOAD) { send_ack(sock, cmd, flags, TTC_ACK_BAD_LEN, NULL, 0); pos++; /* resync from next byte */ continue; } - if (*fill - pos < (size_t)TTC_UL_HDR_LEN + len) break; /* need more */ + if (*fill - pos < (size_t)TTC_UL_HDR_LEN + len) + break; /* need more */ handle_command(sock, cmd, flags, &buf[pos + TTC_UL_HDR_LEN], len); pos += TTC_UL_HDR_LEN + len; @@ -148,8 +150,7 @@ static void process_stream(int sock, uint8_t *buf, size_t *fill) *fill -= pos; } -static void serve_client(int sock) -{ +static void serve_client(int sock) { ESP_LOGI(TAG, "ground connected"); int one = 1; setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one)); @@ -159,16 +160,22 @@ static void serve_client(int sock) for (;;) { int n = recv(sock, buf + fill, sizeof(buf) - fill, 0); - if (n == 0) { ESP_LOGW(TAG, "ground closed connection"); break; } - if (n < 0) { ESP_LOGW(TAG, "recv error: errno %d", errno); break; } + if (n == 0) { + ESP_LOGW(TAG, "ground closed connection"); + break; + } + if (n < 0) { + ESP_LOGW(TAG, "recv error: errno %d", errno); + break; + } fill += (size_t)n; process_stream(sock, buf, &fill); - if (fill == sizeof(buf)) fill = 0; /* can't happen with valid framing */ + if (fill == sizeof(buf)) + fill = 0; /* can't happen with valid framing */ } } -void ttc_uplink_task(void *arg) -{ +void ttc_uplink_task(void *arg) { (void)arg; for (;;) { ttc_eth_wait_ready(portMAX_DELAY); @@ -183,8 +190,8 @@ void ttc_uplink_task(void *arg) setsockopt(lsock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)); struct sockaddr_in addr = { - .sin_family = AF_INET, - .sin_port = htons(CONFIG_TTC_TCP_UPLINK_PORT), + .sin_family = AF_INET, + .sin_port = htons(CONFIG_TTC_TCP_UPLINK_PORT), .sin_addr.s_addr = htonl(INADDR_ANY), }; if (bind(lsock, (struct sockaddr *)&addr, sizeof(addr)) != 0 || listen(lsock, 1) != 0) { diff --git a/src/Photonics/HAL/esp32/hal_esp32.c b/src/Photonics/HAL/esp32/hal_esp32.c index c8ca1e3..bde3326 100644 --- a/src/Photonics/HAL/esp32/hal_esp32.c +++ b/src/Photonics/HAL/esp32/hal_esp32.c @@ -14,27 +14,28 @@ #include "driver/i2c.h" #include "can_bus.h" -#include "pins.h" +#include "pins.h" static const char *TAG = "photonics_hal"; #define SDA_GPIO 8 #define SCL_GPIO 9 -#define I2C_HZ 100000 +#define I2C_HZ 100000 #define I2C_PORT I2C_NUM_0 -#define ADDR_MUX 0x70 // Check data sheet for TCA9548A, this is the default address with A0,A1,A2 = GND -#define ADDR_LTR390 0x53 +#define ADDR_MUX 0x70 // Check data sheet for TCA9548A, this is the default address with A0,A1,A2 = GND +#define ADDR_LTR390 0x53 #define ADDR_ADS1115 0x48 -static const uint8_t UV_MUX_CHANNEL[PHOTONICS_NUM_UV] = {0, 1}; +static const uint8_t UV_MUX_CHANNEL[PHOTONICS_NUM_UV] = { 0, 1 }; static bool s_mux_ok; static bool s_uv_ok[PHOTONICS_NUM_UV]; static hal_uv_t s_uv_latest[PHOTONICS_NUM_UV]; -typedef enum { LTR390_MODE_ALS, LTR390_MODE_UVS } ltr390_mode_t; +typedef enum { LTR390_MODE_ALS, + LTR390_MODE_UVS } ltr390_mode_t; static ltr390_mode_t s_uv_mode[PHOTONICS_NUM_UV]; static bool s_adc_ok; // true if the onboard ADS1115 was found at init, useful for debugging @@ -56,7 +57,8 @@ static bool i2c_write(uint8_t addr, const uint8_t *data, size_t len) { i2c_master_start(cmd); i2c_master_write_byte(cmd, (uint8_t)((addr << 1) | I2C_MASTER_WRITE), true); - if (len) i2c_master_write(cmd, (uint8_t *)data, len, true); + if (len) + i2c_master_write(cmd, (uint8_t *)data, len, true); i2c_master_stop(cmd); esp_err_t err = i2c_master_cmd_begin(I2C_PORT, cmd, pdMS_TO_TICKS(100)); @@ -70,11 +72,13 @@ static bool i2c_write_read(uint8_t addr, const uint8_t *wr, size_t wr_len, uint8 i2c_master_start(cmd); i2c_master_write_byte(cmd, (uint8_t)((addr << 1) | I2C_MASTER_WRITE), true); - if (wr_len) i2c_master_write(cmd, (uint8_t *)wr, wr_len, true); + if (wr_len) + i2c_master_write(cmd, (uint8_t *)wr, wr_len, true); i2c_master_start(cmd); /* repeated start */ i2c_master_write_byte(cmd, (uint8_t)((addr << 1) | I2C_MASTER_READ), true); - if (rd_len > 1) i2c_master_read(cmd, rd, rd_len - 1, I2C_MASTER_ACK); + if (rd_len > 1) + i2c_master_read(cmd, rd, rd_len - 1, I2C_MASTER_ACK); i2c_master_read_byte(cmd, rd + rd_len - 1, I2C_MASTER_NACK); i2c_master_stop(cmd); @@ -85,7 +89,7 @@ static bool i2c_write_read(uint8_t addr, const uint8_t *wr, size_t wr_len, uint8 } static bool i2c_write_reg(uint8_t addr, uint8_t reg, uint8_t val) { - uint8_t wr[2] = {reg, val}; + uint8_t wr[2] = { reg, val }; return i2c_write(addr, wr, sizeof wr); } @@ -100,19 +104,19 @@ static bool mux_select(uint8_t channel) { return i2c_write(ADDR_MUX, &bit, 1); } -#define LTR390_REG_MAIN_CTRL 0x00 -#define LTR390_REG_MEAS_RATE 0x04 -#define LTR390_REG_GAIN 0x05 +#define LTR390_REG_MAIN_CTRL 0x00 +#define LTR390_REG_MEAS_RATE 0x04 +#define LTR390_REG_GAIN 0x05 #define LTR390_REG_MAIN_STATUS 0x07 -#define LTR390_REG_ALS_DATA0 0x0D -#define LTR390_REG_UVS_DATA0 0x10 +#define LTR390_REG_ALS_DATA0 0x0D +#define LTR390_REG_UVS_DATA0 0x10 static bool ltr390_set_als(void) { bool ok = true; - ok &= i2c_write_reg(ADDR_LTR390, LTR390_REG_GAIN, 0x01); - ok &= i2c_write_reg(ADDR_LTR390, LTR390_REG_MEAS_RATE, 0x22); - ok &= i2c_write_reg(ADDR_LTR390, LTR390_REG_MAIN_CTRL, 0x02); + ok &= i2c_write_reg(ADDR_LTR390, LTR390_REG_GAIN, 0x01); + ok &= i2c_write_reg(ADDR_LTR390, LTR390_REG_MEAS_RATE, 0x22); + ok &= i2c_write_reg(ADDR_LTR390, LTR390_REG_MAIN_CTRL, 0x02); return ok; } @@ -120,36 +124,40 @@ static bool ltr390_set_als(void) { static bool ltr390_set_uvs(void) { bool ok = true; - ok &= i2c_write_reg(ADDR_LTR390, LTR390_REG_GAIN, 0x04); + ok &= i2c_write_reg(ADDR_LTR390, LTR390_REG_GAIN, 0x04); ok &= i2c_write_reg(ADDR_LTR390, LTR390_REG_MEAS_RATE, 0x02); - ok &= i2c_write_reg(ADDR_LTR390, LTR390_REG_MAIN_CTRL, 0x0A); + ok &= i2c_write_reg(ADDR_LTR390, LTR390_REG_MAIN_CTRL, 0x0A); return ok; } static bool ltr390_init_one(uint8_t idx) { mux_select(UV_MUX_CHANNEL[idx]); - if (!i2c_probe(ADDR_LTR390)) return false; + if (!i2c_probe(ADDR_LTR390)) + return false; - i2c_write_reg(ADDR_LTR390, LTR390_REG_MAIN_CTRL, 0x10); + i2c_write_reg(ADDR_LTR390, LTR390_REG_MAIN_CTRL, 0x10); vTaskDelay(pdMS_TO_TICKS(10)); - if (!ltr390_set_als()) return false; + if (!ltr390_set_als()) + return false; s_uv_mode[idx] = LTR390_MODE_ALS; return true; } -static uint32_t ltr390_read_data(uint8_t reg){ - uint8_t buf[3] = {0}; - if (!i2c_read_reg(ADDR_LTR390, reg, buf, sizeof buf)) return 0; +static uint32_t ltr390_read_data(uint8_t reg) { + uint8_t buf[3] = { 0 }; + if (!i2c_read_reg(ADDR_LTR390, reg, buf, sizeof buf)) + return 0; return (uint32_t)buf[0] | ((uint32_t)buf[1] << 8) | ((uint32_t)(buf[2] & 0x0F) << 16); } hal_uv_t hal_read_uv(uint8_t idx) { - hal_uv_t r = {0}; - if (idx >= PHOTONICS_NUM_UV || !s_mux_ok || !s_uv_ok[idx]) return r; + hal_uv_t r = { 0 }; + if (idx >= PHOTONICS_NUM_UV || !s_mux_ok || !s_uv_ok[idx]) + return r; r = s_uv_latest[idx]; r.fresh = false; @@ -157,26 +165,27 @@ hal_uv_t hal_read_uv(uint8_t idx) { mux_select(UV_MUX_CHANNEL[idx]); uint8_t status = 0; - if (!i2c_read_reg(ADDR_LTR390, LTR390_REG_MAIN_STATUS, &status, 1)) return r; - if (!(status & 0x08)) return r; + if (!i2c_read_reg(ADDR_LTR390, LTR390_REG_MAIN_STATUS, &status, 1)) + return r; + if (!(status & 0x08)) + return r; // Read the data from the sensor, convert to lux or UVI, and flip the mode for next time - // Flipping the mode is a bit weird but the original photonics code does it? + // Flipping the mode is a bit weird but the original photonics code does it? // TODO(remy) double check with Kyane if (s_uv_mode[idx] == LTR390_MODE_ALS) { uint32_t raw = ltr390_read_data(LTR390_REG_ALS_DATA0); - float lux = 0.6f * (float)raw / 3.0f; + float lux = 0.6f * (float)raw / 3.0f; r.lux_x10 = (int32_t)lroundf(lux * 10.0f); ltr390_set_uvs(); s_uv_mode[idx] = LTR390_MODE_UVS; } else { uint32_t raw = ltr390_read_data(LTR390_REG_UVS_DATA0); - float uvi = (float)raw / 2300.0f; + float uvi = (float)raw / 2300.0f; r.uvi_x1000 = (int32_t)lroundf(uvi * 1000.0f); ltr390_set_als(); s_uv_mode[idx] = LTR390_MODE_ALS; - } r.ok = true; @@ -188,15 +197,15 @@ hal_uv_t hal_read_uv(uint8_t idx) { // Literally ctrl-c and ctrl-v from Instrumentation's hal.c, just with the ADS1115 address changed :3 hal_adc_t hal_read_adc(void) { - hal_adc_t r = {0}; - if (!s_adc_ok) return r; + hal_adc_t r = { 0 }; + if (!s_adc_ok) + return r; r.ok = true; for (int ch = 0; ch < 4; ch++) { uint16_t mux = (uint16_t)(0x4 + ch); - uint16_t config = (uint16_t)( - (1u << 15) | (mux << 12) | (0x1u << 9) | (1u << 8) | (0x4u << 5) | 0x3u); - uint8_t wr[3] = {0x01, (uint8_t)(config >> 8), (uint8_t)(config & 0xFF)}; + uint16_t config = (uint16_t)((1u << 15) | (mux << 12) | (0x1u << 9) | (1u << 8) | (0x4u << 5) | 0x3u); + uint8_t wr[3] = { 0x01, (uint8_t)(config >> 8), (uint8_t)(config & 0xFF) }; if (!i2c_write(ADDR_ADS1115, wr, sizeof wr)) { r.ok = false; continue; @@ -212,29 +221,29 @@ hal_adc_t hal_read_adc(void) { // The 0.125f is to convert from raw counts to millivolts, based on the ADS1115 datasheet for the selected gain // ADS1115 datasheet: https://www.ti.com/lit/ds/symlink/ads1115.pdf - r.mv[ch] = (int16_t)lroundf(raw * 0.125f); + r.mv[ch] = (int16_t)lroundf(raw * 0.125f); } return r; } bool hal_init(void) { - if (!can_bus_init(PIN_CAN_TX, PIN_CAN_RX)) return false; + if (!can_bus_init(PIN_CAN_TX, PIN_CAN_RX)) + return false; i2c_config_t conf = { - .mode = I2C_MODE_MASTER, - .sda_io_num = SDA_GPIO, - .scl_io_num = SCL_GPIO, - .sda_pullup_en = GPIO_PULLUP_DISABLE, - .scl_pullup_en = GPIO_PULLUP_DISABLE, + .mode = I2C_MODE_MASTER, + .sda_io_num = SDA_GPIO, + .scl_io_num = SCL_GPIO, + .sda_pullup_en = GPIO_PULLUP_DISABLE, + .scl_pullup_en = GPIO_PULLUP_DISABLE, .master.clk_speed = I2C_HZ, }; - if (i2c_param_config(I2C_PORT, &conf) != ESP_OK || - i2c_driver_install(I2C_PORT, conf.mode, 0, 0, 0) != ESP_OK) { + if (i2c_param_config(I2C_PORT, &conf) != ESP_OK || i2c_driver_install(I2C_PORT, conf.mode, 0, 0, 0) != ESP_OK) { ESP_LOGE(TAG, "I2C bus init failed!!! sensors unavailable at boot"); // still boot just with broken sensors - return true; + return true; } int found = 0; @@ -259,7 +268,8 @@ bool hal_init(void) { } // Defaults to channel 0 on boot, this is just a placeholder to init everything - if (s_mux_ok) mux_select(0); + if (s_mux_ok) + mux_select(0); s_adc_ok = i2c_probe(ADDR_ADS1115); ESP_LOGI(TAG, "ADS1115 %s", s_adc_ok ? "OK" : "NOT FOUND"); diff --git a/src/Photonics/HAL/esp32/pins.h b/src/Photonics/HAL/esp32/pins.h index c450e58..15b1d20 100644 --- a/src/Photonics/HAL/esp32/pins.h +++ b/src/Photonics/HAL/esp32/pins.h @@ -1,11 +1,11 @@ /** * @file pins.h - * @brief Photonics pin map + * @brief Photonics pin map */ #ifndef HELIA_PHOTONICS_PINS_H #define HELIA_PHOTONICS_PINS_H -#define PIN_CAN_TX 1 -#define PIN_CAN_RX 2 +#define PIN_CAN_TX 1 +#define PIN_CAN_RX 2 #endif // If you're editing this it's because someone messed up I bet \ No newline at end of file diff --git a/src/Photonics/HAL/hal.h b/src/Photonics/HAL/hal.h index f7f90ce..ac4adcb 100644 --- a/src/Photonics/HAL/hal.h +++ b/src/Photonics/HAL/hal.h @@ -17,15 +17,15 @@ extern "C" { /** @brief LTR390 Sensor struct */ typedef struct { - bool ok; // true if sensor was found at init - bool fresh; // true if data actually changed, depends on how we want to measure photonics but added for now to avoid data duplication - int32_t lux_x10; // ambient light, scaled by 10 to avoid floating point + bool ok; // true if sensor was found at init + bool fresh; // true if data actually changed, depends on how we want to measure photonics but added for now to avoid data duplication + int32_t lux_x10; // ambient light, scaled by 10 to avoid floating point int32_t uvi_x1000; // UV index, scaled by 1000 to avoid floating point } hal_uv_t; /** @brief Onboard ADS1115, 4 single-ended channels */ typedef struct { - bool ok; // true if ADC was found at init + bool ok; // true if ADC was found at init int16_t mv[4]; } hal_adc_t; diff --git a/src/Photonics/comms.c b/src/Photonics/comms.c index 16438d5..ec00a90 100644 --- a/src/Photonics/comms.c +++ b/src/Photonics/comms.c @@ -16,18 +16,26 @@ void photonics_comms_boot_done(photonics_comms_t *c) { void photonics_comms_on_frame(photonics_comms_t *c, const can_frame_t *rx) { switch (can_decode_sys_cmd(rx, ME)) { - case CAN_SYS_UNLOCK: c->state = fsm_next(c->state, FSM_EVT_UNLOCK); break; - case CAN_SYS_SLEEP: c->state = fsm_next(c->state, FSM_EVT_SLEEP); break; - case CAN_SYS_RESET: c->reset_requested = true; break; + case CAN_SYS_UNLOCK: + c->state = fsm_next(c->state, FSM_EVT_UNLOCK); + break; + case CAN_SYS_SLEEP: + c->state = fsm_next(c->state, FSM_EVT_SLEEP); + break; + case CAN_SYS_RESET: + c->reset_requested = true; + break; // base case - case CAN_SYS_NONE: break; + case CAN_SYS_NONE: + break; } } size_t photonics_comms_on_tick(photonics_comms_t *c, uint32_t now_ms, can_frame_t tx[PHOTONICS_COMMS_MAX_TX]) { - - if (!util_every(now_ms, &c->next_heartbeat_ms, CAN_HEARTBEAT_PERIOD_MS)) return 0; + + if (!util_every(now_ms, &c->next_heartbeat_ms, CAN_HEARTBEAT_PERIOD_MS)) + return 0; can_heartbeat_t hb = { ME, (uint8_t)c->state, now_ms / 1000u }; can_encode_heartbeat(&tx[0], &hb); diff --git a/src/Photonics/comms.h b/src/Photonics/comms.h index 684d684..f1641f9 100644 --- a/src/Photonics/comms.h +++ b/src/Photonics/comms.h @@ -1,7 +1,7 @@ /** * @file comms.h * @brief Photonics communication logic: this is jsut heartbeat and state transitions. Check out control.c for actual photonics data - * + * * TODO(remy): add more detailed description of the comms logic, including state machine and heartbeat */ #ifndef HELIA_PHOTONICS_COMMS_H @@ -21,8 +21,8 @@ extern "C" { typedef struct { fsm_state_t state; - uint32_t next_heartbeat_ms; - bool reset_requested; + uint32_t next_heartbeat_ms; + bool reset_requested; } photonics_comms_t; void photonics_comms_init(photonics_comms_t *c, uint32_t now_ms); diff --git a/src/Photonics/control.c b/src/Photonics/control.c index a3ddfa5..bb810b8 100644 --- a/src/Photonics/control.c +++ b/src/Photonics/control.c @@ -33,7 +33,7 @@ void photonics_control_task(void *arg) { (void)arg; // Just to avoid warnings again uint32_t next_summary_ms = now_ms(); - uint32_t uv_frames[PHOTONICS_NUM_UV] = {0}; + uint32_t uv_frames[PHOTONICS_NUM_UV] = { 0 }; uint32_t adc_frames = 0; ESP_LOGI(TAG, "control core up"); @@ -73,11 +73,11 @@ void photonics_control_task(void *arg) { if (util_every(now_ms(), &next_summary_ms, 5000u)) { ESP_LOGI(TAG, "frames: uv0=%lu uv1=%lu adc=%lu", - (unsigned long)uv_frames[0], (unsigned long)uv_frames[1], - (unsigned long)adc_frames); + (unsigned long)uv_frames[0], (unsigned long)uv_frames[1], + (unsigned long)adc_frames); } - vTaskDelay(pdMS_TO_TICKS(100)); + vTaskDelay(pdMS_TO_TICKS(100)); } } #endif /* ESP_PLATFORM */ \ No newline at end of file diff --git a/src/Photonics/control.h b/src/Photonics/control.h index 018de67..e950de6 100644 --- a/src/Photonics/control.h +++ b/src/Photonics/control.h @@ -10,7 +10,7 @@ extern "C" { #endif /// @brief Main control task for data collection for photonics. Args are unused, just added this here to avoid compiler warnings! -/// @param arg +/// @param arg void photonics_control_task(void *arg); #ifdef __cplusplus diff --git a/src/Photonics/setup.c b/src/Photonics/setup.c index 5e7dd0b..32b643c 100644 --- a/src/Photonics/setup.c +++ b/src/Photonics/setup.c @@ -12,13 +12,11 @@ static const char *TAG = "photonics"; #define RX_TIMEOUT_MS 20u #define TX_TIMEOUT_MS 10u -static uint32_t now_ms(void) -{ +static uint32_t now_ms(void) { return (uint32_t)pdTICKS_TO_MS(xTaskGetTickCount()); } -static void comms_task(void *arg) -{ +static void comms_task(void *arg) { (void)arg; // unsused, just added this here to avoid compiler warnings :) photonics_comms_t comms; @@ -27,14 +25,14 @@ static void comms_task(void *arg) photonics_comms_init(&comms, now_ms()); photonics_comms_boot_done(&comms); - ESP_LOGI(TAG, "state %s", fsm_state_name(comms.state)); while (1) { can_frame_t rx, tx[PHOTONICS_COMMS_MAX_TX]; fsm_state_t before = comms.state; - if (can_bus_recv(&rx, RX_TIMEOUT_MS)) photonics_comms_on_frame(&comms, &rx); + if (can_bus_recv(&rx, RX_TIMEOUT_MS)) + photonics_comms_on_frame(&comms, &rx); size_t n = photonics_comms_on_tick(&comms, now_ms(), tx); @@ -42,7 +40,7 @@ static void comms_task(void *arg) if (!can_bus_send(&tx[i], TX_TIMEOUT_MS)) { ESP_LOGW(TAG, "send failed, id=0x%03lX", (unsigned long)tx[i].id); - + if (now_ms() - last_status_log_ms >= 2000u) { can_bus_log_status(); last_status_log_ms = now_ms(); @@ -50,17 +48,19 @@ static void comms_task(void *arg) } } - if (comms.state != before) ESP_LOGI(TAG, "state %s -> %s", fsm_state_name(before), fsm_state_name(comms.state)); - if (comms.reset_requested) hal_restart(); + if (comms.state != before) + ESP_LOGI(TAG, "state %s -> %s", fsm_state_name(before), fsm_state_name(comms.state)); + if (comms.reset_requested) + hal_restart(); can_bus_poll_recovery(); } } -void app_main(void) -{ +void app_main(void) { ESP_LOGI(TAG, "boot"); - if (!hal_init()) ESP_LOGE(TAG, "CAN init failed"); + if (!hal_init()) + ESP_LOGE(TAG, "CAN init failed"); xTaskCreatePinnedToCore(comms_task, "photonics_comms", 4096, NULL, 10, NULL, 0); xTaskCreatePinnedToCore(photonics_control_task, "photonics_ctrl", 4096, NULL, 5, NULL, 1); diff --git a/tests/libs/test_can.cpp b/tests/libs/test_can.cpp index c9e1f6e..51af30b 100644 --- a/tests/libs/test_can.cpp +++ b/tests/libs/test_can.cpp @@ -2,8 +2,7 @@ #include #include "can.h" -TEST(CanId, RoundTripsEveryCombination) -{ +TEST(CanId, RoundTripsEveryCombination) { for (unsigned p = 0; p < 4; p++) for (unsigned s = 0; s < 8; s++) for (unsigned t = 0; t < 64; t++) { @@ -15,57 +14,56 @@ TEST(CanId, RoundTripsEveryCombination) } } -TEST(CanId, OutOfRangeTypeIsMaskedNotSpilled) -{ +TEST(CanId, OutOfRangeTypeIsMaskedNotSpilled) { // 0x41 is 7 bits; must not corrupt the source field uint32_t id = can_make_id(CAN_PRIO_INFO, CAN_SRC_EPS, 0x41); EXPECT_EQ(can_id_source(id), CAN_SRC_EPS); EXPECT_EQ(can_id_type(id), 0x01); } -TEST(CanId, KnownValues) -{ +TEST(CanId, KnownValues) { EXPECT_EQ(can_make_id(CAN_PRIO_INFO, CAN_SRC_MASTER, CAN_MSG_HEARTBEAT), 0x640u); EXPECT_EQ(can_make_id(CAN_PRIO_IMPORTANT, CAN_SRC_MASTER, CAN_CMD_UNLOCK_NODE), 0x240u); } -TEST(CanBytes, LittleEndianLayout) -{ +TEST(CanBytes, LittleEndianLayout) { uint8_t b[4] = {}; can_put_u32(b, 0x11223344u); - EXPECT_EQ(b[0], 0x44); EXPECT_EQ(b[1], 0x33); EXPECT_EQ(b[2], 0x22); EXPECT_EQ(b[3], 0x11); + EXPECT_EQ(b[0], 0x44); + EXPECT_EQ(b[1], 0x33); + EXPECT_EQ(b[2], 0x22); + EXPECT_EQ(b[3], 0x11); can_put_u16(b, 0xABCD); - EXPECT_EQ(b[0], 0xCD); EXPECT_EQ(b[1], 0xAB); + EXPECT_EQ(b[0], 0xCD); + EXPECT_EQ(b[1], 0xAB); } -TEST(CanBytes, RoundTripsExtremes) -{ +TEST(CanBytes, RoundTripsExtremes) { uint8_t b[4] = {}; - const int16_t i16s[] = {INT16_MIN, -1, 0, 372, INT16_MAX}; + const int16_t i16s[] = { INT16_MIN, -1, 0, 372, INT16_MAX }; for (int16_t v : i16s) { can_put_i16(b, v); EXPECT_EQ(can_get_i16(b), v); } - for (uint32_t v : {0u, 1u, 0xDEADBEEFu, UINT32_MAX}) { + for (uint32_t v : { 0u, 1u, 0xDEADBEEFu, UINT32_MAX }) { can_put_u32(b, v); EXPECT_EQ(can_get_u32(b), v); } } -TEST(CanFrame, InitZeroesPayloadAndClampsDlc) -{ +TEST(CanFrame, InitZeroesPayloadAndClampsDlc) { can_frame_t f; memset(&f, 0xFF, sizeof f); can_frame_init(&f, CAN_PRIO_INFO, CAN_SRC_EPS, 0x04, 12); EXPECT_EQ(f.dlc, 8); - for (uint8_t byte : f.data) EXPECT_EQ(byte, 0); + for (uint8_t byte : f.data) + EXPECT_EQ(byte, 0); } /* ---- Heartbeat --------------------------------------------------------- */ -TEST(CanHeartbeat, RoundTrip) -{ - can_heartbeat_t in = {CAN_SRC_EPS, 2, 123456u}, out = {}; +TEST(CanHeartbeat, RoundTrip) { + can_heartbeat_t in = { CAN_SRC_EPS, 2, 123456u }, out = {}; can_frame_t f; can_encode_heartbeat(&f, &in); ASSERT_TRUE(can_decode_heartbeat(&f, &out)); @@ -74,18 +72,17 @@ TEST(CanHeartbeat, RoundTrip) EXPECT_EQ(out.uptime_s, 123456u); } -TEST(CanHeartbeat, RejectsCommandsAndShortFrames) -{ +TEST(CanHeartbeat, RejectsCommandsAndShortFrames) { can_heartbeat_t out = {}; can_frame_t f; can_encode_sys_cmd(&f, CAN_SYS_UNLOCK, CAN_SRC_BROADCAST); // type 0x00 too EXPECT_FALSE(can_decode_heartbeat(&f, &out)); - can_encode_sys_cmd(&f, CAN_SYS_UNLOCK, CAN_SRC_EPS); // Master, type 0x00 + can_encode_sys_cmd(&f, CAN_SYS_UNLOCK, CAN_SRC_EPS); // Master, type 0x00 EXPECT_FALSE(can_decode_heartbeat(&f, &out)); - can_heartbeat_t hb = {CAN_SRC_EPS, 1, 5}; + can_heartbeat_t hb = { CAN_SRC_EPS, 1, 5 }; can_encode_heartbeat(&f, &hb); f.dlc = 4; EXPECT_FALSE(can_decode_heartbeat(&f, &out)); @@ -94,11 +91,10 @@ TEST(CanHeartbeat, RejectsCommandsAndShortFrames) /* ---- System commands --------------------------------------------------- */ -TEST(CanSysCmd, MasterHeartbeatIsNotAnUnlock) -{ +TEST(CanSysCmd, MasterHeartbeatIsNotAnUnlock) { // The old bug: Master heartbeat and CMD_UNLOCK_NODE share source 0x1 and // type 0x00. A heartbeat whose first byte equals our ID must not unlock us. - can_heartbeat_t hb = {CAN_SRC_MASTER, (uint8_t)CAN_SRC_EPS, 0}; + can_heartbeat_t hb = { CAN_SRC_MASTER, (uint8_t)CAN_SRC_EPS, 0 }; can_frame_t f; can_encode_heartbeat(&f, &hb); ASSERT_EQ(f.data[0], (uint8_t)CAN_SRC_EPS); @@ -106,51 +102,38 @@ TEST(CanSysCmd, MasterHeartbeatIsNotAnUnlock) } struct SysCase { - const char *name; + const char *name; can_sys_cmd_t sent; - can_source_t target; - can_source_t me; + can_source_t target; + can_source_t me; can_sys_cmd_t expected; }; -class CanSysCmdTable : public ::testing::TestWithParam {}; +class CanSysCmdTable : public ::testing::TestWithParam { }; -TEST_P(CanSysCmdTable, EncodeThenDecode) -{ +TEST_P(CanSysCmdTable, EncodeThenDecode) { const SysCase &c = GetParam(); can_frame_t f; ASSERT_TRUE(can_encode_sys_cmd(&f, c.sent, c.target)); EXPECT_EQ(can_decode_sys_cmd(&f, c.me), c.expected); } -INSTANTIATE_TEST_SUITE_P(All, CanSysCmdTable, ::testing::Values( - SysCase{"UnlockAll", CAN_SYS_UNLOCK, CAN_SRC_BROADCAST, CAN_SRC_EPS, CAN_SYS_UNLOCK}, - SysCase{"SleepAll", CAN_SYS_SLEEP, CAN_SRC_BROADCAST, CAN_SRC_EPS, CAN_SYS_SLEEP}, - SysCase{"ResetAll", CAN_SYS_RESET, CAN_SRC_BROADCAST, CAN_SRC_EPS, CAN_SYS_RESET}, - SysCase{"UnlockMe", CAN_SYS_UNLOCK, CAN_SRC_EPS, CAN_SRC_EPS, CAN_SYS_UNLOCK}, - SysCase{"SleepMe", CAN_SYS_SLEEP, CAN_SRC_EPS, CAN_SRC_EPS, CAN_SYS_SLEEP}, - SysCase{"ResetMe", CAN_SYS_RESET, CAN_SRC_EPS, CAN_SRC_EPS, CAN_SYS_RESET}, - SysCase{"UnlockOtherNode", CAN_SYS_UNLOCK, CAN_SRC_THERMAL, CAN_SRC_EPS, CAN_SYS_NONE}, - SysCase{"ResetOtherNode", CAN_SYS_RESET, CAN_SRC_THERMAL, CAN_SRC_EPS, CAN_SYS_NONE} -), [](const auto &info) { return std::string(info.param.name); }); - -TEST(CanSysCmd, TargetedCommandWithNoPayloadIsIgnored) -{ +INSTANTIATE_TEST_SUITE_P(All, CanSysCmdTable, ::testing::Values(SysCase { "UnlockAll", CAN_SYS_UNLOCK, CAN_SRC_BROADCAST, CAN_SRC_EPS, CAN_SYS_UNLOCK }, SysCase { "SleepAll", CAN_SYS_SLEEP, CAN_SRC_BROADCAST, CAN_SRC_EPS, CAN_SYS_SLEEP }, SysCase { "ResetAll", CAN_SYS_RESET, CAN_SRC_BROADCAST, CAN_SRC_EPS, CAN_SYS_RESET }, SysCase { "UnlockMe", CAN_SYS_UNLOCK, CAN_SRC_EPS, CAN_SRC_EPS, CAN_SYS_UNLOCK }, SysCase { "SleepMe", CAN_SYS_SLEEP, CAN_SRC_EPS, CAN_SRC_EPS, CAN_SYS_SLEEP }, SysCase { "ResetMe", CAN_SYS_RESET, CAN_SRC_EPS, CAN_SRC_EPS, CAN_SYS_RESET }, SysCase { "UnlockOtherNode", CAN_SYS_UNLOCK, CAN_SRC_THERMAL, CAN_SRC_EPS, CAN_SYS_NONE }, SysCase { "ResetOtherNode", CAN_SYS_RESET, CAN_SRC_THERMAL, CAN_SRC_EPS, CAN_SYS_NONE }), [](const auto &info) { return std::string(info.param.name); }); + +TEST(CanSysCmd, TargetedCommandWithNoPayloadIsIgnored) { can_frame_t f; can_encode_sys_cmd(&f, CAN_SYS_UNLOCK, CAN_SRC_EPS); f.dlc = 0; // data[0] still holds our ID, but it isn't part of the frame EXPECT_EQ(can_decode_sys_cmd(&f, CAN_SRC_EPS), CAN_SYS_NONE); } -TEST(CanSysCmd, WrongPriorityIsIgnored) -{ +TEST(CanSysCmd, WrongPriorityIsIgnored) { can_frame_t f; can_frame_init(&f, CAN_PRIO_INFO, CAN_SRC_BROADCAST, CAN_CMD_UNLOCK_ALL, 0); EXPECT_EQ(can_decode_sys_cmd(&f, CAN_SRC_EPS), CAN_SYS_NONE); } -TEST(CanSysCmd, BadInputs) -{ +TEST(CanSysCmd, BadInputs) { can_frame_t f; EXPECT_FALSE(can_encode_sys_cmd(&f, CAN_SYS_NONE, CAN_SRC_EPS)); EXPECT_FALSE(can_encode_sys_cmd(&f, (can_sys_cmd_t)99, CAN_SRC_EPS)); diff --git a/tests/libs/test_can_eps.cpp b/tests/libs/test_can_eps.cpp index 15f05ee..3b16511 100644 --- a/tests/libs/test_can_eps.cpp +++ b/tests/libs/test_can_eps.cpp @@ -1,9 +1,8 @@ #include #include "can_eps.h" -TEST(CanEps, StatusRoundTrip) -{ - can_eps_status_t in = {412, 4120, -35}, out = {}; +TEST(CanEps, StatusRoundTrip) { + can_eps_status_t in = { 412, 4120, -35 }, out = {}; can_frame_t f; can_encode_eps_status(&f, &in); EXPECT_EQ(f.dlc, 6); @@ -13,9 +12,8 @@ TEST(CanEps, StatusRoundTrip) EXPECT_EQ(out.temp_c_x10, -35); } -TEST(CanEps, InvalidSentinelSurvives) -{ - can_eps_status_t in = {INT16_MIN, INT16_MIN, INT16_MIN}, out = {}; +TEST(CanEps, InvalidSentinelSurvives) { + can_eps_status_t in = { INT16_MIN, INT16_MIN, INT16_MIN }, out = {}; can_frame_t f; can_encode_eps_status(&f, &in); ASSERT_TRUE(can_decode_eps_status(&f, &out)); @@ -23,15 +21,14 @@ TEST(CanEps, InvalidSentinelSurvives) EXPECT_EQ(out.temp_c_x10, INT16_MIN); } -TEST(CanEps, RejectsOtherFrames) -{ +TEST(CanEps, RejectsOtherFrames) { can_eps_status_t out; can_frame_t f; - can_heartbeat_t hb = {CAN_SRC_EPS, 1, 0}; + can_heartbeat_t hb = { CAN_SRC_EPS, 1, 0 }; can_encode_heartbeat(&f, &hb); EXPECT_FALSE(can_decode_eps_status(&f, &out)); - can_eps_status_t in = {1, 2, 3}; + can_eps_status_t in = { 1, 2, 3 }; can_encode_eps_status(&f, &in); f.dlc = 5; EXPECT_FALSE(can_decode_eps_status(&f, &out)); diff --git a/tests/libs/test_fsm.cpp b/tests/libs/test_fsm.cpp index 9ec57df..f4e8023 100644 --- a/tests/libs/test_fsm.cpp +++ b/tests/libs/test_fsm.cpp @@ -8,48 +8,36 @@ struct Transition { }; // Makes ctest output readable: "SAFE + evt 2 -> ACTIVE" instead of raw bytes -static std::ostream &operator<<(std::ostream &os, const Transition &t) -{ +static std::ostream &operator<<(std::ostream &os, const Transition &t) { return os << fsm_state_name(t.from) << " + evt " << t.evt << " -> " << fsm_state_name(t.expected); } -class FsmTransitions : public ::testing::TestWithParam {}; +class FsmTransitions : public ::testing::TestWithParam { }; -TEST_P(FsmTransitions, NextStateIsCorrect) -{ +TEST_P(FsmTransitions, NextStateIsCorrect) { const Transition &t = GetParam(); EXPECT_EQ(fsm_next(t.from, t.evt), t.expected) << fsm_state_name(t.from) << " + event " << t.evt; } INSTANTIATE_TEST_SUITE_P(AllTransitions, FsmTransitions, ::testing::Values( - // INIT - Transition{FSM_INIT, FSM_EVT_NONE, FSM_INIT}, - Transition{FSM_INIT, FSM_EVT_INIT_OK, FSM_SAFE}, - Transition{FSM_INIT, FSM_EVT_UNLOCK, FSM_INIT}, // can't skip SAFE - Transition{FSM_INIT, FSM_EVT_SLEEP, FSM_INIT}, - // SAFE - Transition{FSM_SAFE, FSM_EVT_NONE, FSM_SAFE}, - Transition{FSM_SAFE, FSM_EVT_INIT_OK, FSM_SAFE}, - Transition{FSM_SAFE, FSM_EVT_UNLOCK, FSM_ACTIVE}, - Transition{FSM_SAFE, FSM_EVT_SLEEP, FSM_SLEEP}, - // ACTIVE - Transition{FSM_ACTIVE, FSM_EVT_NONE, FSM_ACTIVE}, - Transition{FSM_ACTIVE, FSM_EVT_UNLOCK, FSM_ACTIVE}, // repeated unlock is harmless - Transition{FSM_ACTIVE, FSM_EVT_SLEEP, FSM_SLEEP}, - // SLEEP - Transition{FSM_SLEEP, FSM_EVT_UNLOCK, FSM_SLEEP}, - Transition{FSM_SLEEP, FSM_EVT_INIT_OK, FSM_SLEEP} -)); + // INIT + Transition { FSM_INIT, FSM_EVT_NONE, FSM_INIT }, Transition { FSM_INIT, FSM_EVT_INIT_OK, FSM_SAFE }, Transition { FSM_INIT, FSM_EVT_UNLOCK, FSM_INIT }, // can't skip SAFE + Transition { FSM_INIT, FSM_EVT_SLEEP, FSM_INIT }, + // SAFE + Transition { FSM_SAFE, FSM_EVT_NONE, FSM_SAFE }, Transition { FSM_SAFE, FSM_EVT_INIT_OK, FSM_SAFE }, Transition { FSM_SAFE, FSM_EVT_UNLOCK, FSM_ACTIVE }, Transition { FSM_SAFE, FSM_EVT_SLEEP, FSM_SLEEP }, + // ACTIVE + Transition { FSM_ACTIVE, FSM_EVT_NONE, FSM_ACTIVE }, Transition { FSM_ACTIVE, FSM_EVT_UNLOCK, FSM_ACTIVE }, // repeated unlock is harmless + Transition { FSM_ACTIVE, FSM_EVT_SLEEP, FSM_SLEEP }, + // SLEEP + Transition { FSM_SLEEP, FSM_EVT_UNLOCK, FSM_SLEEP }, Transition { FSM_SLEEP, FSM_EVT_INIT_OK, FSM_SLEEP })); -TEST(Fsm, CorruptedStateFailsSafe) -{ +TEST(Fsm, CorruptedStateFailsSafe) { EXPECT_EQ(fsm_next(static_cast(42), FSM_EVT_UNLOCK), FSM_SAFE); } -TEST(Fsm, StateNamesNeverNull) -{ +TEST(Fsm, StateNamesNeverNull) { for (int s = 0; s <= FSM_STATE_COUNT; ++s) { ASSERT_NE(fsm_state_name(static_cast(s)), nullptr); } diff --git a/tests/libs/test_util_thermistor.cpp b/tests/libs/test_util_thermistor.cpp index 38dd8fd..7596cf0 100644 --- a/tests/libs/test_util_thermistor.cpp +++ b/tests/libs/test_util_thermistor.cpp @@ -2,46 +2,40 @@ #include #include "util_thermistor.h" -static util_ntc_cfg_t cfg(bool ntc_on_top) -{ - return {3300.0f, 10000.0f, 10000.0f, 25.0f, 3950.0f, ntc_on_top}; +static util_ntc_cfg_t cfg(bool ntc_on_top) { + return { 3300.0f, 10000.0f, 10000.0f, 25.0f, 3950.0f, ntc_on_top }; } /* Divider voltage the circuit would produce at temp_c (the forward model) */ -static float divider_mv(const util_ntc_cfg_t &c, float temp_c) -{ +static float divider_mv(const util_ntc_cfg_t &c, float temp_c) { float r = c.r0_ohm * std::exp(c.beta * (1.0f / (temp_c + 273.15f) - 1.0f / (c.t0_c + 273.15f))); return c.ntc_on_top ? c.supply_mv * c.r_fixed_ohm / (r + c.r_fixed_ohm) : c.supply_mv * r / (r + c.r_fixed_ohm); } -TEST(UtilNtc, MidpointIsReferenceTemperature) -{ +TEST(UtilNtc, MidpointIsReferenceTemperature) { // R_ntc == R_fixed == R0 puts the ADC at half supply in either layout util_ntc_cfg_t top = cfg(true), bottom = cfg(false); EXPECT_NEAR(util_ntc_temp_c(&top, 1650.0f), 25.0f, 0.01f); EXPECT_NEAR(util_ntc_temp_c(&bottom, 1650.0f), 25.0f, 0.01f); } -TEST(UtilNtc, InvertsTheDividerAcrossTheRange) -{ - for (bool top : {true, false}) { +TEST(UtilNtc, InvertsTheDividerAcrossTheRange) { + for (bool top : { true, false }) { util_ntc_cfg_t c = cfg(top); - for (float t : {-40.0f, -10.0f, 0.0f, 35.0f, 60.0f, 100.0f}) { + for (float t : { -40.0f, -10.0f, 0.0f, 35.0f, 60.0f, 100.0f }) { EXPECT_NEAR(util_ntc_temp_c(&c, divider_mv(c, t)), t, 0.05f) << "top=" << top << " t=" << t; } } } -TEST(UtilNtc, HotterMeansHigherVoltageWhenNtcOnTop) -{ +TEST(UtilNtc, HotterMeansHigherVoltageWhenNtcOnTop) { util_ntc_cfg_t c = cfg(true); EXPECT_GT(util_ntc_temp_c(&c, 2000.0f), util_ntc_temp_c(&c, 1500.0f)); } -TEST(UtilNtc, OpenOrShortedThermistorIsNaN) -{ +TEST(UtilNtc, OpenOrShortedThermistorIsNaN) { util_ntc_cfg_t c = cfg(true); EXPECT_TRUE(std::isnan(util_ntc_temp_c(&c, 0.0f))); EXPECT_TRUE(std::isnan(util_ntc_temp_c(&c, 3300.0f))); @@ -49,8 +43,7 @@ TEST(UtilNtc, OpenOrShortedThermistorIsNaN) EXPECT_TRUE(std::isnan(util_ntc_temp_c(&c, NAN))); } -TEST(UtilNtc, BadConfigIsNaN) -{ +TEST(UtilNtc, BadConfigIsNaN) { util_ntc_cfg_t c = cfg(true); c.beta = 0.0f; EXPECT_TRUE(std::isnan(util_ntc_temp_c(&c, 1650.0f))); diff --git a/tests/libs/test_utilities.cpp b/tests/libs/test_utilities.cpp index f6812a3..721edf7 100644 --- a/tests/libs/test_utilities.cpp +++ b/tests/libs/test_utilities.cpp @@ -9,8 +9,7 @@ static const float kNaN = std::numeric_limits::quiet_NaN(); static const float kInf = std::numeric_limits::infinity(); -TEST(UtilMath, InRange) -{ +TEST(UtilMath, InRange) { EXPECT_TRUE(util_in_range(37.2f, -50.0f, 100.0f)); EXPECT_TRUE(util_in_range(-50.0f, -50.0f, 100.0f)); // edges inclusive EXPECT_FALSE(util_in_range(-200.0f, -50.0f, 100.0f)); // the SED's example @@ -18,64 +17,57 @@ TEST(UtilMath, InRange) EXPECT_FALSE(util_in_range(kInf, -50.0f, 100.0f)); } -TEST(UtilMath, Clamp) -{ +TEST(UtilMath, Clamp) { EXPECT_EQ(util_clampf(5.0f, 0.0f, 10.0f), 5.0f); EXPECT_EQ(util_clampf(-1.0f, 0.0f, 10.0f), 0.0f); EXPECT_EQ(util_clampf(11.0f, 0.0f, 10.0f), 10.0f); EXPECT_EQ(util_clampf(kNaN, 0.0f, 10.0f), 0.0f); } -TEST(UtilMath, ToI16RoundsAndScales) -{ - EXPECT_EQ(util_to_i16(37.2f, 10.0f), 372); // SED example - EXPECT_EQ(util_to_i16(-12.36f, 10.0f), -124); // rounds to nearest +TEST(UtilMath, ToI16RoundsAndScales) { + EXPECT_EQ(util_to_i16(37.2f, 10.0f), 372); // SED example + EXPECT_EQ(util_to_i16(-12.36f, 10.0f), -124); // rounds to nearest EXPECT_EQ(util_to_i16(28.012f, 1000.0f), 28012); // volts -> mV } -TEST(UtilMath, ToI16SaturatesAndFlagsInvalid) -{ +TEST(UtilMath, ToI16SaturatesAndFlagsInvalid) { EXPECT_EQ(util_to_i16(1e9f, 1.0f), INT16_MAX); EXPECT_EQ(util_to_i16(-1e9f, 1.0f), INT16_MIN + 1); // never collides with INVALID EXPECT_EQ(util_to_i16(kInf, 1.0f), INT16_MAX); EXPECT_EQ(util_to_i16(kNaN, 10.0f), UTIL_I16_INVALID); } -TEST(UtilMath, FromI16) -{ +TEST(UtilMath, FromI16) { EXPECT_FLOAT_EQ(util_from_i16(372, 10.0f), 37.2f); EXPECT_TRUE(std::isnan(util_from_i16(UTIL_I16_INVALID, 10.0f))); EXPECT_TRUE(std::isnan(util_from_i16(100, 0.0f))); } -TEST(UtilEma, FirstSampleSeedsOutput) -{ +TEST(UtilEma, FirstSampleSeedsOutput) { util_ema_t f; util_ema_init(&f, 0.1f); EXPECT_FLOAT_EQ(util_ema_update(&f, 35.0f), 35.0f); // no ramp from 0 } -TEST(UtilEma, ConvergesToStepInput) -{ +TEST(UtilEma, ConvergesToStepInput) { util_ema_t f; util_ema_init(&f, 0.2f); util_ema_update(&f, 0.0f); float out = 0.0f; - for (int i = 0; i < 100; i++) out = util_ema_update(&f, 10.0f); + for (int i = 0; i < 100; i++) + out = util_ema_update(&f, 10.0f); EXPECT_NEAR(out, 10.0f, 1e-3f); } -TEST(UtilEma, SmoothsASpike) -{ +TEST(UtilEma, SmoothsASpike) { util_ema_t f; util_ema_init(&f, 0.1f); util_ema_update(&f, 35.0f); EXPECT_NEAR(util_ema_update(&f, 135.0f), 45.0f, 1e-4f); // 10% of the jump } -TEST(UtilEma, BadAlphaMeansNoFiltering) -{ - for (float a : {0.0f, -0.5f, 1.5f, kNaN}) { +TEST(UtilEma, BadAlphaMeansNoFiltering) { + for (float a : { 0.0f, -0.5f, 1.5f, kNaN }) { util_ema_t f; util_ema_init(&f, a); util_ema_update(&f, 1.0f); @@ -83,8 +75,7 @@ TEST(UtilEma, BadAlphaMeansNoFiltering) } } -TEST(UtilBangBang, HysteresisCycle) -{ +TEST(UtilBangBang, HysteresisCycle) { util_bangbang_t c; util_bangbang_init(&c, 35.0f, 0.5f); EXPECT_FALSE(c.on); @@ -96,16 +87,14 @@ TEST(UtilBangBang, HysteresisCycle) EXPECT_TRUE(util_bangbang_update(&c, 34.5f)); // bottom of band: on } -TEST(UtilBangBang, NaNTurnsOff) -{ +TEST(UtilBangBang, NaNTurnsOff) { util_bangbang_t c; util_bangbang_init(&c, 35.0f, 0.5f); util_bangbang_update(&c, 20.0f); EXPECT_FALSE(util_bangbang_update(&c, kNaN)); } -TEST(UtilBangBang, SetpointChangeTakesEffect) -{ +TEST(UtilBangBang, SetpointChangeTakesEffect) { util_bangbang_t c; util_bangbang_init(&c, 35.0f, 0.5f); EXPECT_FALSE(util_bangbang_update(&c, 36.0f)); @@ -113,17 +102,15 @@ TEST(UtilBangBang, SetpointChangeTakesEffect) EXPECT_TRUE(util_bangbang_update(&c, 36.0f)); } -TEST(UtilTimer, FiresOncePerPeriod) -{ +TEST(UtilTimer, FiresOncePerPeriod) { uint32_t next = 0; - EXPECT_TRUE(util_every(0, &next, 500)); // first call fires immediately + EXPECT_TRUE(util_every(0, &next, 500)); // first call fires immediately EXPECT_FALSE(util_every(499, &next, 500)); EXPECT_TRUE(util_every(500, &next, 500)); EXPECT_FALSE(util_every(999, &next, 500)); } -TEST(UtilTimer, SurvivesClockWrap) -{ +TEST(UtilTimer, SurvivesClockWrap) { uint32_t next = UINT32_MAX - 100; EXPECT_TRUE(util_every(UINT32_MAX - 100, &next, 500)); EXPECT_FALSE(util_every(398, &next, 500)); // 499 ms later, wrapped diff --git a/tests/src/test_eps.cpp b/tests/src/test_eps.cpp index 0ea155b..444beac 100644 --- a/tests/src/test_eps.cpp +++ b/tests/src/test_eps.cpp @@ -6,8 +6,7 @@ #include "util_math.h" /* Pin voltage the real divider gives at temp_c (independent of util_ntc_temp_c) */ -static float divider_mv(float temp_c) -{ +static float divider_mv(float temp_c) { const util_ntc_cfg_t c = EPS_NTC_CFG; float r = c.r0_ohm * std::exp(c.beta * (1.0f / (temp_c + 273.15f) - 1.0f / (c.t0_c + 273.15f))); return c.ntc_on_top ? c.supply_mv * c.r_fixed_ohm / (r + c.r_fixed_ohm) @@ -21,28 +20,24 @@ class EpsControl : public ::testing::Test { eps_control_t ctl; eps_data_t d; void SetUp() override { eps_control_init(&ctl); } - void step(bool s_ok, float s_mv, bool t_ok, float t_mv) - { - eps_raw_t raw = {s_ok, s_mv, t_ok, t_mv}; + void step(bool s_ok, float s_mv, bool t_ok, float t_mv) { + eps_raw_t raw = { s_ok, s_mv, t_ok, t_mv }; eps_control_step(&ctl, &raw, &d); } }; -TEST_F(EpsControl, CurrentFromShunt) -{ +TEST_F(EpsControl, CurrentFromShunt) { step(true, 41.2f, true, MV_25C); EXPECT_EQ(d.shunt_mv_x100, 4120); EXPECT_EQ(d.current_ma, 412); // 41.2 mV / 0.1 ohm } -TEST_F(EpsControl, NegativeCurrentIsValid) -{ +TEST_F(EpsControl, NegativeCurrentIsValid) { step(true, -1.0f, true, MV_25C); EXPECT_EQ(d.current_ma, -10); } -TEST_F(EpsControl, SaturatedOrMissingShuntIsInvalid) -{ +TEST_F(EpsControl, SaturatedOrMissingShuntIsInvalid) { step(true, 81.92f, true, MV_25C); EXPECT_EQ(d.current_ma, UTIL_I16_INVALID); EXPECT_EQ(d.shunt_mv_x100, UTIL_I16_INVALID); @@ -52,14 +47,12 @@ TEST_F(EpsControl, SaturatedOrMissingShuntIsInvalid) EXPECT_NE(d.temp_c_x10, UTIL_I16_INVALID); // one bad sensor doesn't hide the other } -TEST_F(EpsControl, ThermistorAt25C) -{ +TEST_F(EpsControl, ThermistorAt25C) { step(true, 0.0f, true, MV_25C); EXPECT_EQ(d.temp_c_x10, 250); } -TEST_F(EpsControl, ThermistorColdAndWarm) -{ +TEST_F(EpsControl, ThermistorColdAndWarm) { step(true, 0.0f, true, divider_mv(-20.0f)); EXPECT_EQ(d.temp_c_x10, -200); @@ -68,48 +61,42 @@ TEST_F(EpsControl, ThermistorColdAndWarm) EXPECT_EQ(d.temp_c_x10, 300); } -TEST_F(EpsControl, ClippedAdcIsInvalidNotAFalseTemperature) -{ +TEST_F(EpsControl, ClippedAdcIsInvalidNotAFalseTemperature) { step(true, 0.0f, true, 3100.0f); EXPECT_EQ(d.temp_c_x10, UTIL_I16_INVALID); } -TEST_F(EpsControl, DisconnectedThermistorIsInvalid) -{ - step(true, 0.0f, true, 0.0f); // pin pulled to ground +TEST_F(EpsControl, DisconnectedThermistorIsInvalid) { + step(true, 0.0f, true, 0.0f); // pin pulled to ground EXPECT_EQ(d.temp_c_x10, UTIL_I16_INVALID); - step(true, 0.0f, false, MV_25C); // ADC read failed + step(true, 0.0f, false, MV_25C); // ADC read failed EXPECT_EQ(d.temp_c_x10, UTIL_I16_INVALID); } -TEST_F(EpsControl, TemperatureSpikeIsSmoothed) -{ - step(true, 0.0f, true, MV_25C); // 25.0 degC seeds the filter - step(true, 0.0f, true, divider_mv(30.0f)); // sudden jump to 30 degC - EXPECT_EQ(d.temp_c_x10, 260); // only 20% of the way there +TEST_F(EpsControl, TemperatureSpikeIsSmoothed) { + step(true, 0.0f, true, MV_25C); // 25.0 degC seeds the filter + step(true, 0.0f, true, divider_mv(30.0f)); // sudden jump to 30 degC + EXPECT_EQ(d.temp_c_x10, 260); // only 20% of the way there } class EpsComms : public ::testing::Test { protected: eps_comms_t c; - eps_data_t data = {412, 4120, 301}; + eps_data_t data = { 412, 4120, 301 }; can_frame_t tx[EPS_COMMS_MAX_TX]; - void SetUp() override - { + void SetUp() override { eps_comms_init(&c, 0); eps_comms_boot_done(&c); // SAFE, as setup.c does } - void receive(can_sys_cmd_t cmd, can_source_t target) - { + void receive(can_sys_cmd_t cmd, can_source_t target) { can_frame_t f; can_encode_sys_cmd(&f, cmd, target); eps_comms_on_frame(&c, &f); } }; -TEST_F(EpsComms, SafeSendsHeartbeatButNoStatus) -{ +TEST_F(EpsComms, SafeSendsHeartbeatButNoStatus) { ASSERT_EQ(eps_comms_on_tick(&c, 0, &data, tx), 1u); can_heartbeat_t hb; ASSERT_TRUE(can_decode_heartbeat(&tx[0], &hb)); @@ -117,8 +104,7 @@ TEST_F(EpsComms, SafeSendsHeartbeatButNoStatus) EXPECT_EQ(hb.state, FSM_SAFE); } -TEST_F(EpsComms, UnlockStartsStatus) -{ +TEST_F(EpsComms, UnlockStartsStatus) { receive(CAN_SYS_UNLOCK, CAN_SRC_EPS); EXPECT_EQ(c.state, FSM_ACTIVE); @@ -130,37 +116,32 @@ TEST_F(EpsComms, UnlockStartsStatus) EXPECT_EQ(s.temp_c_x10, 301); } -TEST_F(EpsComms, StatusEverySecond) -{ +TEST_F(EpsComms, StatusEverySecond) { receive(CAN_SYS_UNLOCK, CAN_SRC_BROADCAST); EXPECT_EQ(eps_comms_on_tick(&c, 0, &data, tx), 2u); EXPECT_EQ(eps_comms_on_tick(&c, 500, &data, tx), 1u); // heartbeat only EXPECT_EQ(eps_comms_on_tick(&c, 1000, &data, tx), 2u); // both } -TEST_F(EpsComms, OtherNodesUnlockIsIgnored) -{ +TEST_F(EpsComms, OtherNodesUnlockIsIgnored) { receive(CAN_SYS_UNLOCK, CAN_SRC_THERMAL); EXPECT_EQ(c.state, FSM_SAFE); } -TEST_F(EpsComms, SleepAndReset) -{ +TEST_F(EpsComms, SleepAndReset) { receive(CAN_SYS_RESET, CAN_SRC_BROADCAST); EXPECT_TRUE(c.reset_requested); receive(CAN_SYS_SLEEP, CAN_SRC_EPS); EXPECT_EQ(c.state, FSM_SLEEP); } -TEST_F(EpsComms, HeartbeatEvery500ms) -{ +TEST_F(EpsComms, HeartbeatEvery500ms) { EXPECT_EQ(eps_comms_on_tick(&c, 0, &data, tx), 1u); EXPECT_EQ(eps_comms_on_tick(&c, 499, &data, tx), 0u); EXPECT_EQ(eps_comms_on_tick(&c, 500, &data, tx), 1u); } -TEST_F(EpsComms, TimingSurvivesClockWrap) -{ +TEST_F(EpsComms, TimingSurvivesClockWrap) { eps_comms_init(&c, UINT32_MAX - 100); EXPECT_EQ(eps_comms_on_tick(&c, UINT32_MAX - 100, &data, tx), 1u); EXPECT_EQ(eps_comms_on_tick(&c, 398, &data, tx), 0u); // 499 ms later, wrapped diff --git a/tests/src/test_instrumentation.cpp b/tests/src/test_instrumentation.cpp index 55a03b7..63427b2 100644 --- a/tests/src/test_instrumentation.cpp +++ b/tests/src/test_instrumentation.cpp @@ -1,8 +1,7 @@ #include #include "comms.h" -TEST(InstrComms, HeartbeatAsInstrumentation) -{ +TEST(InstrComms, HeartbeatAsInstrumentation) { instr_comms_t c; can_frame_t tx[INSTR_COMMS_MAX_TX]; instr_comms_init(&c, 0); @@ -15,8 +14,7 @@ TEST(InstrComms, HeartbeatAsInstrumentation) EXPECT_EQ(hb.state, FSM_SAFE); } -TEST(InstrComms, UnlockedByMaster) -{ +TEST(InstrComms, UnlockedByMaster) { instr_comms_t c; can_frame_t f; instr_comms_init(&c, 0); diff --git a/tests/src/test_master.cpp b/tests/src/test_master.cpp index fbb0646..be460b0 100644 --- a/tests/src/test_master.cpp +++ b/tests/src/test_master.cpp @@ -11,17 +11,15 @@ class MasterComms : public ::testing::Test { void SetUp() override { master_comms_init(&c, 0); } - can_frame_t heartbeat_from(can_source_t src, fsm_state_t state) - { + can_frame_t heartbeat_from(can_source_t src, fsm_state_t state) { can_frame_t f; - can_heartbeat_t hb = {src, (uint8_t)state, 12}; + can_heartbeat_t hb = { src, (uint8_t)state, 12 }; can_encode_heartbeat(&f, &hb); return f; } }; -TEST_F(MasterComms, StartsActiveAndSendsHeartbeat) -{ +TEST_F(MasterComms, StartsActiveAndSendsHeartbeat) { EXPECT_EQ(c.state, FSM_ACTIVE); ASSERT_EQ(master_comms_on_tick(&c, 0, tx), 1u); can_heartbeat_t hb; @@ -32,8 +30,7 @@ TEST_F(MasterComms, StartsActiveAndSendsHeartbeat) EXPECT_EQ(master_comms_on_tick(&c, 500, tx), 1u); } -TEST_F(MasterComms, UnlocksANodeInSafe) -{ +TEST_F(MasterComms, UnlocksANodeInSafe) { can_frame_t hb = heartbeat_from(CAN_SRC_EPS, FSM_SAFE); ASSERT_EQ(master_comms_on_frame(&c, 0, &hb, tx), 1u); // The reply is an unlock EPS accepts, and no other node does @@ -41,54 +38,47 @@ TEST_F(MasterComms, UnlocksANodeInSafe) EXPECT_EQ(can_decode_sys_cmd(&tx[0], CAN_SRC_THERMAL), CAN_SYS_NONE); } -TEST_F(MasterComms, LeavesActiveNodesAlone) -{ +TEST_F(MasterComms, LeavesActiveNodesAlone) { can_frame_t hb = heartbeat_from(CAN_SRC_EPS, FSM_ACTIVE); EXPECT_EQ(master_comms_on_frame(&c, 0, &hb, tx), 0u); } -TEST_F(MasterComms, IgnoresOtherFrames) -{ +TEST_F(MasterComms, IgnoresOtherFrames) { can_frame_t f; - can_eps_status_t s = {412, 4120, 301}; + can_eps_status_t s = { 412, 4120, 301 }; can_encode_eps_status(&f, &s); EXPECT_EQ(master_comms_on_frame(&c, 0, &f, tx), 0u); } -TEST_F(MasterComms, DescribesHeartbeat) -{ +TEST_F(MasterComms, DescribesHeartbeat) { can_frame_t hb = heartbeat_from(CAN_SRC_EPS, FSM_SAFE); EXPECT_EQ(std::string(master_describe_frame(&hb, text, sizeof text)), - "EPS heartbeat: SAFE, up 12 s"); + "EPS heartbeat: SAFE, up 12 s"); } -TEST_F(MasterComms, DescribesEpsStatusIncludingInvalid) -{ +TEST_F(MasterComms, DescribesEpsStatusIncludingInvalid) { can_frame_t f; - can_eps_status_t s = {412, 4120, INT16_MIN}; + can_eps_status_t s = { 412, 4120, INT16_MIN }; can_encode_eps_status(&f, &s); EXPECT_EQ(std::string(master_describe_frame(&f, text, sizeof text)), - "EPS status: current 412.00 mA, shunt 41.20 mV, PCB invalid"); + "EPS status: current 412.00 mA, shunt 41.20 mV, PCB invalid"); } -TEST_F(MasterComms, DescribesUnknownFrames) -{ +TEST_F(MasterComms, DescribesUnknownFrames) { can_frame_t f; can_frame_init(&f, CAN_PRIO_WARNING, CAN_SRC_THERMAL, 0x06, 2); EXPECT_EQ(std::string(master_describe_frame(&f, text, sizeof text)), - "THERMAL frame: prio 2, type 0x06, 2 bytes (id 0x5C6)"); + "THERMAL frame: prio 2, type 0x06, 2 bytes (id 0x5C6)"); } -TEST_F(MasterComms, DescribeNeverOverflows) -{ +TEST_F(MasterComms, DescribeNeverOverflows) { can_frame_t hb = heartbeat_from(CAN_SRC_INSTRUMENTATION, FSM_SAFE); char tiny[8]; master_describe_frame(&hb, tiny, sizeof tiny); EXPECT_EQ(std::string(tiny).size(), 7u); } -TEST_F(MasterComms, TracksNodesComingAndGoing) -{ +TEST_F(MasterComms, TracksNodesComingAndGoing) { EXPECT_EQ(c.alive_mask, 0); can_frame_t eps = heartbeat_from(CAN_SRC_EPS, FSM_ACTIVE); can_frame_t ins = heartbeat_from(CAN_SRC_INSTRUMENTATION, FSM_ACTIVE); @@ -96,15 +86,14 @@ TEST_F(MasterComms, TracksNodesComingAndGoing) master_comms_on_frame(&c, 1000, &ins, tx); EXPECT_EQ(c.alive_mask, (1u << CAN_SRC_EPS) | (1u << CAN_SRC_INSTRUMENTATION)); - master_comms_on_frame(&c, 2400, &eps, tx); // EPS keeps talking, Instrumentation goes quiet - master_comms_on_tick(&c, 2500, tx); // 1500 ms since Instrumentation: not yet lost + master_comms_on_frame(&c, 2400, &eps, tx); // EPS keeps talking, Instrumentation goes quiet + master_comms_on_tick(&c, 2500, tx); // 1500 ms since Instrumentation: not yet lost EXPECT_EQ(c.alive_mask, (1u << CAN_SRC_EPS) | (1u << CAN_SRC_INSTRUMENTATION)); - master_comms_on_tick(&c, 2501, tx); // 1501 ms: lost + master_comms_on_tick(&c, 2501, tx); // 1501 ms: lost EXPECT_EQ(c.alive_mask, 1u << CAN_SRC_EPS); } -TEST_F(MasterComms, IgnoresItsOwnHeartbeat) -{ +TEST_F(MasterComms, IgnoresItsOwnHeartbeat) { can_frame_t own = heartbeat_from(CAN_SRC_MASTER, FSM_ACTIVE); EXPECT_EQ(master_comms_on_frame(&c, 0, &own, tx), 0u); EXPECT_EQ(c.alive_mask, 0);