|
@@ -1,1259 +1,171 @@
|
|
/*
|
|
/*
|
|
- * Copyright (c) Siemens AG, 2019
|
|
|
|
|
|
+ * Copyright (c) Siemens AG, 2019-2022
|
|
*
|
|
*
|
|
* Authors:
|
|
* Authors:
|
|
* Gao Nian <nian.gao@siemens.com>
|
|
* 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
|
|
* This file is subject to the terms and conditions of the MIT License. See
|
|
* COPYING.MIT file in the top-level directory.
|
|
* 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 <stdbool.h>
|
|
#include <stdlib.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <stdio.h>
|
|
|
|
+#include <getopt.h>
|
|
#include <string.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");
|
|
perror("Error");
|
|
}
|
|
}
|
|
-
|
|
|
|
close(fd);
|
|
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;
|
|
break;
|
|
-
|
|
|
|
- default:
|
|
|
|
- isCandidateDevice = false;
|
|
|
|
|
|
+ case 'm':
|
|
|
|
+ mode = strdup(optarg);
|
|
break;
|
|
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;
|
|
}
|
|
}
|