David Fletcher / Mbed 2 deprecated cc3100_Test_websock_Camera_CM4F

Dependencies:   mbed

camera_app/camera_app.cpp

Committer:
dflet
Date:
2015-09-15
Revision:
21:38c6b11aa348
Parent:
18:3f1b52616d00
Child:
22:f9b5e0b80bf2

File content as of revision 21:38c6b11aa348:

//*****************************************************************************
// camera_app.c
//
// camera application macro & APIs
//
// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/
//
//
//  Redistribution and use in source and binary forms, with or without
//  modification, are permitted provided that the following conditions
//  are met:
//
//    Redistributions of source code must retain the above copyright
//    notice, this list of conditions and the following disclaimer.
//
//    Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in the
//    documentation and/or other materials provided with the
//    distribution.
//
//    Neither the name of Texas Instruments Incorporated nor the names of
//    its contributors may be used to endorse or promote products derived
//    from this software without specific prior written permission.
//
//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
//  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
//  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
//  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
//  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
//  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
//  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
//  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
//  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
//  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//*****************************************************************************
//*****************************************************************************
//
//! \addtogroup camera_app
//! @{
//
//*****************************************************************************
#include "mbed.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

// SimpleLink include
#include "cc3100_simplelink.h"

#include "oslib/osi.h"
#include "app_config.h"
#include "camera_app.h"
#include "mt9d111.h"
#ifdef OV5642_CAM
#include "ov5642.h"
#endif
#ifdef OV2640_CAM
#include "ov2640.h"
#include "ov5642.h"
#endif
#include "i2cconfig.h"

#include "cli_uart.h"
#include "Led_config.h"
#include "HttpDebug.h"

using namespace mbed_cc3100;



//*****************************************************************************
// Macros
//*****************************************************************************
#define USER_FILE_NAME          "www/images/cc3200_camera_capture.jpg"
#define AP_SSID_LEN_MAX         (33)
#define ROLE_INVALID            (-5)
//*****************************************************************************
//                      GLOBAL VARIABLES
//*****************************************************************************

unsigned int g_frame_size_in_bytes;
extern volatile unsigned char g_CaptureImage;
extern int g_uiIpObtained = 0;
extern int g_uiSimplelinkRole = ROLE_INVALID;
unsigned int g_uiIpAddress = 0;
uint32_t picLoop = 0;
volatile static unsigned char g_frame_end;
volatile static uint16_t g_lines;


DCMI_HandleTypeDef phdcmi;
DMA_HandleTypeDef phdma_dcmi;

#ifdef ENABLE_JPEG
int PIXELS_IN_X_AXIS = 320;
int PIXELS_IN_Y_AXIS = 240;
int FRAME_SIZE_IN_BYTES = (320 * 240 * 2);
#else
int PIXELS_IN_X_AXIS = 176;
int PIXELS_IN_Y_AXIS = 144;
int FRAME_SIZE_IN_BYTES = (176 * 144 * 2);
#endif

struct ImageBuffer {
#ifdef ENABLE_JPEG
    char g_header[SMTP_BUF_LEN] /*= {'\0'}*/;
#endif
    uint32_t g_image_buffer[((IMAGE_BUF_SIZE)/(sizeof(unsigned int)))];//25Kb
    uint8_t sec_image_buffer[26 * 1024];
};

ImageBuffer g_image;

typedef enum pictureRequest {
    NO_PICTURE = 0x00,
    SINGLE_HIGH_RESOLUTION = 0x01,
    STREAM_LOW_RESOLUTION = 0x02

} e_pictureRequest;

typedef enum pictureFormat {
    RAW_10BIT = 0,
    ITU_R_BT601,
    YCbCr_4_2_2,
    YCbCr_4_2_0,
    RGB_565,
    RGB_555,
    RGB_444

} e_pictureFormat;

typedef enum pictureResolution {
    QVGA = 0,
    VGA,
    SVGA,
    XGA,
    uXGA

} e_pictureResolution;


#ifdef ENABLE_JPEG
#define FORMAT_YCBCR422   0
#define FORMAT_YCBCR420   1
#define FORMAT_MONOCHROME 2

unsigned char JPEG_StdQuantTblY[64] = {
    16,  11,  10,  16,  24,  40,  51,  61,
    12,  12,  14,  19,  26,  58,  60,  55,
    14,  13,  16,  24,  40,  57,  69,  56,
    14,  17,  22,  29,  51,  87,  80,  62,
    18,  22,  37,  56,  68,  109, 103, 77,
    24,  35,  55,  64,  81,  104, 113, 92,
    49,  64,  78,  87, 103,  121, 120, 101,
    72,  92,  95,  98, 112,  100, 103,  99
};

unsigned char JPEG_StdQuantTblC[64] = {
    17,  18,  24,  47,  99,  99,  99,  99,
    18,  21,  26,  66,  99,  99,  99,  99,
    24,  26,  56,  99,  99,  99,  99,  99,
    47,  66,  99,  99,  99,  99,  99,  99,
    99,  99,  99,  99,  99,  99,  99,  99,
    99,  99,  99,  99,  99,  99,  99,  99,
    99,  99,  99,  99,  99,  99,  99,  99,
    99,  99,  99,  99,  99,  99,  99,  99
};
//
// This table is used for regular-position to zigzagged-position lookup
//  This is Figure A.6 from the ISO/IEC 10918-1 1993 specification
//
static unsigned char zigzag[64] = {
    0, 1, 5, 6,14,15,27,28,
    2, 4, 7,13,16,26,29,42,
    3, 8,12,17,25,30,41,43,
    9,11,18,24,31,40,44,53,
    10,19,23,32,39,45,52,54,
    20,22,33,38,46,51,55,60,
    21,34,37,47,50,56,59,61,
    35,36,48,49,57,58,62,63
};

