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.
 
 

480 lines
11 KiB

#include "owi.h"
#include "delay.h"
#include <string.h>
#include <stdio.h>
#include "uart.h"
#ifndef OWI_STRONG_DRIVE_HIGH_US
#define OWI_STRONG_DRIVE_HIGH_US 5u /* 5~20us 정도로 시작해서 튜닝 */
#endif
/* 내부 상태 */
static uint32_t bit_period_us = OWI_BIT_PERIOD_US;
static uint8_t g_owi_timeout_latched = 0;
/* =========================================================
* GPIO helpers (P70 / HW Open-Drain)
* - LOW : 출력 모드 + 0
* - HIGH : 입력(Hi-Z)로 release (pull-up으로 상승)
* ========================================================= */
void GPIO_Clear(void)
{
/* open-drain ON 보장 */
OWI_PORT_POM |= (uint8_t)OWI_PIN_MASK;
/* latch low */
OWI_PORT_P &= (uint8_t)~OWI_PIN_MASK;
/* output */
OWI_PORT_PM &= (uint8_t)~OWI_PIN_MASK;
}
void GPIO_Input(void)
{
OWI_PORT_POM |= OWI_PIN_MASK; // ★ 반드시
OWI_PORT_P |= OWI_PIN_MASK; // latch HIGH
OWI_PORT_PM |= OWI_PIN_MASK;
}
int GPIO_Read(void)
{
return (OWI_PORT_P & (uint8_t)OWI_PIN_MASK) ? 1 : 0;
}
void OWI_Release(void)
{
/* open-drain ON */
OWI_PORT_POM |= (uint8_t)OWI_PIN_MASK;
/* latch high (release 상태에서 깔끔) */
OWI_PORT_P |= (uint8_t)OWI_PIN_MASK;
/* input = Hi-Z */
OWI_PORT_PM |= (uint8_t)OWI_PIN_MASK;
}
static void GPIO_StrongDriveHighKick(uint32_t kick_us)
{
/* 1) 우선 release 상태로 */
OWI_Release();
/* 2) 라인이 LOW면(누가 당기면) 강제 HIGH 금지 */
if (!GPIO_Read()) {
return;
}
/* 3) 오픈드레인 OFF -> push-pull */
OWI_PORT_POM &= (uint8_t)~OWI_PIN_MASK;
/* 4) 출력 HIGH로 강하게 밀어올림 */
OWI_PORT_P |= (uint8_t)OWI_PIN_MASK; /* latch high */
OWI_PORT_PM &= (uint8_t)~OWI_PIN_MASK; /* output */
delay_us(kick_us);
/* 5) 다시 오픈드레인 ON + release(Hi-Z) */
OWI_PORT_POM |= (uint8_t)OWI_PIN_MASK;
OWI_Release();
}
void GPIO_ForceHighKick(void)
{
GPIO_StrongDriveHighKick(OWI_STRONG_DRIVE_HIGH_US);
}
void OWI_DriveLow(void)
{
/* open-drain ON */
OWI_PORT_POM |= (uint8_t)OWI_PIN_MASK;
/* latch low */
OWI_PORT_P &= (uint8_t)~OWI_PIN_MASK;
/* output */
OWI_PORT_PM &= (uint8_t)~OWI_PIN_MASK;
}
/* =========================================================
* OWI Init
* ========================================================= */
void OWI_Init(uint32_t bit_time_us)
{
bit_period_us = bit_time_us;
(void)bit_period_us; /* 현재 타이밍은 매크로(TBIT) 사용 */
/* HW Open-Drain enable: P70만 */
OWI_PORT_POM |= (uint8_t)OWI_PIN_MASK;
/* 내부 Pull-up: 필요 시 사용(외부 풀업이면 꺼도 됨) */
//OWI_PORT_PU |= (uint8_t)OWI_PIN_MASK;
OWI_PORT_PU &= (uint8_t)~OWI_PIN_MASK; // P70만 OFF
/* idle = release */
GPIO_Input();
}
/* =========================================================
* Start/Stop/Secure
* ========================================================= */
void OWI_Start(void)
{
GPIO_Clear();
delay_us(TSTART_HOLD);
GPIO_Input();
GPIO_StrongDriveHighKick(OWI_STRONG_DRIVE_HIGH_US);
delay_us(TBIT);
}
void OWI_Stop(void)
{
GPIO_Input();
delay_us(TSTOP_LOW);
delay_us(TIDLE);
//GPIO_Clear();
}
/* =========================================================
* Stop conditions
* - Write stop : keep line HIGH (release) for tOWI_STOP
* - Read stop : clamp line LOW for tOWI_STOP to terminate slave response loop
* ========================================================= */
static void OWI_StopWrite(void)
{
/* Request 종료: HIGH 고정(Release) */
OWI_Release();
delay_us(TSTOP_LOW); /* tOWI_STOP (>= 2*TBIT 권장) */
delay_us(TIDLE); /* bus free time */
}
static void OWI_StopRead(void)
{
/* Response 종료: 마스터가 LOW로 클램프해서 stop 생성 */
OWI_DriveLow();
delay_us(TSTOP_LOW); /* tOWI_STOP */
OWI_Release();
delay_us(TIDLE);
}
void OWI_SecureStop(void)
{
int i;
GPIO_Clear();
delay_us(SECURE_HIGH);
for (i = 0; i < (int)SECURE_TOGGLE_COUNT; i++) {
/* HIGH 구간: release + strong kick */
GPIO_Input();
delay_us(SECURE_TOGGLE_HIGH);
//GPIO_ForceHighKick();
// if (SECURE_TOGGLE_HIGH > OWI_STRONG_HIGH_US) {
// delay_us(SECURE_TOGGLE_HIGH - OWI_STRONG_HIGH_US);
// }
/* LOW 구간 */
GPIO_Clear();
delay_us(SECURE_TOGGLE_LOW);
}
/* 마지막 HIGH */
GPIO_Input();
GPIO_ForceHighKick();
if (SECURE_HIGH > OWI_STRONG_HIGH_US) {
delay_us(SECURE_HIGH - OWI_STRONG_HIGH_US);
}
/* 이어서 기존 시퀀스 유지 */
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();
/* (선택) HIGH 초반에만 아주 짧게 킥 */
GPIO_StrongDriveHighKick(5u);
/* 나머지 HIGH 시간 */
if (t_high > 5u) delay_us(t_high - 5u);
/* LOW 구간 */
OWI_DriveLow();
delay_us(t_low);
}
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)
{
uint8_t bit;
int timeout = (int)(bit_period_us * 2u);
while (!(GPIO_Read()) && timeout-- > 0) {
delay_us(1);
}
if (timeout <= 0) {
if (!g_owi_timeout_latched) {
HOST_PRINT("OWI Timeout\r\n");
g_owi_timeout_latched = 1;
}
return 0xFF;
}
delay_us((bit_period_us * 1u) / 2u);
bit = (uint8_t)GPIO_Read();
delay_us((bit_period_us * 2u) / 5u);
return bit;
}
uint8_t OWI_ReadByte(void)
{
uint8_t data = 0;
int i;
for (i = 7; i >= 0; i--) {
data |= (uint8_t)(OWI_ReadBit() << i);
}
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;
for (i = 0; i < length; i++) {
buf[i] = OWI_ReadByte();
}
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 = buf[i + 1];
delay(10000);
sprintf(uart_buf, "%02X%02X ", va0, va1);
strcpy(tmp_buf, uart_buf);
HOST_PRINT(tmp_buf);
delay(10000);
}
}
/* =========================================================
* Command / Diagnostic (네 로직 유지)
* ========================================================= */
#define OWI_MAX_RETRY 2
#define OWI_RECOVERY_MIN_US 500
void OWI_A_CommandMode(const uint8_t *tx_data, uint8_t tx_len, uint8_t id)
{
uint8_t CMD_LIST[6][4] = {
{0x50,0x2E,0x00,0x00},
{0x50,0x2E,0x01,0x00},
{0x50,0x2E,0x02,0x00},
{0x50,0x2E,0x16,0x00},
{0x50,0x2E,0x41,0x00},
{0x50,0x2E,0x00,0x00}
};
char line[128];
size_t n = 0;
uint8_t rx[RAM_BYTES];
int i, j, retry, all_ff;
uint8_t read_address = 0x51;
delay_us(7000);
for (j = 0; j < 6; j++) {
OWI_SecureStop();
for (i = 0; i < 4; i++) {
OWI_WriteByte(CMD_LIST[j][i]);
}
OWI_Stop();
delay_us(OWI_RECOVERY_MIN_US);
for (i = 0; i < RAM_BYTES; i++) rx[i] = 0xFF;
for (retry = 0; retry <= OWI_MAX_RETRY; retry++) {
delay_us(OWI_RECOVERY_MIN_US);
OWI_SecureStop();
OWI_WriteByte(read_address);
for (i = 0; i < RAM_BYTES; i++) rx[i] = OWI_ReadByte();
OWI_Stop();
all_ff = 1;
for (i = 0; i < RAM_BYTES; i++) {
if (rx[i] != 0xFF) { all_ff = 0; break; }
}
if (!all_ff) break;
if (retry == OWI_MAX_RETRY) {
return;
}
}
n += sprintf(&line[n], "%02X%02X", rx[1], rx[2]);
line[n++] = ',';
}
if (tx_data != NULL && tx_len == 3) {
for (retry = 0; retry <= OWI_MAX_RETRY; retry++) {
OWI_SecureStop();
OWI_WriteByte((uint8_t)(id << 1));
for (i = 0; i < 3; i++) {
OWI_WriteByte(tx_data[i]);
}
OWI_Stop();
delay_us(OWI_RECOVERY_MIN_US);
for (i = 0; i < RAM_BYTES; i++) rx[i] = 0xFF;
OWI_SecureStop();
OWI_WriteByte((uint8_t)((id << 1) | 1u));
for (i = 0; i < RAM_BYTES; i++) {
rx[i] = OWI_ReadByte();
}
OWI_Stop();
all_ff = 1;
for (i = 0; i < RAM_BYTES; i++) {
if (rx[i] != 0xFF) { all_ff = 0; break; }
}
if (!all_ff) break;
if (retry == OWI_MAX_RETRY) {
return;
}
}
n += sprintf(&line[n], "%02X%02X", rx[1], rx[2]);
} else {
n += sprintf(&line[n], "0000");
}
line[n++] = '\r';
line[n++] = '\n';
line[n] = '\0';
HOST_PRINT(line);
delay(10000);
}
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)
{
int i;
delay_us(10000);
OWI_Init(OWI_BIT_PERIOD_US);
OWI_SecureStop();
OWI_WriteByte((uint8_t)(id << 1));
for (i = 0; i < (int)tx_len; i++) {
OWI_WriteByte(tx_data[i]);
}
OWI_Stop();
HOST_PRINT("51\r\n");
}
void OWI_CommandMode(const uint8_t *tx_data, uint8_t tx_len, uint8_t id)
{
int i;
OWI_SecureStop();
OWI_WriteByte((uint8_t)(id << 1));
for (i = 0; i < (int)tx_len; i++) {
OWI_WriteByte(tx_data[i]);
}
OWI_Stop();
HOST_PRINT("51\r\n");
}
void OWI_ReadBytesAndPrint(int length, uint8_t id)
{
static uint8_t buf[600];
static char out[2*600 + 3];
int i;
uint16_t p = 0;
if (length <= 0) {
HOST_PRINT("Err:read_len_nonzero\r\n");
return;
}
if (length > 600) length = 600;
g_owi_timeout_latched = 0;
OWI_SecureStop();
OWI_WriteByte((uint8_t)((id << 1) | 1u));
for (i = 0; i < length; i++) {
buf[i] = OWI_ReadByte();
}
for (i = 0; i < length; i++) {
uint8_t b = buf[i];
out[p++] = "0123456789ABCDEF"[b >> 4];
out[p++] = "0123456789ABCDEF"[b & 0x0F];
}
out[p++] = '\r';
out[p++] = '\n';
out[p] = '\0';
OWI_StopRead();
HOST_PRINT(out);
}