aboutsummaryrefslogtreecommitdiffstats
path: root/o3000_xfer_handler.c
diff options
context:
space:
mode:
Diffstat (limited to 'o3000_xfer_handler.c')
-rw-r--r--o3000_xfer_handler.c175
1 files changed, 175 insertions, 0 deletions
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
+*
+* <PRE>
+* 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
+* </PRE>
+*
+*/
+
+
+#include <string.h>
+
+#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);
+ }
+ }
+ }
+}
+