TI's CC3100 websocket camera demo with Arducam mini ov5642 and freertos. Should work with other M3's. Work in progress test demo.

Dependencies:   mbed

camera_app/camera_app.cpp

Committer:
dflet
Date:
2015-09-11
Revision:
1:e448e81c416f
Parent:
0:400d8e75a8d0

File content as of revision 1:e448e81c416f:

//*****************************************************************************
// 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 "camera_app.h"
#include "ArduCAM.h"
#include "ov5642_regs.h"
//#include "i2cconfig.h"
//#include "camera.h"

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

using namespace mbed_cc3100;


ArduCAM myCAM(OV5642, p14, SPI(p11, p12, p13), I2C(p28, p27));

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

unsigned int g_frame_size_in_bytes;
unsigned int g_uiDeviceModeConfig = ROLE_AP; //default is AP mode 
extern volatile unsigned char g_CaptureImage;
extern int g_uiIpObtained = 0;
extern int g_uiSimplelinkRole = ROLE_INVALID;
uint32_t picLoop = 0;
unsigned int g_uiIpAddress = 0;
volatile static unsigned char g_frame_end;

#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 = 240;
    int PIXELS_IN_Y_AXIS = 256;
    int FRAME_SIZE_IN_BYTES = (240 * 256 * 2);
#endif    

struct ImageBuffer
{
#ifdef ENABLE_JPEG
	char g_header[SMTP_BUF_LEN] /*= {'\0'}*/;
#endif
	uint8_t g_image_buffer[IMAGE_BUF_SIZE];//12Kb
};

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                         
//
//*****************************************************************************

unsigned short StartCamera(char **WriteBuffer)
{
	unsigned short 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)
{    
    getCamId();
    
#ifdef ENABLE_JPEG
    //Change to JPEG capture mode and initialize the OV5642 module    
    myCAM.set_format(JPEG);
#endif    
    
    //
    // Initialize camera sensor
    //
    myCAM.InitCAM();
    myCAM.clear_fifo_flag();
    myCAM.write_reg(ARDUCHIP_TIM, VSYNC_LEVEL_MASK);
    myCAM.write_reg(ARDUCHIP_FRAMES,0x00); //Bit[2:0]Number of frames to be captured
    
}

void getCamId(){
	
	uint8_t vid = 0;
	uint8_t pid = 0;
	
	//Check if the camera module type is OV5642
    myCAM.rdSensorReg16_8(OV5642_CHIPID_HIGH, &vid);
    myCAM.rdSensorReg16_8(OV5642_CHIPID_LOW, &pid);
    if((vid != 0x56) || (pid != 0x42)){
      printf("Can't find OV5642 module! vid = 0x%x pid = 0x%x\r\n",vid, pid);
      while(1);
    }else{
      printf("OV5642 detected\r\n");
  }
}	

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

    //uint32_t g_header_length = 0;
    myCAM.flush_fifo();
    wait_ms(5);
    myCAM.clear_fifo_flag();     
    wait(1);
    //
    // Perform Image Capture 
    //
#ifdef ENABLE_JPEG
    myCAM.start_capture();
#else

#endif 

    while (!(myCAM.get_bit(ARDUCHIP_TRIG, CAP_DONE_MASK))){
      wait_ms(100);
   }
   g_frame_size_in_bytes = myCAM.read_fifo_length();
   read_fifo_burst(); 
 
    /* Read the number of data items transferred in bytes) */
    if(g_frame_size_in_bytes <= 0 ){
    	HttpDebug("\r\nFailed to capture or data over-run, check camera connections!\r\n");
    	while(1){
    		wait(0.5);
    	}
    }	
       
    //
    // Create JPEG Header
    //
#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, 9);
//    HttpDebug("g_header_length = 0x%x \r\n",g_header_length);
    // This pushes the header to the start of the array so that the entire picture can be contiguous in memory
//    memcpy(Image + g_header_length, Image, g_frame_size_in_bytes);
//    memcpy(Image, g_image.g_header, g_header_length);
    // This pushes the header to the end of the array so that the entire picture can be contiguous in memory
//    memcpy(Image + g_frame_size_in_bytes, g_image.g_header, g_header_length);

#endif//ENABLE_JPEG
    picLoop++;
    HttpDebug("\r\nPicture Sent %d\r\n",picLoop);

    *WriteBuffer = (char*)g_image.g_image_buffer;

	return(g_frame_size_in_bytes);
}

uint8_t read_fifo_burst()
{
    
    uint32_t bytesRead = 0;
    uint8_t temp = 0;
    uint8_t temp_last = 0;
    int32_t i;
    
    myCAM.cs_low(); 
    myCAM.set_fifo_burst();    
    myCAM._cam_spi.write(0x00);//Ignore first byte
    i = 0;
    while( 1 ){        
        temp_last = temp;    
        temp = (uint8_t )myCAM._cam_spi.write(0x00);
        g_image.g_image_buffer[i] = temp;
        i++;
        bytesRead++;
        if( temp == 0xD9 && temp_last == 0xFF ){           
           break;
        }
        if(i>= 1024 *10){
           HttpDebug("\r\nFile size exceeds 10K limit 0x%x\r\n",bytesRead);
           break;
        }
    }
    g_frame_size_in_bytes = bytesRead;
    myCAM.cs_high();
    
    return 1;
}

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

#ifdef ENABLE_JPEG
static int JfifApp0Marker(char *pbuf)
{
    *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)
{
    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)
{
    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)
{
    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)
{
    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)
{
    *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)
{
    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.
//! @}
//
//*****************************************************************************