00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00026 # include <sys/select.h>
00027 # include <sys/param.h>
00028 # include <termios.h>
00029 typedef struct termios term_info;
00030 typedef struct {
00031 int fd;
00032 term_info tiOld;
00033 term_info tiNew;
00034 } serial_port_unix;
00035
00036
00037
00038 static const unsigned long int uiTimeoutStatic = 15000;
00039
00040 static unsigned long int uiTimeoutPerByte = 0;
00041
00042
00043 # define CCLAIMED 0x80000000
00044
00045 serial_port
00046 uart_open (const char *pcPortName)
00047 {
00048 serial_port_unix *sp = malloc (sizeof (serial_port_unix));
00049
00050 if (sp == 0)
00051 return INVALID_SERIAL_PORT;
00052
00053 sp->fd = open (pcPortName, O_RDWR | O_NOCTTY | O_NONBLOCK);
00054 if (sp->fd == -1) {
00055 uart_close (sp);
00056 return INVALID_SERIAL_PORT;
00057 }
00058
00059 if (tcgetattr (sp->fd, &sp->tiOld) == -1) {
00060 uart_close (sp);
00061 return INVALID_SERIAL_PORT;
00062 }
00063
00064 if (sp->tiOld.c_iflag & CCLAIMED) {
00065 uart_close (sp);
00066 return CLAIMED_SERIAL_PORT;
00067 }
00068
00069 sp->tiNew = sp->tiOld;
00070
00071 sp->tiNew.c_cflag = CS8 | CLOCAL | CREAD;
00072 sp->tiNew.c_iflag = CCLAIMED | IGNPAR;
00073 sp->tiNew.c_oflag = 0;
00074 sp->tiNew.c_lflag = 0;
00075
00076 sp->tiNew.c_cc[VMIN] = 0;
00077 sp->tiNew.c_cc[VTIME] = 0;
00078
00079 if (tcsetattr (sp->fd, TCSANOW, &sp->tiNew) == -1) {
00080 uart_close (sp);
00081 return INVALID_SERIAL_PORT;
00082 }
00083
00084 tcflush (sp->fd, TCIFLUSH);
00085 return sp;
00086 }
00087
00099 #define UART_BAUDRATE_T0_BYTE_DURATION(X) ((1000000 * 10)/ X)
00100
00101 void
00102 uart_set_speed (serial_port sp, const uint32_t uiPortSpeed)
00103 {
00104
00105 uiTimeoutPerByte = UART_BAUDRATE_T0_BYTE_DURATION(uiPortSpeed);
00106 DBG ("Serial port speed requested to be set to %d bauds (%lu µs).", uiPortSpeed, uiTimeoutPerByte);
00107 const serial_port_unix *spu = (serial_port_unix *) sp;
00108
00109
00110
00111 speed_t stPortSpeed = B9600;
00112 switch (uiPortSpeed) {
00113 case 9600:
00114 stPortSpeed = B9600;
00115 break;
00116 case 19200:
00117 stPortSpeed = B19200;
00118 break;
00119 case 38400:
00120 stPortSpeed = B38400;
00121 break;
00122 # ifdef B57600
00123 case 57600:
00124 stPortSpeed = B57600;
00125 break;
00126 # endif
00127 # ifdef B115200
00128 case 115200:
00129 stPortSpeed = B115200;
00130 break;
00131 # endif
00132 # ifdef B230400
00133 case 230400:
00134 stPortSpeed = B230400;
00135 break;
00136 # endif
00137 # ifdef B460800
00138 case 460800:
00139 stPortSpeed = B460800;
00140 break;
00141 # endif
00142 default:
00143 ERR ("Unable to set serial port speed to %d bauds. Speed value must be one of those defined in termios(3).",
00144 uiPortSpeed);
00145 return;
00146 };
00147
00148
00149 cfsetispeed ((struct termios *) &(spu->tiNew), stPortSpeed);
00150 cfsetospeed ((struct termios *) &(spu->tiNew), stPortSpeed);
00151 if (tcsetattr (spu->fd, TCSADRAIN, &(spu->tiNew)) == -1) {
00152 ERR ("%s", "Unable to apply new speed settings.");
00153 }
00154 }
00155
00156 uint32_t
00157 uart_get_speed (serial_port sp)
00158 {
00159 uint32_t uiPortSpeed = 0;
00160 const serial_port_unix *spu = (serial_port_unix *) sp;
00161 switch (cfgetispeed (&spu->tiNew)) {
00162 case B9600:
00163 uiPortSpeed = 9600;
00164 break;
00165 case B19200:
00166 uiPortSpeed = 19200;
00167 break;
00168 case B38400:
00169 uiPortSpeed = 38400;
00170 break;
00171 # ifdef B57600
00172 case B57600:
00173 uiPortSpeed = 57600;
00174 break;
00175 # endif
00176 # ifdef B115200
00177 case B115200:
00178 uiPortSpeed = 115200;
00179 break;
00180 # endif
00181 # ifdef B230400
00182 case B230400:
00183 uiPortSpeed = 230400;
00184 break;
00185 # endif
00186 # ifdef B460800
00187 case B460800:
00188 uiPortSpeed = 460800;
00189 break;
00190 # endif
00191 }
00192
00193 return uiPortSpeed;
00194 }
00195
00196 void
00197 uart_close (const serial_port sp)
00198 {
00199 if (((serial_port_unix *) sp)->fd >= 0) {
00200 tcsetattr (((serial_port_unix *) sp)->fd, TCSANOW, &((serial_port_unix *) sp)->tiOld);
00201 close (((serial_port_unix *) sp)->fd);
00202 }
00203 free (sp);
00204 }
00205
00211 int
00212 uart_receive (serial_port sp, byte_t * pbtRx, size_t * pszRx)
00213 {
00214 int res;
00215 int byteCount;
00216 fd_set rfds;
00217
00218 int iExpectedByteCount = (int)*pszRx;
00219 DBG ("iExpectedByteCount == %d", iExpectedByteCount);
00220 struct timeval tvTimeout = {
00221 .tv_sec = 0,
00222 .tv_usec = uiTimeoutStatic + (uiTimeoutPerByte * iExpectedByteCount),
00223 };
00224 struct timeval tv = tvTimeout;
00225
00226
00227 *pszRx = 0;
00228 do {
00229
00230 FD_ZERO (&rfds);
00231 FD_SET (((serial_port_unix *) sp)->fd, &rfds);
00232 res = select (((serial_port_unix *) sp)->fd + 1, &rfds, NULL, NULL, &tv);
00233
00234
00235 if (res < 0) {
00236 DBG ("%s", "RX error.");
00237 return DEIO;
00238 }
00239
00240 if (res == 0) {
00241 if (*pszRx == 0) {
00242
00243
00244 return DETIMEOUT;
00245 } else {
00246
00247 return 0;
00248 }
00249 }
00250
00251 res = ioctl (((serial_port_unix *) sp)->fd, FIONREAD, &byteCount);
00252 if (res < 0) {
00253 return DEIO;
00254 }
00255
00256 res = read (((serial_port_unix *) sp)->fd, pbtRx + (*pszRx), MIN(byteCount, iExpectedByteCount));
00257 iExpectedByteCount -= MIN (byteCount, iExpectedByteCount);
00258
00259
00260 if (res <= 0) {
00261 return DEIO;
00262 }
00263
00264 *pszRx += res;
00265
00266 tv.tv_usec = uiTimeoutPerByte * MIN( iExpectedByteCount, 16 );
00267
00268 } while (byteCount && (iExpectedByteCount > 0));
00269 DBG ("byteCount == %d, iExpectedByteCount == %d", byteCount, iExpectedByteCount);
00270 return 0;
00271 }
00272
00278 int
00279 uart_send (serial_port sp, const byte_t * pbtTx, const size_t szTx)
00280 {
00281 int32_t res;
00282 size_t szPos = 0;
00283 fd_set rfds;
00284 struct timeval tvTimeout = {
00285 .tv_sec = 0,
00286 .tv_usec = uiTimeoutStatic + (uiTimeoutPerByte * szTx),
00287 };
00288 struct timeval tv = tvTimeout;
00289
00290 while (szPos < szTx) {
00291
00292 FD_ZERO (&rfds);
00293 FD_SET (((serial_port_unix *) sp)->fd, &rfds);
00294 res = select (((serial_port_unix *) sp)->fd + 1, NULL, &rfds, NULL, &tv);
00295
00296
00297 if (res < 0) {
00298 DBG ("%s", "TX error.");
00299 return DEIO;
00300 }
00301
00302 if (res == 0) {
00303 DBG ("%s", "TX time-out.");
00304 return DETIMEOUT;
00305 }
00306
00307 res = write (((serial_port_unix *) sp)->fd, pbtTx + szPos, szTx - szPos);
00308
00309
00310 if (res <= 0) {
00311 return DEIO;
00312 }
00313
00314 szPos += res;
00315
00316
00317 tv.tv_usec = uiTimeoutStatic + uiTimeoutPerByte * MIN( szTx - szPos, 16 );
00318 }
00319 return 0;
00320 }
00321