fork of Camera_LS_Y201 lib supporting the 2MP variant/successor

Fork of Camera_LS_Y201 by Shinichiro Nakamura

Camera_LS_Y201.cpp

Committer:
humlet
Date:
2014-03-18
Revision:
2:ce4d1351bdeb
Parent:
1:43358d40f879

File content as of revision 2:ce4d1351bdeb:

/**
 * =============================================================================
 * LS-Y201 device driver class (Version 0.0.1)
 * Reference documents: LinkSprite JPEG Color Camera Serial UART Interface
 *                      January 2010
 * =============================================================================
 * Copyright (c) 2010 Shinichiro Nakamura (CuBeatSystems)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 * =============================================================================
 */

#include "Camera_LS_Y201.h"

#define TMOUT 2000

/**
 * Create.
 *
 * @param tx Transmitter.
 * @param rx Receiver.
 */
Camera_LS_Y201::Camera_LS_Y201(PinName tx, PinName rx) : serial(tx, rx)
{
    serial.baud(115200);
}

/**
 * Dispose.
 */
Camera_LS_Y201::~Camera_LS_Y201()
{
}

/**
 * Reset module.
 *
 * @return Error code.
 */
Camera_LS_Y201::ErrorCode Camera_LS_Y201::reset()
{
    uint8_t send[4] = {
        0x56,
        0x00,
        0x26,
        0x00
    };
    //uint8_t recv[50];

    const int nBauds = 5;
    const int bauds[nBauds] = {38400,57600,115200,128000,256000};
    for(int i=0; i<nBauds; ++i) {
        printf("Reset @ %d baud: ",bauds[i]);
        serial.baud(bauds[i]);
        waitIdle();
        if (!sendBytes(send, sizeof(send), 200 * TMOUT)) {
            printf("TxKO\n");
            continue;
        } else {
            printf("TxOK ");
        }
        
        //serial.baud(115200);
        
        ErrorCode r = waitInitEnd();
        if (r != NoError) {
            printf("RxKO\n");
            continue;
        } else {
            printf("RxOK ...4s...\n");
            wait(4);
            return NoError;
        }
    }
    return UnexpectedReply;
    /*
    if (!recvBytes(recv, sizeof(recv), 200 * TMOUT)) {
        return RecvError;
    }
    if ((recv[0] == 0x76)
            && (recv[1] == 0x00)
            && (recv[2] == 0x26)
            && (recv[3] == 0x00)) {
        ErrorCode r = waitInitEnd();
        if (r != NoError) {
            return r;
        }
        wait(4);
        return NoError;
    } else {
        printf("%X %X %X %X\n",recv[0],recv[1],recv[2],recv[3]);
        return UnexpectedReply;
    }
    */
}

/**
 * Set image size.
 *
 * @param is Image size.
 * @return Error code.
 */
Camera_LS_Y201::ErrorCode Camera_LS_Y201::setImageSize(ImageSize is)
{
    uint8_t send[5] = {
        0x56,
        0x00,
        0x54,
        0x01,
        0x00    // 0x11:320x240, 0x00:640x480, 0x22:160x120
    };
    uint8_t recv[5];
    switch (is) {
        case ImageSize160x120:
            send[4] = 0x22;
            break;
        case ImageSize320x240:
            send[4] = 0x11;
            break;
        case ImageSize640x480:
            send[4] = 0x00;
            break;
        case ImageSize800x600:
            send[4] = 0x1d;
            break;
        case ImageSize1024x768:
            send[4] = 0x1c;
            break;
        case ImageSize1280x960:
            send[4] = 0x1b;
            break;
        case ImageSize1600x1200:
            send[4] = 0x21;
            break;
        default:
            return InvalidArguments;
    }
    if (!sendBytes(send, sizeof(send), 200 * TMOUT)) {
        return SendError;
    }
    if (!recvBytes(recv, sizeof(recv), 200 * TMOUT)) {
        return RecvError;
    }
    if ((recv[0] == 0x76)
            && (recv[1] == 0x00)
            && (recv[2] == 0x54)
            && (recv[3] == 0x00)
            && (recv[4] == 0x00)) {
        wait(1);
        //return reset();
        return NoError;
    } else {
        return UnexpectedReply;
    }
}



Camera_LS_Y201::ErrorCode Camera_LS_Y201::setCompressionRatio(int cr)
{
    uint8_t send[9] = {
        0x56,
        0x00,
        0x31,
        0x05,
        0x01,
        0x01,
        0x12,
        0x04,
        cr
    };
    uint8_t recv[5];

    //printf("Setting Img-Qual to %d\n", cr);

    if (!sendBytes(send, sizeof(send), 200 * TMOUT)) {
        return SendError;
    }
    if (!recvBytes(recv, sizeof(recv), 200 * TMOUT)) {
        return RecvError;
    }
    if ((recv[0] == 0x76)
            && (recv[1] == 0x00)
            && (recv[2] == 0x31)
            && (recv[3] == 0x00)
            && (recv[4] == 0x00)) {
        wait(1);
        //return reset();
        return NoError;
    } else {
        return UnexpectedReply;
    }
}

