📄 iportai_linuxc_mstxrx.c
字号:
/* iPort/AI Asynchronous Communication Sample Application for Linux Version 2 - 19-JUN-06 Provided by MCC (Micro Computer Control Corporation) www.mcc-us.com This application supports the following I2C bus operations: 1. Master transmit 2. Master recieve 3. Master TxRx 4. Slave transmit 5. Slave recieve System requirements: 1. GCC (>=3.6) 2. User has write access to serial ports (more information below) 3. iPort/AI I2C Bus host adapter 4. Linux kernel 2.4 or newer Serial port information: Considerations and trouble shooting for using the serial port can be found in the file "serial_help.txt". How to compile this software: 1. Run "make clean" to remove any past compiled versions of this software 2. Run "make" to compile the software 3. Run the program by entering "./iPortAI_LinuxC_MSTxRx /dev/ttySn", where n is the number of the desired serial port (see "serial_help.txt" for more info) Example: ./iPortAI_LinuxC_MSTxRx /dev/ttyS0 Notes: This software operates asynchronously, meaning that operations can be initiated either by the software itself, or by incoming data. In addition, functions that perform master operations can be modified to avoid waiting for a reply, and return immediately, allowing the software to go about it's business and check for replies when it gets a chance. Slave commands are automatically detected and interpreted, without requiring the software to know anything about their happening (beyond some predefined routines to handle them). Because of this added flexibility, this method is recommended over the synchronous form, and is necessary for full operation as a slave. Also, this code uses software flow control. Hardware flow control would require a different configuration in configureSerial(), as well as the adjusted iPortAI_setFlow() call. Revision history: 19-JUN-06 Fixed incorrrect "reset" message - released version 2 02-JUN-06 First revision*///Minimum necessary header files#include <stdio.h> //Generic input/output#include <fcntl.h> //Modes and flags for IO#include <string.h> //String routines#include <termios.h> //Terminal control#include <sys/signal.h> //Operating system signals#include <sys/time.h> //Timer definitions//Function prototypesvoid configureSerial ();int writeSerial (char *);void handleReply (int);void identifySignal ();void printAction (char *);int validateAddress (char *);void iPortAI_reset ();void iPortAI_setFormat (int);void iPortAI_setFlow (int);void iPortAI_setAddress (char *);void iPortAI_selectSlave (char *);int iPortAI_open ();int iPortAI_close ();int iPortAI_MTx (char *);int iPortAI_MRx (int);int iPortAI_STx (char *s);int iPortAI_M_Send (char *, char *);int iPortAI_M_Recieve (char *, int);int iPortAI_M_SendRecieve (char *, char *, int);void iPortAI_S_Recieve ();void iPortAI_S_Send ();void configureWatchdog ();void handleWatchdog (int);void resetWatchdog ();//Watchdog variables#define WATCHDOG_FREQUENCY 10 //The frequency of the watchdog timer, in Hz#define WATCHDOG_TIMEOUT_COUNT 100 //The number of ticks before the watchdog announces a timeoutvolatile int WATCHDOG; //Global flag to enable/disable the watchdog timervolatile int TIMEOUT; //Global flag to determine if the watchdog timer announced a timeoutvolatile int wt; //Global watchdog timer counter//If the user doesn't supply a serial port when he/she runs the program,//this default port will be used.char DEFAULT_SERIAL_PORT[] = "/dev/ttyS0";//Global descriptor for the serial portint port_descriptor;//Global flag to announce when a signal is recievedvolatile int DATA_READY;//Space for the signal name and any accompanying data#define MAX_DATA_SIZE 255char sig[5] = {0, 0, 0, 0, 0};volatile char *data;char buffer[MAX_DATA_SIZE];volatile int bptr;//Space for the slave's datachar SLAVE_BUFFER_IN[MAX_DATA_SIZE];char SLAVE_BUFFER_OUT[4] = {'~', '0', '0', 0};//Handy defines#define ON 1#define OFF 0#define SOFTWARE 0#define HARDWARE 1#define HEX_ONLY 0#define ALLOW_ASCII 1//Main routineint main (int argc, char **argv) { //If the user supplied a serial port, use that, otherwise //use our predefined default. char *serial_port; if (argc > 1) serial_port = argv[1]; else serial_port = DEFAULT_SERIAL_PORT; printf("Using %s as our serial port.\n", serial_port); //Attempt to open the port for read+write access, without needing to //be a controlling terminal on the port. port_descriptor = open(serial_port, O_RDWR | O_NOCTTY); if (port_descriptor == -1) { printf("Failed to open %s for read+write access.\n", serial_port); return 1; } //Configure the serial port configureSerial(); //Configure the watchdog timer configureWatchdog(); //Configure the iPortAI iPortAI_reset(); iPortAI_setFlow(SOFTWARE); iPortAI_setFormat(HEX_ONLY); iPortAI_setAddress("70"); iPortAI_open(); //Select a slave, then send it four messages in a row iPortAI_selectSlave("4E"); iPortAI_MTx("~FF~12~44"); iPortAI_MTx("~00~67"); iPortAI_MTx("~FF~10~00~EC~E4~30"); iPortAI_MTx("~00"); //Send two messages to different slaves, using the high level wrapper iPortAI_M_Send("4E", "~77~17~27~88"); iPortAI_M_Send("40", "ASCII data!"); //Recieve a message from a slave, using the high level wrapper iPortAI_M_Recieve("4E", 2); //Send a message, then recieve a message from a slave in one step iPortAI_M_SendRecieve("4E", "~FF~FF~7C", 4); //Send a big message, then read a single byte char big[100]; int i; for (i = 0; i < 98; i++) big[i] = '+'; strcpy(&big[96], "~55"); big[99] = 0; iPortAI_M_SendRecieve("4E", big, 1); //All done! Close the iPort's connection to the I2C bus and //the operating systems serial port before we exit iPortAI_close(); close(port_descriptor); return 0;}/************************************************ Serial Port Communication Routines************************************************///Configure a serial port//Takes:// Nothing//Returns:// Nothingvoid configureSerial () { //Attach our handler to the IO signal struct sigaction sh; sh.sa_handler = handleReply; sh.sa_flags = 0; sh.sa_restorer = NULL; sigaction(SIGIO, &sh, NULL); //Tell the OS to let this process catch the IO signal fcntl(port_descriptor, F_SETOWN, getpid()); //Make the port descriptor asynchronous fcntl(port_descriptor, F_SETFL, FASYNC); //Read in the current port options struct termios options; tcgetattr(port_descriptor, &options); //Configure the port options.c_cflag = 0; //Clear all flags (if you don't, many bits options.c_iflag = 0; //must be cleared manually to ensure the options.c_oflag = 0; //correct mode is chosen) options.c_lflag = 0; options.c_cflag |= B19200; //baud rate: 19.2 kpbs options.c_cflag |= CS8; //8 data bits (no parity and 1 stop bit are default) options.c_cflag |= CREAD; //Enable the reciever options.c_cflag |= CLOCAL; //Set "local" mode options.c_iflag |= (IXON | IXOFF | IXANY); //Software flow control options.c_cc[VEOL] = 13; //CR byte options.c_cc[VEOL2] = 10; //LF byte options.c_cc[VSTART] = 17; //XON byte options.c_cc[VSTOP] = 19; //XOFF byte options.c_cc[VMIN] = 0; //No blocking options.c_cc[VTIME] = 0; //Store the new options tcflush(port_descriptor, TCIFLUSH); tcsetattr(port_descriptor, TCSANOW, &options);}//Write a string to the serial port//Takes:// buffer: char * - pointer to an array of characters (a string)//Returns:// 1 on success, 0 on failure//Notes:// Success does not mean the iPortAI recieved the string, just that// on this end things appear to have worked. Even if the iPortAI// is not connected this command will usually succeed.int writeSerial (char *buffer) { //Reset the buffers DATA_READY = 0; sig[0] = 0; data = buffer; bptr = 0; //Determine how many bytes are in the user's string int c = strlen(buffer); //Try to write to the port int bytes_written = write(port_descriptor, buffer, c); //If we succesfully wrote all of our buffer out, we succeeded if (bytes_written == c) return 1; else return 0;}//Handle data coming into the serial port//Takes:// status: int//Returns:// Nothing//Notes:// This function is called automatically when 1 or more bytes of data (a // chunk) is in the serial port buffer. This chunk could be nothing important,// it could be the start of a new message, or it could be extra data going// along with the last message.void handleReply (int status) { //This flag tells us if we're reading preliminary data up until a "/", or //if we're reading actual content static int read_prelim = 1; //Read the chunk into a temporary buffer char temp[MAX_DATA_SIZE]; int l = read(port_descriptor, temp, MAX_DATA_SIZE); //Append a null character to mark the end of the chunk temp[l] = 0; //Read past "filler" data (CR's, LF's, asterisks) at the beginning of the chunk. //If we're reading actual message data, however, we can't skip over asterisks, since //they might be part of an ASCII string we're being sent. char *reply = temp; if (!read_prelim) while ((*reply == 13 || *reply == 10) && *reply != 0) reply++; else while ((*reply == 13 || *reply == 10 || *reply == '*') && *reply != 0) reply++; //If the first non-filler byte is a "/", it's a new message //and we're done reading preliminary data int is_newmessage = 0; if (*reply == '/' && read_prelim == 1) { is_newmessage = 1; read_prelim = 0; } //Find the end of the chunk by finding the first filler character (will be //a CR or an LF, unless there's nothing to find, in which case we hit a null) int end_of_data = 0; while (reply[end_of_data] != 13 && reply[end_of_data] != 10 && reply[end_of_data] != 0) end_of_data++; //If the chunk is now empty, we don't have anything worth looking at if (reply[0] == 0) return; //If the chunk ended in a CR, it's the end of a message, and we need to set the //preliminary flag so the next read will know it's getting a brand new message. int is_messagedone = 0; if (reply[end_of_data] == 13) { is_messagedone = 1; read_prelim = 1; } //"reply" now holds the actual content that was sent to us. It might be nothing (if all //we were sent was filler data), it might be a message ("/MTC" or whatever), or it could //be extra data to be appended to whatever we read last (such as data coming from a slave //transfer). reply[end_of_data] = 0; l = end_of_data; //Copy this data into the permanent buffer. If it's a new message, we'll just overwrite //whatever is already in the buffer. If it's not a new message (ie. it's extra data //for the last chunk) just tack it on the end. if (is_newmessage) bptr = 0; strncpy(&buffer[bptr], reply, l + 1); bptr += l; //If this data concludes a message (we checked earlier), update //the global variables to point to the respective parts, and set the //ready flag. Also identify the message and print out some information. if (is_messagedone) { strncpy(sig, buffer, 4); data = buffer + 4; bptr = 0; DATA_READY = 1; sigrelse(SIGIO); //Release the signal manually identifySignal(); }}//Identify a signal.//Takes:// Nothing//Returns:// Nothing//Notes:// Most messages are handled with a simple output string. Slave messages, however, require// us to switch gears and act as a slave.void identifySignal () { printf("- "); if (!strcmp(sig, "/OCC")) printf("Open connection complete.\n");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -