Browse Source

change code struct

WKJay 5 năm trước cách đây
mục cha
commit
da669919bb
6 tập tin đã thay đổi với 450 bổ sung71 xóa
  1. 1 1
      Makefile
  2. 6 5
      inc/dlt645.h
  3. 312 0
      port/serial_linux.c
  4. 58 0
      port/serial_linux.h
  5. 13 4
      sample/dlt645_sample.c
  6. 60 61
      src/dlt645.c

+ 1 - 1
Makefile

@@ -1,4 +1,4 @@
-CFLAGS = -Wall -std=c99 -I./inc -I./port
+CFLAGS = -Wall -std=c99 -I./inc -I./port 
 LIB = -lm
 LINK = 
 CC = gcc

+ 6 - 5
inc/dlt645.h

@@ -22,7 +22,7 @@ typedef struct dlt645 dlt645_t;
 
 typedef struct _dlt645_backend
 {
-    int (*select)(dlt645_t *ctx);
+    void (*close)(dlt645_t *ctx);                                  //release
     int (*write)(struct dlt645 *ctx, uint8_t *buf, uint16_t len); //底层写函数
     int (*read)(struct dlt645 *ctx, uint8_t *msg, uint16_t len);  //底层读函数
 } dlt645_backend_t;
@@ -43,11 +43,8 @@ typedef enum
     DLT645_1997
 } dlt645_protocal;
 
-extern dlt645_t *dlt645_new_ctx(const char *device,
-                                int baud, char parity, uint8_t data_bit, uint8_t stop_bit, uint8_t is_rs485);
+extern void dlt645_ctx_init_default(dlt645_t *ctx);
 extern void dlt645_close(dlt645_t *ctx);
-//设置从机地址
-extern void dlt645_set_addr(dlt645_t *ctx, uint8_t *addr);
 //设置调试开关
 extern int dlt645_set_debug(dlt645_t *ctx, int flag);
 //数据采集
@@ -58,5 +55,9 @@ extern uint32_t dec_to_bcd(uint32_t val);
 extern int str_to_bcd(char *str, uint8_t *bcd_store_address, uint16_t bcd_len);
 
 extern void dlt645_set_response_timeout(dlt645_t *ctx, uint32_t timeout_ms);
+extern int dlt645_set_backend(dlt645_t *ctx, const dlt645_backend_t *backend);
+//设置从机地址
+extern void dlt645_set_addr(dlt645_t *ctx, uint8_t *addr);
+
 
 #endif

+ 312 - 0
port/serial_linux.c