unsigned int JPEG_StdHuffmanTbl[384] = {
    0x100, 0x101, 0x204, 0x30b, 0x41a, 0x678, 0x7f8, 0x9f6,
    0xf82, 0xf83, 0x30c, 0x41b, 0x679, 0x8f6, 0xaf6, 0xf84,
    0xf85, 0xf86, 0xf87, 0xf88, 0x41c, 0x7f9, 0x9f7, 0xbf4,
    0xf89, 0xf8a, 0xf8b, 0xf8c, 0xf8d, 0xf8e, 0x53a, 0x8f7,
    0xbf5, 0xf8f, 0xf90, 0xf91, 0xf92, 0xf93, 0xf94, 0xf95,
    0x53b, 0x9f8, 0xf96, 0xf97, 0xf98, 0xf99, 0xf9a, 0xf9b,
    0xf9c, 0xf9d, 0x67a, 0xaf7, 0xf9e, 0xf9f, 0xfa0, 0xfa1,
    0xfa2, 0xfa3, 0xfa4, 0xfa5, 0x67b, 0xbf6, 0xfa6, 0xfa7,
    0xfa8, 0xfa9, 0xfaa, 0xfab, 0xfac, 0xfad, 0x7fa, 0xbf7,
    0xfae, 0xfaf, 0xfb0, 0xfb1, 0xfb2, 0xfb3, 0xfb4, 0xfb5,
    0x8f8, 0xec0, 0xfb6, 0xfb7, 0xfb8, 0xfb9, 0xfba, 0xfbb,
    0xfbc, 0xfbd, 0x8f9, 0xfbe, 0xfbf, 0xfc0, 0xfc1, 0xfc2,
    0xfc3, 0xfc4, 0xfc5, 0xfc6, 0x8fa, 0xfc7, 0xfc8, 0xfc9,
    0xfca, 0xfcb, 0xfcc, 0xfcd, 0xfce, 0xfcf, 0x9f9, 0xfd0,
    0xfd1, 0xfd2, 0xfd3, 0xfd4, 0xfd5, 0xfd6, 0xfd7, 0xfd8,
    0x9fa, 0xfd9, 0xfda, 0xfdb, 0xfdc, 0xfdd, 0xfde, 0xfdf,
    0xfe0, 0xfe1, 0xaf8, 0xfe2, 0xfe3, 0xfe4, 0xfe5, 0xfe6,
    0xfe7, 0xfe8, 0xfe9, 0xfea, 0xfeb, 0xfec, 0xfed, 0xfee,
    0xfef, 0xff0, 0xff1, 0xff2, 0xff3, 0xff4, 0xff5, 0xff6,
    0xff7, 0xff8, 0xff9, 0xffa, 0xffb, 0xffc, 0xffd, 0xffe,
    0x30a, 0xaf9, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
    0xfd0, 0xfd1, 0xfd2, 0xfd3, 0xfd4, 0xfd5, 0xfd6, 0xfd7,
    0x101, 0x204, 0x30a, 0x418, 0x419, 0x538, 0x678, 0x8f4,
    0x9f6, 0xbf4, 0x30b, 0x539, 0x7f6, 0x8f5, 0xaf6, 0xbf5,
    0xf88, 0xf89, 0xf8a, 0xf8b, 0x41a, 0x7f7, 0x9f7, 0xbf6,
    0xec2, 0xf8c, 0xf8d, 0xf8e, 0xf8f, 0xf90, 0x41b, 0x7f8,
    0x9f8, 0xbf7, 0xf91, 0xf92, 0xf93, 0xf94, 0xf95, 0xf96,
    0x53a, 0x8f6, 0xf97, 0xf98, 0xf99, 0xf9a, 0xf9b, 0xf9c,
    0xf9d, 0xf9e, 0x53b, 0x9f9, 0xf9f, 0xfa0, 0xfa1, 0xfa2,
    0xfa3, 0xfa4, 0xfa5, 0xfa6, 0x679, 0xaf7, 0xfa7, 0xfa8,
    0xfa9, 0xfaa, 0xfab, 0xfac, 0xfad, 0xfae, 0x67a, 0xaf8,
    0xfaf, 0xfb0, 0xfb1, 0xfb2, 0xfb3, 0xfb4, 0xfb5, 0xfb6,
    0x7f9, 0xfb7, 0xfb8, 0xfb9, 0xfba, 0xfbb, 0xfbc, 0xfbd,
    0xfbe, 0xfbf, 0x8f7, 0xfc0, 0xfc1, 0xfc2, 0xfc3, 0xfc4,
    0xfc5, 0xfc6, 0xfc7, 0xfc8, 0x8f8, 0xfc9, 0xfca, 0xfcb,
    0xfcc, 0xfcd, 0xfce, 0xfcf, 0xfd0, 0xfd1, 0x8f9, 0xfd2,
    0xfd3, 0xfd4, 0xfd5, 0xfd6, 0xfd7, 0xfd8, 0xfd9, 0xfda,
    0x8fa, 0xfdb, 0xfdc, 0xfdd, 0xfde, 0xfdf, 0xfe0, 0xfe1,
    0xfe2, 0xfe3, 0xaf9, 0xfe4, 0xfe5, 0xfe6, 0xfe7, 0xfe8,
    0xfe9, 0xfea, 0xfeb, 0xfec, 0xde0, 0xfed, 0xfee, 0xfef,
    0xff0, 0xff1, 0xff2, 0xff3, 0xff4, 0xff5, 0xec3, 0xff6,
    0xff7, 0xff8, 0xff9, 0xffa, 0xffb, 0xffc, 0xffd, 0xffe,
    0x100, 0x9fa, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
    0xfd0, 0xfd1, 0xfd2, 0xfd3, 0xfd4, 0xfd5, 0xfd6, 0xfd7,
    0x100, 0x202, 0x203, 0x204, 0x205, 0x206, 0x30e, 0x41e,
    0x53e, 0x67e, 0x7fe, 0x8fe, 0xfff, 0xfff, 0xfff, 0xfff,
    0x100, 0x101, 0x102, 0x206, 0x30e, 0x41e, 0x53e, 0x67e,
    0x7fe, 0x8fe, 0x9fe, 0xafe, 0xfff, 0xfff, 0xfff, 0xfff
};
#endif

