You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

252 lines
6.3 KiB

#include <stdio.h> /* Standard input/output definitions */
#include <stdlib.h>
#include <stdint.h> /* Standard types */
#include <string.h> /* String function definitions */
#include <unistd.h> /* UNIX standard function definitions */
#include <fcntl.h> /* File control definitions */
#include <errno.h> /* Error number definitions */
#include <termios.h> /* POSIX terminal control definitions */
#include <sys/ioctl.h>
#ifdef __APPLE__
// define 460k baud rate, seems not to be available in headers on osx
#define B460800 460800
#endif
void help(void);
int serialport_init(const char* serialport, unsigned int baud);
int serialport_read_until(int fd, unsigned int until);
// Checks for an argument (characters with a leading '-')
// Returns 0 if argument does not exist or the index of argument
// type in the argv[] array
int parArgTypExists (int argc, char *argv[], char argType)
{
char tmp[3];
tmp[0] = '-';
tmp[1] = argType;
tmp[2] = 0;
if (argc > 1) {
for (int i = 1; i < argc; i++) {
if (!strcmp (argv[i], tmp))
return i;
}
}
return 0;
}
// Get string argument value
// Returns 0 in error case, returns 1 if OK
// (string is limited to max. 4096 characters)
int parGetString (int argc, char *argv[], char argType, char *value)
{
int a = parArgTypExists(argc, argv, argType);
// Check for errors
if (a == 0) return 0;
if (a >= (argc -1)) return 0;
if (strlen(argv[a+1]) > 256) return 0;
strcpy(value, argv[a+1]);
return 1;
}
// Get unsigned int argument value
// Returns 0 in error case, 1 if OK
int parGetUnsignedInt (int argc, char *argv[], char argType,
unsigned int *value)
{
int a = parArgTypExists (argc, argv, argType);
/* error checking */
if (a == 0) return 0;
if (a >= (argc -1)) return 0;
a = sscanf(argv[a+1], "%iu", value);
return a;
}
void help(void) {
printf("Usage: uart_trng -p <serialport> [OPTIONS]\n"
"\n"
"Options:\n"
" -h, --help Print this help message\n"
" -p, --port=serialport Serial port where the uart_trng device is plugged on\n"
" -b, --baud=baudrate Baudrate (bps) of uart_trng device, default = 9600\n"
" -s, --size number of bytes to receive from uart_trng device,\n"
" 0 for reading until break with Ctrl-c, default = 1024\n"
"\n");
}
int main(int argc, char *argv[])
{
int fd = 0;
int r = 0;
char serialport[256];
unsigned int baudrate = 9600;
unsigned int size = 1024;
// check for command line arguments
if (argc == 1) {
help();
return 1;
}
else {
if (parArgTypExists (argc, argv, 'h')) {
help();
return 1;
}
// get serial port
if (parArgTypExists (argc, argv, 'p')) {
r = parGetString (argc, argv, 'p', serialport);
if (r == 0) {
return (1);
}
} else {
help();
return (1);
}
// get baud rate
if (parArgTypExists (argc, argv, 'b')) {
r = parGetUnsignedInt (argc, argv, 'b', &baudrate);
if (r == 0) {
return (1);
}
}
// get read size in bytes
if (parArgTypExists (argc, argv, 's')) {
r = parGetUnsignedInt (argc, argv, 's', &size);
if (r == 0) {
return (1);
}
}
}
fd = serialport_init(serialport, baudrate);
if (fd == -1)
return -1;
serialport_read_until(fd, size);
exit(EXIT_SUCCESS);
}
int serialport_read_until(int fd, unsigned int until)
{
char b[1];
int index = 0;
int n;
while (1) {
while (1) {
// read one char
n = read(fd, b, 1);
// we had a read error
// check if there were no bytes to read or if it was a real error
if (n == -1) {
if (errno != EAGAIN) {
fprintf(stderr,"serial read error at byte %d", index);
return -1;
}
} else {
break;
}
}
// we got no byte, so wait 10 ms for the next try
if (n == 0) {
usleep (10 * 1000);
continue;
}
printf("%c",b[0]);
if (until == 0) {
continue;
} else {
index++;
if (index == until) {
break;
}
}
};
fprintf(stderr,"uart_trng: read %d random bytes from device\n", until);
return 0;
}
// takes the string name of the serial port (e.g. "/dev/tty.usbserial","COM1")
// and a baud rate (bps) and connects to that port at that speed and 8N1.
// opens the port in fully raw mode so you can send binary data.
// returns valid fd, or -1 on error
int serialport_init(const char* serialport, unsigned int baud)
{
struct termios toptions;
int fd;
fprintf(stderr,"init_serialport: opening port %s @ %u bps\n",
serialport, baud);
fd = open(serialport, O_RDWR | O_NOCTTY | O_NDELAY);
if (fd == -1) {
perror("init_serialport: Unable to open port ");
return -1;
}
if (tcgetattr(fd, &toptions) < 0) {
perror("init_serialport: Couldn't get term attributes");
return -1;
}
speed_t brate = baud; // let you override switch below if needed
switch(baud) {
case 4800: brate=B4800; break;
case 9600: brate=B9600; break;
#ifdef B14400
case 14400: brate=B14400; break;
#endif
case 19200: brate=B19200; break;
#ifdef B28800
case 28800: brate=B28800; break;
#endif
case 38400: brate=B38400; break;
case 57600: brate=B57600; break;
case 115200: brate=B115200; break;
case 230400: brate=B230400; break;
case 460800: brate=B460800; break;
}
cfsetispeed(&toptions, brate);
cfsetospeed(&toptions, brate);
// 8N1
toptions.c_cflag &= ~PARENB;
toptions.c_cflag &= ~CSTOPB;
toptions.c_cflag &= ~CSIZE;
toptions.c_cflag |= CS8;
// no flow control
toptions.c_cflag &= ~CRTSCTS;
toptions.c_cflag |= CREAD | CLOCAL; // turn on READ & ignore ctrl lines
toptions.c_iflag &= ~(IXON | IXOFF | IXANY); // turn off s/w flow ctrl
toptions.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // make raw
toptions.c_oflag &= ~OPOST; // make raw
// see: http://unixwiz.net/techtips/termios-vmin-vtime.html
toptions.c_cc[VMIN] = 0;
toptions.c_cc[VTIME] = 20;
if( tcsetattr(fd, TCSANOW, &toptions) < 0) {
perror("init_serialport: Couldn't set term attributes");
return -1;
}
return fd;
}