Camera_LS_Y201::ErrorCode Camera_LS_Y201::setBaudRate(Camera_LS_Y201::BaudRate br)
{
    uint8_t send[6] = {
        0x56,
        0x00,
        0x24,
        0x03,
        0x01,
        br
    };
    uint8_t recv[5];

    if (!sendBytes(send, sizeof(send), 200 * TMOUT)) {
        return SendError;
    }



    if (!recvBytes(recv, sizeof(recv), 200 * TMOUT)) {
        return RecvError;
    }
    if ((recv[0] == 0x76)
            && (recv[1] == 0x00)
            && (recv[2] == 0x24)
            && (recv[3] == 0x00)
            && (recv[4] == 0x00)) {
        wait(1);
        //return reset();
        switch(br) {
                /*case BaudRate9600:
                    serial.baud(9600);
                    break;*/
            case BaudRate38400:
                serial.baud(38400);
                break;
            case BaudRate57600:
                serial.baud(57600);
                break;
            case BaudRate115200:
                serial.baud(115200);
                break;
            case BaudRate128000:
                serial.baud(128000);
                break;
            case BaudRate256000:
                serial.baud(256000);
                break;
            default:
                return InvalidArguments;
        }
        return NoError;
    } else {
        return UnexpectedReply;
    }
}




/**
 * Take picture.
 *
 * @return Error code.
 */
Camera_LS_Y201::ErrorCode Camera_LS_Y201::takePicture()
{
    uint8_t send[5] = {
        0x56,
        0x00,
        0x36,
        0x01,
        0x00
    };
    uint8_t recv[5];

    if (!sendBytes(send, sizeof(send), 200 * TMOUT)) {
        return SendError;
    }
    if (!recvBytes(recv, sizeof(recv), 2000 * TMOUT)) {
        return RecvError;
    }

    if ((recv[0] == 0x76)
            && (recv[1] == 0x00)
            && (recv[2] == 0x36)
            && (recv[3] == 0x00)
            && (recv[4] == 0x00)) {
        /*
         * I think the camera need a time for operating.
         * But there is no any comments on the documents.
         */
        wait_ms(100);
        return NoError;
    } else {
        return UnexpectedReply;
    }
}

/**
 * Read jpeg file size.
 *
 * @param fileSize File size.
 * @return Error code.
 */
Camera_LS_Y201::ErrorCode Camera_LS_Y201::readJpegFileSize(int *fileSize)
{
    uint8_t send[5] = {
        0x56,
        0x00,
        0x34,
        0x01,
        0x00
    };
    uint8_t recv[9];

    if (!sendBytes(send, sizeof(send), 2000 * TMOUT)) {
        return SendError;
    }
    if (!recvBytes(recv, sizeof(recv), 2000 * TMOUT)) {
        return RecvError;
    }

    if ((recv[0] == 0x76)
            && (recv[1] == 0x00)
            && (recv[2] == 0x34)
            && (recv[3] == 0x00)
            && (recv[4] == 0x04)
            && (recv[5] == 0x00)
            /*&& (recv[6] == 0x00)*/) {
        *fileSize =     ((recv[6] & 0x00ff) << 16)
                        |   ((recv[7] & 0x00ff) << 8)
                        |   ((recv[8] & 0x00ff) << 0);
        return NoError;
    } else {
        return UnexpectedReply;
    }
}

/**
 * Read jpeg file content.
 *
 * @param func A pointer to a call back function.
 * @return Error code.
 */
