www.pudn.com > uart.zip > uart_comm.c, change:2015-10-23,size:16823b


/******************************************************************************* 
 * Copyright (c) 2015 Suzhou Robot Information Technology Co., Ltd. 
 * Filename   : uart_comm.c 
 * Author     : zj       Version:0.0.1      Date:2015.09.14 
 * Description: 串口收/发模块 
 * Others     : 
 * History    : 
 * <Author>  <Date>    <Version> <Description> 
 *  zj     2015.09.14   0.0.1     创建初始版本 
 ******************************************************************************/ 
 
/***********************************头文件*************************************/ 
#include "uart_comm.h" 
#include "inner_msg.h" 
#include "uart_drv.h" 
#include "storage.h" 
#include "msglog.h" 
#include <string.h> 
#include <stdbool.h> 
 
/***********************************宏定义*************************************/ 
/* 定义串口模拟消息测试,1:串口发来的数据第1字节是模块代码,第2字节是请求命令,后面的是请求数据 
                         0:串口发来的数据就是发往modBus模块的请求数据*/ 
#define UART_DEBUG_MSG_TEST  0 
// 使用默认配置,用于调试 
//#define UART_USE_DEFAULT_CFG 
// 发送请求消息的CID2命令码: modBus模块解析数据包命令 
#define UART_CMD (0x11) 
// 指定发送的模块: modBus模块 
#define UART_SEND_MODULE (IM_CID1_MODBUS_PROT) 
// 读取串口配置的地址 
#define UART_CONFIG_ADDR (CONF_START_ADDR + 2*(0x510-0x500)) 
// 发送请求消息或者发送响应消息时路由尝试重发的截止时间,此时间内会一直尝试发送 
#define UART_SEND_MSG_WAIT_TIME 30 // (ms) 
// 等待接收响应消息时间,超时后手动删除发送请求消息的路由表 
#define UART_RECV_MSG_WAIT_TIME 2000 // (ms) 
// 串口收发消息INFO字段最大字节数 
#define UART_MSG_MAX_LEN 256 
// 上行串口使用哪个串口,使用顶板的串口1作为通讯串口 
#define USE_UP_UART_NO 0 
 
/*********************************结构体定义***********************************/ 
typedef enum _uart_event{ 
    UART_COMM_STATUS_1 = 1, 
    UART_COMM_STATUS_2, 
    UART_COMM_STATUS_3, 
    UART_COMM_STATUS_4 
}uart_event_t; // 本模块轮询状态 
 
typedef struct _uart_config_msg_info{ 
    unsigned int addr; 
    unsigned int len; 
}uart_config_msg_info_t // 读配置时的info格式,8字节 
; 
 
/********************************内部函数声明**********************************/ 
void uart_comm_init(void); 
void uart_comm_process(void); 
static void uart_comm_msg_event(void); 
static unsigned int uart_comm_get_data(void); 
static int uart_comm_send_askMsg(void); 
static int uart_comm_wait_answerMsg(void); 
static int uart_comm_recv_answerMsg(void); 
void uart_comm_get_config_process(void); 
 
/**********************************变量定义************************************/ 
// 定义串口模块运行函数指针 
p_module_proc_func_t g_p_uart_proc = uart_comm_init; 
 
// 发送请求/响应消息的帧序号 
unsigned short g_uartMsgSerial = 1; 
// 接收请求或接收响应消息路由表 
msg_swt_tab_t g_uartRecvMsgTable = { 
    IM_CID1_NONE, IM_CID1_NONE, 0, 0, 0 
}; 
 
// 接收请求消息INFO段的缓存,暂时未使用 
unsigned char p_uartRecvMsgAskBuf[1] = {0}; 
// 接收响应消息INFO段的缓存 
unsigned char p_uartRecvMsgAnswerBuf[UART_MSG_MAX_LEN] = {0}; 
// 接收请求消息的缓存 
inner_msg_t g_uartRecvMsgAsk = { 
    IM_CID1_NONE, 0, 0, 0, 
    p_uartRecvMsgAskBuf 
}; 
// 接收响应消息的缓存 
inner_msg_t g_uartRecvMsgAnswer = { 
    IM_CID1_NONE, 0, 0, 0, 
    p_uartRecvMsgAnswerBuf 
}; 
 
