From: Karol Lewandowski Date: Mon, 2 Jan 2023 16:23:55 +0000 (+0100) Subject: uart: Add nonblocking IO and assorted functions X-Git-Tag: accepted/tizen/unified/20230215.155624~7 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=e14fc739d7de7a6592fc76051b302910d8169b4b;p=platform%2Fcore%2Fapi%2Fperipheral-io.git uart: Add nonblocking IO and assorted functions This commits extends UART API with following: * additional nonblocking variants of the peripheral_open_flags_e for use in peripheral_open_with_flags(): - PERIPHERAL_OPEN_FLAGS_PRIVATE_NONBLOCK - PERIPHERAL_OPEN_FLAGS_SHARED_NONBLOCK * peripheral_uart_drain() and peripheral_uart_flush() API functions Change-Id: I4fe45ff8a2115e954244affe16818aa5b9710e47 --- diff --git a/include/peripheral_io.h b/include/peripheral_io.h index c438a23..e90b0f3 100644 --- a/include/peripheral_io.h +++ b/include/peripheral_io.h @@ -342,12 +342,19 @@ typedef struct _peripheral_i2c_s *peripheral_i2c_h; int peripheral_i2c_open(int bus, int address, peripheral_i2c_h *i2c); /** - * @brief Enumeration for open flags. + * @brief Enumeration for open flags (bitmask). * @since_tizen 6.5 + * + * @remarks Enum values are supposed to be used as bitmask, where only one + * value can be specified for following flag groups: + * - locking mode - either #PERIPHERAL_OPEN_FLAGS_PRIVATE or #PERIPHERAL_OPEN_FLAGS_SHARED can be used + * + * The #PERIPHERAL_OPEN_FLAGS_NONBLOCK can be used with all other available flags. */ typedef enum { - PERIPHERAL_OPEN_FLAGS_PRIVATE = 0, /**< Exclusive access to device */ - PERIPHERAL_OPEN_FLAGS_SHARED = 1, /**< Shared access to device */ + PERIPHERAL_OPEN_FLAGS_PRIVATE = 0, /**< Exclusive access to device */ + PERIPHERAL_OPEN_FLAGS_SHARED = 1, /**< Shared access to device */ + PERIPHERAL_OPEN_FLAGS_NONBLOCK = 2, /**< (Since 7.5) Nonblocking read/write flag */ } peripheral_open_flags_e; /** @@ -1086,6 +1093,49 @@ int peripheral_uart_set_flow_control(peripheral_uart_h uart, */ int peripheral_uart_read(peripheral_uart_h uart, uint8_t *data, uint32_t length); + +/** + * @platform + * @brief Discards data queued for writing to UART slave device, but not yet transmitted. + * @since_tizen 7.5 + * @privlevel platform + * @privilege http://tizen.org/privilege/peripheralio + * + * @param[in] uart The UART handle + * + * @return #PERIPHERAL_ERROR_NONE on success, otherwise a negative error value + * @retval #PERIPHERAL_ERROR_NONE Successful + * @retval #PERIPHERAL_ERROR_IO_ERROR I/O operation failed + * @retval #PERIPHERAL_ERROR_TRY_AGAIN Try again + * @retval #PERIPHERAL_ERROR_PERMISSION_DENIED Permission denied + * @retval #PERIPHERAL_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #PERIPHERAL_ERROR_NOT_SUPPORTED Not supported + * @retval #PERIPHERAL_ERROR_UNKNOWN Unknown internal error + * + */ +int peripheral_uart_flush(peripheral_uart_h uart); + +/** + * @platform + * @brief Waits for all data queued for UART to be transmitted. + * @since_tizen 7.5 + * @privlevel platform + * @privilege http://tizen.org/privilege/peripheralio + * + * @param[in] uart The UART handle + * + * @return #PERIPHERAL_ERROR_NONE on success, otherwise a negative error value + * @retval #PERIPHERAL_ERROR_NONE Successful + * @retval #PERIPHERAL_ERROR_IO_ERROR I/O operation failed + * @retval #PERIPHERAL_ERROR_TRY_AGAIN Try again + * @retval #PERIPHERAL_ERROR_PERMISSION_DENIED Permission denied + * @retval #PERIPHERAL_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #PERIPHERAL_ERROR_NOT_SUPPORTED Not supported + * @retval #PERIPHERAL_ERROR_UNKNOWN Unknown internal error + * + */ +int peripheral_uart_drain(peripheral_uart_h uart); + /** * @platform * @brief Writes data to the UART slave device. diff --git a/packaging/capi-system-peripheral-io.spec b/packaging/capi-system-peripheral-io.spec index beb2434..3ee431d 100644 --- a/packaging/capi-system-peripheral-io.spec +++ b/packaging/capi-system-peripheral-io.spec @@ -1,6 +1,6 @@ Name: capi-system-peripheral-io Summary: Tizen Peripheral Input & Output library -Version: 0.3.2 +Version: 0.3.3 Release: 0 Group: System & System Tools License: Apache-2.0 diff --git a/src/common.h b/src/common.h index 544bb67..45a1a54 100644 --- a/src/common.h +++ b/src/common.h @@ -113,3 +113,8 @@ static inline int peripheral_get_lock_type(peripheral_open_flags_e flags) return LOCK_SH; return LOCK_EX; } + +static inline int peripheral_get_nonblock_flag(peripheral_open_flags_e flags) +{ + return flags & PERIPHERAL_OPEN_FLAGS_NONBLOCK ? O_NONBLOCK : 0; +} diff --git a/src/peripheral_uart.c b/src/peripheral_uart.c index 2e86a28..3cd2e13 100644 --- a/src/peripheral_uart.c +++ b/src/peripheral_uart.c @@ -104,8 +104,15 @@ int peripheral_uart_open_flags(int port, peripheral_open_flags_e flags, peripher RETVM_IF(!__is_feature_supported(), PERIPHERAL_ERROR_NOT_SUPPORTED, "UART feature is not supported"); RETVM_IF(uart == NULL, PERIPHERAL_ERROR_INVALID_PARAMETER, "Invalid uart handle"); RETVM_IF(port < 0, PERIPHERAL_ERROR_INVALID_PARAMETER, "Invalid port number"); - RETVM_IF(flags != PERIPHERAL_OPEN_FLAGS_PRIVATE && flags != PERIPHERAL_OPEN_FLAGS_SHARED, - PERIPHERAL_ERROR_INVALID_PARAMETER, "Invalid flags"); + + /* The PRIVATE flag is actually 0 and doesn't represent any bit, + * it's just there so people don't have to write a magic 0 constant + * for shared access. This means some care needs to be taken when + * manipulating it as a bitflag (in particular it is skipped here). */ + static const int ALL_OPEN_FLAGS + = PERIPHERAL_OPEN_FLAGS_NONBLOCK + | PERIPHERAL_OPEN_FLAGS_SHARED; + RETVM_IF(flags & ~ALL_OPEN_FLAGS, PERIPHERAL_ERROR_INVALID_PARAMETER, "Invalid flags"); __attribute__ ((cleanup(cleanup_handlep))) peripheral_uart_h handle = (peripheral_uart_h)calloc(1, sizeof *handle); if (handle == NULL) { @@ -120,7 +127,7 @@ int peripheral_uart_open_flags(int port, peripheral_open_flags_e flags, peripher }; char path[DEV_PATH_FMT_MAX_SIZE] = {0, }; /* space for /dev/ttyXXX%d */ - const int FLAGS = O_RDWR | O_NOCTTY | O_CLOEXEC; + const int FLAGS = O_RDWR | O_NOCTTY | O_CLOEXEC | peripheral_get_nonblock_flag(flags); int fd = -1; int retval = peripheral_uart_find_devpath(port, path, DEV_PATH_FMT_MAX_SIZE); @@ -171,9 +178,26 @@ int peripheral_uart_open(int port, peripheral_uart_h *uart) return peripheral_uart_open_flags(port, PERIPHERAL_OPEN_FLAGS_PRIVATE, uart); } -static void peripheral_uart_flush(peripheral_uart_h uart) +int peripheral_uart_flush(peripheral_uart_h uart) { - tcflush(uart->fd, TCIOFLUSH); + RETVM_IF(!__is_feature_supported(), PERIPHERAL_ERROR_NOT_SUPPORTED, "UART feature is not supported"); + RETVM_IF(uart == NULL, PERIPHERAL_ERROR_INVALID_PARAMETER, "uart handle is NULL"); + + int ret = tcflush(uart->fd, TCIOFLUSH); + CHECK_ERROR(ret < 0); + + return PERIPHERAL_ERROR_NONE; +} + +int peripheral_uart_drain(peripheral_uart_h uart) +{ + RETVM_IF(!__is_feature_supported(), PERIPHERAL_ERROR_NOT_SUPPORTED, "UART feature is not supported"); + RETVM_IF(uart == NULL, PERIPHERAL_ERROR_INVALID_PARAMETER, "uart handle is NULL"); + + int ret = tcdrain(uart->fd); + CHECK_ERROR(ret < 0); + + return PERIPHERAL_ERROR_NONE; } /** @@ -213,7 +237,7 @@ int peripheral_uart_set_baud_rate(peripheral_uart_h uart, peripheral_uart_baud_r tio.c_cc[VMIN] = 1; tio.c_cc[VTIME] = 0; - peripheral_uart_flush(uart); + (void)peripheral_uart_flush(uart); ret = tcsetattr(uart->fd, TCSANOW, &tio); CHECK_ERROR(ret != 0); @@ -238,7 +262,7 @@ int peripheral_uart_set_byte_size(peripheral_uart_h uart, peripheral_uart_byte_s tio.c_cflag |= byteinfo[byte_size]; tio.c_cflag |= (CLOCAL | CREAD); - peripheral_uart_flush(uart); + (void)peripheral_uart_flush(uart); ret = tcsetattr(uart->fd, TCSANOW, &tio); CHECK_ERROR(ret != 0); @@ -275,7 +299,7 @@ int peripheral_uart_set_parity(peripheral_uart_h uart, peripheral_uart_parity_e break; } - peripheral_uart_flush(uart); + (void)peripheral_uart_flush(uart); ret = tcsetattr(uart->fd, TCSANOW, &tio); CHECK_ERROR(ret != 0); @@ -300,7 +324,7 @@ int peripheral_uart_set_stop_bits(peripheral_uart_h uart, peripheral_uart_stop_b else // PERIPHERAL_UART_STOP_BITS_2BIT tio.c_cflag |= CSTOPB; - peripheral_uart_flush(uart); + (void)peripheral_uart_flush(uart); ret = tcsetattr(uart->fd, TCSANOW, &tio); CHECK_ERROR(ret != 0); @@ -334,7 +358,7 @@ int peripheral_uart_set_flow_control(peripheral_uart_h uart, peripheral_uart_sof else // PERIPHERAL_UART_SOFTWARE_FLOW_CONTROL_NONE tio.c_iflag &= ~(IXON | IXOFF | IXANY); - peripheral_uart_flush(uart); + (void)peripheral_uart_flush(uart); ret = tcsetattr(uart->fd, TCSANOW, &tio); CHECK_ERROR(ret != 0);