//*****************************************************************************
//
//!     Start Camera
//!     1. Establishes connection w/ AP//
//!     2. Initializes the camera sub-components//! GPIO Enable & Configuration
//!     3. Listens and processes the image capture requests from user-applications
//!
//!	\param[out]                      WriteBuffer - Pointer to the Frame Buffer
//!     \return                     None
//
//*****************************************************************************

uint32_t StartCamera(char **WriteBuffer)
{
    uint32_t Writelength;
    //
    // Waits in the below loop till Capture button is pressed
    //
    Writelength = CaptureImage(WriteBuffer);

    return(Writelength);

}
//*****************************************************************************
//
//!     InitCameraComponents
//!     PinMux, Camera Initialization and Configuration
//!
//!	\param[in] width - X-Axis
//!	\param[in] width - Y-Axis
//! \return  None
//
//*****************************************************************************

void InitCameraComponents(int width, int height)
{
    Uart_Write((uint8_t*)"InitCameraComponents \n\r");
    //
    // Initialize I2C Interface
    //
    I2CInit();
#ifdef MT9D111_CAM
    cam_power_on();    
    getCamId();
    
    //
    // Initialize camera sensor
    //
    CameraSensorInit();
#ifdef ENABLE_JPEG
    //
    // Configure Sensor in Capture Mode
    //
    PIXELS_IN_X_AXIS = width;
    PIXELS_IN_Y_AXIS = height;
    FRAME_SIZE_IN_BYTES = PIXELS_IN_X_AXIS * PIXELS_IN_Y_AXIS * BYTES_PER_PIXEL;

    StartSensorInJpegMode(width, height);

#endif//ENABLE_JPEG
#endif//MT9D111_CAM    
    
#ifdef OV5642_CAM
    check_camId();
    init_cam();    
#endif//OV5642_CAM

#ifdef OV2640_CAM
    camId();
    initCam();    
#endif//OV2640_CAM

    
    
}

//*****************************************************************************
//
//!     Set resolution of camera
//!
//!	\param[in] width - X Axis
//!	\param[in] height - Y Axis
//! \return  0 on success else -ve
//
//*****************************************************************************

int SetCameraResolution(int width, int height)
{
    Uart_Write((uint8_t*)"SetCameraResolution \n\r");
    int lRetVal = 0;

    PIXELS_IN_X_AXIS = width;
    PIXELS_IN_Y_AXIS = height;
    FRAME_SIZE_IN_BYTES = PIXELS_IN_X_AXIS * PIXELS_IN_Y_AXIS * BYTES_PER_PIXEL;
    lRetVal = CameraSensorResolution(width, height);
    return lRetVal;
}

