Browse Source

switchserialmode getestet ttyX30

Reinhard Russinger 2 years ago
parent
commit
2344d1afd3

+ 1 - 1
board/PSG/iot2050/rootfs/etc/init.d/rcS

@@ -15,7 +15,7 @@ fi
 #---- expand rootfs if not done yet
 /etc/init.d/expandfs.sh
 #---- X30 /dev/ttyS2 Einstellungen
-switchserialmode ttyuart -D /dev/ttyS2 -m rs485
+switchserialmode -m rs485
 # Start all init scripts in /etc/init.d
 # executing them in numerical order.
 #

+ 2 - 2
board/PSG/iot2050/rootfs/etc/netplug.d/netplug

@@ -25,7 +25,7 @@ action="$2"
 case "$action" in
 in)
     if [ -x /sbin/ifup ]; then
-	exec /sbin/ifup $dev
+	/sbin/ifup $dev
     else
 	echo "Please teach me how to plug in an interface!" 1>&2
 	exit 1
@@ -35,7 +35,7 @@ out)
     if [ -x /sbin/ifdown ]; then
 	# At least on Fedora Core 1, the call to ip addr flush infloops
 	# /sbin/ifdown $dev && exec /sbin/ip addr flush $dev
-	exec /sbin/ifdown $dev
+	/sbin/ifdown $dev
     else
 	echo "Please teach me how to unplug an interface!" 1>&2
 	exit 1

+ 1 - 0
board/PSG/iot2050/rootfs/etc/udev/rules.d/20-create-symbolic-linkfor-x30.rules

@@ -0,0 +1 @@
+SUBSYSTEM=="tty", KERNEL=="ttyS2", DRIVERS=="omap8250", SYMLINK+="ttyX30"

BIN
package/switchserialmode/src/.o


+ 1 - 1
package/switchserialmode/src/Makefile

@@ -9,7 +9,7 @@ CFLAGS = -I ./
 PROGNAME = switchserialmode
 #---------------------------------------------
 
-OBJECTS = $(PROGNAME).o
+OBJECTS = $(PROGNAME).o gpio_helper.o serial/cp2102n.o serial/omap_8250.o transceiver/sp339e.o
 all:    $(PROGNAME)
 
 $(PROGNAME): $(OBJECTS) 

+ 34 - 0
package/switchserialmode/src/gpio_helper.c

@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) Siemens AG, 2019-2022
+ *
+ * Authors:
+ *  Gao Nian <nian.gao@siemens.com>
+ *  Chao Zeng <chao.zeng@siemens.com>
+ *
+ * This file is subject to the terms and conditions of the MIT License.  See
+ * COPYING.MIT file in the top-level directory.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <gpiod.h>
+#include <string.h>
+#include "gpio_helper.h"
+
+void gpio_set(const uint8_t *line_name, uint32_t value)
+{
+    struct gpiod_line *line;
+
+    line = gpiod_line_find(line_name);
+    if (!line) {
+        printf("Unable to find GPIO line %s\n", line_name);
+        return;
+    }
+
+    if (gpiod_line_request_output(line, "switchserialmode", value) < 0) {
+        perror("gpiod_line_request_output");
+    }
+
+    gpiod_line_release(line);
+    gpiod_line_close_chip(line);
+}

+ 7 - 0
package/switchserialmode/src/gpio_helper.h

@@ -0,0 +1,7 @@
+#ifndef GPIOHELPER
+#define GPIOHELPER
+
+#include <stdint.h>
+
+void gpio_set(const uint8_t *line_name, uint32_t value);
+#endif

+ 379 - 0
package/switchserialmode/src/serial/cp2102n.c

