First release

Dependencies:   EthernetInterface HTTPServer TextLCD mbed-rpc mbed-rtos mbed

Sample code of section 5 in Oct 2014 issue of the Interface Magazine, published by CQ publishing in Japan. CQ出版社インターフェース誌 2014年10月号5章に掲載のサンプルコードです.

LPC1768にトラ技OV7670モジュールとサーボを接続したうえで,リモート操作可能なネットワーク・カメラにしています.このコードのうちカメラ制御部には,Sadaei Osakabe氏のコードを流用させていただいています.

また,次のHTMLファイルをダウンロードして,LPC1768のフラッシュメモリに置いてください.ネットワーク経由で,このHTMLにアクセスをします(ブラウザで開く). /media/uploads/smorioka/netcam.htm

main.cpp

Committer:
smorioka
Date:
2014-08-26
Revision:
0:993f719c9352

File content as of revision 0:993f719c9352:

/*
 * Copyright (c) 2014, Sumio Morioka
 * All rights reserved.
 *
 * This source code was originally written by Dr.Sumio Morioka for use in the Oct 2014 issue of 
 * "the Interface magazine", published by CQ publishing Co.Ltd in Japan (http://www.cqpub.co.jp).
 * The author has no responsibility on any results caused by using this code.
 *
 * - Distribution date of this code: Aug 26, 2014
 * - Author: Dr.Sumio Morioka (http://www002.upp.so-net.ne.jp/morioka)
 *
 *
 * IMPORTANT NOTICE:
 * 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 the copyright holder 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 HOLDER 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.
 */
 
#include "mbed.h"
#include "mbed_rpc.h"

#include "TextLCD.h"
#include "LocalFileSystem.h"

#include "EthernetInterface.h"
#include "HTTPServer.h"
#include "FsHandler.h"
#include "RpcHandler.h"

#include "ov7670.h"

TextLCD lcd(p24, p26, p27, p28, p29, p30);


//#define USE_RPCOUT
#undef USE_RPCOUT

#ifndef USE_RPCOUT
DigitalOut led1(LED1), led2(LED2), led3(LED3), led4(LED4);
PwmOut sv0(p21), sv1(p22), sv2(p23);
#else
RpcDigitalOut led1(LED1, "led1");
RpcDigitalOut led2(LED2, "led2");
RpcDigitalOut led3(LED3, "led3");
RpcDigitalOut led4(LED4, "led4");

RpcPwmOut sv0(p21, "sv0");
RpcPwmOut sv1(p22, "sv1");
RpcPwmOut sv2(p23, "sv2");
#endif


LocalFileSystem local("webfs");

OV7670 camera(
    p9,p10,			// SDA,SCL(I2C / SCCB)
    p5,p6,p7,		// VSYNC,HREF,WEN(FIFO)
    p20,p19,p18,p17,p16,p15,p14,p13,	// D7-D0
    p8,p11,p12);	// RRST,OE,RCLK

//Timer tmr;

#define QQVGA
//#define QVGA
//#define VGA34

#ifdef QQVGA
#define SIZEX 160
#define SIZEY 120
#endif

#ifdef QVGA
#define SIZEX 320
#define SIZEY 240
#endif

#ifdef VGA34
#define SIZEX 480
#define SIZEY 360
#endif


//void cam_cap(void);
void cam_cap(Arguments* input, Reply* output);
RPCFunction rpcFunc(&cam_cap, "cam_cap");

#ifndef USE_RPCOUT
float	sv0_rpc;
float	sv1_rpc;
float	sv2_rpc;

RPCVariable<float> rpc_sv0_val(&sv0_rpc, "sv0");
RPCVariable<float> rpc_sv1_val(&sv1_rpc, "sv1");
RPCVariable<float> rpc_sv2_val(&sv2_rpc, "sv2");
#endif

int		cap_flag;
RPCVariable<int> rpc_cap_flag(&cap_flag, "cap_flag");


int memfree(void)
{
	int	ret = 1;
	while (1) {
		char	*p	= (char *)malloc(ret);
		if (p == NULL)
			break;
		free(p);
		ret++;
	}
	return (ret);
}


float deg_to_pulsewidth(float deg)
{
	// limit range
	if (deg < -90.0f)
		deg	= -90.0f;
	else if (deg > 90.0f)
		deg = 90.0f;

	// return result
	return (0.00145f + 0.001f * (deg / 90.0f));
}