//*****************************************************************************
//
//!     CaptureImage
//!     Configures DMA and starts the Capture. Post Capture writes to SFLASH
//!
//!	\param                      None
//!     \return                     None
//!
//
//*****************************************************************************
uint32_t CaptureImage(char** WriteBuffer)
{

    uint32_t g_header_length = 0;
    uint32_t image_size = 0;
    uint32_t *pbuffer = &(g_image.g_image_buffer[0]);
    uint8_t *sec_pbuffer = &(g_image.sec_image_buffer[0]);
//    int32_t lRetVal= -1;
    int32_t err = 0;
#ifdef MT9D111_CAM     
    uint8_t jpeg_end[] = {0xFF, 0xD9};
#endif
    picLoop++;    
    DMAConfig();
    
//    wait(1);
#ifdef MT9D111_CAM    
    /* Send cam capture request, value in frames */
    Start_still_capture(1);// Switch to context b
    wait(1);
#endif
    //
    // DCMI Perform Image Capture
    //
#ifdef ENABLE_JPEG
    HAL_DCMI_Start_DMA(&phdcmi, DCMI_MODE_SNAPSHOT, (uint32_t)pbuffer, NUM_OF_4B_CHUNKS);
#else
    HAL_DCMI_Start_DMA(&phdcmi, DCMI_MODE_CONTINUOUS, (uint32_t)pbuffer, NUM_OF_4B_CHUNKS);
#endif

    while(g_frame_end == 0);//Set in the Frame complete callback function 

#ifdef MT9D111_CAM    
    Stop_still_capture();// Switch to context a
#endif    
    /* Read the number of data items transferred in bytes ((4x) uint = bytes) */
    g_frame_size_in_bytes = 4*(NUM_OF_4B_CHUNKS - phdma_dcmi.Instance->NDTR);//NDTR counts down!
    if(g_frame_size_in_bytes <= 0 || g_frame_size_in_bytes > (NUM_OF_4B_CHUNKS *4)) {
        err = HAL_DMA_GetState(&phdma_dcmi);
        HttpDebug("\r\nDMA error! 0x%x\r\n",err);
        HttpDebug("\r\nDMA error! 0x%x\r\n",phdma_dcmi.ErrorCode);
        HttpDebug("g_frame_size_in_bytes = 0x%x\r\n",g_frame_size_in_bytes);
        HttpDebug("\r\nFailed to capture data, check camera connections!\r\n");
        HAL_DMA_Abort(&phdma_dcmi);
#ifdef MT9D111_CAM        
        cam_power_off();
#endif        
      	HAL_DCMI_MspDeInit(&phdcmi);
        HttpDebug("Image Capture failed\n\r");
        while(1) {
            wait(0.5);
        }
    } 
    
    uint8_t* Image = reinterpret_cast<uint8_t*>(pbuffer);
    
#ifdef MT9D111_CAM
    memcpy(Image + g_frame_size_in_bytes, jpeg_end, 2);
    g_frame_size_in_bytes += 2;
#endif
        
    //
    // Create JPEG Header
    //
#ifdef MT9D111_CAM    
#ifdef ENABLE_JPEG
    memset(g_image.g_header, '\0', sizeof(g_image.g_header));
    g_header_length = CreateJpegHeader((char *)&(g_image.g_header[0]), PIXELS_IN_X_AXIS, PIXELS_IN_Y_AXIS, 0, 0x0020, 8);

    // This pushes the header to the start of the array so that the entire picture can be contiguous in memory    
    memcpy(sec_pbuffer + g_header_length, Image, g_frame_size_in_bytes);
    memcpy(sec_pbuffer, g_image.g_header, g_header_length);

    image_size = g_header_length + g_frame_size_in_bytes;  
    HttpDebug("\r\nCapture Image %d size 0x%x\r\n",picLoop, image_size); 
#endif//ENABLE_JPEG
    *WriteBuffer = (char*)g_image.sec_image_buffer;
    return(g_header_length += g_frame_size_in_bytes);
#endif//MT9D111_CAM
    HttpDebug("\r\nCapture Image %d size 0x%x\r\n",picLoop, image_size);    
    *WriteBuffer = (char*)g_image.sec_image_buffer;

    return(g_frame_size_in_bytes);
}
//*****************************************************************************
//
//!     DMA Config
//!     Initialize the DMA\DCMI and Setup the DMA transfer
//!
//!	\param                      None
//!     \return                     None
//
//*****************************************************************************
void DMAConfig()
{

    phdcmi.Init.SynchroMode      = DCMI_SYNCHRO_HARDWARE;
#ifdef OV5642_CAM       
    phdcmi.Init.PCKPolarity      = DCMI_PCKPOLARITY_RISING;//Data clocked out on rising edge
    phdcmi.Init.VSPolarity       = DCMI_VSPOLARITY_HIGH;//Active high
    phdcmi.Init.HSPolarity       = DCMI_HSPOLARITY_LOW;//Active low
#endif    
#ifdef OV2640_CAM    
    phdcmi.Init.PCKPolarity      = DCMI_PCKPOLARITY_RISING;//Data clocked out on rising edge
    phdcmi.Init.VSPolarity       = DCMI_VSPOLARITY_LOW;//Active low
    phdcmi.Init.HSPolarity       = DCMI_HSPOLARITY_LOW;//Active low
#endif    
#ifdef MT9D111_CAM
    phdcmi.Init.PCKPolarity      = DCMI_PCKPOLARITY_RISING;//Data clocked out on rising edge 
//    phdcmi.Init.PCKPolarity      = DCMI_PCKPOLARITY_FALLING;//Data clocked out on falling edge       
    phdcmi.Init.VSPolarity       = DCMI_VSPOLARITY_LOW;//Active high
    phdcmi.Init.HSPolarity       = DCMI_HSPOLARITY_LOW;//Active high    
#endif        
    phdcmi.Init.CaptureRate      = DCMI_CR_ALL_FRAME;
    phdcmi.Init.ExtendedDataMode = DCMI_EXTEND_DATA_8B;//8 bit data
#ifdef ENABLE_JPEG
    phdcmi.Init.JPEGMode         = DCMI_JPEG_ENABLE;
#else
    phdcmi.Init.JPEGMode         = DCMI_JPEG_DISABLE;
#endif
    phdcmi.Instance              = DCMI;

    DCMI_MspInit(&phdcmi);
    HAL_DCMI_Init(&phdcmi);
     
}

