serial: smart link

This commit is contained in:
fengzero
2023-07-07 07:23:16 +00:00
parent 45994cc23f
commit ef06dec1a5
4 changed files with 319 additions and 0 deletions
+6
View File
@@ -89,6 +89,12 @@ set(NEURON_BASE_SOURCES
src/utils/async_queue.c
src/utils/mem_cache.c
${PERSIST_SOURCES})
if (SMART_LINK)
message(STATUS "using smart link")
add_definitions(-DNEU_SMART_LINK)
set(NEURON_BASE_SOURCES ${NEURON_BASE_SOURCES} src/connection/smart_link.c)
endif()
add_library(neuron-base SHARED)
target_sources(neuron-base PRIVATE ${NEURON_BASE_SOURCES} ${NEURON_SRC_PARSE})
@@ -0,0 +1,25 @@
/**
* NEURON IIoT System for Industry 4.0
* Copyright (C) 2020-2023 EMQ Technologies Co., Ltd All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
**/
#ifndef NEURON_CONNECTION_SMART_LINK_H
#define NEURON_CONNECTION_SMART_LINK_H
int neu_conn_smart_link_auto_set(const char *dev_path);
#endif
+6
View File
@@ -854,6 +854,12 @@ static void conn_connect(neu_conn_t *conn)
break;
}
case NEU_CONN_TTY_CLIENT: {
#ifdef NEU_SMART_LINK
#include "connection/neu_smart_link.h"
int ret =
neu_conn_smart_link_auto_set(conn->param.params.tty_client.device);
zlog_notice(conn->param.log, "smart link ret: %d", ret);
#endif
struct termios tty_opt = { 0 };
fd = open(conn->param.params.tty_client.device, O_RDWR | O_NOCTTY, 0);
+282
View File
@@ -0,0 +1,282 @@
#include <errno.h>
#include <fcntl.h>
#include <linux/serial.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <termios.h>
#include <unistd.h>
#include <jansson.h>
#include "json/json.h"
#include "connection/neu_smart_link.h"
#define DEVICE_CONF_PATH "/etc/config/device.conf"
#define SERIAL_CONF_PATH "/etc/config/serial.conf"
#define SMART_LINK_PATH "/dev/smartlink"
#define TYPE 'S'
#define UART_RS232 _IOWR(TYPE, 1, int)
#define UART_RS485 _IOWR(TYPE, 0, int)
enum SERIAL_MODE { SM_RS232, SM_RS422, SM_RS485 };
static int get_port(const char *path);
static int get_port_property(int port, int *mode, int *baudrate);
static int read_file(const char *path, char **buf);
static int set_serial_mode(const char *dev_path, int baudrate, int mode);
int neu_conn_smart_link_auto_set(const char *dev_path)
{
int mode = 0;
int baudrate = 0;
int port = get_port(dev_path);
if (port <= 0) {
return -1;
}
printf("get port %d\n", port);
int ret = get_port_property(port, &mode, &baudrate);
if (ret != 0) {
return -1;
}
printf("get port property %d %d\n", mode, baudrate);
ret = set_serial_mode(dev_path, baudrate, mode);
return ret;
}
static int read_file(const char *path, char **buf)
{
FILE *fp = NULL;
fp = fopen(path, "r");
if (fp == NULL) {
return -1;
}
fseek(fp, 0, SEEK_END);
int size = ftell(fp);
rewind(fp);
*buf = calloc(1, size + 1);
if (buf == NULL) {
fclose(fp);
return -1;
}
int ret = fread(*buf, 1, size, fp);
if (ret != size) {
fclose(fp);
free(*buf);
return -1;
}
fclose(fp);
return ret;
}
static int get_port(const char *dev_path)
{
json_t * root = NULL;
json_error_t error;
char * buf = NULL;
int ret = read_file(DEVICE_CONF_PATH, &buf);
if (ret <= 0) {
return -1;
}
root = json_loads(buf, JSON_DECODE_ANY, &error);
if (root == NULL) {
free(buf);
return -1;
}
neu_json_elem_t e_tty = {
.name = "tty_name",
.t = NEU_JSON_OBJECT,
};
ret = neu_json_decode_value(root, &e_tty);
if (ret != 0 || json_is_array((json_t *) e_tty.v.val_object) == false) {
free(buf);
json_decref(root);
return -1;
}
int index = 0;
json_t *e_dev = NULL;
json_array_foreach(e_tty.v.val_object, index, e_dev)
{
neu_json_elem_t e_dd = {
.name = "device",
.t = NEU_JSON_STR,
};
ret = neu_json_decode_value(e_dev, &e_dd);
if (ret != 0) {
free(buf);
json_decref(root);
return -1;
}
if (strcmp(e_dd.v.val_str, dev_path) == 0) {
neu_json_elem_t e_port = {
.name = "port",
.t = NEU_JSON_INT,
};
ret = neu_json_decode_value(e_dev, &e_port);
if (ret != 0) {
free(buf);
json_decref(root);
return -1;
}
free(buf);
json_decref(root);
free(e_dd.v.val_str);
return e_port.v.val_int;
}
free(e_dd.v.val_str);
}
free(buf);
json_decref(root);
return -1;
}
static int get_port_property(int port, int *mode, int *baudrate)
{
json_t * root = NULL;
json_error_t error;
char * buf = NULL;
int ret = read_file(SERIAL_CONF_PATH, &buf);
if (ret <= 0) {
return -1;
}
root = json_loads(buf, JSON_DECODE_ANY, &error);
if (root == NULL) {
free(buf);
return -1;
}
json_t *e_port = json_array_get(root, port - 1);
if (e_port == NULL) {
json_decref(root);
free(buf);
return -1;
}
neu_json_elem_t elems[] = {
{
.name = "mode",
.t = NEU_JSON_INT,
},
{
.name = "baudrate",
.t = NEU_JSON_INT,
},
};
ret = neu_json_decode_by_json(e_port, NEU_JSON_ELEM_SIZE(elems), elems);
if (ret != 0) {
free(buf);
json_decref(root);
return -1;
}
*mode = elems[0].v.val_int;
*baudrate = elems[1].v.val_int;
json_decref(root);
free(buf);
return 0;
}
static int set_serial_mode(const char *dev_path, int baudrate, int mode)
{
static pthread_mutex_t mode_switch_mtx = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_lock(&mode_switch_mtx);
int serial_fd, switch_fd;
int tty_num, para;
int ret = -1;
struct serial_rs485 conf;
conf.flags &= !SER_RS485_ENABLED;
switch (baudrate) {
case 38400:
conf.delay_rts_after_send = 1;
break;
case 57600:
conf.delay_rts_after_send = 4;
break;
case 115200:
conf.delay_rts_after_send = 6;
break;
default:
conf.delay_rts_after_send = 0;
break;
}
if ((serial_fd = open(dev_path, O_RDWR | O_NOCTTY | O_NDELAY)) < 0) {
fprintf(stderr, "open %s failed, fd: %d, strerr: %s\n", dev_path,
serial_fd, strerror(errno));
goto out;
}
if (mode != SM_RS232) {
if (ioctl(serial_fd, TIOCMGET, &para) != 0) {
fprintf(stderr, "ioctl failed, strerr: %s\n", strerror(errno));
goto out2;
}
if (mode == SM_RS422) {
para |= TIOCM_DTR;
conf.flags |= SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND;
} else if (mode == SM_RS485) {
para &= ~TIOCM_DTR;
conf.flags |= SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND;
}
if (ioctl(serial_fd, TIOCMSET, &para) != 0) {
fprintf(stderr, "ioctl failed, strerr: %s\n", strerror(errno));
goto out2;
}
}
ioctl(serial_fd, TIOCSRS485, &conf);
if ((switch_fd = open(SMART_LINK_PATH, O_RDWR)) < 0) {
fprintf(stderr, "open %s failed, ret: %d, strerr: %s\n",
SMART_LINK_PATH, switch_fd, strerror(errno));
goto out2;
}
sscanf(dev_path, "%*[a-zA-Z/]%d", &tty_num);
printf("tty_num: %d\n", tty_num);
if (mode == SM_RS232) {
ret = ioctl(switch_fd, UART_RS232, tty_num);
} else {
ret = ioctl(switch_fd, UART_RS485, tty_num);
}
if (ret < 0) {
fprintf(stderr, "ioctl failed, ret: %d, strerr: %s\n", ret,
strerror(errno));
}
close(switch_fd);
out2:
close(serial_fd);
out:
pthread_mutex_unlock(&mode_switch_mtx);
return ret;
}