// gcc -Wall -Wextra -O2 -o tele_only main.c && ./tele_only // // Payload-only test: // - NO KISS decode // - NO AX.25 parsing // - Just: hex payload -> bytes -> memcpy -> print // // Change requested: // - Keep COMM reserved fields in the struct (for alignment) // - DO NOT print comm_res_1/2/3 #include #include #include #include #define MPPT_CHANNEL 7 #define BATT_TEMP 4 #define MAX_INPUT_BYTES 2048 static uint8_t g_payload[MAX_INPUT_BYTES]; static uint16_t g_payload_len = 0; static char g_timestamp[20]; /* ------------------------------------------------------- * Telemetry structs (payload = 149 bytes) * - No typedef names: remote_reserve_t / data_1_t / data_2_t * - Layout is identical (packed) * ------------------------------------------------------- */ typedef struct __attribute__((packed)) { struct __attribute__((packed)) { uint16_t res_1; uint16_t res_2; uint8_t res_3; } res; uint8_t pcdu_on; } pcdu_t; typedef struct __attribute__((packed)) { struct __attribute__((packed)) { uint16_t res_1; uint16_t res_2; uint8_t res_3; } res; } comm_t; typedef struct __attribute__((packed)) { struct __attribute__((packed)) { uint16_t res_1; uint16_t res_2; uint8_t res_3; } res; float isens[MPPT_CHANNEL]; float power[MPPT_CHANNEL]; float vbus[MPPT_CHANNEL]; } mppt_t; typedef struct __attribute__((packed)) { struct __attribute__((packed)) { uint16_t res_1; uint16_t res_2; uint8_t res_3; } res; uint16_t heater_cnt; float batt_temp[BATT_TEMP]; float batt_vout; float batt_iout; float batt_vin; float batt_iin; } batt_t; typedef struct __attribute__((packed)) { uint8_t status_1; uint8_t status_2; } status_t; typedef struct __attribute__((packed)) { struct __attribute__((packed)) { uint16_t res_1; uint16_t res_2; uint8_t res_3; } res; } obc_t; typedef struct __attribute__((packed)) { pcdu_t pcdu; comm_t comm; /* reserved (not displayed) */ mppt_t mppt; batt_t batt; status_t ant; obc_t obc; uint8_t ident[3]; } remote_tele_t; static remote_tele_t g_param; /* ----------------------------- * Hex dump * ----------------------------- */ static void hex_dump(const char *label, const uint8_t *buf, uint16_t len) { printf("%s (len=%u)\n", label, len); for (uint16_t i = 0; i < len; i++) { if ((i % 16) == 0) printf("%04u: ", i); printf("%02X ", buf[i]); if ((i % 16) == 15 || i == (len - 1)) printf("\n"); } } /* ----------------------------- * Safe reads (avoid unaligned access from packed) * ----------------------------- */ static float read_f32_unaligned(const void *p) { float v; memcpy(&v, p, sizeof(v)); return v; } static uint16_t read_u16_unaligned(const void *p) { uint16_t v; memcpy(&v, p, sizeof(v)); return v; } /* ----------------------------- * Timestamp + printing * ----------------------------- */ static const char *get_timestamp(void) { time_t current_time; struct tm *time_info; time(¤t_time); time_info = localtime(¤t_time); strftime(g_timestamp, sizeof(g_timestamp), "%Y-%m-%d %H:%M:%S", time_info); return g_timestamp; } static void print_float_array_unaligned(const char *label, const void *arr_bytes, uint8_t len) { const uint8_t *p = (const uint8_t *)arr_bytes; printf("%-20s = [ ", label); for (uint8_t i = 0; i < len; i++) { float v = read_f32_unaligned(p + (i * 4)); printf("%f ", v); } printf("]\r\n"); } static void print_telemetry(void) { printf("\033[0;31m"); printf("Last Updated - %s\n", get_timestamp()); printf("\033[0m"); printf("sizeof(remote_tele_t) = %u bytes\r\n", (unsigned)sizeof(remote_tele_t)); /* PCDU */ printf("\033[0;32m"); printf("pcdu_on = 0x%02X\r\n", g_param.pcdu.pcdu_on); printf("\033[0m"); /* COMM: reserved, not displayed */ (void)g_param.comm; /* MPPT */ printf("\033[0;33m"); printf("mppt_r1 = %u\r\n", g_param.mppt.res.res_1); printf("mppt_r2 = %u\r\n", g_param.mppt.res.res_2); printf("mppt_r3 = %u\r\n", g_param.mppt.res.res_3); printf("\033[0m"); printf("\033[0;32m"); print_float_array_unaligned("mppt_power", &g_param.mppt.power[0], MPPT_CHANNEL); print_float_array_unaligned("mppt_vbus ", &g_param.mppt.vbus[0], MPPT_CHANNEL); print_float_array_unaligned("mppt_isens", &g_param.mppt.isens[0], MPPT_CHANNEL); printf("\033[0m"); /* BATT */ printf("\033[0;33m"); printf("batt_r1 = %u\r\n", g_param.batt.res.res_1); printf("batt_r2 = %u\r\n", g_param.batt.res.res_2); printf("batt_r3 = %u\r\n", g_param.batt.res.res_3); printf("batt_heater_cnt = %u\r\n", read_u16_unaligned(&g_param.batt.heater_cnt)); printf("\033[0m"); printf("\033[0;32m"); printf("batt_vout = %f\r\n", read_f32_unaligned(&g_param.batt.batt_vout)); printf("batt_iout = %f\r\n", read_f32_unaligned(&g_param.batt.batt_iout)); printf("batt_vin = %f\r\n", read_f32_unaligned(&g_param.batt.batt_vin)); printf("batt_iin = %f\r\n", read_f32_unaligned(&g_param.batt.batt_iin)); print_float_array_unaligned("batt_temp ", &g_param.batt.batt_temp[0], BATT_TEMP); printf("\033[0m"); /* STATUS */ printf("\033[0;33m"); printf("status_1 = 0x%02X\r\n", g_param.ant.status_1); printf("status_2 = 0x%02X\r\n", g_param.ant.status_2); printf("\033[0m"); /* OBC */ printf("\033[0;32m"); printf("obc_r1 = %u\r\n", g_param.obc.res.res_1); printf("obc_r2 = %u\r\n", g_param.obc.res.res_2); printf("obc_r3 = %u\r\n", g_param.obc.res.res_3); printf("\033[0m"); /* IDENT */ printf("\033[0;33m"); printf("ident = %c%c%c\r\n", g_param.ident[0], g_param.ident[1], g_param.ident[2]); printf("\033[0m"); printf("\r\n"); } /* ----------------------------- * Hex string -> bytes * ----------------------------- */ static int hex_nibble(char c) { if (c >= '0' && c <= '9') return c - '0'; if (c >= 'a' && c <= 'f') return 10 + (c - 'a'); if (c >= 'A' && c <= 'F') return 10 + (c - 'A'); return -1; } static uint16_t parse_hex_bytes(const char *s, uint8_t *out, uint16_t out_cap) { uint16_t n = 0; while (*s) { while (*s == ' ' || *s == '\n' || *s == '\r' || *s == '\t') s++; if (!*s) break; int hi = hex_nibble(s[0]); int lo = hex_nibble(s[1]); if (hi < 0 || lo < 0) break; if (n >= out_cap) break; out[n++] = (uint8_t)((hi << 4) | lo); s += 2; while (*s == ' ') s++; } return n; } /* ----------------------------- * Main: payload-only test vector * ----------------------------- */ int main(void) { const char *PAYLOAD_HEX = "05 00 56 01 03 AA 02 00 16 01 02 01 00 9C 00 01 " "00 00 80 3F CD CC 8C 3F 9A 99 99 3F 66 66 A6 3F " "33 33 B3 3F 00 00 C0 3F CD CC CC 3F 00 00 A0 40 " "00 00 C0 40 00 00 E0 40 00 00 00 41 00 00 10 41 " "00 00 20 41 00 00 30 41 66 66 A6 40 00 00 B0 40 " "99 99 B9 40 33 33 C3 40 CC CC CC 40 66 66 D6 40 " "00 00 E0 40 00 00 EA 00 02 2D 00 00 00 A0 41 00 " "00 C8 41 00 00 F0 41 00 00 0C 42 CD CC EC 40 66 " "66 E6 3F 66 66 E6 40 9A 99 99 3F 0F 03 00 00 37 " "02 05 42 43 4E"; g_payload_len = parse_hex_bytes(PAYLOAD_HEX, g_payload, sizeof(g_payload)); printf("Payload bytes: %u\n", g_payload_len); if (g_payload_len < sizeof(remote_tele_t)) { printf("Not enough payload bytes for telemetry. Need %u, have %u\n", (unsigned)sizeof(remote_tele_t), (unsigned)g_payload_len); return 1; } memcpy(&g_param, g_payload, sizeof(remote_tele_t)); hex_dump("Telemetry bytes (remote_tele_t)", (const uint8_t *)&g_param, (uint16_t)sizeof(remote_tele_t)); print_telemetry(); return 0; }