void DCMI_MspInit(DCMI_HandleTypeDef* hdcmi)
{

    /* Peripheral DCMI init*/

    GPIO_InitTypeDef GPIO_InitStruct;
    if(hdcmi->Instance==DCMI) {
        __GPIOA_CLK_ENABLE();
        __GPIOB_CLK_ENABLE();
        __GPIOC_CLK_ENABLE();
        __GPIOE_CLK_ENABLE();

        /* Peripheral clock enable */
        __DCMI_CLK_ENABLE();
        /* DMA controller clock enable */
        __DMA2_CLK_ENABLE();

        /**MCO1 GPIO Configuration
        PA8     ------> RCC_MCO_1
        */

        /**DCMI GPIO Configuration
        PA9     ------> DCMI_D0
        PA10    ------> DCMI_D1
        PC8     ------> DCMI_D2
        PC9     ------> DCMI_D3
        PE4     ------> DCMI_D4
        PB6     ------> DCMI_D5
        PE5     ------> DCMI_D6
        PE6     ------> DCMI_D7
        PA6     ------> DCMI_PIXCK
        PA4     ------> DCMI_HSYNC
        PB7     ------> DCMI_VSYNC

        */
        /* D4 D6 D7 */
        GPIO_InitStruct.Pin = GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6;
        GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
        GPIO_InitStruct.Pull = GPIO_PULLUP;
        GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
        GPIO_InitStruct.Alternate = GPIO_AF13_DCMI;
        HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);

        /* HSYNC PIXCLK D0 D1 */
        GPIO_InitStruct.Pin = GPIO_PIN_4|GPIO_PIN_6|GPIO_PIN_9|GPIO_PIN_10;
        GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
        GPIO_InitStruct.Pull = GPIO_PULLUP;
        GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
        GPIO_InitStruct.Alternate = GPIO_AF13_DCMI;
        HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

        /* D2 D3 */
        GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9;
        GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
        GPIO_InitStruct.Pull = GPIO_PULLUP;
        GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
        GPIO_InitStruct.Alternate = GPIO_AF13_DCMI;
        HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

        /* D5 VSYNC */
        GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7;
        GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
        GPIO_InitStruct.Pull = GPIO_PULLUP;
        GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
        GPIO_InitStruct.Alternate = GPIO_AF13_DCMI;
        HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

        phdma_dcmi.Instance                 = DMA2_Stream1;
        phdma_dcmi.Init.Channel             = DMA_CHANNEL_1;
        phdma_dcmi.Init.Direction           = DMA_PERIPH_TO_MEMORY;
        phdma_dcmi.Init.PeriphInc           = DMA_PINC_DISABLE;
        phdma_dcmi.Init.MemInc              = DMA_MINC_ENABLE;
        phdma_dcmi.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;//Cam is 1 byte wide data (8 bits) should this be word?????
        phdma_dcmi.Init.MemDataAlignment    = DMA_PDATAALIGN_WORD;//Memory has been defined as uint (1 word)
        phdma_dcmi.Init.Mode                = DMA_NORMAL;
        phdma_dcmi.Init.Priority            = DMA_PRIORITY_HIGH;
        phdma_dcmi.Init.FIFOMode            = DMA_FIFOMODE_DISABLE;
        phdma_dcmi.Init.FIFOThreshold       = DMA_FIFO_THRESHOLD_FULL;
        phdma_dcmi.Init.MemBurst            = DMA_MBURST_SINGLE;
        phdma_dcmi.Init.PeriphBurst         = DMA_PBURST_SINGLE;

        __HAL_LINKDMA(hdcmi, DMA_Handle, phdma_dcmi);

        /*** Configure the NVIC for DCMI and DMA ***/
        /* NVIC configuration for DCMI transfer complete interrupt */
        HAL_NVIC_SetPriority(DCMI_IRQn, 3, 0);
        HAL_NVIC_EnableIRQ(DCMI_IRQn);

        /* NVIC configuration for DMA2 transfer complete interrupt */
        HAL_NVIC_SetPriority(DMA2_Stream1_IRQn, 3, 0);
        HAL_NVIC_EnableIRQ(DMA2_Stream1_IRQn);

        HAL_DMA_Init(&phdma_dcmi);
    }

    g_frame_size_in_bytes = 0;
    g_frame_end = 0;
}

/******************************************************************************/
/* STM32F4xx Peripheral Interrupt Handlers                                    */
/* Add here the Interrupt Handlers for the used peripherals.                  */
/* For the available peripheral interrupt handler names,                      */
/* please refer to the startup file (startup_stm32f4xx.s).                    */
/******************************************************************************/

void HAL_DCMI_ErrorCallback(DCMI_HandleTypeDef *hdcmi)
{
    int32_t dcmi_state;
    int32_t dcmi_error;
    
    HAL_DMA_Abort(&phdma_dcmi);
    
    HttpDebug("\r\nDCMI_ErrorCallback!\r\n");
    
    dcmi_state = HAL_DCMI_GetState(&phdcmi);
    if(0 == dcmi_state){
    	HttpDebug("\r\nDCMI not yet initialized or disabled\r\n");
    }else if(1 == dcmi_state){
    	HttpDebug("\r\nDCMI initialized and ready for use\r\n");
    }else if(2 == dcmi_state){
    	HttpDebug("\r\nDCMI internal processing is ongoing\r\n");
    }else if(3 == dcmi_state){
    	HttpDebug("\r\nDCMI timeout state\r\n");
    }else if(4 == dcmi_state){	
    	HttpDebug("\r\nDCMI error state\r\n");
    	dcmi_error = HAL_DCMI_GetError(&phdcmi);
    	if(1 == dcmi_error){
    		HttpDebug("\r\nDCMI Synchronisation error\r\n");
    	}else if(2 == dcmi_error){
    		HttpDebug("\r\nDCMI Overrun\r\n");
    	}		
    }				
    HttpDebug("\r\nExtra info! \r\n");
    g_frame_size_in_bytes = 4*(NUM_OF_4B_CHUNKS - phdma_dcmi.Instance->NDTR);//NDTR counts down!
    if(g_frame_size_in_bytes >= 0xC800){
    	HttpDebug("Bytes captured equals or exceeds buffer size! \r\n");
    	HttpDebug("Bytes captured 0x%x\r\n",g_frame_size_in_bytes);
    }else{	
        HttpDebug("Bytes captured 0x%x\r\n",g_frame_size_in_bytes);
    }
    
    HAL_DMA_Abort(&phdma_dcmi);
#ifdef MT9D111_CAM    
    cam_power_off();
#endif    
    HAL_DCMI_MspDeInit(&phdcmi);    
}

void HAL_DCMI_LineEventCallback(DCMI_HandleTypeDef *hdcmi)
{
    //g_lines++;
    //HttpDebug("\r\nDCMI_LineEventCallback! 0x%x\r\n",hdcmi->ErrorCode);

}

void HAL_DCMI_VsyncEventCallback(DCMI_HandleTypeDef *hdcmi)
{
    //g_lines = 0;
//    printf("\r\nVsyncEventCallback\r\n");

}

void HAL_DCMI_FrameEventCallback(DCMI_HandleTypeDef *hdcmi)
{
    HAL_DMA_Abort(&phdma_dcmi);
    g_frame_end = 1;
    
    //HttpDebug("\r\nDCMI Frame Capture complete! \r\n");

}

void HAL_DCMI_MspDeInit(DCMI_HandleTypeDef* hdcmi)
{
    if(hdcmi->Instance==DCMI) {

        /* Peripheral clock disable */
        __DCMI_CLK_DISABLE();

        /**DCMI GPIO Configuration
        PE4     ------> DCMI_D4
        PE5     ------> DCMI_D6
        PE6     ------> DCMI_D7
        PA4     ------> DCMI_HSYNC
        PA6     ------> DCMI_PIXCK
        PC8     ------> DCMI_D2
        PC9     ------> DCMI_D3
        PA9     ------> DCMI_D0
        PA10    ------> DCMI_D1
        PB6     ------> DCMI_D5
        PB7     ------> DCMI_VSYNC

        PA8     ------> MCO1
        */

        HAL_GPIO_DeInit(GPIOE, GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6);

        HAL_GPIO_DeInit(GPIOA, GPIO_PIN_4|GPIO_PIN_6|GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10);

        HAL_GPIO_DeInit(GPIOC, GPIO_PIN_9|GPIO_PIN_8);

        HAL_GPIO_DeInit(GPIOB, GPIO_PIN_6|GPIO_PIN_7);

        /* Peripheral DMA DeInit*/
        HAL_DMA_DeInit(hdcmi->DMA_Handle);

        /* Peripheral interrupt DeInit*/
        HAL_NVIC_DisableIRQ(DCMI_IRQn);

        HAL_GPIO_DeInit(GPIOA, GPIO_PIN_8);
        HAL_GPIO_DeInit(GPIOB, GPIO_PIN_8 | GPIO_PIN_9);
    }


}

//*****************************************************************************
//
//!     JfifApp0Marker
//!
//!	\param                      Pointer to the output buffer
//!     \return                     Length of the Marker
//
//*****************************************************************************

#ifdef ENABLE_JPEG
static int JfifApp0Marker(char *pbuf)
{
//    Uart_Write((uint8_t*)"JfifApp0Marker \n\r");
    *pbuf++= 0xFF;                  // APP0 marker
    *pbuf++= 0xE0;
    *pbuf++= 0x00;                  // length
    *pbuf++= 0x10;
    *pbuf++= 0x4A;                  // JFIF identifier
    *pbuf++= 0x46;
    *pbuf++= 0x49;
    *pbuf++= 0x46;
    *pbuf++= 0x00;
    *pbuf++= 0x01;                  // version
    *pbuf++= 0x02;
    *pbuf++= 0x00;                  // units
    *pbuf++= 0x00;                  // X density
    *pbuf++= 0x01;
    *pbuf++= 0x00;                  // Y density
    *pbuf++= 0x01;
    *pbuf++= 0x00;                  // X thumbnail
    *pbuf++= 0x00;                  // Y thumbnail
    return 18;
}


//*****************************************************************************
//
//!    FrameHeaderMarker
//!
//!	\param1                      pointer to the output buffer
//!	\param2                      width
//!	\param3                      height
//!	\param4                      format
//!
//!     \return                       Length of the header marker
//
//*****************************************************************************
static int FrameHeaderMarker(char *pbuf, int width, int height, int format)
{
//    Uart_Write((uint8_t*)"FrameHeaderMarker \n\r");
    int length;
    if (format == FORMAT_MONOCHROME)
        length = 11;
    else
        length = 17;

    *pbuf++= 0xFF;                      // start of frame: baseline DCT
    *pbuf++= 0xC0;
    *pbuf++= length>>8;                 // length field
    *pbuf++= length&0xFF;
    *pbuf++= 0x08;                      // sample precision
    *pbuf++= height>>8;                 // number of lines
    *pbuf++= height&0xFF;
    *pbuf++= width>>8;                  // number of samples per line
    *pbuf++= width&0xFF;

    if (format == FORMAT_MONOCHROME) {  // monochrome
        *pbuf++= 0x01;                  // number of image components in frame
        *pbuf++= 0x00;                  // component identifier: Y
        *pbuf++= 0x11;                  // horizontal | vertical sampling factor: Y
        *pbuf++= 0x00;                  // quantization table selector: Y
    } else if (format == FORMAT_YCBCR422) { // YCbCr422
        *pbuf++= 0x03;                  // number of image components in frame
        *pbuf++= 0x00;                  // component identifier: Y
        *pbuf++= 0x21;                  // horizontal | vertical sampling factor: Y
        *pbuf++= 0x00;                  // quantization table selector: Y
        *pbuf++= 0x01;                  // component identifier: Cb
        *pbuf++= 0x11;                  // horizontal | vertical sampling factor: Cb
        *pbuf++= 0x01;                  // quantization table selector: Cb
        *pbuf++= 0x02;                  // component identifier: Cr
        *pbuf++= 0x11;                  // horizontal | vertical sampling factor: Cr
        *pbuf++= 0x01;                  // quantization table selector: Cr
    } else {                            // YCbCr420
        *pbuf++= 0x03;                  // number of image components in frame
        *pbuf++= 0x00;                  // component identifier: Y
        *pbuf++= 0x22;                  // horizontal | vertical sampling factor: Y
        *pbuf++= 0x00;                  // quantization table selector: Y
        *pbuf++= 0x01;                  // component identifier: Cb
        *pbuf++= 0x11;                  // horizontal | vertical sampling factor: Cb
        *pbuf++= 0x01;                  // quantization table selector: Cb
        *pbuf++= 0x02;                  // component identifier: Cr
        *pbuf++= 0x11;                  // horizontal | vertical sampling factor: Cr
        *pbuf++= 0x01;                  // quantization table selector: Cr
    }

    return (length+2);
}


