diff options
author | Pablo Neira Ayuso <pablo@gnumonks.org> | 2012-03-17 12:20:49 +0100 |
---|---|---|
committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2012-04-04 19:08:27 +0200 |
commit | 729a0917ac17e2c5a70ab24cc884ff68a7df52af (patch) | |
tree | b6fab3d56abfcdf4af2ac7504271aef3940aefa8 | |
parent | 163707ba12dc7cee520eee88b4f1d4dad2c20049 (diff) |
add rs232 support
This include an example to open /dev/ttyACM0 to receive data from
u-blox GPS and one to configure it in TIMEPULSE2 mode.
-rw-r--r-- | examples/Makefile.am | 8 | ||||
-rw-r--r-- | examples/rs232-read.c | 92 | ||||
-rw-r--r-- | examples/rs232-write.c | 386 | ||||
-rw-r--r-- | include/osmocom/netif/rs232.h | 21 | ||||
-rw-r--r-- | src/Makefile.am | 1 | ||||
-rw-r--r-- | src/rs232.c | 272 |
6 files changed, 780 insertions, 0 deletions
diff --git a/examples/Makefile.am b/examples/Makefile.am index c9849db..1063245 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -10,6 +10,8 @@ noinst_PROGRAMS = ipa-stream-client \ lapd-over-datagram-network \ stream-client \ stream-server \ + rs232-read \ + rs232-write \ rtp-udp-test-client \ rtp-udp-test-server @@ -39,6 +41,12 @@ stream_server_SOURCES = stream-server.c stream_server_LDADD = $(top_builddir)/src/libosmonetif.la \ $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) +rs232_read_SOURCES = rs232-read.c +rs232_read_LDADD = $(top_builddir)/src/libosmonetif.la $(LIBOSMOCORE_LIBS) + +rs232_write_SOURCES = rs232-write.c +rs232_write_LDADD = $(top_builddir)/src/libosmonetif.la $(LIBOSMOCORE_LIBS) + rtp_udp_test_client_SOURCES = rtp-udp-test-client.c rtp_udp_test_client_LDADD = $(top_builddir)/src/libosmonetif.la \ $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) diff --git a/examples/rs232-read.c b/examples/rs232-read.c new file mode 100644 index 0000000..8aeb6f8 --- /dev/null +++ b/examples/rs232-read.c @@ -0,0 +1,92 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <osmocom/core/select.h> +#include <osmocom/core/talloc.h> +#include <osmocom/core/msgb.h> +#include <osmocom/core/logging.h> +#include <osmocom/core/application.h> + +#include <osmocom/netif/rs232.h> + +#define DRS232TEST 0 + +struct log_info_cat osmo_rs232_test_cat[] = { + [DRS232TEST] = { + .name = "DRS232TEST", + .description = "rs232 test", + .color = "\033[1;35m", + .enabled = 1, .loglevel = LOGL_DEBUG, + }, +}; + +const struct log_info osmo_rs232_test_log_info = { + .filter_fn = NULL, + .cat = osmo_rs232_test_cat, + .num_cat = ARRAY_SIZE(osmo_rs232_test_cat), +}; + +static struct osmo_rs232 *r; + +void sighandler(int foo) +{ + LOGP(DRS232TEST, LOGL_NOTICE, "closing rs232.\n"); + osmo_rs232_close(r); + osmo_rs232_destroy(r); + exit(EXIT_SUCCESS); +} + +static int read_cb(struct osmo_rs232 *r) +{ + struct msgb *msg; + + LOGP(DRS232TEST, LOGL_DEBUG, "received data from rs232\n"); + + msg = msgb_alloc(1024, "rs232/test"); + if (msg == NULL) { + LOGP(DRS232TEST, LOGL_ERROR, "cannot allocate message\n"); + return 0; + } + if (osmo_rs232_read(r, msg) < 0) { + LOGP(DRS232TEST, LOGL_ERROR, "cannot read from rs232\n"); + return 0; + } + LOGP(DRS232TEST, LOGL_DEBUG, "received %d bytes\n", msg->len); + + printf("%s", msg->data); + + msgb_free(msg); + return 0; +} + +static void *tall_test; + +int main(void) +{ + tall_test = talloc_named_const(NULL, 1, "osmo_rs232_test"); + + osmo_init_logging(&osmo_rs232_test_log_info); + log_set_log_level(osmo_stderr_target, LOGL_NOTICE); + + r = osmo_rs232_create(tall_test); + if (r == NULL) { + LOGP(DRS232TEST, LOGL_ERROR, "cannot create rs232 object\n"); + exit(EXIT_FAILURE); + } + osmo_rs232_set_serial_port(r, "/dev/ttyACM0"); + osmo_rs232_set_baudrate(r, 9600); + osmo_rs232_set_read_cb(r, read_cb); + + if (osmo_rs232_open(r) < 0) { + LOGP(DRS232TEST, LOGL_ERROR, "cannot open rs232\n"); + exit(EXIT_FAILURE); + } + + LOGP(DRS232TEST, LOGL_NOTICE, "Entering main loop\n"); + + while(1) { + osmo_select_main(0); + } +} diff --git a/examples/rs232-write.c b/examples/rs232-write.c new file mode 100644 index 0000000..370bd12 --- /dev/null +++ b/examples/rs232-write.c @@ -0,0 +1,386 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <arpa/inet.h> +#include <unistd.h> + +#include <osmocom/core/select.h> +#include <osmocom/core/talloc.h> +#include <osmocom/core/msgb.h> +#include <osmocom/core/logging.h> +#include <osmocom/core/application.h> + +#include <osmocom/netif/rs232.h> + +#define DRS232TEST 0 + +struct log_info_cat osmo_rs232_test_cat[] = { + [DRS232TEST] = { + .name = "DRS232TEST", + .description = "rs232 test", + .color = "\033[1;35m", + .enabled = 1, .loglevel = LOGL_DEBUG, + }, +}; + +const struct log_info osmo_rs232_test_log_info = { + .filter_fn = NULL, + .cat = osmo_rs232_test_cat, + .num_cat = ARRAY_SIZE(osmo_rs232_test_cat), +}; + +static struct osmo_rs232 *r; + +void sighandler(int foo) +{ + LOGP(DRS232TEST, LOGL_NOTICE, "closing rs232.\n"); + osmo_rs232_close(r); + osmo_rs232_destroy(r); + exit(EXIT_SUCCESS); +} + +static int read_cb(struct osmo_rs232 *r) +{ + struct msgb *msg; + + LOGP(DRS232TEST, LOGL_DEBUG, "received data from rs232\n"); + + msg = msgb_alloc(1024, "rs232/test"); + if (msg == NULL) { + LOGP(DRS232TEST, LOGL_ERROR, "cannot allocate message\n"); + return 0; + } + if (osmo_rs232_read(r, msg) < 0) { + LOGP(DRS232TEST, LOGL_ERROR, "cannot receive message\n"); + return 0; + } + LOGP(DRS232TEST, LOGL_DEBUG, "received %d bytes\n", msg->len); + + printf("received %d bytes ", msg->len); + + int i; + printf("("); + for (i=0; i<msg->len; i++) + printf("\\x%.2x", 0xff & msg->data[i]); + printf(") %s\n", msg->data); + + msgb_free(msg); + + return 0; +} + +static void *tall_test; + +/* u-blox6_ReceiverDescriptionProtocolSpec_(GPS.G6-SW-10018).pdf */ + +/* See Sect 23. */ +struct ubx_hdr { + uint8_t sync_char1; /* 0xb5 */ + uint8_t sync_char2; /* 0x62 */ + uint8_t class; + uint8_t id; +} __attribute__((packed)); + +static void ubx_header(struct msgb *msg, uint8_t class, uint8_t id) +{ + /* See Sect. 31.24 */ + struct ubx_hdr ubxhdr = { + .sync_char1 = 0xb5, + .sync_char2 = 0x62, + .class = class, + .id = id, + }; + memcpy(msg->data, &ubxhdr, sizeof(struct ubx_hdr)); + msgb_put(msg, sizeof(struct ubx_hdr)); +} + +/* See Sect 26. */ +static void ubx_checksum(struct msgb *msg, uint8_t *ck) +{ + struct ubx_hdr *ubxhdr = (struct ubx_hdr *)msg->data; + /* skip sync chars in checksum calculation. */ + uint8_t *buf = ((uint8_t *)ubxhdr) + 2; + int i; + + memset(ck, 0, sizeof(uint16_t)); + + for (i=0; i<msg->len-2; i++) { + ck[0] += buf[i]; + ck[1] += ck[0]; + } +} + +# if __BYTE_ORDER == __LITTLE_ENDIAN +# define utohl(x) (x) +# define utohs(x) (x) +# define htoul(x) (x) +# define htous(x) (x) +# else +# if __BYTE_ORDER == __BIG_ENDIAN +# define utohl(x) __bswap_32 (x) +# define utohs(x) __bswap_16 (x) +# define htoul(x) __bswap_32 (x) +# define htous(x) __bswap_16 (x) +# endif +# endif + +static void ubx_payload_start(struct msgb *msg) +{ + uint16_t len = 0; + /* make room for payload length. */ + memcpy(msg->data + msg->len, &len, sizeof(len)); + msgb_put(msg, sizeof(len)); +} + +static void ubx_payload_put_u8(struct msgb *msg, uint8_t data) +{ + memcpy(msg->data + msg->len, &data, sizeof(data)); + msgb_put(msg, sizeof(data)); +} + +static void ubx_payload_put_le16(struct msgb *msg, uint16_t data) +{ + uint16_t le_data = htous(data); + memcpy(msg->data + msg->len, &le_data, sizeof(data)); + msgb_put(msg, sizeof(data)); +} + +static void ubx_payload_put_le32(struct msgb *msg, uint32_t data) +{ + uint32_t le_data = htoul(data); + memcpy(msg->data + msg->len, &le_data, sizeof(data)); + msgb_put(msg, sizeof(data)); +} + +static void ubx_payload_stop(struct msgb *msg) +{ + uint16_t *length = (uint16_t *) &(msg->data[4]); + uint8_t checksum[2]; + + /* length does not includes the header, ID, length. + * note that checksum has not been yet added. + */ + *length = htous(msg->len - 6); + + ubx_checksum(msg, checksum); + memcpy(msg->data + msg->len, checksum, sizeof(checksum)); + msgb_put(msg, sizeof(checksum)); +} + +static void cfg_prt(void) +{ + struct msgb *msg; + + msg = msgb_alloc(512, "CFG-PRT for USB"); + if (msg == NULL) + exit(EXIT_FAILURE); + + ubx_header(msg, 0x06, 0x00); /* CFG-PRT */ + + ubx_payload_start(msg); + ubx_payload_put_u8(msg, 0x03); /* Port ID is (=3 USB). */ + ubx_payload_put_u8(msg, 0x00); /* Reserved. */ + ubx_payload_put_le16(msg, 0x0000); /* TX ready. */ + ubx_payload_put_le32(msg, 0x00000000); /* Reserved. */ + ubx_payload_put_le32(msg, 0x00000000); /* Reserved. */ + ubx_payload_put_le16(msg, 0x0003); /* InProtoMask (NMEA+UBX). */ + ubx_payload_put_le16(msg, 0x0001); /* OutProtoMask (UBX). */ + ubx_payload_put_le16(msg, 0x0000); /* Flags. */ + ubx_payload_put_le16(msg, 0x0000); /* Reserved. */ + ubx_payload_stop(msg); + + int i; + for (i=0; i<msg->len; i++) + printf("\\x%.2x", 0xff & msg->data[i]); + printf("\n"); + + if (osmo_rs232_write(r, msg) < 0) { + LOGP(DRS232TEST, LOGL_ERROR, "cannot write to rs232\n"); + exit(EXIT_FAILURE); + } +} + +static int nmea_checksum(char *nmea_cmd, uint8_t *checksum) +{ + int i, ret = 0; + uint8_t from, to; + char *start, *end; + + /* find starting $ */ + start = strtok(nmea_cmd, "$"); + if (start == NULL) + return -1; + + from = start - nmea_cmd; + + end = strtok(start+1, "*"); + if (end == NULL) + return -1; + + to = end - nmea_cmd; + + ret = (uint8_t)nmea_cmd[0]; + for (i=from+1; i<to; i++) + ret ^= (uint8_t)nmea_cmd[i]; + + *checksum = ret; + + return 0; +} + +static void send_pubx(void) +{ + struct msgb *msg; + + /* See 21.8: UBX,41. + * + * $PUBX,41,portId,inProto,outProto,baudrate,autobauding*cs + * + * [in|out]Proto: bit = 0 (ubx), bit = 1 (nmea) + * + * Sect 4. Serial Communication Ports Description + * + * 0 DDC + * 1 UART1 + * 2 UART2 + * 3 USB + * 4 SPI + * 5 reserved + * + * The NMEA command below comes without the checksum calculated. + */ + char nmea_cmd[128] = "$PUBX,41,3,0001,0001,9600,0*"; + uint8_t checksum; + + if (nmea_checksum(nmea_cmd, &checksum) < 0) { + LOGP(DRS232TEST, LOGL_ERROR, "error calculating checksum\n"); + exit(EXIT_FAILURE); + } + sprintf(nmea_cmd + strlen(nmea_cmd), "%u\r\n", checksum); + + msg = msgb_alloc(300, "rs232/test"); + if (msg == NULL) { + LOGP(DRS232TEST, LOGL_ERROR, "cannot allocate message\n"); + exit(EXIT_FAILURE); + } + memcpy(msg->data, nmea_cmd, strlen(nmea_cmd)); + msgb_put(msg, strlen(nmea_cmd)); + + if (osmo_rs232_write(r, msg) < 0) { + LOGP(DRS232TEST, LOGL_ERROR, "cannot write to rs232\n"); + exit(EXIT_FAILURE); + } +} + +static void cfg_tp5(void) +{ + struct msgb *msg; + + msg = msgb_alloc(512, "CFG-TP5 for USB"); + if (msg == NULL) + exit(EXIT_FAILURE); + + ubx_header(msg, 0x06, 0x31); /* CFG-TP5 */ + + ubx_payload_start(msg); + ubx_payload_put_u8(msg, 0x01); /* TIMEPULSE2 (=1) */ + ubx_payload_put_u8(msg, 0x00); /* Reserved. */ + ubx_payload_put_le16(msg, 0x0000); /* Reserved. */ + ubx_payload_put_le16(msg, 0); /* Antenna Delay (ns) */ + ubx_payload_put_le16(msg, 0); /* RF Group Delay (ns) */ + ubx_payload_put_le32(msg, 8192000); /* freqPeriod (Hz/us) */ + ubx_payload_put_le32(msg, 8192000); /* freqPeriodLoc (Hz/us) */ + ubx_payload_put_le32(msg, 0x80000000); /* pulseLenRation: + 1/2^-32 (us() */ + ubx_payload_put_le32(msg, 0x80000000); /* pulseLenRationLock: + 1/2^-32 (us() */ + ubx_payload_put_le32(msg, 0); /* userConfigDelay (ns) */ + ubx_payload_put_le32(msg, (1 << 0) | (1 << 1) | (1 << 2) | (1 << 3)); + /* flags: bits 0, 1 and 3. */ + ubx_payload_stop(msg); + + int i; + for (i=0; i<msg->len; i++) + printf("\\x%.2x", 0xff & msg->data[i]); + printf("\n"); + + if (osmo_rs232_write(r, msg) < 0) { + LOGP(DRS232TEST, LOGL_ERROR, "cannot write to rs232\n"); + exit(EXIT_FAILURE); + } +} + +static int kbd_cb(struct osmo_fd *fd, unsigned int what) +{ + char buf[1024]; + int ret, val; + + ret = read(STDIN_FILENO, buf, sizeof(buf)); + if (ret < 0) { + LOGP(DRS232TEST, LOGL_ERROR, "cannot write to read from " + "keyboard\n"); + exit(EXIT_FAILURE); + } + + val = atoi(buf); + switch(val) { + case 1: + printf("sending command PUBX to switch to UBX mode\n"); + send_pubx(); + break; + case 2: + printf("sending command TP5\n"); + cfg_tp5(); + break; + case 3: + printf("sending command CFG-PRT\n"); + cfg_prt(); + break; + default: + printf("wrong option: select 1, 2 or 3\n"); + break; + } + return 0; +} + +int main(void) +{ + struct osmo_fd *kbd_ofd; + + tall_test = talloc_named_const(NULL, 1, "osmo_rs232_test"); + + osmo_init_logging(&osmo_rs232_test_log_info); + log_set_log_level(osmo_stderr_target, LOGL_NOTICE); + + r = osmo_rs232_create(tall_test); + if (r == NULL) { + LOGP(DRS232TEST, LOGL_ERROR, "cannot create rs232 object\n"); + exit(EXIT_FAILURE); + } + osmo_rs232_set_serial_port(r, "/dev/ttyACM0"); + osmo_rs232_set_baudrate(r, 9600); + osmo_rs232_set_delay_us(r, 3330); + osmo_rs232_set_read_cb(r, read_cb); + + if (osmo_rs232_open(r) < 0) { + LOGP(DRS232TEST, LOGL_ERROR, "cannot open rs232\n"); + exit(EXIT_FAILURE); + } + + LOGP(DRS232TEST, LOGL_NOTICE, "Entering main loop\n"); + + kbd_ofd = talloc_zero(tall_test, struct osmo_fd); + if (!kbd_ofd) { + LOGP(DRS232TEST, LOGL_ERROR, "OOM\n"); + exit(EXIT_FAILURE); + } + kbd_ofd->fd = STDIN_FILENO; + kbd_ofd->when = BSC_FD_READ; + kbd_ofd->data = NULL; + kbd_ofd->cb = kbd_cb; + osmo_fd_register(kbd_ofd); + + while(1) { + osmo_select_main(0); + } +} diff --git a/include/osmocom/netif/rs232.h b/include/osmocom/netif/rs232.h new file mode 100644 index 0000000..30bc52b --- /dev/null +++ b/include/osmocom/netif/rs232.h @@ -0,0 +1,21 @@ +#ifndef _OSMO_RS232_H_ +#define _OSMO_RS232_H_ + +struct osmo_rs232; + +struct osmo_rs232 *osmo_rs232_create(void *ctx); + +void osmo_rs232_set_serial_port(struct osmo_rs232 *, const char *serial_port); +void osmo_rs232_set_delay_us(struct osmo_rs232 *, int delay_us); +void osmo_rs232_set_baudrate(struct osmo_rs232 *, int baudrate); +void osmo_rs232_set_read_cb(struct osmo_rs232 *r, int (*read_cb)(struct osmo_rs232 *r)); + +int osmo_rs232_open(struct osmo_rs232 *r); + +int osmo_rs232_read(struct osmo_rs232 *r, struct msgb *msg); +int osmo_rs232_write(struct osmo_rs232 *r, struct msgb *msg); + +void osmo_rs232_close(struct osmo_rs232 *r); +void osmo_rs232_destroy(struct osmo_rs232 *r); + +#endif /* _OSMO_RS232_H_ */ diff --git a/src/Makefile.am b/src/Makefile.am index f29c40b..0a3d3db 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -15,5 +15,6 @@ libosmonetif_la_LIBADD = channel/libosmonetif-channel.la libosmonetif_la_SOURCES = channel.c \ datagram.c \ ipa.c \ + rs232.c \ rtp.c \ stream.c diff --git a/src/rs232.c b/src/rs232.c new file mode 100644 index 0000000..70aff46 --- /dev/null +++ b/src/rs232.c @@ -0,0 +1,272 @@ +/* T-Link interface using POSIX serial port */ + +/* (C) 2008-2011 by Harald Welte <laforge@gnumonks.org> + * + * All Rights Reserved + * + * Authors: Harald Welte <laforge@gnumonks.org> + * Pablo Neira Ayuso <pablo@gnumonks.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> +#include <string.h> +#include <termios.h> +#include <fcntl.h> +#include <limits.h> + +#include <osmocom/core/select.h> +#include <osmocom/core/msgb.h> +#include <osmocom/core/logging.h> +#include <osmocom/core/talloc.h> +#include <osmocom/abis/e1_input.h> + +struct osmo_rs232 { + struct osmo_fd ofd; + struct llist_head tx_queue; + + struct { + int (*read)(struct osmo_rs232 *); + } cb; + + /* sometimes we want to delay the transmission. */ + struct osmo_timer_list tx_timer; + + struct { + char serial_port[PATH_MAX]; + int baudrate; + unsigned int delay_us; + } cfg; +}; + +void rs232_tx_timer_cb(void *ptr) +{ + struct osmo_rs232 *r = ptr; + + /* we're again ready to transmit. */ + r->ofd.when |= BSC_FD_WRITE; +} + +static int handle_ser_write(struct osmo_fd *bfd) +{ + struct osmo_rs232 *r = bfd->data; + struct llist_head *lh; + struct msgb *msg; + int written; + + LOGP(DLINP, LOGL_DEBUG, "writing data to rs232\n"); + + if (llist_empty(&r->tx_queue)) { + r->ofd.when &= ~BSC_FD_WRITE; + return 0; + } + lh = r->tx_queue.next; + llist_del(lh); + msg = llist_entry(lh, struct msgb, list); + + written = write(bfd->fd, msg->data, msg->len); + if (written < msg->len) { + LOGP(DLINP, LOGL_ERROR, "rs232: short write\n"); + msgb_free(msg); + return -1; + } + msgb_free(msg); + + /* We've got more data to write, but we have to wait to make it. */ + if (!llist_empty(&r->tx_queue) && r->cfg.delay_us) { + r->ofd.when &= ~BSC_FD_WRITE; + osmo_timer_schedule(&r->tx_timer, 0, r->cfg.delay_us); + } + return 0; +} + +static int handle_ser_read(struct osmo_fd *bfd) +{ + struct osmo_rs232 *r = bfd->data; + + LOGP(DLINP, LOGL_DEBUG, "data to be read in rs232\n"); + + if (r->cb.read) + r->cb.read(r); + + return 0; +} + +static int serial_fd_cb(struct osmo_fd *bfd, unsigned int what) +{ + int rc = 0; + + if (what & BSC_FD_READ) + rc = handle_ser_read(bfd); + + if (rc < 0) + return rc; + + if (what & BSC_FD_WRITE) + rc = handle_ser_write(bfd); + + return rc; +} + +struct osmo_rs232 *osmo_rs232_create(void *ctx) +{ + struct osmo_rs232 *r; + + r = talloc_zero(ctx, struct osmo_rs232); + if (r == NULL) + return NULL; + + INIT_LLIST_HEAD(&r->tx_queue); + + return r; +} + +void osmo_rs232_set_serial_port(struct osmo_rs232 *r, char *serial_port) +{ + strncpy(r->cfg.serial_port, serial_port, PATH_MAX); + r->cfg.serial_port[PATH_MAX-1] = '\0'; +} + +void osmo_rs232_set_baudrate(struct osmo_rs232 *r, int baudrate) +{ + r->cfg.baudrate = baudrate; +} + +void osmo_rs232_set_delay_us(struct osmo_rs232 *r, int delay_us) +{ + r->cfg.delay_us = delay_us; +} + +void osmo_rs232_set_read_cb(struct osmo_rs232 *r, + int (*read_cb)(struct osmo_rs232 *r)) +{ + r->cb.read = read_cb; +} + +/* XXX: Better use TIOCGSERIAL / TIOCSSERIAL to allow setting non-standard. */ +static struct baudrate2termbits { + int rate; + int def; +} baudrate2termbits[] = { + { 9600, B9600 }, + { 19200, B19200 }, + { 38400, B38400 }, + { 115200, B1152000 }, + { -1, -1 }, +}; + +int osmo_rs232_open(struct osmo_rs232 *r) +{ + int rc, i, speed = 0; + struct osmo_fd *bfd = &r->ofd; + struct termios tio; + + rc = open(r->cfg.serial_port, O_RDWR); + if (rc < 0) { + LOGP(DLINP, LOGL_ERROR, "rs232: cannot open serial port: %s", + strerror(errno)); + return rc; + } + bfd->fd = rc; + + /* set baudrate */ + rc = tcgetattr(bfd->fd, &tio); + if (rc < 0) { + LOGP(DLINP, LOGL_ERROR, "rs232: tcgetattr says: %s", + strerror(errno)); + return rc; + } + for (i=0; i<baudrate2termbits[i].rate; i++) { + if (baudrate2termbits[i].rate == -1) + break; + + if (baudrate2termbits[i].rate == r->cfg.baudrate) { + speed = baudrate2termbits[i].def; + break; + } + } + if (speed == 0) { + close(rc); + bfd->fd = -1; + return -1; + } + + cfsetispeed(&tio, speed); + cfsetospeed(&tio, speed); + tio.c_cflag |= (CREAD | CLOCAL | CS8); + tio.c_cflag &= ~(PARENB | CSTOPB | CSIZE | CRTSCTS); + tio.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); + tio.c_iflag |= (INPCK | ISTRIP); + tio.c_iflag &= ~(ISTRIP | IXON | IXOFF | IGNBRK | INLCR | ICRNL | IGNCR); + tio.c_oflag &= ~(OPOST); + rc = tcsetattr(bfd->fd, TCSADRAIN, &tio); + if (rc < 0) { + LOGP(DLINP, LOGL_ERROR, "rs232: tcsetattr says: %s", + strerror(errno)); + return rc; + } + + bfd->when = BSC_FD_READ; + bfd->cb = serial_fd_cb; + bfd->data = r; + + rc = osmo_fd_register(bfd); + if (rc < 0) { + close(bfd->fd); + LOGP(DLINP, LOGL_ERROR, "rs232: could not register FD: %s\n", + strerror(rc)); + return rc; + } + + if (r->cfg.delay_us) { + r->tx_timer.cb = rs232_tx_timer_cb; + r->tx_timer.data = r; + } + return 0; +} + +int osmo_rs232_read(struct osmo_rs232 *r, struct msgb *msg) +{ + int ret; + + ret = read(r->ofd.fd, msg->data, msg->data_len); + if (ret < 0) { + LOGP(DLINP, LOGL_ERROR, "read error: %s\n", strerror(errno)); + return -EIO; + } + msgb_put(msg, ret); + return ret; +} + +void osmo_rs232_write(struct osmo_rs232 *r, struct msgb *msg) +{ + msgb_enqueue(&r->tx_queue, msg); + r->ofd.when |= BSC_FD_WRITE; +} + +void osmo_rs232_close(struct osmo_rs232 *r) +{ + close(r->ofd.fd); + r->ofd.fd = -1; +} + +void osmo_rs232_destroy(struct osmo_rs232 *r) +{ + talloc_free(r); +} |