Diff: ucam.cpp
- Revision:
- 0:796c01948235
diff -r 000000000000 -r 796c01948235 ucam.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ucam.cpp Fri Dec 09 05:32:12 2011 +0000
@@ -0,0 +1,365 @@
+#include "ucam.h"
+/*commands*/
+#define CMD_ACK 0x0E
+#define CMD_SYNC 0x0D
+#define CMD_INITIAL 0x01
+#define CMD_SNAPSHOT 0x05
+#define CMD_PICTURE 0x04
+#define CMD_DATA 0x0A
+#define CMD_BAUDRATE 0x07
+#define MAX_SYNC 60
+#define PACKET_LENGTH 506
+#define BUFFER_SIZE 8129
+#define DEBUG_WARN 0x01
+#define DEBUG_INFO 0x02
+#define DEBUG_COMS 0x04
+#define DEBUG_LEVEL 0xff
+
+#if DEBUG_LEVEL
+ extern Serial debug;
+#endif
+
+struct ucam_command{
+ union{
+ struct{
+ uint8_t buf[6];
+ };
+ struct{
+ uint8_t pre;
+ uint8_t id;
+ uint8_t p1;
+ uint8_t p2;
+ uint8_t p3;
+ uint8_t p4;
+ };
+ };
+};
+
+struct{
+ uint16_t ss;
+ uint16_t se;
+ uint8_t sz[BUFFER_SIZE];
+}fbuf;
+
+uint8_t pbuf[PACKET_LENGTH * 2];
+
+inline void buf_put_char(uint8_t ch)
+{
+ register uint16_t se = fbuf.se;
+ register uint16_t idx = (se + 1) % BUFFER_SIZE;
+
+ if (idx != fbuf.ss) {
+ fbuf.sz[se] = ch;
+ fbuf.se = idx;
+ }
+
+ ///*buffer is full*/
+ //#if (DEBUG_LEVEL & DEBUG_WARN)
+ // debug.printf("warning buffer full\n");
+ //#endif
+}
+
+uint8_t buf_get_char()
+{
+ uint16_t ch = fbuf.ss % BUFFER_SIZE;
+
+ while( ch == fbuf.se){
+ /*buffer is empty*/
+ wait_ms(1);
+ }
+
+ ch = fbuf.sz[fbuf.ss];
+ fbuf.ss = (fbuf.ss + 1) % BUFFER_SIZE;
+ return ch;
+}
+
+UCam::UCam(PinName tx_pin, PinName rx_pin, PinName led_pin, uint32_t baudrate):
+led(led_pin)
+{
+ ucam = new Serial(p13, p14);
+ ucam->baud(115200);
+ ucam->attach(this, &UCam::uart_isr);
+ fbuf.ss = 0;
+ fbuf.se = 0;
+}
+
+uint16_t buf_size()
+{
+ return fbuf.se - fbuf.ss;
+}
+
+UCam::~UCam()
+{
+ led = 0;
+ delete ucam;
+}
+
+void UCam::uart_isr(void)
+{
+ register uint16_t i;
+ register uint16_t size = 0;
+ register uint8_t *buf = pbuf;
+
+ do{
+ buf[size++] = ucam->getc();
+ }while (ucam->readable());
+
+ for (i=0; i<size; i++)
+ buf_put_char(buf[i]);
+}
+
+int8_t UCam::connect()
+{
+ struct ucam_command cmd;
+
+ /*reset state machine*/
+ //send_cmd(0x08, 0x01, 0x00, 0x00, 0x00);
+ //wait(1.0);
+
+ /*full reset*/
+ // send_cmd(0x08, 0x00, 0x00, 0x00, 0xff);
+ // wait(1.0);
+
+ int8_t state=0;
+#if (DEBUG_LEVEL & DEBUG_INFO)
+ debug.puts("syncing...\n");
+#endif
+
+ for (int i = 0; i < MAX_SYNC; i++) {
+ switch(state){
+ case 0: /*sync and recv ACK*/
+ if (send_cmd(CMD_SYNC) == 0)
+ ++state;
+ break;
+
+ case 1:/*recv SYNC*/
+ if (recv_cmd(&cmd) == 0 && cmd.id == CMD_SYNC)
+ ++state;
+ break;
+
+ case 2:/*send ACK SYNC*/
+ if (send_cmd(CMD_ACK, CMD_SYNC, 0x00, 0x00, 0x00, 0x01) == 0)
+ ++state;
+ break;
+
+ case 3:
+ led = 1;
+ send_cmd(CMD_BAUDRATE, 0x00, 0x04, 0x00, 0x00);
+ ucam->baud(737280);
+ return 0;
+ }
+ wait(0.100);
+ }
+
+ return -1;
+}
+
+int8_t UCam::send_cmd(uint8_t id, uint8_t p1, uint8_t p2, uint8_t p3, uint8_t p4, uint8_t noack)
+{
+ struct ucam_command cmd;
+
+ ucam->putc(0xAA);
+ ucam->putc(id);
+ ucam->putc(p1);
+ ucam->putc(p2);
+ ucam->putc(p3);
+ ucam->putc(p4);
+
+#if (DEBUG_LEVEL & DEBUG_COMS)
+ debug.printf("> aa %02x %02x %02x %02x %02x\n",
+ id, p1, p2, p3, p4);
+#endif/*enable_debug*/
+
+ if (noack)
+ return 0;
+
+ /*recv ACK*/
+ if (recv_cmd(&cmd) == 0 && cmd.id == CMD_ACK && cmd.p1 == id)
+ return 0;
+
+ return -1;
+}
+
+int8_t UCam::recv_cmd(struct ucam_command *cmd)
+{
+ for (int8_t i = 0; i < sizeof(struct ucam_command); i++) {
+ cmd->buf[i] = buf_get_char();
+ }
+
+#if (DEBUG_LEVEL & DEBUG_COMS)
+ debug.printf("< %02x %02x %02x %02x %02x %02x\n",
+ cmd->pre, cmd->id, cmd->p1,
+ cmd->p2, cmd->p3, cmd->p4);
+#endif/*enable_debug*/
+
+ if (cmd->pre != 0xAA)
+ goto error;
+
+ return 0;
+error:
+ return -1;
+}
+
+int8_t UCam::snapshot(uint8_t *buf, uint16_t *len, uint8_t color_space, uint8_t raw_size, uint8_t jpeg_size)
+{
+ struct ucam_command cmd;
+
+ if (send_cmd(CMD_INITIAL, 0x00, color_space, raw_size, jpeg_size) != 0)
+ return -1;
+
+ if (send_cmd(0x06, 0x08, 0x00, 0x02, 0x00) != 0) //set packet size to 512
+ return -2;
+
+ if (send_cmd(CMD_SNAPSHOT, 0x00, 0x00, 0x00, 0x00) != 0)
+ return -3;
+
+ if (send_cmd(CMD_PICTURE, 0x01, 0x00, 0x00, 0x00) != 0)
+ return -4;
+
+ if (recv_cmd(&cmd) != 0 || cmd.id != CMD_DATA)
+ return -5;
+
+ uint8_t id = 0;
+ uint8_t byte;
+ uint8_t blocks;
+
+ uint32_t size = 0, i = 0;
+
+ size = (size | cmd.p4) << 16;
+ size = (size | cmd.p3) << 8;
+ size = (size | cmd.p2);
+
+ blocks = size / PACKET_LENGTH;
+ if (size % PACKET_LENGTH)
+ ++blocks;
+
+#if (DEBUG_LEVEL & DEBUG_INFO)
+ debug.printf("image %d %d\n", size, blocks);
+#endif/*enable_debug*/
+
+ *len = size;
+ while (blocks--) {
+ if (send_cmd(CMD_ACK, 0x00, 0x00, id++, 0x00, true) != 0)
+ return -6;
+
+ buf_get_char(); //id lsb
+ buf_get_char(); //id msb
+
+ size=0;
+ byte = buf_get_char(); //size lsb
+ size |= buf_get_char(); //size msb
+ size = (size << 8) | byte;
+
+ if (size == 0 || size > PACKET_LENGTH)
+ return -7;
+
+ for (i = 0; i<size; i++) {
+ *buf++ = buf_get_char();
+ }
+ buf_get_char(); //checksum lsb
+ buf_get_char(); //checksum msb
+ }
+
+ /*ack frame*/
+ send_cmd(CMD_ACK, 0x00, 0x00, 0xF0, 0xF0, 0x01);
+ return 0;
+}
+
+int8_t UCam::start_video(uint8_t color_space, uint8_t raw_size, uint8_t jpeg_size)
+{
+ if (send_cmd(CMD_INITIAL, 0x00, color_space, raw_size, jpeg_size) != 0)
+ return -1;
+
+ if (send_cmd(0x06, 0x08, 0x00, 0x02, 0x00) != 0) //set packet size to 512
+ return -2;
+
+ return 0;
+}
+
+int8_t UCam::next_frame(uint8_t *buf, uint16_t *len)
+{
+ uint8_t id = 0;
+ uint8_t byte;
+ uint8_t blocks;
+ uint32_t size = 0, i = 0;
+
+ struct ucam_command cmd;
+
+ wait_ms(10); /* don't know why*/
+
+ if (send_cmd(CMD_PICTURE, 0x05, 0x00, 0x00, 0x00) != 0)
+ goto error;
+
+ if (recv_cmd(&cmd) != 0 || cmd.id != CMD_DATA)
+ goto error;
+
+
+ size = (size | cmd.p4) << 16;
+ size = (size | cmd.p3) << 8;
+ size = (size | cmd.p2);
+
+ blocks = size / PACKET_LENGTH;
+ if (size % PACKET_LENGTH)
+ ++blocks;
+
+ #if (DEBUG_LEVEL & DEBUG_WARN)
+ debug.printf("image %d %d\n", size, blocks);
+ #endif/*enable_debug*/
+
+ *len = size;
+ while (blocks--) {
+ if (send_cmd(CMD_ACK, 0x00, 0x00, id++, 0x00, true) != 0)
+ goto error;
+
+ size = 0;
+ byte = buf_get_char(); //id lsb
+ size |= buf_get_char(); //id msb
+ size = (size << 8) | byte;
+
+ #if (DEBUG_LEVEL & DEBUG_INFO)
+ debug.printf("block id %d ", size);
+ #endif
+
+ size=0;
+ byte = buf_get_char(); //size lsb
+ size |= buf_get_char(); //size msb
+ size = (size << 8) | byte;
+
+ #if (DEBUG_LEVEL & DEBUG_INFO)
+ debug.printf("block size %d\n", size);
+ #endif
+
+ if (size > PACKET_LENGTH || size > buf_size()) {
+ #if (DEBUG_LEVEL & DEBUG_INFO)
+ debug.printf("warning: invalid size %d\n", size);
+ #endif
+ goto error;
+ }
+
+ if (blocks == 0 && size == PACKET_LENGTH) { /*ucam bug*/
+ #if (DEBUG_LEVEL & DEBUG_WARN)
+ debug.printf("warning: soft reset\n");
+ #endif
+ /*soft reset*/
+ wait(1.0);
+ send_cmd(0x08, 0x01, 0x00, 0x00, 0xFF);
+
+ /*ack frame*/
+ send_cmd(CMD_ACK, 0x00, 0x00, 0xF0, 0xF0, 0x01);
+ goto error;
+ }
+
+ for (i = 0; i<size; i++) {
+ *buf++ = buf_get_char();
+ }
+
+ buf_get_char(); //checksum lsb
+ buf_get_char(); //checksum msb
+ }
+
+ /*ack frame*/
+ send_cmd(CMD_ACK, 0x00, 0x00, 0xF0, 0xF0, 0x01);
+ return 0;
+error:
+ return -1;
+}
\ No newline at end of file