kopia lustrzana https://github.com/cyoung/stratux
200 wiersze
4.9 KiB
C
200 wiersze
4.9 KiB
C
//
|
|
// Copyright 2015, Oliver Jowett <oliver@mutability.co.uk>
|
|
//
|
|
|
|
// This file is free software: you may copy, redistribute 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 file 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, see <http://www.gnu.org/licenses/>.
|
|
|
|
#include <stdlib.h>
|
|
#include <fcntl.h>
|
|
#include <errno.h>
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
|
|
#include "uat.h"
|
|
#include "reader.h"
|
|
|
|
struct dump978_reader {
|
|
int fd;
|
|
char buf[4096];
|
|
uint8_t frame[UPLINK_FRAME_DATA_BYTES]; // max uplink frame size
|
|
int used;
|
|
};
|
|
|
|
static int process_input(struct dump978_reader *reader, frame_handler_t handler, void *handler_data);
|
|
static int process_line(struct dump978_reader *reader, frame_handler_t handler, void *handler_data, char *p, char *end);
|
|
static int hexbyte(char *buf);
|
|
|
|
struct dump978_reader *dump978_reader_new(int fd, int nonblock)
|
|
{
|
|
struct dump978_reader *reader = calloc(1, sizeof(*reader));
|
|
if (!reader)
|
|
return NULL;
|
|
|
|
if (nonblock) {
|
|
int flags = fcntl(fd, F_GETFL);
|
|
if (flags < 0 || fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) {
|
|
int save_errno = errno;
|
|
free(reader);
|
|
errno = save_errno;
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
reader->fd = fd;
|
|
reader->used = 0;
|
|
return reader;
|
|
}
|
|
|
|
int dump978_read_frames(struct dump978_reader *reader,
|
|
frame_handler_t handler,
|
|
void *handler_data)
|
|
{
|
|
int framecount = 0;
|
|
ssize_t bytes_read;
|
|
|
|
if (!reader) {
|
|
errno = EINVAL;
|
|
return -1;
|
|
}
|
|
|
|
for (;;) {
|
|
if (reader->used == sizeof(reader->buf)) {
|
|
// line too long, ditch input
|
|
reader->used = 0;
|
|
}
|
|
|
|
bytes_read = read(reader->fd,
|
|
reader->buf + reader->used,
|
|
sizeof(reader->buf) - reader->used);
|
|
if (bytes_read <= 0)
|
|
break;
|
|
|
|
reader->used += bytes_read;
|
|
|
|
framecount += process_input(reader, handler, handler_data);
|
|
}
|
|
|
|
if (bytes_read == 0)
|
|
return framecount; // EOF
|
|
|
|
// only report EAGAIN et al if no frames were read
|
|
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
|
|
return (framecount > 0 ? framecount : -1);
|
|
|
|
return -1; // propagate unexpected error
|
|
}
|
|
|
|
void dump978_reader_free(struct dump978_reader *reader)
|
|
{
|
|
if (!reader)
|
|
return;
|
|
|
|
free(reader);
|
|
}
|
|
|
|
static int process_input(struct dump978_reader *reader, frame_handler_t handler, void *handler_data)
|
|
{
|
|
char *p = reader->buf;
|
|
char *end = reader->buf + reader->used;
|
|
int framecount = 0;
|
|
|
|
while (p < end) {
|
|
char *newline;
|
|
|
|
newline = memchr(p, '\n', end - p);
|
|
if (newline == NULL)
|
|
break;
|
|
|
|
if (*p == '-' || *p == '+')
|
|
framecount += process_line(reader, handler, handler_data, p, newline);
|
|
|
|
p = newline+1;
|
|
}
|
|
|
|
if (p >= end) {
|
|
reader->used = 0;
|
|
} else {
|
|
reader->used = end - p;
|
|
memmove(reader->buf, p, reader->used);
|
|
}
|
|
|
|
return framecount;
|
|
}
|
|
|
|
static int process_line(struct dump978_reader *reader, frame_handler_t handler, void *handler_data, char *p, char *end)
|
|
{
|
|
uint8_t *out;
|
|
int len = 0;
|
|
frame_type_t frametype;
|
|
|
|
if (*p == '-')
|
|
frametype = UAT_DOWNLINK;
|
|
else if (*p == '+')
|
|
frametype = UAT_UPLINK;
|
|
else
|
|
return 0;
|
|
|
|
out = reader->frame;
|
|
++p;
|
|
while (p < end) {
|
|
int byte;
|
|
|
|
if (p[0] == ';') {
|
|
// ignore rest of line
|
|
handler(frametype, reader->frame, len, handler_data);
|
|
return 1;
|
|
}
|
|
|
|
if (len >= sizeof(reader->frame))
|
|
return 0; // oversized frame
|
|
|
|
byte = hexbyte(p);
|
|
if (byte < 0)
|
|
return 0; // badly formatted byte
|
|
|
|
++len;
|
|
*out++ = byte;
|
|
p += 2;
|
|
}
|
|
|
|
return 0; // ran off the end without seeing semicolon
|
|
}
|
|
|
|
static int hexbyte(char *buf)
|
|
{
|
|
int i;
|
|
char c;
|
|
|
|
c = buf[0];
|
|
if (c >= '0' && c <= '9')
|
|
i = (c - '0');
|
|
else if (c >= 'a' && c <= 'f')
|
|
i = (c - 'a' + 10);
|
|
else if (c >= 'A' && c <= 'F')
|
|
i = (c - 'A' + 10);
|
|
else
|
|
return -1;
|
|
|
|
i <<= 4;
|
|
c = buf[1];
|
|
if (c >= '0' && c <= '9')
|
|
return i | (c - '0');
|
|
else if (c >= 'a' && c <= 'f')
|
|
return i | (c - 'a' + 10);
|
|
else if (c >= 'A' && c <= 'F')
|
|
return i | (c - 'A' + 10);
|
|
else
|
|
return -1;
|
|
}
|