// 发送请求消息或者发送响应消息的INFO缓存 
unsigned char p_uartSendMsgBuf[UART_MSG_MAX_LEN] = {0}; 
// 发送请求消息或者发送响应消息的消息缓存 
inner_msg_t g_uartSendMsg = { 
    IM_CID1_UART, 0, 0, 0, 
    p_uartSendMsgBuf 
}; 
// 发送请求消息或者发送响应消息的结构体 
msg_send_buff_t g_uartSendMsgStruct = { 
    UART_SEND_MSG_WAIT_TIME, &g_uartSendMsg 
}; 
 
// 轮询处理的全局状态 
static uart_event_t g_uart_event_status = UART_COMM_STATUS_1; 
// 串口序号,当前使用顶板的cpu串口1 
static unsigned char g_uartNo = USE_UP_UART_NO; 
// 发送模块CID1代码(先读取配置,然后才是向modBus发送消息) 
static unsigned char g_uart_send_module = IM_CID1_STORAGE; 
// 发送的请求消息命令 
static unsigned char g_uart_send_cmd = UART_CMD; 
// 串口配置数据 
static uart_config_t g_uart_config = {2, 1, 1}; // 默认配置波特率9600,偶校验,1位停止位 
// 串口配置数据指针 
static uart_config_t *gp_uart_config = NULL; 
 
//////////////////////////////////////////////////////////////////////////////// 
///////////////////////////////////接口函数///////////////////////////////////// 
//////////////////////////////////////////////////////////////////////////////// 
 
//////////////////////////////////////////////////////////////////////////////// 
/////////////////////////////////内部私有函数/////////////////////////////////// 
//////////////////////////////////////////////////////////////////////////////// 
/******************************************************************************* 
*Function    : uart_comm_init 
*Description : 串口模块初始化 
*Parameter   : 
*Return      : 
*Others      :  
*******************************************************************************/ 
void uart_comm_init(void) 
{ 
    // 注册接收请求消息与接收响应消息的结构体 
    im_reg_module_msg(IM_CID1_UART, 1, &g_uartRecvMsgTable, &g_uartMsgSerial, 
                      1, UART_MSG_MAX_LEN, 
                      &g_uartRecvMsgAsk, &g_uartRecvMsgAnswer); 
 
    // 在轮询的过程中获取串口配置 
    g_uart_send_module = IM_CID1_STORAGE; // 设置目标模块为存储模块 
    g_p_uart_proc = uart_comm_get_config_process; // 设置模块处理函数指针为获取配置 
    g_uart_event_status = UART_COMM_STATUS_1; // 设置处理状态为第一步 
} 
 
