/********************************************************** * driver for MCA-25 camera * * @Author : Simon Schulz [avrauctionant.de] * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 51 * Franklin St, Fifth Floor, Boston, MA 02110, USA * * http://www.gnu.de/gpl-ger.html ***********************************************************/ #include "mca25.h" #include "main.h" volatile unsigned char mca25_uart_disabled; unsigned char mca25_cam_busy_for_socket = MCA25_NOT_BUSY; unsigned char mca25_cam_status = 0; /* typical usage: 1) mca25_init(); -> trigger a hardware reset and activates mux transfer 2) mca25_configure(); -> set up image format etc. 3) mca25_start_image_grab(); -> activate image grabbing, take a preview image 4) mca25_grab_jpeg(); -> activate jpg transfer 5) mca25_grab_data(); -> get x byte data 6) while (){ mca25_send_data_ack(); mca25_grab_data(); ... } -> ack & grab loop => see mca25_copy_image_data_to_tcp_buffer() as an example ;) */ int memcmp_P(unsigned char *buf, PGM_P pointer, unsigned int len) { while(len--) if( *buf++ != pgm_read_byte(pointer++)) return 1; return 0; } /*====================================================================== | copy the image data to the tcp data buffer, | buffer must be at least CAM_BUFFER_LEN byte long ! `======================================================================*/ /*unsigned char mca25_copy_image_data_to_tcp_buffer(char *buffer, int *bufferlen){ unsigned int result16; unsigned int len = 0; unsigned char frametype = 0; //Errechnet startpunkt der Daten im Tcp buffer //IP Headerl�ge + TCP Headerl�ge + Ethernetframe result16 = ((buffer[IP_VERS_LEN] & 0x0F) << 2) + ((buffer[TCP_HDRFLAGS] & 0xF0) >>2) + 14; //if we have had an error, we need to skip //the remaining picture. cam has no ABORT cmd ?!?! if (mca25_cam_status == MCA25_SKIP_PICTURE){ frametype = 0x48; //skip the current active picture... //dirty hack but seems like cam does //not have any abort commands :( while (frametype == 0x48){ mca25_uart_disabled = 0; mca25_send_data_ack(); mca25_uart_disabled = 1; mca25_grab_data((buffer+result16), &len, &frametype); //grabs 250 byte data } mca25_uart_disabled=0; printf_P(PSTR("\xF9\x01\xEF\x0B\xE3\x07\x23\x0C\x01\x79\xF9"); mca25_uart_disabled=1; mca25_cam_status = MCA25_FIRST_DATA; } #if USE_SERVO //this is the _only_ safe position to move the servo //a servo movement while cam is running freezes the cam ! //maybe a seperate power supply for servo can fix this (EM) if (servo_need_update){ servo_move(); //wait some time for (unsigned int z=0; z<60000; z++){ for (int y=0; y<20; y++){ nop();nop();nop();nop();nop();nop(); } } } #endif if (mca25_cam_status == MCA25_FIRST_DATA){ //start grab here, this takes a //long time... mca25_start_image_grab(); //initialise jpg dump mca25_grab_jpeg(); //first packet done mca25_cam_status = MCA25_NEXT_DATA; }else{ // if (mca25_cam_status == MCA25_NEXT_DATA){ mca25_uart_disabled = 0; mca25_send_data_ack(); mca25_uart_disabled = 1; } // we use the ethernet buffer for // storing the image data // --> make sure it is big enough ! (fixme) mca25_grab_data((buffer+result16), &len, &frametype); //sometimes the last packet seems to be empty //-> send this dummy data, it does not matter ... if (len == 0) len = CAM_BUFFER_LEN; //store data length result16 = result16 + len; //fixme, do something here ... */ /*if (result16 > (MTU_SIZE - 1)){ Buffer_Full = 1; printf_P(PSTR("WARN: buffer > MTU-1 !\n"); break; }*/ /* //Wait a short Time for(int a = 0;a<1000;a++){nop();}; TCP_New_Packtlen (buffer,bufferlen,result16); // last picture is XX SH SL CC 00 // CC = 0x48 -> more data (?) // = 0x49 -> last data if (frametype!=0x48){ // this is important ! after the image grad // we need to do this! without this the camera // sometimes hangs while grabbing another image ... strange // reconfig mux (?) mca25_uart_disabled=0; printf_P(PSTR("\xF9\x01\xEF\x0B\xE3\x07\x23\x0C\x01\x79\xF9"); mca25_uart_disabled=1; return 0; // this is a smaller packet -> it was the last }else return 1; // this is a full packet -> there should be more (fixme) } */ /*====================================================================== | grab the next x byte data frame | (cam must bei in jpg capture mode!) `======================================================================*/ void mca25_grab_data(char *buffer, unsigned int *datalen, char *frametype){ unsigned int j=0; unsigned char togo=31; unsigned char rx=0; unsigned char state=0; unsigned char firstframe = 1; //enable uart: mca25_uart_disabled=0; *datalen = 0; // we start with len=0, // we extract the packetlength // after the first packet and update len // // if we re in state12 -> continue, we do not have the full len yet while( *datalen==0 || (j<*datalen) || state>99 || state == 12 ){ MCA25_STATUS_LED_ON(); while (!(USR & (1< retry //MCA25_ERROR_LED_ON(); } } break; case 3: //next byte is frame len: togo = (rx-1)/2; //rx/2 //printf_P(PSTR("len=%d\n",togo); //if (togo != 31 && togo != 13) printf_P(PSTR("len=%d\n",togo); if (firstframe==1) state = 10; //get frame info else state = 100; //grab data break; case 10: //90 01 00 48 00 xx //this is the first packet and we //have not sampled anything //-> this is 0x90 -> ignore togo--; state = 11; firstframe = 0; break; case 11: //this is the first packet and //this byte is hi(length) *datalen = (unsigned int)(rx<<8); togo--; state = 12; break; case 12: //this is the first packet and //this byte is lo(length) *datalen = (unsigned int)*datalen + (unsigned int)(rx) - 6; //substract the first //6byte frame info //make sure len is valid if (*datalen > CAM_BUFFER_LEN){ *datalen = CAM_BUFFER_LEN; } togo--; state = 13; break; case 13: //this is the first packet and //this byte is the frame type *frametype = rx; togo--; state = 14; break; case 14: //this is the first packet and //this byte is ??? -> ignore togo--; state = 15; break; case 15: //this is the first packet and //this byte is ??? -> ignore togo--; state = 100; //now sample data break; case 100: //now sample data: if (j first 256 byte // xx xx = 48 01 -> middle // xx xx = 49 01 -> last data! #if CAM_BUFFER_LEN == 256 if (memcmp_P(buf,PSTR("\xF9\x83\xEF\x3F\x90"),5) == 0){ #else // 512byte buf: // 90 02 00 C3 00 00 // 90 02 00 48 01 FD // A0 01 10 49 01 0D if (memcmp_P(buf,PSTR("\xF9\x83\xEF\x3F\x90\x02"),6) == 0){ #endif if (buf[7] == 0xC3 && buf[8] == 0x00){ //first frame: datapos = 1; }else if(buf[7] == 0x48 && buf[8] == 0x01){ //middle datapos = 2; }else if(buf[7] == 0x49 && buf[8] == 0x01){ //end: datapos = 3; }else if(buf[7] == 0x48 && buf[8] == 0x00){ //end? datapos = 2; }else{ //printf_P(PSTR("buf7=%x, buf8=%x\n\n",buf[7],buf[8]); } state = 1; //last data -> send ack! mca25_send_data_ack(); }else if (memcmp_P(buf,PSTR("\xF9\x83\xEF\x3F\xA0"),5) == 0){ // F9 83 EF 3F A0 00 4C 49 00 49 00 if(buf[7] == 0x49 && buf[8] == 0x00){ //end when CAM_BUF_LEN = 256 datapos = 3; }else if(buf[7] == 0x49 && buf[8] == 0x01){ //end when CAM_BUF_LEN = 512 datapos = 3; }else{ //printf_P(PSTR("buf7=%x, buf8=%x\n\n",buf[7],buf[8]); } state = 1; //last data -> send ack! mca25_send_data_ack(); } break; case 1: // wait for end of 256 Byte packet: // [F9 83 EF 11 ** ** ** ** ** ** ** ** 3F F9 ] #if CAM_BUFFER_LEN == 256 if ( (memcmp_P(buf,PSTR("\xF9\x83\xEF\x11"),4) == 0) || (memcmp_P(buf,PSTR("\xF9\x83\xEF\x1D"),4) == 0) ) { #else if ( (memcmp_P(buf,PSTR("\xF9\x83\xEF\x21"),4) == 0) || (memcmp_P(buf,PSTR("\xF9\x83\xEF\x31"),4) == 0) ) { #endif state =0; if (datapos == 3){ //pic finished -> exit state = 100; } } break; } } //preview image #i has been grabbed. } //disable uart: mca25_uart_disabled=1; } /*====================================================================== | configure the camera | (mca25_init() has to be called first !) `======================================================================*/ void mca25_configure(){ unsigned char state=0; unsigned char buf[MCA25_COMM_BUFFER_LEN]; //enable uart: mca25_uart_disabled=0; while (state != 100){ mca25_read_mux_packet(buf); //read MUX packet switch (state){ case 0: mca25_pgm_send(MCA25_CONFIG_640x480); state = 1; break; case 1: // wait for cam ACK: // [F9 83 EF 07 A0 00 03 C7 F9 if (memcmp_P(buf,PSTR("\xF9\x83\xEF\x07\xA0\x00\x03\xC7\xF9"),9) == 0){ // request camera info: // [F9 81 EF 2F 83 00 17 42 00 14 78 2D 62 74 2F 63 // 61 6D 65 72 61 2D 69 6E 66 6F 00 90 F9] printf_P(PSTR("\xF9\x81\xEF\x2F\x83")); uart_putchar('\x00'); printf_P(PSTR("\x17\x42")); uart_putchar('\x00'); printf_P(PSTR("\x14\x78\x2D\x62\x74\x2F\x63\x61\x6D\x65\x72\x61")); printf_P(PSTR("\x2D\x69\x6E\x66\x6F")); uart_putchar('\x00'); printf_P(PSTR("\x90\xF9")); state = 2; } break; case 2: // ignore camera info ... // -> wait for last info packet: // [F9 83 EF 33 79 65 72 3D 22 31 30 22 2F 3E 3C 2F // 63 61 6D 65 72 61 2D 69 6E 66 6F 3E 00 E4 F9] if (memcmp_P(buf,PSTR("\xF9\x83\xEF\x33\x79\x65\x72\x3D\x22\x31\x30\x22" "\x2F\x3E\x3C\x2F\x63\x61\x6D\x65\x72\x61\x2D\x69" "\x6E\x66\x6F\x3E\x00\xE4\xF9"),31)){ //CAM READY ! state = 100; } break; } } //disable uart: mca25_uart_disabled=1; } /*====================================================================== | initialise the camera | this has to be done at first, it activates the mux mode also `======================================================================*/ void mca25_init(void){ unsigned char state=0; unsigned char buf[MCA25_COMM_BUFFER_LEN]; //enable uart: mca25_uart_disabled=0; MCA25_RESET_PORT_DIR |= (1< exit init loop. } break; default: break; } } //disable uart: mca25_uart_disabled=1; } /*====================================================================== | resets the camera (hw reset !) `======================================================================*/ void mca25_reset_cam(){ unsigned char j; MCA25_RESET_LO(); //wait some time: unsigned long i; for (j=0; j<20; j++){ i = 0; while (i < 60000 * 20) i++; } MCA25_RESET_HI(); } /************************** HELPER ***********************************/ void mca25_send_data_ack(){ printf_P(PSTR("\xF9\x81\xEF\x07\x83")); uart_putchar('\x00'); printf_P(PSTR("\x03\xA6\xF9")); } void mca25_set_460800baud(){ unsigned long i = 0; while (i < 60000 * 20) i++; UBRR=(F_CPU / (460800 * 16L) - 1); } void mca25_send_ok(){ puts("\r\r\nOK\r"); //puts adds a newline !! } void mca25_read_mux_packet(unsigned char *buffer){ unsigned int cnt; for(cnt=0;cnt < MCA25_COMM_BUFFER_LEN - 1;cnt++){ MCA25_STATUS_LED_ON(); while (!(USR & (1<0 && buffer[cnt] == 0xF9){ //'\xF9'){ buffer[cnt+1] = '\0'; break; //we have finished out read. } } return; } void mca25_read_at_command(unsigned char *buffer){ unsigned int cnt; for(cnt=0;cnt exit; break; }else{ if (valid>=3) uart_putchar(old[3]); else valid++; /*if (in == 0xF9){ //wait some time int a = 0; while (a < 1000){a++;} }*/ } } } /******************************* CONSTANTS **********************************/ //some constants (command sequence) PROGMEM char MCA25_START_JPG[] = { 0xF9,0x81,0xEF,0x3F,0x83,0x00,0x82,0x71,0x00,0x58,0x3C,0x6D,0x6F,0x6E,0x69,0x74,0x6F,0x72,0x69,0x6E,0x67,0x2D,0x63,0x6F, 0x6D,0x6D,0x61,0x6E,0x64,0x20,0x76,0x65,0x72,0x73,0x69,0x8C,0xF9, 0xF9,0x81,0xEF,0x3F,0x6F,0x6E,0x3D,0x22,0x31,0x2E,0x30,0x22,0x20,0x74,0x61,0x6B,0x65,0x2D,0x70,0x69,0x63,0x3D,0x22,0x4E, 0x4F,0x22,0x20,0x73,0x65,0x6E,0x64,0x2D,0x70,0x69,0x78,0x8C,0xF9, 0xF9,0x81,0xEF,0x3F,0x65,0x6C,0x2D,0x73,0x69,0x7A,0x65,0x3D,0x22,0x36,0x34,0x30,0x2A,0x34,0x38,0x30,0x22,0x20,0x7A,0x6F, 0x6F,0x6D,0x3D,0x22,0x31,0x30,0x22,0x2F,0x3E,0x42,0x00,0x8C,0xF9, 0xF9,0x81,0xEF,0x3F,0x21,0x78,0x2D,0x62,0x74,0x2F,0x69,0x6D,0x61,0x67,0x69,0x6E,0x67,0x2D,0x6D,0x6F,0x6E,0x69,0x74,0x6F, 0x72,0x69,0x6E,0x67,0x2D,0x69,0x6D,0x61,0x67,0x65,0x00,0x8C,0xF9, 0xF9,0x81,0xEF,0x0D,0x4C,0x00,0x06,0x06,0x01,0x80,0x4B,0xF9, '%','E','N','D'}; PROGMEM char MCA25_START_CAPTURING_1[] = { 0xF9,0x81,0xEF,0x3F,0x83,0x00,0x69,0x71,0x00,0x3F,0x3C,0x6D,0x6F,0x6E,0x69,0x74,0x6F,0x72,0x69, 0x6E,0x67,0x2D,0x63,0x6F,0x6D,0x6D,0x61,0x6E,0x64,0x20,0x76,0x65,0x72,0x73,0x69,0x8C,0xF9, '%','E','N','D'}; PROGMEM char MCA25_START_CAPTURING_2[] = { 0xF9,0x81,0xEF,0x3F,0x6F,0x6E,0x3D,0x22,0x31,0x2E,0x30,0x22,0x20,0x74,0x61,0x6B,0x65,0x2D,0x70, 0x69,0x63,0x3D,0x22,0x59,0x45,0x53,0x22,0x20,0x7A,0x6F,0x6F,0x6D,0x3D,0x22,0x31,0x8C,0xF9, 0xF9,0x81,0xEF,0x3F,0x30,0x22,0x2F,0x3E,0x42,0x00,0x21,0x78,0x2D,0x62,0x74,0x2F,0x69,0x6D,0x61, 0x67,0x69,0x6E,0x67,0x2D,0x6D,0x6F,0x6E,0x69,0x74,0x6F,0x72,0x69,0x6E,0x67,0x2D,0x8C,0xF9, '%','E','N','D'}; PROGMEM char MCA25_START_CAPTURING_3[] = { 0xF9,0x81,0xEF,0x19,0x69,0x6D,0x61,0x67,0x65,0x00,0x4C,0x00,0x06,0x06,0x01,0x80,0x50,0xF9,'%','E','N','D'}; PROGMEM char MCA25_CONFIG_640x480[] = { 0xF9,0x81,0xEF,0x3F,0x82,0x01,0x3B,0x01,0x00,0x03,0x49,0x01,0x35,0x3C,0x63,0x61,0x6D,0x65, 0x72,0x61,0x2D,0x73,0x65,0x74,0x74,0x69,0x6E,0x67,0x73,0x20,0x76,0x65,0x72,0x73,0x69,0x8C,0xF9, 0xF9,0x81,0xEF,0x3F,0x6F,0x6E,0x3D,0x22,0x31,0x2E,0x30,0x22,0x20,0x77,0x68,0x69,0x74,0x65, 0x2D,0x62,0x61,0x6C,0x61,0x6E,0x63,0x65,0x3D,0x22,0x4F,0x46,0x46,0x22,0x20,0x63,0x6F,0x8C,0xF9, 0xF9,0x81,0xEF,0x3F,0x6C,0x6F,0x72,0x2D,0x63,0x6F,0x6D,0x70,0x65,0x6E,0x73,0x61,0x74,0x69, 0x6F,0x6E,0x3D,0x22,0x31,0x33,0x22,0x20,0x66,0x75,0x6E,0x2D,0x6C,0x61,0x79,0x65,0x72,0x8C,0xF9, 0xF9,0x81,0xEF,0x3F,0x3D,0x22,0x30,0x22,0x3E,0x3C,0x6D,0x6F,0x6E,0x69,0x74,0x6F,0x72,0x69, 0x6E,0x67,0x2D,0x66,0x6F,0x72,0x6D,0x61,0x74,0x20,0x65,0x6E,0x63,0x6F,0x64,0x69,0x6E,0x8C,0xF9, 0xF9,0x81,0xEF,0x3F,0x67,0x3D,0x22,0x45,0x42,0x4D,0x50,0x22,0x20,0x70,0x69,0x78,0x65,0x6C, 0x2D,0x73,0x69,0x7A,0x65,0x3D,0x22,0x38,0x30,0x2A,0x36,0x30,0x22,0x20,0x63,0x6F,0x6C,0x8C,0xF9, 0xF9,0x81,0xEF,0x3F,0x6F,0x72,0x2D,0x64,0x65,0x70,0x74,0x68,0x3D,0x22,0x38,0x22,0x2F,0x3E, 0x0D,0x0A,0x3C,0x74,0x68,0x75,0x6D,0x62,0x6E,0x61,0x69,0x6C,0x2D,0x66,0x6F,0x72,0x6D,0x8C,0xF9, 0xF9,0x81,0xEF,0x3F,0x61,0x74,0x20,0x65,0x6E,0x63,0x6F,0x64,0x69,0x6E,0x67,0x3D,0x22,0x45, 0x42,0x4D,0x50,0x22,0x20,0x70,0x69,0x78,0x65,0x6C,0x2D,0x73,0x69,0x7A,0x65,0x3D,0x22,0x8C,0xF9, 0xF9,0x81,0xEF,0x3F,0x31,0x30,0x31,0x2A,0x38,0x30,0x22,0x20,0x63,0x6F,0x6C,0x6F,0x72,0x2D, 0x64,0x65,0x70,0x74,0x68,0x3D,0x22,0x38,0x22,0x2F,0x3E,0x0D,0x0A,0x3C,0x6E,0x61,0x74,0x8C,0xF9, 0xF9,0x81,0xEF,0x3F,0x69,0x76,0x65,0x2D,0x66,0x6F,0x72,0x6D,0x61,0x74,0x20,0x65,0x6E,0x63, 0x6F,0x64,0x69,0x6E,0x67,0x3D,0x22,0x22,0x20,0x70,0x69,0x78,0x65,0x6C,0x2D,0x73,0x69,0x8C,0xF9, 0xF9,0x81,0xEF,0x3F,0x7A,0x65,0x3D,0x22,0x36,0x34,0x30,0x2A,0x34,0x38,0x30,0x22,0x2F,0x3E, 0x0D,0x0A,0x3C,0x2F,0x63,0x61,0x6D,0x65,0x72,0x61,0x2D,0x73,0x65,0x74,0x74,0x69,0x6E,0x8C,0xF9, 0xF9,0x81,0xEF,0x0B,0x67,0x73,0x3E,0x0D,0x0A,0xAF,0xF9,'%','E','N','D'};