257 lines
4.5 KiB
C
257 lines
4.5 KiB
C
/*
|
|
* Copyright © 2012 Keith Packard <keithp@keithp.com>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
|
*/
|
|
|
|
#define _DEFAULT_SOURCE 1
|
|
#include <termios.h>
|
|
#include <unistd.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <fcntl.h>
|
|
#include <poll.h>
|
|
#include "sky_flash.h"
|
|
#include <stdio.h>
|
|
#include <sys/time.h>
|
|
#include <stdint.h>
|
|
#include <unistd.h>
|
|
#include <stdarg.h>
|
|
|
|
int skytraq_verbose = 1;
|
|
|
|
int
|
|
skytraq_setspeed(int fd, int baud)
|
|
{
|
|
int b;
|
|
int ret;
|
|
struct termios term;
|
|
|
|
switch (baud) {
|
|
case 9600:
|
|
b = B9600;
|
|
break;
|
|
case 38400:
|
|
b = B38400;
|
|
break;
|
|
case 115200:
|
|
b = B115200;
|
|
break;
|
|
default:
|
|
fprintf (stderr, "Invalid baudrate %d\n", baud);
|
|
return -1;
|
|
}
|
|
ret = tcgetattr(fd, &term);
|
|
cfmakeraw(&term);
|
|
#ifdef USE_POLL
|
|
term.c_cc[VMIN] = 1;
|
|
term.c_cc[VTIME] = 0;
|
|
#else
|
|
term.c_cc[VMIN] = 0;
|
|
term.c_cc[VTIME] = 1;
|
|
#endif
|
|
|
|
cfsetspeed(&term, b);
|
|
|
|
ret = tcsetattr(fd, TCSAFLUSH, &term);
|
|
return ret;
|
|
}
|
|
|
|
int skytraq_open_time;
|
|
|
|
int
|
|
skytraq_open(const char *path)
|
|
{
|
|
int fd;
|
|
int ret;
|
|
|
|
fd = open(path, O_RDWR | O_NOCTTY);
|
|
if (fd < 0) {
|
|
perror (path);
|
|
return -1;
|
|
}
|
|
|
|
ret = skytraq_setspeed(fd, 9600);
|
|
if (ret < 0) {
|
|
close (fd);
|
|
return -1;
|
|
}
|
|
skytraq_open_time = skytraq_millis();
|
|
return fd;
|
|
}
|
|
|
|
|
|
#define BAUD 57600
|
|
#define BPS (BAUD/10 * 9/10)
|
|
#define US_PER_CHAR (1000000 / BPS)
|
|
|
|
int
|
|
skytraq_write(int fd, const void *d, int len)
|
|
{
|
|
const char *data = d;
|
|
int r;
|
|
|
|
skytraq_dbg_printf (0, "%4d: ", len);
|
|
if (len < 70)
|
|
skytraq_dbg_buf(0, data, len);
|
|
while (len) {
|
|
int this_time = len;
|
|
if (this_time > 128)
|
|
this_time = 128;
|
|
skytraq_dbg_printf(0, ".");
|
|
fflush(stdout);
|
|
r = write(fd, data, this_time);
|
|
if (r <= 0)
|
|
return r;
|
|
usleep(r * US_PER_CHAR);
|
|
data += r;
|
|
len -= r;
|
|
}
|
|
skytraq_dbg_newline();
|
|
return 1;
|
|
}
|
|
|
|
int
|
|
skytraq_setcomm(int fd, int baudrate)
|
|
{
|
|
uint8_t msg[11];
|
|
int i;
|
|
uint8_t cksum;
|
|
|
|
int target_baudrate = 0;
|
|
switch(baudrate)
|
|
{
|
|
case 4800:
|
|
target_baudrate=0;
|
|
break;
|
|
case 9600:
|
|
target_baudrate=1;
|
|
break;
|
|
case 19200:
|
|
target_baudrate=2;
|
|
break;
|
|
case 38400:
|
|
target_baudrate=3;
|
|
break;
|
|
case 57600:
|
|
target_baudrate=4;
|
|
break;
|
|
case 115200:
|
|
target_baudrate=5;
|
|
break;
|
|
case 230400:
|
|
target_baudrate=6;
|
|
break;
|
|
}
|
|
msg[0] = 0xa0; /* header */
|
|
msg[1] = 0xa1;
|
|
msg[2] = 0x00; /* length */
|
|
msg[3] = 0x04;
|
|
msg[4] = 0x05; /* configure serial port */
|
|
msg[5] = 0x00; /* COM 1 */
|
|
msg[6] = target_baudrate;
|
|
msg[7] = 0x00; /* update to SRAM only */
|
|
|
|
cksum = 0;
|
|
for (i = 4; i < 8; i++)
|
|
cksum ^= msg[i];
|
|
msg[8] = cksum;
|
|
msg[9] = 0x0d;
|
|
msg[10] = 0x0a;
|
|
return skytraq_write(fd, msg, 11);
|
|
}
|
|
|
|
int
|
|
skytraq_waitchar(int fd, int timeout)
|
|
{
|
|
struct pollfd fds[1];
|
|
int ret;
|
|
unsigned char c;
|
|
|
|
for (;;) {
|
|
fds[0].fd = fd;
|
|
fds[0].events = POLLIN;
|
|
ret = poll(fds, 1, timeout);
|
|
if (ret >= 1) {
|
|
if (fds[0].revents & POLLIN) {
|
|
ret = read(fd, &c, 1);
|
|
if (ret == 1) {
|
|
skytraq_dbg_char(1, c);
|
|
return c;
|
|
}
|
|
}
|
|
} else if (ret == 0)
|
|
return -2;
|
|
else {
|
|
perror("poll");
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
int
|
|
skytraq_waitstatus(int fd, const char *status, int timeout)
|
|
{
|
|
const char *s;
|
|
int c;
|
|
|
|
for (;;) {
|
|
c = skytraq_waitchar(fd, timeout);
|
|
if (c < 0) {
|
|
skytraq_dbg_newline();
|
|
return c;
|
|
}
|
|
if ((char) c == *status) {
|
|
s = status + 1;
|
|
for (;;) {
|
|
c = skytraq_waitchar(fd, timeout);
|
|
if (c < 0) {
|
|
skytraq_dbg_newline();
|
|
return c;
|
|
}
|
|
if ((char) c != *s)
|
|
break;
|
|
if (!*s) {
|
|
skytraq_dbg_newline();
|
|
return 0;
|
|
}
|
|
s++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
skytraq_flush(int fd)
|
|
{
|
|
while (skytraq_waitchar(fd, 1) >= 0)
|
|
;
|
|
}
|
|
|
|
int
|
|
skytraq_cmd_wait(int fd, const char *message, int len, const char *status, int timeout)
|
|
{
|
|
skytraq_flush(fd);
|
|
skytraq_write(fd, message, len);
|
|
return skytraq_waitstatus(fd, status, timeout);
|
|
}
|
|
|
|
int
|
|
skytraq_cmd_nowait(int fd, const char *message, int len)
|
|
{
|
|
skytraq_flush(fd);
|
|
return skytraq_write(fd, message, len);
|
|
}
|