//*****************************************************************************
//
//!     ScanHeaderMarker
//!
//!	\param1                     pointer to output buffer
//!	\param2                     Format
//!
//!     \return                     Length
//
//*****************************************************************************
static int ScanHeaderMarker(char *pbuf, int format)
{
    int length;
    if (format == FORMAT_MONOCHROME)
        length = 8;
    else
        length = 12;

    *pbuf++= 0xFF;                  // start of scan
    *pbuf++= 0xDA;
    *pbuf++= length>>8;             // length field
    *pbuf++= length&0xFF;
    if (format == FORMAT_MONOCHROME) { // monochrome
        *pbuf++= 0x01;              // number of image components in scan
        *pbuf++= 0x00;              // scan component selector: Y
        *pbuf++= 0x00;              // DC | AC huffman table selector: Y
    } else {                        // YCbCr
        *pbuf++= 0x03;              // number of image components in scan
        *pbuf++= 0x00;              // scan component selector: Y
        *pbuf++= 0x00;              // DC | AC huffman table selector: Y
        *pbuf++= 0x01;              // scan component selector: Cb
        *pbuf++= 0x11;              // DC | AC huffman table selector: Cb
        *pbuf++= 0x02;              // scan component selector: Cr
        *pbuf++= 0x11;              // DC | AC huffman table selector: Cr
    }

    *pbuf++= 0x00;                  // Ss: start of predictor selector
    *pbuf++= 0x3F;                  // Se: end of spectral selector
    *pbuf++= 0x00;                  // Ah | Al: successive approximation bit position

    return (length+2);
}


//*****************************************************************************
//
//!     DefineQuantizationTableMarker
//!      Calculate and write the quantisation tables
//!      qscale is the customised scaling factor - see MT9D131 developer guide page 78
//!
//!	\param1                      pointer to the output buffer
//!	\param2                      Quantization Scale
//!	\param3                      Format
//!
//!     \return                      Length of the Marker
//
//*****************************************************************************
static int DefineQuantizationTableMarker (unsigned char *pbuf, int qscale, int format)
{
//    Uart_Write((uint8_t*)"DefineQuantizationTableMarker \n\r");
    int i, length, temp;
    unsigned char newtbl[64];           // temporary array to store scaled zigzagged quant entries

    if (format == FORMAT_MONOCHROME)    // monochrome
        length  =  67;
    else
        length  =  132;

    *pbuf++  =  0xFF;                   // define quantization table marker
    *pbuf++  =  0xDB;
    *pbuf++  =  length>>8;              // length field
    *pbuf++  =  length&0xFF;
    *pbuf++  =  0;                      // quantization table precision | identifier for luminance

    // calculate scaled zigzagged luminance quantisation table entries
    for (i=0; i<64; i++) {
        temp = (JPEG_StdQuantTblY[i] * qscale + 16) / 32;
        // limit the values to the valid range
        if (temp <= 0)
            temp = 1;
        if (temp > 255)
            temp = 255;
        newtbl[zigzag[i]] = (unsigned char) temp;
    }

    // write the resulting luminance quant table to the output buffer
    for (i=0; i<64; i++)
        *pbuf++ = newtbl[i];

    // if format is monochrome we're finished, otherwise continue on, to do chrominance quant table
    if (format == FORMAT_MONOCHROME)
        return (length+2);

    *pbuf++ = 1;                        // quantization table precision | identifier for chrominance

    // calculate scaled zigzagged chrominance quantisation table entries
    for (i=0; i<64; i++) {
        temp = (JPEG_StdQuantTblC[i] * qscale + 16) / 32;
        // limit the values to the valid range
        if (temp <= 0)
            temp = 1;
        if (temp > 255)
            temp = 255;
        newtbl[zigzag[i]] = (unsigned char) temp;
    }

    // write the resulting chrominance quant table to the output buffer
    for (i=0; i<64; i++)
        *pbuf++ = newtbl[i];

    return (length+2);
}


//*****************************************************************************
//
//!     DefineHuffmanTableMarkerDC
//!
//!	\param1                      pointer to Marker buffer
//!	\param2                      Huffman table
//!	\param3                      Class Identifier
//!
//!     \return                      Length of the marker
//
//*****************************************************************************
static int DefineHuffmanTableMarkerDC(char *pbuf, unsigned int *htable, int class_id)
{
//    Uart_Write((uint8_t*)"DefineHuffmanTableMarkerDC \n\r");
    int i, l, count;
    int length;
    char *plength;

    *pbuf++= 0xFF;                  // define huffman table marker
    *pbuf++= 0xC4;
    plength = pbuf;                 // place holder for length field
    *pbuf++;
    *pbuf++;
    *pbuf++= class_id;              // huffman table class | identifier

    for (l = 0; l < 16; l++) {
        count = 0;
        for (i = 0; i < 12; i++) {
            if ((htable[i] >> 8) == l)
                count++;
        }
        *pbuf++= count;             // number of huffman codes of length l+1
    }

    length = 19;
    for (l = 0; l < 16; l++) {
        for (i = 0; i < 12; i++) {
            if ((htable[i] >> 8) == l) {
                *pbuf++= i;         // HUFFVAL with huffman codes of length l+1
                length++;
            }
        }
    }

    *plength++= length>>8;          // length field
    *plength = length&0xFF;

    return (length + 2);
}


