nut/tools/nut-scanner/nutscan-serial.c
2016-07-18 02:11:41 +02:00

201 lines
5.1 KiB
C

/*
* Copyright (C) 2011 - EATON
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*! \file nutscan-serial.c
\brief helper functions to get serial devices name
\author Frederic Bohe <fredericbohe@eaton.com>
\author Arnaud Quette <arnaud.quette@free.fr>
*/
#include "nutscan-serial.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "nut_platform.h"
#ifdef WIN32
/* Windows: all serial port names start with "COM" */
#define SERIAL_PORT_PREFIX "COM"
#else
/* Unix: all serial port names start with "/dev/tty" */
#define SERIAL_PORT_PREFIX "/dev/tty"
#endif
#define ERR_OUT_OF_BOUND "Serial port range out of bound (must be 0 to 9 or a to z depending on your system)\n"
typedef struct {
char * name;
char auto_start_port;
char auto_stop_port;
} device_portname_t;
device_portname_t device_portname[] = {
#ifdef NUT_PLATFORM_HPUX
/* the first number seems to be a card instance, the second number seems
to be a port number */
{ "/dev/tty0p%c", '0', '9' },
{ "/dev/tty1p%c", '0', '9' },
/* osf/1 and Digital UNIX style */
{ "/dev/tty0%c", '0', '9' },
#endif
#ifdef NUT_PLATFORM_SOLARIS
{ "/dev/tty%c", 'a', 'z' },
#endif
#ifdef NUT_PLATFORM_AIX
{ "/dev/tty%c", '0', '9' },
#endif
#ifdef NUT_PLATFORM_LINUX
{ "/dev/ttyS%c", '0', '9' },
{ "/dev/ttyUSB%c", '0', '9' },
#endif
#ifdef NUT_PLATFORM_MS_WINDOWS
{ "COM%c", '1', '9'},
#endif
/* SGI IRIX */
/* { "/dev/ttyd%i", "=" }, */
/* { "/dev/ttyf%i", "=" }, */
/* FIXME: Mac OS X has no serial port, but maybe ttyUSB? */
{ NULL, 0 }
};
/* Return 1 if port_name is a full path name to a serial port,
* as per SERIAL_PORT_PREFIX */
static int is_serial_port_path(const char * port_name)
{
if (!strncmp(port_name, SERIAL_PORT_PREFIX, strlen(SERIAL_PORT_PREFIX))) {
return 1;
}
return 0;
}
/* Add "port" to "list" */
static char ** add_port(char ** list, char * port)
{
char ** res;
int count = 0;
if(list == NULL) {
count = 0;
}
else {
while(list[count] != NULL) {
count++;
}
}
/*+1 to get the number of port from the index nb_ports*/
/*+1 for the terminal NULL */
res = realloc(list,(count+1+1)*sizeof(char*));
if( res == NULL ) {
return NULL;
}
res[count] = strdup(port);
res[count+1] = NULL;
return res;
}
/* Return a list of serial ports name, in 'ports_list', according to the OS,
* the provided 'ports_range', and the number of available ports */
char ** nutscan_get_serial_ports_list(const char *ports_range)
{
char start_port = 0;
char stop_port = 0;
char current_port = 0;
char * list_sep_ptr = NULL;
char ** ports_list = NULL;
char str_tmp[128];
char * tok;
device_portname_t *cur_device = NULL;
char * saveptr = NULL;
char * range;
int flag_auto = 0;
/* 1) check ports_list */
if ((ports_range == NULL) || (!strncmp(ports_range, "auto", 4))) {
flag_auto = 1;
}
else {
range = strdup(ports_range);
/* we have a list:
* - single element: X (digit) or port name (COM1, /dev/ttyS0, ...)
* - range list: X-Y
* - multiple elements (coma separated): /dev/ttyS0,/dev/ttyUSB0 */
if ( (list_sep_ptr = strchr(range, '-')) != NULL ) {
tok = strtok_r(range,"-",&saveptr);
if( tok[1] != 0 ) {
fprintf(stderr,ERR_OUT_OF_BOUND);
free(range);
return NULL;
}
start_port = tok[0];
tok = strtok_r(NULL,"-",&saveptr);
if( tok != NULL ) {
if( tok[1] != 0 ) {
fprintf(stderr,ERR_OUT_OF_BOUND);
free(range);
return NULL;
}
stop_port = tok[0];
}
else {
stop_port = start_port;
}
}
else if ( ((list_sep_ptr = strchr(ports_range, ',')) != NULL )
&& (is_serial_port_path(ports_range)) ) {
tok = strtok_r(range,",",&saveptr);
while( tok != NULL ) {
ports_list = add_port(ports_list,tok);
tok = strtok_r(NULL,",",&saveptr);
}
}
else {
/* we have been provided a single port name */
/* it's a full device name */
if( ports_range[1] != 0 ) {
ports_list = add_port(ports_list,range);
}
/* it's device number */
else {
start_port = stop_port = ports_range[0];
}
}
free(range);
}
if( start_port == 0 && !flag_auto) {
return ports_list;
}
for (cur_device=device_portname;cur_device->name!= NULL;cur_device++) {
if( flag_auto ) {
start_port = cur_device->auto_start_port;
stop_port = cur_device->auto_stop_port;
}
for( current_port=start_port; current_port <= stop_port;
current_port++){
snprintf(str_tmp, sizeof(str_tmp),cur_device->name,
current_port);
ports_list = add_port(ports_list,str_tmp);
}
}
return ports_list;
}