int main() 
{
	float	sv0_val, sv1_val, sv2_val;
	
#ifndef USE_RPCOUT
    led1 = 0;
    led2 = 0;
    led3 = 0;
    led4 = 0;
#else
	led1.write(0);
	led2.write(0);
	led3.write(0);
	led4.write(0);
#endif

#ifdef USE_RPCOUT
	sv0_val	= 0.00045f;			// unit: sec
	sv1_val	= 0.00145f;			// unit: sec
	sv2_val	= 0.00245f;			// unit: sec

	sv0.period(0.02f);			// unit: sec
	sv0.pulsewidth(sv0_val);

	sv1.period(0.02f);			// unit: sec
	sv1.pulsewidth(sv1_val);

	sv2.period(0.02f);			// unit: sec
	sv2.pulsewidth(sv2_val);

#else
	sv0_val	= 0.0f;				// unit: deg
	sv1_val	= 0.0f;				// unit: deg
	sv2_val	= 0.0f;				// unit: deg
	
	sv0.period(0.02f);			// unit: sec
	sv0.pulsewidth(deg_to_pulsewidth(sv0_val));

	sv1.period(0.02f);			// unit: sec
	sv1.pulsewidth(deg_to_pulsewidth(sv1_val));

	sv2.period(0.02f);			// unit: sec
	sv2.pulsewidth(deg_to_pulsewidth(sv2_val));

	sv0_rpc	= sv0_val;
	sv1_rpc	= sv1_val;
	sv2_rpc	= sv2_val;
#endif
	
	cap_flag	= 0;

	////////////////////////////////////////////////////////////////////////////
    camera.WriteReg(0x12, 0x80);			// com7; reset
    wait_ms(200);

	camera.InitDefaultReg();

    // negate vsync
    camera.WriteReg(0x15, 0x02);			// com10; negative vsync

#ifdef QQVGA
	camera.InitQQVGA();
#endif
#ifdef QVGA
	camera.InitQVGA();
#endif
#ifdef VGA34
	camera.InitVGA_3_4();
#endif

    // data format
    camera.WriteReg(0x12, 0x04 + 0);    // com7 RGB	(bit1...test pattern)
    camera.WriteReg(0x40, 0xD0);    // com15 RGB565
    camera.WriteReg(0x8c, 0x00);    // RGB444

    wait_ms(300);

//{
//FILE *f = fopen("/webfs/REG.TXT", "wt");
//for (int i = 0; i < 256; i++) {
//    int val = camera.ReadReg(i);
//	fprintf(f, "%02X ", val);
//	if ((i % 16) == 15)
//		fprintf(f, "\n");
//}
//fclose(f);
//}

    //////////////////////////////////////////////////

    // network
    EthernetInterface   eth;    // locate here

//  //Static IP
//	char *ip		= "192.168.0.20";
//	char *mask		= "255.255.255.0";
//	char *gateway	= "192.168.0.1";
//	eth.init(ip, mask, gateway);
    //DHCP
	eth.init();

    eth.connect();

    lcd.locate(0, 0);
    lcd.printf("IP %s", eth.getIPAddress());

	// rcp
#ifdef USE_RPCOUT
//    RPC::add_rpc_class<RpcDigitalIn>();		// read
    RPC::add_rpc_class<RpcDigitalOut>();		// read,write
//    RPC::add_rpc_class<RpcDigitalInOut>();	// read,write,input,output
    RPC::add_rpc_class<RpcPwmOut>();			// read,write,period,period_ms,pulsewidth,pulsewidth_ms
//    RPC::add_rpc_class<RpcAnalogIn>();		// read,read_u16
//    RPC::add_rpc_class<RpcAnalogOut>();		// read,write,write_u16
//    RPC::add_rpc_class<RpcSPI>();				// format,frequency,write
//    RPC::add_rpc_class<RpcSerial>();			// baud,readable,writeable(SPELL?),putc,getc,puts
//    RPC::add_rpc_class<RpcTimer>();			// start,stop,reset,read,read_ms,read_us
#endif

    // http
    HTTPServer svr;         // locate here
    HTTPFsRequestHandler::mount("/webfs/", "/");
    svr.addHandler<HTTPFsRequestHandler>("/");
    svr.addHandler<HTTPRpcRequestHandler>("/rpc");

    svr.start(80, &eth);

//    lcd.locate(0, 1);
//    lcd.printf("mem %d", memfree());
		
#ifndef USE_RPCOUT
	led1 = 1;
#else
	led1.write(1);
#endif

    while (1) {
		svr.poll();

#ifndef USE_RPCOUT
		if (sv0_val != sv0_rpc) {
			sv0_val	= sv0_rpc;
			// limit
			if (sv0_val < -90.0f)
				sv0_val	= -90.0f;
			else if (sv0_val > 90.0f)
				sv0_val	= 90.0f;

			sv0_rpc	= sv0_val;
			sv0.pulsewidth(deg_to_pulsewidth(sv0_val));

    		lcd.locate(0, 1);
    		lcd.printf("0:%f ", sv0_val);
    	}

		if (sv1_val != sv1_rpc) {
			sv1_val	= sv1_rpc;
			// limit
			if (sv1_val < -90.0f)
				sv1_val	= -90.0f;
			else if (sv1_val > 90.0f)
				sv1_val	= 90.0f;

			sv1_rpc	= sv1_val;
			sv1.pulsewidth(deg_to_pulsewidth(sv1_val));

    		lcd.locate(0, 1);
    		lcd.printf("1:%f ", sv1_val);
    	}

		if (sv2_val != sv2_rpc) {
			sv2_val	= sv2_rpc;
			// limit
			if (sv2_val < -90.0f)
				sv2_val	= -90.0f;
			else if (sv2_val > 90.0f)
				sv2_val	= 90.0f;

			sv2_rpc	= sv2_val;
			sv2.pulsewidth(deg_to_pulsewidth(sv2_val));

    		lcd.locate(0, 1);
    		lcd.printf("2:%f ", sv2_val);
    	}
#endif

		wait_ms(10);
   }
}