//*****************************************************************************
//
//!     DefineHuffmanTableMarkerAC
//!     1. Establishes connection w/ AP//
//!     2. Initializes the camera sub-components//! GPIO Enable & Configuration
//!     3. Listens and processes the image capture requests from user-applications
//!
//!	\param1                      pointer to Marker buffer
//!	\param2                      Huffman table
//!	\param3                      Class Identifier
//!
//!     \return                      Length of the Marker
//!
//
//*****************************************************************************
static int DefineHuffmanTableMarkerAC(char *pbuf, unsigned int *htable, int class_id)
{
//    Uart_Write((uint8_t*)"DefineHuffmanTableMarkerAC \n\r");
    int i, l, a, b, count;
    char *plength;
    int length;

    *pbuf++= 0xFF;                      // define huffman table marker
    *pbuf++= 0xC4;
    plength = pbuf;                     // place holder for length field
    *pbuf++;
    *pbuf++;
    *pbuf++= class_id;                  // huffman table class | identifier

    for (l = 0; l < 16; l++) {
        count = 0;
        for (i = 0; i < 162; i++) {
            if ((htable[i] >> 8) == l)
                count++;
        }

        *pbuf++= count;                 // number of huffman codes of length l+1
    }

    length = 19;
    for (l = 0; l < 16; l++) {
        // check EOB: 0|0
        if ((htable[160] >> 8) == l) {
            *pbuf++= 0;                 // HUFFVAL with huffman codes of length l+1
            length++;
        }

        // check HUFFVAL: 0|1 to E|A
        for (i = 0; i < 150; i++) {
            if ((htable[i] >> 8) == l) {
                a = i/10;
                b = i%10;
                *pbuf++= (a<<4)|(b+1);  // HUFFVAL with huffman codes of length l+1
                length++;
            }
        }

        // check ZRL: F|0
        if ((htable[161] >> 8) == l) {
            *pbuf++= 0xF0;              // HUFFVAL with huffman codes of length l+1
            length++;
        }

        // check HUFFVAL: F|1 to F|A
        for (i = 150; i < 160; i++) {
            if ((htable[i] >> 8) == l) {
                a = i/10;
                b = i%10;
                *pbuf++= (a<<4)|(b+1);  // HUFFVAL with huffman codes of length l+1
                length++;
            }
        }
    }

    *plength++= length>>8;              // length field
    *plength = length&0xFF;
    return (length + 2);
}


//*****************************************************************************
//
//!     DefineRestartIntervalMarker
//!
//!	\param1                      pointer to Marker buffer
//!	\param2                      return interval
//!
//!     \return                      Length
//
//*****************************************************************************
static int DefineRestartIntervalMarker(char *pbuf, int ri)
{
//    Uart_Write((uint8_t*)"DefineRestartIntervalMarker \n\r");
    *pbuf++= 0xFF;                  // define restart interval marker
    *pbuf++= 0xDD;
    *pbuf++= 0x00;                  // length
    *pbuf++= 0x04;
    *pbuf++= ri >> 8;               // restart interval
    *pbuf++= ri & 0xFF;
    return 6;
}
//*****************************************************************************
//
//!     CreateJpegHeader
//!     Create JPEG Header in JFIF format
//!
//!	\param1                     header - pointer to JPEG header buffer
//!	\param2                     width - image width
//!	\param3                     height - image height
//!	\param4                     format - color format (0 = YCbCr422, 1 = YCbCr420, 2 = monochrome)
//!	\param5                     restart_int - restart marker interval
//!	\param6                     qscale - quantization table scaling factor
//!
//!     \return                     length of JPEG header (bytes)
//
//*****************************************************************************

static int CreateJpegHeader(char *header, int width, int height,
                            int format, int restart_int, int qscale)
{
//    Uart_Write((uint8_t*)"CreateJpegHeader \n\r");
    char *pbuf = header;
    int length;

    // SOI
    *pbuf++= 0xFF;
    *pbuf++= 0xD8;
    length = 2;

    // JFIF APP0
    length += JfifApp0Marker(pbuf);

    // Quantization Tables
    pbuf = header + length;
    length += DefineQuantizationTableMarker((unsigned char *)pbuf, qscale, format);

    // Frame Header
    pbuf = header + length;
    length += FrameHeaderMarker(pbuf, width, height, format);

    // Huffman Table DC 0 for Luma
    pbuf = header + length;
    length += DefineHuffmanTableMarkerDC(pbuf, &JPEG_StdHuffmanTbl[352], 0x00);

    // Huffman Table AC 0 for Luma
    pbuf = header + length;
    length += DefineHuffmanTableMarkerAC(pbuf, &JPEG_StdHuffmanTbl[0], 0x10);

    if (format != FORMAT_MONOCHROME) { // YCbCr
        // Huffman Table DC 1 for Chroma
        pbuf = header + length;
        length += DefineHuffmanTableMarkerDC(pbuf, &JPEG_StdHuffmanTbl[368], 0x01);

        // Huffman Table AC 1 for Chroma
        pbuf = header + length;
        length += DefineHuffmanTableMarkerAC(pbuf, &JPEG_StdHuffmanTbl[176], 0x11);
    }

    // Restart Interval
    if (restart_int > 0) {
        pbuf = header + length;
        length += DefineRestartIntervalMarker(pbuf, restart_int);
    }

    // Scan Header
    pbuf = header + length;
    length += ScanHeaderMarker(pbuf, format);

    return length;
}
#endif// jpeg defined 



//*****************************************************************************
//
// Close the Doxygen group.
//! @}
//
//*****************************************************************************