This is an digital video camera program using NKK\'s oLED swtich and 4D Systems\' uCam serial camera. It takes image from the uCam and displays on the IS-C15 switch. Some image processing demos are included. This program uses FatFileSytem, SDFileSystem, and TextLCD library. See http://www.youtube.com/watch?v=fqHTaCRHyQs for how it works. CQ出版社の「mbed/ARM活用事例」第10章シリアル接続カメラと有機ELディスプレイ内蔵スイッチで作るmbedディジタル・カメラの作例です。動作の様子は http://www.youtube.com/watch?v=fqHTaCRHyQs で見れます。
Dependencies: TextLCD mbed SDFileSystem
ucam.cpp@0:07d02a20d1cc, 2011-10-06 (annotated)
- Committer:
- non
- Date:
- Thu Oct 06 00:54:08 2011 +0000
- Revision:
- 0:07d02a20d1cc
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
non | 0:07d02a20d1cc | 1 | /* 4D Systems uCam serial RAW/JPEG camera library |
non | 0:07d02a20d1cc | 2 | * Copyright (c) 2011, Noriaki Mitsunaga |
non | 0:07d02a20d1cc | 3 | * |
non | 0:07d02a20d1cc | 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy |
non | 0:07d02a20d1cc | 5 | * of this software and associated documentation files (the "Software"), to deal |
non | 0:07d02a20d1cc | 6 | * in the Software without restriction, including without limitation the rights |
non | 0:07d02a20d1cc | 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
non | 0:07d02a20d1cc | 8 | * copies of the Software, and to permit persons to whom the Software is |
non | 0:07d02a20d1cc | 9 | * furnished to do so, subject to the following conditions: |
non | 0:07d02a20d1cc | 10 | * |
non | 0:07d02a20d1cc | 11 | * The above copyright notice and this permission notice shall be included in |
non | 0:07d02a20d1cc | 12 | * all copies or substantial portions of the Software. |
non | 0:07d02a20d1cc | 13 | * |
non | 0:07d02a20d1cc | 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
non | 0:07d02a20d1cc | 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
non | 0:07d02a20d1cc | 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
non | 0:07d02a20d1cc | 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
non | 0:07d02a20d1cc | 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
non | 0:07d02a20d1cc | 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
non | 0:07d02a20d1cc | 20 | * THE SOFTWARE. |
non | 0:07d02a20d1cc | 21 | */ |
non | 0:07d02a20d1cc | 22 | #include "mbed.h" |
non | 0:07d02a20d1cc | 23 | #include "ucam.h" |
non | 0:07d02a20d1cc | 24 | |
non | 0:07d02a20d1cc | 25 | // uCam-TTL commands: |
non | 0:07d02a20d1cc | 26 | const unsigned char ACK[] = {0xaa, 0x0e, 0x0d, 0, 0, 0}; |
non | 0:07d02a20d1cc | 27 | const unsigned char ACK1[] = {0xaa, 0x0e, 0x0d, 0, 1, 0}; |
non | 0:07d02a20d1cc | 28 | const unsigned char ACK_F0F0_[] = {0xaa, 0x0e, 0, 0, 0xf0, 0xf0}; |
non | 0:07d02a20d1cc | 29 | const unsigned char GETPICTURE_SNAPSHOT[] = {0xaa, 0x04, 0x01, 0, 0, 0}; |
non | 0:07d02a20d1cc | 30 | // const unsigned char GETPICTURE_RAWPREVIEW[] = {0xaa, 0x04, 0x02, 0, 0, 0}; |
non | 0:07d02a20d1cc | 31 | const unsigned char RESET[] = {0xaa, 0x08, 0x01, 0x0, 0x0, 0xff}; |
non | 0:07d02a20d1cc | 32 | const unsigned char SNAPSHOT_JPEG[] = {0xaa, 0x05, 0x00, 1, 0, 0}; |
non | 0:07d02a20d1cc | 33 | const unsigned char SNAPSHOT_RAW[] = {0xaa, 0x05, 0x01, 1, 0, 0}; |
non | 0:07d02a20d1cc | 34 | const unsigned char SYNC[] = {0xaa, 0x0d, 0, 0, 0, 0}; |
non | 0:07d02a20d1cc | 35 | |
non | 0:07d02a20d1cc | 36 | // Send special ACK |
non | 0:07d02a20d1cc | 37 | void uCam::ACK_F0F0() { |
non | 0:07d02a20d1cc | 38 | write(ACK_F0F0_, sizeof(ACK_F0F0_)); |
non | 0:07d02a20d1cc | 39 | } |
non | 0:07d02a20d1cc | 40 | |
non | 0:07d02a20d1cc | 41 | // Check if buf is valid ACK. |
non | 0:07d02a20d1cc | 42 | int uCam::checkACK(const unsigned char *buf) { |
non | 0:07d02a20d1cc | 43 | if (buf[0] == ACK[0] && buf[1] == ACK[1] && buf[2] == ACK[2] |
non | 0:07d02a20d1cc | 44 | && buf[4] == 0 && buf[5] == 0) |
non | 0:07d02a20d1cc | 45 | return 1; |
non | 0:07d02a20d1cc | 46 | |
non | 0:07d02a20d1cc | 47 | return 0; |
non | 0:07d02a20d1cc | 48 | } |
non | 0:07d02a20d1cc | 49 | |
non | 0:07d02a20d1cc | 50 | // Compare buf to SYNC |
non | 0:07d02a20d1cc | 51 | int uCam::checkSYNC(const unsigned char *buf) { |
non | 0:07d02a20d1cc | 52 | if (memcmp(buf, SYNC, sizeof(SYNC)) == 0) |
non | 0:07d02a20d1cc | 53 | return 1; |
non | 0:07d02a20d1cc | 54 | |
non | 0:07d02a20d1cc | 55 | return 0; |
non | 0:07d02a20d1cc | 56 | } |
non | 0:07d02a20d1cc | 57 | |
non | 0:07d02a20d1cc | 58 | // Send a command to uCam via the serial |
non | 0:07d02a20d1cc | 59 | int uCam::Command(const unsigned char *cmd) { |
non | 0:07d02a20d1cc | 60 | // Send the command |
non | 0:07d02a20d1cc | 61 | write(cmd, 6); |
non | 0:07d02a20d1cc | 62 | |
non | 0:07d02a20d1cc | 63 | // Wait for response |
non | 0:07d02a20d1cc | 64 | unsigned char buf[6]; |
non | 0:07d02a20d1cc | 65 | read(buf, 6); |
non | 0:07d02a20d1cc | 66 | |
non | 0:07d02a20d1cc | 67 | // Check ACK |
non | 0:07d02a20d1cc | 68 | if (buf[0] == 0xaa && buf[1] == 0x0e |
non | 0:07d02a20d1cc | 69 | && buf[2] == cmd[1] |
non | 0:07d02a20d1cc | 70 | /* ignore fourth byte */ |
non | 0:07d02a20d1cc | 71 | && buf[4] == 0 && buf[5] == 0) |
non | 0:07d02a20d1cc | 72 | return 1; |
non | 0:07d02a20d1cc | 73 | |
non | 0:07d02a20d1cc | 74 | return 0; |
non | 0:07d02a20d1cc | 75 | } |
non | 0:07d02a20d1cc | 76 | |
non | 0:07d02a20d1cc | 77 | // Initialize communcation to uCam |
non | 0:07d02a20d1cc | 78 | int uCam::Init() { |
non | 0:07d02a20d1cc | 79 | int i; |
non | 0:07d02a20d1cc | 80 | unsigned char buf[12]; |
non | 0:07d02a20d1cc | 81 | |
non | 0:07d02a20d1cc | 82 | for (i=0; i<60; i ++) { |
non | 0:07d02a20d1cc | 83 | // Send SYNC and check the answer |
non | 0:07d02a20d1cc | 84 | write(SYNC, sizeof(SYNC)); |
non | 0:07d02a20d1cc | 85 | if (readT(buf, sizeof(buf)) == 12 && checkACK(buf)) { |
non | 0:07d02a20d1cc | 86 | break; |
non | 0:07d02a20d1cc | 87 | } |
non | 0:07d02a20d1cc | 88 | } |
non | 0:07d02a20d1cc | 89 | if (i == 60) // Too many retries |
non | 0:07d02a20d1cc | 90 | return 0; |
non | 0:07d02a20d1cc | 91 | |
non | 0:07d02a20d1cc | 92 | // Check SYNC |
non | 0:07d02a20d1cc | 93 | if (!checkSYNC(buf+6)) { |
non | 0:07d02a20d1cc | 94 | return 0; |
non | 0:07d02a20d1cc | 95 | } |
non | 0:07d02a20d1cc | 96 | write(ACK, sizeof(ACK)); |
non | 0:07d02a20d1cc | 97 | return 1; |
non | 0:07d02a20d1cc | 98 | } |
non | 0:07d02a20d1cc | 99 | |
non | 0:07d02a20d1cc | 100 | // Set light frequencey (50Hz or 60Hz) to reduce flicker. |
non | 0:07d02a20d1cc | 101 | int uCam::LightFreq(int f) { |
non | 0:07d02a20d1cc | 102 | unsigned char LIGHT[] = {0xaa, 0x13, 0, 0, 0, 0}; |
non | 0:07d02a20d1cc | 103 | |
non | 0:07d02a20d1cc | 104 | if (f == 50) |
non | 0:07d02a20d1cc | 105 | LIGHT[2] = 0x0; |
non | 0:07d02a20d1cc | 106 | else if (f == 60) |
non | 0:07d02a20d1cc | 107 | LIGHT[2] = 0x1; |
non | 0:07d02a20d1cc | 108 | else |
non | 0:07d02a20d1cc | 109 | return 0; |
non | 0:07d02a20d1cc | 110 | |
non | 0:07d02a20d1cc | 111 | return Command(LIGHT); |
non | 0:07d02a20d1cc | 112 | } |
non | 0:07d02a20d1cc | 113 | |
non | 0:07d02a20d1cc | 114 | // Recive data from serial. It blocks until it recieves len bytes. |
non | 0:07d02a20d1cc | 115 | // buf: recieving buffer |
non | 0:07d02a20d1cc | 116 | // len: length to recieve |
non | 0:07d02a20d1cc | 117 | void uCam::read(unsigned char *p, int len) { |
non | 0:07d02a20d1cc | 118 | for (; len>0; len--, p++) { |
non | 0:07d02a20d1cc | 119 | *p = s->getc(); |
non | 0:07d02a20d1cc | 120 | } |
non | 0:07d02a20d1cc | 121 | } |
non | 0:07d02a20d1cc | 122 | |
non | 0:07d02a20d1cc | 123 | // Recive data from serial with timeout |
non | 0:07d02a20d1cc | 124 | // buf: recieving buffer |
non | 0:07d02a20d1cc | 125 | // len: length of the buffer |
non | 0:07d02a20d1cc | 126 | int uCam::readT(unsigned char *buf, int len) { |
non | 0:07d02a20d1cc | 127 | int c = 0; |
non | 0:07d02a20d1cc | 128 | unsigned char *q = buf; |
non | 0:07d02a20d1cc | 129 | |
non | 0:07d02a20d1cc | 130 | for (int j=0; j<2000; j ++) { |
non | 0:07d02a20d1cc | 131 | if (s->readable()) { |
non | 0:07d02a20d1cc | 132 | *q = s->getc(); |
non | 0:07d02a20d1cc | 133 | if (c < len) { |
non | 0:07d02a20d1cc | 134 | q ++; |
non | 0:07d02a20d1cc | 135 | c ++; |
non | 0:07d02a20d1cc | 136 | } |
non | 0:07d02a20d1cc | 137 | } |
non | 0:07d02a20d1cc | 138 | wait_us(50); |
non | 0:07d02a20d1cc | 139 | } |
non | 0:07d02a20d1cc | 140 | |
non | 0:07d02a20d1cc | 141 | return c; |
non | 0:07d02a20d1cc | 142 | } |
non | 0:07d02a20d1cc | 143 | |
non | 0:07d02a20d1cc | 144 | // Reset uCam |
non | 0:07d02a20d1cc | 145 | void uCam::Reset() { |
non | 0:07d02a20d1cc | 146 | Command(RESET); |
non | 0:07d02a20d1cc | 147 | } |
non | 0:07d02a20d1cc | 148 | |
non | 0:07d02a20d1cc | 149 | // Recieve a JPEG image packet. You need to call SnapshotJPEGi() before. |
non | 0:07d02a20d1cc | 150 | // no: packet number (starts from 0) |
non | 0:07d02a20d1cc | 151 | // buf: recieving buffer |
non | 0:07d02a20d1cc | 152 | // pksz: packet size to recieve |
non | 0:07d02a20d1cc | 153 | int uCam::SnapshotJPEGd(int no, unsigned char *buf, int pksz) { |
non | 0:07d02a20d1cc | 154 | unsigned char ACK_[] = {0xaa, 0x0e, 0x00, 0, 0, 0}; |
non | 0:07d02a20d1cc | 155 | |
non | 0:07d02a20d1cc | 156 | ACK_[4] = no & 0xff; |
non | 0:07d02a20d1cc | 157 | ACK_[5] = (no >> 8) & 0xff; |
non | 0:07d02a20d1cc | 158 | |
non | 0:07d02a20d1cc | 159 | write(ACK_, sizeof(ACK_)); |
non | 0:07d02a20d1cc | 160 | read(buf, pksz); |
non | 0:07d02a20d1cc | 161 | |
non | 0:07d02a20d1cc | 162 | return 1; |
non | 0:07d02a20d1cc | 163 | } |
non | 0:07d02a20d1cc | 164 | |
non | 0:07d02a20d1cc | 165 | // Prepare to recieve a JPEG image. |
non | 0:07d02a20d1cc | 166 | // Res: resolution of the image (did not work well for 640x480 with uCam-TTL(ov528 version)) |
non | 0:07d02a20d1cc | 167 | // pksz: packet size to recieve |
non | 0:07d02a20d1cc | 168 | int uCam::SnapshotJPEGi(int Res, int pksz) { |
non | 0:07d02a20d1cc | 169 | unsigned char INITIAL[] = {0xaa, 0x01, 0x00, 0x07, 0x01, 0x00}; |
non | 0:07d02a20d1cc | 170 | unsigned char SET_PACKAGESIZE[] = {0xaa, 0x06, 0x08, 0x00, 0x00, 0x00}; |
non | 0:07d02a20d1cc | 171 | unsigned char buf[6]; |
non | 0:07d02a20d1cc | 172 | |
non | 0:07d02a20d1cc | 173 | INITIAL[5] = Res; |
non | 0:07d02a20d1cc | 174 | SET_PACKAGESIZE[3] = pksz & 0xff; |
non | 0:07d02a20d1cc | 175 | SET_PACKAGESIZE[4] = (pksz >> 8) & 0xff; |
non | 0:07d02a20d1cc | 176 | |
non | 0:07d02a20d1cc | 177 | if (!Command(INITIAL)) |
non | 0:07d02a20d1cc | 178 | return 0; |
non | 0:07d02a20d1cc | 179 | if (!Command(SET_PACKAGESIZE)) |
non | 0:07d02a20d1cc | 180 | return 0; |
non | 0:07d02a20d1cc | 181 | if (!Command(SNAPSHOT_JPEG)) |
non | 0:07d02a20d1cc | 182 | return 0; |
non | 0:07d02a20d1cc | 183 | if (!Command(GETPICTURE_SNAPSHOT)) |
non | 0:07d02a20d1cc | 184 | return 0; |
non | 0:07d02a20d1cc | 185 | |
non | 0:07d02a20d1cc | 186 | read(buf, 6); |
non | 0:07d02a20d1cc | 187 | if (!(buf[0] == 0xaa && buf[1] == 0x0a && buf[2] == 0x01)) |
non | 0:07d02a20d1cc | 188 | return 0; |
non | 0:07d02a20d1cc | 189 | |
non | 0:07d02a20d1cc | 190 | return buf[5]<<16 | buf[4]<<8 | buf[3]; // return file size |
non | 0:07d02a20d1cc | 191 | } |
non | 0:07d02a20d1cc | 192 | |
non | 0:07d02a20d1cc | 193 | // Take a raw image. |
non | 0:07d02a20d1cc | 194 | // |
non | 0:07d02a20d1cc | 195 | // Color: color mode (supporte form 8bit gray, RGB232, or RGB565 only) |
non | 0:07d02a20d1cc | 196 | // Res: image resolution |
non | 0:07d02a20d1cc | 197 | // buf: buffer to save the image |
non | 0:07d02a20d1cc | 198 | int uCam::SnapshotRaw(int Color, int Res, unsigned char *buf) { |
non | 0:07d02a20d1cc | 199 | unsigned char INITIAL[] = {0xaa, 0x01, 0x00, 0x00, 0x00, 0x07}; |
non | 0:07d02a20d1cc | 200 | |
non | 0:07d02a20d1cc | 201 | INITIAL[3] = Color; |
non | 0:07d02a20d1cc | 202 | INITIAL[4] = Res; |
non | 0:07d02a20d1cc | 203 | |
non | 0:07d02a20d1cc | 204 | if (!Command(INITIAL)) |
non | 0:07d02a20d1cc | 205 | return 0; |
non | 0:07d02a20d1cc | 206 | if (!Command(SNAPSHOT_RAW)) |
non | 0:07d02a20d1cc | 207 | return 0; |
non | 0:07d02a20d1cc | 208 | if (!Command(GETPICTURE_SNAPSHOT)) |
non | 0:07d02a20d1cc | 209 | return 0; |
non | 0:07d02a20d1cc | 210 | |
non | 0:07d02a20d1cc | 211 | read(buf, 6); |
non | 0:07d02a20d1cc | 212 | if (!(buf[0] == 0xaa && buf[1] == 0x0a && buf[2] == 0x01)) |
non | 0:07d02a20d1cc | 213 | return 0; |
non | 0:07d02a20d1cc | 214 | |
non | 0:07d02a20d1cc | 215 | // lcd.printf("%d\n", buf[3] + buf[4]<<8 + buf[5]<<16); |
non | 0:07d02a20d1cc | 216 | read(buf, buf[5]<<16 | buf[4]<<8 | buf[3] /* 80*60*2*/ ); |
non | 0:07d02a20d1cc | 217 | write(ACK1, sizeof(ACK1)); |
non | 0:07d02a20d1cc | 218 | |
non | 0:07d02a20d1cc | 219 | return 1; |
non | 0:07d02a20d1cc | 220 | } |
non | 0:07d02a20d1cc | 221 | |
non | 0:07d02a20d1cc | 222 | // Take a raw image. This function crops |
non | 0:07d02a20d1cc | 223 | // the image while it is recieving data from uCam |
non | 0:07d02a20d1cc | 224 | // |
non | 0:07d02a20d1cc | 225 | // Color: color mode (supporte form 8bit gray, RGB232, or RGB565 only) |
non | 0:07d02a20d1cc | 226 | // Res: image resolution |
non | 0:07d02a20d1cc | 227 | // x0, y0: top left corner of the cropping area |
non | 0:07d02a20d1cc | 228 | // w, h: width and height of cropping area |
non | 0:07d02a20d1cc | 229 | // buf: buffer to save the image |
non | 0:07d02a20d1cc | 230 | int uCam::SnapshotRawCrop(int Color, int Res, |
non | 0:07d02a20d1cc | 231 | int x0, int y0, int w, int h, |
non | 0:07d02a20d1cc | 232 | unsigned char *buf) { |
non | 0:07d02a20d1cc | 233 | unsigned char INITIAL[] = {0xaa, 0x01, 0x00, 0x00, 0x00, 0x07}; |
non | 0:07d02a20d1cc | 234 | int W = ucam_raw_resolution_w[(Res-1)/2]; |
non | 0:07d02a20d1cc | 235 | int H = ucam_raw_resolution_h[(Res-1)/2]; |
non | 0:07d02a20d1cc | 236 | |
non | 0:07d02a20d1cc | 237 | if (Color == UCAM_COLOR_TYPE_RGB565) { |
non | 0:07d02a20d1cc | 238 | W *= 2; |
non | 0:07d02a20d1cc | 239 | x0 *= 2; |
non | 0:07d02a20d1cc | 240 | w *= 2; |
non | 0:07d02a20d1cc | 241 | } |
non | 0:07d02a20d1cc | 242 | |
non | 0:07d02a20d1cc | 243 | INITIAL[3] = Color; |
non | 0:07d02a20d1cc | 244 | INITIAL[4] = Res; |
non | 0:07d02a20d1cc | 245 | |
non | 0:07d02a20d1cc | 246 | if (!Command(INITIAL)) |
non | 0:07d02a20d1cc | 247 | return 0; |
non | 0:07d02a20d1cc | 248 | if (!Command(SNAPSHOT_RAW)) |
non | 0:07d02a20d1cc | 249 | return 0; |
non | 0:07d02a20d1cc | 250 | if (!Command(GETPICTURE_SNAPSHOT)) |
non | 0:07d02a20d1cc | 251 | return 0; |
non | 0:07d02a20d1cc | 252 | |
non | 0:07d02a20d1cc | 253 | read(buf, 6); |
non | 0:07d02a20d1cc | 254 | if (!(buf[0] == 0xaa && buf[1] == 0x0a && buf[2] == 0x01)) |
non | 0:07d02a20d1cc | 255 | return 0; |
non | 0:07d02a20d1cc | 256 | |
non | 0:07d02a20d1cc | 257 | for (int i=y0*W; i>0; i--) /* Skip */ |
non | 0:07d02a20d1cc | 258 | s->getc(); |
non | 0:07d02a20d1cc | 259 | |
non | 0:07d02a20d1cc | 260 | for (int i=h; i>0; i--) { |
non | 0:07d02a20d1cc | 261 | for (int j=x0; j>0; j--) /* Skip */ |
non | 0:07d02a20d1cc | 262 | s->getc(); |
non | 0:07d02a20d1cc | 263 | read(buf, w); |
non | 0:07d02a20d1cc | 264 | buf += w; |
non | 0:07d02a20d1cc | 265 | for (int j=W-w-x0; j>0; j--) /* Skip */ |
non | 0:07d02a20d1cc | 266 | s->getc(); |
non | 0:07d02a20d1cc | 267 | } |
non | 0:07d02a20d1cc | 268 | for (int i=(H-y0-h)*W; i>0; i--) /* Skip */ |
non | 0:07d02a20d1cc | 269 | s->getc(); |
non | 0:07d02a20d1cc | 270 | write(ACK1, sizeof(ACK1)); |
non | 0:07d02a20d1cc | 271 | |
non | 0:07d02a20d1cc | 272 | return 1; |
non | 0:07d02a20d1cc | 273 | } |
non | 0:07d02a20d1cc | 274 | |
non | 0:07d02a20d1cc | 275 | // Write <len> characters from p to the serial |
non | 0:07d02a20d1cc | 276 | void uCam::write(const unsigned char *p, int len) { |
non | 0:07d02a20d1cc | 277 | for (; len>0; len--, p++) { |
non | 0:07d02a20d1cc | 278 | s->putc(*p); |
non | 0:07d02a20d1cc | 279 | } |
non | 0:07d02a20d1cc | 280 | } |