X-Git-Url: https://sigrok.org/gitweb/?a=blobdiff_plain;f=serialport.c;h=8408ec7efb7d892d06399e329c9d00041fd7926f;hb=31b3a8f5b52aa90cf3795679da626255fd21c67a;hp=eed009ab5f8b50d8195c6771f4209ee36a0ef235;hpb=8f189c4c0f0b8fdf528688c9204c2e3a4e507659;p=libserialport.git diff --git a/serialport.c b/serialport.c index eed009a..8408ec7 100644 --- a/serialport.c +++ b/serialport.c @@ -4,6 +4,7 @@ * Copyright (C) 2010-2012 Bert Vermeulen * Copyright (C) 2010-2012 Uwe Hermann * Copyright (C) 2013 Martin Ling + * Copyright (C) 2013 Matthias Heidbrink * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as @@ -37,6 +38,7 @@ #ifdef __APPLE__ #include #include +#include #include #endif #ifdef __linux__ @@ -77,13 +79,14 @@ const struct std_baudrate std_baudrates[] = { */ BAUD(110), BAUD(300), BAUD(600), BAUD(1200), BAUD(2400), BAUD(4800), BAUD(9600), BAUD(14400), BAUD(19200), BAUD(38400), BAUD(57600), - BAUD(115200), BAUD(128000), BAUD(256000) + BAUD(115200), BAUD(128000), BAUD(256000), #else - BAUD(50), BAUD(75), BAUD(110), BAUD(134), BAUD(150), BAUD(200), BAUD(300), - BAUD(600), BAUD(1200), BAUD(1800), BAUD(2400), BAUD(4800), BAUD(9600), - BAUD(19200), BAUD(38400), BAUD(57600), BAUD(115200), BAUD(230400), + BAUD(50), BAUD(75), BAUD(110), BAUD(134), BAUD(150), BAUD(200), + BAUD(300), BAUD(600), BAUD(1200), BAUD(1800), BAUD(2400), BAUD(4800), + BAUD(9600), BAUD(19200), BAUD(38400), BAUD(57600), BAUD(115200), + BAUD(230400), #if !defined(__APPLE__) && !defined(__OpenBSD__) - BAUD(460800) + BAUD(460800), #endif #endif }; @@ -92,12 +95,14 @@ const struct std_baudrate std_baudrates[] = { #define NUM_STD_BAUDRATES ARRAY_SIZE(std_baudrates) /* Helper functions. */ -static int validate_port(struct sp_port *port); +static enum sp_return validate_port(struct sp_port *port); static struct sp_port **list_append(struct sp_port **list, const char *portname); -static int get_config(struct sp_port *port, struct port_data *data, struct sp_port_config *config); -static int set_config(struct sp_port *port, struct port_data *data, struct sp_port_config *config); +static enum sp_return get_config(struct sp_port *port, struct port_data *data, + struct sp_port_config *config); +static enum sp_return set_config(struct sp_port *port, struct port_data *data, + const struct sp_port_config *config); -int sp_get_port_by_name(const char *portname, struct sp_port **port_ptr) +enum sp_return sp_get_port_by_name(const char *portname, struct sp_port **port_ptr) { struct sp_port *port; int len; @@ -115,8 +120,7 @@ int sp_get_port_by_name(const char *portname, struct sp_port **port_ptr) len = strlen(portname) + 1; - if (!(port->name = malloc(len))) - { + if (!(port->name = malloc(len))) { free(port); return SP_ERR_MEM; } @@ -134,7 +138,7 @@ int sp_get_port_by_name(const char *portname, struct sp_port **port_ptr) return SP_OK; } -int sp_copy_port(const struct sp_port *port, struct sp_port **copy_ptr) +enum sp_return sp_copy_port(const struct sp_port *port, struct sp_port **copy_ptr) { if (!copy_ptr) return SP_ERR_ARG; @@ -177,7 +181,7 @@ fail: return NULL; } -int sp_list_ports(struct sp_port ***list_ptr) +enum sp_return sp_list_ports(struct sp_port ***list_ptr) { struct sp_port **list; int ret = SP_OK; @@ -197,25 +201,21 @@ int sp_list_ports(struct sp_port ***list_ptr) int name_len; if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("HARDWARE\\DEVICEMAP\\SERIALCOMM"), - 0, KEY_QUERY_VALUE, &key) != ERROR_SUCCESS) - { + 0, KEY_QUERY_VALUE, &key) != ERROR_SUCCESS) { ret = SP_ERR_FAIL; goto out_done; } if (RegQueryInfoKey(key, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - &max_value_len, &max_data_size, NULL, NULL) != ERROR_SUCCESS) - { + &max_value_len, &max_data_size, NULL, NULL) != ERROR_SUCCESS) { ret = SP_ERR_FAIL; goto out_close; } max_data_len = max_data_size / sizeof(TCHAR); - if (!(value = malloc((max_value_len + 1) * sizeof(TCHAR)))) - { + if (!(value = malloc((max_value_len + 1) * sizeof(TCHAR)))) { ret = SP_ERR_MEM; goto out_close; } - if (!(data = malloc((max_data_len + 1) * sizeof(TCHAR)))) - { + if (!(data = malloc((max_data_len + 1) * sizeof(TCHAR)))) { ret = SP_ERR_MEM; goto out_free_value; } @@ -232,8 +232,7 @@ int sp_list_ports(struct sp_port ***list_ptr) #else name_len = data_len + 1; #endif - if (!(name = malloc(name_len))) - { + if (!(name = malloc(name_len))) { ret = SP_ERR_MEM; goto out; } @@ -242,8 +241,7 @@ int sp_list_ports(struct sp_port ***list_ptr) #else strcpy(name, data); #endif - if (type == REG_SZ && !(list = list_append(list, name))) - { + if (type == REG_SZ && !(list = list_append(list, name))) { ret = SP_ERR_MEM; goto out; } @@ -266,14 +264,12 @@ out_done: CFTypeRef cf_path; Boolean result; - if (IOMasterPort(MACH_PORT_NULL, &master) != KERN_SUCCESS) - { + if (IOMasterPort(MACH_PORT_NULL, &master) != KERN_SUCCESS) { ret = SP_ERR_FAIL; goto out_done; } - if (!(classes = IOServiceMatching(kIOSerialBSDServiceValue))) - { + if (!(classes = IOServiceMatching(kIOSerialBSDServiceValue))) { ret = SP_ERR_FAIL; goto out_done; } @@ -281,14 +277,12 @@ out_done: CFDictionarySetValue(classes, CFSTR(kIOSerialBSDTypeKey), CFSTR(kIOSerialBSDAllTypes)); - if (IOServiceGetMatchingServices(master, classes, &iter) != KERN_SUCCESS) - { + if (IOServiceGetMatchingServices(master, classes, &iter) != KERN_SUCCESS) { ret = SP_ERR_FAIL; goto out_done; } - if (!(path = malloc(PATH_MAX))) - { + if (!(path = malloc(PATH_MAX))) { ret = SP_ERR_MEM; goto out_release; } @@ -300,8 +294,7 @@ out_done: result = CFStringGetCString(cf_path, path, PATH_MAX, kCFStringEncodingASCII); CFRelease(cf_path); - if (result && !(list = list_append(list, path))) - { + if (result && !(list = list_append(list, path))) { ret = SP_ERR_MEM; IOObjectRelease(port); goto out; @@ -332,14 +325,12 @@ out_done: udev_enumerate_add_match_subsystem(ud_enumerate, "tty"); udev_enumerate_scan_devices(ud_enumerate); ud_list = udev_enumerate_get_list_entry(ud_enumerate); - udev_list_entry_foreach(ud_entry, ud_list) - { + udev_list_entry_foreach(ud_entry, ud_list) { path = udev_list_entry_get_name(ud_entry); ud_dev = udev_device_new_from_syspath(ud, path); /* If there is no parent device, this is a virtual tty. */ ud_parent = udev_device_get_parent(ud_dev); - if (ud_parent == NULL) - { + if (ud_parent == NULL) { udev_device_unref(ud_dev); continue; } @@ -348,8 +339,7 @@ out_done: * The only way to tell which actually exist on a given system * is to try to open them and make an ioctl call. */ driver = udev_device_get_driver(ud_parent); - if (driver && !strcmp(driver, "serial8250")) - { + if (driver && !strcmp(driver, "serial8250")) { if ((fd = open(name, O_RDWR | O_NONBLOCK | O_NOCTTY)) < 0) goto skip; ioctl_result = ioctl(fd, TIOCGSERIAL, &serial_info); @@ -362,8 +352,7 @@ out_done: list = list_append(list, name); skip: udev_device_unref(ud_dev); - if (!list) - { + if (!list) { ret = SP_ERR_MEM; goto out; } @@ -373,15 +362,11 @@ out: udev_unref(ud); #endif - if (ret == SP_OK) - { + if (ret == SP_OK) { *list_ptr = list; - } - else - { + } else { if (list) sp_free_port_list(list); - *list_ptr = NULL; } @@ -397,7 +382,7 @@ void sp_free_port_list(struct sp_port **list) free(list); } -static int validate_port(struct sp_port *port) +static enum sp_return validate_port(struct sp_port *port) { if (port == NULL) return 0; @@ -413,7 +398,7 @@ static int validate_port(struct sp_port *port) #define CHECK_PORT() do { if (!validate_port(port)) return SP_ERR_ARG; } while (0) -int sp_open(struct sp_port *port, int flags) +enum sp_return sp_open(struct sp_port *port, enum sp_mode flags) { if (!port) return SP_ERR_ARG; @@ -461,8 +446,7 @@ int sp_open(struct sp_port *port, int flags) ret = get_config(port, &data, &config); - if (ret < 0) - { + if (ret < 0) { sp_close(port); return ret; } @@ -481,8 +465,7 @@ int sp_open(struct sp_port *port, int flags) ret = set_config(port, &data, &config); - if (ret < 0) - { + if (ret < 0) { sp_close(port); return ret; } @@ -491,7 +474,7 @@ int sp_open(struct sp_port *port, int flags) return SP_OK; } -int sp_close(struct sp_port *port) +enum sp_return sp_close(struct sp_port *port) { CHECK_PORT(); @@ -510,7 +493,7 @@ int sp_close(struct sp_port *port) return SP_OK; } -int sp_flush(struct sp_port *port) +enum sp_return sp_flush(struct sp_port *port) { CHECK_PORT(); @@ -526,7 +509,7 @@ int sp_flush(struct sp_port *port) return SP_OK; } -int sp_write(struct sp_port *port, const void *buf, size_t count) +enum sp_return sp_write(struct sp_port *port, const void *buf, size_t count) { CHECK_PORT(); @@ -551,7 +534,7 @@ int sp_write(struct sp_port *port, const void *buf, size_t count) #endif } -int sp_read(struct sp_port *port, void *buf, size_t count) +enum sp_return sp_read(struct sp_port *port, void *buf, size_t count) { CHECK_PORT(); @@ -575,7 +558,8 @@ int sp_read(struct sp_port *port, void *buf, size_t count) #endif } -static int get_config(struct sp_port *port, struct port_data *data, struct sp_port_config *config) +static enum sp_return get_config(struct sp_port *port, struct port_data *data, + struct sp_port_config *config) { unsigned int i; @@ -625,33 +609,33 @@ static int get_config(struct sp_port *port, struct port_data *data, struct sp_po } switch (data->dcb.fRtsControl) { - case RTS_CONTROL_DISABLE: - config->rts = SP_RTS_OFF; - break; - case RTS_CONTROL_ENABLE: - config->rts = SP_RTS_ON; - break; - case RTS_CONTROL_HANDSHAKE: - config->rts = SP_RTS_FLOW_CONTROL; - break; - default: - config->rts = -1; + case RTS_CONTROL_DISABLE: + config->rts = SP_RTS_OFF; + break; + case RTS_CONTROL_ENABLE: + config->rts = SP_RTS_ON; + break; + case RTS_CONTROL_HANDSHAKE: + config->rts = SP_RTS_FLOW_CONTROL; + break; + default: + config->rts = -1; } config->cts = data->dcb.fOutxCtsFlow ? SP_CTS_FLOW_CONTROL : SP_CTS_IGNORE; switch (data->dcb.fDtrControl) { - case DTR_CONTROL_DISABLE: - config->dtr = SP_DTR_OFF; - break; - case DTR_CONTROL_ENABLE: - config->dtr = SP_DTR_ON; - break; - case DTR_CONTROL_HANDSHAKE: - config->dtr = SP_DTR_FLOW_CONTROL; - break; - default: - config->dtr = -1; + case DTR_CONTROL_DISABLE: + config->dtr = SP_DTR_OFF; + break; + case DTR_CONTROL_ENABLE: + config->dtr = SP_DTR_ON; + break; + case DTR_CONTROL_HANDSHAKE: + config->dtr = SP_DTR_FLOW_CONTROL; + break; + default: + config->dtr = -1; } config->dsr = data->dcb.fOutxDsrFlow ? SP_DSR_FLOW_CONTROL : SP_DSR_IGNORE; @@ -682,8 +666,13 @@ static int get_config(struct sp_port *port, struct port_data *data, struct sp_po } } - if (i == NUM_STD_BAUDRATES) + if (i == NUM_STD_BAUDRATES) { +#ifdef __APPLE__ + config->baudrate = (int)data->term.c_ispeed; +#else config->baudrate = -1; +#endif + } switch (data->term.c_cflag & CSIZE) { case CS8: @@ -721,18 +710,35 @@ static int get_config(struct sp_port *port, struct port_data *data, struct sp_po config->dtr = (data->controlbits & TIOCM_DTR) ? SP_DTR_ON : SP_DTR_OFF; config->dsr = SP_DSR_IGNORE; + + if (data->term.c_iflag & IXOFF) { + if (data->term.c_iflag & IXON) + config->xon_xoff = SP_XONXOFF_INOUT; + else + config->xon_xoff = SP_XONXOFF_IN; + } else { + if (data->term.c_iflag & IXON) + config->xon_xoff = SP_XONXOFF_OUT; + else + config->xon_xoff = SP_XONXOFF_DISABLED; + } #endif return SP_OK; } -static int set_config(struct sp_port *port, struct port_data *data, struct sp_port_config *config) +static enum sp_return set_config(struct sp_port *port, struct port_data *data, + const struct sp_port_config *config) { unsigned int i; +#ifdef __APPLE__ + BAUD_TYPE baud_nonstd; + + baud_nonstd = B0; +#endif #ifdef _WIN32 - if (config->baudrate >= 0) - { + if (config->baudrate >= 0) { for (i = 0; i < NUM_STD_BAUDRATES; i++) { if (config->baudrate == std_baudrates[i].value) { data->dcb.BaudRate = std_baudrates[i].index; @@ -862,10 +868,9 @@ static int set_config(struct sp_port *port, struct port_data *data, struct sp_po if (!SetCommState(port->hdl, &data->dcb)) return SP_ERR_FAIL; -#else // !_WIN32 +#else /* !_WIN32 */ - if (config->baudrate >= 0) - { + if (config->baudrate >= 0) { for (i = 0; i < NUM_STD_BAUDRATES; i++) { if (config->baudrate == std_baudrates[i].value) { if (cfsetospeed(&data->term, std_baudrates[i].index) < 0) @@ -877,8 +882,17 @@ static int set_config(struct sp_port *port, struct port_data *data, struct sp_po } } - if (i == NUM_STD_BAUDRATES) + /* Non-standard baud rate */ + if (i == NUM_STD_BAUDRATES) { +#ifdef __APPLE__ + /* Set "dummy" baud rate */ + if (cfsetspeed(&data->term, B9600) < 0) + return SP_ERR_FAIL; + baud_nonstd = config->baudrate; +#else return SP_ERR_ARG; +#endif + } } if (config->bits >= 0) { @@ -893,6 +907,9 @@ static int set_config(struct sp_port *port, struct port_data *data, struct sp_po case 6: data->term.c_cflag |= CS6; break; + case 5: + data->term.c_cflag |= CS5; + break; default: return SP_ERR_ARG; } @@ -930,8 +947,7 @@ static int set_config(struct sp_port *port, struct port_data *data, struct sp_po } } - if (config->rts >= 0 || config->cts >= 0) - { + if (config->rts >= 0 || config->cts >= 0) { /* Asymmetric use of RTS/CTS not supported yet. */ if (data->term.c_iflag & CRTSCTS) { @@ -963,8 +979,7 @@ static int set_config(struct sp_port *port, struct port_data *data, struct sp_po } } - if (config->dtr >= 0 || config->dsr >= 0) - { + if (config->dtr >= 0 || config->dsr >= 0) { /* DTR/DSR flow control not supported yet. */ if (config->dtr == SP_DTR_FLOW_CONTROL || config->dsr == SP_DSR_FLOW_CONTROL) return SP_ERR_ARG; @@ -998,48 +1013,68 @@ static int set_config(struct sp_port *port, struct port_data *data, struct sp_po if (tcsetattr(port->fd, TCSADRAIN, &data->term) < 0) return SP_ERR_FAIL; -#endif + +#ifdef __APPLE__ + if (baud_nonstd != B0) { + if (ioctl(port->fd, IOSSIOSPEED, &baud_nonstd) == -1) + return SP_ERR_FAIL; + /* Set baud rates in data->term to correct, but incompatible + * with tcsetattr() value, same as delivered by tcgetattr(). */ + if (cfsetspeed(&data->term, baud_nonstd) < 0) + return SP_ERR_FAIL; + } +#endif /* __APPLE__ */ + +#endif /* !_WIN32 */ return SP_OK; } #define TRY(x) do { int ret = x; if (ret != SP_OK) return ret; } while (0) -int sp_set_config(struct sp_port *port, struct sp_port_config *config) +enum sp_return sp_set_config(struct sp_port *port, const struct sp_port_config *config) { struct port_data data; struct sp_port_config prev_config; + CHECK_PORT(); + + if (!config) + return SP_ERR_ARG; + TRY(get_config(port, &data, &prev_config)); TRY(set_config(port, &data, config)); return SP_OK; } -#define CREATE_SETTER(x) int sp_set_##x(struct sp_port *port, int x) { \ +#define CREATE_SETTER(x, type) int sp_set_##x(struct sp_port *port, type x) { \ struct port_data data; \ struct sp_port_config config; \ + CHECK_PORT(); \ TRY(get_config(port, &data, &config)); \ config.x = x; \ TRY(set_config(port, &data, &config)); \ return SP_OK; \ } -CREATE_SETTER(baudrate) -CREATE_SETTER(bits) -CREATE_SETTER(parity) -CREATE_SETTER(stopbits) -CREATE_SETTER(rts) -CREATE_SETTER(cts) -CREATE_SETTER(dtr) -CREATE_SETTER(dsr) -CREATE_SETTER(xon_xoff) - -int sp_set_flowcontrol(struct sp_port *port, int flowcontrol) +CREATE_SETTER(baudrate, int) +CREATE_SETTER(bits, int) +CREATE_SETTER(parity, enum sp_parity) +CREATE_SETTER(stopbits, int) +CREATE_SETTER(rts, enum sp_rts) +CREATE_SETTER(cts, enum sp_cts) +CREATE_SETTER(dtr, enum sp_dtr) +CREATE_SETTER(dsr, enum sp_dsr) +CREATE_SETTER(xon_xoff, enum sp_xonxoff) + +enum sp_return sp_set_flowcontrol(struct sp_port *port, enum sp_flowcontrol flowcontrol) { struct port_data data; struct sp_port_config config; + CHECK_PORT(); + TRY(get_config(port, &data, &config)); if (flowcontrol == SP_FLOWCONTROL_XONXOFF)