mirror of
https://github.com/tio/tio.git
synced 2026-05-01 14:57:59 +02:00
211 lines
5.9 KiB
C
211 lines
5.9 KiB
C
/*
|
|
* tio - a serial device I/O tool
|
|
*
|
|
* Copyright (c) 2022 Martin Lund
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* 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 General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU 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.
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <sys/ioctl.h>
|
|
#include <stdbool.h>
|
|
#include "options.h"
|
|
#include "print.h"
|
|
#include "error.h"
|
|
|
|
#ifdef HAVE_RS485
|
|
|
|
#include <linux/serial.h>
|
|
|
|
static struct serial_rs485 rs485_config_saved;
|
|
static struct serial_rs485 rs485_config;
|
|
static bool rs485_config_written = false;
|
|
|
|
void rs485_parse_config(const char *arg)
|
|
{
|
|
bool token_found = true;
|
|
char *token = NULL;
|
|
char *buffer = strdup(arg);
|
|
|
|
while (token_found == true)
|
|
{
|
|
if (token == NULL)
|
|
{
|
|
token = strtok(buffer,",");
|
|
}
|
|
else
|
|
{
|
|
token = strtok(NULL, ",");
|
|
}
|
|
|
|
if (token != NULL)
|
|
{
|
|
char keyname[31];
|
|
unsigned int value;
|
|
int match_count;
|
|
|
|
match_count = sscanf(token, "%30[^=]=%d", keyname, &value);
|
|
|
|
if (match_count == 2)
|
|
{
|
|
if (!strcmp(keyname, "RTS_ON_SEND"))
|
|
{
|
|
if (value)
|
|
{
|
|
/* Set logical level for RTS pin equal to 1 when sending */
|
|
option.rs485_config_flags |= SER_RS485_RTS_ON_SEND;
|
|
}
|
|
else
|
|
{
|
|
/* Set logical level for RTS pin equal to 0 when sending */
|
|
option.rs485_config_flags &= ~(SER_RS485_RTS_ON_SEND);
|
|
}
|
|
}
|
|
else if (!strcmp(keyname, "RTS_AFTER_SEND"))
|
|
{
|
|
if (value)
|
|
{
|
|
/* Set logical level for RTS pin equal to 1 after sending */
|
|
option.rs485_config_flags |= SER_RS485_RTS_AFTER_SEND;
|
|
}
|
|
else
|
|
{
|
|
/* Set logical level for RTS pin equal to 0 after sending */
|
|
option.rs485_config_flags &= ~(SER_RS485_RTS_AFTER_SEND);
|
|
}
|
|
}
|
|
else if (!strcmp(keyname, "RTS_DELAY_BEFORE_SEND"))
|
|
{
|
|
/* Set RTS delay before send */
|
|
option.rs485_delay_rts_before_send = value;
|
|
}
|
|
else if (!strcmp(keyname, "RTS_DELAY_AFTER_SEND"))
|
|
{
|
|
/* Set RTS delay after send */
|
|
option.rs485_delay_rts_after_send = value;
|
|
}
|
|
}
|
|
else if (match_count == 1)
|
|
{
|
|
if (!strcmp(keyname, "RX_DURING_TX"))
|
|
{
|
|
/* Receive data even while sending data */
|
|
option.rs485_config_flags |= SER_RS485_RX_DURING_TX;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
token_found = false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
token_found = false;
|
|
}
|
|
}
|
|
free(buffer);
|
|
}
|
|
|
|
void rs485_print_config(void)
|
|
{
|
|
tio_printf(" RS-485 Configuration:");
|
|
tio_printf(" RTS_ON_SEND: %s", (rs485_config.flags & SER_RS485_RTS_ON_SEND) ? "high" : "low");
|
|
tio_printf(" RTS_AFTER_SEND: %s", (rs485_config.flags & SER_RS485_RTS_AFTER_SEND) ? "high" : "low");
|
|
tio_printf(" RTS_DELAY_BEFORE_SEND = %d", rs485_config.delay_rts_before_send);
|
|
tio_printf(" RTS_DELAY_AFTER_SEND = %d", rs485_config.delay_rts_after_send);
|
|
tio_printf(" RX_DURING_TX: %s", (rs485_config.flags & SER_RS485_RX_DURING_TX) ? "enabled" : "disabled");
|
|
}
|
|
|
|
int rs485_mode_enable(int fd)
|
|
{
|
|
/* Save existing RS-485 configuration */
|
|
ioctl (fd, TIOCGRS485, &rs485_config_saved);
|
|
|
|
/* Prepare new RS-485 configuration */
|
|
rs485_config.flags = SER_RS485_ENABLED;
|
|
rs485_config.flags |= option.rs485_config_flags;
|
|
|
|
if (option.rs485_delay_rts_before_send > 0)
|
|
{
|
|
rs485_config.delay_rts_before_send = option.rs485_delay_rts_before_send;
|
|
}
|
|
else
|
|
{
|
|
rs485_config.delay_rts_before_send = rs485_config_saved.delay_rts_before_send;
|
|
}
|
|
|
|
if (option.rs485_delay_rts_after_send > 0)
|
|
{
|
|
rs485_config.delay_rts_after_send = option.rs485_delay_rts_after_send;
|
|
}
|
|
else
|
|
{
|
|
rs485_config.delay_rts_after_send = rs485_config_saved.delay_rts_after_send;
|
|
}
|
|
|
|
/* Write new RS-485 configuration */
|
|
if (ioctl(fd, TIOCSRS485, &rs485_config) < 0)
|
|
{
|
|
tio_warning_printf("RS-485 mode is not supported by your device (%s)", strerror(errno));
|
|
return -1;
|
|
}
|
|
|
|
rs485_config_written = true;
|
|
|
|
return 0;
|
|
}
|
|
|
|
void rs485_mode_restore(int fd)
|
|
{
|
|
if (rs485_config_written)
|
|
{
|
|
/* Write saved RS-485 configuration */
|
|
if (ioctl(fd, TIOCSRS485, &rs485_config_saved) < 0)
|
|
{
|
|
tio_warning_printf("TIOCGRS485 ioctl failed (%s)", strerror(errno));
|
|
}
|
|
}
|
|
}
|
|
|
|
#else
|
|
|
|
void rs485_parse_config(const char *arg)
|
|
{
|
|
UNUSED(arg);
|
|
return;
|
|
}
|
|
|
|
void rs485_print_config(void)
|
|
{
|
|
return;
|
|
}
|
|
|
|
int rs485_mode_enable(int fd)
|
|
{
|
|
UNUSED(fd);
|
|
tio_error_printf("RS485 mode is not supported on your system");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
void rs485_mode_restore(int fd)
|
|
{
|
|
UNUSED(fd);
|
|
return;
|
|
}
|
|
|
|
#endif
|