413 lines
11 KiB
C
413 lines
11 KiB
C
#include "erpc_core.h"
|
||
#include "crc16.h"
|
||
#include "string.h"
|
||
void cal_crc16(erpc_msg_t *msg)
|
||
{
|
||
u16 crc = 0;
|
||
crc = crc16_cal(msg->src_id, crc);
|
||
crc = crc16_cal(msg->dest_id, crc);
|
||
crc = crc16_cal(msg->type, crc);
|
||
crc = crc16_cal(msg->len, crc);
|
||
for (int i = 0; i < msg->len; i++)
|
||
{
|
||
crc = crc16_cal(msg->data[i], crc);
|
||
}
|
||
msg->crc = crc;
|
||
}
|
||
u8 check_crc16(erpc_msg_t *msg)
|
||
{
|
||
u16 crc = 0;
|
||
crc = crc16_cal(msg->src_id, crc);
|
||
crc = crc16_cal(msg->dest_id, crc);
|
||
crc = crc16_cal(msg->type, crc);
|
||
crc = crc16_cal(msg->len, crc);
|
||
for (int i = 0; i < msg->len; i++)
|
||
{
|
||
crc = crc16_cal(msg->data[i], crc);
|
||
}
|
||
return crc == msg->crc;
|
||
}
|
||
|
||
static erpc_cache_t *find_free_cache(erpc_hw_t *hw)
|
||
{
|
||
for (int i = 0; i < ERPC_MSG_CACHE_SIZE; i++)
|
||
{
|
||
|
||
if (hw->send_cache[i].state == CACHE_FREE)
|
||
{
|
||
return &hw->send_cache[i];
|
||
}
|
||
}
|
||
return NULL;
|
||
}
|
||
// static erpc_cache_t *clean_ack_cache(erpc_hw_t *hw, u8 dest_id)
|
||
// {
|
||
// return NULL;
|
||
// }
|
||
static erpc_cache_t *find_ack_cache(erpc_hw_t *hw, u8 dest_id, u16 port)
|
||
{
|
||
for (int i = 0; i < ERPC_MSG_CACHE_SIZE; i++)
|
||
{
|
||
erpc_cache_t *cache = &hw->send_cache[i];
|
||
if (cache->state == CACHE_REC_ACK && cache->msg.src_id == dest_id && cache->msg.port == port)
|
||
{
|
||
return cache;
|
||
}
|
||
}
|
||
return NULL;
|
||
}
|
||
static u8 check_port_send_available(erpc_hw_t *hw, u8 port)
|
||
{
|
||
for (int i = 0; i < ERPC_MSG_CACHE_SIZE; i++)
|
||
{
|
||
erpc_cache_t *cache = &hw->send_cache[i];
|
||
if (cache->state != CACHE_FREE)
|
||
{
|
||
if (cache->msg.port == port)
|
||
{
|
||
return 0;
|
||
}
|
||
}
|
||
}
|
||
return 1;
|
||
}
|
||
static void free_port_ack_cache(erpc_hw_t *hw, u16 port)
|
||
{
|
||
for (int i = 0; i < ERPC_MSG_CACHE_SIZE; i++)
|
||
{
|
||
erpc_cache_t *cache = &hw->recv_cache[i];
|
||
if (cache->state == CACHE_REC_ACK)
|
||
{
|
||
if (cache->msg.port == port)
|
||
{
|
||
cache->state = CACHE_FREE;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
static u32 send_data(erpc_hw_t *hw, erpc_cache_t *cache, u16 port, u16 *timeout)
|
||
{
|
||
free_port_ack_cache(hw, port);
|
||
cache->state = CACHE_WAIT_SEND;
|
||
// 等待发送完成
|
||
while (*timeout)
|
||
{
|
||
if (cache->state == CACHE_SEND_OK)
|
||
{
|
||
return 0;
|
||
}
|
||
else if (cache->state == CACHE_SEND_HW_ERR)
|
||
{
|
||
return ERPC_ERR_SEND_HW_ERR;
|
||
}
|
||
else
|
||
{
|
||
hw->sleep(1);
|
||
}
|
||
(*timeout)--;
|
||
}
|
||
|
||
if (*timeout == 0)
|
||
{
|
||
return ERPC_ERR_SEND_TIMEOUT;
|
||
}
|
||
return 0;
|
||
}
|
||
static u32 wait_ack(erpc_hw_t *hw, erpc_cache_t *rec, u8 dest_id, u16 port, u16 *timeout)
|
||
{
|
||
while (*timeout)
|
||
{
|
||
rec = find_ack_cache(hw, dest_id, port);
|
||
if (rec != NULL)
|
||
{
|
||
return 0;
|
||
}
|
||
hw->sleep(1);
|
||
(*timeout)--;
|
||
}
|
||
if (timeout == 0)
|
||
{
|
||
return ERPC_ERR_SEND_ACK_TIMEOUT;
|
||
}
|
||
return 0;
|
||
}
|
||
u32 send_request(erpc_hw_t *hw, u8 dest_id, u16 port, u8 *data, u16 len, u16 timeout, u8 retry)
|
||
{
|
||
erpc_cache_t *cache = find_free_cache(hw);
|
||
CHECK_DEAL(cache == NULL, ERPC_ERR_NO_FREE_SEND_CACHE);
|
||
hw->lock();
|
||
if (check_port_send_available(hw, port) == 0)
|
||
{
|
||
hw->unlock();
|
||
return ERPC_ERR_SEND_PORT_IS_INUSE;
|
||
}
|
||
cache->msg.dest_id = dest_id;
|
||
cache->state = CACHE_IN_USE;
|
||
hw->unlock();
|
||
cache->msg.src_id = hw->local_id;
|
||
cache->msg.type = ERPC_MSG_TYPE_REQUEST;
|
||
cache->msg.len = len;
|
||
cache->msg.port = port;
|
||
memcpy(cache->msg.data, data, len);
|
||
cal_crc16(&cache->msg);
|
||
erpc_cache_t *rec = NULL;
|
||
u16 timeout_copy = timeout;
|
||
while (retry--)
|
||
{
|
||
/**
|
||
* 发送失败应该立即返回,不能retry
|
||
*/
|
||
u32 ret = send_data(hw, cache, port, &timeout);
|
||
if (ret)
|
||
{
|
||
cache->state = CACHE_FREE;
|
||
return ret;
|
||
}
|
||
// 等待ack
|
||
ret = wait_ack(hw, rec, dest_id, port, &timeout);
|
||
if (ret == 0)
|
||
{
|
||
break;
|
||
}
|
||
timeout = timeout_copy;
|
||
}
|
||
CHECK_DEAL(retry == 0, ERPC_ERR_SEND_ACK_TIMEOUT);
|
||
// 释放cache
|
||
cache->state = CACHE_FREE;
|
||
rec->state = CACHE_FREE;
|
||
return 0;
|
||
}
|
||
|
||
static erpc_cache_t *find_response_cache(erpc_hw_t *hw, u8 dest_id, u16 port)
|
||
{
|
||
for (int i = 0; i < ERPC_MSG_CACHE_SIZE; i++)
|
||
{
|
||
erpc_cache_t *cache = &hw->recv_cache[i];
|
||
if (cache->state == CACHE_GET_RESP && cache->msg.src_id == dest_id && cache->msg.port == port)
|
||
{
|
||
return cache;
|
||
}
|
||
}
|
||
return NULL;
|
||
}
|
||
static void free_response_cache(erpc_hw_t *hw, u8 dest_id, u16 port)
|
||
{
|
||
for (int i = 0; i < ERPC_MSG_CACHE_SIZE; i++)
|
||
{
|
||
erpc_cache_t *cache = &hw->recv_cache[i];
|
||
if (cache->state == CACHE_GET_RESP && cache->msg.src_id == dest_id && cache->msg.port == port)
|
||
{
|
||
cache->state = CACHE_FREE;
|
||
}
|
||
}
|
||
}
|
||
static u32 send_ack(erpc_hw_t *hw, u8 dest_id, u16 port, u16 time_out)
|
||
{
|
||
erpc_cache_t *cache = find_free_cache(hw);
|
||
CHECK_DEAL(cache == NULL, ERPC_ERR_NO_FREE_SEND_CACHE);
|
||
hw->lock();
|
||
if (check_port_send_available(hw, port) == 0)
|
||
{
|
||
hw->unlock();
|
||
return ERPC_ERR_SEND_PORT_IS_INUSE;
|
||
}
|
||
cache->msg.dest_id = dest_id;
|
||
cache->state = CACHE_IN_USE;
|
||
hw->unlock();
|
||
cache->msg.src_id = hw->local_id;
|
||
cache->msg.type = ERPC_MSG_TYPE_ACK;
|
||
cache->msg.len = 0;
|
||
cache->msg.port = port;
|
||
cal_crc16(&cache->msg);
|
||
u32 ret = send_data(hw, cache, port, &time_out);
|
||
return ret;
|
||
}
|
||
/**
|
||
* 发送请求,等待响应
|
||
* @param hw 硬件接口
|
||
* @param dest_id 目标ID
|
||
* @param port 端口号
|
||
* @param data_out 请求数据
|
||
* @param len_out 请求数据长度
|
||
* @param data_in 响应数据
|
||
* @param len_in 响应数据长度
|
||
* @param send_timeout 发送超时时间
|
||
* @param recv_timeout 接收超时时间
|
||
* @param retry 重试次数
|
||
* @return 0 成功,其他失败
|
||
*/
|
||
u32 send_request_wait_response(erpc_hw_t *hw, u8 dest_id, u16 port, u8 *data_out, u16 len_out, u8 *data_in, u16 *len_in, u16 send_timeout, u16 recv_timeout, u8 retry)
|
||
{
|
||
free_response_cache(hw, dest_id, port);
|
||
u32 ret = send_request(hw, dest_id, port, data_out, len_out, send_timeout, retry);
|
||
CHECK_DEAL(ret != 0, ret);
|
||
while (recv_timeout)
|
||
{
|
||
erpc_cache_t *rec = find_response_cache(hw, dest_id, port);
|
||
if (rec != NULL)
|
||
{
|
||
// 拷贝数据
|
||
int len = rec->msg.len;
|
||
if (len > *len_in)
|
||
{
|
||
len = *len_in;
|
||
}
|
||
memcpy(data_in, rec->msg.data, len);
|
||
*len_in = len;
|
||
rec->state = CACHE_FREE;
|
||
break;
|
||
}
|
||
recv_timeout--;
|
||
hw->sleep(1);
|
||
}
|
||
CHECK_DEAL(recv_timeout == 0, ERPC_ERR_NO_CMD_RETURN);
|
||
ret = send_ack(hw, dest_id, port, send_timeout);
|
||
CHECK_DEAL(ret != 0, ret);
|
||
return 0;
|
||
}
|
||
|
||
u32 send_response(erpc_hw_t *hw, erpc_cache_t *cache_rec, u8 *data, u16 len, u16 timeout, u8 retry)
|
||
{
|
||
erpc_cache_t *cache = find_free_cache(hw);
|
||
CHECK_DEAL(cache == NULL, ERPC_ERR_NO_FREE_SEND_CACHE);
|
||
hw->lock();
|
||
if (check_port_send_available(hw, cache->msg.port) == 0)
|
||
{
|
||
hw->unlock();
|
||
return ERPC_ERR_SEND_PORT_IS_INUSE;
|
||
}
|
||
cache->msg.dest_id = cache_rec->msg.src_id;
|
||
cache->state = CACHE_IN_USE;
|
||
hw->unlock();
|
||
cache->msg.src_id = hw->local_id;
|
||
cache->msg.type = ERPC_MSG_TYPE_ACK;
|
||
cache->msg.len = 0;
|
||
cache->msg.port = cache_rec->msg.port;
|
||
memcpy(cache->msg.data, data, len);
|
||
cal_crc16(&cache->msg);
|
||
u16 timeout_copy = timeout;
|
||
erpc_cache_t *rec = NULL;
|
||
while (retry--)
|
||
{
|
||
u32 ret = send_data(hw, cache, cache->msg.port, &timeout);
|
||
if (ret)
|
||
{
|
||
cache->state = CACHE_FREE;
|
||
return ret;
|
||
}
|
||
// 等待ack
|
||
ret = wait_ack(hw, rec,cache->msg.dest_id,cache->msg.port, &timeout);
|
||
if (ret == 0)
|
||
{
|
||
break;
|
||
}
|
||
timeout = timeout_copy;
|
||
}
|
||
CHECK_DEAL(retry == 0, ERPC_ERR_SEND_ACK_TIMEOUT);
|
||
// 释放cache
|
||
cache->state = CACHE_FREE;
|
||
rec->state = CACHE_FREE;
|
||
return 0;
|
||
}
|
||
|
||
u32 write_rec_cache(erpc_hw_t *hw, u8 *data, u16 len)
|
||
{
|
||
for (int i = 0; i < ERPC_MSG_CACHE_SIZE; i++)
|
||
{
|
||
if (hw->recv_cache[i].state == CACHE_FREE)
|
||
{
|
||
hw->lock();
|
||
u8 *data_in = (u8 *)&hw->recv_cache[i].msg;
|
||
for (int j = 0; j < len; j++)
|
||
{
|
||
data_in[j] = data[j];
|
||
}
|
||
hw->recv_cache[i].state = CACHE_GET_DATA;
|
||
hw->unlock();
|
||
return 0;
|
||
}
|
||
|
||
}
|
||
return 1;
|
||
}
|
||
void send_core(erpc_hw_t *hw)
|
||
{
|
||
for (int i = 0; i < ERPC_MSG_CACHE_SIZE; i++)
|
||
{
|
||
erpc_cache_t *cache = &hw->send_cache[i];
|
||
if (cache->state == CACHE_WAIT_SEND)
|
||
{
|
||
u32 ret = hw->send((u8 *)&cache->msg, cache->msg.len + ERPC_MSG_HEADER_SIZE);
|
||
if (ret == 0)
|
||
{
|
||
cache->state = CACHE_SEND_OK;
|
||
}
|
||
else
|
||
{
|
||
cache->state = CACHE_SEND_HW_ERR;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
void recv_core(erpc_hw_t *hw)
|
||
{
|
||
for (int i = 0; i < ERPC_MSG_CACHE_SIZE; i++)
|
||
{
|
||
erpc_cache_t *cache = &hw->recv_cache[i];
|
||
if (cache->state == CACHE_GET_DATA)
|
||
{
|
||
if (check_crc16(&cache->msg) == 1)
|
||
{
|
||
cache->state = CACHE_GET_MSG;
|
||
}
|
||
else
|
||
{
|
||
cache->state = CACHE_FREE;
|
||
}
|
||
}
|
||
switch (cache->state)
|
||
{
|
||
case CACHE_GET_MSG:
|
||
{
|
||
switch (cache->msg.type)
|
||
{
|
||
case ERPC_MSG_TYPE_ACK:
|
||
{
|
||
cache->state = CACHE_REC_ACK;
|
||
}
|
||
break;
|
||
case ERPC_MSG_TYPE_RESPONSE:
|
||
{
|
||
cache->state = CACHE_GET_RESP;
|
||
}
|
||
break;
|
||
case ERPC_MSG_TYPE_REQUEST:
|
||
{
|
||
cache->state = CACHE_WAIT_HANDLE;
|
||
}
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
break;
|
||
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
void recv_handle(erpc_hw_t *hw)
|
||
{
|
||
for (int i = 0; i < ERPC_MSG_CACHE_SIZE; i++)
|
||
{
|
||
erpc_cache_t *cache = &hw->recv_cache[i];
|
||
if (cache->state == CACHE_WAIT_HANDLE)
|
||
{
|
||
|
||
cache->state = CACHE_FREE;
|
||
}
|
||
}
|
||
} |