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