// // Copyright 2015, Oliver Jowett // // 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 . #include #include #include #include #include #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; }