Dependencies:   mbed

ucam.cpp

Committer:
mux
Date:
2011-12-09
Revision:
0:796c01948235

File content as of revision 0:796c01948235:

#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;
}