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;
 | |
| }
 |