evt3.c
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | |||
| 2 | #include "evutils/evt3.h" | ||
| 3 | #include "evutils/types.h" | ||
| 4 | #include "evutils/parser.h" | ||
| 5 | |||
| 6 | #include <stdio.h> | ||
| 7 | #include <stdint.h> | ||
| 8 | |||
| 9 | #define EVT3_get_packet_type(packet) (((packet) >> 12) & 0xF) | ||
| 10 | #define EVT3_get_packet_data(packet) ((packet) & 0x0FFF) | ||
| 11 | |||
| 12 | enum EVT3_PacketType { | ||
| 13 | EVT3_EVT_ADDR_Y = 0x0, | ||
| 14 | EVT3_EVT_ADDR_X = 0x2, | ||
| 15 | EVT3_VECT_BASE_X = 0x3, | ||
| 16 | EVT3_VECT_12 = 0x4, | ||
| 17 | EVT3_VECT_8 = 0x5, | ||
| 18 | EVT3_EVT_TIME_LOW = 0x6, | ||
| 19 | EVT3_CONTINUED_4 = 0x7, | ||
| 20 | EVT3_EVT_TIME_HIGH = 0x8, | ||
| 21 | EVT3_EXT_TRIGGER = 0xA, | ||
| 22 | EVT3_OTHERS = 0xE, | ||
| 23 | EVT3_CONTINUED_12 = 0xF | ||
| 24 | }; | ||
| 25 | |||
| 26 | |||
| 27 | typedef struct evt3_state_s { | ||
| 28 | uint64_t ts_high_high; | ||
| 29 | uint64_t ts_high; | ||
| 30 | uint64_t ts_low; | ||
| 31 | uint64_t ts; | ||
| 32 | |||
| 33 | uint16_t y; | ||
| 34 | uint16_t vecbase_x; | ||
| 35 | uint8_t vecbase_p; | ||
| 36 | } evt3_state_t; | ||
| 37 | |||
| 38 | |||
| 39 | |||
| 40 | 189 | size_t EVT3_state_size(void) { | |
| 41 | 189 | return sizeof(evt3_state_t); | |
| 42 | } | ||
| 43 | |||
| 44 | |||
| 45 | #define EMIT_SOA() do { \ | ||
| 46 | unsigned has = (vec_valid != 0u); \ | ||
| 47 | uint32_t lz = (uint32_t)__builtin_ctz(vec_valid | 0x80000000u); \ | ||
| 48 | out_ts[n] = ts; \ | ||
| 49 | out_x[n] = (uint16_t)(bx + lz); \ | ||
| 50 | out_y[n] = y; \ | ||
| 51 | out_p[n] = p; \ | ||
| 52 | n += has; \ | ||
| 53 | vec_valid &= vec_valid - 1u; \ | ||
| 54 | } while (0) | ||
| 55 | |||
| 56 | |||
| 57 | // EVUTILS_UNALIGNED typedefs are provided in compat.h | ||
| 58 | |||
| 59 | __attribute__((always_inline)) | ||
| 60 | static inline const unaligned_uint16_t * EVT3_parse_vector_12_12_8_soa( | ||
| 61 | const unaligned_uint16_t * __restrict__ current, | ||
| 62 | evt3_state_t * __restrict__ state, | ||
| 63 | timestamp_t* __restrict__ out_ts, uint16_t* __restrict__ out_x, | ||
| 64 | uint16_t* __restrict__ out_y, uint8_t* __restrict__ out_p, | ||
| 65 | size_t * n_events) { | ||
| 66 | |||
| 67 | 46093684 | uint32_t vec_valid = EVT3_get_packet_data(*current); | |
| 68 | 46093684 | current++; | |
| 69 | |||
| 70 |
3/8✓ Branch 0 taken 45615413 times.
✓ Branch 1 taken 186 times.
✓ Branch 2 taken 470516 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
46086115 | if(likely(EVT3_get_packet_type(*current) == EVT3_VECT_12)) { |
| 71 | 46090996 | vec_valid |= (uint32_t)(EVT3_get_packet_data(*current) << 12); | |
| 72 | 46090996 | current++; | |
| 73 | |||
| 74 |
6/16✓ Branch 0 taken 45615396 times.
✓ Branch 1 taken 17 times.
✓ Branch 2 taken 4875 times.
✓ Branch 3 taken 153 times.
✓ Branch 4 taken 470516 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 39 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
|
46090996 | if (likely(EVT3_get_packet_type(*current) == EVT3_VECT_8)) { |
| 75 | 46090826 | vec_valid |= (uint32_t)(*current & 0x00FF) << 24; | |
| 76 | 46090826 | current++; | |
| 77 | } | ||
| 78 | } | ||
| 79 | 46093684 | const timestamp_t ts = state->ts; | |
| 80 | 46093684 | const uint16_t y = state->y; | |
| 81 | 46093684 | const uint8_t p = state->vecbase_p; | |
| 82 | 46093684 | const uint16_t bx = state->vecbase_x; | |
| 83 | 46093684 | size_t n = *n_events; | |
| 84 | |||
| 85 | 46093684 | EMIT_SOA(); EMIT_SOA(); EMIT_SOA(); EMIT_SOA(); /* 4 unconditional — no branch between them */ | |
| 86 | |||
| 87 |
8/16✓ Branch 0 taken 241506969 times.
✓ Branch 1 taken 45615599 times.
✓ Branch 2 taken 122951 times.
✓ Branch 3 taken 7530 times.
✓ Branch 4 taken 6565364 times.
✓ Branch 5 taken 470516 times.
✓ Branch 6 taken 995 times.
✓ Branch 7 taken 39 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
|
294289963 | while (vec_valid) { EMIT_SOA(); } /* tail: only pop>4 (~23%) re-enters */ |
| 88 | |||
| 89 | 46093684 | *n_events = n; | |
| 90 | 46093684 | state->vecbase_x = bx + 32; | |
| 91 | |||
| 92 | 46093684 | return current; | |
| 93 | } | ||
| 94 | |||
| 95 | |||
| 96 | |||
| 97 | // TODO: For future performance optimization, implement dynamic CPU dispatch | ||
| 98 | // (e.g., using __attribute__((target_clones("avx2", "default"))) on GCC/Clang) | ||
| 99 | // or manual cpuid + function pointers to enable SIMD decoding on supported | ||
| 100 | // hardware without breaking universal portability on older CPUs. | ||
| 101 | |||
| 102 | |||
| 103 | #define EVT3_INPUT_PADDING 4 | ||
| 104 | EVUTILS_TARGET_CLONES | ||
| 105 | 4522 | parser_result_t EVT3_parse_chunk_soa( | |
| 106 | evt3_state_t *state, | ||
| 107 | const evt3_input_buffer_t *input_buffer, | ||
| 108 | event_buffer_soa_t *event_buffer, | ||
| 109 | trigger_buffer_soa_t *trigger_buffer) { | ||
| 110 | |||
| 111 | // Hoist variables for better optimization | ||
| 112 | 4522 | const unaligned_uint16_t *restrict current = (const unaligned_uint16_t *)input_buffer->begin; | |
| 113 | 4522 | const unaligned_uint16_t * end_offset = (const unaligned_uint16_t *)(input_buffer->end - EVT3_INPUT_PADDING); | |
| 114 | |||
| 115 | // Event output buffers | ||
| 116 | 4522 | const size_t events_capacity = event_buffer->capacity; | |
| 117 | // Keep space for one full vector group; guard the size_t subtraction | ||
| 118 | // against tiny buffers (capacity <= 64 would wrap to a huge offset). | ||
| 119 | 4522 | const size_t events_capacity_offset = events_capacity > 64 ? events_capacity - 64 : 0; | |
| 120 | 4522 | size_t n_events_read = event_buffer->size; | |
| 121 | |||
| 122 | 4522 | timestamp_t* restrict out_ts = event_buffer->t; | |
| 123 | 4522 | uint16_t* restrict out_x = event_buffer->x; | |
| 124 | 4522 | uint16_t* restrict out_y = event_buffer->y; | |
| 125 | 4522 | uint8_t* restrict out_p = event_buffer->p; | |
| 126 | |||
| 127 | // Trigger output buffers | ||
| 128 | 4522 | const size_t triggers_capacity = trigger_buffer->capacity; | |
| 129 | 4522 | size_t n_triggers_read = trigger_buffer->size; | |
| 130 | |||
| 131 | 4522 | timestamp_t* restrict trigger_ts = trigger_buffer->t; | |
| 132 | 4522 | uint8_t* restrict trigger_id = trigger_buffer->id; | |
| 133 | 4522 | uint8_t* restrict trigger_p = trigger_buffer->p; | |
| 134 | |||
| 135 | // State variables | ||
| 136 | 4522 | evt3_state_t local_state = *state; | |
| 137 | |||
| 138 | 4522 | parse_status_t status = EVUTILS_PARSE_OK; | |
| 139 | |||
| 140 | |||
| 141 | // Main parsing looop | ||
| 142 | 4522 | while( | |
| 143 | 477226428 | current < end_offset && | |
| 144 |
5/12EVT3_parse_chunk_soa.avx2:
✓ Branch 0 taken 852 times.
✓ Branch 1 taken 477226428 times.
✓ Branch 2 taken 624 times.
✓ Branch 3 taken 477225804 times.
✓ Branch 4 taken 477225804 times.
✗ Branch 5 not taken.
EVT3_parse_chunk_soa.default:
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
477227280 | n_events_read < events_capacity_offset && |
| 145 | n_triggers_read < triggers_capacity) { | ||
| 146 | |||
| 147 | 477225804 | uint32_t packet_type = EVT3_get_packet_type(*current); | |
| 148 | 477225804 | uint32_t packet_data = EVT3_get_packet_data(*current); | |
| 149 | |||
| 150 | // Most common case checks first | ||
| 151 |
2/4EVT3_parse_chunk_soa.avx2:
✓ Branch 0 taken 258976216 times.
✓ Branch 1 taken 218249588 times.
EVT3_parse_chunk_soa.default:
✗ Branch 0 not taken.
✗ Branch 1 not taken.
|
477225804 | if(packet_type == EVT3_EVT_ADDR_X) { |
| 152 | 258976216 | out_ts[n_events_read] = local_state.ts; | |
| 153 | 258976216 | out_y[n_events_read] = local_state.y; | |
| 154 | 258976216 | out_x[n_events_read] = (packet_data & 0x7FF); | |
| 155 | 258976216 | out_p[n_events_read] = (packet_data & 0x800) >> 11; | |
| 156 | 258976216 | n_events_read++; | |
| 157 | 258976216 | current++; | |
| 158 | 258976216 | continue; | |
| 159 | } | ||
| 160 |
2/4EVT3_parse_chunk_soa.avx2:
✓ Branch 0 taken 30186390 times.
✓ Branch 1 taken 188063198 times.
EVT3_parse_chunk_soa.default:
✗ Branch 0 not taken.
✗ Branch 1 not taken.
|
218249588 | if(packet_type == EVT3_VECT_BASE_X) { |
| 161 | // Implementation omitted for brevity | ||
| 162 | 30186390 | local_state.vecbase_x = packet_data & 0x7FF; | |
| 163 | 30186390 | local_state.vecbase_p = (packet_data & 0x800) >> 11; | |
| 164 | |||
| 165 | 30186390 | current++; | |
| 166 | |||
| 167 | // Parse vector messages | ||
| 168 |
5/12EVT3_parse_chunk_soa.avx2:
✓ Branch 0 taken 45615873 times.
✓ Branch 1 taken 30186116 times.
✓ Branch 2 taken 45615873 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 45615599 times.
✓ Branch 5 taken 274 times.
EVT3_parse_chunk_soa.default:
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
75801989 | while (EVT3_get_packet_type(*current) == EVT3_VECT_12 && current < end_offset && n_events_read < events_capacity_offset) { |
| 169 | 45615599 | current = EVT3_parse_vector_12_12_8_soa(current, &local_state, out_ts, out_x, out_y, out_p, &n_events_read); | |
| 170 | } | ||
| 171 | |||
| 172 | 30186390 | continue; | |
| 173 | } | ||
| 174 | |||
| 175 |
7/14EVT3_parse_chunk_soa.avx2:
✓ Branch 0 taken 143037219 times.
✓ Branch 1 taken 6291614 times.
✓ Branch 2 taken 36778761 times.
✓ Branch 3 taken 3422 times.
✓ Branch 4 taken 7530 times.
✓ Branch 5 taken 3046 times.
✓ Branch 6 taken 1941606 times.
EVT3_parse_chunk_soa.default:
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
|
188063198 | switch(packet_type) { |
| 176 | 143037219 | case EVT3_EVT_ADDR_Y: | |
| 177 | 143037219 | local_state.y = packet_data & 0x7FF; | |
| 178 | 143037219 | break; | |
| 179 | 6291614 | case EVT3_EVT_TIME_HIGH: | |
| 180 | { | ||
| 181 | 6291614 | uint32_t new_ts_high = packet_data << 12; | |
| 182 | |||
| 183 |
2/4EVT3_parse_chunk_soa.avx2:
✓ Branch 0 taken 2304 times.
✓ Branch 1 taken 6289310 times.
EVT3_parse_chunk_soa.default:
✗ Branch 0 not taken.
✗ Branch 1 not taken.
|
6291614 | if(unlikely(new_ts_high < local_state.ts_high)) { |
| 184 | 2304 | local_state.ts_high_high += 0x1000000; | |
| 185 | } | ||
| 186 | 6291614 | local_state.ts_high = new_ts_high; | |
| 187 | |||
| 188 | 6291614 | current++; | |
| 189 | 6291614 | packet_type = EVT3_get_packet_type(*current); | |
| 190 | |||
| 191 |
2/4EVT3_parse_chunk_soa.avx2:
✓ Branch 0 taken 1872369 times.
✓ Branch 1 taken 4419245 times.
EVT3_parse_chunk_soa.default:
✗ Branch 0 not taken.
✗ Branch 1 not taken.
|
6291614 | if(unlikely(packet_type != EVT3_EVT_TIME_LOW)) { |
| 192 | 1872369 | continue; | |
| 193 | } | ||
| 194 | 4419245 | packet_data = EVT3_get_packet_data(*current); | |
| 195 | } | ||
| 196 | __attribute__((fallthrough)); | ||
| 197 | 41198006 | case EVT3_EVT_TIME_LOW: | |
| 198 | 41198006 | local_state.ts_low = packet_data; | |
| 199 | 41198006 | local_state.ts = local_state.ts_high_high | local_state.ts_high | local_state.ts_low; | |
| 200 | 41198006 | break; | |
| 201 | 3422 | case EVT3_EXT_TRIGGER: | |
| 202 | 3422 | trigger_ts[n_triggers_read] = local_state.ts; | |
| 203 | 3422 | trigger_id[n_triggers_read] = packet_data >> 8; | |
| 204 | 3422 | trigger_p[n_triggers_read] = packet_data & 0x1; | |
| 205 | 3422 | n_triggers_read++; | |
| 206 | 3422 | break; | |
| 207 |
2/4EVT3_parse_chunk_soa.avx2:
✓ Branch 0 taken 5028 times.
✓ Branch 1 taken 2502 times.
EVT3_parse_chunk_soa.default:
✗ Branch 0 not taken.
✗ Branch 1 not taken.
|
7530 | case EVT3_VECT_12: |
| 208 | 7530 | current = EVT3_parse_vector_12_12_8_soa(current, &local_state, out_ts, out_x, out_y, out_p, &n_events_read); | |
| 209 | 7530 | continue; | |
| 210 | break; | ||
| 211 | 3046 | case EVT3_VECT_8: | |
| 212 | case EVT3_EVT_ADDR_X: | ||
| 213 | case EVT3_VECT_BASE_X: | ||
| 214 | // Unexpected packet in this position (corrupt/out-of-order | ||
| 215 | // stream): skip the offending word and stop so the caller can | ||
| 216 | // warn and resume. strict mode turns the warning into an error. | ||
| 217 | 3046 | status = EVUTILS_PARSE_WARNING; | |
| 218 | 3046 | current++; | |
| 219 | 3046 | goto parse_end; | |
| 220 | 1941606 | case EVT3_OTHERS: | |
| 221 | case EVT3_CONTINUED_12: | ||
| 222 | case EVT3_CONTINUED_4: | ||
| 223 | default: | ||
| 224 | 1941606 | break; | |
| 225 | } | ||
| 226 | 186180253 | current++; | |
| 227 | } | ||
| 228 | 1476 | parse_end: | |
| 229 | 4522 | *state = local_state; | |
| 230 | |||
| 231 | 4522 | event_buffer->size = n_events_read; | |
| 232 | 4522 | trigger_buffer->size = n_triggers_read; | |
| 233 | |||
| 234 | /* Report why parsing stopped: output space exhausted vs input drained. */ | ||
| 235 |
2/4EVT3_parse_chunk_soa.avx2:
✓ Branch 0 taken 1476 times.
✓ Branch 1 taken 3046 times.
EVT3_parse_chunk_soa.default:
✗ Branch 0 not taken.
✗ Branch 1 not taken.
|
4522 | if (status != EVUTILS_PARSE_WARNING) { |
| 236 |
3/8EVT3_parse_chunk_soa.avx2:
✓ Branch 0 taken 852 times.
✓ Branch 1 taken 624 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 852 times.
EVT3_parse_chunk_soa.default:
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
1476 | if (n_events_read >= events_capacity_offset || n_triggers_read >= triggers_capacity) { |
| 237 | 624 | status = EVUTILS_PARSE_OUTPUT_FULL; | |
| 238 | } | ||
| 239 | } | ||
| 240 | |||
| 241 | 4522 | return (parser_result_t){ | |
| 242 | .current = (const void *)current, | ||
| 243 | .status = status | ||
| 244 | }; | ||
| 245 | } | ||
| 246 | |||
| 247 | |||
| 248 | /* delta_t variant: a specialised copy of EVT3_parse_chunk_soa that stops as soon | ||
| 249 | * as the running timestamp reaches end_ts, so one call decodes exactly one time | ||
| 250 | * window (events with ts < end_ts) with no Python-side boundary search or | ||
| 251 | * overshoot carry. The n_events parser above is left untouched (and branch-free) | ||
| 252 | * -- only the top-of-loop timestamp guard and the shared vector sub-parser | ||
| 253 | * differ. Emits EVUTILS_PARSE_WINDOW_DONE when the window boundary is reached. | ||
| 254 | * | ||
| 255 | * The guard sits at the top of the loop because in EVT3 the timestamp only | ||
| 256 | * changes at TIME_LOW / TIME_HIGH words; every event (ADDR_X, VECT_*) copies the | ||
| 257 | * current local_state.ts, so once ts >= end_ts no further event can belong to | ||
| 258 | * this window. State is persisted, so the next call resumes at the exact word | ||
| 259 | * with the correct timestamp. */ | ||
| 260 | EVUTILS_TARGET_CLONES | ||
| 261 | 220 | parser_result_t EVT3_parse_delta_t_soa( | |
| 262 | evt3_state_t *state, | ||
| 263 | const evt3_input_buffer_t *input_buffer, | ||
| 264 | event_buffer_soa_t *event_buffer, | ||
| 265 | trigger_buffer_soa_t *trigger_buffer, | ||
| 266 | timestamp_t end_ts) { | ||
| 267 | |||
| 268 | 220 | parse_status_t status = EVUTILS_PARSE_OK; | |
| 269 | 220 | const unaligned_uint16_t *restrict current = (const unaligned_uint16_t *)input_buffer->begin; | |
| 270 | 220 | const unaligned_uint16_t * end_offset = (const unaligned_uint16_t *)(input_buffer->end - EVT3_INPUT_PADDING); | |
| 271 | |||
| 272 | 220 | const size_t events_capacity = event_buffer->capacity; | |
| 273 | 220 | const size_t events_capacity_offset = events_capacity > 64 ? events_capacity - 64 : 0; | |
| 274 | 220 | size_t n_events_read = event_buffer->size; | |
| 275 | |||
| 276 | 220 | timestamp_t* restrict out_ts = event_buffer->t; | |
| 277 | 220 | uint16_t* restrict out_x = event_buffer->x; | |
| 278 | 220 | uint16_t* restrict out_y = event_buffer->y; | |
| 279 | 220 | uint8_t* restrict out_p = event_buffer->p; | |
| 280 | |||
| 281 | 220 | const size_t triggers_capacity = trigger_buffer->capacity; | |
| 282 | 220 | size_t n_triggers_read = trigger_buffer->size; | |
| 283 | |||
| 284 | 220 | timestamp_t* restrict trigger_ts = trigger_buffer->t; | |
| 285 | 220 | uint8_t* restrict trigger_id = trigger_buffer->id; | |
| 286 | 220 | uint8_t* restrict trigger_p = trigger_buffer->p; | |
| 287 | |||
| 288 | 220 | evt3_state_t local_state = *state; | |
| 289 | |||
| 290 | 220 | while( | |
| 291 | 1506341 | current < end_offset && | |
| 292 | 1506362 | n_events_read < events_capacity_offset && | |
| 293 | n_triggers_read < triggers_capacity) { | ||
| 294 | |||
| 295 | /* Time boundary reached: every remaining event would land in the next | ||
| 296 | * window. Stop here; state (incl. ts) is saved for the next call. */ | ||
| 297 | 1506332 | if (local_state.ts >= end_ts) { | |
| 298 | 190 | break; | |
| 299 | } | ||
| 300 | |||
| 301 | 1506142 | __builtin_prefetch(current + 64, 0, 0); | |
| 302 | 1506142 | uint32_t packet_type = EVT3_get_packet_type(*current); | |
| 303 | 1506142 | uint32_t packet_data = EVT3_get_packet_data(*current); | |
| 304 | |||
| 305 | 1506142 | if(packet_type == EVT3_EVT_ADDR_X) { | |
| 306 | 853326 | out_ts[n_events_read] = local_state.ts; | |
| 307 | 853326 | out_y[n_events_read] = local_state.y; | |
| 308 | 853326 | out_x[n_events_read] = (packet_data & 0x7FF); | |
| 309 | 853326 | out_p[n_events_read] = (packet_data & 0x800) >> 11; | |
| 310 | 853326 | n_events_read++; | |
| 311 | 853326 | current++; | |
| 312 | 853326 | continue; | |
| 313 | } | ||
| 314 | 652816 | if(packet_type == EVT3_VECT_BASE_X) { | |
| 315 | 147673 | local_state.vecbase_x = packet_data & 0x7FF; | |
| 316 | 147673 | local_state.vecbase_p = (packet_data & 0x800) >> 11; | |
| 317 | 147673 | current++; | |
| 318 | 618189 | while (EVT3_get_packet_type(*current) == EVT3_VECT_12 && current < end_offset && n_events_read < events_capacity_offset) { | |
| 319 | 470516 | current = EVT3_parse_vector_12_12_8_soa(current, &local_state, out_ts, out_x, out_y, out_p, &n_events_read); | |
| 320 | } | ||
| 321 | 147673 | continue; | |
| 322 | } | ||
| 323 | |||
| 324 | 505143 | switch(packet_type) { | |
| 325 | 356639 | case EVT3_EVT_ADDR_Y: | |
| 326 | 356639 | local_state.y = packet_data & 0x7FF; | |
| 327 | 356639 | break; | |
| 328 | 7202 | case EVT3_EVT_TIME_HIGH: | |
| 329 | { | ||
| 330 | 7202 | uint32_t new_ts_high = packet_data << 12; | |
| 331 | 7202 | if(unlikely(new_ts_high < local_state.ts_high)) { | |
| 332 | ✗ | local_state.ts_high_high += 0x1000000; | |
| 333 | } | ||
| 334 | 7202 | local_state.ts_high = new_ts_high; | |
| 335 | 7202 | current++; | |
| 336 | 7202 | packet_type = EVT3_get_packet_type(*current); | |
| 337 | 7202 | if(unlikely(packet_type != EVT3_EVT_TIME_LOW)) { | |
| 338 | 809 | continue; | |
| 339 | } | ||
| 340 | 6393 | packet_data = EVT3_get_packet_data(*current); | |
| 341 | } | ||
| 342 | __attribute__((fallthrough)); | ||
| 343 | 145703 | case EVT3_EVT_TIME_LOW: | |
| 344 | 145703 | local_state.ts_low = packet_data; | |
| 345 | 145703 | local_state.ts = local_state.ts_high_high | local_state.ts_high | local_state.ts_low; | |
| 346 | 145703 | break; | |
| 347 | ✗ | case EVT3_EXT_TRIGGER: | |
| 348 | ✗ | trigger_ts[n_triggers_read] = local_state.ts; | |
| 349 | ✗ | trigger_id[n_triggers_read] = packet_data >> 8; | |
| 350 | ✗ | trigger_p[n_triggers_read] = packet_data & 0x1; | |
| 351 | ✗ | n_triggers_read++; | |
| 352 | ✗ | break; | |
| 353 | 39 | case EVT3_VECT_12: | |
| 354 | 39 | current = EVT3_parse_vector_12_12_8_soa(current, &local_state, out_ts, out_x, out_y, out_p, &n_events_read); | |
| 355 | 39 | continue; | |
| 356 | break; | ||
| 357 | ✗ | case EVT3_VECT_8: | |
| 358 | case EVT3_EVT_ADDR_X: | ||
| 359 | case EVT3_VECT_BASE_X: | ||
| 360 | // Unexpected packet in this position (corrupt/out-of-order | ||
| 361 | // stream): skip the offending word and stop so the caller can | ||
| 362 | // warn and resume. strict mode turns the warning into an error. | ||
| 363 | ✗ | status = EVUTILS_PARSE_WARNING; | |
| 364 | ✗ | current++; | |
| 365 | ✗ | goto parse_end_delta; | |
| 366 | 1953 | case EVT3_OTHERS: | |
| 367 | case EVT3_CONTINUED_12: | ||
| 368 | case EVT3_CONTINUED_4: | ||
| 369 | default: | ||
| 370 | 1953 | break; | |
| 371 | } | ||
| 372 | 504295 | current++; | |
| 373 | } | ||
| 374 | |||
| 375 | 30 | parse_end_delta: | |
| 376 | 220 | *state = local_state; | |
| 377 | 220 | event_buffer->size = n_events_read; | |
| 378 | 220 | trigger_buffer->size = n_triggers_read; | |
| 379 | |||
| 380 | 220 | if (status != EVUTILS_PARSE_WARNING) { | |
| 381 | 220 | if (local_state.ts >= end_ts) { | |
| 382 | 190 | status = EVUTILS_PARSE_WINDOW_DONE; | |
| 383 | 30 | } else if (n_events_read >= events_capacity_offset || n_triggers_read >= triggers_capacity) { | |
| 384 | 9 | status = EVUTILS_PARSE_OUTPUT_FULL; | |
| 385 | } else { | ||
| 386 | 21 | status = EVUTILS_PARSE_OK; /* input drained for this call */ | |
| 387 | } | ||
| 388 | } | ||
| 389 | |||
| 390 | 220 | return (parser_result_t){ | |
| 391 | .current = (const void *)current, | ||
| 392 | .status = status | ||
| 393 | }; | ||
| 394 | } | ||
| 395 | |||
| 396 |