You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

222 lines
5.7 KiB

#include "app_owi_service.h"
#include "owi.h"
#include "delay.h"
#include "r_cg_wdt.h"
#include <string.h>
#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);
}