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.
		
		
		
		
		
			
		
			
				
					143 lines
				
				4.6 KiB
			
		
		
			
		
	
	
					143 lines
				
				4.6 KiB
			|   
											10 years ago
										 | /*
 | ||
|  | The MIT License (MIT) | ||
|  | 
 | ||
|  | Copyright (c) 2016 Fred Sundvik | ||
|  | 
 | ||
|  | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
|  | of this software and associated documentation files (the "Software"), to deal | ||
|  | in the Software without restriction, including without limitation the rights | ||
|  | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
|  | copies of the Software, and to permit persons to whom the Software is | ||
|  | furnished to do so, subject to the following conditions: | ||
|  | 
 | ||
|  | The above copyright notice and this permission notice shall be included in all | ||
|  | copies or substantial portions of the Software. | ||
|  | 
 | ||
|  | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
|  | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
|  | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
|  | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
|  | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
|  | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
|  | SOFTWARE. | ||
|  | */ | ||
|  | 
 | ||
|   
											10 years ago
										 | #include "serial_link/protocol/byte_stuffer.h"
 | ||
|  | #include "serial_link/protocol/frame_validator.h"
 | ||
|  | #include "serial_link/protocol/physical.h"
 | ||
|  | #include <stdbool.h>
 | ||
|   
											10 years ago
										 | 
 | ||
|   
											10 years ago
										 | // This implements the "Consistent overhead byte stuffing protocol"
 | ||
|  | // https://en.wikipedia.org/wiki/Consistent_Overhead_Byte_Stuffing
 | ||
|  | // http://www.stuartcheshire.org/papers/COBSforToN.pdf
 | ||
|  | 
 | ||
|  | typedef struct byte_stuffer_state { | ||
|  |     uint16_t next_zero; | ||
|  |     uint16_t data_pos; | ||
|   
											10 years ago
										 |     bool long_frame; | ||
|  |     uint8_t data[MAX_FRAME_SIZE]; | ||
|   
											10 years ago
										 | }byte_stuffer_state_t; | ||
|  | 
 | ||
|   
											10 years ago
										 | static byte_stuffer_state_t states[NUM_LINKS]; | ||
|  | 
 | ||
|  | void init_byte_stuffer_state(byte_stuffer_state_t* state) { | ||
|  |     state->next_zero = 0; | ||
|  |     state->data_pos = 0; | ||
|  |     state->long_frame = false; | ||
|  | } | ||
|   
											10 years ago
										 | 
 | ||
|  | void init_byte_stuffer(void) { | ||
|   
											10 years ago
										 |     int i; | ||
|  |     for (i=0;i<NUM_LINKS;i++) { | ||
|  |         init_byte_stuffer_state(&states[i]); | ||
|  |     } | ||
|   
											10 years ago
										 | } | ||
|  | 
 | ||