void uart_comm_get_config_process(void) 
{ 
    uart_config_msg_info_t uart_config_info = { 
        UART_CONFIG_ADDR, 
        sizeof(uart_config_t) 
    }; 
     
    switch (g_uart_event_status) { 
    case UART_COMM_STATUS_1: // 1、组请求配置包 
        g_uartSendMsgStruct.p_msg->cid1 = IM_CID1_UART; // 本模块CID码 
        g_uartSendMsgStruct.p_msg->cid2 = 0x11; // 读取配置的命令 
        g_uartSendMsgStruct.p_msg->serial = g_uartMsgSerial; // 帧序号 
        g_uartSendMsgStruct.p_msg->info_len =  
                        sizeof(uart_config_msg_info_t); // INFO域长度8 
        memcpy(g_uartSendMsgStruct.p_msg->p_info, &uart_config_info, 
               sizeof(uart_config_msg_info_t)); 
        g_uartSendMsgStruct.wait_tm = UART_RECV_MSG_WAIT_TIME; 
             
        g_uart_event_status = UART_COMM_STATUS_2; // 设置全局状态为步骤2 
 
        break; 
    case UART_COMM_STATUS_2: // 2、发送命令请求消息 
        uart_comm_send_askMsg(); 
        break; 
    case UART_COMM_STATUS_3: // 3、等待应答消息响应 
        uart_comm_wait_answerMsg(); 
        break; 
    case UART_COMM_STATUS_4: // 4、接收并处理响应消息 
        memcpy(&g_uart_config, g_uartRecvMsgAnswer.p_info, 
               sizeof(g_uart_config)); 
         
        if (g_uartRecvMsgAnswer.cid1 != g_uart_send_module) { 
            /* 如果不是存储模块发来的包,则直接丢弃 */ 
        } else if (g_uartRecvMsgAnswer.cid2 != IM_RTN_NORMAL) { 
            /* 如果消息返回码不正确,则直接丢弃 */ 
        } else if (g_uartRecvMsgAnswer.info_len == 0) { 
            /* 如果没有INFO数据,则直接丢弃 */ 
        } else if (g_uartRecvMsgAnswer.serial != g_uartMsgSerial - 1) { 
            /* 如果响应的帧序号与发送的不一致,则直接丢弃 */ 
        } else if (g_uart_config.baudrate > 4) { 
            /* 如果波特率配置错误 */ 
        } else if (g_uart_config.parity > 2) { 
            /* 如果校验位配置错误 */ 
        } else if (g_uart_config.stopbits > 2) { 
            /* 如果停止位错误 */ 
        } else { 
            /* 如果收到的响应消息正常,则继续处理,用读取的配置初始化串口 */ 
            gp_uart_config = &g_uart_config; 
        } 
#if defined (UART_USE_DEFAULT_CFG) 
        gp_uart_config = NULL; 
        uart_init(gp_uart_config); // 串口硬件初始化 
#else 
        uart_init(gp_uart_config); // 串口硬件初始化 
#endif 
        msg_log("sys init ok!"); 
 
        /* 清除消息,退出处理流程 */ 
        im_release_ask_answer_buf(&g_uartRecvMsgAnswer); // 清除接收响应消息缓存 
        // 删除路由信息 
        im_del_swt_info_by_ask_module(IM_CID1_UART, g_uart_send_module, 
                                      g_uartMsgSerial - 1); 
        g_uart_event_status = UART_COMM_STATUS_1; // 设置全局状态为步骤1 
 
        g_p_uart_proc = uart_comm_process; // 设置模块处理函数指针 
        g_uart_send_module = UART_SEND_MODULE; 
        break; 
    default: 
        break; // 出错的情况 
    } 
} 
 
/******************************************************************************* 
*Function    : uart_comm_process 
*Description : 串口模块轮询处理 
*Parameter   : 
*Return      : 
*Others      :  
*******************************************************************************/ 
void uart_comm_process(void) 
{ 
    uart_process(); 
    uart_comm_msg_event(); 
} 
 
/******************************************************************************* 
*Function    : uart_comm_destroy 
*Description :  串口模块销毁函数 
*Parameter   : 
*Return      : 
*Others      :  
*******************************************************************************/ 
void uart_comm_destroy(void) 
{ 
    // 空函数 
} 
 
/******************************************************************************* 
*Function    : uart_comm_msg_event 
*Description : 串口模块轮询事件判断,实现方法见<应用程序_详细设计_串口收发模块> 
               文档 
*Parameter   : 
*Return      : 
*Others      :  
*******************************************************************************/ 
static void uart_comm_msg_event(void) 
{ 
    switch (g_uart_event_status) { 
    case UART_COMM_STATUS_1: // 1、截包 
        uart_comm_get_data(); 
        break; 
    case UART_COMM_STATUS_2: // 2、发送命令请求消息 
        uart_comm_send_askMsg(); 
        break; 
    case UART_COMM_STATUS_3: // 3、等待应答消息响应 
        uart_comm_wait_answerMsg(); 
        break; 
    case UART_COMM_STATUS_4: // 4、接收并处理响应消息 
        uart_comm_recv_answerMsg(); 
        break; 
    default: 
        break; // 出错的情况 
    } 
} 
 