@@ -0,0 +1,312 @@
+/*************************************************
+ Copyright (c) 2019
+ All rights reserved.
+ File name:     dlt645_port.c
+ Description:   DLT645 移植&使用例程文件
+ History:
+ 1. Version:    
+    Date:       2019-09-19
+    Author:     wangjunjie
+    Modify:     
+*************************************************/
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <termios.h>
+
+#include "serial_linux.h"
+
+//DL/T 645硬件拓展结构体
+typedef struct
+{
+    int fd;
+    uint8_t is_rs485;
+    struct termios old_tios;
+} serial_port_t;
+
+static int serial_select(dlt645_t *ctx)
+{
+    int s_rc;
+    fd_set rfds;
+    struct timeval tv;
+    serial_port_t *port = ctx->port_data;
+
+    FD_ZERO(&rfds);
+    FD_SET(port->fd, &rfds);
+    tv.tv_sec = ctx->response_timeout / 1000;
+    tv.tv_usec = (ctx->response_timeout % 1000) * 1000;
+    s_rc = select(port->fd + 1, &rfds, NULL, NULL, &tv);
+    if (s_rc < 0)
+    {
+        return -1;
+    }
+    else
+    {
+        return s_rc;
+    }
+}
+
+/**
+ * Name:    serial_linux_hw_read
+ * Brief:   dlt645 硬件层接收数据
+ * Input:
+ *  @ctx:   645运行环境
+ *  @msg:   接收数据存放地址
+ *  @len:   数据最大接收长度 
+ * Output:  读取数据的长度 -1:error 0:timeout
+ */
+static int serial_linux_hw_read(dlt645_t *ctx, uint8_t *msg, uint16_t len)
+{
+    //实际接收长度
+    int rc = 0;
+    serial_port_t *port = ctx->port_data;
+
+    rc = serial_select(ctx);
+    if (rc < 0)
+    {
+        printf("select error on fd %d\r\n", port->fd);
+        return -1;
+    }
+    else if (rc == 0)
+    {
+        printf("select timeout on fd %d\r\n", port->fd);
+        return -0;
+    }
+
+    rc = read(port->fd, msg, len);
+    return rc;
+}
+
+/**
+ * Name:    serial_linux_hw_write
+ * Brief:   dlt645 硬件层发送数据
+ * Input:
+ *  @ctx:   645运行环境
+ *  @buf:   待发送数据
+ *  @len:   发送长度
+ * Output:  实际发送的字节数,错误返回-1
+ */
+static int serial_linux_hw_write(dlt645_t *ctx, uint8_t *buf, uint16_t len)
+{
+    serial_port_t *port = ctx->port_data;
+    int write_len = 0;
+    write_len = write(port->fd, buf, len);
+    return write_len;
+}
+
+static void _port_close(serial_port_t *port)
+{
+    if (port)
+    {
+        tcsetattr(port->fd, TCSANOW, &port->old_tios);
+        if (port->fd)
+        {
+            if(close(port->fd)==0)
+            {
+                printf("close fd:%d success\r\n", port->fd);
+            }
+            else
+            {
+                 printf("close fd:%d failed\r\n", port->fd);
+            }
+            
+        }
+    }
+}
+
+static void serial_linux_hw_close(dlt645_t *ctx)
+{
+    if (ctx == NULL)
+    {
+        return;
+    }
+    if (ctx->port_data)
+    {
+        _port_close(ctx->port_data);
+        free(ctx->port_data);
+        ctx->port_data = NULL;
+    }
+    free(ctx);
+    ctx = NULL;
+}
+
+const dlt645_backend_t serial_linux_backend = {
+    serial_linux_hw_close,
+    serial_linux_hw_write,
+    serial_linux_hw_read};
+
+/**
+ * Name:    serial_linux_port_init
+ * Brief:   硬件层初始化
+ * Input:   None
+ * Output:  None
+ */
+static int serial_linux_port_init(dlt645_t *ctx, void *param)
+{
+    serial_linux_param_t *port_param = param;
+    if (ctx == NULL)
+    {
+        printf("no ctx available\r\n");
+        return -1;
+    }
+    serial_port_t *port = dlt645_malloc(sizeof(serial_port_t));
+    if (port == NULL)
+    {
+        printf("no memory for serial_port_t\r\n");
+        return -1;
+    }
+    memset(port, 0, sizeof(serial_port_t));
+
+    //串口初始化
+    port->fd = open(port_param->device_name, O_RDWR | O_NOCTTY);
+    if (port->fd < 0)
+    {
+        printf("cannot open device %s \r\n", port_param->device_name);
+        dlt645_free(port);
+        return -1;
+    }
+    else
+    {
+        struct termios opt;
+        int baudrate = 0;
+        tcgetattr(port->fd, &port->old_tios);
+        memset(&opt, 0, sizeof(struct termios));
+
+        //清空串口接收缓冲区
+        tcflush(port->fd, TCIOFLUSH);
+
+        // 设置串口输出波特率
+        switch (port_param->baud)
+        {
+        case SERIAL_B1200:
+            baudrate = B1200;
+            break;
+        case SERIAL_B2400:
+            baudrate = B2400;
+            break;
+        case SERIAL_B4800:
+            baudrate = B4800;
+            break;
+        case SERIAL_B9600:
+            baudrate = B9600;
+            break;
+        case SERIAL_B19200:
+            baudrate = B19200;
+            break;
+        case SERIAL_B38400:
+            baudrate = B38400;
+            break;
+        case SERIAL_B57600:
+            baudrate = B57600;
+            break;
+        case SERIAL_B115200:
+            baudrate = B115200;
+            break;
+        default:
+            printf("unknown baud rate :%d, use default 9600\r\n", port_param->baud);
+            baudrate = B9600;
+            break;
+        }
+
+        if ((cfsetospeed(&opt, baudrate) < 0) ||
+            (cfsetispeed(&opt, baudrate) < 0))
+        {
+            close(port->fd);
+            dlt645_free(port);
+            return -1;
+        }
+
+        //设置数据位数
+        opt.c_cflag &= ~CSIZE;
+        switch (port_param->data_bits)
+        {
+        case DATA_BITS_5:
+            opt.c_cflag |= CS5;
+            break;
+        case DATA_BITS_6:
+            opt.c_cflag |= CS6;
+            break;
+        case DATA_BITS_7:
+            opt.c_cflag |= CS7;
+            break;
+        case DATA_BITS_8:
+        default:
+            opt.c_cflag |= CS8;
+            break;
+        }
+
+        //校验位
+        switch (port_param->parity)
+        {
+        case PARITY_NONE:
+            opt.c_cflag &= ~PARENB;
+            opt.c_iflag &= ~INPCK;
+            break;
+        case PARITY_EVEN:
+            opt.c_cflag |= PARENB;
+            opt.c_cflag &= ~PARODD;
+            opt.c_iflag |= INPCK;
+            break;
+        case PARITY_ODD:
+            opt.c_cflag |= PARENB;
+            opt.c_cflag |= PARODD;
+            opt.c_iflag |= INPCK;
+            break;
+        default:
+            break;
+        }
+
+        //设置停止位
+        if (port_param->stop_bits == STOP_BITS_1)
+        {
+            opt.c_cflag &= ~CSTOPB;
+        }
+        else
+        {
+            opt.c_cflag |= CSTOPB;
+        }
+
+        /* Software flow control is disabled */
+        opt.c_iflag &= ~(IXON | IXOFF | IXANY);
+        /* Raw ouput */
+        opt.c_oflag &= ~OPOST;
+        opt.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
+
+        printf("Device %s on fd %d is set to 9600bps,8N1\n", port_param->device_name, port->fd);
+
+        //更新配置
+        if (tcsetattr(port->fd, TCSANOW, &opt) < 0)
+        {
+            close(port->fd);
+            dlt645_free(port);
+            return -1;
+        }
+    }
+    ctx->port_data = port;
+    return 0;
+}
+
+dlt645_t *dlt645_new_serial_linux(serial_linux_param_t *params)
+{
+    //create dlt645 context
+    dlt645_t *ctx = malloc(sizeof(dlt645_t));
+    if (ctx == NULL)
+    {
+        printf("no memory for dlt645 ctx,malloc failed\r\n");
+        return NULL;
+    }
+    //set default params
+    dlt645_ctx_init_default(ctx);
+    //set backend
+    dlt645_set_backend(ctx, &serial_linux_backend);
+    //hardware init
+    if (serial_linux_port_init(ctx, params) < 0)
+    {
+        free(ctx);
+        return NULL;
+    }
+    return ctx;
+}

