Compare commits
21 Commits
master
...
developmen
| Author | SHA1 | Date |
|---|---|---|
|
|
a53a56d24a | 6 days ago |
|
|
41fc1e371f | 6 days ago |
|
|
73c54695a7 | 2 months ago |
|
|
baeb8c71a5 | 3 months ago |
|
|
dd771262ee | 3 months ago |
|
|
d83cbec862 | 4 months ago |
|
|
f99d2cd6c7 | 4 months ago |
|
|
f5dfae3549 | 4 months ago |
|
|
a2f046d7ab | 4 months ago |
|
|
befdc9c6bf | 4 months ago |
|
|
3800ba2a4a | 5 months ago |
|
|
592e0faa24 | 5 months ago |
|
|
bc6bd16e70 | 5 months ago |
|
|
06263ffdd9 | 5 months ago |
|
|
601c3256ed | 5 months ago |
|
|
37d1564bb6 | 5 months ago |
|
|
294d8e2eac | 5 months ago |
|
|
2dcaa0c406 | 5 months ago |
|
|
c0dd680c5f | 5 months ago |
|
|
304e882ce8 | 5 months ago |
|
|
d5a978ba62 | 5 months ago |
64 changed files with 14172 additions and 2572 deletions
@ -0,0 +1,596 @@ |
|||||
|
#include "owi.h" |
||||
|
/*
|
||||
|
* Test 1: bit-period-only variant. |
||||
|
* This local override keeps the replacement self-contained in owi.c. |
||||
|
* TBIT and all timing macros in owi.h expand from this value at use time. |
||||
|
*/ |
||||
|
#undef OWI_BIT_PERIOD_US |
||||
|
#define OWI_BIT_PERIOD_US 2000u |
||||
|
|
||||
|
#include "delay.h" |
||||
|
#include "r_cg_wdt.h" |
||||
|
#include <string.h> |
||||
|
#include <stdio.h> |
||||
|
#include "uart.h" |
||||
|
#include "r_cg_wdt.h" |
||||
|
|
||||
|
#ifndef OWI_STRONG_DRIVE_HIGH_US |
||||
|
#define OWI_STRONG_DRIVE_HIGH_US 5u |
||||
|
#endif |
||||
|
|
||||
|
/* 내부 상태 */ |
||||
|
static uint32_t bit_period_us = OWI_BIT_PERIOD_US; |
||||
|
static uint8_t g_owi_timeout_latched = 0; |
||||
|
|
||||
|
static uint16_t g_owi_last_timeout_byte_index = 0xFFFFu; |
||||
|
static uint8_t g_owi_last_timeout_bit_index = 0xFFu; |
||||
|
|
||||
|
static uint16_t g_owi_current_read_byte_index = 0u; |
||||
|
static uint8_t g_owi_current_read_bit_index = 0u; |
||||
|
|
||||
|
/* =========================================================
|
||||
|
* GPIO helpers (P70 / HW Open-Drain) |
||||
|
* - LOW : 출력 모드 + 0 |
||||
|
* - HIGH : 입력(Hi-Z)로 release |
||||
|
* ========================================================= */ |
||||
|
void GPIO_Clear(void) |
||||
|
{ |
||||
|
OWI_PORT_POM |= (uint8_t)OWI_PIN_MASK; |
||||
|
OWI_PORT_P &= (uint8_t)~OWI_PIN_MASK; |
||||
|
OWI_PORT_PM &= (uint8_t)~OWI_PIN_MASK; |
||||
|
} |
||||
|
|
||||
|
void GPIO_Input(void) |
||||
|
{ |
||||
|
OWI_PORT_POM |= (uint8_t)OWI_PIN_MASK; |
||||
|
OWI_PORT_P |= (uint8_t)OWI_PIN_MASK; |
||||
|
OWI_PORT_PM |= (uint8_t)OWI_PIN_MASK; |
||||
|
} |
||||
|
|
||||
|
int GPIO_Read(void) |
||||
|
{ |
||||
|
return (OWI_PORT_P & (uint8_t)OWI_PIN_MASK) ? 1 : 0; |
||||
|
} |
||||
|
|
||||
|
static void OWI_Release(void) |
||||
|
{ |
||||
|
OWI_PORT_POM |= (uint8_t)OWI_PIN_MASK; |
||||
|
OWI_PORT_P |= (uint8_t)OWI_PIN_MASK; |
||||
|
OWI_PORT_PM |= (uint8_t)OWI_PIN_MASK; |
||||
|
} |
||||
|
|
||||
|
static void GPIO_StrongDriveHighKick(uint32_t kick_us) |
||||
|
{ |
||||
|
OWI_Release(); |
||||
|
|
||||
|
if (!GPIO_Read()) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
OWI_PORT_POM &= (uint8_t)~OWI_PIN_MASK; |
||||
|
OWI_PORT_P |= (uint8_t)OWI_PIN_MASK; |
||||
|
OWI_PORT_PM &= (uint8_t)~OWI_PIN_MASK; |
||||
|
|
||||
|
delay_us(kick_us); |
||||
|
|
||||
|
OWI_PORT_POM |= (uint8_t)OWI_PIN_MASK; |
||||
|
OWI_Release(); |
||||
|
} |
||||
|
|
||||
|
void GPIO_ForceHighKick(void) |
||||
|
{ |
||||
|
GPIO_StrongDriveHighKick(OWI_STRONG_DRIVE_HIGH_US); |
||||
|
} |
||||
|
|
||||
|
static void OWI_DriveLow(void) |
||||
|
{ |
||||
|
OWI_PORT_POM |= (uint8_t)OWI_PIN_MASK; |
||||
|
OWI_PORT_P &= (uint8_t)~OWI_PIN_MASK; |
||||
|
OWI_PORT_PM &= (uint8_t)~OWI_PIN_MASK; |
||||
|
} |
||||
|
|
||||
|
/* =========================================================
|
||||
|
* Diagnostics |
||||
|
* ========================================================= */ |
||||
|
uint8_t OWI_HasTimeout(void) |
||||
|
{ |
||||
|
return g_owi_timeout_latched; |
||||
|
} |
||||
|
|
||||
|
void OWI_ClearTimeout(void) |
||||
|
{ |
||||
|
g_owi_timeout_latched = 0; |
||||
|
g_owi_last_timeout_byte_index = 0xFFFFu; |
||||
|
g_owi_last_timeout_bit_index = 0xFFu; |
||||
|
} |
||||
|
|
||||
|
uint16_t OWI_GetLastTimeoutByteIndex(void) |
||||
|
{ |
||||
|
return g_owi_last_timeout_byte_index; |
||||
|
} |
||||
|
|
||||
|
uint8_t OWI_GetLastTimeoutBitIndex(void) |
||||
|
{ |
||||
|
return g_owi_last_timeout_bit_index; |
||||
|
} |
||||
|
|
||||
|
/* =========================================================
|
||||
|
* OWI Init |
||||
|
* ========================================================= */ |
||||
|
void OWI_Init(uint32_t bit_time_us) |
||||
|
{ |
||||
|
bit_period_us = bit_time_us; |
||||
|
(void)bit_period_us; |
||||
|
|
||||
|
OWI_PORT_POM |= (uint8_t)OWI_PIN_MASK; |
||||
|
OWI_PORT_PU &= (uint8_t)~OWI_PIN_MASK; |
||||
|
|
||||
|
OWI_ClearTimeout(); |
||||
|
GPIO_Input(); |
||||
|
} |
||||
|
|
||||
|
/* =========================================================
|
||||
|
* Start/Stop/Secure |
||||
|
* ========================================================= */ |
||||
|
void OWI_Start(void) |
||||
|
{ |
||||
|
GPIO_Clear(); |
||||
|
delay_us(TSTART_HOLD); |
||||
|
|
||||
|
GPIO_Input(); |
||||
|
delay_us(TBIT); |
||||
|
} |
||||
|
|
||||
|
void OWI_Stop(void) |
||||
|
{ |
||||
|
GPIO_Input(); |
||||
|
delay_us(TSTOP_LOW); |
||||
|
delay_us(TIDLE); |
||||
|
} |
||||
|
|
||||
|
static void OWI_StopWrite(void) |
||||
|
{ |
||||
|
OWI_Release(); |
||||
|
delay_us(TSTOP_LOW); |
||||
|
delay_us(TIDLE); |
||||
|
} |
||||
|
|
||||
|
static void OWI_StopRead(void) |
||||
|
{ |
||||
|
OWI_DriveLow(); |
||||
|
delay_us(TSTOP_LOW); |
||||
|
OWI_Release(); |
||||
|
delay_us(TIDLE); |
||||
|
} |
||||
|
|
||||
|
static uint8_t OWI_WaitFirstBitStart(void) |
||||
|
{ |
||||
|
int timeout; |
||||
|
|
||||
|
timeout = (int)(bit_period_us * 4u); |
||||
|
|
||||
|
/* 첫 번째 HIGH->LOW 시작을 기다림 */ |
||||
|
while (GPIO_Read() && timeout-- > 0) { |
||||
|
delay_us(1u); |
||||
|
} |
||||
|
|
||||
|
if (timeout <= 0) { |
||||
|
if (!g_owi_timeout_latched) { |
||||
|
g_owi_timeout_latched = 1; |
||||
|
g_owi_last_timeout_byte_index = 0u; |
||||
|
g_owi_last_timeout_bit_index = 0u; |
||||
|
} |
||||
|
return 0u; |
||||
|
} |
||||
|
|
||||
|
return 1u; |
||||
|
} |
||||
|
|
||||
|
static uint8_t OWI_WaitForFallingEdge(uint16_t byte_index, uint8_t bit_index) |
||||
|
{ |
||||
|
int timeout = (int)(bit_period_us * 4u); |
||||
|
|
||||
|
while (GPIO_Read() && timeout-- > 0) { |
||||
|
delay_us(1u); |
||||
|
} |
||||
|
|
||||
|
if (timeout <= 0) { |
||||
|
if (!g_owi_timeout_latched) { |
||||
|
g_owi_timeout_latched = 1; |
||||
|
g_owi_last_timeout_byte_index = byte_index; |
||||
|
g_owi_last_timeout_bit_index = bit_index; |
||||
|
} |
||||
|
return 0u; |
||||
|
} |
||||
|
|
||||
|
return 1u; |
||||
|
} |
||||
|
|
||||
|
static uint8_t OWI_ReadByte_StreamSynced(uint16_t byte_index) |
||||
|
{ |
||||
|
uint8_t data = 0; |
||||
|
int b; |
||||
|
|
||||
|
for (b = 7; b >= 0; b--) { |
||||
|
uint8_t bit_index = (uint8_t)(7 - b); |
||||
|
uint8_t bit; |
||||
|
|
||||
|
g_owi_current_read_byte_index = byte_index; |
||||
|
g_owi_current_read_bit_index = bit_index; |
||||
|
|
||||
|
/* 슬롯 시작 후 중앙 샘플 */ |
||||
|
delay_us(bit_period_us / 2u); |
||||
|
bit = GPIO_Read() ? 1u : 0u; |
||||
|
data |= (uint8_t)(bit << b); |
||||
|
|
||||
|
/* 남은 반 슬롯 대기 */ |
||||
|
delay_us(bit_period_us / 2u); |
||||
|
} |
||||
|
|
||||
|
return data; |
||||
|
} |
||||
|
|
||||
|
void OWI_SecureStop(void) |
||||
|
{ |
||||
|
int i; |
||||
|
|
||||
|
GPIO_Clear(); |
||||
|
delay_us(SECURE_HIGH); |
||||
|
|
||||
|
for (i = 0; i < (int)SECURE_TOGGLE_COUNT; i++) { |
||||
|
GPIO_Input(); |
||||
|
delay_us(SECURE_TOGGLE_HIGH); |
||||
|
|
||||
|
GPIO_Clear(); |
||||
|
delay_us(SECURE_TOGGLE_LOW); |
||||
|
} |
||||
|
|
||||
|
GPIO_Input(); |
||||
|
delay_us(SECURE_HIGH); |
||||
|
|
||||
|
GPIO_Clear(); |
||||
|
delay_us(TSTART_HOLD); |
||||
|
GPIO_Input(); |
||||
|
} |
||||
|
|
||||
|
/* =========================================================
|
||||
|
* Bit/Byte IO |
||||
|
* ========================================================= */ |
||||
|
void OWI_WriteBit(int bit) |
||||
|
{ |
||||
|
uint32_t t_low = bit ? (uint32_t)TLOW_1 : (uint32_t)TLOW_0; |
||||
|
uint32_t t_high = (uint32_t)TBIT - t_low; |
||||
|
|
||||
|
/* HIGH 구간 */ |
||||
|
OWI_Release(); |
||||
|
delay_us(t_high); |
||||
|
|
||||
|
/* LOW 구간 */ |
||||
|
OWI_DriveLow(); |
||||
|
delay_us(t_low); |
||||
|
|
||||
|
/* 다음 슬롯 시작 전 반드시 release */ |
||||
|
OWI_Release(); |
||||
|
} |
||||
|
|
||||
|
void OWI_WriteByte(uint8_t data) |
||||
|
{ |
||||
|
int i; |
||||
|
for (i = 7; i >= 0; i--) { |
||||
|
OWI_WriteBit((data >> i) & 0x01u); |
||||
|
} |
||||
|
GPIO_Input(); |
||||
|
} |
||||
|
|
||||
|
uint8_t OWI_ReadBit(void) |
||||
|
{ |
||||
|
int timeout; |
||||
|
int low_width = 0; |
||||
|
|
||||
|
/* 1) 라인이 HIGH가 될 때까지 정리 */ |
||||
|
timeout = (int)(bit_period_us * 2u); |
||||
|
while (!GPIO_Read() && timeout-- > 0) { |
||||
|
delay_us(1u); |
||||
|
} |
||||
|
|
||||
|
if (timeout <= 0) { |
||||
|
if (!g_owi_timeout_latched) { |
||||
|
g_owi_timeout_latched = 1; |
||||
|
g_owi_last_timeout_byte_index = g_owi_current_read_byte_index; |
||||
|
g_owi_last_timeout_bit_index = g_owi_current_read_bit_index; |
||||
|
} |
||||
|
return 0u; |
||||
|
} |
||||
|
|
||||
|
/* 2) 다음 LOW 시작 대기 */ |
||||
|
timeout = (int)(bit_period_us * 2u); |
||||
|
while (GPIO_Read() && timeout-- > 0) { |
||||
|
delay_us(1u); |
||||
|
} |
||||
|
|
||||
|
if (timeout <= 0) { |
||||
|
if (!g_owi_timeout_latched) { |
||||
|
g_owi_timeout_latched = 1; |
||||
|
g_owi_last_timeout_byte_index = g_owi_current_read_byte_index; |
||||
|
g_owi_last_timeout_bit_index = g_owi_current_read_bit_index; |
||||
|
} |
||||
|
return 0u; |
||||
|
} |
||||
|
|
||||
|
/* 3) LOW가 유지되는 시간을 직접 측정 */ |
||||
|
while (!GPIO_Read() && low_width < (int)(bit_period_us * 2u)) { |
||||
|
delay_us(1u); |
||||
|
low_width++; |
||||
|
} |
||||
|
|
||||
|
/* 4) LOW 폭 기준으로 판정
|
||||
|
- 짧으면 1 |
||||
|
- 길면 0 |
||||
|
threshold ~= TBIT/2 |
||||
|
*/ |
||||
|
return (low_width < (int)(bit_period_us / 2u)) ? 1u : 0u; |
||||
|
} |
||||
|
|
||||
|
uint8_t OWI_ReadByte(void) |
||||
|
{ |
||||
|
uint8_t data = 0; |
||||
|
int i; |
||||
|
|
||||
|
for (i = 7; i >= 0; i--) { |
||||
|
g_owi_current_read_bit_index = (uint8_t)(7 - i); |
||||
|
data |= (uint8_t)(OWI_ReadBit() << i); |
||||
|
if (OWI_HasTimeout()) { |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
return data; |
||||
|
} |
||||
|
|
||||
|
/* =========================================================
|
||||
|
* Debug Print |
||||
|
* ========================================================= */ |
||||
|
void OWI_T_ReadBytesAndPrint(int length) |
||||
|
{ |
||||
|
uint8_t buf[129]; |
||||
|
int i; |
||||
|
char uart_buf[8]; |
||||
|
char tmp_buf[8]; |
||||
|
uint8_t va0, va1; |
||||
|
|
||||
|
if (length > 129) length = 129; |
||||
|
if (length <= 0) return; |
||||
|
|
||||
|
OWI_ClearTimeout(); |
||||
|
|
||||
|
for (i = 0; i < length; i++) { |
||||
|
R_WDT_Restart(); |
||||
|
g_owi_current_read_byte_index = (uint16_t)i; |
||||
|
buf[i] = OWI_ReadByte(); |
||||
|
if (OWI_HasTimeout()) { |
||||
|
i++; |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
sprintf(uart_buf, "%02X ", buf[0]); |
||||
|
strcpy(tmp_buf, uart_buf); |
||||
|
HOST_PRINT(tmp_buf); |
||||
|
|
||||
|
for (i = 1; i < length; i += 2) { |
||||
|
va0 = buf[i]; |
||||
|
va1 = (uint8_t)((i + 1 < length) ? buf[i + 1] : 0u); |
||||
|
|
||||
|
delay_us(200); |
||||
|
sprintf(uart_buf, "%02X%02X ", va0, va1); |
||||
|
strcpy(tmp_buf, uart_buf); |
||||
|
HOST_PRINT(tmp_buf); |
||||
|
delay_us(200); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/* =========================================================
|
||||
|
* Raw helpers |
||||
|
* ========================================================= */ |
||||
|
static void owi_result_init(owi_io_result_t *r) |
||||
|
{ |
||||
|
if (!r) return; |
||||
|
memset(r, 0, sizeof(*r)); |
||||
|
r->ok = 1; |
||||
|
r->timeout_byte_index = 0xFFFFu; |
||||
|
r->timeout_bit_index = 0xFFu; |
||||
|
} |
||||
|
|
||||
|
static void owi_result_latch_timeout(owi_io_result_t *r) |
||||
|
{ |
||||
|
if (!r) return; |
||||
|
|
||||
|
if (OWI_HasTimeout()) { |
||||
|
r->ok = 0; |
||||
|
r->timeout = 1; |
||||
|
r->timeout_byte_index = OWI_GetLastTimeoutByteIndex(); |
||||
|
r->timeout_bit_index = OWI_GetLastTimeoutBitIndex(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void OWI_T_CommandModeRaw(const uint8_t *tx_data, uint8_t tx_len, uint8_t id, owi_io_result_t *r) |
||||
|
{ |
||||
|
int i; |
||||
|
|
||||
|
owi_result_init(r); |
||||
|
|
||||
|
//delay_us(200);
|
||||
|
OWI_Init(OWI_BIT_PERIOD_US); |
||||
|
OWI_ClearTimeout(); |
||||
|
|
||||
|
R_WDT_Restart(); |
||||
|
OWI_SecureStop(); |
||||
|
R_WDT_Restart(); |
||||
|
OWI_WriteByte((uint8_t)(id << 1)); |
||||
|
R_WDT_Restart(); |
||||
|
|
||||
|
for (i = 0; i < (int)tx_len; i++) { |
||||
|
R_WDT_Restart(); |
||||
|
OWI_WriteByte(tx_data[i]); |
||||
|
R_WDT_Restart(); |
||||
|
} |
||||
|
|
||||
|
OWI_Stop(); |
||||
|
R_WDT_Restart(); |
||||
|
owi_result_latch_timeout(r); |
||||
|
} |
||||
|
|
||||
|
void OWI_CommandModeRaw(const uint8_t *tx_data, uint8_t tx_len, uint8_t id, owi_io_result_t *r) |
||||
|
{ |
||||
|
int i; |
||||
|
|
||||
|
owi_result_init(r); |
||||
|
OWI_Init(OWI_BIT_PERIOD_US); |
||||
|
OWI_ClearTimeout(); |
||||
|
|
||||
|
R_WDT_Restart(); |
||||
|
OWI_SecureStop(); |
||||
|
R_WDT_Restart(); |
||||
|
OWI_WriteByte((uint8_t)(id << 1)); |
||||
|
R_WDT_Restart(); |
||||
|
|
||||
|
for (i = 0; i < (int)tx_len; i++) { |
||||
|
R_WDT_Restart(); |
||||
|
OWI_WriteByte(tx_data[i]); |
||||
|
R_WDT_Restart(); |
||||
|
} |
||||
|
|
||||
|
OWI_Stop(); |
||||
|
R_WDT_Restart(); |
||||
|
owi_result_latch_timeout(r); |
||||
|
} |
||||
|
|
||||
|
void OWI_ReadBytesRaw(int length, uint8_t id, owi_io_result_t *r) |
||||
|
{ |
||||
|
int i; |
||||
|
int max_len; |
||||
|
uint8_t is_long_read; |
||||
|
|
||||
|
if (!r) return; |
||||
|
|
||||
|
owi_result_init(r); |
||||
|
OWI_Init(OWI_BIT_PERIOD_US); |
||||
|
|
||||
|
if (length <= 0) { |
||||
|
r->ok = 0; |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
max_len = (int)OWI_IO_MAX_BYTES; |
||||
|
if (length > max_len) { |
||||
|
length = max_len; |
||||
|
} |
||||
|
|
||||
|
r->read_len = (uint16_t)length; |
||||
|
OWI_ClearTimeout(); |
||||
|
|
||||
|
/* Only 119 keeps the established mid-stream sync. */ |
||||
|
is_long_read = (length == 119) ? 1u : 0u; |
||||
|
|
||||
|
R_WDT_Restart(); |
||||
|
OWI_SecureStop(); |
||||
|
OWI_WriteByte((uint8_t)((id << 1) | 1u)); |
||||
|
|
||||
|
/*
|
||||
|
* For 129 bytes, wait for the first edge immediately after the read ID. |
||||
|
* The old 100us delay could enter an already-started first pulse. |
||||
|
* Preserve the established delay for every other read length. |
||||
|
*/ |
||||
|
if (length != 129) { |
||||
|
delay_us(100u); |
||||
|
} |
||||
|
|
||||
|
R_WDT_Restart(); |
||||
|
if (!OWI_WaitForFallingEdge(0u, 0u)) { |
||||
|
owi_result_latch_timeout(r); |
||||
|
OWI_StopRead(); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
for (i = 0; i < length; i++) { |
||||
|
R_WDT_Restart(); |
||||
|
|
||||
|
/* Preserve the existing mid-stream sync for the 119-byte path only. */ |
||||
|
if (is_long_read && i == (length - 50)) { |
||||
|
R_WDT_Restart(); |
||||
|
if (!OWI_WaitForFallingEdge((uint16_t)i, 0u)) { |
||||
|
owi_result_latch_timeout(r); |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
r->data[i] = OWI_ReadByte_StreamSynced((uint16_t)i); |
||||
|
|
||||
|
if (OWI_HasTimeout()) { |
||||
|
owi_result_latch_timeout(r); |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
OWI_StopRead(); |
||||
|
} |
||||
|
|
||||
|
void OWI_disable(void) |
||||
|
{ |
||||
|
HOST_PRINT("51\r\n"); |
||||
|
} |
||||
|
|
||||
|
void OWI_T_CommandMode(const uint8_t *tx_data, uint8_t tx_len, uint8_t id) |
||||
|
{ |
||||
|
owi_io_result_t r; |
||||
|
(void)r; |
||||
|
|
||||
|
OWI_T_CommandModeRaw(tx_data, tx_len, id, &r); |
||||
|
HOST_PRINT("51\r\n"); |
||||
|
} |
||||
|
|
||||
|
void OWI_CommandMode(const uint8_t *tx_data, uint8_t tx_len, uint8_t id) |
||||
|
{ |
||||
|
owi_io_result_t r; |
||||
|
(void)r; |
||||
|
|
||||
|
OWI_CommandModeRaw(tx_data, tx_len, id, &r); |
||||
|
HOST_PRINT("51\r\n"); |
||||
|
} |
||||
|
|
||||
|
void OWI_ReadBytesAndPrint(int length, uint8_t id) |
||||
|
{ |
||||
|
owi_io_result_t r; |
||||
|
char out[(2 * OWI_IO_MAX_BYTES) + 40]; |
||||
|
int i; |
||||
|
uint16_t p = 0; |
||||
|
|
||||
|
if (length <= 0) { |
||||
|
HOST_PRINT("Err:read_len_nonzero\r\n"); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
OWI_ReadBytesRaw(length, id, &r); |
||||
|
|
||||
|
if (r.read_len == 0) { |
||||
|
HOST_PRINT("Err:read_len_nonzero\r\n"); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
for (i = 0; i < (int)r.read_len; i++) { |
||||
|
uint8_t b = r.data[i]; |
||||
|
out[p++] = "0123456789ABCDEF"[b >> 4]; |
||||
|
out[p++] = "0123456789ABCDEF"[b & 0x0F]; |
||||
|
} |
||||
|
|
||||
|
if (r.timeout) { |
||||
|
p += (uint16_t)sprintf(&out[p], " !TO(B%u b%u)", |
||||
|
(unsigned)r.timeout_byte_index, |
||||
|
(unsigned)r.timeout_bit_index); |
||||
|
} |
||||
|
|
||||
|
out[p++] = '\r'; |
||||
|
out[p++] = '\n'; |
||||
|
out[p] = '\0'; |
||||
|
|
||||
|
HOST_PRINT(out); |
||||
|
} |
||||
@ -0,0 +1,602 @@ |
|||||
|
#include "owi.h" |
||||
|
#include "delay.h" |
||||
|
#include "r_cg_wdt.h" |
||||
|
#include <string.h> |
||||
|
#include <stdio.h> |
||||
|
#include "uart.h" |
||||
|
#include "r_cg_wdt.h" |
||||
|
|
||||
|
#ifndef OWI_STRONG_DRIVE_HIGH_US |
||||
|
#define OWI_STRONG_DRIVE_HIGH_US 5u |
||||
|
#endif |
||||
|
|
||||
|
/*
|
||||
|
* Test 2 hardware time base |
||||
|
* ------------------------- |
||||
|
* Project clock: fCLK = 32 MHz |
||||
|
* TAU0 channel 5: CK03 = fCLK / 32 = 1 MHz (one count per microsecond) |
||||
|
* |
||||
|
* Channel 5 and CK03 are otherwise unused by this project. Only the CK03 |
||||
|
* field of TPS0 is changed, so CK00 to CK02 remain untouched. |
||||
|
*/ |
||||
|
#define OWI_TIMER_CHANNEL_MASK 0x0020u |
||||
|
#define OWI_TIMER_CK03_DIV32 0x5000u |
||||
|
#define OWI_TIMER_TMR_CK03_INTERVAL 0xC000u |
||||
|
|
||||
|
/* 내부 상태 */ |
||||
|
static uint32_t bit_period_us = OWI_BIT_PERIOD_US; |
||||
|
static uint8_t g_owi_timeout_latched = 0; |
||||
|
|
||||
|
static uint16_t g_owi_last_timeout_byte_index = 0xFFFFu; |
||||
|
static uint8_t g_owi_last_timeout_bit_index = 0xFFu; |
||||
|
|
||||
|
static uint16_t g_owi_current_read_byte_index = 0u; |
||||
|
static uint8_t g_owi_current_read_bit_index = 0u; |
||||
|
static uint16_t g_owi_next_sample_tick = 0u; |
||||
|
|
||||
|
static void OWI_TimerStart1MHz(void) |
||||
|
{ |
||||
|
TAU0EN = 1U; |
||||
|
NOP(); |
||||
|
NOP(); |
||||
|
NOP(); |
||||
|
NOP(); |
||||
|
|
||||
|
TT0 |= (uint16_t)OWI_TIMER_CHANNEL_MASK; |
||||
|
TMMK05 = 1U; |
||||
|
TMIF05 = 0U; |
||||
|
TOE0 &= (uint16_t)~OWI_TIMER_CHANNEL_MASK; |
||||
|
|
||||
|
TPS0 = (uint16_t)((TPS0 & 0x0FFFu) | OWI_TIMER_CK03_DIV32); |
||||
|
TMR05 = OWI_TIMER_TMR_CK03_INTERVAL; |
||||
|
TDR05 = 0xFFFFu; |
||||
|
TS0 |= (uint16_t)OWI_TIMER_CHANNEL_MASK; |
||||
|
} |
||||
|
|
||||
|
static void OWI_TimerStop(void) |
||||
|
{ |
||||
|
TT0 |= (uint16_t)OWI_TIMER_CHANNEL_MASK; |
||||
|
TMIF05 = 0U; |
||||
|
} |
||||
|
|
||||
|
static uint16_t OWI_TimerNow(void) |
||||
|
{ |
||||
|
return (uint16_t)(0xFFFFu - TCR05); |
||||
|
} |
||||
|
|
||||
|
static void OWI_TimerWaitUntil(uint16_t deadline) |
||||
|
{ |
||||
|
while ((int16_t)(uint16_t)(OWI_TimerNow() - deadline) < 0) { |
||||
|
NOP(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/* =========================================================
|
||||
|
* GPIO helpers (P70 / HW Open-Drain) |
||||
|
* - LOW : 출력 모드 + 0 |
||||
|
* - HIGH : 입력(Hi-Z)로 release |
||||
|
* ========================================================= */ |
||||
|
void GPIO_Clear(void) |
||||
|
{ |
||||
|
OWI_PORT_POM |= (uint8_t)OWI_PIN_MASK; |
||||
|
OWI_PORT_P &= (uint8_t)~OWI_PIN_MASK; |
||||
|
OWI_PORT_PM &= (uint8_t)~OWI_PIN_MASK; |
||||
|
} |
||||
|
|
||||
|
void GPIO_Input(void) |
||||
|
{ |
||||
|
OWI_PORT_POM |= (uint8_t)OWI_PIN_MASK; |
||||
|
OWI_PORT_P |= (uint8_t)OWI_PIN_MASK; |
||||
|
OWI_PORT_PM |= (uint8_t)OWI_PIN_MASK; |
||||
|
} |
||||
|
|
||||
|
int GPIO_Read(void) |
||||
|
{ |
||||
|
return (OWI_PORT_P & (uint8_t)OWI_PIN_MASK) ? 1 : 0; |
||||
|
} |
||||
|
|
||||
|
static void OWI_Release(void) |
||||
|
{ |
||||
|
OWI_PORT_POM |= (uint8_t)OWI_PIN_MASK; |
||||
|
OWI_PORT_P |= (uint8_t)OWI_PIN_MASK; |
||||
|
OWI_PORT_PM |= (uint8_t)OWI_PIN_MASK; |
||||
|
} |
||||
|
|
||||
|
static void GPIO_StrongDriveHighKick(uint32_t kick_us) |
||||
|
{ |
||||
|
OWI_Release(); |
||||
|
|
||||
|
if (!GPIO_Read()) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
OWI_PORT_POM &= (uint8_t)~OWI_PIN_MASK; |
||||
|
OWI_PORT_P |= (uint8_t)OWI_PIN_MASK; |
||||
|
OWI_PORT_PM &= (uint8_t)~OWI_PIN_MASK; |
||||
|
|
||||
|
delay_us(kick_us); |
||||
|
|
||||
|
OWI_PORT_POM |= (uint8_t)OWI_PIN_MASK; |
||||
|
OWI_Release(); |
||||
|
} |
||||
|
|
||||
|
void GPIO_ForceHighKick(void) |
||||
|
{ |
||||
|
GPIO_StrongDriveHighKick(OWI_STRONG_DRIVE_HIGH_US); |
||||
|
} |
||||
|
|
||||
|
static void OWI_DriveLow(void) |
||||
|
{ |
||||
|
OWI_PORT_POM |= (uint8_t)OWI_PIN_MASK; |
||||
|
OWI_PORT_P &= (uint8_t)~OWI_PIN_MASK; |
||||
|
OWI_PORT_PM &= (uint8_t)~OWI_PIN_MASK; |
||||
|
} |
||||
|
|
||||
|
/* =========================================================
|
||||
|
* Diagnostics |
||||
|
* ========================================================= */ |
||||
|
uint8_t OWI_HasTimeout(void) |
||||
|
{ |
||||
|
return g_owi_timeout_latched; |
||||
|
} |
||||
|
|
||||
|
void OWI_ClearTimeout(void) |
||||
|
{ |
||||
|
g_owi_timeout_latched = 0; |
||||
|
g_owi_last_timeout_byte_index = 0xFFFFu; |
||||
|
g_owi_last_timeout_bit_index = 0xFFu; |
||||
|
} |
||||
|
|
||||
|
uint16_t OWI_GetLastTimeoutByteIndex(void) |
||||
|
{ |
||||
|
return g_owi_last_timeout_byte_index; |
||||
|
} |
||||
|
|
||||
|
uint8_t OWI_GetLastTimeoutBitIndex(void) |
||||
|
{ |
||||
|
return g_owi_last_timeout_bit_index; |
||||
|
} |
||||
|
|
||||
|
/* =========================================================
|
||||
|
* OWI Init |
||||
|
* ========================================================= */ |
||||
|
void OWI_Init(uint32_t bit_time_us) |
||||
|
{ |
||||
|
bit_period_us = bit_time_us; |
||||
|
(void)bit_period_us; |
||||
|
|
||||
|
OWI_PORT_POM |= (uint8_t)OWI_PIN_MASK; |
||||
|
OWI_PORT_PU &= (uint8_t)~OWI_PIN_MASK; |
||||
|
|
||||
|
OWI_ClearTimeout(); |
||||
|
GPIO_Input(); |
||||
|
} |
||||
|
|
||||
|
/* =========================================================
|
||||
|
* Start/Stop/Secure |
||||
|
* ========================================================= */ |
||||
|
void OWI_Start(void) |
||||
|
{ |
||||
|
GPIO_Clear(); |
||||
|
delay_us(TSTART_HOLD); |
||||
|
|
||||
|
GPIO_Input(); |
||||
|
delay_us(TBIT); |
||||
|
} |
||||
|
|
||||
|
void OWI_Stop(void) |
||||
|
{ |
||||
|
GPIO_Input(); |
||||
|
delay_us(TSTOP_LOW); |
||||
|
delay_us(TIDLE); |
||||
|
} |
||||
|
|
||||
|
static void OWI_StopWrite(void) |
||||
|
{ |
||||
|
OWI_Release(); |
||||
|
delay_us(TSTOP_LOW); |
||||
|
delay_us(TIDLE); |
||||
|
} |
||||
|
|
||||
|
static void OWI_StopRead(void) |
||||
|
{ |
||||
|
OWI_DriveLow(); |
||||
|
delay_us(TSTOP_LOW); |
||||
|
OWI_Release(); |
||||
|
delay_us(TIDLE); |
||||
|
} |
||||
|
|
||||
|
static uint8_t OWI_WaitFirstBitStart(void) |
||||
|
{ |
||||
|
int timeout; |
||||
|
|
||||
|
timeout = (int)(bit_period_us * 4u); |
||||
|
|
||||
|
/* 첫 번째 HIGH->LOW 시작을 기다림 */ |
||||
|
while (GPIO_Read() && timeout-- > 0) { |
||||
|
delay_us(1u); |
||||
|
} |
||||
|
|
||||
|
if (timeout <= 0) { |
||||
|
if (!g_owi_timeout_latched) { |
||||
|
g_owi_timeout_latched = 1; |
||||
|
g_owi_last_timeout_byte_index = 0u; |
||||
|
g_owi_last_timeout_bit_index = 0u; |
||||
|
} |
||||
|
return 0u; |
||||
|
} |
||||
|
|
||||
|
return 1u; |
||||
|
} |
||||
|
|
||||
|
static uint8_t OWI_ReadByte_StreamSynced(uint16_t byte_index) |
||||
|
{ |
||||
|
uint8_t data = 0; |
||||
|
int b; |
||||
|
|
||||
|
for (b = 7; b >= 0; b--) { |
||||
|
uint8_t bit_index = (uint8_t)(7 - b); |
||||
|
uint8_t bit; |
||||
|
|
||||
|
g_owi_current_read_byte_index = byte_index; |
||||
|
g_owi_current_read_bit_index = bit_index; |
||||
|
|
||||
|
/*
|
||||
|
* The deadline is advanced from the R-bit end reference, never from |
||||
|
* the end of the previous CPU delay. Per-byte processing time |
||||
|
* therefore cannot accumulate as sampling drift. |
||||
|
*/ |
||||
|
OWI_TimerWaitUntil(g_owi_next_sample_tick); |
||||
|
bit = GPIO_Read() ? 1u : 0u; |
||||
|
data |= (uint8_t)(bit << b); |
||||
|
g_owi_next_sample_tick = |
||||
|
(uint16_t)(g_owi_next_sample_tick + (uint16_t)bit_period_us); |
||||
|
} |
||||
|
|
||||
|
return data; |
||||
|
} |
||||
|
|
||||
|
void OWI_SecureStop(void) |
||||
|
{ |
||||
|
int i; |
||||
|
|
||||
|
GPIO_Clear(); |
||||
|
delay_us(SECURE_HIGH); |
||||
|
|
||||
|
for (i = 0; i < (int)SECURE_TOGGLE_COUNT; i++) { |
||||
|
GPIO_Input(); |
||||
|
delay_us(SECURE_TOGGLE_HIGH); |
||||
|
|
||||
|
GPIO_Clear(); |
||||
|
delay_us(SECURE_TOGGLE_LOW); |
||||
|
} |
||||
|
|
||||
|
GPIO_Input(); |
||||
|
delay_us(SECURE_HIGH); |
||||
|
|
||||
|
GPIO_Clear(); |
||||
|
delay_us(TSTART_HOLD); |
||||
|
GPIO_Input(); |
||||
|
} |
||||
|
|
||||
|
/* =========================================================
|
||||
|
* Bit/Byte IO |
||||
|
* ========================================================= */ |
||||
|
void OWI_WriteBit(int bit) |
||||
|
{ |
||||
|
uint32_t t_low = bit ? (uint32_t)TLOW_1 : (uint32_t)TLOW_0; |
||||
|
uint32_t t_high = (uint32_t)TBIT - t_low; |
||||
|
|
||||
|
/* HIGH 구간 */ |
||||
|
OWI_Release(); |
||||
|
delay_us(t_high); |
||||
|
|
||||
|
/* LOW 구간 */ |
||||
|
OWI_DriveLow(); |
||||
|
delay_us(t_low); |
||||
|
|
||||
|
/* 다음 슬롯 시작 전 반드시 release */ |
||||
|
OWI_Release(); |
||||
|
} |
||||
|
|
||||
|
void OWI_WriteByte(uint8_t data) |
||||
|
{ |
||||
|
int i; |
||||
|
for (i = 7; i >= 0; i--) { |
||||
|
OWI_WriteBit((data >> i) & 0x01u); |
||||
|
} |
||||
|
GPIO_Input(); |
||||
|
} |
||||
|
|
||||
|
uint8_t OWI_ReadBit(void) |
||||
|
{ |
||||
|
int timeout; |
||||
|
int low_width = 0; |
||||
|
|
||||
|
/* 1) 라인이 HIGH가 될 때까지 정리 */ |
||||
|
timeout = (int)(bit_period_us * 2u); |
||||
|
while (!GPIO_Read() && timeout-- > 0) { |
||||
|
delay_us(1u); |
||||
|
} |
||||
|
|
||||
|
if (timeout <= 0) { |
||||
|
if (!g_owi_timeout_latched) { |
||||
|
g_owi_timeout_latched = 1; |
||||
|
g_owi_last_timeout_byte_index = g_owi_current_read_byte_index; |
||||
|
g_owi_last_timeout_bit_index = g_owi_current_read_bit_index; |
||||
|
} |
||||
|
return 0u; |
||||
|
} |
||||
|
|
||||
|
/* 2) 다음 LOW 시작 대기 */ |
||||
|
timeout = (int)(bit_period_us * 2u); |
||||
|
while (GPIO_Read() && timeout-- > 0) { |
||||
|
delay_us(1u); |
||||
|
} |
||||
|
|
||||
|
if (timeout <= 0) { |
||||
|
if (!g_owi_timeout_latched) { |
||||
|
g_owi_timeout_latched = 1; |
||||
|
g_owi_last_timeout_byte_index = g_owi_current_read_byte_index; |
||||
|
g_owi_last_timeout_bit_index = g_owi_current_read_bit_index; |
||||
|
} |
||||
|
return 0u; |
||||
|
} |
||||
|
|
||||
|
/* 3) LOW가 유지되는 시간을 직접 측정 */ |
||||
|
while (!GPIO_Read() && low_width < (int)(bit_period_us * 2u)) { |
||||
|
delay_us(1u); |
||||
|
low_width++; |
||||
|
} |
||||
|
|
||||
|
/* 4) LOW 폭 기준으로 판정
|
||||
|
- 짧으면 1 |
||||
|
- 길면 0 |
||||
|
threshold ~= TBIT/2 |
||||
|
*/ |
||||
|
return (low_width < (int)(bit_period_us / 2u)) ? 1u : 0u; |
||||
|
} |
||||
|
|
||||
|
uint8_t OWI_ReadByte(void) |
||||
|
{ |
||||
|
uint8_t data = 0; |
||||
|
int i; |
||||
|
|
||||
|
for (i = 7; i >= 0; i--) { |
||||
|
g_owi_current_read_bit_index = (uint8_t)(7 - i); |
||||
|
data |= (uint8_t)(OWI_ReadBit() << i); |
||||
|
if (OWI_HasTimeout()) { |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
return data; |
||||
|
} |
||||
|
|
||||
|
/* =========================================================
|
||||
|
* Debug Print |
||||
|
* ========================================================= */ |
||||
|
void OWI_T_ReadBytesAndPrint(int length) |
||||
|
{ |
||||
|
uint8_t buf[129]; |
||||
|
int i; |
||||
|
char uart_buf[8]; |
||||
|
char tmp_buf[8]; |
||||
|
uint8_t va0, va1; |
||||
|
|
||||
|
if (length > 129) length = 129; |
||||
|
if (length <= 0) return; |
||||
|
|
||||
|
OWI_ClearTimeout(); |
||||
|
|
||||
|
for (i = 0; i < length; i++) { |
||||
|
R_WDT_Restart(); |
||||
|
g_owi_current_read_byte_index = (uint16_t)i; |
||||
|
buf[i] = OWI_ReadByte(); |
||||
|
if (OWI_HasTimeout()) { |
||||
|
i++; |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
sprintf(uart_buf, "%02X ", buf[0]); |
||||
|
strcpy(tmp_buf, uart_buf); |
||||
|
HOST_PRINT(tmp_buf); |
||||
|
|
||||
|
for (i = 1; i < length; i += 2) { |
||||
|
va0 = buf[i]; |
||||
|
va1 = (uint8_t)((i + 1 < length) ? buf[i + 1] : 0u); |
||||
|
|
||||
|
delay_us(200); |
||||
|
sprintf(uart_buf, "%02X%02X ", va0, va1); |
||||
|
strcpy(tmp_buf, uart_buf); |
||||
|
HOST_PRINT(tmp_buf); |
||||
|
delay_us(200); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/* =========================================================
|
||||
|
* Raw helpers |
||||
|
* ========================================================= */ |
||||
|
static void owi_result_init(owi_io_result_t *r) |
||||
|
{ |
||||
|
if (!r) return; |
||||
|
memset(r, 0, sizeof(*r)); |
||||
|
r->ok = 1; |
||||
|
r->timeout_byte_index = 0xFFFFu; |
||||
|
r->timeout_bit_index = 0xFFu; |
||||
|
} |
||||
|
|
||||
|
static void owi_result_latch_timeout(owi_io_result_t *r) |
||||
|
{ |
||||
|
if (!r) return; |
||||
|
|
||||
|
if (OWI_HasTimeout()) { |
||||
|
r->ok = 0; |
||||
|
r->timeout = 1; |
||||
|
r->timeout_byte_index = OWI_GetLastTimeoutByteIndex(); |
||||
|
r->timeout_bit_index = OWI_GetLastTimeoutBitIndex(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void OWI_T_CommandModeRaw(const uint8_t *tx_data, uint8_t tx_len, uint8_t id, owi_io_result_t *r) |
||||
|
{ |
||||
|
int i; |
||||
|
|
||||
|
owi_result_init(r); |
||||
|
|
||||
|
//delay_us(200);
|
||||
|
OWI_Init(OWI_BIT_PERIOD_US); |
||||
|
OWI_ClearTimeout(); |
||||
|
|
||||
|
R_WDT_Restart(); |
||||
|
OWI_SecureStop(); |
||||
|
R_WDT_Restart(); |
||||
|
OWI_WriteByte((uint8_t)(id << 1)); |
||||
|
R_WDT_Restart(); |
||||
|
|
||||
|
for (i = 0; i < (int)tx_len; i++) { |
||||
|
R_WDT_Restart(); |
||||
|
OWI_WriteByte(tx_data[i]); |
||||
|
R_WDT_Restart(); |
||||
|
} |
||||
|
|
||||
|
OWI_Stop(); |
||||
|
R_WDT_Restart(); |
||||
|
owi_result_latch_timeout(r); |
||||
|
} |
||||
|
|
||||
|
void OWI_CommandModeRaw(const uint8_t *tx_data, uint8_t tx_len, uint8_t id, owi_io_result_t *r) |
||||
|
{ |
||||
|
int i; |
||||
|
|
||||
|
owi_result_init(r); |
||||
|
OWI_Init(OWI_BIT_PERIOD_US); |
||||
|
OWI_ClearTimeout(); |
||||
|
|
||||
|
R_WDT_Restart(); |
||||
|
OWI_SecureStop(); |
||||
|
R_WDT_Restart(); |
||||
|
OWI_WriteByte((uint8_t)(id << 1)); |
||||
|
R_WDT_Restart(); |
||||
|
|
||||
|
for (i = 0; i < (int)tx_len; i++) { |
||||
|
R_WDT_Restart(); |
||||
|
OWI_WriteByte(tx_data[i]); |
||||
|
R_WDT_Restart(); |
||||
|
} |
||||
|
|
||||
|
OWI_Stop(); |
||||
|
R_WDT_Restart(); |
||||
|
owi_result_latch_timeout(r); |
||||
|
} |
||||
|
|
||||
|
void OWI_ReadBytesRaw(int length, uint8_t id, owi_io_result_t *r) |
||||
|
{ |
||||
|
int i; |
||||
|
int max_len; |
||||
|
|
||||
|
if (!r) return; |
||||
|
|
||||
|
owi_result_init(r); |
||||
|
OWI_Init(OWI_BIT_PERIOD_US); |
||||
|
|
||||
|
if (length <= 0) { |
||||
|
r->ok = 0; |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
max_len = (int)OWI_IO_MAX_BYTES; |
||||
|
if (length > max_len) { |
||||
|
length = max_len; |
||||
|
} |
||||
|
|
||||
|
r->read_len = (uint16_t)length; |
||||
|
OWI_ClearTimeout(); |
||||
|
|
||||
|
R_WDT_Restart(); |
||||
|
OWI_SecureStop(); |
||||
|
OWI_TimerStart1MHz(); |
||||
|
OWI_WriteByte((uint8_t)((id << 1) | 1u)); |
||||
|
|
||||
|
/*
|
||||
|
* OWI_WriteByte() returns at the end of the R bit. Every sample deadline |
||||
|
* is an absolute 1 MHz timer value derived from this one reference. |
||||
|
*/ |
||||
|
g_owi_next_sample_tick = |
||||
|
(uint16_t)(OWI_TimerNow() + (uint16_t)(bit_period_us / 2u)); |
||||
|
|
||||
|
for (i = 0; i < length; i++) { |
||||
|
R_WDT_Restart(); |
||||
|
|
||||
|
r->data[i] = OWI_ReadByte_StreamSynced((uint16_t)i); |
||||
|
|
||||
|
if (OWI_HasTimeout()) { |
||||
|
owi_result_latch_timeout(r); |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
OWI_TimerStop(); |
||||
|
OWI_StopRead(); |
||||
|
} |
||||
|
|
||||
|
void OWI_disable(void) |
||||
|
{ |
||||
|
HOST_PRINT("51\r\n"); |
||||
|
} |
||||
|
|
||||
|
void OWI_T_CommandMode(const uint8_t *tx_data, uint8_t tx_len, uint8_t id) |
||||
|
{ |
||||
|
owi_io_result_t r; |
||||
|
(void)r; |
||||
|
|
||||
|
OWI_T_CommandModeRaw(tx_data, tx_len, id, &r); |
||||
|
HOST_PRINT("51\r\n"); |
||||
|
} |
||||
|
|
||||
|
void OWI_CommandMode(const uint8_t *tx_data, uint8_t tx_len, uint8_t id) |
||||
|
{ |
||||
|
owi_io_result_t r; |
||||
|
(void)r; |
||||
|
|
||||
|
OWI_CommandModeRaw(tx_data, tx_len, id, &r); |
||||
|
HOST_PRINT("51\r\n"); |
||||
|
} |
||||
|
|
||||
|
void OWI_ReadBytesAndPrint(int length, uint8_t id) |
||||
|
{ |
||||
|
owi_io_result_t r; |
||||
|
char out[(2 * OWI_IO_MAX_BYTES) + 40]; |
||||
|
int i; |
||||
|
uint16_t p = 0; |
||||
|
|
||||
|
if (length <= 0) { |
||||
|
HOST_PRINT("Err:read_len_nonzero\r\n"); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
OWI_ReadBytesRaw(length, id, &r); |
||||
|
|
||||
|
if (r.read_len == 0) { |
||||
|
HOST_PRINT("Err:read_len_nonzero\r\n"); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
for (i = 0; i < (int)r.read_len; i++) { |
||||
|
uint8_t b = r.data[i]; |
||||
|
out[p++] = "0123456789ABCDEF"[b >> 4]; |
||||
|
out[p++] = "0123456789ABCDEF"[b & 0x0F]; |
||||
|
} |
||||
|
|
||||
|
if (r.timeout) { |
||||
|
p += (uint16_t)sprintf(&out[p], " !TO(B%u b%u)", |
||||
|
(unsigned)r.timeout_byte_index, |
||||
|
(unsigned)r.timeout_bit_index); |
||||
|
} |
||||
|
|
||||
|
out[p++] = '\r'; |
||||
|
out[p++] = '\n'; |
||||
|
out[p] = '\0'; |
||||
|
|
||||
|
HOST_PRINT(out); |
||||
|
} |
||||
@ -0,0 +1,666 @@ |
|||||
|
#include "owi.h" |
||||
|
#include "delay.h" |
||||
|
#include "r_cg_wdt.h" |
||||
|
#include <string.h> |
||||
|
#include <stdio.h> |
||||
|
#include "uart.h" |
||||
|
#include "r_cg_wdt.h" |
||||
|
|
||||
|
#ifndef OWI_STRONG_DRIVE_HIGH_US |
||||
|
#define OWI_STRONG_DRIVE_HIGH_US 5u |
||||
|
#endif |
||||
|
|
||||
|
/*
|
||||
|
* Test 3 hardware time base |
||||
|
* ------------------------- |
||||
|
* Project clock: fCLK = 32 MHz |
||||
|
* TAU0 channel 5: CK03 = fCLK / 32 = 1 MHz (one count per microsecond) |
||||
|
* |
||||
|
* Channel 5 and CK03 are otherwise unused by this project. Only the CK03 |
||||
|
* field of TPS0 is changed, so CK00 to CK02 remain untouched. |
||||
|
*/ |
||||
|
#define OWI_TIMER_CHANNEL_MASK 0x0020u |
||||
|
#define OWI_TIMER_CK03_DIV32 0x5000u |
||||
|
#define OWI_TIMER_TMR_CK03_INTERVAL 0xC000u |
||||
|
|
||||
|
/* 내부 상태 */ |
||||
|
static uint32_t bit_period_us = OWI_BIT_PERIOD_US; |
||||
|
static uint8_t g_owi_timeout_latched = 0; |
||||
|
|
||||
|
static uint16_t g_owi_last_timeout_byte_index = 0xFFFFu; |
||||
|
static uint8_t g_owi_last_timeout_bit_index = 0xFFu; |
||||
|
|
||||
|
static uint16_t g_owi_current_read_byte_index = 0u; |
||||
|
static uint8_t g_owi_current_read_bit_index = 0u; |
||||
|
static uint16_t g_owi_next_bit_start_tick = 0u; |
||||
|
|
||||
|
static void OWI_TimerStart1MHz(void) |
||||
|
{ |
||||
|
TAU0EN = 1U; |
||||
|
NOP(); |
||||
|
NOP(); |
||||
|
NOP(); |
||||
|
NOP(); |
||||
|
|
||||
|
TT0 |= (uint16_t)OWI_TIMER_CHANNEL_MASK; |
||||
|
TMMK05 = 1U; |
||||
|
TMIF05 = 0U; |
||||
|
TOE0 &= (uint16_t)~OWI_TIMER_CHANNEL_MASK; |
||||
|
|
||||
|
TPS0 = (uint16_t)((TPS0 & 0x0FFFu) | OWI_TIMER_CK03_DIV32); |
||||
|
TMR05 = OWI_TIMER_TMR_CK03_INTERVAL; |
||||
|
TDR05 = 0xFFFFu; |
||||
|
TS0 |= (uint16_t)OWI_TIMER_CHANNEL_MASK; |
||||
|
} |
||||
|
|
||||
|
static void OWI_TimerStop(void) |
||||
|
{ |
||||
|
TT0 |= (uint16_t)OWI_TIMER_CHANNEL_MASK; |
||||
|
TMIF05 = 0U; |
||||
|
} |
||||
|
|
||||
|
static uint16_t OWI_TimerNow(void) |
||||
|
{ |
||||
|
return (uint16_t)(0xFFFFu - TCR05); |
||||
|
} |
||||
|
|
||||
|
static uint8_t OWI_TimerDeadlineReached(uint16_t deadline) |
||||
|
{ |
||||
|
return ((int16_t)(uint16_t)(OWI_TimerNow() - deadline) >= 0) ? 1u : 0u; |
||||
|
} |
||||
|
|
||||
|
static void OWI_TimerWaitUntil(uint16_t deadline) |
||||
|
{ |
||||
|
while (!OWI_TimerDeadlineReached(deadline)) { |
||||
|
NOP(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
static void OWI_LatchReadTimeout(uint16_t byte_index, uint8_t bit_index) |
||||
|
{ |
||||
|
if (!g_owi_timeout_latched) { |
||||
|
g_owi_timeout_latched = 1u; |
||||
|
g_owi_last_timeout_byte_index = byte_index; |
||||
|
g_owi_last_timeout_bit_index = bit_index; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
static uint8_t OWI_MeasureFallingEdge(uint16_t bit_start, |
||||
|
uint16_t byte_index, |
||||
|
uint8_t bit_index, |
||||
|
uint16_t *edge_tick) |
||||
|
{ |
||||
|
uint16_t bit_end = |
||||
|
(uint16_t)(bit_start + (uint16_t)bit_period_us); |
||||
|
uint16_t edge; |
||||
|
|
||||
|
OWI_TimerWaitUntil(bit_start); |
||||
|
|
||||
|
/*
|
||||
|
* Each OWI bit starts HIGH. First discard a possible LOW remainder at |
||||
|
* the exact boundary, then capture the next HIGH-to-LOW transition. |
||||
|
*/ |
||||
|
while (!GPIO_Read()) { |
||||
|
if (OWI_TimerDeadlineReached(bit_end)) { |
||||
|
OWI_LatchReadTimeout(byte_index, bit_index); |
||||
|
return 0u; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
while (GPIO_Read()) { |
||||
|
if (OWI_TimerDeadlineReached(bit_end)) { |
||||
|
OWI_LatchReadTimeout(byte_index, bit_index); |
||||
|
return 0u; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
edge = OWI_TimerNow(); |
||||
|
if ((uint16_t)(edge - bit_start) >= (uint16_t)bit_period_us) { |
||||
|
OWI_LatchReadTimeout(byte_index, bit_index); |
||||
|
return 0u; |
||||
|
} |
||||
|
|
||||
|
*edge_tick = edge; |
||||
|
return 1u; |
||||
|
} |
||||
|
|
||||
|
/* =========================================================
|
||||
|
* GPIO helpers (P70 / HW Open-Drain) |
||||
|
* - LOW : 출력 모드 + 0 |
||||
|
* - HIGH : 입력(Hi-Z)로 release |
||||
|
* ========================================================= */ |
||||
|
void GPIO_Clear(void) |
||||
|
{ |
||||
|
OWI_PORT_POM |= (uint8_t)OWI_PIN_MASK; |
||||
|
OWI_PORT_P &= (uint8_t)~OWI_PIN_MASK; |
||||
|
OWI_PORT_PM &= (uint8_t)~OWI_PIN_MASK; |
||||
|
} |
||||
|
|
||||
|
void GPIO_Input(void) |
||||
|
{ |
||||
|
OWI_PORT_POM |= (uint8_t)OWI_PIN_MASK; |
||||
|
OWI_PORT_P |= (uint8_t)OWI_PIN_MASK; |
||||
|
OWI_PORT_PM |= (uint8_t)OWI_PIN_MASK; |
||||
|
} |
||||
|
|
||||
|
int GPIO_Read(void) |
||||
|
{ |
||||
|
return (OWI_PORT_P & (uint8_t)OWI_PIN_MASK) ? 1 : 0; |
||||
|
} |
||||
|
|
||||
|
static void OWI_Release(void) |
||||
|
{ |
||||
|
OWI_PORT_POM |= (uint8_t)OWI_PIN_MASK; |
||||
|
OWI_PORT_P |= (uint8_t)OWI_PIN_MASK; |
||||
|
OWI_PORT_PM |= (uint8_t)OWI_PIN_MASK; |
||||
|
} |
||||
|
|
||||
|
static void GPIO_StrongDriveHighKick(uint32_t kick_us) |
||||
|
{ |
||||
|
OWI_Release(); |
||||
|
|
||||
|
if (!GPIO_Read()) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
OWI_PORT_POM &= (uint8_t)~OWI_PIN_MASK; |
||||
|
OWI_PORT_P |= (uint8_t)OWI_PIN_MASK; |
||||
|
OWI_PORT_PM &= (uint8_t)~OWI_PIN_MASK; |
||||
|
|
||||
|
delay_us(kick_us); |
||||
|
|
||||
|
OWI_PORT_POM |= (uint8_t)OWI_PIN_MASK; |
||||
|
OWI_Release(); |
||||
|
} |
||||
|
|
||||
|
void GPIO_ForceHighKick(void) |
||||
|
{ |
||||
|
GPIO_StrongDriveHighKick(OWI_STRONG_DRIVE_HIGH_US); |
||||
|
} |
||||
|
|
||||
|
static void OWI_DriveLow(void) |
||||
|
{ |
||||
|
OWI_PORT_POM |= (uint8_t)OWI_PIN_MASK; |
||||
|
OWI_PORT_P &= (uint8_t)~OWI_PIN_MASK; |
||||
|
OWI_PORT_PM &= (uint8_t)~OWI_PIN_MASK; |
||||
|
} |
||||
|
|
||||
|
/* =========================================================
|
||||
|
* Diagnostics |
||||
|
* ========================================================= */ |
||||
|
uint8_t OWI_HasTimeout(void) |
||||
|
{ |
||||
|
return g_owi_timeout_latched; |
||||
|
} |
||||
|
|
||||
|
void OWI_ClearTimeout(void) |
||||
|
{ |
||||
|
g_owi_timeout_latched = 0; |
||||
|
g_owi_last_timeout_byte_index = 0xFFFFu; |
||||
|
g_owi_last_timeout_bit_index = 0xFFu; |
||||
|
} |
||||
|
|
||||
|
uint16_t OWI_GetLastTimeoutByteIndex(void) |
||||
|
{ |
||||
|
return g_owi_last_timeout_byte_index; |
||||
|
} |
||||
|
|
||||
|
uint8_t OWI_GetLastTimeoutBitIndex(void) |
||||
|
{ |
||||
|
return g_owi_last_timeout_bit_index; |
||||
|
} |
||||
|
|
||||
|
/* =========================================================
|
||||
|
* OWI Init |
||||
|
* ========================================================= */ |
||||
|
void OWI_Init(uint32_t bit_time_us) |
||||
|
{ |
||||
|
bit_period_us = bit_time_us; |
||||
|
(void)bit_period_us; |
||||
|
|
||||
|
OWI_PORT_POM |= (uint8_t)OWI_PIN_MASK; |
||||
|
OWI_PORT_PU &= (uint8_t)~OWI_PIN_MASK; |
||||
|
|
||||
|
OWI_ClearTimeout(); |
||||
|
GPIO_Input(); |
||||
|
} |
||||
|
|
||||
|
/* =========================================================
|
||||
|
* Start/Stop/Secure |
||||
|
* ========================================================= */ |
||||
|
void OWI_Start(void) |
||||
|
{ |
||||
|
GPIO_Clear(); |
||||
|
delay_us(TSTART_HOLD); |
||||
|
|
||||
|
GPIO_Input(); |
||||
|
delay_us(TBIT); |
||||
|
} |
||||
|
|
||||
|
void OWI_Stop(void) |
||||
|
{ |
||||
|
GPIO_Input(); |
||||
|
delay_us(TSTOP_LOW); |
||||
|
delay_us(TIDLE); |
||||
|
} |
||||
|
|
||||
|
static void OWI_StopWrite(void) |
||||
|
{ |
||||
|
OWI_Release(); |
||||
|
delay_us(TSTOP_LOW); |
||||
|
delay_us(TIDLE); |
||||
|
} |
||||
|
|
||||
|
static void OWI_StopRead(void) |
||||
|
{ |
||||
|
OWI_DriveLow(); |
||||
|
delay_us(TSTOP_LOW); |
||||
|
OWI_Release(); |
||||
|
delay_us(TIDLE); |
||||
|
} |
||||
|
|
||||
|
static uint8_t OWI_WaitFirstBitStart(void) |
||||
|
{ |
||||
|
int timeout; |
||||
|
|
||||
|
timeout = (int)(bit_period_us * 4u); |
||||
|
|
||||
|
/* 첫 번째 HIGH->LOW 시작을 기다림 */ |
||||
|
while (GPIO_Read() && timeout-- > 0) { |
||||
|
delay_us(1u); |
||||
|
} |
||||
|
|
||||
|
if (timeout <= 0) { |
||||
|
if (!g_owi_timeout_latched) { |
||||
|
g_owi_timeout_latched = 1; |
||||
|
g_owi_last_timeout_byte_index = 0u; |
||||
|
g_owi_last_timeout_bit_index = 0u; |
||||
|
} |
||||
|
return 0u; |
||||
|
} |
||||
|
|
||||
|
return 1u; |
||||
|
} |
||||
|
|
||||
|
static uint8_t OWI_ReadByte_StreamSynced(uint16_t byte_index) |
||||
|
{ |
||||
|
uint8_t data = 0; |
||||
|
int b; |
||||
|
|
||||
|
for (b = 7; b >= 0; b--) { |
||||
|
uint8_t bit_index = (uint8_t)(7 - b); |
||||
|
uint8_t bit; |
||||
|
uint16_t edge_tick; |
||||
|
uint16_t edge_position; |
||||
|
|
||||
|
g_owi_current_read_byte_index = byte_index; |
||||
|
g_owi_current_read_bit_index = bit_index; |
||||
|
|
||||
|
if (!OWI_MeasureFallingEdge(g_owi_next_bit_start_tick, |
||||
|
byte_index, |
||||
|
bit_index, |
||||
|
&edge_tick)) { |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
edge_position = |
||||
|
(uint16_t)(edge_tick - g_owi_next_bit_start_tick); |
||||
|
|
||||
|
/*
|
||||
|
* OWI write timing is HIGH first and LOW second: |
||||
|
* 0: falling edge near TBIT/4 |
||||
|
* 1: falling edge near 3*TBIT/4 |
||||
|
*/ |
||||
|
bit = (edge_position < (uint16_t)(bit_period_us / 2u)) ? 0u : 1u; |
||||
|
data |= (uint8_t)(bit << b); |
||||
|
g_owi_next_bit_start_tick = |
||||
|
(uint16_t)(g_owi_next_bit_start_tick + |
||||
|
(uint16_t)bit_period_us); |
||||
|
} |
||||
|
|
||||
|
return data; |
||||
|
} |
||||
|
|
||||
|
void OWI_SecureStop(void) |
||||
|
{ |
||||
|
int i; |
||||
|
|
||||
|
GPIO_Clear(); |
||||
|
delay_us(SECURE_HIGH); |
||||
|
|
||||
|
for (i = 0; i < (int)SECURE_TOGGLE_COUNT; i++) { |
||||
|
GPIO_Input(); |
||||
|
delay_us(SECURE_TOGGLE_HIGH); |
||||
|
|
||||
|
GPIO_Clear(); |
||||
|
delay_us(SECURE_TOGGLE_LOW); |
||||
|
} |
||||
|
|
||||
|
GPIO_Input(); |
||||
|
delay_us(SECURE_HIGH); |
||||
|
|
||||
|
GPIO_Clear(); |
||||
|
delay_us(TSTART_HOLD); |
||||
|
GPIO_Input(); |
||||
|
} |
||||
|
|
||||
|
/* =========================================================
|
||||
|
* Bit/Byte IO |
||||
|
* ========================================================= */ |
||||
|
void OWI_WriteBit(int bit) |
||||
|
{ |
||||
|
uint32_t t_low = bit ? (uint32_t)TLOW_1 : (uint32_t)TLOW_0; |
||||
|
uint32_t t_high = (uint32_t)TBIT - t_low; |
||||
|
|
||||
|
/* HIGH 구간 */ |
||||
|
OWI_Release(); |
||||
|
delay_us(t_high); |
||||
|
|
||||
|
/* LOW 구간 */ |
||||
|
OWI_DriveLow(); |
||||
|
delay_us(t_low); |
||||
|
|
||||
|
/* 다음 슬롯 시작 전 반드시 release */ |
||||
|
OWI_Release(); |
||||
|
} |
||||
|
|
||||
|
void OWI_WriteByte(uint8_t data) |
||||
|
{ |
||||
|
int i; |
||||
|
for (i = 7; i >= 0; i--) { |
||||
|
OWI_WriteBit((data >> i) & 0x01u); |
||||
|
} |
||||
|
GPIO_Input(); |
||||
|
} |
||||
|
|
||||
|
uint8_t OWI_ReadBit(void) |
||||
|
{ |
||||
|
int timeout; |
||||
|
int low_width = 0; |
||||
|
|
||||
|
/* 1) 라인이 HIGH가 될 때까지 정리 */ |
||||
|
timeout = (int)(bit_period_us * 2u); |
||||
|
while (!GPIO_Read() && timeout-- > 0) { |
||||
|
delay_us(1u); |
||||
|
} |
||||
|
|
||||
|
if (timeout <= 0) { |
||||
|
if (!g_owi_timeout_latched) { |
||||
|
g_owi_timeout_latched = 1; |
||||
|
g_owi_last_timeout_byte_index = g_owi_current_read_byte_index; |
||||
|
g_owi_last_timeout_bit_index = g_owi_current_read_bit_index; |
||||
|
} |
||||
|
return 0u; |
||||
|
} |
||||
|
|
||||
|
/* 2) 다음 LOW 시작 대기 */ |
||||
|
timeout = (int)(bit_period_us * 2u); |
||||
|
while (GPIO_Read() && timeout-- > 0) { |
||||
|
delay_us(1u); |
||||
|
} |
||||
|
|
||||
|
if (timeout <= 0) { |
||||
|
if (!g_owi_timeout_latched) { |
||||
|
g_owi_timeout_latched = 1; |
||||
|
g_owi_last_timeout_byte_index = g_owi_current_read_byte_index; |
||||
|
g_owi_last_timeout_bit_index = g_owi_current_read_bit_index; |
||||
|
} |
||||
|
return 0u; |
||||
|
} |
||||
|
|
||||
|
/* 3) LOW가 유지되는 시간을 직접 측정 */ |
||||
|
while (!GPIO_Read() && low_width < (int)(bit_period_us * 2u)) { |
||||
|
delay_us(1u); |
||||
|
low_width++; |
||||
|
} |
||||
|
|
||||
|
/* 4) LOW 폭 기준으로 판정
|
||||
|
- 짧으면 1 |
||||
|
- 길면 0 |
||||
|
threshold ~= TBIT/2 |
||||
|
*/ |
||||
|
return (low_width < (int)(bit_period_us / 2u)) ? 1u : 0u; |
||||
|
} |
||||
|
|
||||
|
uint8_t OWI_ReadByte(void) |
||||
|
{ |
||||
|
uint8_t data = 0; |
||||
|
int i; |
||||
|
|
||||
|
for (i = 7; i >= 0; i--) { |
||||
|
g_owi_current_read_bit_index = (uint8_t)(7 - i); |
||||
|
data |= (uint8_t)(OWI_ReadBit() << i); |
||||
|
if (OWI_HasTimeout()) { |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
return data; |
||||
|
} |
||||
|
|
||||
|
/* =========================================================
|
||||
|
* Debug Print |
||||
|
* ========================================================= */ |
||||
|
void OWI_T_ReadBytesAndPrint(int length) |
||||
|
{ |
||||
|
uint8_t buf[129]; |
||||
|
int i; |
||||
|
char uart_buf[8]; |
||||
|
char tmp_buf[8]; |
||||
|
uint8_t va0, va1; |
||||
|
|
||||
|
if (length > 129) length = 129; |
||||
|
if (length <= 0) return; |
||||
|
|
||||
|
OWI_ClearTimeout(); |
||||
|
|
||||
|
for (i = 0; i < length; i++) { |
||||
|
R_WDT_Restart(); |
||||
|
g_owi_current_read_byte_index = (uint16_t)i; |
||||
|
buf[i] = OWI_ReadByte(); |
||||
|
if (OWI_HasTimeout()) { |
||||
|
i++; |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
sprintf(uart_buf, "%02X ", buf[0]); |
||||
|
strcpy(tmp_buf, uart_buf); |
||||
|
HOST_PRINT(tmp_buf); |
||||
|
|
||||
|
for (i = 1; i < length; i += 2) { |
||||
|
va0 = buf[i]; |
||||
|
va1 = (uint8_t)((i + 1 < length) ? buf[i + 1] : 0u); |
||||
|
|
||||
|
delay_us(200); |
||||
|
sprintf(uart_buf, "%02X%02X ", va0, va1); |
||||
|
strcpy(tmp_buf, uart_buf); |
||||
|
HOST_PRINT(tmp_buf); |
||||
|
delay_us(200); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/* =========================================================
|
||||
|
* Raw helpers |
||||
|
* ========================================================= */ |
||||
|
static void owi_result_init(owi_io_result_t *r) |
||||
|
{ |
||||
|
if (!r) return; |
||||
|
memset(r, 0, sizeof(*r)); |
||||
|
r->ok = 1; |
||||
|
r->timeout_byte_index = 0xFFFFu; |
||||
|
r->timeout_bit_index = 0xFFu; |
||||
|
} |
||||
|
|
||||
|
static void owi_result_latch_timeout(owi_io_result_t *r) |
||||
|
{ |
||||
|
if (!r) return; |
||||
|
|
||||
|
if (OWI_HasTimeout()) { |
||||
|
r->ok = 0; |
||||
|
r->timeout = 1; |
||||
|
r->timeout_byte_index = OWI_GetLastTimeoutByteIndex(); |
||||
|
r->timeout_bit_index = OWI_GetLastTimeoutBitIndex(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void OWI_T_CommandModeRaw(const uint8_t *tx_data, uint8_t tx_len, uint8_t id, owi_io_result_t *r) |
||||
|
{ |
||||
|
int i; |
||||
|
|
||||
|
owi_result_init(r); |
||||
|
|
||||
|
//delay_us(200);
|
||||
|
OWI_Init(OWI_BIT_PERIOD_US); |
||||
|
OWI_ClearTimeout(); |
||||
|
|
||||
|
R_WDT_Restart(); |
||||
|
OWI_SecureStop(); |
||||
|
R_WDT_Restart(); |
||||
|
OWI_WriteByte((uint8_t)(id << 1)); |
||||
|
R_WDT_Restart(); |
||||
|
|
||||
|
for (i = 0; i < (int)tx_len; i++) { |
||||
|
R_WDT_Restart(); |
||||
|
OWI_WriteByte(tx_data[i]); |
||||
|
R_WDT_Restart(); |
||||
|
} |
||||
|
|
||||
|
OWI_Stop(); |
||||
|
R_WDT_Restart(); |
||||
|
owi_result_latch_timeout(r); |
||||
|
} |
||||
|
|
||||
|
void OWI_CommandModeRaw(const uint8_t *tx_data, uint8_t tx_len, uint8_t id, owi_io_result_t *r) |
||||
|
{ |
||||
|
int i; |
||||
|
|
||||
|
owi_result_init(r); |
||||
|
OWI_Init(OWI_BIT_PERIOD_US); |
||||
|
OWI_ClearTimeout(); |
||||
|
|
||||
|
R_WDT_Restart(); |
||||
|
OWI_SecureStop(); |
||||
|
R_WDT_Restart(); |
||||
|
OWI_WriteByte((uint8_t)(id << 1)); |
||||
|
R_WDT_Restart(); |
||||
|
|
||||
|
for (i = 0; i < (int)tx_len; i++) { |
||||
|
R_WDT_Restart(); |
||||
|
OWI_WriteByte(tx_data[i]); |
||||
|
R_WDT_Restart(); |
||||
|
} |
||||
|
|
||||
|
OWI_Stop(); |
||||
|
R_WDT_Restart(); |
||||
|
owi_result_latch_timeout(r); |
||||
|
} |
||||
|
|
||||
|
void OWI_ReadBytesRaw(int length, uint8_t id, owi_io_result_t *r) |
||||
|
{ |
||||
|
int i; |
||||
|
int max_len; |
||||
|
|
||||
|
if (!r) return; |
||||
|
|
||||
|
owi_result_init(r); |
||||
|
OWI_Init(OWI_BIT_PERIOD_US); |
||||
|
|
||||
|
if (length <= 0) { |
||||
|
r->ok = 0; |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
max_len = (int)OWI_IO_MAX_BYTES; |
||||
|
if (length > max_len) { |
||||
|
length = max_len; |
||||
|
} |
||||
|
|
||||
|
r->read_len = (uint16_t)length; |
||||
|
OWI_ClearTimeout(); |
||||
|
|
||||
|
R_WDT_Restart(); |
||||
|
OWI_SecureStop(); |
||||
|
OWI_TimerStart1MHz(); |
||||
|
OWI_WriteByte((uint8_t)((id << 1) | 1u)); |
||||
|
|
||||
|
/*
|
||||
|
* OWI_WriteByte() returns at the end of the R bit. Each bit slot and its |
||||
|
* falling-edge position are measured from this absolute reference. |
||||
|
*/ |
||||
|
g_owi_next_bit_start_tick = OWI_TimerNow(); |
||||
|
|
||||
|
for (i = 0; i < length; i++) { |
||||
|
R_WDT_Restart(); |
||||
|
|
||||
|
r->data[i] = OWI_ReadByte_StreamSynced((uint16_t)i); |
||||
|
|
||||
|
if (OWI_HasTimeout()) { |
||||
|
owi_result_latch_timeout(r); |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
OWI_TimerStop(); |
||||
|
OWI_StopRead(); |
||||
|
} |
||||
|
|
||||
|
void OWI_disable(void) |
||||
|
{ |
||||
|
HOST_PRINT("51\r\n"); |
||||
|
} |
||||
|
|
||||
|
void OWI_T_CommandMode(const uint8_t *tx_data, uint8_t tx_len, uint8_t id) |
||||
|
{ |
||||
|
owi_io_result_t r; |
||||
|
(void)r; |
||||
|
|
||||
|
OWI_T_CommandModeRaw(tx_data, tx_len, id, &r); |
||||
|
HOST_PRINT("51\r\n"); |
||||
|
} |
||||
|
|
||||
|
void OWI_CommandMode(const uint8_t *tx_data, uint8_t tx_len, uint8_t id) |
||||
|
{ |
||||
|
owi_io_result_t r; |
||||
|
(void)r; |
||||
|
|
||||
|
OWI_CommandModeRaw(tx_data, tx_len, id, &r); |
||||
|
HOST_PRINT("51\r\n"); |
||||
|
} |
||||
|
|
||||
|
void OWI_ReadBytesAndPrint(int length, uint8_t id) |
||||
|
{ |
||||
|
owi_io_result_t r; |
||||
|
char out[(2 * OWI_IO_MAX_BYTES) + 40]; |
||||
|
int i; |
||||
|
uint16_t p = 0; |
||||
|
|
||||
|
if (length <= 0) { |
||||
|
HOST_PRINT("Err:read_len_nonzero\r\n"); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
OWI_ReadBytesRaw(length, id, &r); |
||||
|
|
||||
|
if (r.read_len == 0) { |
||||
|
HOST_PRINT("Err:read_len_nonzero\r\n"); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
for (i = 0; i < (int)r.read_len; i++) { |
||||
|
uint8_t b = r.data[i]; |
||||
|
out[p++] = "0123456789ABCDEF"[b >> 4]; |
||||
|
out[p++] = "0123456789ABCDEF"[b & 0x0F]; |
||||
|
} |
||||
|
|
||||
|
if (r.timeout) { |
||||
|
p += (uint16_t)sprintf(&out[p], " !TO(B%u b%u)", |
||||
|
(unsigned)r.timeout_byte_index, |
||||
|
(unsigned)r.timeout_bit_index); |
||||
|
} |
||||
|
|
||||
|
out[p++] = '\r'; |
||||
|
out[p++] = '\n'; |
||||
|
out[p] = '\0'; |
||||
|
|
||||
|
HOST_PRINT(out); |
||||
|
} |
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
File diff suppressed because it is too large
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,181 @@ |
|||||
|
#include "app_cmd_parser.h" |
||||
|
#include <string.h> |
||||
|
#include <ctype.h> |
||||
|
|
||||
|
static int parse_x_v_addr(const char *line, uint8_t *addr) |
||||
|
{ |
||||
|
if (!line || !addr) return 0; |
||||
|
if (!(line[0] == 'x' || line[0] == 'X')) return 0; |
||||
|
if (!isdigit((unsigned char)line[1]) || !isdigit((unsigned char)line[2])) return 0; |
||||
|
if (!(line[3] == 'v' || line[3] == 'V')) return 0; |
||||
|
if (line[4] != '\0') return 0; |
||||
|
|
||||
|
*addr = (uint8_t)((line[1] - '0') * 10 + (line[2] - '0')); |
||||
|
return 1; |
||||
|
} |
||||
|
|
||||
|
static int find_payload_pos(const char *line) |
||||
|
{ |
||||
|
const char *p = strchr(line, ':'); |
||||
|
if (!p) return -1; |
||||
|
return (int)(p - line + 1); |
||||
|
} |
||||
|
|
||||
|
static uint8_t hex_nibble(char c) |
||||
|
{ |
||||
|
c = (char)toupper((unsigned char)c); |
||||
|
if (c >= '0' && c <= '9') return (uint8_t)(c - '0'); |
||||
|
if (c >= 'A' && c <= 'F') return (uint8_t)(10 + (c - 'A')); |
||||
|
return 0xFFu; |
||||
|
} |
||||
|
|
||||
|
static int hex_pair_to_u8(char hi, char lo, uint8_t *out) |
||||
|
{ |
||||
|
uint8_t h = hex_nibble(hi); |
||||
|
uint8_t l = hex_nibble(lo); |
||||
|
if (h == 0xFFu || l == 0xFFu || !out) return 0; |
||||
|
*out = (uint8_t)((h << 4) | l); |
||||
|
return 1; |
||||
|
} |
||||
|
|
||||
|
int app_cmd_parse_line(app_cmd_src_t src, const char *line, app_job_t *job) |
||||
|
{ |
||||
|
uint8_t addr = 0; |
||||
|
int payload_pos; |
||||
|
int len; |
||||
|
int pos; |
||||
|
unsigned int k; |
||||
|
|
||||
|
if (!line || !job) return 0; |
||||
|
|
||||
|
memset(job, 0, sizeof(*job)); |
||||
|
job->src = src; |
||||
|
job->check_on = 1; |
||||
|
|
||||
|
/* ?? ?? ?? ?? */ |
||||
|
strncpy(job->line, line, sizeof(job->line) - 1); |
||||
|
job->line[sizeof(job->line) - 1] = '\0'; |
||||
|
|
||||
|
len = (int)strlen(line); |
||||
|
|
||||
|
/* ?? ??*/ |
||||
|
if (line[0] != 'x' && line[0] != 'X') { |
||||
|
job->type = APP_JOB_LOCAL_EXEC; |
||||
|
strncpy(job->line, line, sizeof(job->line) - 1); |
||||
|
job->line[sizeof(job->line) - 1] = '\0'; |
||||
|
return 1; |
||||
|
} |
||||
|
|
||||
|
/* xNNv */ |
||||
|
if (parse_x_v_addr(line, &addr)) { |
||||
|
job->type = APP_JOB_SCAN_ADDR; |
||||
|
job->addr = addr; |
||||
|
|
||||
|
strncpy(job->line, line, sizeof(job->line) - 1); |
||||
|
job->line[sizeof(job->line) - 1] = '\0'; |
||||
|
|
||||
|
return 1; |
||||
|
} |
||||
|
|
||||
|
payload_pos = find_payload_pos(line); |
||||
|
if (payload_pos < 0) { |
||||
|
job->type = APP_JOB_FORWARD_LINE; |
||||
|
strncpy(job->line, line, sizeof(job->line) - 1); |
||||
|
job->line[sizeof(job->line) - 1] = '\0'; |
||||
|
return 1; |
||||
|
} |
||||
|
|
||||
|
if (len < payload_pos) return 0; |
||||
|
if (!isdigit((unsigned char)line[1]) || !isdigit((unsigned char)line[2])) return 0; |
||||
|
|
||||
|
job->addr = (uint8_t)((line[1] - '0') * 10 + (line[2] - '0')); |
||||
|
|
||||
|
/* xNNc_001101:... ±âÁØ¿¡¼ channel = 001 */ |
||||
|
if (payload_pos >= 8 && |
||||
|
isdigit((unsigned char)line[5]) && |
||||
|
isdigit((unsigned char)line[6]) && |
||||
|
isdigit((unsigned char)line[7])) { |
||||
|
job->channel = (uint8_t)((line[5] - '0') * 100 + |
||||
|
(line[6] - '0') * 10 + |
||||
|
(line[7] - '0')); |
||||
|
} |
||||
|
|
||||
|
job->mode = (char)toupper((unsigned char)line[3]); |
||||
|
|
||||
|
if (payload_pos >= 11) { |
||||
|
job->hash_on = (uint8_t)(line[8] == '1'); |
||||
|
job->anaout_on = (uint8_t)(line[9] == '1'); |
||||
|
job->check_on = (uint8_t)(line[10] == '1'); |
||||
|
} |
||||
|
|
||||
|
pos = payload_pos; |
||||
|
if (pos + 1 >= len) return 0; |
||||
|
|
||||
|
if ((line[pos] == 'o' || line[pos] == 'O') && |
||||
|
(line[pos + 1] == 'w' || line[pos + 1] == 'W')) { |
||||
|
job->type = APP_JOB_PROTO_OW; |
||||
|
pos += 2; |
||||
|
|
||||
|
if (pos < len && (line[pos] == 't' || line[pos] == 'T')) { |
||||
|
job->proto = APP_PROTO_OWIT; |
||||
|
pos++; |
||||
|
} else { |
||||
|
job->proto = APP_PROTO_OWIW; |
||||
|
} |
||||
|
} |
||||
|
else if ((line[pos] == 'o' || line[pos] == 'O') && |
||||
|
(line[pos + 1] == 'r' || line[pos + 1] == 'R')) { |
||||
|
job->type = APP_JOB_PROTO_OR; |
||||
|
job->proto = APP_PROTO_OWIR; |
||||
|
pos += 2; |
||||
|
} |
||||
|
else { |
||||
|
job->type = APP_JOB_FORWARD_LINE; |
||||
|
strncpy(job->line, line, sizeof(job->line) - 1); |
||||
|
job->line[sizeof(job->line) - 1] = '\0'; |
||||
|
return 1; |
||||
|
} |
||||
|
|
||||
|
if (pos < len && (line[pos] == '_' || line[pos] == ':')) pos++; |
||||
|
|
||||
|
if (pos + 1 >= len) return 0; |
||||
|
if (!hex_pair_to_u8(line[pos], line[pos + 1], &job->id)) return 0; |
||||
|
pos += 2; |
||||
|
|
||||
|
if (pos + 2 >= len || |
||||
|
!isdigit((unsigned char)line[pos]) || |
||||
|
!isdigit((unsigned char)line[pos + 1]) || |
||||
|
!isdigit((unsigned char)line[pos + 2])) { |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
job->len = (uint16_t)(100 * (line[pos] - '0') + |
||||
|
10 * (line[pos + 1] - '0') + |
||||
|
(line[pos + 2] - '0')); |
||||
|
pos += 3; |
||||
|
|
||||
|
if (job->type == APP_JOB_PROTO_OW) { |
||||
|
if (job->len == 0 || job->len > APP_JOB_PAYLOAD_MAX) return 0; |
||||
|
if (pos + ((int)job->len * 2) > len) return 0; |
||||
|
|
||||
|
for (k = 0; k < job->len; k++) { |
||||
|
if (!hex_pair_to_u8(line[pos + (int)(2 * k)], |
||||
|
line[pos + (int)(2 * k + 1)], |
||||
|
&job->payload[k])) { |
||||
|
return 0; |
||||
|
} |
||||
|
} |
||||
|
pos += (int)job->len * 2; |
||||
|
|
||||
|
/* payload ?? ??? ? ??? parse ?? */ |
||||
|
if (pos != len) return 0; |
||||
|
|
||||
|
} else { |
||||
|
if (job->len == 0 || job->len > APP_JOB_PAYLOAD_MAX) return 0; |
||||
|
|
||||
|
/* OR? payload? ??? ??? len ?? ?? ??? ? */ |
||||
|
if (pos != len) return 0; |
||||
|
} |
||||
|
|
||||
|
return 1; |
||||
|
} |
||||
@ -0,0 +1,8 @@ |
|||||
|
#ifndef APP_CMD_PARSER_H |
||||
|
#define APP_CMD_PARSER_H |
||||
|
|
||||
|
#include "app_types.h" |
||||
|
|
||||
|
int app_cmd_parse_line(app_cmd_src_t src, const char *line, app_job_t *job); |
||||
|
|
||||
|
#endif |
||||
@ -0,0 +1,221 @@ |
|||||
|
#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); |
||||
|
} |
||||
@ -0,0 +1,20 @@ |
|||||
|
#ifndef APP_OWI_SERVICE_H |
||||
|
#define APP_OWI_SERVICE_H |
||||
|
|
||||
|
#include "r_cg_macrodriver.h" |
||||
|
#include "owi.h" |
||||
|
|
||||
|
typedef struct { |
||||
|
uint8_t ok; |
||||
|
uint8_t timeout; |
||||
|
uint16_t read_len; |
||||
|
uint8_t data[OWI_IO_MAX_BYTES]; |
||||
|
uint16_t timeout_byte_index; |
||||
|
uint8_t timeout_bit_index; |
||||
|
} app_owi_result_t; |
||||
|
|
||||
|
app_owi_result_t app_owi_read_basic(uint8_t id, int length); |
||||
|
app_owi_result_t app_owi_write_basic(uint8_t id, const uint8_t *tx_data, uint8_t tx_len); |
||||
|
app_owi_result_t app_owi_write_t_basic(uint8_t id, const uint8_t *tx_data, uint8_t tx_len); |
||||
|
|
||||
|
#endif |
||||
@ -0,0 +1,12 @@ |
|||||
|
#include "app_result.h" |
||||
|
#include "uart.h" |
||||
|
|
||||
|
void app_result_print_ok(const char *msg) |
||||
|
{ |
||||
|
uart1_send_string(msg); |
||||
|
} |
||||
|
|
||||
|
void app_result_print_err(const char *msg) |
||||
|
{ |
||||
|
uart1_send_string(msg); |
||||
|
} |
||||
@ -0,0 +1,7 @@ |
|||||
|
#ifndef APP_RESULT_H |
||||
|
#define APP_RESULT_H |
||||
|
|
||||
|
void app_result_print_ok(const char *msg); |
||||
|
void app_result_print_err(const char *msg); |
||||
|
|
||||
|
#endif |
||||
@ -0,0 +1,51 @@ |
|||||
|
#include "app_scheduler.h" |
||||
|
#include <string.h> |
||||
|
|
||||
|
#define APP_JOB_QUEUE_SIZE 8 |
||||
|
|
||||
|
static app_job_t g_queue[APP_JOB_QUEUE_SIZE]; |
||||
|
static uint8_t g_head; |
||||
|
static uint8_t g_tail; |
||||
|
static uint8_t g_count; |
||||
|
|
||||
|
void app_scheduler_init(void) |
||||
|
{ |
||||
|
g_head = 0; |
||||
|
g_tail = 0; |
||||
|
g_count = 0; |
||||
|
memset(g_queue, 0, sizeof(g_queue)); |
||||
|
} |
||||
|
|
||||
|
int app_scheduler_push(const app_job_t *job) |
||||
|
{ |
||||
|
if (!job) return 0; |
||||
|
if (g_count >= APP_JOB_QUEUE_SIZE) return 0; |
||||
|
|
||||
|
g_queue[g_tail] = *job; |
||||
|
g_tail = (uint8_t)((g_tail + 1U) % APP_JOB_QUEUE_SIZE); |
||||
|
g_count++; |
||||
|
return 1; |
||||
|
} |
||||
|
|
||||
|
int app_scheduler_pop(app_job_t *job) |
||||
|
{ |
||||
|
if (!job) return 0; |
||||
|
if (g_count == 0) return 0; |
||||
|
|
||||
|
*job = g_queue[g_head]; |
||||
|
g_head = (uint8_t)((g_head + 1U) % APP_JOB_QUEUE_SIZE); |
||||
|
g_count--; |
||||
|
return 1; |
||||
|
} |
||||
|
|
||||
|
int app_scheduler_is_empty(void) |
||||
|
{ |
||||
|
return (g_count == 0U); |
||||
|
} |
||||
|
void app_scheduler_clear(void) |
||||
|
{ |
||||
|
g_head = 0; |
||||
|
g_tail = 0; |
||||
|
g_count = 0; |
||||
|
memset(g_queue, 0, sizeof(g_queue)); |
||||
|
} |
||||
@ -0,0 +1,12 @@ |
|||||
|
#ifndef APP_SCHEDULER_H |
||||
|
#define APP_SCHEDULER_H |
||||
|
|
||||
|
#include "app_types.h" |
||||
|
|
||||
|
void app_scheduler_init(void); |
||||
|
int app_scheduler_push(const app_job_t *job); |
||||
|
int app_scheduler_pop(app_job_t *job); |
||||
|
int app_scheduler_is_empty(void); |
||||
|
void app_scheduler_clear(void); |
||||
|
|
||||
|
#endif |
||||
@ -0,0 +1,51 @@ |
|||||
|
|
||||
|
#ifndef APP_TYPES_H |
||||
|
#define APP_TYPES_H |
||||
|
|
||||
|
#include "r_cg_macrodriver.h" |
||||
|
|
||||
|
#define APP_JOB_PAYLOAD_MAX 320 |
||||
|
#define APP_JOB_LINE_MAX 320 |
||||
|
|
||||
|
typedef enum { |
||||
|
APP_CMD_SRC_PC = 0, |
||||
|
APP_CMD_SRC_RS485 = 1 |
||||
|
} app_cmd_src_t; |
||||
|
|
||||
|
typedef enum { |
||||
|
APP_JOB_NONE = 0, |
||||
|
APP_JOB_SCAN_ADDR, |
||||
|
APP_JOB_PROTO_OW, |
||||
|
APP_JOB_PROTO_OR, |
||||
|
APP_JOB_FORWARD_LINE, |
||||
|
APP_JOB_LOCAL_EXEC |
||||
|
} app_job_type_t; |
||||
|
|
||||
|
typedef enum { |
||||
|
APP_PROTO_NONE = 0, |
||||
|
APP_PROTO_OWIW, |
||||
|
APP_PROTO_OWIT, |
||||
|
APP_PROTO_OWIR |
||||
|
} app_proto_t; |
||||
|
|
||||
|
typedef struct { |
||||
|
app_job_type_t type; |
||||
|
app_cmd_src_t src; |
||||
|
|
||||
|
uint8_t addr; |
||||
|
uint8_t channel; |
||||
|
char mode; |
||||
|
uint8_t hash_on; |
||||
|
uint8_t anaout_on; |
||||
|
uint8_t check_on; |
||||
|
|
||||
|
app_proto_t proto; |
||||
|
uint8_t id; |
||||
|
uint16_t len; |
||||
|
uint8_t payload[APP_JOB_PAYLOAD_MAX]; |
||||
|
|
||||
|
/* fallback¿ë ªÀº line¸¸ º¸°ü */ |
||||
|
char line[APP_JOB_LINE_MAX]; |
||||
|
} app_job_t; |
||||
|
|
||||
|
#endif |
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Loading…
Reference in new issue