From 85a628da2b1a28aee6a991056b9f1a41ce2448c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominic=20H=C3=B6glinger?= Date: Sun, 18 May 2025 12:45:56 +0200 Subject: [PATCH] Add 64 bit integers and doubles --- README.md | 2 +- st.c | 43 +++++++++++++++++++++++++-- st.h | 25 +++++++++++++++- st_record.py | 84 +++++++++++++++++++++++++++++++++++++++++----------- 4 files changed, 132 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index deab324..0fe0901 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ ST is a small tracing library written in C99. It is optimized for minimal data usage and aims to be easy to use while also being flexible enough to be integrated in hard real time systems. -Signal types supported are all integers up to 32 bit as well as their arrays, floats, events and strings. +Signal types supported are all integers up to 64 bit, integer arrays up to 32 bit, floats, doubles, events and strings. ![Demo of st_record.py in TUI mode displaying various traced signals and diagnostic information regarding ST](.media/demo-tui.gif "Demo of st_record.py in TUI mode") diff --git a/st.c b/st.c index 28e9d5c..e2c37a0 100644 --- a/st.c +++ b/st.c @@ -50,11 +50,13 @@ typedef enum st_v1 = 0x21, st_v2 = 0x22, st_v4 = 0x24, + st_v8 = 0x28, st_a1 = 0x31, st_a2 = 0x32, st_a4 = 0x34, st_s4 = 0x44, st_f4 = 0x54, + st_f8 = 0x58, st_ev = 0x60, } st_type_t; @@ -72,8 +74,10 @@ typedef struct typedef union { uint32_t u32value; + uint64_t u64value; #if (!ST_FLOAT_DISABLE) float f32value; + double f64value; #endif } st_convert_t; @@ -387,6 +391,16 @@ void st_u32trace(const char* const tag, const uint32_t value, const bool skip_ti } } +void st_u64trace(const char* const tag, const uint64_t value, const bool skip_time) +{ + if (s_enabled == true) + { + uint32_t ts = skip_time ? 0UL : st_timestamp(); + tracebuffer_add(ts, st_v8, (uint32_t)(value & 0xFFFFFFFF), 0U, tag); + tracebuffer_add(ts, st_v8, (uint32_t)(value >> 32), 1U, tag); + } +} + void st_s8trace(const char* const tag, const int8_t value, const bool skip_time) { if (s_enabled == true) @@ -403,7 +417,7 @@ void st_s16trace(const char* const tag, const int16_t value, const bool skip_tim } } -void st_s4trace(const char* const tag, const int32_t value, const bool skip_time) +void st_s32trace(const char* const tag, const int32_t value, const bool skip_time) { if (s_enabled == true) { @@ -411,6 +425,16 @@ void st_s4trace(const char* const tag, const int32_t value, const bool skip_time } } +void st_s64trace(const char* const tag, const int64_t value, const bool skip_time) +{ + if (s_enabled == true) + { + uint32_t ts = skip_time ? 0UL : st_timestamp(); + tracebuffer_add(ts, st_v8, (uint32_t)(value & 0xFFFFFFFF), 0U, tag); + tracebuffer_add(ts, st_v8, (uint32_t)(value >> 32), 1U, tag); + } +} + void st_au8trace(const char* const tag, const uint8_t value[const], const uint8_t size, const bool skip_time) { if (s_enabled == true) @@ -512,12 +536,23 @@ void st_strtrace(const char* const tag, const char* const str, const bool skip_t #if (!ST_FLOAT_DISABLE) void st_f32trace(const char* const tag, const float value, const bool skip_time) { - st_convert_t converter = {.f32value = value }; + st_convert_t converter = { .f32value = value }; if (s_enabled == true) { tracebuffer_add(skip_time ? 0UL : st_timestamp(), st_f4, converter.u32value, 0U, tag); } } + +void st_f64trace(const char* const tag, const double value, const bool skip_time) +{ + st_convert_t converter = { .f64value = value }; + if (s_enabled == true) + { + uint32_t ts = skip_time ? 0UL : st_timestamp(); + tracebuffer_add(ts, st_f8, (uint32_t)(converter.u64value & 0xFFFFFFFF), 0U, tag); + tracebuffer_add(ts, st_f8, (uint32_t)(converter.u64value >> 32), 1U, tag); + } +} #endif static size_t frame_preamble(char buffer[], const size_t buffer_size) @@ -567,6 +602,8 @@ static size_t pack_frame(char packet_bytes[], const st_trace_t* const p_packet) case st_s4: case st_f4: case st_d4: + case st_v8: + case st_f8: packet_bytes[packet_size++] = ST_BYTE(p_packet->m_value, 0); packet_bytes[packet_size++] = ST_BYTE(p_packet->m_value, 1); packet_bytes[packet_size++] = ST_BYTE(p_packet->m_value, 2); @@ -580,6 +617,8 @@ static size_t pack_frame(char packet_bytes[], const st_trace_t* const p_packet) case st_a2: case st_a4: case st_s4: + case st_v8: + case st_f8: packet_bytes[packet_size++] = (char)p_packet->m_sub; break; } diff --git a/st.h b/st.h index adfb6b0..05c2b5f 100644 --- a/st.h +++ b/st.h @@ -184,6 +184,14 @@ void st_u16trace(const char* const tag, const uint16_t value, const bool skip_ti */ void st_u32trace(const char* const tag, const uint32_t value, const bool skip_time); +/** @brief Trace an u64 value + * @param[in] tag Signal name of the trace + * @param[in] value Value to trace + * @param[in] skip_time Use last recorded timestamp for this trace + * @return None + */ +void st_u64trace(const char* const tag, const uint64_t value, const bool skip_time); + /** @brief Trace an s8 value * @param[in] tag Signal name of the trace * @param[in] value Value to trace @@ -208,6 +216,14 @@ void st_s16trace(const char* const tag, const int16_t value, const bool skip_tim */ void st_s32trace(const char* const tag, const int32_t value, const bool skip_time); +/** @brief Trace an s64 value + * @param[in] tag Signal name of the trace + * @param[in] value Value to trace + * @param[in] skip_time Use last recorded timestamp for this trace + * @return None + */ +void st_s64trace(const char* const tag, const int64_t value, const bool skip_time); + /** @brief Trace an array of u8 values * @param[in] tag Signal name of the trace * @param[in] value Value array to trace @@ -272,7 +288,6 @@ void st_as32trace(const char* const tag, const int32_t value[const], const uint8 void st_strtrace(const char* const tag, const char* const str, const bool skip_time); #if (!ST_FLOAT_DISABLE) - /** @brief Trace an f32 value * @param[in] tag Signal name of the trace * @param[in] value Value to trace @@ -280,6 +295,14 @@ void st_strtrace(const char* const tag, const char* const str, const bool skip_t * @return None */ void st_f32trace(const char* const tag, const float value, const bool skip_time); + +/** @brief Trace an f64 value + * @param[in] tag Signal name of the trace + * @param[in] value Value to trace + * @param[in] skip_time Use last recorded timestamp for this trace + * @return None + */ +void st_f64trace(const char* const tag, const double value, const bool skip_time); #endif #endif diff --git a/st_record.py b/st_record.py index 400aa3d..71e6b32 100644 --- a/st_record.py +++ b/st_record.py @@ -170,7 +170,7 @@ def fastlz_decompress_lv1(datain, doutlen): def scan_for_signals(directory, predefined_signals): library_files = ['st.c', 'st.h'] rx_events = re.compile(r'st_evtrace\(\"([^\"]+)\"') - rx_scalars = re.compile(r'st_([usf])(8|16|32)trace\(\"([^\"]+)\"') + rx_scalars = re.compile(r'st_([usf])(8|16|32|64)trace\(\"([^\"]+)\"') rx_arrays = re.compile(r'st_a([us])(8|16|32)trace\(\"([^\"]+)\"\,\s*[^,]+,\s*((?:0x)?[a-zA-Z0-9]+)') rx_strings = re.compile(r'st_strtrace\(\"([^\"]+)\"') signals = {} @@ -227,11 +227,13 @@ class Filter: 0x21 : "V1", 0x22 : "V2", 0x24 : "V4", + 0x28 : "V8", 0x31 : "A1", 0x32 : "A2", 0x34 : "A4", 0x44 : "S4", 0x54 : "F4", + 0x58 : "F8", 0x60 : "EV" } @@ -291,7 +293,6 @@ class Filter: return tag = self.TAGCODE_LUT[tagcode] - value = None offset = 1 match tag: @@ -301,11 +302,11 @@ class Filter: case "D2"|"V2"|"A2": value = decode_binstr(packet[offset:offset+2]) offset += 2 - case "D4"|"V4"|"A4"|"F4"|"S4": + case "D4"|"V4"|"V8"|"A4"|"F4"|"F8"|"S4": value = decode_binstr(packet[offset:offset+4]) offset += 4 sub = None - if tag[0] == 'A' or tag[0] == 'S': + if tag[0] == 'A' or tag[0] == 'S' or tag == 'V8' or tag == 'F8': sub = decode_binstr(packet[offset:offset+1]) offset += 1 @@ -315,7 +316,6 @@ class Filter: except Exception as ex: self.packets_dropped += 1 return - self.process_value(hashtag, value, sub, tag) self.packet_counter += 1 @@ -370,6 +370,7 @@ class VcdSink: def __init__(self, fs, signals, timescale='1 us'): self.writer = VCDWriter(fs, timescale=timescale, date=datetime.datetime.now().isoformat(), version=f"ST v1.0.2") self.skalars = {} + self.mw_skalars = {} self.arrays = {} self.strings = {} self.varnames = {} @@ -393,6 +394,12 @@ class VcdSink: case 'f32': dtype = 'real' dsize = 32 + case 'f64': + dtype = 'real' + dsize = 64 + case 'u64'|'s64': + dtype = 'integer' + dsize = 64 case 'u32'|'s32': dtype = 'integer' dsize = 32 @@ -416,6 +423,8 @@ class VcdSink: self.arrays[hvar] = vars elif dtype == 'string': self.strings[hvar] = [self.writer.register_var(hier, name, dtype, size=dsize), ""] + elif vtype in ['u64', 's64', 'f64']: + self.mw_skalars[hvar] = [self.writer.register_var(hier, name, dtype, size=dsize), 0] else: self.skalars[hvar] = self.writer.register_var(hier, name, dtype, size=dsize) @@ -472,6 +481,36 @@ class VcdSink: self.packets_dropped += 1 self.strings[tag][1] = "" self._emit(timestamp, tag, string, None) + elif datatag in ['V8', 'F8']: + timestamp = self.timestamp + commit = False + commit_value = 0 + if sub == 0: + self.mw_skalars[tag][1] = 0 + self.mw_skalars[tag][1] |= (value << (32 * sub)) + if sub == 1: + commit = True + if datatag == 'V8': + commit_value = self.mw_skalars[tag][1] + elif datatag == 'F8': + try: + commit_value = struct.unpack("