@@ -0,0 +1,379 @@
+/*
+ * Copyright (c) Siemens AG, 2019-2022
+ *
+ * Authors:
+ *  Gao Nian <nian.gao@siemens.com>
+ *  Chao Zeng <chao.zeng@siemens.com>
+ *
+ * This file is subject to the terms and conditions of the MIT License.  See
+ * COPYING.MIT file in the top-level directory.
+ */
+
+#include <string.h>
+#include <unistd.h>
+#include <termios.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <libusb-1.0/libusb.h>
+#include <stdarg.h>
+#include <assert.h>
+#include "gpio_helper.h"
+#include "switchserialmode.h"
+
+#define MAIN_GPIO_CONTROL_1_INDEX      600
+#define CP2102N_RS485_BIT              4
+#define MAIN_GPIO_CONTROL_2_INDEX      601
+#define CP2102N_RS485_LOGIC_BIT        0
+#define CP2102N_RS485_SETUP_INDEX      669
+#define CP2102N_RS485_HOLD_INDEX       671
+#define MAIN_RESET_LATCH_P1_INDEX      587
+#define CP2102N_GPIO2_RESET_LATH_BIT   5
+
+#define CP2102N_MAX_CONFIG_LENGTH      0x02a6
+
+#define IS_CP2102N_RS485PIN_RS485_MODE(config)    ((config)[MAIN_GPIO_CONTROL_1_INDEX] \
+                                                            & (1 << CP2102N_RS485_BIT))
+#define IS_CP2102N_RS485PIN_RS485_LOGIC(config)   (config[MAIN_GPIO_CONTROL_2_INDEX] \
+                                                            & (1 << CP2102N_RS485_LOGIC_BIT))
+#define GET_CP2102N_GPIO2_RESET_LATH(config)   (config[MAIN_RESET_LATCH_P1_INDEX] \
+                                                            & (uint8_t)(1 << CP2102N_GPIO2_RESET_LATH_BIT))
+#define GET_CP2102N_RS485_SETUP_TIME(config)   (((config[CP2102N_RS485_SETUP_INDEX] << 8) & 0xff00)\
+                                                            | (config[CP2102N_RS485_SETUP_INDEX + 1] & 0xff))
+#define GET_CP2102N_RS485_HOLD_TIME(config)   (((config[CP2102N_RS485_HOLD_INDEX] << 8) & 0xff00) \
+                                                            | (config[CP2102N_RS485_HOLD_INDEX + 1] & 0xff))
+
+typedef struct cp2102n_conf_ops {
+    uint8_t deviceConf[CP2102N_MAX_CONFIG_LENGTH];
+    uint16_t confCheckSum;
+    libusb_device_handle *usbHandle;
+    /*cfg update function*/
+    void (*cfg_rs485_setup_time)(struct cp2102n_conf_ops *conf, uint32_t timeVal);
+    void (*cfg_rs485_hold_time)(struct cp2102n_conf_ops *conf, uint32_t timeVal);
+    void (*cfg_rs485pin_to_gpio)(struct cp2102n_conf_ops *conf);
+    void (*cfg_rs485pin_to_rs485)(struct cp2102n_conf_ops *conf);
+    void (*cfg_rs485_logic)(struct cp2102n_conf_ops *conf, uint8_t logic);
+    void (*cfg_rs485pin_gpio_reset_level)(struct cp2102n_conf_ops *conf, uint8_t rstLogic);
+} cp2102n_conf_ops_t;
+
+static cp2102n_conf_ops_t *cp2102n_cfg_operation = NULL;
+
+static void cfg_cp2102n_rs485_setup_time(struct cp2102n_conf_ops *conf, uint32_t timeVal)
+{
+    conf->deviceConf[CP2102N_RS485_SETUP_INDEX] = (uint8_t)(((timeVal) >> 8) & 0xff);
+    conf->deviceConf[CP2102N_RS485_SETUP_INDEX + 1] = (uint8_t)((timeVal) & 0xff);
+}
+
+static void cfg_cp2102n_rs485_hold_time(struct cp2102n_conf_ops *conf, uint32_t timeVal)
+{
+    conf->deviceConf[CP2102N_RS485_HOLD_INDEX] = (uint8_t)(((timeVal) >> 8) & 0xff);
+    conf->deviceConf[CP2102N_RS485_HOLD_INDEX + 1] = (uint8_t)((timeVal) & 0xff);
+}
+
+static void cfg_cp2102n_rs485pin_to_gpio(struct cp2102n_conf_ops *conf)
+{
+    conf->deviceConf[MAIN_GPIO_CONTROL_1_INDEX] &= (uint8_t)(~(1 << CP2102N_RS485_BIT));
+}
+
+static void cfg_cp2102n_rs485pin_to_rs485(struct cp2102n_conf_ops *conf)
+{
+    conf->deviceConf[MAIN_GPIO_CONTROL_1_INDEX] |= (uint8_t)(1 << CP2102N_RS485_BIT);
+}
+
+static void cfg_cp2102n_rs485_logic(struct cp2102n_conf_ops *conf, uint8_t logic)
+{
+    if (logic)
+        conf->deviceConf[MAIN_GPIO_CONTROL_2_INDEX] |= (uint8_t)(1 << CP2102N_RS485_LOGIC_BIT);
+    else
+        conf->deviceConf[MAIN_GPIO_CONTROL_2_INDEX] &= (uint8_t)(~(1 << CP2102N_RS485_LOGIC_BIT));
+}
+
+static void cfg_cp2102n_rs485pin_gpio_reset_level(struct cp2102n_conf_ops *conf, uint8_t rstLogic)
+{
+    if(rstLogic)
+        conf->deviceConf[MAIN_RESET_LATCH_P1_INDEX] |= (uint8_t)(1 << CP2102N_GPIO2_RESET_LATH_BIT);
+    else
+        conf->deviceConf[MAIN_RESET_LATCH_P1_INDEX] &= (uint8_t)(~(1 << CP2102N_GPIO2_RESET_LATH_BIT));
+}
+
+static int8_t cp2102n_read_config(struct cp2102n_conf_ops *conf)
+{
+    assert(conf->usbHandle);
+    uint32_t rlen = libusb_control_transfer(conf->usbHandle, 0xC0, 0xFF,
+                                            0x0E, /* wValue */
+                                            0, /* WIndex */
+                                            conf->deviceConf, /* data */
+                                            CP2102N_MAX_CONFIG_LENGTH, /* data size */
+                                            0);
+
+    return (rlen == CP2102N_MAX_CONFIG_LENGTH) ? SUCCESS : ERROR;
+}
+
+static int8_t cp2102n_write_config_to_device(struct cp2102n_conf_ops *conf)
+{
+    assert(conf->usbHandle);
+    uint32_t wlen = libusb_control_transfer(conf->usbHandle, 0x40, 0xFF,
+                                            0x370F, /* wValue */
+                                            0, /* WIndex */
+                                            conf->deviceConf, /* data */
+                                            CP2102N_MAX_CONFIG_LENGTH, /* data size */
+                                            0);
+
+    return (wlen == CP2102N_MAX_CONFIG_LENGTH) ? SUCCESS : ERROR;
+}
+
+static int8_t find_on_board_cp2102n(libusb_device *device)
+{
+    /*
+        On iot2050 board cp2102n locate at 1.4
+     */
+    #define ROOT_HUB_PORT 1
+    #define INTERMINATE_HUB_PORT 4
+    uint8_t port_numbers[7];
+
+    int r = libusb_get_port_numbers(device, port_numbers, 7);
+    if (r != 2)
+        return ERROR;
+
+    if ((ROOT_HUB_PORT == port_numbers[0]) &&
+        INTERMINATE_HUB_PORT == port_numbers[1]) {
+        return SUCCESS;
+    }
+
+    printf("No matched cp2102n\n");
+    return ERROR;
+}
+
+static int8_t cp2102n_open(struct cp2102n_conf_ops *conf)
+{
+    libusb_device **list = NULL;
+    libusb_device *found = NULL;
+
+    const uint8_t numOfUSBDevices = libusb_get_device_list(NULL, &list);
+
+    if (numOfUSBDevices < 0) {
+        printf("Libusb_get_device_list error");
+        goto error;
+    }
+
+    for (uint8_t i = 0; i < numOfUSBDevices; i++) {
+        if (!find_on_board_cp2102n(list[i])) {
+            found = list[i];
+            break;
+        }
+    }
+
+    if (found) {
+        if (libusb_open(found, &(conf->usbHandle))) {
+            printf("Open usb failed\n");
+            goto error;
+        }
+    } else {
+        printf("No matched device found\n");
+        goto error;
+    }
+
+    libusb_free_device_list(list, 1);
+    return SUCCESS;
+
+error:
+    libusb_free_device_list(list, 1);
+    return ERROR;
+
+}
+
+static void cp2102n_close(struct cp2102n_conf_ops *conf)
+{
+    if(NULL != conf->usbHandle) {
+        libusb_close(conf->usbHandle);
+    }
+}
+
+/* cp210x checksum caculate method */
+static uint16_t fletcher16(const uint8_t *bytes, uint16_t len)
+{
+    uint16_t sum1 = 0xff, sum2 = 0xff;
+    uint16_t tlen = 0;
+
+    while (len) {
+        tlen = len >= 20 ? 20 : len;
+        len -= tlen;
+        do {
+                sum2 += sum1 += *bytes++;
+        } while (--tlen);
+        sum1 = (sum1 & 0xff) + (sum1 >> 8);
+        sum2 = (sum2 & 0xff) + (sum2 >> 8);
+    }
+    /* Second reduction step to reduce sums to 8 bits */
+    sum1 = (sum1 & 0xff) + (sum1 >> 8);
+    sum2 = (sum2 & 0xff) + (sum2 >> 8);
+    return sum2 << 8 | sum1;
+}
+
+static int8_t write_config_to_device(struct cp2102n_conf_ops *conf)
+{
+    uint16_t checkSumNew = fletcher16(conf -> deviceConf, CP2102N_MAX_CONFIG_LENGTH - 2);
+    uint8_t deviceConf[CP2102N_MAX_CONFIG_LENGTH] = {0};
+    if (conf -> confCheckSum != checkSumNew) {
+        //update checksum
+        conf->deviceConf[CP2102N_MAX_CONFIG_LENGTH - 2] = (uint8_t)((checkSumNew >> 8) & 0xff);
+        conf->deviceConf[CP2102N_MAX_CONFIG_LENGTH - 1] = (uint8_t)((checkSumNew) & 0xff);
+        if(SUCCESS != cp2102n_write_config_to_device(conf)) {
+            printf("cp2102n_write_config_to_device failed\n");
+            return ERROR;
+        }
+
+        memcpy(deviceConf, conf->deviceConf, CP2102N_MAX_CONFIG_LENGTH);
+        cp2102n_read_config(conf);
+        if (memcmp(deviceConf, conf->deviceConf, CP2102N_MAX_CONFIG_LENGTH)) {
+            printf("Write configuration failed\n");
+            return ERROR;
+        }
+    }
+    return SUCCESS;
+} 
+
+static void cp2102n_hardware_reset(void)
+{
+    /*
+        reset device to take effective right now
+        for pg1 advanced board,there is no wire connect to reset pin.reset would not work.
+        for later baord, hardware reset can take effective.
+    */
+    if (ADVANCED_BOARD_PG1 != get_board_type()) {
+        gpio_set("CP2102N-RESET", 0);
+        usleep(30 * 1000);
+        gpio_set("CP2102N-RESET", 1);
+        sleep(1);
+    }
+}
+
+static void cp2102n_set_rs485_setup_time(uint8_t setuptime)
+{
+    cp2102n_cfg_operation->cfg_rs485_setup_time(cp2102n_cfg_operation, setuptime);
+}
+
+static void cp2102n_set_rs485_hold_time(uint8_t holdtime)
+{
+    cp2102n_cfg_operation->cfg_rs485_hold_time(cp2102n_cfg_operation, holdtime);
+}
+
+static void print_cfg(uint8_t *devConf)
+{
+    const uint8_t *mode = NULL;
+    const uint8_t *activeLogic = NULL;
+
+    if (IS_CP2102N_RS485PIN_RS485_MODE((devConf))) {
+        mode = "rs485";
+        activeLogic = IS_CP2102N_RS485PIN_RS485_LOGIC(devConf) ? "high" : "low";
+    }
+    else {
+        if (GET_CP2102N_GPIO2_RESET_LATH(devConf)) {
+            mode = "rs422";
+            activeLogic = "high";
+        }
+        else {
+            mode = "rs232";
+            activeLogic = "low";
+        }
+    }
+
+    printf("%s %s setup-time(0x%04x) hold-time(0x%04x)\n",
+            mode, activeLogic,
+            GET_CP2102N_RS485_SETUP_TIME(devConf),
+            GET_CP2102N_RS485_HOLD_TIME(devConf));
+}
+
+static void cp2102n_print_mode(void)
+{
+    print_cfg(cp2102n_cfg_operation->deviceConf);
+}
+
+static void cp2102n_switch_mode(uint8_t *mode)
+{
+    if (0 == strcasecmp(mode, "rs232")) {
+        cp2102n_cfg_operation->cfg_rs485pin_to_gpio(cp2102n_cfg_operation);
+        cp2102n_cfg_operation->cfg_rs485pin_gpio_reset_level(cp2102n_cfg_operation, 0);
+    }
+    else if (0 == strcasecmp(mode, "rs422")) {
+        cp2102n_cfg_operation->cfg_rs485pin_to_gpio(cp2102n_cfg_operation);
+        cp2102n_cfg_operation->cfg_rs485pin_gpio_reset_level(cp2102n_cfg_operation, 1);
+    }
+    else if(0 == strcasecmp(mode, "rs485")) {
+        cp2102n_cfg_operation->cfg_rs485pin_to_rs485(cp2102n_cfg_operation);
+        cp2102n_cfg_operation->cfg_rs485_logic(cp2102n_cfg_operation, 1);
+    }
+}
+
+static int8_t cp2102_ops_init(struct cp2102n_conf_ops **conf)
+{
+    if (cp2102n_open(*conf)) {
+        printf("Open usb device failed\n");
+        return ERROR;
+    }
+
+    if (cp2102n_read_config(*conf)) {
+        printf("Read config failed\n");
+        return ERROR;
+    }
+
+    (*conf)->confCheckSum = fletcher16((*conf)->deviceConf, CP2102N_MAX_CONFIG_LENGTH - 2);
+    (*conf)->cfg_rs485_setup_time = cfg_cp2102n_rs485_setup_time;
+    (*conf)->cfg_rs485_hold_time = cfg_cp2102n_rs485_hold_time;
+    (*conf)->cfg_rs485_logic = cfg_cp2102n_rs485_logic;
+    (*conf)->cfg_rs485pin_gpio_reset_level = cfg_cp2102n_rs485pin_gpio_reset_level;
+    (*conf)->cfg_rs485pin_to_gpio = cfg_cp2102n_rs485pin_to_gpio;
+    (*conf)->cfg_rs485pin_to_rs485 = cfg_cp2102n_rs485pin_to_rs485;
+
+    return SUCCESS;
+}
+
+static int8_t cp2102n_init(uint8_t *deviceNode)
+{
+    libusb_init(NULL);
+
+    cp2102n_cfg_operation = (cp2102n_conf_ops_t *)malloc(sizeof(cp2102n_conf_ops_t));
+    memset(cp2102n_cfg_operation, 0, sizeof(cp2102n_conf_ops_t));
+
+    if (cp2102_ops_init(&cp2102n_cfg_operation)) {
+        printf("Cp2102n init falied\n");
+        return ERROR;
+    }
+
+    return SUCCESS;
+}
+
+static void cp2102n_release()
+{
+    int8_t ret = write_config_to_device(cp2102n_cfg_operation);
+    cp2102n_close(cp2102n_cfg_operation);
+    free(cp2102n_cfg_operation);
+    cp2102n_cfg_operation = NULL;
+    libusb_exit(NULL);
+    if (SUCCESS == ret)
+        cp2102n_hardware_reset();
+}
+
+static void cp2102n_pre_process(void *data)
+{
+    platform_t *preProcess = (platform_t *)data;
+    if (preProcess->private_data) {
+        controller_setting_t *privData = (controller_setting_t *)(preProcess->private_data);
+        if ((0 == GET_CP2102N_RS485_SETUP_TIME(cp2102n_cfg_operation->deviceConf)) ||
+            (0 == GET_CP2102N_RS485_HOLD_TIME(cp2102n_cfg_operation->deviceConf))) {
+            cfg_cp2102n_rs485_setup_time(cp2102n_cfg_operation, privData->setup_time);
+            cfg_cp2102n_rs485_hold_time(cp2102n_cfg_operation, privData->hold_time);
+        }
+    }
+}
+
+serial_ops_t cp210x_ops = {
+    .devName = "cp2102n24",
+    .init = cp2102n_init,
+    .setMode = cp2102n_switch_mode,
+    .getMode = cp2102n_print_mode,
+    .rs485HoldTime = cp2102n_set_rs485_hold_time,
+    .rs485SetupTime = cp2102n_set_rs485_setup_time,
+    .release = cp2102n_release,
+    .preProcess = cp2102n_pre_process,
+};

+ 153 - 0
package/switchserialmode/src/serial/omap_8250.c

@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) Siemens AG, 2019-2022
+ *
+ * Authors:
+ *  Gao Nian <nian.gao@siemens.com>
+ *  Chao Zeng <chao.zeng@siemens.com>
+ *
+ * This file is subject to the terms and conditions of the MIT License.  See
+ * COPYING.MIT file in the top-level directory.
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <termios.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include <string.h>
+#include <linux/serial.h>
+#include <linux/types.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include "switchserialmode.h"
+
+
+#define GET_UART_RTS_ACTIVE_LOGIC(flags)  (!((flags) & SER_RS485_RTS_ON_SEND))
+
+typedef struct omap_8250 {
+    struct serial_rs485 r485Conf;
+    int32_t uartHandle;
+    int8_t (*ttyuart_set_rs485conf)(struct omap_8250 *);
+} omap_8250_ops_t;
+
+omap_8250_ops_t omap_8250_ops;
+
+static int8_t ttyuart_get_rs485conf(struct omap_8250 *ops)
+{
+    int32_t ret = ioctl(ops->uartHandle, TIOCGRS485, &(ops->r485Conf));
+    if (ret < 0) {
+        perror("Error");
+        return ERROR;
+    }
+
+    return SUCCESS;
+}
+
+static int8_t ttyuart_set_rs485conf(struct omap_8250 *ops)
+{
+    int32_t ret = ioctl(ops->uartHandle, TIOCSRS485, ops->r485Conf);
+    if (ret < 0) {
+        perror("Error");
+        return ERROR;
+    }
+
+    return SUCCESS;
+}
+
+static int8_t ttyuart_init(uint8_t *uartdev)
+{
+    int32_t fd = open(uartdev, O_RDWR);
+    if (fd < 0) {
+        printf("Open tty uart failed\n");
+        return ERROR;
+    }
+
+    omap_8250_ops.uartHandle = fd;
+    omap_8250_ops.ttyuart_set_rs485conf = ttyuart_set_rs485conf;
+
+    if (SUCCESS != ttyuart_get_rs485conf(&omap_8250_ops)) {
+        printf("Get configuration fail\n");
+        return ERROR;
+    }
+
+    return SUCCESS;
+}
+
+static void ttyuart_release(void)
+{
+    /*write conf to the device*/
+    if (SUCCESS != omap_8250_ops.ttyuart_set_rs485conf(&omap_8250_ops)) {
+        printf("Set configuration fail\n");
+    }
+
+    close(omap_8250_ops.uartHandle);
+}
+
+static void ttyuart_print_mode(void)
+{
+    const uint8_t *mode = NULL;
+    const uint8_t *activelogic = NULL;
+    struct serial_rs485 rs485Conf = omap_8250_ops.r485Conf;
+
+    if (!(rs485Conf.flags & SER_RS485_ENABLED)) {
+        mode = "rs232";
+        activelogic = "";
+    }
+    else {
+        if (rs485Conf.flags & SER_RS485_RX_DURING_TX) {
+            mode = "rs422";
+            activelogic = "";
+        }
+        else {
+            mode = "rs485";
+            activelogic = GET_UART_RTS_ACTIVE_LOGIC(rs485Conf.flags) ? "active-logic(high)" \
+                                                                        : "active-logic(low)";
+        }
+    }
+
+    printf("%s %s\n", mode, activelogic);
+}
+
+static void ttyuart_switch_mode(uint8_t *mode)
+{
+    struct serial_rs485 *rs485Conf = (struct serial_rs485 *)&(omap_8250_ops.r485Conf);
+    memset(rs485Conf, 0, sizeof(rs485Conf));
+    /*
+        The latest kernel has already handle these flags.Its could be deleted.
+        For the previous compatability, keep this settings
+    */
+    rs485Conf->flags &= ~(SER_RS485_RTS_ON_SEND);
+    rs485Conf->flags |= (SER_RS485_RTS_AFTER_SEND);
+
+    if (0 == strcasecmp(mode, "rs485")) {
+        rs485Conf->flags |= SER_RS485_ENABLED;
+    }
+    else if (0 == strcasecmp(mode, "rs422")) {
+        rs485Conf->flags |= SER_RS485_ENABLED | SER_RS485_RX_DURING_TX;
+    }
+    else if (0 == strcasecmp(mode, "rs232")) {
+        memset(rs485Conf, 0, sizeof(rs485Conf));
+    }
+}
+
+static void ttyuart_set_rs485_hold_time(uint8_t holdtime)
+{
+    printf("Set RS485 hold time not supported\n");
+}
+
+static void ttyuart_set_rs485_setup_time(uint8_t holdtime)
+{
+    printf("Set RS485 setup time not supported\n");
+}
+
+serial_ops_t ttyuart_ops = {
+    .devName = "/dev/ttyX30",
+    .init = ttyuart_init,
+    .rs485HoldTime = ttyuart_set_rs485_hold_time,
+    .rs485SetupTime = ttyuart_set_rs485_setup_time,
+    .setMode = ttyuart_switch_mode,
+    .getMode = ttyuart_print_mode,
+    .release = ttyuart_release,
+};

+ 112 - 1200
package/switchserialmode/src/switchserialmode.c

@@ -1,1259 +1,171 @@
 /*
- * Copyright (c) Siemens AG, 2019
+ * Copyright (c) Siemens AG, 2019-2022
  *
  * Authors:
  *  Gao Nian <nian.gao@siemens.com>
+ *  Chao Zeng <chao.zeng@siemens.com>
  *
  * This file is subject to the terms and conditions of the MIT License.  See
  * COPYING.MIT file in the top-level directory.
  */
-
-#include <linux/serial.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <sys/ioctl.h>
-#include <net/if.h>
-#include <termios.h>
 #include <stdbool.h>
 #include <stdlib.h>
 #include <stdio.h>
+#include <getopt.h>
 #include <string.h>
