#include "app_owi_service.h" #include "owi.h" #include "delay.h" #include "r_cg_wdt.h" #include #define OWI_VERIFIED_MAX_LEN 129u #define OWI_VERIFIED_127_ATTEMPTS 6u #define OWI_VERIFIED_129_ATTEMPTS 8u #define OWI_VERIFIED_FIRST_US 30000u #define OWI_VERIFIED_RETRY_US 10000u static app_owi_result_t app_owi_from_raw(const owi_io_result_t *io) { app_owi_result_t r; uint16_t i; memset(&r, 0, sizeof(r)); if (!io) { r.ok = 0; return r; } r.ok = io->ok; r.timeout = io->timeout; r.read_len = io->read_len; r.timeout_byte_index = io->timeout_byte_index; r.timeout_bit_index = io->timeout_bit_index; for (i = 0; i < io->read_len && i < OWI_IO_MAX_BYTES; i++) { r.data[i] = io->data[i]; } return r; } static uint8_t s_verified_long[OWI_VERIFIED_MAX_LEN]; static uint8_t s_verified_long_len = 0u; static uint8_t is_long_owi_read(int length) { return (length == 119) ? 1u : 0u; } static app_owi_result_t app_owi_read_verified_long(uint8_t id, uint8_t length, uint8_t max_attempts) { static uint8_t samples[3][OWI_VERIFIED_MAX_LEN]; owi_io_result_t io; uint8_t sample_count = 0u; uint8_t attempt; uint8_t sample; uint8_t replace_index = 0u; memset(&io, 0, sizeof(io)); for (attempt = 0u; attempt < max_attempts; attempt++) { delay_us((attempt == 0u) ? OWI_VERIFIED_FIRST_US : OWI_VERIFIED_RETRY_US); R_WDT_Restart(); OWI_ReadBytesRaw((int)length, id, &io); R_WDT_Restart(); if (!io.ok || io.timeout || io.read_len < length || io.data[0] != 0x26u) { continue; } /* One fresh full read matching a previously verified value is enough. */ if (s_verified_long_len == length && memcmp(s_verified_long, io.data, length) == 0) { return app_owi_from_raw(&io); } for (sample = 0u; sample < sample_count; sample++) { if (memcmp(samples[sample], io.data, length) == 0) { memcpy(s_verified_long, io.data, length); s_verified_long_len = length; return app_owi_from_raw(&io); } } if (sample_count < 3u) { memcpy(samples[sample_count], io.data, length); sample_count++; } else { /* Keep recent distinct samples so a later stable pair can match. */ memcpy(samples[replace_index], io.data, length); replace_index++; if (replace_index >= 3u) { replace_index = 0u; } } } /* Do not return a possibly corrupted long sample. */ memset(&io, 0, sizeof(io)); io.ok = 0u; io.timeout = 1u; io.timeout_byte_index = 0xFFFEu; io.timeout_bit_index = 0xFEu; return app_owi_from_raw(&io); } static uint8_t looks_bad_tail(const owi_io_result_t *io) { uint16_t i; uint8_t zero_run = 0; uint8_t ff_run = 0; if (!io) return 1u; if (io->read_len < 24u) return 1u; for (i = (uint16_t)(io->read_len - 24u); i < io->read_len; i++) { uint8_t b = io->data[i]; if (b == 0x00u) zero_run++; else zero_run = 0; if (b == 0xFFu) ff_run++; else ff_run = 0; /* tail ?? 8??? ?? ?? 00/FF? ??? */ if (zero_run >= 8u || ff_run >= 8u) { return 1u; } } return 0u; } /* ? ? ?? 4???? ?? 00 ?? ?? FF? ????? ?? */ static uint8_t looks_bad_last_bytes(const owi_io_result_t *io) { uint16_t start; uint8_t i; uint8_t all_zero = 1u; uint8_t all_ff = 1u; if (!io) return 1u; if (io->read_len < 3u) return 1u; start = (uint16_t)(io->read_len - 3u); for (i = 0; i < 3u; i++) { uint8_t b = io->data[start + i]; if (b != 0x00u) all_zero = 0u; if (b != 0xFFu) all_ff = 0u; } return (uint8_t)(all_zero || all_ff); } static uint8_t needs_retry_for_long_read(const owi_io_result_t *io, int length) { if (!is_long_owi_read(length)) return 0u; if (!io) return 1u; if (!io->ok) return 1u; if (io->timeout) return 1u; if (io->read_len < (uint16_t)length) return 1u; if (looks_bad_tail(io)) return 1u; if (looks_bad_last_bytes(io)) return 1u; return 0u; } app_owi_result_t app_owi_read_basic(uint8_t id, int length) { owi_io_result_t io; if (length == 127) { return app_owi_read_verified_long(id, 127u, OWI_VERIFIED_127_ATTEMPTS); } if (length == 129) { return app_owi_read_verified_long(id, 129u, OWI_VERIFIED_129_ATTEMPTS); } R_WDT_Restart(); OWI_ReadBytesRaw(length, id, &io); R_WDT_Restart(); if (needs_retry_for_long_read(&io, length)) { R_WDT_Restart(); delay_us(3000u); R_WDT_Restart(); OWI_ReadBytesRaw(length, id, &io); R_WDT_Restart(); /* ??? ??? ???? ?? ?? */ if (needs_retry_for_long_read(&io, length)) { io.ok = 0u; io.timeout = 1u; io.timeout_byte_index = 0xFFFEu; io.timeout_bit_index = 0xFEu; } } return app_owi_from_raw(&io); } app_owi_result_t app_owi_write_basic(uint8_t id, const uint8_t *tx_data, uint8_t tx_len) { owi_io_result_t io; OWI_CommandModeRaw(tx_data, tx_len, id, &io); return app_owi_from_raw(&io); } app_owi_result_t app_owi_write_t_basic(uint8_t id, const uint8_t *tx_data, uint8_t tx_len) { owi_io_result_t io; OWI_T_CommandModeRaw(tx_data, tx_len, id, &io); return app_owi_from_raw(&io); }