+ 58 - 0
port/serial_linux.h

@@ -0,0 +1,58 @@
+#ifndef __DLT645_PORT_H
+#define __DLT645_PORT_H
+#include "dlt645.h"
+
+//波特率
+typedef enum _serial_baud
+{
+    SERIAL_B1200,
+    SERIAL_B2400,
+    SERIAL_B4800,
+    SERIAL_B9600,
+    SERIAL_B19200,
+    SERIAL_B38400,
+    SERIAL_B57600,
+    SERIAL_B115200,
+} serial_baud_t;
+//校验位
+typedef enum _serial_parity
+{
+    PARITY_NONE,
+    PARITY_ODD,
+    PARITY_EVEN
+} serial_parity_t;
+//数据位
+typedef enum _serial_data_bits
+{
+    DATA_BITS_5,
+    DATA_BITS_6,
+    DATA_BITS_7,
+    DATA_BITS_8
+} serial_data_bits_t;
+//停止位
+typedef enum _serial_stop_bits
+{
+    STOP_BITS_1,
+    STOP_BITS_2
+} serial_stop_bits_t;
+//模式
+typedef enum _serial_mode
+{
+    RS485,
+    RS232
+} serial_mode_t;
+
+//645 硬件接口参数
+typedef struct _serial_linux_param
+{
+    char *device_name;
+    serial_baud_t baud;           //波特率
+    serial_parity_t parity;       //校验位
+    serial_data_bits_t data_bits; //数据位
+    serial_stop_bits_t stop_bits; //停止位
+    serial_mode_t mode;           //串口模式
+} serial_linux_param_t;
+
+dlt645_t *dlt645_new_serial_linux(serial_linux_param_t *params);
+
+#endif

