summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--camera.c410
1 files changed, 274 insertions, 136 deletions
diff --git a/camera.c b/camera.c
index 0368fdf..3260660 100644
--- a/camera.c
+++ b/camera.c
@@ -1,81 +1,162 @@
#include "camera.h"
#include "legato.h"
+#include <termios.h>
COMPONENT_INIT { }
-// File descriptor is returned in the fd pointer
-le_result_t fd_openCam (int *fd) {
- *fd = le_tty_Open(TTY_PATH, O_RDWR | O_NOCTTY | O_NDELAY);
- le_result_t baudRes = le_tty_SetBaudRate(*fd, LE_TTY_SPEED_38400);
- le_result_t rawRes = le_tty_SetRaw(*fd, CAM_BUFF_SIZE, TTY_TIMEOUT);
- return baudRes == LE_OK && rawRes == LE_OK ? LE_OK : LE_FAULT;
-}
-
-void fd_closeCam (int fd) {
- le_tty_Close(fd);
-}
-
-le_result_t fd_resetCamTty (int *fd) {
- fd_closeCam(*fd);
- return fd_openCam(fd);
-}
-
+/**
+ * Convert an integer baud rate to a speed_t
+ */
+speed_t fd_convertBaud (int baud) {
+ speed_t b;
+ switch (baud) {
+ case 50: b = B50; break;
+ case 75: b = B75; break;
+ case 110: b = B110; break;
+ case 134: b = B134; break;
+ case 150: b = B150; break;
+ case 200: b = B200; break;
+ case 300: b = B300; break;
+ case 600: b = B600; break;
+ case 1200: b = B1200; break;
+ case 1800: b = B1800; break;
+ case 2400: b = B2400; break;
+ case 9600: b = B9600; break;
+ case 19200: b = B19200; break;
+ case 38400: b = B38400; break;
+ case 57600: b = B57600; break;
+ case 115200: b = B115200; break;
+ case 230400: b = B230400; break;
+ default:
+ b = -2;
+ }
+ return b;
+}
+
+/**
+ * Open a serial connection on device
+ *
+ * Lifted from here
+ * https://github.com/WiringPi/WiringPi/blob/master/wiringPi/wiringSerial.c
+ */
+int fd_openSerial (const char *device, int baud) {
+ struct termios options;
+ speed_t binaryBaud = fd_convertBaud(baud);
+ int status, fd;
+ if ((fd = open(device, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK)) == -1)
+ return -1 ;
+ fcntl(fd, F_SETFL, O_RDWR);
+ tcgetattr(fd, &options);
+ cfmakeraw(&options);
+ cfsetispeed(&options, binaryBaud);
+ cfsetospeed(&options, binaryBaud);
+
+ options.c_cflag |= (CLOCAL | CREAD);
+ options.c_cflag &= ~PARENB;
+ options.c_cflag &= ~CSTOPB;
+ options.c_cflag &= ~CSIZE;
+ options.c_cflag |= CS8;
+ options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
+ options.c_oflag &= ~OPOST;
+
+ options.c_cc[VMIN] = 0;
+ options.c_cc[VTIME] = 100; // Ten seconds (100 deciseconds)
+
+ tcsetattr(fd, TCSANOW | TCSAFLUSH, &options);
+
+ ioctl(fd, TIOCMGET, &status);
+
+ status |= TIOCM_DTR;
+ status |= TIOCM_RTS;
+
+ ioctl(fd, TIOCMSET, &status);
+ usleep(10000); // 10mS
+ return fd;
+}
+
+/**
+ * Open a serial connection to the camera
+ */
+int fd_openCam () {
+ return fd_openSerial(TTY_PATH, CAM_BAUD_RATE);
+}
+
+/**
+ * Close the serial connection to the camera
+ */
+int fd_closeCam (int fd) {
+ return close(fd);
+}
+
+/**
+ * Read a byte from fd into data
+ */
ssize_t fd_getByte (int fd, uint8_t *data) {
return read(fd, data, 1);
}
+/**
+ * Check how many bytes are available
+ * on the serial connection described by fd
+ */
int fd_dataAvail (int fd, int *data) {
return ioctl(fd, FIONREAD, data);
}
-void sendCommand (Camera *cam, uint8_t cmd, uint8_t args[], uint8_t nArgs) {
- // TODO figure out the longest possible command
- // as I doubt it's anywhere near 100
- //
- // The other (and probably better option) here would
- // be to call malloc
- uint8_t toWrite[100] = { VC0706_PREFIX, cam->serialNum, cmd };
+/**
+ * Send a command sequence to cam
+ * Should not be called directly (use cam_runCommand)
+ */
+void cam_sendCommand (Camera *cam, uint8_t cmd, uint8_t args[], uint8_t nArgs) {
int start = 3;
int end = nArgs + start;
+ uint8_t *toWrite = malloc(end);
+ *toWrite = VC0706_PREFIX;
+ *(toWrite + 1) = cam->serialNum;
+ *(toWrite + 2) = cmd;
for (int i = start; i < end; i++) {
- toWrite[i] = args[i - start];
+ *(toWrite + i) = args[i - start];
};
- for (int i = 0; i < end; i++) {
- LE_DEBUG("toSend[%d]=0x%x", i, toWrite[i]);
- }
- write(cam->fd, &toWrite[0], end);
+ write(cam->fd, toWrite, end);
+ free(toWrite);
}
-bool runCommand (Camera *cam, uint8_t cmd, uint8_t args[], uint8_t nArgs, uint8_t respLen, bool flushFlag) {
+/**
+ * Run a command described by cmd and args on cam
+ */
+bool cam_runCommand (Camera *cam, uint8_t cmd, uint8_t args[], uint8_t nArgs, uint8_t respLen, bool flushFlag) {
if (flushFlag) {
- readResponse(cam, 100, 10);
+ cam_readResponse(cam, 100, 10);
}
- sendCommand(cam, cmd, args, nArgs);
- uint8_t actual = readResponse(cam, respLen, 200);
- LE_DEBUG("Expected: %d, Actual: %d", respLen, actual);
- if (actual != respLen)
+ cam_sendCommand(cam, cmd, args, nArgs);
+ if (cam_readResponse(cam, respLen, 200) != respLen)
return false;
- if (!verifyResponse(cam, cmd))
+ if (!cam_verifyResponse(cam, cmd))
return false;
return true;
}
-bool runCommandFlush (Camera *cam, uint8_t cmd, uint8_t args[], uint8_t nArgs, uint8_t respLen) {
- return runCommand(cam, cmd, args, nArgs, respLen, true);
+/**
+ * Flush buffer before running command
+ */
+bool cam_runCommandFlush (Camera *cam, uint8_t cmd, uint8_t args[], uint8_t nArgs, uint8_t respLen) {
+ return cam_runCommand(cam, cmd, args, nArgs, respLen, true);
}
-// Reads from the camera and returns how many bytes it read
-uint8_t readResponse (Camera *cam, uint8_t nBytes, uint8_t timeout) {
+/**
+ * Read a response from cam
+ */
+uint8_t cam_readResponse (Camera *cam, uint8_t nBytes, uint8_t timeout) {
uint8_t counter = 0;
cam->bufferLen = 0;
int avail = 0;
uint8_t data;
while ((counter < timeout) && (cam->bufferLen < nBytes)) {
- // data is returned in avail pointer
- int availRes = fd_dataAvail(cam->fd, &avail);
+ // available data is returned in avail pointer
+ bool availSuccess = fd_dataAvail(cam->fd, &avail) == 0;
// this case covers no data available
// or when fd_dataAvail fails
- if (avail <= 0 || availRes != 0) {
+ if (avail <= 0 || !availSuccess) {
usleep(1000);
counter++;
continue;
@@ -88,20 +169,12 @@ uint8_t readResponse (Camera *cam, uint8_t nBytes, uint8_t timeout) {
return cam->bufferLen;
}
-void printBuffer (Camera *cam) {
- LE_DEBUG("Printing cam buffer");
- for(int i = 0; i < NUM_ARRAY_MEMBERS(cam->buff); i++) {
- LE_DEBUG("buff[%d]=%x", i, cam->buff[i]);
- }
-}
-
-bool verifyResponse (Camera *cam, uint8_t cmd) {
+/**
+ * Verify that a given response is valid
+ */
+bool cam_verifyResponse (Camera *cam, uint8_t cmd) {
// If any of these are not equal than
// the command failed
- LE_DEBUG("buff[0] correct? %d", cam->buff[0] == VC0706_RESP_PREFIX);
- LE_DEBUG("buff[1] correct? %d", cam->buff[1] == cam->serialNum);
- LE_DEBUG("buff[2] correct? %d", cam->buff[2] == cmd);
- LE_DEBUG("buff[3] correct? %d", cam->buff[3] == 0x0);
return
cam->buff[0] == VC0706_RESP_PREFIX &&
cam->buff[1] == cam->serialNum &&
@@ -109,59 +182,80 @@ bool verifyResponse (Camera *cam, uint8_t cmd) {
cam->buff[3] == 0x0;
}
-bool cameraFrameBuffCtrl (Camera *cam, uint8_t cmd) {
+/**
+ * Helper for commands related
+ * to controlling the frame buffer
+ */
+bool cam_frameBuffCtrl (Camera *cam, uint8_t cmd) {
uint8_t args[] = { 0x1, cmd };
- return runCommandFlush(cam, VC0706_FBUF_CTRL, args, sizeof(args), 5);
+ return cam_runCommandFlush(cam, VC0706_FBUF_CTRL, args, sizeof(args), 5);
}
-bool takePicture (Camera *cam) {
+/**
+ * Stop the frame to take a photo
+ */
+bool cam_takePicture (Camera *cam) {
cam->frameptr = 0;
- return cameraFrameBuffCtrl(cam, VC0706_STOPCURRENTFRAME);
+ return cam_frameBuffCtrl(cam, VC0706_STOPCURRENTFRAME);
}
-bool reset (Camera *cam) {
+/**
+ * Reset cam
+ */
+bool cam_reset (Camera *cam) {
uint8_t args[] = { 0x0 };
- return runCommandFlush(cam, VC0706_RESET, args, sizeof(args), 5);
+ bool runRes = cam_runCommandFlush(cam, VC0706_RESET, args, sizeof(args), 5);
+ sleep(2); // wait for camera to come back online
+ return runRes;
}
-bool TVon (Camera *cam) {
+/**
+ * Enable the analog TV out
+ */
+bool cam_tvOn (Camera *cam) {
uint8_t args[] = { 0x1, 0x1 };
- return runCommandFlush(cam, VC0706_TVOUT_CTRL, args, sizeof(args), 5);
+ return cam_runCommandFlush(cam, VC0706_TVOUT_CTRL, args, sizeof(args), 5);
}
-bool TVOff (Camera *cam) {
+/**
+ * Disable the analog TV out
+ */
+bool cam_tvOff (Camera *cam) {
uint8_t args[] = { 0x1, 0x0 };
- return runCommandFlush(cam, VC0706_TVOUT_CTRL, args, sizeof(args), 5);
+ return cam_runCommandFlush(cam, VC0706_TVOUT_CTRL, args, sizeof(args), 5);
}
-uint8_t* readPicture (Camera *cam, uint8_t n) {
+/**
+ * Request a block of size n data from cam
+ */
+uint8_t* cam_readPicture (Camera *cam, uint8_t n) {
uint8_t args[] = { 0x0C, 0x0, 0x0A,
0, 0, cam->frameptr >> 8, cam->frameptr & 0xFF,
0, 0, 0, n,
CAM_DELAY >> 8, CAM_DELAY & 0xFF };
- LE_DEBUG("frameptr: %d", cam->frameptr);
- if (!runCommand(cam, VC0706_READ_FBUF, args, sizeof(args), 5, false)) { // don't flush
- LE_DEBUG("Failed in runCommand");
+ if (!cam_runCommand(cam, VC0706_READ_FBUF, args, sizeof(args), 5, false)) // don't flush
return NULL;
- }
- int imgDataRead = readResponse(cam, n + 5, CAM_DELAY);
- LE_DEBUG("Image data read: %d", imgDataRead);
- if (imgDataRead == 0) {
- LE_DEBUG("Failed in readResponse");
+ if (cam_readResponse(cam, n + 5, CAM_DELAY) == 0)
return NULL;
- }
cam->frameptr += n;
return &(cam->buff[0]);
}
-bool resumeVideo (Camera *cam) {
- return cameraFrameBuffCtrl(cam, VC0706_RESUMEFRAME);
+/**
+ * Resume frame capture
+ */
+bool cam_resumeVideo (Camera *cam) {
+ return cam_frameBuffCtrl(cam, VC0706_RESUMEFRAME);
}
-uint32_t frameLength (Camera *cam) {
+/**
+ * Get the length of the frame
+ * currently on cam
+ */
+uint32_t cam_frameLength (Camera *cam) {
uint8_t args[] = { 0x01, 0x00 };
- if (!runCommandFlush(cam, VC0706_GET_FBUF_LEN, args, sizeof(args), 9))
+ if (!cam_runCommandFlush(cam, VC0706_GET_FBUF_LEN, args, sizeof(args), 9))
return 0;
uint32_t len;
@@ -176,92 +270,124 @@ uint32_t frameLength (Camera *cam) {
return len;
}
-char* getVersion (Camera *cam) {
+/**
+ * Get the version from cam
+ */
+char* cam_getVersion (Camera *cam) {
uint8_t args[] = { 0x00 };
- sendCommand(cam, VC0706_GEN_VERSION, args, sizeof(args));
- if (!readResponse(cam, CAM_BUFF_SIZE, 200)) {
- LE_DEBUG("Failed to get version, returning empty string");
- return 0;
- }
+ cam_sendCommand(cam, VC0706_GEN_VERSION, args, sizeof(args));
+ if (!cam_readResponse(cam, CAM_BUFF_SIZE, 200))
+ return NULL;
cam->buff[cam->bufferLen] = 0;
return (char*)&(cam->buff[5]);
}
-uint8_t available (Camera *cam) {
+/**
+ * Get the length of cam's buffer
+ */
+uint8_t cam_available (Camera *cam) {
return cam->bufferLen;
}
-uint8_t getDownsize (Camera *cam) {
+/**
+ * Get cam's current downsize
+ */
+uint8_t cam_getDownsize (Camera *cam) {
uint8_t args[] = { 0x0 };
- if (!runCommandFlush(cam, VC0706_DOWNSIZE_STATUS, args, sizeof(args), 6))
+ if (!cam_runCommandFlush(cam, VC0706_DOWNSIZE_STATUS, args, sizeof(args), 6))
return -1;
return cam->buff[5];
}
-bool setDownsize (Camera *cam, uint8_t newSize) {
+/**
+ * Set cam's downsize
+ */
+bool cam_setDownsize (Camera *cam, uint8_t newSize) {
uint8_t args[] = { 0x01, newSize };
- return runCommandFlush(cam, VC0706_DOWNSIZE_CTRL, args, sizeof(args), 5);
+ return cam_runCommandFlush(cam, VC0706_DOWNSIZE_CTRL, args, sizeof(args), 5);
}
-uint8_t getImageSize (Camera *cam) {
+/**
+ * Get cam's current image size
+ */
+uint8_t cam_getImageSize (Camera *cam) {
uint8_t args[] = { 0x4, 0x4, 0x1, 0x00, 0x19 };
- if (!runCommandFlush(cam, VC0706_READ_DATA, args, sizeof(args), 6))
+ if (!cam_runCommandFlush(cam, VC0706_READ_DATA, args, sizeof(args), 6))
return -1;
return cam->buff[5];
}
-bool setImageSize (Camera *cam, uint8_t x) {
+/**
+ * Set cam's image size to x
+ */
+bool cam_setImageSize (Camera *cam, uint8_t x) {
uint8_t args[] = { 0x05, 0x04, 0x01, 0x00, 0x19, x };
- return runCommandFlush(cam, VC0706_WRITE_DATA, args, sizeof(args), 5);
+ return cam_runCommandFlush(cam, VC0706_WRITE_DATA, args, sizeof(args), 5);
}
-bool getMotionDetect (Camera *cam) {
+bool cam_getMotionDetect (Camera *cam) {
uint8_t args[] = { 0x0 };
- if (!runCommandFlush(cam, VC0706_COMM_MOTION_STATUS, args, sizeof(args), 6))
+ if (!cam_runCommandFlush(cam, VC0706_COMM_MOTION_STATUS, args, sizeof(args), 6))
return false;
return cam->buff[5];
}
-uint8_t getMotionStatus(Camera *cam, uint8_t x) {
+uint8_t cam_getMotionStatus (Camera *cam, uint8_t x) {
uint8_t args[] = { 0x01, x };
- return runCommandFlush(cam, VC0706_MOTION_STATUS, args, sizeof(args), 5);
+ return cam_runCommandFlush(cam, VC0706_MOTION_STATUS, args, sizeof(args), 5);
}
-bool motionDetected (Camera *cam) {
- if (readResponse(cam, 4, 200) != 4)
+/**
+ * Return true if cam detected motion
+ */
+bool cam_motionDetected (Camera *cam) {
+ if (cam_readResponse(cam, 4, 200) != 4)
return false;
- if (!verifyResponse(cam, VC0706_COMM_MOTION_DETECTED))
+ if (!cam_verifyResponse(cam, VC0706_COMM_MOTION_DETECTED))
return false;
return true;
}
-bool setMotionDetect (Camera *cam, bool flag) {
- if (!setMotionStatus(cam, VC0706_MOTIONCONTROL, VC0706_UARTMOTION, VC0706_ACTIVATEMOTION))
+/**
+ * Enable/disable motion detection on cam
+ */
+bool cam_setMotionDetect (Camera *cam, bool flag) {
+ if (!cam_setMotionStatus(cam, VC0706_MOTIONCONTROL, VC0706_UARTMOTION, VC0706_ACTIVATEMOTION))
return false;
uint8_t args[] = { 0x1, flag };
- return runCommandFlush(cam, VC0706_MOTION_STATUS, args, sizeof(args), 5);
+ return cam_runCommandFlush(cam, VC0706_MOTION_STATUS, args, sizeof(args), 5);
}
-bool setMotionStatus (Camera *cam, uint8_t x, uint8_t d1, uint8_t d2) {
+bool cam_setMotionStatus (Camera *cam, uint8_t x, uint8_t d1, uint8_t d2) {
uint8_t args[] = { 0x03, x, d1, d2 };
- return runCommandFlush(cam, VC0706_MOTION_CTRL, args, sizeof(args), 5);
+ return cam_runCommandFlush(cam, VC0706_MOTION_CTRL, args, sizeof(args), 5);
}
-uint8_t getCompression (Camera *cam) {
+/**
+ * Get cam's current level of compression
+ */
+uint8_t cam_getCompression (Camera *cam) {
uint8_t args[] = { 0x4, 0x1, 0x1, 0x12, 0x04 };
- runCommandFlush(cam, VC0706_READ_DATA, args, sizeof(args), 6);
+ cam_runCommandFlush(cam, VC0706_READ_DATA, args, sizeof(args), 6);
return cam->buff[5];
}
-bool setCompression (Camera *cam, uint8_t c) {
+/**
+ * Set cam's level of compression to c
+ */
+bool cam_setCompression (Camera *cam, uint8_t c) {
uint8_t args[] = { 0x5, 0x1, 0x1, 0x12, 0x04, c };
- return runCommandFlush(cam, VC0706_WRITE_DATA, args, sizeof(args), 5);
+ return cam_runCommandFlush(cam, VC0706_WRITE_DATA, args, sizeof(args), 5);
}
-bool getPTZ(Camera *cam, uint16_t *w, uint16_t *h, uint16_t *wz, uint16_t *hz, uint16_t *pan, uint16_t *tilt) {
+/**
+ * Get cam's current PTZ values
+ * All values returned in pointers
+ */
+bool cam_getPTZ(Camera *cam, uint16_t *w, uint16_t *h, uint16_t *wz, uint16_t *hz, uint16_t *pan, uint16_t *tilt) {
uint8_t args[] = { 0x0 };
- if (!runCommandFlush(cam, VC0706_GET_ZOOM, args, sizeof(args), 16))
+ if (!cam_runCommandFlush(cam, VC0706_GET_ZOOM, args, sizeof(args), 16))
return false;
*w = cam->buff[5];
*w <<= 8;
@@ -290,27 +416,37 @@ bool getPTZ(Camera *cam, uint16_t *w, uint16_t *h, uint16_t *wz, uint16_t *hz, u
return true;
}
-bool setPTZ (Camera *cam, uint16_t wz, uint16_t hz, uint16_t pan, uint16_t tilt) {
+/**
+ * Set cam's PTZ settings
+ */
+bool cam_setPTZ (Camera *cam, uint16_t wz, uint16_t hz, uint16_t pan, uint16_t tilt) {
uint8_t args[] = {
0x08, wz >> 8, wz,
hz >> 8, wz,
pan >> 8, pan,
tilt >> 8, tilt
};
- return !runCommandFlush(cam, VC0706_SET_ZOOM, args, sizeof(args), 5);
+ return !cam_runCommandFlush(cam, VC0706_SET_ZOOM, args, sizeof(args), 5);
}
-uint8_t getImageBlockSize (int jpgLen) {
+/**
+ * Return how much data should be requested
+ * from cam based on jpgLen
+ */
+uint8_t cam_getImageBlockSize (int jpgLen) {
return CAM_BLOCK_SIZE < jpgLen ? CAM_BLOCK_SIZE : jpgLen;
}
-bool readImageBlock (Camera *cam, FILE *filePtr) {
- int jpgLen = frameLength(cam);
+/**
+ * Read the entire frame buffer from cam
+ * into filePtr
+ */
+bool cam_readImageBlocks (Camera *cam, FILE *filePtr) {
+ int jpgLen = cam_frameLength(cam);
bool success = true;
while (jpgLen > 0) {
- uint8_t bytesToRead = getImageBlockSize(jpgLen);
- LE_DEBUG("jpgLen: %d, bytesToRead: %d", jpgLen, bytesToRead);
- uint8_t *buff = readPicture(cam, bytesToRead);
+ uint8_t bytesToRead = cam_getImageBlockSize(jpgLen);
+ uint8_t *buff = cam_readPicture(cam, bytesToRead);
if (buff == NULL) {
LE_ERROR("Failed to read image data");
success = false;
@@ -318,20 +454,16 @@ bool readImageBlock (Camera *cam, FILE *filePtr) {
}
fwrite(buff, sizeof(*buff), bytesToRead, filePtr);
jpgLen -= bytesToRead;
- // TODO figure out why resetting the resetting
- // the serial connection after reading a block
- // keeps the camera responsive
- //
- // This may be a limitation in le_tty
- // so using Linux system calls may be worthwhile
- fd_resetCamTty(&(cam->fd));
}
- fclose(filePtr);
- printBuffer(cam);
return success;
}
-bool readImageToFile (Camera *cam, char *path) {
+/**
+ * Read the image from cam into a file
+ * described by path
+ */
+bool cam_readImageToFile (Camera *cam, char *path) {
+ bool success = false;
char writePath[100];
// e.g /mnt/sd/<timestamp>.jpg
sprintf(writePath, "%s/%d.jpg", path, (int)time(0));
@@ -339,21 +471,27 @@ bool readImageToFile (Camera *cam, char *path) {
FILE *filePtr = fopen(writePath, "w");
if (filePtr != NULL) {
LE_INFO("Got valid file pointer");
- return readImageBlock(cam, filePtr);
+ success = cam_readImageBlocks(cam, filePtr);
}
else {
LE_ERROR("Invalid file pointer for %s", writePath);
- return false;
}
+ LE_INFO("Done writing image");
+ fclose(filePtr);
+ return success;
}
-bool snapshotToFile (Camera *cam, char *path, uint8_t imgSize) {
- setImageSize(cam, imgSize);
+/**
+ * Take a photo on cam and write it to a file
+ * described by path
+ */
+bool cam_snapshotToFile (Camera *cam, char *path, uint8_t imgSize) {
+ cam_setImageSize(cam, imgSize);
LE_INFO("Taking photo...");
- bool photoTaken = takePicture(cam);
+ bool photoTaken = cam_takePicture(cam);
if (photoTaken) {
LE_INFO("Photo taken");
- return readImageToFile(cam, path);
+ return cam_readImageToFile(cam, path);
}
else {
LE_ERROR("Failed to take photo");