-#include <malloc.h>
-#include <libusb-1.0/libusb.h>
-#include <gpiod.h>
-#include <stdarg.h>
-
-typedef unsigned char   BYTE;
-typedef unsigned int    UINT;
-typedef unsigned short  U16;
-
-typedef enum _E_STATUS {
-    e_SUCCESS                 = 0x00,
-    e_IO_ERROR                = 0x01,
-
-    e_DEVICE_NOT_FOUND        = 0xFF
-} E_STATUS;
-
-#define ERROR(msg, ...)    printf("ERROR: "msg"\n", ##__VA_ARGS__);
-
-typedef enum{
-    e_case_sensitive = 0,
-    e_case_insensitive
-}E_CASE_SENSITIVE;
-
-#define MUTIL_THREAD   100
-
-static char *format(const char *fmt, ...)
-{
-    #define MAX_STRING_SIZE   128
-
-    static char string[MUTIL_THREAD][MAX_STRING_SIZE] = {{0,0}};
-
-    static int cnt = 0;
-    if(cnt == MUTIL_THREAD)
-    {
-        cnt = 0;
-    }
-
-    memset((char *)&string[cnt][0], 0, MAX_STRING_SIZE);
-
-    va_list ap;
-    va_start(ap, fmt);
-    vsprintf((char *)&string[cnt][0], fmt, ap);
-    va_end(ap);
-
-    char *ptr = (char *)&string[cnt][0];
-    cnt++;
-
-    return ptr;
-}
-
-static char **split(const char *string, const char *delimiter, int *num)
-{
-    #define MAX_SECTION   20
-    static char *args[MUTIL_THREAD][MAX_SECTION] = {{0,0}};
-
-    #define BUF_SIZE   256
-    static char buf[MUTIL_THREAD][BUF_SIZE] = {{0,0}};
-
-    static int count = 0;
-    if(count == MUTIL_THREAD)
-    {
-        count = 0;
-    }
-
-    memset((char *)&buf[count][0], 0, BUF_SIZE);
-    memcpy((char *)&buf[count][0], string, strlen(string));
-
-    int i = 0;
-    char *p = strtok((char *)&buf[count][0], delimiter);
-    while(NULL != p)
-    {
-        args[count][i++] = p;
-        p = strtok(NULL, delimiter);
-    }
-
-    if(NULL != num)
-    {
-        *num = i;
-    }
-
-    char **ptr = &args[count][0];
-    count++;
-
-    return ptr;
-}
-
-#define ARG(fmt, ...)   split(format(fmt, ##__VA_ARGS__), " ", NULL)
-
-static bool compare_string(const char *dest, const char *arg, const E_CASE_SENSITIVE casesensitive)
-{
-    const char *DELIMITER = ",";
-
-    int num = 0;
-    char **list = split(arg, DELIMITER, &num);
-
-    int i = 0;
-    for(i = 0; i < num; i++)
-    {
-        if(casesensitive == e_case_sensitive)
-        {
-            if(0 == strncmp(list[i], dest, strlen(dest)))
-            {
-                return true;
-            }
-        }
-        else
-        {
-            if(0 == strcasecmp(list[i], dest))
-            {
-                return true;
-            }
-        }
-    }
-    return false;
-}
-
-static bool check_arg(int argc, char **argv, const char *name, const E_CASE_SENSITIVE casesensitive)
-{
-    for(int i = 0; i < argc; i++)
-    {
-        if(compare_string(argv[i], name, casesensitive))
-        {
-            return true;
-        }
-    }
-
-    return false;
-}
-
-static int get_arg_int(int argc, char **argv, const char *name, const E_CASE_SENSITIVE casesensitive, int defaultValue)
-{
-    for(int i = 0; i < argc; i++)
-    {
-        if(compare_string(argv[i], name, casesensitive)
-            && ((i + 1) < argc)
-            && ('-' != argv[i + 1][0]))
-        {
-            return strtol(argv[i + 1], NULL, 0);
-        }
-    }
-
-    return defaultValue;
-}
-
-static char *get_arg_string(int argc, char **argv, const char *name, const E_CASE_SENSITIVE casesensitive, char *defaultValue)
-{
-    for(int i = 0; i < argc; i++)
-    {
-        if(compare_string(argv[i], name, casesensitive)
-            && ((i + 1) < argc))
-        {
-            return argv[i + 1];
-        }
-    }
-
-    return defaultValue;
-}
-
-
-#define   LEN(a)   (sizeof(a)/sizeof((a)[0]))
-
-void gpio_set(const char *line_name, int value)
-{
-    struct gpiod_line *line;
-
-    line = gpiod_line_find(line_name);
-    if (!line) {
-        ERROR("Unable to find GPIO line %s", line_name);
-        return;
-    }
-
-    if (gpiod_line_request_output(line, "switchserialmode", value) < 0) {
-        perror("gpiod_line_request_output");
-    }
-
-    gpiod_line_release(line);
-    gpiod_line_close_chip(line);
-}
-
-static void gpio_set_mode(int mode0, int mode1)
-{
-    gpio_set("UART0-enable", 1);
-    gpio_set("UART0-mode0", mode0);
-    gpio_set("UART0-mode1", mode1);
-}
-
-static void gpio_set_terminate(int onoff)
-{
-    gpio_set("UART0-terminate", onoff);
-}
-
-static void gpio_switch_mode(const char *mode, int terminate)
-{
-    if(compare_string(mode, "rs232", e_case_insensitive))
-    {
-        gpio_set_mode(1, 0);
-        gpio_set_terminate(0);
-    }
-    else if(compare_string(mode, "rs485", e_case_insensitive))
-    {
-        gpio_set_mode(0, 1);
-        gpio_set_terminate(terminate);
-    }
-    else if(compare_string(mode, "rs422", e_case_insensitive))
-    {
-        gpio_set_mode(1, 1);
-        gpio_set_terminate(terminate);
-    }
-}
-
-
-#ifndef SER_RS485_TERMINATE_BUS
-#define SER_RS485_TERMINATE_BUS     (1 << 5)
-#endif
-
-#define SET_UART_RTS_ACTIVE_LOGIC(flags, logic)  \
-    do{\
-        if(logic){\
-            flags &= ~(SER_RS485_RTS_ON_SEND);   \
-            flags |= (SER_RS485_RTS_AFTER_SEND); \
-        }else{\
-            flags |= (SER_RS485_RTS_ON_SEND);     \
-            flags &= ~(SER_RS485_RTS_AFTER_SEND);}\
-    }while(0)
-
-#define GET_UART_RTS_ACTIVE_LOGIC(flags)  (!((flags) & SER_RS485_RTS_ON_SEND))
-
-static E_STATUS ttyuart_get_rs485conf(const char *uartdev, struct serial_rs485 *pcfg)
-{
-    int fd = open(uartdev, O_RDWR);
-    if(fd < 0)
-    {
-        ERROR("open %s failed", uartdev);
-        return e_IO_ERROR;
-    }
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include "switchserialmode.h"
 
-    int ret = ioctl(fd, TIOCGRS485, pcfg);
-    if(ret < 0)
-    {
-        perror("Error");
-    }
+extern serial_ops_t ttyuart_ops;
+extern serial_ops_t cp210x_ops;
+extern transceiver_ops_t sp339e_ops;
 
-    close(fd);
-    return 0 == ret ? e_SUCCESS : e_IO_ERROR;
-}
+static platform_t *curr_platform = NULL;
+static controller_setting_t default_setting = {0x5, 0x5};
 
-static void ttyuart_print_mode(const char *uartdev)
+boardType_e get_board_type(void)
 {
-    struct serial_rs485 rs485conf;
-
-    if(e_SUCCESS != ttyuart_get_rs485conf(uartdev, &rs485conf))
-    {
-        return;
-    }
-
-    const char *mode = NULL;
-    const char *activelogic = NULL;
-    const char *terminate = NULL;
+    int32_t ret;
+    const uint8_t *modelPath = "/proc/device-tree/model";
+    uint8_t recvBuf[30] = {0};
+    int32_t fd = open(modelPath, O_RDONLY);
 
-    if(!(rs485conf.flags & SER_RS485_ENABLED))
-    {
-        mode = "rs232";
-        activelogic = "";
-        terminate = "";
-    }
-    else
-    {
-        if(rs485conf.flags & SER_RS485_RX_DURING_TX)
-        {
-            mode = "rs422";
-            activelogic = "";
-        }
-        else
-        {
-            mode = "rs485";
-            activelogic = GET_UART_RTS_ACTIVE_LOGIC(rs485conf.flags) ? "active-logic(high)" : "active-logic(low)";
-        }
-
-        if(rs485conf.flags & SER_RS485_TERMINATE_BUS)
-        {
-            terminate = "terminating";
-        }
-        else
-        {
-            terminate = "non-terminating";
-        }
+    if (fd  < 0) {
+       perror("Get tye error");
+       return ERROR;
     }
 
-    printf("%s %s %s\n", mode, activelogic, terminate);
-}
-
-static E_STATUS ttyuart_set_rs485conf(const char *uartdev, struct serial_rs485 *pcfg)
-{
-    int fd = open(uartdev, O_RDWR);
-    if(fd < 0)
-    {
-        ERROR("open %s failed", uartdev);
-        return e_IO_ERROR;
-    }
-
-    int ret = ioctl(fd, TIOCSRS485, pcfg);
-    if(ret < 0)
-    {
+    ret = read(fd, recvBuf, 30);
+    if (ret < 0) {
         perror("Error");
     }
-
     close(fd);
-    return 0 == ret ? e_SUCCESS : e_IO_ERROR;
-}
-
-static E_STATUS ttyuart_switchto_rs232(const char *uartdev)
-{
-    struct serial_rs485 rs485conf;
-    memset(&rs485conf, 0, sizeof(rs485conf));
-
-    return ttyuart_set_rs485conf(uartdev, &rs485conf);
-}
-
-static E_STATUS ttyuart_switchto_rs485(const char *uartdev, int logicLevel)
-{
-    struct serial_rs485 rs485conf;
-    memset(&rs485conf, 0, sizeof(rs485conf));
-
-    SET_UART_RTS_ACTIVE_LOGIC(rs485conf.flags, logicLevel);
 
-    rs485conf.flags |= SER_RS485_ENABLED;
+    if (0 == strcmp(recvBuf,"SIMATIC IOT2050 Advanced"))
+        return ADVANCED_BOARD_PG1;
+    else if (strstr(recvBuf,"Advanced"))
+        return ADVANCED_BOARD;
 
-    return ttyuart_set_rs485conf(uartdev, &rs485conf);
+    return BASIC_BOARD;
 }
 
-static E_STATUS ttyuart_switchto_rs422(const char *uartdev, int logicLevel)
+static void usage(void)
 {
-    struct serial_rs485 rs485conf;
-    memset(&rs485conf, 0, sizeof(rs485conf));
-
-    SET_UART_RTS_ACTIVE_LOGIC(rs485conf.flags, logicLevel);
-
-    rs485conf.flags |= SER_RS485_ENABLED | SER_RS485_RX_DURING_TX;
-
-    return ttyuart_set_rs485conf(uartdev, &rs485conf);
+    fprintf(stdout,
+        " -h, --help                     : display help information\n"
+        " -m, --mode                     : set serial work mode, the mode can be set 'rs232' 'rs422 'or 'rs485'.\n"
+        " -d, --display                  : display the current mode\n"
+        " -t, --terminator               : Terminate the RS422 or RS485 bus.\n"
+        " -s, --setup u16                : set rs485-pin's setup time in rs485 mode.\n"
+        " -o, --hold u16                 : set rs485-pin's hold time in rs485 mode.\n"
+    );
 }
 
-const char * const TTYUART_USAGE = "\
-It's to operate tty serial device.\n\
-    -h,--help: display help information.\n\
-    -D,--device: specified device, like '/dev/ttyS1' etc.\n\
-    -m,--mode mode: set serial work mode, the mode can be set 'rs232' or 'rs485' or 'rs422'.\n\
-    -l,--logic level: set RTS-pin logic level when sending in rs485 mode, logic can be set '0' or '1'.\n\
-    -d,--display: display the current mode of ttyuart\n";
+static struct option serial_long_options[] = {
+    {"help", no_argument, NULL, 'h'},
+    {"mode", required_argument, NULL, 'm'},
+    {"display", no_argument, NULL, 'd'},
+    {"setup", required_argument, NULL, 's'},
+    {"hold", required_argument, NULL, 'o'},
+    {"terminator", no_argument, NULL, 't'},
+    { NULL, 0, NULL, 0}
+};
 
-static void ttyuart_command_handle(int argc, char **argv)
+static void init_ops(void)
 {
-    if(check_arg(argc, argv, "-h,--help", e_case_sensitive))
-    {
-        printf("%s", TTYUART_USAGE);
-        return;
-    }
-
-    const char *devType = get_arg_string(argc, argv, "-D,--device", e_case_sensitive, NULL);
-    if(NULL == devType)
-    {
-        ERROR("parameter error, must specify serial device via '-D,--device'");
-        return;
-    }
+    curr_platform = (platform_t *)malloc(sizeof(platform_t));
+    memset(curr_platform, 0, sizeof(platform_t));
 
-    if(check_arg(argc, argv, "-d,--display", e_case_sensitive))
-    {
-        ttyuart_print_mode(devType);
-        return;
-    }
-
-    const char *mode = get_arg_string(argc, argv, "-m,--mode", e_case_sensitive, NULL);
-    if(NULL == mode)
-    {
-        ERROR("parameter error, must specify mode via '-m,--mode'");
-        return;
+    if (get_board_type()) {
+        curr_platform->serOps = &cp210x_ops;
+        curr_platform->transOps = &sp339e_ops;;
+        curr_platform->private_data = (controller_setting_t*)&default_setting;
     }
-
-    int logicLevel = get_arg_int(argc, argv, "-l,--logic", e_case_sensitive, 1);
-
-    if(0 == strcasecmp(mode, "rs232"))
-    {
-        ttyuart_switchto_rs232(devType);
-    }
-    else if(0 == strcasecmp(mode, "rs485"))
-    {
-        ttyuart_switchto_rs485(devType, logicLevel);
-    }
-    else if(0 == strcasecmp(mode, "rs422"))
-    {
-        ttyuart_switchto_rs422(devType, logicLevel);
-    }
-    else
-    {
-        ERROR("parameter error, don't support '%s'", mode);
-    }
-}
-
-
-
-/* Device Part Numbers */
-typedef enum _SILABS_PARTNUM_CPXXXX {
-    CP210x_PARTNUM_UNKNOWN =  ((BYTE)(0xFF & 0x00)),
-    CP210x_PARTNUM_CP2101 = ((BYTE)(0xFF & 0x01)),
-    CP210x_PARTNUM_CP2102 = ((BYTE)(0xFF & 0x02)),
-    CP210x_PARTNUM_CP2103 = ((BYTE)(0xFF & 0x03)),
-    CP210x_PARTNUM_CP2104 = ((BYTE)(0xFF & 0x04)),
-    CP210x_PARTNUM_CP2105 = ((BYTE)(0xFF & 0x05)),
-    CP210x_PARTNUM_CP2108 = ((BYTE)(0xFF & 0x08)),
-    CP210x_PARTNUM_CP2109 = ((BYTE)(0xFF & 0x09)),
-
-    SILABS_PARTNUM_CP2110 = ((BYTE)(0xFF & 0x0A)),
-    HID_UART_PART_CP2110 = SILABS_PARTNUM_CP2110,
-
-    CP210x_PARTNUM_CP2112 = ((BYTE)(0xFF & 0x0C)),
-    HID_SMBUS_PART_CP2112 = CP210x_PARTNUM_CP2112,
-
-    SILABS_PARTNUM_CP2114 = ((BYTE)(0xFF & 0x0E)),
-    HID_UART_PART_CP2114 = SILABS_PARTNUM_CP2114,
-
-    CP210x_PARTNUM_CP2102N_QFN28 = ((BYTE)(0xFF & 0x20)),
-    CP210x_PARTNUM_CP2102N_QFN24 = ((BYTE)(0xFF & 0x21)),
-    CP210x_PARTNUM_CP2102N_QFN20 = ((BYTE)(0xFF & 0x22)),
-
-    CP210x_PARTNUM_USBXPRESS_F3XX = ((BYTE)(0xFF & 0x80)),
-    CP210x_PARTNUM_USBXPRESS_EFM8 = ((BYTE)(0xFF & 0x80)),
-    CP210x_PARTNUM_USBXPRESS_EFM32 = ((BYTE)(0xFF & 0x81))
-}SILABS_PARTNUM_CPXXXX;
-
-struct cp210x_info{
-    SILABS_PARTNUM_CPXXXX partnum;
-    const char * const name;
-};
-
-const struct cp210x_info cp210x_info_list[] = {
-    {CP210x_PARTNUM_CP2101, "CP2101"},
-    {CP210x_PARTNUM_CP2102, "CP2102"},
-    {CP210x_PARTNUM_CP2103, "CP2103"},
-    {CP210x_PARTNUM_CP2104, "CP2104"},
-    {CP210x_PARTNUM_CP2105, "CP2105"},
-    {CP210x_PARTNUM_CP2108, "CP2108"},
-    {CP210x_PARTNUM_CP2109, "CP2109"},
-
-    {SILABS_PARTNUM_CP2110, "CP2110"},
-    {CP210x_PARTNUM_CP2112, "CP2112"},
-    {SILABS_PARTNUM_CP2114, "CP2114"},
-
-    {CP210x_PARTNUM_CP2102N_QFN28, "CP2102N28"},
-    {CP210x_PARTNUM_CP2102N_QFN24, "CP2102N24"},
-    {CP210x_PARTNUM_CP2102N_QFN20, "CP2102N20"}};
-
-static libusb_context *g_LibusbContext = NULL;
-
-static const char *cp210x_find_name(SILABS_PARTNUM_CPXXXX partnum)
-{
-    for(int i = 0; i < sizeof(cp210x_info_list)/sizeof(cp210x_info_list[0]); i++)
-    {
-        if(cp210x_info_list[i].partnum == partnum)
-        {
-            return cp210x_info_list[i].name;
-        }
+    else {
+        curr_platform->serOps = &ttyuart_ops;
+        curr_platform->transOps = &sp339e_ops;
     }
 
-    return NULL;
-}
-
-static SILABS_PARTNUM_CPXXXX cp210x_find_partnum(const char *name)
-{
-    for(int i = 0; i < sizeof(cp210x_info_list)/sizeof(cp210x_info_list[0]); i++)
+    if (curr_platform->serOps->init(curr_platform->serOps->devName))
     {
-        if(0 == strcasecmp(cp210x_info_list[i].name, name))
-        {
-            return cp210x_info_list[i].partnum;
-        }
+        printf("Init error\n");
+        exit(1);
     }
-
-    return CP210x_PARTNUM_UNKNOWN;
 }
 
-static bool is_valid_cp210x_partnum(const SILABS_PARTNUM_CPXXXX _v)
-{
-    return (((CP210x_PARTNUM_CP2101 <= _v) && (_v <= CP210x_PARTNUM_CP2105))
-                || (CP210x_PARTNUM_CP2108 == _v)
-                || (CP210x_PARTNUM_CP2109 == _v)
-                || (CP210x_PARTNUM_CP2112 == _v)
-                || ((CP210x_PARTNUM_CP2102N_QFN28 <= _v) && (_v <= CP210x_PARTNUM_CP2102N_QFN20))
-                || (CP210x_PARTNUM_USBXPRESS_F3XX == _v));
-}
-
-static bool cp210x_is_candidate_device(libusb_device *pdev)
+int main(int argc, char **argv)
 {
-    bool isCandidateDevice = false;   /* innocent til proven guilty */
-    struct libusb_device_descriptor devDesc;
-
-    if(0 != libusb_get_device_descriptor(pdev, &devDesc))
-    {
-        return isCandidateDevice;
-    }
-
-    switch(devDesc.bDeviceClass)
-    {
-        case LIBUSB_CLASS_PER_INTERFACE:  /* CP2102, CP2112,  */
-            if((1 == devDesc.iManufacturer) && (2 == devDesc.iProduct) && (3 <= devDesc.iSerialNumber))
-            {
-                struct libusb_config_descriptor *pconfigDesc = NULL;
-                isCandidateDevice = true;
-
-                if(0 == libusb_get_config_descriptor(pdev, 0, &pconfigDesc))
-                {
-                    if(pconfigDesc->bNumInterfaces
-                        && pconfigDesc->interface->num_altsetting
-                        && (LIBUSB_CLASS_VENDOR_SPEC != pconfigDesc->interface->altsetting->bInterfaceClass))
-                    {
-                        isCandidateDevice = false;
-                    }
-
-                    libusb_free_config_descriptor(pconfigDesc);
-                    pconfigDesc = (struct libusb_config_descriptor *)NULL;
-               }
-            }
+    bool display_current_mode = false;
+    uint8_t *mode = NULL;
+    uint32_t setupTime = 0;
+    uint32_t holdTime = 0;
+    bool set_termination = false;
+    uint8_t *options = "hm:ds:o:t";
+    int32_t c;
+
+    /*parse parameter*/
+    while ((c = getopt_long(argc, argv, options,
+                serial_long_options, NULL)) != EOF) {
+    switch (c) {
+        case 'h':
+            usage();
+            exit(1);
+        case 'd':
+            display_current_mode = true;
             break;
-
-        default:
-            isCandidateDevice = false;
+        case 'm':
+            mode = strdup(optarg);
             break;
-    }
-
-    return isCandidateDevice;
-}
-
-static E_STATUS cp210x_get_partnumber(libusb_device_handle *h, BYTE *partnum)
-{
-    int ret = libusb_control_transfer(h, 0xC0, 0xFF, 0x370B, 0x0000, partnum, 1, 7000);
-
-    if(1 == ret)
-    {
-        return e_SUCCESS;
-    }
-
-    if(LIBUSB_ERROR_TIMEOUT == ret)
-    {
-        ERROR("libusb_control_transfer timeout");
-        return e_IO_ERROR;
-    }
-
-    struct libusb_config_descriptor *configDesc = NULL;
-    E_STATUS status = e_IO_ERROR;
-
-    if(0 == libusb_get_config_descriptor(libusb_get_device(h), 0, &configDesc))
-    {
-        /* Looking for a very particular fingerprint to conclude the device is a CP2101 */
-        if ((configDesc->bNumInterfaces > 0)
-            && (configDesc->interface[0].altsetting->bNumEndpoints > 1)
-            && ((configDesc->interface[0].altsetting->endpoint[0].bEndpointAddress & 0x0F) == 0x03)
-            && ((configDesc->interface[0].altsetting->endpoint[1].bEndpointAddress & 0x0F) == 0x03))
-        {
-            *partnum = CP210x_PARTNUM_CP2101;
-            status = e_SUCCESS;
-        }
-
-        libusb_free_config_descriptor(configDesc);
-    }
-
-    return status;
-}
-
-static E_STATUS cp210x_read_config(libusb_device_handle *usbhd, BYTE *config, UINT len)
-{
-    UINT rlen = libusb_control_transfer(usbhd, 0xC0, 0xFF,
-                                                     0x0E, /* wValue */
-                                                        0, /* WIndex */
-                                                   config, /* data */
-                                                      len, /* data size */
-                                                        0);
-
-    return (rlen == len) ? e_SUCCESS : e_IO_ERROR;
-}
-
-static E_STATUS cp210x_write_config(libusb_device_handle *usbhd, BYTE *config, UINT len)
-{
-    UINT wlen = libusb_control_transfer(usbhd, 0x40, 0xFF,
-                                                   0x370F, /* wValue */
-                                                        0, /* WIndex */
-                                                   config, /* data */
-                                                      len, /* data size */
-                                                        0);
-
-    return (wlen == len) ? e_SUCCESS : e_IO_ERROR;
-}
-
-static int cp210x_list(const char **namelist, int len)
-{
-    libusb_device_handle *usbh = NULL;
-    libusb_device **list = NULL;
-
-    /* Enumerate all USB devices, returning the number of USB devices and a list of those devices */
-    const ssize_t numOfUSBDevices = libusb_get_device_list(g_LibusbContext, &list);
-
-    /* A negative count indicates an error */
-    if(numOfUSBDevices < 0)
-    {
-        ERROR("libusb_get_device_list error");
-        return 0;
-    }
-
-    int n = 0;
-
-    for(ssize_t i = 0; i < numOfUSBDevices; i++)
-    {
-        libusb_device *device = list[i];
-        libusb_device_handle *h = NULL;
-
-        if(cp210x_is_candidate_device(device) && (0 == libusb_open(list[i], &h)))
-        {
-            BYTE partNum = 0;
-
-            if((0 == cp210x_get_partnumber(h, &partNum))
-                && is_valid_cp210x_partnum((SILABS_PARTNUM_CPXXXX)partNum))
-            {
-                if(n < len)
-                {
-                    namelist[n++] = cp210x_find_name(partNum);
-                }
-            }
-
-            libusb_close(h);
-        }
-    } /* end for */
-
-    libusb_free_device_list(list, 1); /* Unreference all devices to free the device list */
-    return n;
-}
-
-static libusb_device_handle *cp210x_open(SILABS_PARTNUM_CPXXXX cp210x_partnum)
-{
-    libusb_device_handle *usbh = NULL;
-    libusb_device **list = NULL;
-
-    /* Enumerate all USB devices, returning the number of USB devices and a list of those devices */
-    const ssize_t numOfUSBDevices = libusb_get_device_list(g_LibusbContext, &list);
-
-    /* A negative count indicates an error */
-    if(numOfUSBDevices < 0)
-    {
-        ERROR("libusb_get_device_list error");
-        return NULL;
-    }
-
-    for(ssize_t i = 0; i < numOfUSBDevices; i++)
-    {
-        libusb_device *device = list[i];
-        libusb_device_handle *h = NULL;
-
-        if(cp210x_is_candidate_device(device) && (0 == libusb_open(list[i], &h)))
-        {
-            BYTE partNum = 0;
-
-            if((0 == cp210x_get_partnumber(h, &partNum))
-                && is_valid_cp210x_partnum((SILABS_PARTNUM_CPXXXX)partNum)
-                && (partNum == cp210x_partnum))
-            {
-                if(NULL == usbh)
-                {
-                    usbh = h;
-                }
-                else
-                {
-                    ERROR("conflicts, find multi '%s'", cp210x_find_name(partNum));
-                    libusb_close(usbh);
-                    libusb_close(h);
-                    return NULL;
-                }
-            }
-            else
-            {
-                libusb_close(h);
-            }
-        }
-    } /* end for */
-
-    libusb_free_device_list(list, 1);
-    return usbh;
-}
-
-static void cp210x_close(libusb_device_handle *usbh)
-{
-    if(NULL != usbh)
-    {
-        libusb_close(usbh);
-    }
-}
-
-static void cp210x_reset(libusb_device_handle *usbh)
-{
-    if(NULL != usbh)
-    {
-        libusb_reset_device(usbh);
-    }
-}
-
-static U16 fletcher16(const BYTE *bytes, U16 len)
-{
-    U16 sum1 = 0xff, sum2 = 0xff;
-    U16 tlen = 0;
-
-    while (len) {
-        tlen = len >= 20 ? 20 : len;
-        len -= tlen;
-        do {
-                sum2 += sum1 += *bytes++;
-        } while (--tlen);
-        sum1 = (sum1 & 0xff) + (sum1 >> 8);
-        sum2 = (sum2 & 0xff) + (sum2 >> 8);
-    }
-    /* Second reduction step to reduce sums to 8 bits */
-    sum1 = (sum1 & 0xff) + (sum1 >> 8);
-    sum2 = (sum2 & 0xff) + (sum2 >> 8);
-    return sum2 << 8 | sum1;
-}
-
-static void cp210x_compute_configure_checksum(BYTE *config, U16 len)
-{
-    U16 checksum = fletcher16(config, len - 2);
-    config[len - 2] = (BYTE)((checksum >> 8) & 0xff);
-    config[len - 1] = (BYTE)((checksum) & 0xff);
-}
-
-#define MAIN_GPIO_CONTROL_1_INDEX      600
-#define CP2102N_RS485_BIT              4
-#define MAIN_GPIO_CONTROL_2_INDEX      601
-#define CP2102N_RS485_LOGIC_BIT        0
-#define CP2102N_RS485_SETUP_INDEX      669
-#define CP2102N_RS485_HOLD_INDEX       671
-#define MAIN_RESET_LATCH_P1_INDEX      587
-#define CP2102N_GPIO2_RESET_LATH_BIT   5
-
-#define SET_CP2102N_RS485PIN_TO_RS585(config)   ((config)[MAIN_GPIO_CONTROL_1_INDEX] |= (BYTE)(1 << CP2102N_RS485_BIT))
-#define IS_CP2102N_RS485PIN_RS485_MODE(config)    ((config)[MAIN_GPIO_CONTROL_1_INDEX] & (1 << CP2102N_RS485_BIT))
-#define SET_CP2102N_RS485PIN_TO_GPIO(config)    ((config)[MAIN_GPIO_CONTROL_1_INDEX] &= (BYTE)(~(1 << CP2102N_RS485_BIT)))
-
-#define SET_CP2102N_RS485PIN_RS485_ACTIVE_LOGIC(config, logic)\
-    do{\
-        if(logic)\
-            config[MAIN_GPIO_CONTROL_2_INDEX] |= (BYTE)(1 << CP2102N_RS485_LOGIC_BIT);   \
-        else \
-            config[MAIN_GPIO_CONTROL_2_INDEX] &= (BYTE)(~(1 << CP2102N_RS485_LOGIC_BIT));\
-    }while(0)
-
-#define IS_CP2102N_RS485PIN_RS485_LOGIC(config)   (config[MAIN_GPIO_CONTROL_2_INDEX] & (1 << CP2102N_RS485_LOGIC_BIT))
-
-#define SET_CP2102N_GPIO2_RESET_LATH(config, logic) \
-    do{\
-        if(logic)\
-            config[MAIN_RESET_LATCH_P1_INDEX] |= (BYTE)(1 << CP2102N_GPIO2_RESET_LATH_BIT);   \
-        else\
-            config[MAIN_RESET_LATCH_P1_INDEX] &= (BYTE)(~(1 << CP2102N_GPIO2_RESET_LATH_BIT));   \
-    }while(0)
-
-#define GET_CP2102N_GPIO2_RESET_LATH(config)   (config[MAIN_RESET_LATCH_P1_INDEX] & (BYTE)(1 << CP2102N_GPIO2_RESET_LATH_BIT))
-
-#define SET_CP2102N_RS485_SETUP_TIME(config, u16vl) \
-    do{\
-        config[CP2102N_RS485_SETUP_INDEX] = (BYTE)(((u16vl) >> 8) & 0xff); \
-        config[CP2102N_RS485_SETUP_INDEX + 1] = (BYTE)((u16vl) & 0xff);    \
-    }while(0)
-
-#define GET_CP2102N_RS485_SETUP_TIME(config)   (((config[CP2102N_RS485_SETUP_INDEX] << 8) & 0xff00) | (config[CP2102N_RS485_SETUP_INDEX + 1] & 0xff))
-
-#define CFG_CP2102N_RS485_HOLD_TIME(config, u16vl) \
-    do{\
-        config[CP2102N_RS485_HOLD_INDEX] = (BYTE)(((u16vl) >> 8) & 0xff); \
-        config[CP2102N_RS485_HOLD_INDEX + 1] = (BYTE)((u16vl) & 0xff);    \
-    }while(0)
-
-#define GET_CP2102N_RS485_HOLD_TIME(config)   (((config[CP2102N_RS485_HOLD_INDEX] << 8) & 0xff00) | (config[CP2102N_RS485_HOLD_INDEX + 1] & 0xff))
-
-
-const char * const CP210X_USAGE = "\
-It's to operate cp210x device.\n\
-    -h,--help: display help information.\n\
-    -l,--list: list cp210x device.\n\
-    -D,--device: specified device, like 'cp2102', 'cp2102n24', 'cp2102n28' etc.\n\
-    -r,--read-config filename: read configuration from cp210x to filename.\n\
-    -w,--write-config filename: write configuration from filename to cp210x.\n\
-    -m,--rs485pin mode: set rs485-pin work mode, the mode can be set 'gpio' or 'rs485'.\n\
-    -g,--rs485-logic logic: set rs485-pin logic level when sending in rs485 mode, logic can be set '0' or '1'.\n\
-    -s,--setup u16: set rs485-pin's setup time in rs485 mode.\n\
-    -o,--hold u16: set rs485-pin's hold time in rs485 mode.\n\
-    -d,--display: display the current mode of cp210x.\n\
-    -v,--reset-level: set rs485-pin's default logic level in gpio mode.\n\
-    -e,--reset: reset cp210x.\n";
-
-
-typedef enum {
-    e_CONTINUE = 0,
-    e_STOP,
-}E_CMD_EXE_STATUS;
-
-#define CP210x_MAX_CONFIG_LENGTH  0x02a6
-
-typedef E_CMD_EXE_STATUS (*cmd_hander)(int argc, char **argv);
-
-static U16 g_CheckSumOld = 0;
-
-static libusb_device_handle *cp210x_cmd_open_device(int argc, char **argv)
-{
-    static libusb_device_handle *usbhd = NULL;
-    if(NULL != usbhd)
-    {
-        return usbhd;
-    }
-
-    SILABS_PARTNUM_CPXXXX ePartNum = CP210x_PARTNUM_UNKNOWN;
-    const char *devType = get_arg_string(argc, argv, "-D,--device", e_case_sensitive, NULL);
-    if(devType)
-    {
-        ePartNum = cp210x_find_partnum(devType);
-        if(CP210x_PARTNUM_UNKNOWN == ePartNum)
-        {
-            ERROR("parameter error, don't support '%s'", devType);
-            return NULL;
-        }
-    }
-    else
-    {
-        ERROR("parameter error, must specify cp210x device via '-D,--device'");
-        return NULL;
-    }
-
-    usbhd = cp210x_open(ePartNum);
-    if(NULL == usbhd)
-    {
-        ERROR("open '%s' failed", devType);
-    }
-
-    return usbhd;
-}
-
-static BYTE *cp210x_cmd_get_config(int argc, char **argv)
-{
-    static BYTE config[CP210x_MAX_CONFIG_LENGTH] = {0};
-
-    static bool isGeted = false;
-    if(isGeted)
-    {
-        return config;
-    }
-
-    libusb_device_handle *usbhd = cp210x_cmd_open_device(argc, argv);
-    if(NULL == usbhd)
-    {
-        return NULL;
-    }
-
-    memset((char*)(&(config[0])), 0, CP210x_MAX_CONFIG_LENGTH);
-
-    if(e_SUCCESS != cp210x_read_config(usbhd, config, CP210x_MAX_CONFIG_LENGTH))
-    {
-        ERROR("cp210x_read_config failed");
-        return NULL;
-    }
-
-    g_CheckSumOld = ((config[CP210x_MAX_CONFIG_LENGTH - 2] << 8) & 0xff00) | (config[CP210x_MAX_CONFIG_LENGTH - 1] & 0xff);
-    isGeted = true;
-
-    return config;
-}
-
-static E_CMD_EXE_STATUS cp210x_cmd_help(int argc, char **argv)
-{
-    printf("%s", CP210X_USAGE);
-    return e_STOP;;
-}
-
-static E_CMD_EXE_STATUS cp210x_cmd_list(int argc, char **argv)
-{
-    #define MAX_NUM   10
-    const char *namelist[MAX_NUM] = {0};
-    int num = cp210x_list(namelist, MAX_NUM);
-
-    int i = 0;
-    for(i = 0; i < num; i++)
-    {
-        if(0 == i)
-        {
-            printf("Find cp210x:\n");
+        case 's':
+            setupTime = atoi(optarg);
+            break;
+        case 'o':
+            holdTime = atoi(optarg);
+            break;
+        case 't':
+            set_termination = true;
+            break;
+        default:
+            printf("Operation not supported\n");
+            exit(1);
         }
-        printf("\t%s\n", namelist[i]);
-    }
-
-    return e_STOP;
-}
-
-static E_CMD_EXE_STATUS cp210x_cmd_print_mode(int argc, char **argv)
-{
-    BYTE *config = cp210x_cmd_get_config(argc, argv);
-    if(NULL == config)
-    {
-        return e_STOP;
-    }
-
-    if(IS_CP2102N_RS485PIN_RS485_MODE(config))
-    {
-        printf("rs485 active-logic(%s) setup-time(0x%04x) hold-time(0x%04x)\n"
-                        , IS_CP2102N_RS485PIN_RS485_LOGIC(config) ? "high" : "low"
-                        , GET_CP2102N_RS485_SETUP_TIME(config)
-                        , GET_CP2102N_RS485_HOLD_TIME(config));
-    }
-    else
-    {
-        printf("gpio reset-logic(%s)\n", GET_CP2102N_GPIO2_RESET_LATH(config) ? "high" : "low");
-    }
-
-    return e_STOP;
-}
-
-static E_CMD_EXE_STATUS cp210x_cmd_read_config(int argc, char **argv)
-{
-    const char *saveName = get_arg_string(argc, argv, "-r,--read-config", e_case_sensitive, NULL);
-    if(NULL == saveName)
-    {
-        ERROR("parameter error, '-r,--read-config' must append a file name");
-        return e_STOP;
     }
 
-    BYTE *config = cp210x_cmd_get_config(argc, argv);
-    if(NULL == config)
-    {
-        return e_STOP;
-    }
-
-    FILE *fp = fopen(saveName, "w");
-
-    #define TMP_SIZE 10
-    char tmp[TMP_SIZE] = {0};
-    int i = 0;
-    for(i = 0; i < CP210x_MAX_CONFIG_LENGTH; i++)
-    {
-        memset(tmp, TMP_SIZE, 0);
-        sprintf(tmp, "0x%02x\n", config[i]);
-        fwrite(tmp, 1, strlen(tmp), fp);
-    }
-
-    fclose(fp);
-    return e_CONTINUE;
-}
-
-static E_CMD_EXE_STATUS cp210x_cmd_write_config(int argc, char **argv)
-{
-    const char *configName = get_arg_string(argc, argv, "-w,--write-config", e_case_sensitive, NULL);
-    if(NULL == configName)
-    {
-        ERROR("parameter error, '-w,--write-config' must append a file name");
-        return e_STOP;
-    }
-
-    BYTE config[CP210x_MAX_CONFIG_LENGTH] = {0};
-
-    FILE *fp = fopen(configName, "r");
-    if(NULL == fp)
-    {
-        ERROR("open '%s' failed", configName);
-        return e_STOP;
-    }
-
-    #define MAX_LINE   10
-    char tmp[MAX_LINE] = {0};
-    int i = 0;
-
-    while(!feof(fp) && (i < CP210x_MAX_CONFIG_LENGTH))
-    {
-        memset(tmp, 0, MAX_LINE);
-        fgets(tmp, MAX_LINE, fp);
-        config[i++] = strtol(tmp, NULL, 0);
-    }
-
-    fclose(fp);
-
-    libusb_device_handle *usbhd = cp210x_cmd_open_device(argc, argv);
-    if(NULL == usbhd)
-    {
-        return e_STOP;
-    }
-
-    cp210x_compute_configure_checksum(config, CP210x_MAX_CONFIG_LENGTH);
-
-    if(e_SUCCESS != cp210x_write_config(usbhd, config, CP210x_MAX_CONFIG_LENGTH))
-    {
-        ERROR("cp210x_write_config failed");
-        return e_STOP;
-    }
-
-    return e_CONTINUE;
-}
-
-static E_CMD_EXE_STATUS cp210x_cmd_set_mode(int argc, char **argv)
-{
-    const char *mode = get_arg_string(argc, argv, "-m,--rs485pin", e_case_sensitive, NULL);
-    if(NULL == mode)
-    {
-        ERROR("parameter error, '-m,--rs485pin' must append a mode");
-        return e_STOP;
-    }
-
-    BYTE *config = cp210x_cmd_get_config(argc, argv);
-    if(NULL == config)
-    {
-        return e_STOP;
-    }
-
-    if(0 == strcasecmp(mode, "gpio"))
-    {
-        SET_CP2102N_RS485PIN_TO_GPIO(config);
-
-    }
-    else if(0 == strcasecmp(mode, "rs485"))
-    {
-        SET_CP2102N_RS485PIN_TO_RS585(config);
-    }
-    else
-    {
-        ERROR("parameter error, '-m,--rs485pin' must append a mode, it can be 'gpio' or 'rs485'");
-        return e_STOP;
-    }
-
-    return e_CONTINUE;
-}
-
-static E_CMD_EXE_STATUS cp210x_cmd_set_rs485_logic(int argc, char **argv)
-{
-    const int logic = get_arg_int(argc, argv, "-g,--rs485-logic", e_case_sensitive, -1);
-    if(-1 == logic)
-    {
-        ERROR("parameter error, '-g,--rs485-logic' must append a value, like '0' or '1'");
-        return e_STOP;
-    }
-
-    BYTE *config = cp210x_cmd_get_config(argc, argv);
-    if(NULL == config)
-    {
-        return e_STOP;
-    }
-
-    SET_CP2102N_RS485PIN_RS485_ACTIVE_LOGIC(config, logic);
-
-    return e_CONTINUE;
-}
-
-static E_CMD_EXE_STATUS cp210x_cmd_set_rs485_setup(int argc, char **argv)
-{
-    const int setuptime = get_arg_int(argc, argv, "-s,--setup", e_case_sensitive, -1);
-    if(-1 == setuptime)
-    {
-        ERROR("parameter error, '-s,--setup' must append a unsigned short type value, like '0x1234' or '1234'");
-        return e_STOP;
-    }
+    init_ops();
 
-    BYTE *config = cp210x_cmd_get_config(argc, argv);
-    if(NULL == config)
-    {
-        return e_STOP;
+    if (display_current_mode) {
+        curr_platform->serOps->getMode();
+        return SUCCESS;
     }
 
-    SET_CP2102N_RS485_SETUP_TIME(config, setuptime);
-    return e_CONTINUE;
-}
+    if (curr_platform->serOps->preProcess)
+        curr_platform->serOps->preProcess(curr_platform);
 
-static E_CMD_EXE_STATUS cp210x_cmd_set_rs485_hold(int argc, char **argv)
-{
-    const int holdtime = get_arg_int(argc, argv, "-o,--hold", e_case_sensitive, -1);
-    if(-1 == holdtime)
-    {
-        ERROR("parameter error, '-o,--hold' must append a unsigned short type value, like '0x1234' or '1234'");
-        return e_STOP;
+    if (NULL != mode) {
+        curr_platform->serOps->setMode(mode);
     }
 
-    BYTE *config = cp210x_cmd_get_config(argc, argv);
-    if(NULL == config)
-    {
-        return e_STOP;
-    }
-
-    CFG_CP2102N_RS485_HOLD_TIME(config, holdtime);
-    return e_CONTINUE;
-}
-
-static E_CMD_EXE_STATUS cp210x_cmd_set_rs485pin_gpio_reset_level(int argc, char **argv)
-{
-    int rstLogic = get_arg_int(argc, argv, "-v,--reset-level", e_case_sensitive, -1);
-    if(-1 == rstLogic)
-    {
-        ERROR("parameter error, '-o,--hold' must append a value, like '0' or '1'");
-        return e_STOP;
-    }
-
-    BYTE *config = cp210x_cmd_get_config(argc, argv);
-    if(NULL == config)
-    {
-        return e_STOP;
-    }
-
-    SET_CP2102N_GPIO2_RESET_LATH(config, rstLogic);
-    return e_CONTINUE;
-}
-
-static E_CMD_EXE_STATUS cp210x_cmd_reset(int argc, char **argv)
-{
-    cp210x_reset(cp210x_cmd_open_device(argc, argv));
-    return e_STOP;
-}
-
-typedef struct {
-    const char *const cmd;
-    cmd_hander cmd_func;
-}cmd_list_t;
-
-cmd_list_t cmd_list[] = {
-    {"-h,--help",    cp210x_cmd_help},
-    {"-l,--list",    cp210x_cmd_list},
-    {"-d,--display", cp210x_cmd_print_mode},
-    {"-r,--read-config", cp210x_cmd_read_config},
-    {"-w,--write-config", cp210x_cmd_write_config},
-    {"-m,--rs485pin", cp210x_cmd_set_mode},
-    {"-g,--rs485-logic", cp210x_cmd_set_rs485_logic},
-    {"-s,--setup", cp210x_cmd_set_rs485_setup},
-    {"-o,--hold", cp210x_cmd_set_rs485_hold},
-    {"-v,--reset-level", cp210x_cmd_set_rs485pin_gpio_reset_level},
-    {"-e,--reset", cp210x_cmd_reset}};
-
-static void cp210x_command_handle(int argc, char **argv)
-{
-    libusb_init(&g_LibusbContext);
-
-    const int size = sizeof(cmd_list) / sizeof(cmd_list[0]);
-    int i = 0;
-    for(i = 0; i < size; i++)
-    {
-        if(check_arg(argc, argv, cmd_list[i].cmd, e_case_sensitive))
-        {
-            if(e_STOP == cmd_list[i].cmd_func(argc, argv))
-            {
-                break;
-            }
-        }
+    if (holdTime) {
+        curr_platform->serOps->rs485HoldTime(holdTime);
     }
 
-    if(g_CheckSumOld)
-    {
-        libusb_device_handle *usbhd = cp210x_cmd_open_device(argc, argv);
-
-        BYTE *config = cp210x_cmd_get_config(argc, argv);
-        if(NULL != config)
-        {
-            cp210x_compute_configure_checksum(config, CP210x_MAX_CONFIG_LENGTH);
-            const U16 checkSumNew = ((config[CP210x_MAX_CONFIG_LENGTH - 2] << 8) & 0xff00) | (config[CP210x_MAX_CONFIG_LENGTH - 1] & 0xff);
-
-            if(g_CheckSumOld != checkSumNew)
-            {
-                if(e_SUCCESS != cp210x_write_config(usbhd, config, CP210x_MAX_CONFIG_LENGTH))
-                {
-                    ERROR("cp210x_write_config failed");
-                }
-            }
-        }
-
-        cp210x_close(usbhd);
+    if (setupTime) {
+        curr_platform->serOps->rs485SetupTime(setupTime);
     }
 
-    libusb_exit(g_LibusbContext);
-}
+    /* configure transceiver */
+    if (NULL != mode)
+        curr_platform->transOps->transceiver_switch_mode(mode);
 
-static void cp210x_hardware_reset(void)
-{
-    usleep(60*1000);
-    gpio_set("CP2102N-RESET", 0);
-    sleep(1);
-    gpio_set("CP2102N-RESET", 1);
-}
-
-static void print_usage(const char *name)
-{
-    printf("\
-It's used to set external serial port mode.\n\
-Usage:\n\
-    %s [ttyuart [options]] | [cp210x [options]] | [-m,--mode MODE]\n\n\
-Example:\n\
-    %s ttyuart -h\n\
-    %s cp210x -h\n\
-    %s -m,--mode <rs232 | rs485 | rs422> [-t,--terminate]\n\
-        -t,--terminate: Terminate the rs422 or rs485 bus.\n"
-           , name, name, name, name);
-}
+    //default is disable terminate
+    curr_platform->transOps->transceiver_set_termination(set_termination);
 
-int main(int argc, char **argv)
-{
-    if(1 == argc)
-    {
-        ERROR("parameter error\n");
-        print_usage(argv[0]);
-    }
-    else if(compare_string(argv[1], "-h,--help", e_case_insensitive))
-    {
-        print_usage(argv[0]);
-    }
-    else if(compare_string(argv[1], "ttyuart", e_case_insensitive))
-    {
-        ttyuart_command_handle(argc, argv);
-    }
-    else if(compare_string(argv[1], "cp210x", e_case_insensitive))
-    {
-        cp210x_command_handle(argc, argv);
-    }
-    else if(compare_string(argv[1], "-m,--mode", e_case_insensitive))
-    {
-        const int terminate = check_arg(argc, argv, "-t,--terminate", e_case_sensitive);
-        const char *mode = get_arg_string(argc, argv, "-m", e_case_sensitive, NULL);
-        if(NULL != mode)
-        {
-            gpio_switch_mode(mode, terminate);
-        }
-    }
-     else if(compare_string(argv[1], "-r,--reset", e_case_insensitive))
-    {
-        cp210x_hardware_reset();
-    }
-    else
-    {
-        ERROR("parameter error\n");
-        print_usage(argv[0]);
-    }
+release:
+    if(curr_platform->serOps->release)
+        curr_platform->serOps->release();
+    free(curr_platform);
 
-    return 0;
+    return SUCCESS;
 }

+ 56 - 0
package/switchserialmode/src/switchserialmode.h

@@ -0,0 +1,56 @@
+#ifndef SWITCH_SERIAL_MODE
+#define SWITCH_SERIAL_MODE
+
+#include <stdint.h>
+
+#define ERROR       -1
+#define SUCCESS     0
+
+typedef enum boardType {
+    BASIC_BOARD = 0,
+    ADVANCED_BOARD,
+    ADVANCED_BOARD_PG1
+} boardType_e;
+
+typedef struct transceiver_ops {
+    void (*transceiver_set_termination)( uint8_t onoff);
+    void (*transceiver_switch_mode)(const uint8_t *mode);
+} transceiver_ops_t;
+
+typedef struct serial_ops {
+    /*Device node*/
+    uint8_t *devName;
+
+    /*Init device resources*/
+    int8_t (*init)(uint8_t *devName);
+
+    /*Set serial mode,like rs232 rs485 rs422*/
+    void (*setMode)(uint8_t *mode);
+
+    /*Display current serial mode*/
+    void (*getMode)(void);
+
+    /*For the device which support setup and hold time*/
+    void (*rs485HoldTime)(uint8_t time);
+    void (*rs485SetupTime)(uint8_t time);
+
+    /*Release*/
+    void (*release)(void);
+
+    void (*preProcess)(void *);
+} serial_ops_t;
+
+typedef struct controller_setting {
+    uint32_t hold_time;
+    uint32_t setup_time;
+} controller_setting_t;
+
+typedef struct platform {
+    serial_ops_t *serOps;
+    transceiver_ops_t *transOps;
+    void *private_data;
+} platform_t;
+
+boardType_e get_board_type(void);
+
+#endif

BIN
package/switchserialmode/src/switchserialmode.o


+ 50 - 0
package/switchserialmode/src/transceiver/sp339e.c

@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) Siemens AG, 2019-2022
+ *
+ * Authors:
+ *  Gao Nian <nian.gao@siemens.com>
+ *  Chao Zeng <chao.zeng@siemens.com>
+ *
+ * This file is subject to the terms and conditions of the MIT License.  See
+ * COPYING.MIT file in the top-level directory.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <gpiod.h>
+#include <string.h>
+#include "switchserialmode.h"
+#include "gpio_helper.h"
+
+static void sp339e_set_mode(uint32_t mode0, uint32_t mode1)
+{
+    gpio_set("UART0-enable", 1);
+    gpio_set("UART0-mode0", mode0);
+    gpio_set("UART0-mode1", mode1);
+}
+
+static void sp339e_set_termination(uint8_t onoff)
+{
+    gpio_set("UART0-terminate", onoff);
+}
+
+static void sp339e_switch_mode(const uint8_t *mode)
+{
+    if (0 == strcasecmp(mode, "rs232"))
+    {
+        sp339e_set_mode(1, 0);
+    }
+    else if(0 == strcasecmp(mode, "rs485"))
+    {
+        sp339e_set_mode(0, 1);
+    }
+    else if(0 == strcasecmp(mode, "rs422"))
+    {
+        sp339e_set_mode(1, 1);
+    }
+}
+
+transceiver_ops_t sp339e_ops = {
+    .transceiver_set_termination = sp339e_set_termination,
+    .transceiver_switch_mode = sp339e_switch_mode,
+};