+ 13 - 4
sample/dlt645_sample.c

@@ -13,7 +13,7 @@
 #include <string.h>
 #include <unistd.h>
 #include <signal.h>
-#include "dlt645.h"
+#include "serial_linux.h"
 
 #define DEVICE_NAME "/dev/ttyUSB0"
 //dlt645 采集测试标识符 (A相电压)
@@ -61,18 +61,27 @@ static void stop(int param)
  */
 int main(void)
 {
+    serial_linux_param_t param;
     signal(SIGINT, stop);
     //dlt645 硬件层初始化
-    dlt645 = dlt645_new_ctx(DEVICE_NAME, 9600, 'N', 8, 1, 0);
-    dlt645_set_response_timeout(dlt645, 1500);
+    param.device_name = DEVICE_NAME;
+    param.baud = SERIAL_B9600;
+    param.parity = PARITY_NONE;
+    param.data_bits = DATA_BITS_8;
+    param.stop_bits = STOP_BITS_1;
+    param.mode = RS232;
+
+    dlt645 = dlt645_new_serial_linux(&param);
     if (dlt645 == NULL)
     {
         return -1;
     }
+
+    dlt645_set_response_timeout(dlt645, 1500);
     while (1)
     {
         //采集测试
         dlt645_read_test();
-        usleep(1000 * 1000);
+        sleep(1);
     }
 }

+ 60 - 61
src/dlt645.c

@@ -10,7 +10,6 @@
     Modify:     
 *************************************************/
 #include "dlt645_private.h"
-#include "dlt645_port.h"
 #include "dlt645_1997.h"
 #include "dlt645_2007.h"
 #include <string.h>