Camera_LS_Y201::ErrorCode Camera_LS_Y201::readJpegFileContent(void (*func)(int done, int total, uint8_t *buf, size_t siz))
{
    uint8_t send[16] = {
        0x56,
        0x00,
        0x32,
        0x0C,
        0x00,
        0x0A,
        0x00,
        0x00, // 7 mhh
        0x00, // 8 MH
        0x00, // 9 ML
        0x00,
        0x00, // 11 khh
        0x00, // 12 KH
        0x00, // 13 KL
        0x00, // XX
        0x00  // XX
    };
    uint8_t body[256];
    uint32_t m = 0; // Staring address.
    uint32_t k = sizeof(body); // Packet size.
    uint16_t x = 10;    // Interval time. XX XX * 0.01m[sec]
    bool end = false;

    /*
     * Get the data size.
     */
    int siz_done = 0;
    int siz_total = 0;
    ErrorCode r = readJpegFileSize(&siz_total);
    if (r != NoError) {
        printf("ouch01\n");
        return r;
    }

    printf("Going to read %d bytes\n", siz_total);

    do {
        send[7] = (m >> 16) & 0xff;
        send[8] = (m >> 8) & 0xff;
        send[9] = (m >> 0) & 0xff;
        send[11] = (k >> 16) & 0xff;
        send[12] = (k >> 8) & 0xff;
        send[13] = (k >> 0) & 0xff;
        send[14] = (x >> 8) & 0xff;
        send[15] = (x >> 0) & 0xff;
        /*
         * Send a command.
         */
        if (!sendBytes(send, sizeof(send), 200 * TMOUT)) {
            printf("ouch02\n");
            return SendError;
        }
        /*
         * Read the header of the response.
         */
        uint8_t header[5];
        if (!recvBytes(header, sizeof(header), 2 * 1000 * TMOUT)) {
            printf("ouch03\n");
            return RecvError;
        }
        /*
         * Check the response and fetch an image data.
         */
        if ((header[0] == 0x76)
                && (header[1] == 0x00)
                && (header[2] == 0x32)
                && (header[3] == 0x00)
                && (header[4] == 0x00)) {
            if (!recvBytes(body, sizeof(body), 2 * 1000 * TMOUT)) {
                printf("ouch04\n");
                return RecvError;
            }
            siz_done += sizeof(body);
            if (func != NULL) {
                if (siz_done > siz_total) {
                    siz_done = siz_total;
                }
                func(siz_done, siz_total, body, sizeof(body));
            }
            for (int i = 1; i < sizeof(body); i++) {
                if ((body[i - 1] == 0xFF) && (body[i - 0] == 0xD9)) {
                    end = true;
                }
            }
        } else {
            printf("ouch05\n");
            return UnexpectedReply;
        }
        /*
         * Read the footer of the response.
         */
        uint8_t footer[5];
        if (!recvBytes(footer, sizeof(footer), 2 * 1000 * TMOUT)) {
            return RecvError;
        }

        m += sizeof(body);
    } while (!end);
    return NoError;
}

/**
 * Stop taking pictures.
 *
 * @return Error code.
 */
Camera_LS_Y201::ErrorCode Camera_LS_Y201::stopTakingPictures()
{
    uint8_t send[5] = {
        0x56,
        0x00,
        0x36,
        0x01,
        0x03
    };
    uint8_t recv[5];

    if (!sendBytes(send, sizeof(send), 200 * TMOUT)) {
        return SendError;
    }
    if (!recvBytes(recv, sizeof(recv), 200 * TMOUT)) {
        return RecvError;
    }

    if ((recv[0] == 0x76)
            && (recv[1] == 0x00)
            && (recv[2] == 0x36)
            && (recv[3] == 0x00)
            && (recv[4] == 0x00)) {
        /*
         * I think the camera need a time for operating.
         * But there is no any comments on the documents.
         */
        wait_ms(100);
        return NoError;
    } else {
        return UnexpectedReply;
    }
}

/**
 * Wait init end codes.
 *
 * @return True if the data sended.
 */
Camera_LS_Y201::ErrorCode Camera_LS_Y201::waitInitEnd()
{
    static const char *PWR_ON_MSG = "Init end\x0d\x0a";
    for (int i = 0; i < strlen(PWR_ON_MSG); i++) {
        static const int MAXCNT = 128;
        int cnt = 0;
        uint8_t c = 0x00;
        do {
            if (!recvBytes(&c, sizeof(c), 200 * TMOUT)) {
                return Timeout;
            }

            /*
             * What is the version of the camera.
             * You can check the version with this code.
             *
             * VC0703 1.00
             * 3o ctrl in
             * Init end
             */
#if 0
            printf("%c", c);
#endif

            cnt++;
            if (MAXCNT < cnt) {
                return UnexpectedReply;
            }
        } while (c != PWR_ON_MSG[i]);
    }
    return NoError;
}

/**
 * Send bytes to camera module.
 *
 * @param buf Pointer to the data buffer.
 * @param len Length of the data buffer.
 *
 * @return True if the data sended.
 */
bool Camera_LS_Y201::sendBytes(uint8_t *buf, size_t len, int timeout_us)
{
    for (uint32_t i = 0; i < (uint32_t)len; i++) {
        int cnt = 0;
        while (!serial.writeable()) {
            wait_us(1);
            cnt++;
            if (timeout_us < cnt) {
                return false;
            }
        }
        serial.putc(buf[i]);
    }
    return true;
}

/**
 * Receive bytes from camera module.
 *
 * @param buf Pointer to the data buffer.
 * @param len Length of the data buffer.
 *
 * @return True if the data received.
 */
bool Camera_LS_Y201::recvBytes(uint8_t *buf, size_t len, int timeout_us)
{
    for (uint32_t i = 0; i < (uint32_t)len; i++) {
        int cnt = 0;
        while (!serial.readable()) {
            wait_us(1);
            cnt++;
            if (timeout_us < cnt) {
                return false;
            }
        }
        buf[i] = serial.getc();
    }
    return true;
}

/**
 * Wait received.
 *
 * @return True if the data received.
 */
bool Camera_LS_Y201::waitRecv()
{
    while (!serial.readable()) {
    }
    return true;
}

/**
 * Wait idle state.
 */
bool Camera_LS_Y201::waitIdle()
{
    while (serial.readable()) {
        serial.getc();
    }
    return true;
}