From ea5763b0054d2fbe95f13e90f4e37a10eb9039bf Mon Sep 17 00:00:00 2001 From: Philip Heron Date: Tue, 29 Jun 2010 16:46:13 +0100 Subject: [PATCH] Add C328 support functions --- Makefile | 2 +- c328.c | 200 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ c328.h | 95 ++++++++++++++++++++++++++ rtty.c | 6 ++ 4 files changed, 302 insertions(+), 1 deletion(-) create mode 100644 c328.c create mode 100644 c328.h diff --git a/Makefile b/Makefile index db41b61..d1b8a07 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ PROJECT=hadie -OBJECTS=hadie.o rtty.o rs8encode.o +OBJECTS=hadie.o rtty.o rs8encode.o c328.o # Serial device used for programming AVR TTYPORT=/dev/ttyACM0 diff --git a/c328.c b/c328.c new file mode 100644 index 0000000..7ef3746 --- /dev/null +++ b/c328.c @@ -0,0 +1,200 @@ +/* Interface to the C328 UART camera */ + +#include "config.h" +#include +#include +#include "c328.h" + +/* >10ms timeout at 300 hz */ +#define CMD_TIMEOUT (4) + +#define RXREADY (UCSR0A & (1 << RXC0)) + +/* Receive buffer */ +#define RXBUF_LEN (64) +static uint8_t rxbuf[RXBUF_LEN]; +static uint8_t rxbuf_len = 0; + +/* Expected package size */ +static uint8_t pkg_len = 64; /* Default is 64 according to datasheet */ + +/* Timeout counter */ +volatile static uint8_t timeout_clk = 0; + +void inline c3_tick() +{ + if(timeout_clk) timeout_clk--; +} + +static void tx_byte(uint8_t b) +{ + /* Wait for empty transmit buffer */ + while(!(UCSR0A & (1 << UDRE0))); + + /* Put data into buffer, sends the data */ + UDR0 = b; +} + +static uint8_t c3_rx(uint8_t timeout) +{ + rxbuf_len = 0; + + timeout_clk = timeout; + while(timeout_clk) + { + if(!RXREADY) continue; + rxbuf[rxbuf_len++] = UDR0; + if(rxbuf_len == 6) break; + } + + if(rxbuf_len != 6) return(0); /* Timeout or incomplete response */ + if(rxbuf[0] != 0xAA) return(0); /* All responses should begin 0xAA */ + + /* Return the received command ID */ + return(rxbuf[1]); +} + +static void c3_tx(uint8_t cmd, uint8_t a1, uint8_t a2, uint8_t a3, uint8_t a4) +{ + tx_byte(0xAA); + tx_byte(cmd); + tx_byte(a1); + tx_byte(a2); + tx_byte(a3); + tx_byte(a4); +} + +static char c3_cmd(uint8_t cmd, uint8_t a1, uint8_t a2, uint8_t a3, uint8_t a4) +{ + uint8_t r; + + c3_tx(cmd, a1, a2, a3, a4); + r = c3_rx(CMD_TIMEOUT); + + /* Did we get an ACK for this command? */ + if(r != CMD_ACK || rxbuf[2] != cmd) return(-1); + + return(0); +} + +void c3_init() +{ + /* Do UART initialisation, port 0 @ 57600 baud for 7.3728 MHz clock */ + UBRR0H = 0; + UBRR0L = 7; + + /* Enable TX & RX */ + UCSR0B = (1 << RXEN0) | (1 << TXEN0); + + /* 8-bit, no parity and 1 stop bit */ + UCSR0C = (1 << UCSZ01) | (1 << UCSZ00); +} + +char c3_sync() +{ + char i; + + /* Send the SYNC command until the camera responds, up to 60 */ + for(i = 0; i < 60; i++) + { + /* Send the sync and wait for an ACK */ + if(c3_cmd(CMD_SYNC, 0, 0, 0, 0) != 0) continue; + + /* ACK should be followed by a SYNC */ + if(c3_rx(CMD_TIMEOUT) != CMD_SYNC) continue; + + /* ACK the SYNC and return success code */ + c3_tx(CMD_ACK, CMD_SYNC, 0, 0, 0); + return(0); + } + + /* If we got here, the camera failed to sync. Panic */ + return(-1); +} + +char c3_setup(uint8_t ct, uint8_t rr, uint8_t jr) +{ + return(c3_cmd(CMD_INIT, 0, ct, rr, jr)); +} + +char c3_set_package_size(uint16_t s) +{ + char r; + + if(s > RXBUF_LEN) return(-1); + + r = c3_cmd(CMD_SET_PKG_SIZE, 0x08, s & 0xFF, s >> 8, 0); + + if(r == 0) pkg_len = s; + + return(r); +} + +char c3_snapshot(uint8_t st, uint16_t skip_frame) +{ + return(c3_cmd(CMD_SNAPSHOT, st, skip_frame & 0xFF, skip_frame >> 8, 0)); +} + +char c3_get_picture(uint8_t pt, uint16_t *length) +{ + /* Send the command */ + if(c3_cmd(CMD_GET_PICTURE, pt, 0, 0, 0) != 0) return(-1); + + /* The camera should now send a DATA message */ + if(c3_rx(CMD_TIMEOUT) != CMD_DATA) return(-1); + + /* Get the file size from the DATA args */ + *length = rxbuf[9] + (rxbuf[10] << 8); + + return(0); +} + +char c3_get_package(uint16_t id, uint8_t **dst, uint16_t *length) +{ + uint8_t checksum; + uint16_t s; + + rxbuf_len = 0; + checksum = 0; + s = pkg_len; + + /* Get the package by sending an ACK */ + c3_tx(CMD_ACK, 0, 0, id & 0xFF, id >> 8); + + /* The camera should immediatly start returning data */ + timeout_clk = CMD_TIMEOUT; + while(timeout_clk && rxbuf_len < s) + { + if(!RXREADY) continue; + + /* Read the byte and update checksum */ + checksum += rxbuf[rxbuf_len++] = UDR0; + + if(rxbuf_len == 4) + { + /* Get the actual length of the package */ + s = rxbuf[2] + (rxbuf[3] << 8) + 6; + if(s > pkg_len) return(-1); + } + } + + /* Test for timeout or incomplete package */ + if(rxbuf_len < s) return(-1); + + /* Test checksum */ + checksum -= rxbuf[rxbuf_len - 2]; + if(checksum != rxbuf[rxbuf_len - 2]) return(-1); + + /* All done */ + *dst = rxbuf; + *length = rxbuf_len; + + return(0); +} + +char c3_finish_picture() +{ + c3_tx(CMD_ACK, 0, 0, 0xF0, 0xF0); + return(0); +} + diff --git a/c328.h b/c328.h new file mode 100644 index 0000000..b6ec326 --- /dev/null +++ b/c328.h @@ -0,0 +1,95 @@ + +#ifndef INC_C328_H +#define INC_C328_H + +/* Commands */ +#define CMD_INIT 0x01 +#define CMD_GET_PICTURE 0x04 +#define CMD_SNAPSHOT 0x05 +#define CMD_SET_PKG_SIZE 0x06 +#define CMD_SET_BAUDRATE 0x07 +#define CMD_RESET 0x08 +#define CMD_POWER_OFF 0x09 +#define CMD_DATA 0x0A +#define CMD_SYNC 0x0D +#define CMD_ACK 0x0E +#define CMD_NAK 0x0F +#define CMD_SET_LIGHT_FREQUENCY 0x13 + +/* Colour Types */ +#define CT_2BIT_GRAY 0x01 +#define CT_4BIT_GRAY 0x02 +#define CT_8BIT_GRAY 0x03 +#define CT_12BIT_COLOUR 0x05 +#define CT_16BIT_COLOUR 0x06 +#define CT_JPEG 0x07 + +/* Preview Resolutions */ +#define PR_80x60 0x01 +#define PR_160x120 0x03 + +/* Snapshot resolutions */ +#define SR_80x64 0x01 +#define SR_160x128 0x03 +#define SR_320x240 0x05 +#define SR_640x480 0x07 + +/* Picture Type */ +#define PT_SNAPSHOT 0x01 +#define PT_PREVIEW 0x02 +#define PT_JPEG_PREVIEW 0x03 + +/* Snapshot Type */ +#define ST_JPEG 0x00 +#define ST_RAW 0x01 + +/* Baudrates (0xXXYY, XX = First Divider, YY = Second Divider) */ +#define BR_7200 0xFF01 +#define BR_9600 0xBF01 +#define BR_14400 0x7F01 +#define BR_19200 0x5F01 +#define BR_28800 0x3F01 +#define BR_38400 0x2F01 +#define BR_57600 0x1F01 +#define BR_115200 0x0F01 +#define BR_921600 0x0101 /* Undocumented */ + +/* Light Frequencies */ +#define LF_50HZ 0x00 +#define LF_60HZ 0x01 + +/* Errors */ +#define ERR_PICTURE_TYPE_ERROR 0x01 +#define ERR_PICTURE_UP_SCALE 0x02 +#define ERR_PICTURE_SCALE_ERROR 0x03 +#define ERR_UNEXPECTED_REPLY 0x04 +#define ERR_SEND_PICTURE_TIMEOUT 0x05 +#define ERR_UNEXPECTED_COMMAND 0x06 +#define ERR_SRAM_JPEG_TYPE_ERROR 0x07 +#define ERR_SRAM_JPEG_SIZE_ERROR 0x08 +#define ERR_PICTURE_FORMAT_ERROR 0x09 +#define ERR_PICTURE_SIZE_ERROR 0x0A +#define ERR_PARAMETER_ERROR 0x0B +#define ERR_SEND_REGISTER_TIMEOUT 0x0C +#define ERR_COMMAND_ID_ERROR 0x0D +#define ERR_PICTURE_NOT_READY 0x0F +#define ERR_TRANSFER_PACKAGE_NUMBER_ERROR 0x10 +#define ERR_SET_TRANSFER_PACKAGE_SIZE_WRONG 0x11 +#define ERR_COMMAND_HEADER_ERROR 0xF0 +#define ERR_COMMAND_LENGTH_ERROR 0xF1 +#define ERR_SEND_PICTURE_ERROR 0xF5 +#define ERR_SEND_COMMAND_ERROR 0xFF + +extern void inline c3_tick(); + +extern void c3_init(); +extern char c3_sync(); + +extern char c3_setup(uint8_t ct, uint8_t rr, uint8_t jr); +extern char c3_set_package_size(uint16_t s); +extern char c3_snapshot(uint8_t st, uint16_t skip_frame); +extern char c3_get_picture(uint8_t pt, uint16_t *length); +extern char c3_get_package(uint16_t id, uint8_t **dst, uint16_t *length); +extern char c3_finish_picture(); + +#endif diff --git a/rtty.c b/rtty.c index 6be4ff9..4fced29 100644 --- a/rtty.c +++ b/rtty.c @@ -15,6 +15,9 @@ #include #include "rtty.h" +/* For camera timeout */ +#include "c328.h" + /* MARK = Upper tone, Idle, bit */ #define TXPIN (1 << 0) /* PB0 */ #define TXENABLE (1 << 1) /* PB1 */ @@ -48,6 +51,9 @@ ISR(TIMER0_COMPA_vect) else byte = pgm_read_byte(txbuf++); txlen--; } + + /* Camera timeout tick */ + c3_tick(); } void rtx_init()