@@ -30,19 +29,13 @@
 int dlt645_receive_msg(dlt645_t *ctx, uint8_t *msg, uint16_t len, uint32_t code, dlt645_protocal protocal)
 {
     int rc;
-    rc = ctx->backend->select(ctx);
-    if (rc < 0)
-    {
-        return -1;
-    }
-    else if (rc == 0)
+
+    rc = ctx->backend->read(ctx, msg, len);
+    if (rc <= 0)
     {
-        DLT645_LOG("receive timeout\r\n");
         return -1;
     }
 
-    rc = ctx->backend->read(ctx, msg, len);
-
     if (protocal == DLT645_1997)
     {
         return dlt645_1997_recv_check(msg, rc, ctx->addr, code);
@@ -76,6 +69,39 @@ int dlt645_send_msg(dlt645_t *ctx, uint8_t *msg, int len)
     return ctx->backend->write(ctx, msg, len);
 }
 
+/**
+ * Name:    dlt645_read_data(用户调用)
+ * Brief:   根据645协议类型读取数据
+ * Input:
+ *  @ctx:           645环境句柄
+ *  @addr:          从站地址
+ *  @code:          标识符
+ *  @read_data:     读取数据存储地址
+ *  @protocal:      协议类型
+ * Output:  成功返回数据长度,失败返回-1
+ */
+int dlt645_read_data(dlt645_t *ctx,
+                     uint32_t code,
+                     uint8_t *read_data,
+                     dlt645_protocal protocal)
+{
+    int rs = -1;
+
+    switch (protocal)
+    {
+    case DLT645_1997:
+        rs = dlt645_1997_read_data(ctx, code, read_data);
+        break;
+    case DLT645_2007:
+        rs = dlt645_2007_read_data(ctx, code, read_data);
+        break;
+    default:
+        DLT645_LOG("unrecognized protocal!\r\n");
+        break;
+    }
+    return rs;
+}
+
 /**
  * Name:    dlt645_set_addr
  * Brief:   设置从站地址
@@ -111,46 +137,26 @@ int dlt645_set_debug(dlt645_t *ctx, int flag)
     return 0;
 }
 
-/**
- * Name:    dlt645_read_data(用户调用)
- * Brief:   根据645协议类型读取数据
- * Input:
- *  @ctx:           645环境句柄
- *  @addr:          从站地址
- *  @code:          标识符
- *  @read_data:     读取数据存储地址
- *  @protocal:      协议类型
- * Output:  成功返回数据长度,失败返回-1
- */
-int dlt645_read_data(dlt645_t *ctx,
-                     uint32_t code,
-                     uint8_t *read_data,
-                     dlt645_protocal protocal)
+int dlt645_set_backend(dlt645_t *ctx, const dlt645_backend_t *backend)
 {
-    int rs = -1;
-
-    switch (protocal)
+    if (backend == NULL)
     {
-    case DLT645_1997:
-        rs = dlt645_1997_read_data(ctx, code, read_data);
-        break;
-    case DLT645_2007:
-        rs = dlt645_2007_read_data(ctx, code, read_data);
-        break;
-    default:
-        DLT645_LOG("unrecognized protocal!\r\n");
-        break;
+        DLT645_LOG("no backend found\r\n");
+        return -1;
     }
-    return rs;
-}
-
-void dlt645_close(dlt645_t *ctx)
-{
-    if (ctx)
+    else if (backend->read == NULL || backend->write == NULL)
+    {
+        DLT645_LOG("no read or write backend, please check\r\n");
+        return -1;
+    }
+    else if (backend->close == NULL)
     {
-        dlt645_port_close(ctx->port_data);
-        dlt645_free(ctx);
+        DLT645_LOG("no close backend, please check\r\n");
+        return -1;
     }
+
+    ctx->backend = backend;
+    return 0;
 }
 
 void dlt645_set_response_timeout(dlt645_t *ctx, uint32_t timeout_ms)
@@ -158,23 +164,16 @@ void dlt645_set_response_timeout(dlt645_t *ctx, uint32_t timeout_ms)
     ctx->response_timeout = timeout_ms;
 }
 
-dlt645_t *dlt645_new_ctx(const char *device,
-                         int baud, char parity, uint8_t data_bit, uint8_t stop_bit, uint8_t is_rs485)
+void dlt645_ctx_init_default(dlt645_t *ctx)
 {
-    dlt645_t *ctx = dlt645_malloc(sizeof(dlt645_t));
-    if (ctx == NULL)
-    {
-        DLT645_LOG("no memory available!\r\n");
-    }
-    else
+    memset(ctx, 0, sizeof(dlt645_t));
+}
+
+void dlt645_close(dlt645_t *ctx)
+{
+    if (ctx)
     {
-        memset(ctx, 0, sizeof(dlt645_t));
-        if (dlt645_port_init(ctx, device, baud, parity, data_bit, stop_bit, is_rs485) < 0)
-        {
-            DLT645_LOG("dlt645 port init failed!\r\n");
-            dlt645_free(ctx);
-            ctx = NULL;
-        }
+        DLT645_LOG("close ctx\r\n");
+        ctx->backend->close(ctx);
     }
-    return ctx;
 }