Dependencies:   mbed

Revision:
0:796c01948235
--- /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