From e60ccb8965bbc1a460bf85bfc87b885cf1260151 Mon Sep 17 00:00:00 2001 From: Patrick Roth Date: Fri, 4 Oct 2019 10:17:42 +0200 Subject: Initial commit import from github --- o3000_xfer_handler.c | 175 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 175 insertions(+) create mode 100644 o3000_xfer_handler.c (limited to 'o3000_xfer_handler.c') diff --git a/o3000_xfer_handler.c b/o3000_xfer_handler.c new file mode 100644 index 0000000..4ae8b2f --- /dev/null +++ b/o3000_xfer_handler.c @@ -0,0 +1,175 @@ +/** +* @file o3000_xfer_handler.c +* @brief O-3000 USB transfer handler +* @author Patrick Brunner - brunner@stettbacher.ch +* @author Patrick Roth - roth@stettbacher.ch +* @version 1.1 +* @date 2016-03-01 +* @copyright 2012-2016 Stettbacher Signal Processing AG +* +* @remarks +* +*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation; either
+* version 2.1 of the License, or (at your option) any later version.
+*
+* This library 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
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this library; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+* 
+* +*/ + + +#include + +#include "o3000/o3000.h" +#include "o3000_private.h" + + +/** + * The preamble, used to detect the beginning of a new frame + */ +static const uint8_t preamble[] = {0xaa, 0x55, 0xde, 0xad, 0xbe, 0xef, 0x55, 0xaa}; + +/** + * Check whether the argument points to a valid preamble. + * + * @param p Memory pointer + * @return TRUE: points to valid preamble, FALSE: no valid preamble + */ +static int is_preamble(uint8_t *p) { + if( (*p == preamble[7]) && + (*(p+1) == preamble[6]) && + (*(p+2) == preamble[5]) && + (*(p+3) == preamble[4]) && + (*(p+4) == preamble[3]) && + (*(p+5) == preamble[2]) && + (*(p+6) == preamble[1]) && + (*(p+7) == preamble[0])) { + return TRUE; + } + else { + return FALSE; + } +} + + +/** + * Scan for the preamble in the buffer specified. + * + * @param buf Buffer start address + * @param size Buffer size + * @return preamble offset in bytes (w.r.t. to start address) or -1 if not found + */ +static int scan_for_preamble(uint8_t *buf, int size) { + + int i, size_preamble, end; + + size_preamble = sizeof(((struct img_header_t*)0)->preamble); + end = size - size_preamble; + + for(i = 0; i < end; i++) { + if(is_preamble(buf+i) == TRUE) { + return i; // preamble found at offset i + } + } + return -1; // preamble not found +} + +/** + * Video transfer handler + * + * This function recursively scans through a video transfer (video data chunk). + * Incomplete image frames are tracked continuously. Whenever an image frame is completed, the video callback handler is called. + * + * NOTE + * The video-cache consists of severalf memory-adjacent USB transfers plus an adjacent framebuffer. In case of a wrap-around + * the end of the image frame (located at the start of the video-cache) is copied to the framebuffer. So this frame won't be fragmented. + * In case of receiving short USB transfers, two image frames won't be adjacent at the video-cache. Therfore, after handling a image + * the state machine is set to not-synced state. + * + * @param session current session (is never NULL otherwise SEGFAULT) + * @param addr Start address of block to be scanned. + * @param len Lenght of block. + */ +void handle_transfer(struct o3000_session_t *session, uint8_t *addr, int len) { + + int offset; + struct img_header_t *img_header; // points to current image header structure + int wraparound_chunk_size; // chunk size (bytes) at wrap-around to copy to frame buffer + int frame_data_remain; // remaining image frame data to process in bytes + + if(session->frame_state == IMG_FRAME_STATE_NOSYNC) { + offset = scan_for_preamble(addr, len); + if(offset < 0) { + o3000_log(session, O3000_LOG_WARNING, "%s: preamble not found (start address=%p, len=%d)\n", + __func__, addr - session->video_cache, len); + return; + } + + // preamble found, we are synchronized now! + session->frame_state = IMG_FRAME_STATE_SYNC; + session->frame_start = addr + offset; // set start address of image frame + session->frame_rx_cnt = 0; // reset data counter + len -= offset; // skip image data located before preamble + + o3000_log(session, O3000_LOG_DEBUG, "%s: preamble found at address offset %d, remaining data of current image frame %d bytes\n", + __func__, session->frame_start - session->video_cache, len); + + // parse image header + img_header = (struct img_header_t*)(session->frame_start); + session->frame_img_header = img_header; + session->image_start = session->frame_start + IMAGE_HEADER_SIZE + img_header->image_start; + session->frame_size = img_header->payload_size + IMAGE_HEADER_SIZE; + } + + + if(session->frame_state == IMG_FRAME_STATE_SYNC) { + session->frame_rx_cnt += len; + + o3000_log(session, O3000_LOG_DEBUG, "%s: sync: %d bytes of %d bytes (image size) received\n", + __func__, session->frame_rx_cnt, session->frame_size); + + // checking whether whole image frame is received + if(session->frame_rx_cnt >= session->frame_size) { + + o3000_log(session, O3000_LOG_DEBUG, "%s: sync: image frame received\n", __func__); + + if(session->frame_start > addr) { + /* + * We have a wrap-around to resolve. Do copy part of the image frame which resides at the + * start of the video cache to the frame buffer. Note that the frame buffer is memory-adjacent + * to the video cache. + */ + wraparound_chunk_size = session->frame_size - (session->frame_buf - session->frame_start); + o3000_log(session, O3000_LOG_DEBUG, "%s: wrap-around, copy %d bytes to frame buffer\n", __func__, wraparound_chunk_size); + memcpy(session->frame_buf, session->video_cache, wraparound_chunk_size); + } + + // delegate image to overlaying application + session->video_cb(session->id, session->image_start, session->frame_img_header); + + /* + * Image frame is processed. + * The following image may won't be memory-adjacent to this one. Because a snapshot + * is sent with zero packet. The easiest way is to change state to NOT SYNC to trigger + * syncronization part again. + */ + session->frame_state = IMG_FRAME_STATE_NOSYNC; + frame_data_remain = session->frame_rx_cnt - session->frame_size; + o3000_log(session, O3000_LOG_DEBUG, "%s: sync: %d bytes remaining from next image frame\n", __func__, frame_data_remain); + if(frame_data_remain > 0) { + handle_transfer(session, addr+(len-frame_data_remain), frame_data_remain); + } + } + } +} + -- cgit v1.2.1