|   
											10 years ago
										 | void byte_stuffer_recv_byte(uint8_t link, uint8_t data) { | ||
|   
											10 years ago
										 |     byte_stuffer_state_t* state = &states[link]; | ||
|   
											10 years ago
										 |     // Start of a new frame
 | ||
|   
											10 years ago
										 |     if (state->next_zero == 0) { | ||
|  |         state->next_zero = data; | ||
|  |         state->long_frame = data == 0xFF; | ||
|  |         state->data_pos = 0; | ||
|   
											10 years ago
										 |         return; | ||
|  |     } | ||
|  | 
 | ||
|   
											10 years ago
										 |     state->next_zero--; | ||
|   
											10 years ago
										 |     if (data == 0) { | ||
|   
											10 years ago
										 |         if (state->next_zero == 0) { | ||
|   
											10 years ago
										 |             // The frame is completed
 | ||
|   
											10 years ago
										 |             if (state->data_pos > 0) { | ||
|  |                 validator_recv_frame(link, state->data, state->data_pos); | ||
|   
											10 years ago
										 |             } | ||
|   
											10 years ago
										 |         } | ||
|  |         else { | ||
|  |             // The frame is invalid, so reset
 | ||
|   
											10 years ago
										 |             init_byte_stuffer_state(state); | ||
|   
											10 years ago
										 |         } | ||
|   
											10 years ago
										 |     } | ||
|  |     else { | ||
|   
											10 years ago
										 |         if (state->data_pos == MAX_FRAME_SIZE) { | ||
|   
											10 years ago
										 |             // We exceeded our maximum frame size
 | ||
|  |             // therefore there's nothing else to do than reset to a new frame
 | ||
|   
											10 years ago
										 |             state->next_zero = data; | ||
|  |             state->long_frame = data == 0xFF; | ||
|  |             state->data_pos = 0; | ||
|   
											10 years ago
										 |         } | ||
|   
											10 years ago
										 |         else if (state->next_zero == 0) { | ||
|  |             if (state->long_frame) { | ||
|   
											10 years ago
										 |                 // This is part of a long frame, so continue
 | ||
|   
											10 years ago
										 |                 state->next_zero = data; | ||
|  |                 state->long_frame = data == 0xFF; | ||
|   
											10 years ago
										 |             } | ||
|  |             else { | ||
|  |                 // Special case for zeroes
 | ||
|   
											10 years ago
										 |                 state->next_zero = data; | ||
|  |                 state->data[state->data_pos++] = 0; | ||
|   
											10 years ago
										 |             } | ||
|   
											10 years ago
										 |         } | ||
|  |         else { | ||
|   
											10 years ago
										 |             state->data[state->data_pos++] = data; | ||
|   
											10 years ago
										 |         } | ||
|  |     } | ||
|   
											10 years ago
										 | } | ||
|   
											10 years ago
										 | 
 | ||
|   
											10 years ago
										 | static void send_block(uint8_t link, uint8_t* start, uint8_t* end, uint8_t num_non_zero) { | ||
|  |     send_data(link, &num_non_zero, 1); | ||
|   
											10 years ago
										 |     if (end > start) { | ||
|   
											10 years ago
										 |         send_data(link, start, end-start); | ||
|   
											10 years ago
										 |     } | ||
|  | } | ||
|  | 
 | ||
|   
											10 years ago
										 | void byte_stuffer_send_frame(uint8_t link, uint8_t* data, uint16_t size) { | ||
|   
											10 years ago
										 |     const uint8_t zero = 0; | ||
|   
											10 years ago
										 |     if (size > 0) { | ||
|   
											10 years ago
										 |         uint16_t num_non_zero = 1; | ||
|   
											10 years ago
										 |         uint8_t* end = data + size; | ||
|  |         uint8_t* start = data; | ||
|  |         while (data < end) { | ||
|   
											10 years ago
										 |             if (num_non_zero == 0xFF) { | ||
|  |                 // There's more data after big non-zero block
 | ||
|  |                 // So send it, and start a new block
 | ||
|   
											10 years ago
										 |                 send_block(link, start, data, num_non_zero); | ||
|   
											10 years ago
										 |                 start = data; | ||
|   
											10 years ago
										 |                 num_non_zero = 1; | ||
|  |             } | ||
|  |             else { | ||
|   
											10 years ago
										 |                 if (*data == 0) { | ||
|  |                     // A zero encountered, so send the block
 | ||
|   
											10 years ago
										 |                     send_block(link, start, data, num_non_zero); | ||
|   
											10 years ago
										 |                     start = data + 1; | ||
|  |                     num_non_zero = 1; | ||
|  |                 } | ||
|  |                 else { | ||
|  |                     num_non_zero++; | ||
|  |                 } | ||
|  |                 ++data; | ||
|   
											10 years ago
										 |             } | ||
|  |         } | ||
|   
											10 years ago
										 |         send_block(link, start, data, num_non_zero); | ||
|  |         send_data(link, &zero, 1); | ||
|   
											10 years ago
										 |     } | ||
|  | } |