//void cam_capture(char *input, char *output)		// compile error
void cam_cap(Arguments* input, Reply* output)
//void cam_cap(void)
{
	FILE *fp_bmp;
    unsigned int d1, d2;
    unsigned char sort[3];

#ifndef USE_RPCOUT
	led2 = 1;
#else
	led2.write(1);
#endif

	cap_flag	= 0;

    fp_bmp	= fopen("/webfs/cam.bmp", "wb");

    /////////////////////////
    // file header
    /////////////////////////
    fprintf(fp_bmp, "BM");
    int val = 14 + 40 + SIZEX * SIZEY * 3;   // file size
    fprintf(fp_bmp, "%c%c%c%c", val % 0x100, val / 0x100, val / 0x10000, val / 0x1000000);
    fprintf(fp_bmp, "%c%c%c%c%c%c%c%c", 0, 0, 0, 0, 0x36, 0, 0, 0);

    /////////////////////////
    // information header
    /////////////////////////
    fprintf(fp_bmp, "%c%c%c%c", 0x28, 0, 0, 0);  // header size
    fprintf(fp_bmp, "%c%c%c%c", SIZEX % 0x100, SIZEX / 0x100, SIZEX / 0x10000, SIZEX / 0x1000000);
    fprintf(fp_bmp, "%c%c%c%c", SIZEY % 0x100, SIZEY / 0x100, SIZEY / 0x10000, SIZEY / 0x1000000);
    fprintf(fp_bmp, "%c%c", 1, 0);               // # of plane
    fprintf(fp_bmp, "%c%c", 24, 0);              // bit count
    fprintf(fp_bmp, "%c%c%c%c", 0, 0, 0, 0);     // compression
    val = SIZEX * SIZEY * 3;         // data size
    fprintf(fp_bmp, "%c%c%c%c", val % 0x100, val / 0x100, val / 0x10000, val / 0x1000000);
    fprintf(fp_bmp, "%c%c%c%c", 0, 0, 0, 0);
    fprintf(fp_bmp, "%c%c%c%c", 0, 0, 0, 0);
    fprintf(fp_bmp, "%c%c%c%c", 0, 0, 0, 0);
    fprintf(fp_bmp, "%c%c%c%c", 0, 0, 0, 0);

    camera.CaptureNext();   // sample start!

    while(camera.CaptureDone() == false)
        ;

    camera.ReadStart();     // reset pointer

#ifndef USE_RPCOUT
	led3 = 1;
#else
	led3.write(1);
#endif

    for (int y = 0;y < SIZEY;y++) {    
        for (int x = 0;x < SIZEX;x++) {
            d1 = camera.ReadOneByte() ; // upper nibble is XXX , lower nibble is B
            d2 = camera.ReadOneByte() ; // upper nibble is G   , lower nibble is R

			// RGB565
			sort[0]	= ((d1 & 0xF8) >> 3) << 3;		// R
			sort[1] = ( ((d1 & 0x07) << 3) + ((d2 & 0xE0) >> 5) ) << 2;		// G
			sort[2]	= (d2 & 0x1F) << 3;				// B

			fprintf(fp_bmp, "%c%c%c", sort[2], sort[1], sort[0]);		// B,G,R
        }
    }

    camera.ReadStop();
	fclose(fp_bmp);

#ifndef USE_RPCOUT
	led2 = 0;
	led3 = 0;
	led4 = 0;
#else
	led2.write(0);
	led3.write(0);
	led4.write(0);
#endif

	cap_flag	= 1;
}

// end of file