📄 rcxsend.c
字号:
/**
* rcxsend.c
* This is essentially a copy of Jose Solorzanos tvm_firmdl3.c or
* rather Kekoa Proudfoot's firmdl3.c and send.c, available
* at http://graphics.stanford.edu/~kekoa/rcx/firmdl3.c
* and http://graphics.stanford.edu/~kekoa/rcx/tools.html
* License information shown below.
*
* Tim's changes:
* 05/30/01 -- This file replaces the old RCXPort-implementation,
* which was based on the javax.comm-Driver.
* It extends the compatibility of send.c with Cygwin
* on Windows 9x Systems.
* Added some command line options, like -debug, -tty.
* Suppressed complements.
* Removed fast mode.
*/
/*
* send.c
*
* A program to communicate with an RCX.
*
* Copyright (C) 1998, Kekoa Proudfoot. All Rights Reserved.
*/
/*
* firmdl3.c
*
* A firmware downloader for the RCX. Version 3.0. Supports single and
* quad speed downloading.
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
* License for the specific language governing rights and limitations
* under the License.
*
* The Original Code is Firmdl code, released October 3, 1998.
*
* The Initial Developer of the Original Code is Kekoa Proudfoot.
* Portions created by Kekoa Proudfoot are Copyright (C) 1998, 1999
* Kekoa Proudfoot. All Rights Reserved.
*
* Contributor(s): Kekoa Proudfoot <kekoa@graphics.stanford.edu>
* Laurent Demailly
* Allen Martin
* Markus Noga
* Gavin Smyth
* Luis Villa
* Jose Solorzano
*/
/*
* usage: rcxsend [options] byte [byte ...] (e.g. rcxsend --debug 10)
*
* If necessary, set DEFAULTTTY, below, to the serial device you want to use.
* Set the RCXTTY environment variable to override DEFAULTTTY.
* Use the command-line option --tty=TTY to override RCXTTY and DEFAULTTTY.
*
* Tim Rinkens
* tau@uni-paderborn.de
* 05/30/01
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <termios.h>
#include <stdio.h>
#include <string.h>
#include <sys/time.h>
#include <ctype.h>
#include <string.h>
/* #include "util.h" */
#if defined(_WIN32)
#include <windows.h>
#endif
/* Machine-dependent defines */
#if defined(LINUX) || defined(linux)
#define DEFAULTTTY "/dev/ttyS0" /* Linux - COM1 */
#elif defined (_WIN32)
#define DEFAULTTTY "com1" /* Cygwin - COM1 */
#elif defined (sun)
#define DEFAULTTTY "/dev/ttya" /* Solaris - first serial port - untested */
#else
#define DEFAULTTTY "/dev/ttyd2" /* IRIX - second serial port */
#endif
/* Global variables */
char *progname;
/*** rcx_comm.h ***/
#ifndef RCX_COMM_H_INCLUDED
#define RCX_COMM_H_INCLUDED
#define RCX_OK 0
#define RCX_NO_TOWER -1
#define RCX_BAD_LINK -2
#define RCX_BAD_ECHO -3
#define RCX_NO_RESPONSE -4
#define RCX_BAD_RESPONSE -5
#if defined(_WIN32)
#define FILEDESCR HANDLE
#define BADFILE NULL
#else
#define FILEDESCR int
#define BADFILE -1
#endif
/* Get a file descriptor for the named tty, exits with message on error */
// extern FILEDESCR rcx_init (char *tty, int is_fast);
extern FILEDESCR rcx_init (char *tty);
/* Close a file descriptor allocated by rcx_init */
extern void rcx_close (FILEDESCR fd);
/* Try to wakeup the tower for timeout ms, returns error code */
extern int rcx_wakeup_tower (FILEDESCR fd, int timeout);
/* Try to send a message, returns error code */
/* Set use_comp=1 to send complements, use_comp=0 to suppress them */
// extern int rcx_send (FILEDESCR fd, void *buf, int len, int use_comp);
extern int rcx_send (FILEDESCR fd, void *buf, int len);
/* Try to receive a message, returns error code */
/* Set use_comp=1 to expect complements */
/* Waits for timeout ms before detecting end of response */
// extern int rcx_recv (FILEDESCR fd, void *buf, int maxlen, int timeout, int use_comp);
extern int rcx_recv (FILEDESCR fd, void *buf, int maxlen, int timeout);
/* Try to send a message and receive its response, returns error code */
/* Set use_comp=1 to send and receive complements, use_comp=0 otherwise */
/* Waits for timeout ms before detecting end of response */
// extern int rcx_sendrecv (FILEDESCR fd, void *send, int slen, void *recv, int rlen, int timeout, int retries, int use_comp);
extern int rcx_sendrecv (FILEDESCR fd, void *send, int slen, void *recv, int rlen, int timeout, int retries);
/* Test whether or not the rcx is alive, returns 1=yes, 0=no */
/* Set use_comp=1 to send complements, use_comp=0 to suppress them */
// extern int rcx_is_alive (FILEDESCR fd, int use_comp);
extern int rcx_is_alive (FILEDESCR fd);
/* Convert an error code to a string */
extern char *rcx_strerror(int error);
/* Hexdump routine */
extern void hexdump(char *prefix, void *buf, int len);
#endif /* RCX_COMM_H_INCLUDED */
/*** rcx_comm.c ***/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <termios.h>
#include <sys/time.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#if defined(_WIN32)
#include <windows.h>
#endif
/* Defines */
#define BUFFERSIZE 4096
/* Globals */
int __comm_debug = 0;
/* Timer routines */
typedef struct timeval timeval_t;
#define tvupdate(tv) gettimeofday(tv,NULL)
#define tvsec(tv) ((tv)->tv_sec)
#define tvmsec(tv) ((tv)->tv_usec * 1e-3)
static float
timer_reset(timeval_t *timer)
{
tvupdate(timer);
return 0;
}
static float
timer_read(timeval_t *timer)
{
timeval_t now;
tvupdate(&now);
return tvsec(&now) - tvsec(timer) + (tvmsec(&now) - tvmsec(timer)) * 1e-3;
}
void myperror(char *str) {
#if defined(_WIN32)
fprintf(stderr, "Error %lu: %s\n", (unsigned long) GetLastError(), str);
#else
perror(str);
#endif
}
/* Timeout read routine */
static int nbread (FILEDESCR fd, void *buf, int maxlen, int timeout)
{
char *bufp = (char *)buf;
int len = 0;
while (len < maxlen) {
#if defined(_WIN32)
DWORD count;
COMMTIMEOUTS CommTimeouts;
GetCommTimeouts (fd, &CommTimeouts);
// Change the COMMTIMEOUTS structure settings.
CommTimeouts.ReadIntervalTimeout = MAXDWORD;
CommTimeouts.ReadTotalTimeoutMultiplier = 0;
CommTimeouts.ReadTotalTimeoutConstant = timeout;
CommTimeouts.WriteTotalTimeoutMultiplier = 10;
CommTimeouts.WriteTotalTimeoutConstant = 1000;
// Set the time-out parameters for all read and write operations
// on the port.
SetCommTimeouts(fd, &CommTimeouts);
if (ReadFile(fd, &bufp[len], maxlen - len, &count, NULL) == FALSE) {
myperror("ReadFile");
fprintf(stderr, "nb_read - error reading tty: %lu\n", (unsigned long) GetLastError());
exit(1);
}
len += count;
if (count == 0) {
//timeout
break;
}
#else
int count;
fd_set fds;
struct timeval tv;
FD_ZERO(&fds);
FD_SET(fd, &fds);
tv.tv_sec = timeout / 1000;
tv.tv_usec = (timeout % 1000) * 1000;
if (select(fd+1, &fds, NULL, NULL, &tv) < 0) {
perror("select");
exit(1);
}
if (!FD_ISSET(fd, &fds))
break;
if ((count = read(fd, &bufp[len], maxlen - len)) < 0) {
perror("read");
exit(1);
}
len += count;
#endif
}
return len;
}
/* discard all characters in the input queue of tty */
static void rx_flush(FILEDESCR fd)
{
#if defined(_WIN32)
PurgeComm(fd, PURGE_RXABORT | PURGE_RXCLEAR);
#else
char echo[BUFFERSIZE];
nbread(fd, echo, BUFFERSIZE, 200);
#endif
}
int mywrite(FILEDESCR fd, const void *buf, size_t len) {
#if defined(_WIN32)
DWORD nBytesWritten=0;
WriteFile(fd, buf, len, &nBytesWritten, NULL);
return nBytesWritten;
#else
return write(fd, buf, len);
#endif
}
/* RCX routines */
FILEDESCR rcx_init(char *tty) // , int is_fast)
{
FILEDESCR fd;
#if defined(_WIN32)
DCB dcb;
#else
struct termios ios;
#endif
// if (__comm_debug) printf("mode = %s\n", is_fast ? "fast" : "slow");
if (__comm_debug) printf("mode = %s\n", "slow");
#if defined(_WIN32)
if ((fd = CreateFile(tty, GENERIC_READ | GENERIC_WRITE,
0, NULL, OPEN_EXISTING,
0, NULL)) == INVALID_HANDLE_VALUE) {
fprintf(stderr, "Error %lu: Opening %s\n", (unsigned long) GetLastError(), tty);
exit(1);
}
// Serial settings
FillMemory(&dcb, sizeof(dcb), 0);
if (!GetCommState(fd, &dcb)) { // get current DCB
// Error in GetCommState
myperror("GetCommState");
exit(1);
} else {
dcb.ByteSize = 8;
// dcb.Parity = (is_fast ? 0 : 1);
dcb.Parity = (1); // 0-4=no,odd,even,mark,space
dcb.StopBits = 0; // 0,1,2 = 1, 1.5, 2
dcb.fBinary = TRUE ;
// dcb.fParity = (is_fast ? FALSE : TRUE) ;
dcb.fParity = (TRUE) ;
dcb.fAbortOnError = FALSE ;
// dcb.BaudRate = (is_fast ? CBR_4800 : CBR_2400);
dcb.BaudRate = (CBR_2400); // Update DCB rate.
// Set new state.
if (!SetCommState(fd, &dcb)) {
// Error in SetCommState. Possibly a problem with the communications
// port handle or a problem with the DCB structure itself.
myperror("SetCommState");
exit(1);
}
}
#else
if ((fd = open(tty, O_RDWR)) < 0) {
perror(tty);
exit(1);
}
if (!isatty(fd)) {
close(fd);
fprintf(stderr, "%s: not a tty\n", tty);
exit(1);
}
memset(&ios, 0, sizeof(ios));
/*
if (is_fast) {
ios.c_cflag = CREAD | CLOCAL | CS8;
cfsetispeed(&ios, B4800);
cfsetospeed(&ios, B4800);
}
else {
*/
ios.c_cflag = CREAD | CLOCAL | CS8 | PARENB | PARODD;
cfsetispeed(&ios, B2400);
cfsetospeed(&ios, B2400);
// }
if (tcsetattr(fd, TCSANOW, &ios) == -1) {
perror("tcsetattr");
exit(1);
}
#endif
return fd;
}
void rcx_close(FILEDESCR fd)
{
#if defined(_WIN32)
CloseHandle(fd);
#else
close(fd);
#endif
}
int rcx_wakeup_tower (FILEDESCR fd, int timeout)
{
char msg[] = { 0x10, 0xfe, 0x10, 0xfe };
char keepalive = 0xff;
char buf[BUFFERSIZE];
timeval_t timer;
int count = 0;
int len;
// First, I send a KeepAlive Byte to settle IR Tower...
mywrite(fd, &keepalive, 1);
usleep(20000);
rx_flush(fd);
timer_reset(&timer);
do {
if (__comm_debug) {
printf("writelen = %d\n", sizeof(msg));
hexdump("W", msg, sizeof(msg));
}
if (mywrite(fd, msg, sizeof(msg)) != sizeof(msg)) {
myperror("write");
exit(1);
}
count += len = nbread(fd, buf, BUFFERSIZE, 50);
if (len == sizeof(msg) && !memcmp(buf, msg, sizeof(msg)))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -