////////////////////////////////////////////////////////////////////////////// // // c-movado: Movado interface in C (Linux/Mac/Windows) // version 1.1 (August 31, 2009) // // (C) Hideki Kozima (xkozima@myu.ac.jp), subject to GPLv2 // //////////////////////////////////////////////////////////////////////// // // serial port interface // void com_init (char *dev); // void com_quit (); // void com_send (unsigned char *data, int n); // int com_rec_byte (unsigned char *data); // void com_send_byte (unsigned char data); #ifdef _WIN32 // Windows #include #include HANDLE ComFH; // file handle void com_error (char *func, char *mess) { fprintf(stderr, "*** com_%s: %s\n", func, mess); fprintf(stderr, "Press ENTER to exit: "); fflush(stderr); getchar(); exit(1); } void com_init (char *dev) { DCB dcb; // device settings COMMTIMEOUTS t_out; // timeout settings int ret; // open serial port ComFH = CreateFile(dev, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); if (ComFH == INVALID_HANDLE_VALUE) com_error("init", "cannot CreateFile"); // set attribute (baud, etc.) FillMemory(&dcb, sizeof(dcb), 0); dcb.DCBlength = sizeof(dcb); ret = BuildCommDCB("38400,n,8,1", &dcb); if (ret == 0) com_error("init", "cannot BuildCommDCB"); dcb.fRtsControl = RTS_CONTROL_DISABLE; ret = SetCommState(ComFH, &dcb); if (ret == 0) com_error("init", "cannot SetCommState"); // set timeout (500ms) t_out.ReadIntervalTimeout = MAXDWORD; t_out.ReadTotalTimeoutMultiplier = MAXDWORD; t_out.ReadTotalTimeoutConstant = 500; t_out.WriteTotalTimeoutMultiplier = MAXDWORD; t_out.WriteTotalTimeoutConstant = 500; ret = SetCommTimeouts(ComFH, &t_out); if (ret == 0) com_error("init", "cannot SetCommTimeouts"); } void com_quit () { int ret; ret = CloseHandle(ComFH); if (ret == 0) com_error("quit", "cannot CloseHandle"); } void com_send (unsigned char *data, int n) { int ret; DWORD n_done; ret = WriteFile(ComFH, data, n, &n_done, NULL); if (ret == 0) com_error("send", "cannot WriteFile"); if ((int) n_done < n) { // still some data to send Sleep(10); com_send(data + n_done, n - n_done); } } int com_rec_byte (unsigned char *data) { int ret; DWORD n_done; // read data from the port ret = ReadFile(ComFH, data, 1, &n_done, NULL); if (ret == 0) com_error("rec_byte", "cannot ReadFile"); // return 1 on success // return 0 on timeout return n_done; } // enf of Windows #else // Linux/Mac #include #include #include #include #include #include #include #include static int ComFD = -1; // file descriptor void com_error (char *func, char *mess) { fprintf(stderr, "*** com_%s: %s\n", func, mess); fprintf(stderr, "Press ENTER to exit: "); fflush(stderr); getchar(); exit(1); } void com_init (char *dev) { static struct termios termios_data; int ret; // open serial port ComFD = open(dev, O_RDWR | O_NOCTTY | O_NONBLOCK); if (ComFD < 0) com_error("init", "can't open the port"); // set attribute (settings and baud) ret = tcgetattr(ComFD, &termios_data); termios_data.c_iflag = 0; termios_data.c_oflag = 0; termios_data.c_lflag = 0; termios_data.c_cflag = CS8 | CREAD | CLOCAL; termios_data.c_cc[VMIN] = 0; // "read" byte by byte termios_data.c_cc[VTIME] = 5; // timeout 500ms ret = cfsetspeed(&termios_data, B38400); if (ret < 0) com_error("init", "cannot set speed"); ret = tcsetattr(ComFD, TCSANOW, &termios_data); if (ret < 0) com_error("init", "cannot set attribute"); // turn off "NONBOLCK" ret = fcntl(ComFD, F_SETFL, 0); if (ret < 0) com_error("init", "can't fcntl (to unset NONBLOCK)"); // flush input/output ret = tcflush(ComFD, TCIOFLUSH); if (ret < 0) com_error("init", "cannot flush"); } void com_quit () { int ret; // close the port ret = close(ComFD); if (ret < 0) com_error("quit", "cannot close the port"); } void com_send (unsigned char *data, int n) { int ret, ret_drain; // write data to the port ret = write(ComFD, data, n); if (ret < 0) com_error("send", "cannot write data to the port"); // drain out the write-buffer ret_drain = tcdrain(ComFD); if (ret_drain < 0) com_error("send", "cannot drain the data"); // incomplete? if (ret < n) { // still some data to send usleep(10000); com_send(data + ret, n - ret); } } int com_rec_byte (unsigned char *data) { int ret; // read data from the port ret = read(ComFD, data, 1); if (ret < 0) com_error("rec_byte", "cannot read byte from the port"); // return 1 on success // return 0 on timeout return ret; } // end of Linux/Mac #endif // // com_send_byte (for Linux/Mac/Windows) void com_send_byte (unsigned char data) { com_send(&data, 1); } ////////////////////////////////////////////////////////////////////////////// // // sending/receiving 6-byte sequences // void seq_send (unsigned char *sequence); // void seq_rec (unsigned char *sequence); void seq_send (unsigned char *sequence) { // set marker for "beginning-of-sequence" sequence[0] |= 0x80; // send a six-byte sequence com_send(sequence, 6); } void seq_rec (unsigned char *sequence) { int i; // find "beginning-of-sequence" do { com_rec_byte(&(sequence[0])); } while (sequence[0] < 0x80); // read the sequence body i = 1; while (i < 6) { com_rec_byte(&(sequence[i])); if (sequence[i] >= 0x80) { // unexpected restart sequence[0] = sequence[i]; i = 0; } i++; } } ////////////////////////////////////////////////////////////////////////////// // // sending/receiving 6-byte packets // void seq_send (unsigned char *packet); // void seq_rec (unsigned char *packet); void pac_send (int addr, int n, int inst, int quad) { unsigned char data[6]; data[0] = 0x80 | ((addr & 0x1f) << 2) | (n & 0x03); data[1] = ((inst & 0x07) << 4) | ((quad & 0x80000000)? 0x08: 0) | ((quad & 0x00800000)? 0x04: 0) | ((quad & 0x00008000)? 0x02: 0) | ((quad & 0x00000080)? 0x01: 0); data[2] = (quad >> 24) & 0x7f; data[3] = (quad >> 16) & 0x7f; data[4] = (quad >> 8) & 0x7f; data[5] = quad & 0x7f; seq_send(data); } void pac_rec (int *addr, int *n, int *inst, int *quad) { unsigned char data[6]; seq_rec(data); *addr = (data[0] & 0x7c) >> 2; *n = (data[0] & 0x03); *inst = (data[1] >> 4); *quad = ((data[2] | ((data[1] & 0x08)? 0x80: 0)) << 24) | ((data[3] | ((data[1] & 0x04)? 0x80: 0)) << 16) | ((data[4] | ((data[1] & 0x02)? 0x80: 0)) << 8) | ((data[5] | ((data[1] & 0x01)? 0x80: 0))); } // // pac_do: send a command packet, and // if needed, receive a returning packet void pac_do (int addr, int n, int inst, int *quad) { // send command pac_send(addr, n, inst, *quad); // receive response (if needed) if (inst >= 5 || ((inst == 4) && ((*quad) & 0x80000000))) pac_rec(&addr, &n, &inst, quad); } //////////////////////////////////////////////////////////////////////////////