/** * @brief s_open - open a serial port * * @param t_port -port number * * @return success/fail */ signed char s_open(char *t_port) { int x; char cmd[200]; if (fd) { S_ERROR("Port is already open\n"); return SERIAL_FAILED; } /* Check if serial port is used by other process */ /* NOTE: it is a bad idea to use lsof, but the alternative * is to write large amount of code.. */ sprintf(cmd, "lsof |grep %s 2>&1 >/dev/null", t_port); x = system(cmd); if (x == 0) { S_ERROR("device %s being used already?\n", t_port); sprintf(cmd, "lsof |grep %s", t_port); system(cmd); return SERIAL_FAILED; } fd = open(t_port, O_RDWR | O_NOCTTY); if (fd < 0) { S_ERROR("failed to open %s\n", t_port); perror(t_port); return SERIAL_FAILED; } strncpy((char *)port, t_port, 30); S_INFO("Serial port %s opend fine\n", port); return SERIAL_OK; }
/** * @brief Flush the serial port data * * @param rx_bytes return bytes that remains(TBD) * @param tx_bytes the bytes that are to be send(TBD) * * @return error/fail */ signed int s_flush(unsigned int *rx_bytes, unsigned int *tx_bytes) { int ret; if (!fd) { S_ERROR("terminal is not open!\n"); return SERIAL_FAILED; } ret = tcflush(fd, TCIFLUSH); if (ret < 0) { S_ERROR("failed to flush buffers2\n"); return SERIAL_FAILED; } S_INFO("Serial port %s flushed fine\n", port); return SERIAL_OK; }
/** * @brief s_read_remaining - get the remaining bytes (TBD) * * @return error or num bytes remaining */ signed int s_read_remaining(void) { if (!fd) { S_ERROR("terminal is not open!\n"); return SERIAL_FAILED; } /* Not implemented yet */ return (0); }
/** * @brief s_putc - put a character into serial port * * @param x - character to write * * @return character written or error */ signed int s_putc(char x) { int ret = 0; S_INFO("[%c] 0x%02x", x, (unsigned char)x); ret = s_write((unsigned char *)&x, 1); if (ret < 0) { S_ERROR("putc failed-%d\n", ret); return ret; } return x; }
/** * @brief s_read - serial port read * * @param p_buffer buffer * @param size buffer length * * @return bytes read if ok, else SERIAL_FAILED */ signed int s_read(unsigned char *p_buffer, unsigned long size) { int ret = 0; if (!fd) { S_ERROR("terminal is not open!\n"); return SERIAL_FAILED; } /* read entire chunk.. no giving up! */ newtio.c_cc[VMIN] = size; newtio.c_cc[VTIME] = VTIME_SET; ret = tcsetattr(fd, TCSANOW, &newtio); ret = read(fd, p_buffer, size); if (ret < 0) { S_ERROR("failed to read data\n"); return SERIAL_FAILED; } S_INFO("Serial read requested=%d, read=%d\n", size, ret); return ret; }
/** * @brief s_getc - get a character from serial port * * @return character read or error */ signed int s_getc(void) { unsigned char x = 0; int ret = 0; ret = s_read(&x, 1); if (ret < 0) { S_ERROR("getc failed-%d\n", ret); return ret; } S_INFO("[%c]%x", x, x); return x; }
/** * @brief s_write - write to serial port * * @param p_buffer - buffer pointer * @param size -size of buffer * * @return bytes wrote if ok, else SERIAL_FAILED */ signed int s_write(unsigned char *p_buffer, unsigned long size) { int ret = 0, ret1; if (!fd) { S_ERROR("terminal is not open!\n"); return SERIAL_FAILED; } ret = write(fd, p_buffer, size); if (ret < 0) { S_ERROR("failed to write data\n"); return SERIAL_FAILED; } /* Wait till it is emptied */ ret1 = tcdrain(fd); if (ret1 < 0) { S_ERROR("failed in datai drain\n"); perror(NULL); return ret1; } S_INFO("Serial wrote Requested=%ld wrote=%d\n", size, ret); return ret; }
static size_t ss_utf8_to_wc(const char *s, const size_t off, const size_t max_off, int *unicode_out, ss_t *s_unicode_error_out) { int encoding_errors = 0; const size_t csize = sc_utf8_to_wc(s, off, max_off, unicode_out, &encoding_errors); if (encoding_errors && s_unicode_error_out) { S_ERROR("broken UTF8"); set_encoding_errors(s_unicode_error_out, S_TRUE); } return csize; }
/** * @brief s_close - close the serial port * * @return sucess/fail */ signed char s_close(void) { int ret = 0; if (!fd) { S_ERROR("terminal is not open!\n"); return SERIAL_FAILED; } /* * To prevent switching modes before the last vestiges * of the data bits have been send, sleep a second. * This seems to be especially true for usb2serial * convertors.. it does look as if the data is buffered * at the usb2serial device itself and closing/changing * attribs before the final data is pushed is going to * kill the last bits which need to be send */ sleep(1); /* restore the old port settings */ ret = tcsetattr(fd, TCSANOW, &oldtio); if (ret < 0) { S_ERROR("failed to rest old settings\n"); return SERIAL_FAILED; } ret = tcflush(fd, TCIFLUSH); if (ret < 0) { S_ERROR("failed to flush serial file handle\n"); } ret = close(fd); fd = 0; if (ret < 0) { S_ERROR("failed to close serial file handle\n"); return SERIAL_FAILED; } S_INFO("Serial closed %s fine\n", port); return SERIAL_OK; }
/** * @brief s_configure - configure the serial port * * @param s_baud_rate -baudrate * @param s_parity -parity * @param s_stop_bits -num stop bits * @param s_data_bits -data bits * * @return -success/failure */ signed char s_configure(unsigned long s_baud_rate, unsigned char s_parity, unsigned char s_stop_bits, unsigned char s_data_bits) { int ret; if (!fd) { S_ERROR("terminal is not open!\n"); return SERIAL_FAILED; } /* save current port settings */ ret = tcgetattr(fd, &oldtio); if (ret < 0) { S_ERROR("failed to set get old attribs\n"); return SERIAL_FAILED; } /* get current settings, and modify as needed */ ret = tcgetattr(fd, &newtio); if (ret < 0) { S_ERROR("failed to get current attribs\n"); return SERIAL_FAILED; } switch (s_baud_rate) { case 57600: s_baud_rate = B57600; break; case 115200: s_baud_rate = B115200; break; /* Add other baudrates - see /usr/include/bits/termios.h */ default: S_ERROR("Unknown baudrate %d\n", (unsigned int)s_baud_rate); return SERIAL_FAILED; } cfsetospeed(&newtio, s_baud_rate); cfsetispeed(&newtio, s_baud_rate); newtio.c_cflag &= ~(CS5 | CS6 | CS7 | CS8); switch (s_data_bits) { case 5: newtio.c_cflag |= CS5; break; case 6: newtio.c_cflag |= CS6; break; case 7: newtio.c_cflag |= CS7; break; case 8: newtio.c_cflag |= CS8; break; default: S_ERROR("unknown data bit %d\n", s_data_bits); return SERIAL_FAILED; } switch (s_stop_bits) { case ONE_STOP_BIT: newtio.c_cflag &= ~CSTOPB; break; case TWO_STOP_BIT: newtio.c_cflag |= CSTOPB; break; default: S_ERROR("unknown stop bit %d\n", s_stop_bits); return SERIAL_FAILED; } newtio.c_cflag &= ~(PARENB | PARODD); newtio.c_iflag &= ~(IGNPAR); switch (s_parity) { case ODDPARITY: /* odd */ newtio.c_cflag |= PARENB | PARODD; newtio.c_iflag |= IGNPAR; break; case EVENPARITY: /* even */ newtio.c_cflag |= PARENB; newtio.c_iflag = 0; break; case NOPARITY: /* none */ break; default: S_ERROR("unknown parity %d", s_parity); return SERIAL_FAILED; } newtio.c_iflag |= IGNBRK; newtio.c_cflag |= CLOCAL | CREAD; S_INFO("c_cflag: 0x%08x\n", (unsigned int)(newtio.c_cflag)); newtio.c_oflag = 0; /* set input mode (non-canonical, no echo,...) */ newtio.c_lflag = 0; newtio.c_cc[VTIME] = VTIME_SET; newtio.c_cc[VMIN] = 1; newtio.c_cc[VSWTC] = 0; ret = tcflush(fd, TCIFLUSH); if (ret < 0) { S_ERROR("failed to set flush buffers\n"); return SERIAL_FAILED; } ret = tcsetattr(fd, TCSANOW, &newtio); if (ret < 0) { S_INFO("tcsetattr -> %s (%d) fd=%d", strerror(errno), ret, fd); S_ERROR("failed to set new attribs\n"); return SERIAL_FAILED; } S_INFO("Serial port %s configured fine\n", port); return SERIAL_OK; }
static ss_t *aux_replace(ss_t **s, const sbool_t cat, const ss_t *src, const size_t off, const ss_t *s1, const ss_t *s2) { ASSERT_RETURN_IF(!s, ss_void); if (!s1) s1 = ss_void; if (!s2) s2 = ss_void; if (!src) src = ss_void; const size_t at = (cat && *s) ? sd_get_size(*s) : 0; const char *p0 = get_str_r(src), *p2 = get_str_r(s2); const size_t l1 = sd_get_size(s1), l2 = sd_get_size(s2); size_t i = off, l = sd_get_size(src); ss_t *out = NULL; ssize_t size_delta = l2 > l1 ? (ssize_t)(l2 - l1) : -(ssize_t)(l1 - l2); sbool_t aliasing = S_FALSE; size_t out_size = at + l; char *o, *o0; if (l2 >= l1) { /* resize required */ size_t nfound = 0; /* scan required size */ for (;; i+= l1, nfound++) if ((i = ss_find(src, i, s1)) == S_NPOS) break; if (nfound == 0) /* 0 occurrences: return */ return ss_check(s); if (size_delta >= 0) out_size += (size_t)size_delta * nfound; else out_size -= (size_t)(-size_delta) * nfound; /* allocate output string */ out = ss_alloc(out_size); if (!out) { S_ERROR("not enough memory"); sd_set_alloc_errors(*s); return ss_check(s); } o0 = o = get_str(out); /* copy prefix data (cat) */ if (at > 0) memcpy(o, get_str_r(*s), at); } else { if (s && *s && *s == src) { aliasing = S_TRUE; } else { if (ss_reserve(s, out_size) < out_size) /* BEHAVIOR */ return ss_check(s); } o0 = o = get_str(*s); } typedef void (*memcpy_t)(void *, const void *, size_t); memcpy_t f_cpy; if (aliasing) { f_cpy = (memcpy_t)memmove; } else { f_cpy = (memcpy_t)memcpy; o += at; if (off > 0) /* copy not affected data */ memcpy(o, p0, off); } o += off; size_t i_next = s1 == s2? S_NPOS : /* no replace */ ss_find(src, i + off, s1); for (i = off;;) { /* before match copy: */ if (i_next == S_NPOS) { f_cpy(o, p0 + i, l - i); o += (l - i); break; } f_cpy(o, p0 + i, i_next - i); o += (i_next - i); /* replace: */ f_cpy(o, p2, l2); o += l2; i = i_next + l1; /* prepare next search: */ i_next = ss_find(src, i, s1); } if (out) { ss_t *s_bck = *s; *s = out; ss_free(&s_bck); } set_size(*s, (size_t)(o - o0)); return *s; }
static ss_t *aux_toXcase(ss_t **s, const sbool_t cat, const ss_t *src, sint32_t (*towX)(sint32_t)) { ASSERT_RETURN_IF(!s, ss_void); if (!src) src = ss_void; const size_t ss = sd_get_size(src), sso_max = *s ? ss_get_max_size(*s) : 0; const char *ps = get_str_r(src); ss_t *out = NULL; const sbool_t aliasing = *s == src; unsigned char is_cached_usize = 0; ssize_t extra = sc_utf8_calc_case_extra_size(ps, 0, ss, towX); size_t cached_usize = 0, at; /* If possible, keep Unicode size cached: */ if (*s) { if (is_unicode_size_cached(*s) && is_unicode_size_cached(src)) { is_cached_usize = 1; cached_usize = get_unicode_size(src) + get_unicode_size(*s); } at = cat ? sd_get_size(*s) : 0; } else { /* copy */ if (is_unicode_size_cached(src)) { is_cached_usize = 1; cached_usize = get_unicode_size(src); } at = 0; } /* Check if it is necessary to allocate more memory: */ size_t sso_req = extra < 0 ? (at + ss - (size_t)(-extra)) : (at + ss + (size_t)extra); char *po0; if (!*s || sso_req > sso_max || (aliasing && extra > 0)) { if (*s && (*s)->ext_buffer) { /* BEHAVIOR */ S_ERROR("not enough memory: strings stored in the " "stored in fixed-length buffer can not be " "resized."); sd_set_alloc_errors(*s); return ss_check(s); } out = ss_alloc(sso_req); if (!out) { /* BEHAVIOR */ S_ERROR("not enough memory: can not " "change character case"); if (*s) sd_set_alloc_errors(*s); return ss_check(s); } char *pout = get_str(out); if (at > 0) /* cat */ memcpy(pout, get_str(*s), at); po0 = pout + at; } else { po0 = get_str(*s) + at; } /* Case conversion loop: */ size_t i = 0; int c = 0; char *po = po0, u8[SSU8_MAX_SIZE]; for (; i < ss;) { #ifdef S_ENABLE_UTF8_7BIT_PARALLEL_CASE_OPTIMIZATIONS unsigned *pou = (unsigned *)po; const size_t i2 = sc_parallel_toX(ps, i, ss, pou, towX); if (i != i2) { po += (i2 - i); i = i2; if (i >= ss) break; } #endif const size_t csize = ss_utf8_to_wc(ps, i, ss, &c, *s); const int c2 = towX(c); size_t csize2; if (c2 == c) { csize2 = csize; if (!aliasing) memcpy(po, ps + i, csize2); } else { csize2 = sc_wc_to_utf8(c2, u8, 0, SSU8_MAX_SIZE); memcpy(po, u8, csize2); } i += csize; po += csize2; } if (out) { /* Case of using a secondary string was required */ ss_t *s_bck = *s; *s = out; ss_free(&s_bck); } if (*s) { set_size(*s, sso_req); set_unicode_size_cached(*s, is_cached_usize); set_unicode_size(*s, cached_usize); } return ss_check(s); }