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

Revision:
0:993f719c9352
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Tue Aug 26 16:49:26 2014 +0000
@@ -0,0 +1,421 @@
+/*
+ * 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