/******************************************************************************* 
*Function    : uart_comm_get_data 
*Description : 从串口驱动获取数据 
*Parameter   : 
*Return      : 0 - 获取失败 
               >0 - 获取成功 
*Others      :  
*******************************************************************************/ 
static unsigned int uart_comm_get_data(void) 
{ 
    unsigned int rxBufLen = 0; 
    uart_t *pUart = NULL; 
    unsigned char *pData; 
     
    if (g_uartNo >= USART_CH_CNT) { 
        g_uartNo = 0; // 当串口号达到最大值,则重新开始循环  
    } 
     
    pUart = &uartCfg[g_uartNo]; 
    if (pUart->RxTickOkTag) { 
        /* 如果该串口有数据可以读 */ 
        if (g_uartNo == USE_UP_UART_NO) { 
            /* 如果是上行串口 */ 
            pUart->RxTickOkTag = false; 
            rxBufLen = loopbuff_getlen(&pUart->rxbuf, 0); 
            if (rxBufLen == 0) { 
                return 0; // 无数据,返回,全局状态保持为步骤1 
            } else if (rxBufLen > 256) { 
                rxBufLen = 256; // 防止溢出 
            } else { 
            } 
 
            pData = g_uartSendMsgStruct.p_msg->p_info; 
            loopbuff_get(&pUart->rxbuf, pData, rxBufLen); // 读取数据 
 
            if (UART_DEBUG_MSG_TEST) { 
                /* 如果收到的是消息测试包 */ 
                if (rxBufLen < 2) { 
                    /* 如果没有发送模块与发送命令 */ 
                } else if (*pData > IM_CID1_HOST_COM) { 
                    /* 如果发送模块代码错误 */ 
                } else { 
                    /* 如果消息测试包正确 */ 
                    g_uart_send_module = *pData; 
                    g_uart_send_cmd = *(pData + 1); 
                    pData = pData + 2; 
                    rxBufLen -= 2; 
                    memmove(g_uartSendMsgStruct.p_msg->p_info, pData, rxBufLen); 
                } 
            } else { 
            } 
 
            g_uartSendMsgStruct.p_msg->info_len = rxBufLen; // INFO域长度 
            g_uartSendMsgStruct.p_msg->cid1 = IM_CID1_UART; // 本模块CID码 
            g_uartSendMsgStruct.p_msg->cid2 = g_uart_send_cmd; // modBus模块解析数据包命令 
            g_uartSendMsgStruct.p_msg->serial = g_uartMsgSerial; // 帧序号 
            g_uartSendMsgStruct.wait_tm = UART_RECV_MSG_WAIT_TIME; 
                 
            g_uart_event_status = UART_COMM_STATUS_2; // 设置全局状态为步骤2 
        } else { 
            /* 如果是调试串口 */ 
            pUart->RxTickOkTag = false; 
        } 
    } else { 
        g_uartNo++; 
    } 
     
    return rxBufLen; 
} 
 
/******************************************************************************* 
*Function    : uart_comm_send_askMsg 
*Description : 将组好的请求消息发送出去 
*Parameter   : 
*Return      : 0 - 处理成功 
*Others      :  
*******************************************************************************/ 
static int uart_comm_send_askMsg(void) 
{ 
    int ret = IM_SEND_ERROR; 
     
    ret = im_send_ask_msg(IM_CID1_NONE, 0, g_uart_send_module, 
                          &g_uartSendMsgStruct, UART_RECV_MSG_WAIT_TIME); 
 
    if (ret == IM_SEND_SUCCESS) { 
        /* 如果发送成功,进入下一步 */ 
        // 添加路由信息 
        im_add_swt_info(IM_CID1_NONE, 0, IM_CID1_UART, 
                        g_uart_send_module, UART_RECV_MSG_WAIT_TIME); 
        // 帧序号累加 
        im_update_serial(&g_uartMsgSerial); 
        g_uart_event_status = UART_COMM_STATUS_3; // 设置全局状态为步骤3 
    } else if ((ret == IM_SEND_TIMEOVER) || (ret == IM_SEND_ERROR)) { 
        /* 如果发送超时,取消当前流程,重新开始 */ 
        g_uart_event_status = UART_COMM_STATUS_1; // 设置全局状态为步骤1 
    } else { 
        /* 其它情况继续保持状态为步骤2,尝试重发 */ 
    } 
 
    return 0; 
} 
 
/******************************************************************************* 
*Function    : uart_comm_wait_answerMsg 
*Description : 查询是否收到响应消息 
*Parameter   : 
*Return      : 0 - 处理成功 
*Others      :  
*******************************************************************************/ 
static int uart_comm_wait_answerMsg(void) 
{ 
    int ret; 
 
    ret = im_is_answer_msg_received(IM_CID1_UART, g_uart_send_module, 
               g_uartMsgSerial - 1); 
 
    if (ret == IM_RCV_SUCCESS) { 
        /* 如果收到响应消息 */ 
        g_uart_event_status = UART_COMM_STATUS_4; // 设置全局状态为步骤4 
 
    // 发送消息成功后serial会自增,所以这里要-1 
    } else if (ret == IM_RCV_TIMEOVER) { 
        /* 如果等待接收响应消息超时,则取消当前流程,重新开始 */ 
        // 删除路由信息 
        im_del_swt_info_by_ask_module(IM_CID1_UART, g_uart_send_module, 
                                      g_uartMsgSerial - 1); 
 
        g_uart_event_status = UART_COMM_STATUS_1; // 设置全局状态为步骤1 
        g_uartRecvMsgAnswer.cid1 = IM_CID1_NONE; 
        g_uartRecvMsgAnswer.info_len = 0; 
    } 
 
    return 0; 
} 
     
/******************************************************************************* 
*Function    : uart_comm_recv_answerMsg 
*Description : 处理收到的响应消息 
*Parameter   : 
*Return      : 0 - 处理成功 
               -1 - 处理失败 
*Others      :  
*******************************************************************************/ 
static int uart_comm_recv_answerMsg(void) 
{ 
    unsigned short dataLen = 0; 
    unsigned short i; 
    unsigned char *pData = NULL; 
    uart_t *pUart = &uartCfg[g_uartNo]; 
     
    if (g_uartRecvMsgAnswer.cid1 != g_uart_send_module) { 
        /* 如果不是modBus协议发来的包,则直接丢弃 */ 
    } else if (g_uartRecvMsgAnswer.cid2 != IM_RTN_NORMAL) { 
        /* 如果消息返回码不正确,则直接丢弃 */ 
    } else if (g_uartRecvMsgAnswer.info_len == 0) { 
        /* 如果没有INFO数据,则直接丢弃 */ 
    } else if (g_uartRecvMsgAnswer.serial != g_uartMsgSerial - 1) { 
        /* 如果响应的帧序号与发送的不一致,则直接丢弃 */ 
    } else { 
        /* 如果收到的响应消息正常,则继续处理,将INFO字段通过串口发送 */ 
        dataLen = g_uartRecvMsgAnswer.info_len; 
        pData = g_uartRecvMsgAnswer.p_info; 
        for (i=0; i<dataLen; i++,pData++) { 
            uart_put_byte(pUart, *pData, dataLen); // 向串口中写入1字节 
        } 
    } 
 
    /* 清除消息,退出处理流程 */ 
    im_release_ask_answer_buf(&g_uartRecvMsgAnswer); // 清除接收响应消息缓存 
 
    g_uart_event_status = UART_COMM_STATUS_1; // 设置全局状态为步骤1 
 
    // 删除路由信息 
    im_del_swt_info_by_ask_module(IM_CID1_UART, g_uart_send_module, 
                                  g_uartMsgSerial - 1); 
 
    return 0; 
} 
 
//////////////////////////////////////////////////////////////////////////////// 
///////////////////////////////////测试代码///////////////////////////////////// 
//////////////////////////////////////////////////////////////////////////////// 
 
#ifdef UART_TEST 
void uart_comm_test1(void) 
{ 
    // 测试从串口接收数据, 
    // 测试将数据包从串口发送 
} 
#endif