?? boss.c
字號:
/****************************************************************************//* casio.c - CasioBoss - Version 2.00 *//**************************************************************************** * * 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; * Look at the file LICENSE for details *****************************************************************************/#include "boss.h"#include "readconf.h"/* * stuff for readconf */#define RCLINELEN 80#define RCFNAME "~/.casiorc"char rcfname[RCLINELEN] = RCFNAME;#define DEFAULTDB "~/.casiodb"#define NELEM(a) ((int)(sizeof(a) / sizeof((a)[0])))char line_str[RCLINELEN] = "/dev/ttyb", speed_str[RCLINELEN] = "9600", passwd_str[RCLINELEN] = "", parity_str[RCLINELEN] = "none", dbase_str[RCLINELEN] = DEFAULTDB, line_str_[RCLINELEN] = "/dev/ttyb", dbase_bak[RCLINELEN] = "";int bytelen, tflag = 0, debugmode = 0;const CONFIG casio_config[] = {/* kind tag refecence size delim flags */ {CF_INT, "bytelen", &bytelen, 0, NULL, 0, NULL}, {CF_INT, "debug", &debugmode, 0, NULL, 0, NULL}, {CF_STRING, "line", line_str, RCLINELEN, NULL, 0, NULL}, {CF_STRING, "speed", speed_str, RCLINELEN, NULL, 0, NULL}, {CF_STRING, "passwd", passwd_str, RCLINELEN, NULL, 0, NULL}, {CF_STRING, "parity", parity_str, RCLINELEN, NULL, 0, NULL}, {CF_STRING, "dbase", dbase_str, RCLINELEN, NULL, 0, NULL},};/* * variables for getopt */extern char *optarg;extern int optind;int ch;char *tilde_expand_filename(const char *filename, uid_t my_uid);#ifndef __i386__#define swapl(x) \ ((x & 0xff000000U) >> 24) | \ ((x & 0x00ff0000U) >> 8) | \ ((x & 0x0000ff00U) << 8) | \ ((x & 0x000000ffU) << 24)#define swaps(x) \ ((x & 0xff00) >> 8) | \ ((x & 0x00ff) << 8)#define ntohl(x) swapl(x)#define ntohs(x) swaps(x)#define htonl(x) swapl(x)#define htons(x) swaps(x)#define NTOHL(x) (x) = ntohl((u_long)x)#define NTOHS(x) (x) = ntohs((u_short)x)#define HTONL(x) (x) = htonl((u_long)x)#define HTONS(x) (x) = htons((u_short)x)#endif/* * global variables: */char *version = "2.1";char *hello = "\nCASIO interface program Solaris 2.x , Sunos4.x, Sunos5.x and Linux v. %s\n\n";char *info = "\This program is a backup and restore utility for a CASIO digital diary.\n\\n\The syntax is:\n\\n\CASIO <-r|-w> [-l <commport>] [-s <baudrate>] [-p <parity] [-b <bytelength] [-o <file>] [-t]\n\\n\ -r|-w: The direction of the data transfer. -r is used for reading\n\ data from the CASIO to the PC. -w for the opposite direction.\n\\n\ commport: The PC's serial port that has to be used. Specify as COM1,\n\ COM2,COM3 or COM4 or simply as 1,2,3 or 4. For Solaris and \n\ specify TTYA or TTYB or simply as A or B.\n\\n\ baudrate: Either 2400, 4800 or 9600 must be specified. Note that not\n\ all communication speeds are supported by all CASIO's.\n\\n\ parity: none, odd, even. (even - Not used at the moment!!!)\n\\n\ bytelength: The number of bits transfered for one Byte, 7 or 8 are valid values\n\\n\ file: The name of the file where the backup data are to be written\n\ to or read from.\n\\n\The other communication parameters on the CASIO have to be set to 8N1 \n\\n\\n\The layout of the used file is not directly in a readable format since\n\all data records as needed for the CASIO are not really processed into\n\a convenient format. The file data are used for backup/restore purposes\n\only and should not be edited.\n\\n\CAUTION: Do not interface the CASIO directly to the PC's serial port, since\n\ this may cause permanent damage to the CASIO. Always use the\n\ circuit as described in circuit*.gif. It contains level converters\n\ for converting the +12/-12 Volts levels on the PC side to the\n\ +5/0 Volts levels that the CASIO uses.\n\\n\ Also keep in mind that the Secret Area of the CASIO has to be\n\ backuped/restored separate.\n\\n";CasioHeader CHeader;Header MHeader;int Port;unsignedint Record;int NOCHECK = 0;int blkflg;byte DataBuffer[512], WBuffer[1024], Direction = READ;byte nbytes;byte Stopped;byte LastRead, WriteStatus;char buffer[20], bufin[20], out;/* * Defaultvalus for communication parameters */tcflag_t speed = B9600, bytel = CS8, parity = PARENB;static struct termios term;static struct termios save_stdin;static struct termios oldterm;FILE *dbg;FILE *data;FILE *casiofile;time_t now;struct tm *tmstruct;char tbuff[256];char deb[256];char dat[256];int err;main (int argc, char *argv[]){ Port = 0; /* * Expand ~ in rc filename to home path */ if (strcpy(rcfname, tilde_expand_filename(rcfname, getuid())) == NULL) { perror("tilde_expand_filename()"); exit(-1); } /* * Read rc file in home dir */ if (read_config_file(argv[0], casio_config, NELEM(casio_config), rcfname) < 0) { perror(rcfname); exit(-1); } /* * Pars arguments */ while ((ch = getopt(argc, argv, "b:d:hl:s:o:p:rvwt")) != EOF) { switch(ch) { case 'b': bytelen = atoi(optarg); break; case 'd': debugmode = atoi(optarg); break; case 'l': strcpy(line_str, optarg); break; case 's': strcpy(speed_str, optarg); break; case 'o': strcpy(dbase_str, optarg); break; case 'p': strcpy(parity_str, optarg); UpperCase (parity_str); break; case 'r': Direction = READ; break; case 't': tflag++; break; case 'v': debugmode++; break; case 'w': Direction = WRITE; break; case 'h': default: fprintf (stderr, hello, version); fprintf (stderr, "%s", info); return (-1); } } dispose_config(argv[0], casio_config, NELEM(casio_config)); /* * Expand ~ in database filename to home path */ if (strcpy(dbase_str, tilde_expand_filename(dbase_str, getuid())) == NULL) { perror("tilde_expand_filename()"); exit(-1); } if (debugmode > 0) { printf("Settings:\n"); printf("=========\n\n"); printf("line=%s\n", line_str); printf("speed=%s\n", speed_str); printf("parity=%s\n", parity_str); printf("bytelen=%d\n", bytelen); printf("dbase=%s\n", dbase_str); printf("debug level =%d\n", debugmode); printf("direction=%s\n", Direction?"Read From Casio":"Write to Casio"); printf("database file =%s\n", dbase_str); } if (debugmode == 6) { printf("\n Debug Level 6 is used only for printing setup info; change to something else\n\n"); exit(0); } time (&now); tmstruct = localtime (&now); strftime (tbuff, 10, ".%y%d%m", tmstruct); if (debugmode > 0) { strcpy (deb, "debug"); strcat (deb, tbuff); dbg = fopen (deb, "w"); } if (tflag) { strcpy (dat, "data"); strcat (dat, tbuff); data = fopen (dat, "w"); } /* * Read the COMM port that has to be used */ strcpy(line_str_, line_str); UpperCase (line_str);#if defined(Solaris2) || defined(Sunos) if (!strcmp (line_str, "COM1") || !strcmp (line_str, "1") || !strcmp (line_str, "TTYA") || !strcmp (line_str, "A")) strcpy(line_str, "/dev/ttya"); else if (!strcmp (line_str, "COM2") || !strcmp (line_str, "2") || !strcmp (line_str, "TTYB") || !strcmp (line_str, "B")) strcpy(line_str, "/dev/ttyb");#else if (!strcmp (line_str, "COM1") || !strcmp (line_str, "1")) strcpy(line_str, "/dev/ttyS0"); else if (!strcmp (line_str, "COM2") || !strcmp (line_str, "2")) strcpy(line_str, "/dev/ttyS1"); else if (!strcmp (line_str, "COM3") || !strcmp (line_str, "3")) strcpy(line_str, "/dev/ttyS2"); else if (!strcmp (line_str, "COM4") || !strcmp (line_str, "4")) strcpy(line_str, "/dev/ttyS3");#endif /* defined(Solaris2) and Sunos*/ else strcpy(line_str, line_str_); if (debugmode > 1) fprintf (dbg, "\nopened port %s...\n", line_str); if ((Port = open (line_str, O_RDWR)) < 0) { fprintf (stderr, "Unknown COM port %s\n", line_str); terminate (); } #if !defined(Solaris2) if ((signal (SIGINT, sig_catch)) == SIG_ERR) /* catch signals */ fprintf (stderr, "signal(SIGINT) error %d", err);#endif /* !defined(Solaris2) */ if ((signal (SIGQUIT, sig_catch)) == SIG_ERR) fprintf (stderr, "signal(SIGINT) error %d", err); if ((signal (SIGTERM, sig_catch)) == SIG_ERR) fprintf (stderr, "signal(SIGINT) error %d", err); /* even more error checking! */ /* should be terminal device - exit if not */ if (isatty (Port) == 0) { fprintf (stderr, "\nNot terminal device...\n"); terminate (); } /* get port attributes, store in oldterm */ if (tcgetattr (Port, &oldterm) < 0) { fprintf (stderr, "\ntcgetattr error..."); terminate (); } /* copy old into new; restore the old sometime when done */ term = oldterm; /* * Baudrate */ if (!strcmp (speed_str, "1200")) speed = B1200; else if (!strcmp (speed_str, "2400")) speed = B2400; else if (!strcmp (speed_str, "4800")) speed = B4800; else if (!strcmp (speed_str, "9600")) speed = B9600; else {printf ("\n ERROR: unrecognized speed >%s<\n",speed_str);exit(0);} /* * Parity */ UpperCase (parity_str); if (!strcmp (parity_str, "NONE")) term.c_cflag &= ~PARENB; else /* parity required */ { term.c_cflag |= PARENB; if (!strcmp (parity_str, "ODD")) term.c_cflag |= PARODD; else if (!strcmp (parity_str, "EVEN")) term.c_cflag &= ~PARODD; else {printf ("\n ERROR: unrecognized parity >%s<\n",parity_str);exit(0);} } /* * Bytelength */ if (bytelen == 7) bytel = CS7; else if (bytelen = 8) bytel = CS8; term.c_cflag &= ~CSIZE; term.c_cflag |= speed | CREAD | bytel | CLOCAL; cfsetispeed (&term, speed); cfsetospeed (&term, speed); /* set non-canonical mode */ term.c_lflag = 0; /* * Ignore bytes with parity errors and make terminal raw and dumb. */ term.c_iflag = 0; term.c_iflag |= IGNBRK; term.c_iflag |= IGNPAR; term.c_oflag &= ~OPOST; /* blocking read until 1 char arrives */ term.c_cc[VMIN] = 1; term.c_cc[VTIME] = 0; /* * Open the required file */ if (Direction == READ) { term.c_iflag |= IXOFF; term.c_cc[VSTART] = XON; term.c_cc[VSTOP] = XOFF; /* * Backup existing database file */ if ((casiofile = fopen (dbase_str, "rb")) != (FILE *) 0) { strcpy(dbase_bak, dbase_str); strcat(dbase_bak, ".bak"); if (debugmode > 1) fprintf(dbg, "Creating backup file %s...", dbase_bak); fclose(casiofile); if (rename(dbase_str, dbase_bak) != 0) { fprintf (stderr, "Cannot rename file %s to %s\n", dbase_str, dbase_bak); terminate (); } if (debugmode > 1) fprintf(dbg, " done\n"); } if ((casiofile = fopen (dbase_str, "wb")) == (FILE *) 0) { fprintf (stderr, "Cannot create output file %s\n", dbase_str); terminate (); } } else { if ((casiofile = fopen (dbase_str, "rb")) == (FILE *) 0) { fprintf (stderr, "Cannot open input file %s\n", dbase_str); terminate (); } } /* now clean the serial line and activate the settings for casio */ tcflush (Port, TCIOFLUSH); if (tcsetattr (Port, TCSAFLUSH, &term) < 0) { fprintf (stderr, "\n failed to set port attr ... exiting \n"); terminate (); } Stopped = 0; WriteStatus = 0; LastRead = 0; fprintf (stdout, hello, version); /* set the stdin to cbreak mode */ tty_cbreak (STDIN_FILENO); while (!Stopped) { if (Direction == READ) { fprintf (stderr, "\nRead data from CASIO to file %s\n", dbase_str); if (debugmode > 1) fprintf (dbg, "\nRead data to file %s\n", dbase_str); WaitForCasio (); if (!Stopped) { fprintf (stderr, "Casio is ready to send\n"); fprintf (stderr, "Hit ESC to terminate at any time \n"); } while (!Stopped) { if (debugmode > 1) fprintf (dbg, "\n++++++++++++++++++++++++++++++++++++++++++++\n"); ReadLine (); if (debugmode > 2) fprintf (dbg, "\nwriting mheader to casiofile: \n"); fwrite (&MHeader, sizeof (MHeader), 1, casiofile); if (debugmode > 1) fprintf (dbg, "\nwriting Databuffer to casiofile: \n"); fwrite (DataBuffer, 1, MHeader.nbytes + 1, casiofile); if (debugmode > 2) fprintf (dbg, "\ncalling display status\n"); DisplayStatus (); } if (debugmode > 2) fprintf (dbg, "\n =========> stopped =1? real=%d\n", Stopped); } else { fprintf (stderr, "\n\nWrite data from file %s to CASIO\n\n", dbase_str); fprintf (stderr, "Hit ESC to terminate at any time \n"); /* as a hack around the original dos code -- set the read to be non-blocking; establish connection; then set it back to block; this is because the very first time we start and try to read we block forever whereas the casio is waiting for a CR-LF pair */ blkflg |= O_NONBLOCK; if (fcntl (Port, F_SETFL, blkflg) < 0) { fprintf (stderr, "\nexiting ..\n"); terminate (); } WaitForCasio (); blkflg &= ~O_NONBLOCK; if (fcntl (Port, F_SETFL, blkflg) < 0) { fprintf (stderr, "\nexiting ..\n"); terminate (); } if (!Stopped) { fprintf (stderr, "Casio is ready to receive\n"); if (debugmode > 1) fprintf (dbg, "Casio is ready to receive\n"); } while (!Stopped) { WriteLine (casiofile); DisplayStatus (); } Stopped = 1; } } terminate ();}/* * W a i t F o r C a s i o * * Establish communication with the CASIO * by exchanging the CR-LF and ACK controls */voidWaitForCasio (){ byte i; if (Direction == READ) { while (!Stopped) { do { i = ReadByte (WAIT); } while (i != CR && !Stopped); if (Stopped) { terminate (); } i = ReadByte (WAIT); if (i == LF) { WriteByte (XON); WriteStatus = XON; return; } } } else { NOCHECK = 1; while (!Stopped) { if (debugmode > 2) fprintf (dbg, "Write: Wait for casio\n"); WriteByte (CR); WriteByte (LF); /* somehow this is needed;inter-byte write time; could probably set it in termios next time */ usleep (36000); if ((ReadByte (NOWAIT) == XON) || (WriteStatus == XON)) { return; } } NOCHECK = 0; }}/* * R e a d H e a d e r * * Read a record header from the CASIO */voidReadHeader (void){ /* * Wait until ':' */ if (debugmode > 2) fprintf (dbg, "\nReadheader waiting for a :\n"); do { CHeader.marker = ReadByte (WAIT); } while (CHeader.marker != ':' && !Stopped); if (debugmode > 2) fprintf (dbg, "\nReadheader got a :\n"); CHeader.nbytes = ((ReadByte (WAIT) & 0xff) << 8) | (ReadByte (WAIT) & 0xff); if (debugmode > 2) fprintf (dbg, "\nReadheader got nbytes %x \n", CHeader.nbytes); CHeader.type = ((ReadByte (WAIT) & 0xff) << 8) | (ReadByte (WAIT) & 0xff); if (debugmode > 2) fprintf (dbg, "\nReadheader got type %x \n", CHeader.type); CHeader.low = ((ReadByte (WAIT) & 0xff) << 8) | (ReadByte (WAIT) & 0xff); if (debugmode > 2) fprintf (dbg, "\nReadheader got low %x \n", CHeader.low); CHeader.high = ((ReadByte (WAIT) & 0xff) << 8) | (ReadByte (WAIT) & 0xff); if (debugmode > 2) fprintf (dbg, "\nReadheader got high %x \n", CHeader.high); /* * Casio header is read, now translate it * into something usefull */ MHeader.nbytes = (atoh (CHeader.nbytes >> 8) << 4) | atoh (CHeader.nbytes & 0xff); if (debugmode > 2) fprintf (dbg, "\nReadheader translated nbytes %x \n", MHeader.nbytes); MHeader.type = (atoh (CHeader.type >> 8) << 4) | atoh (CHeader.type & 0xff); if (debugmode > 1) fprintf (dbg, "\nReadheader: frame type %x \n", MHeader.type); MHeader.address = (atoh (CHeader.high >> 8) << 4) | atoh (CHeader.high & 0xff); MHeader.address *= 256; MHeader.address += (atoh (CHeader.low >> 8) << 4) | atoh (CHeader.low & 0xff); if (debugmode > 2) fprintf (dbg, "\nReadheader translated address %x \n", MHeader.address);}/*
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -