erpc/erpc_core.c

413 lines
11 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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;
}
}
}