Library for interfacing with IIO devices. Licensed under the LGPLv2+
Dependencies: libserialport libxml2
serial.c@4:ad69b39bf124, 2017-06-26 (annotated)
- Committer:
- pcercuei
- Date:
- Mon Jun 26 14:30:10 2017 +0000
- Revision:
- 4:ad69b39bf124
- Parent:
- 3:d147beabba0e
Update to upstream version v0.10
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
pcercuei | 0:df031b60ca29 | 1 | /* |
pcercuei | 0:df031b60ca29 | 2 | * libiio - Library for interfacing industrial I/O (IIO) devices |
pcercuei | 0:df031b60ca29 | 3 | * |
pcercuei | 0:df031b60ca29 | 4 | * Copyright (C) 2014-2016 Analog Devices, Inc. |
pcercuei | 0:df031b60ca29 | 5 | * Author: Paul Cercueil <paul.cercueil@analog.com> |
pcercuei | 0:df031b60ca29 | 6 | * |
pcercuei | 0:df031b60ca29 | 7 | * This library is free software; you can redistribute it and/or |
pcercuei | 0:df031b60ca29 | 8 | * modify it under the terms of the GNU Lesser General Public |
pcercuei | 0:df031b60ca29 | 9 | * License as published by the Free Software Foundation; either |
pcercuei | 0:df031b60ca29 | 10 | * version 2.1 of the License, or (at your option) any later version. |
pcercuei | 0:df031b60ca29 | 11 | * |
pcercuei | 0:df031b60ca29 | 12 | * This library is distributed in the hope that it will be useful, |
pcercuei | 0:df031b60ca29 | 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
pcercuei | 0:df031b60ca29 | 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
pcercuei | 0:df031b60ca29 | 15 | * Lesser General Public License for more details. |
pcercuei | 0:df031b60ca29 | 16 | * |
pcercuei | 0:df031b60ca29 | 17 | * */ |
pcercuei | 0:df031b60ca29 | 18 | |
pcercuei | 0:df031b60ca29 | 19 | #include "debug.h" |
pcercuei | 0:df031b60ca29 | 20 | #include "iio-private.h" |
pcercuei | 0:df031b60ca29 | 21 | #include "iio-lock.h" |
pcercuei | 0:df031b60ca29 | 22 | #include "iiod-client.h" |
pcercuei | 0:df031b60ca29 | 23 | |
pcercuei | 2:9eb0a9a1f958 | 24 | #include <errno.h> |
pcercuei | 0:df031b60ca29 | 25 | #include <libserialport.h> |
pcercuei | 0:df031b60ca29 | 26 | #include <stdio.h> |
pcercuei | 0:df031b60ca29 | 27 | #include <stdlib.h> |
pcercuei | 0:df031b60ca29 | 28 | #include <string.h> |
pcercuei | 0:df031b60ca29 | 29 | |
pcercuei | 0:df031b60ca29 | 30 | #define DEFAULT_TIMEOUT_MS 1000 |
pcercuei | 0:df031b60ca29 | 31 | |
pcercuei | 0:df031b60ca29 | 32 | struct iio_context_pdata { |
pcercuei | 0:df031b60ca29 | 33 | struct sp_port *port; |
pcercuei | 0:df031b60ca29 | 34 | struct iio_mutex *lock; |
pcercuei | 0:df031b60ca29 | 35 | struct iiod_client *iiod_client; |
pcercuei | 0:df031b60ca29 | 36 | |
pcercuei | 0:df031b60ca29 | 37 | unsigned int timeout_ms; |
pcercuei | 0:df031b60ca29 | 38 | }; |
pcercuei | 0:df031b60ca29 | 39 | |
pcercuei | 0:df031b60ca29 | 40 | struct iio_device_pdata { |
pcercuei | 0:df031b60ca29 | 41 | bool opened; |
pcercuei | 0:df031b60ca29 | 42 | }; |
pcercuei | 0:df031b60ca29 | 43 | |
pcercuei | 0:df031b60ca29 | 44 | static inline int libserialport_to_errno(enum sp_return ret) |
pcercuei | 0:df031b60ca29 | 45 | { |
pcercuei | 0:df031b60ca29 | 46 | switch (ret) { |
pcercuei | 0:df031b60ca29 | 47 | case SP_ERR_ARG: |
pcercuei | 0:df031b60ca29 | 48 | return -EINVAL; |
pcercuei | 0:df031b60ca29 | 49 | case SP_ERR_FAIL: |
pcercuei | 0:df031b60ca29 | 50 | return -sp_last_error_code(); |
pcercuei | 0:df031b60ca29 | 51 | case SP_ERR_MEM: |
pcercuei | 0:df031b60ca29 | 52 | return -ENOMEM; |
pcercuei | 0:df031b60ca29 | 53 | case SP_ERR_SUPP: |
pcercuei | 0:df031b60ca29 | 54 | return -ENOSYS; |
pcercuei | 0:df031b60ca29 | 55 | default: |
pcercuei | 0:df031b60ca29 | 56 | return (int) ret; |
pcercuei | 0:df031b60ca29 | 57 | } |
pcercuei | 0:df031b60ca29 | 58 | } |
pcercuei | 0:df031b60ca29 | 59 | |
pcercuei | 0:df031b60ca29 | 60 | static int serial_get_version(const struct iio_context *ctx, |
pcercuei | 0:df031b60ca29 | 61 | unsigned int *major, unsigned int *minor, char git_tag[8]) |
pcercuei | 0:df031b60ca29 | 62 | { |
pcercuei | 0:df031b60ca29 | 63 | struct iio_context_pdata *pdata = ctx->pdata; |
pcercuei | 0:df031b60ca29 | 64 | |
pcercuei | 0:df031b60ca29 | 65 | return iiod_client_get_version(pdata->iiod_client, NULL, |
pcercuei | 0:df031b60ca29 | 66 | major, minor, git_tag); |
pcercuei | 0:df031b60ca29 | 67 | } |
pcercuei | 0:df031b60ca29 | 68 | |
pcercuei | 0:df031b60ca29 | 69 | static int serial_open(const struct iio_device *dev, |
pcercuei | 0:df031b60ca29 | 70 | size_t samples_count, bool cyclic) |
pcercuei | 0:df031b60ca29 | 71 | { |
pcercuei | 0:df031b60ca29 | 72 | const struct iio_context *ctx = iio_device_get_context(dev); |
pcercuei | 0:df031b60ca29 | 73 | struct iio_context_pdata *ctx_pdata = ctx->pdata; |
pcercuei | 0:df031b60ca29 | 74 | struct iio_device_pdata *pdata = dev->pdata; |
pcercuei | 0:df031b60ca29 | 75 | int ret = -EBUSY; |
pcercuei | 0:df031b60ca29 | 76 | |
pcercuei | 0:df031b60ca29 | 77 | iio_mutex_lock(ctx_pdata->lock); |
pcercuei | 0:df031b60ca29 | 78 | if (pdata->opened) |
pcercuei | 0:df031b60ca29 | 79 | goto out_unlock; |
pcercuei | 0:df031b60ca29 | 80 | |
pcercuei | 0:df031b60ca29 | 81 | ret = iiod_client_open_unlocked(ctx_pdata->iiod_client, NULL, |
pcercuei | 0:df031b60ca29 | 82 | dev, samples_count, cyclic); |
pcercuei | 0:df031b60ca29 | 83 | |
pcercuei | 0:df031b60ca29 | 84 | pdata->opened = !ret; |
pcercuei | 0:df031b60ca29 | 85 | |
pcercuei | 0:df031b60ca29 | 86 | out_unlock: |
pcercuei | 0:df031b60ca29 | 87 | iio_mutex_unlock(ctx_pdata->lock); |
pcercuei | 0:df031b60ca29 | 88 | return ret; |
pcercuei | 0:df031b60ca29 | 89 | } |
pcercuei | 0:df031b60ca29 | 90 | |
pcercuei | 0:df031b60ca29 | 91 | static int serial_close(const struct iio_device *dev) |
pcercuei | 0:df031b60ca29 | 92 | { |
pcercuei | 0:df031b60ca29 | 93 | const struct iio_context *ctx = iio_device_get_context(dev); |
pcercuei | 0:df031b60ca29 | 94 | struct iio_context_pdata *ctx_pdata = ctx->pdata; |
pcercuei | 0:df031b60ca29 | 95 | struct iio_device_pdata *pdata = dev->pdata; |
pcercuei | 0:df031b60ca29 | 96 | int ret = -EBADF; |
pcercuei | 0:df031b60ca29 | 97 | |
pcercuei | 0:df031b60ca29 | 98 | iio_mutex_lock(ctx_pdata->lock); |
pcercuei | 0:df031b60ca29 | 99 | if (!pdata->opened) |
pcercuei | 0:df031b60ca29 | 100 | goto out_unlock; |
pcercuei | 0:df031b60ca29 | 101 | |
pcercuei | 0:df031b60ca29 | 102 | ret = iiod_client_close_unlocked(ctx_pdata->iiod_client, NULL, dev); |
pcercuei | 0:df031b60ca29 | 103 | pdata->opened = false; |
pcercuei | 0:df031b60ca29 | 104 | |
pcercuei | 0:df031b60ca29 | 105 | out_unlock: |
pcercuei | 0:df031b60ca29 | 106 | iio_mutex_unlock(ctx_pdata->lock); |
pcercuei | 0:df031b60ca29 | 107 | return ret; |
pcercuei | 0:df031b60ca29 | 108 | } |
pcercuei | 0:df031b60ca29 | 109 | |
pcercuei | 0:df031b60ca29 | 110 | static ssize_t serial_read(const struct iio_device *dev, void *dst, size_t len, |
pcercuei | 0:df031b60ca29 | 111 | uint32_t *mask, size_t words) |
pcercuei | 0:df031b60ca29 | 112 | { |
pcercuei | 0:df031b60ca29 | 113 | const struct iio_context *ctx = iio_device_get_context(dev); |
pcercuei | 0:df031b60ca29 | 114 | struct iio_context_pdata *pdata = ctx->pdata; |
pcercuei | 0:df031b60ca29 | 115 | ssize_t ret; |
pcercuei | 0:df031b60ca29 | 116 | |
pcercuei | 0:df031b60ca29 | 117 | iio_mutex_lock(pdata->lock); |
pcercuei | 0:df031b60ca29 | 118 | ret = iiod_client_read_unlocked(pdata->iiod_client, NULL, |
pcercuei | 0:df031b60ca29 | 119 | dev, dst, len, mask, words); |
pcercuei | 0:df031b60ca29 | 120 | iio_mutex_unlock(pdata->lock); |
pcercuei | 0:df031b60ca29 | 121 | |
pcercuei | 0:df031b60ca29 | 122 | return ret; |
pcercuei | 0:df031b60ca29 | 123 | } |
pcercuei | 0:df031b60ca29 | 124 | |
pcercuei | 0:df031b60ca29 | 125 | static ssize_t serial_write(const struct iio_device *dev, |
pcercuei | 0:df031b60ca29 | 126 | const void *src, size_t len) |
pcercuei | 0:df031b60ca29 | 127 | { |
pcercuei | 0:df031b60ca29 | 128 | const struct iio_context *ctx = iio_device_get_context(dev); |
pcercuei | 0:df031b60ca29 | 129 | struct iio_context_pdata *pdata = ctx->pdata; |
pcercuei | 0:df031b60ca29 | 130 | ssize_t ret; |
pcercuei | 0:df031b60ca29 | 131 | |
pcercuei | 0:df031b60ca29 | 132 | iio_mutex_lock(pdata->lock); |
pcercuei | 0:df031b60ca29 | 133 | ret = iiod_client_write_unlocked(pdata->iiod_client, NULL, dev, src, len); |
pcercuei | 0:df031b60ca29 | 134 | iio_mutex_unlock(pdata->lock); |
pcercuei | 0:df031b60ca29 | 135 | |
pcercuei | 0:df031b60ca29 | 136 | return ret; |
pcercuei | 0:df031b60ca29 | 137 | } |
pcercuei | 0:df031b60ca29 | 138 | |
pcercuei | 0:df031b60ca29 | 139 | static ssize_t serial_read_dev_attr(const struct iio_device *dev, |
pcercuei | 0:df031b60ca29 | 140 | const char *attr, char *dst, size_t len, bool is_debug) |
pcercuei | 0:df031b60ca29 | 141 | { |
pcercuei | 0:df031b60ca29 | 142 | const struct iio_context *ctx = iio_device_get_context(dev); |
pcercuei | 0:df031b60ca29 | 143 | struct iio_context_pdata *pdata = ctx->pdata; |
pcercuei | 0:df031b60ca29 | 144 | |
pcercuei | 0:df031b60ca29 | 145 | return iiod_client_read_attr(pdata->iiod_client, NULL, |
pcercuei | 0:df031b60ca29 | 146 | dev, NULL, attr, dst, len, is_debug); |
pcercuei | 0:df031b60ca29 | 147 | } |
pcercuei | 0:df031b60ca29 | 148 | |
pcercuei | 0:df031b60ca29 | 149 | static ssize_t serial_write_dev_attr(const struct iio_device *dev, |
pcercuei | 0:df031b60ca29 | 150 | const char *attr, const char *src, size_t len, bool is_debug) |
pcercuei | 0:df031b60ca29 | 151 | { |
pcercuei | 0:df031b60ca29 | 152 | const struct iio_context *ctx = iio_device_get_context(dev); |
pcercuei | 0:df031b60ca29 | 153 | struct iio_context_pdata *pdata = ctx->pdata; |
pcercuei | 0:df031b60ca29 | 154 | |
pcercuei | 0:df031b60ca29 | 155 | return iiod_client_write_attr(pdata->iiod_client, NULL, |
pcercuei | 0:df031b60ca29 | 156 | dev, NULL, attr, src, len, is_debug); |
pcercuei | 0:df031b60ca29 | 157 | } |
pcercuei | 0:df031b60ca29 | 158 | |
pcercuei | 0:df031b60ca29 | 159 | static ssize_t serial_read_chn_attr(const struct iio_channel *chn, |
pcercuei | 0:df031b60ca29 | 160 | const char *attr, char *dst, size_t len) |
pcercuei | 0:df031b60ca29 | 161 | { |
pcercuei | 0:df031b60ca29 | 162 | const struct iio_device *dev = iio_channel_get_device(chn); |
pcercuei | 0:df031b60ca29 | 163 | const struct iio_context *ctx = iio_device_get_context(dev); |
pcercuei | 0:df031b60ca29 | 164 | struct iio_context_pdata *pdata = ctx->pdata; |
pcercuei | 0:df031b60ca29 | 165 | |
pcercuei | 0:df031b60ca29 | 166 | return iiod_client_read_attr(pdata->iiod_client, NULL, |
pcercuei | 0:df031b60ca29 | 167 | chn->dev, chn, attr, dst, len, false); |
pcercuei | 0:df031b60ca29 | 168 | } |
pcercuei | 0:df031b60ca29 | 169 | |
pcercuei | 0:df031b60ca29 | 170 | static ssize_t serial_write_chn_attr(const struct iio_channel *chn, |
pcercuei | 0:df031b60ca29 | 171 | const char *attr, const char *src, size_t len) |
pcercuei | 0:df031b60ca29 | 172 | { |
pcercuei | 0:df031b60ca29 | 173 | const struct iio_device *dev = iio_channel_get_device(chn); |
pcercuei | 0:df031b60ca29 | 174 | const struct iio_context *ctx = iio_device_get_context(dev); |
pcercuei | 0:df031b60ca29 | 175 | struct iio_context_pdata *pdata = ctx->pdata; |
pcercuei | 0:df031b60ca29 | 176 | |
pcercuei | 0:df031b60ca29 | 177 | return iiod_client_write_attr(pdata->iiod_client, NULL, |
pcercuei | 0:df031b60ca29 | 178 | dev, chn, attr, src, len, false); |
pcercuei | 0:df031b60ca29 | 179 | } |
pcercuei | 0:df031b60ca29 | 180 | |
pcercuei | 0:df031b60ca29 | 181 | static int serial_set_kernel_buffers_count(const struct iio_device *dev, |
pcercuei | 0:df031b60ca29 | 182 | unsigned int nb_blocks) |
pcercuei | 0:df031b60ca29 | 183 | { |
pcercuei | 0:df031b60ca29 | 184 | const struct iio_context *ctx = iio_device_get_context(dev); |
pcercuei | 0:df031b60ca29 | 185 | struct iio_context_pdata *pdata = ctx->pdata; |
pcercuei | 0:df031b60ca29 | 186 | |
pcercuei | 0:df031b60ca29 | 187 | return iiod_client_set_kernel_buffers_count(pdata->iiod_client, NULL, |
pcercuei | 0:df031b60ca29 | 188 | dev, nb_blocks); |
pcercuei | 0:df031b60ca29 | 189 | } |
pcercuei | 0:df031b60ca29 | 190 | |
pcercuei | 0:df031b60ca29 | 191 | static ssize_t serial_write_data(struct iio_context_pdata *pdata, |
pcercuei | 0:df031b60ca29 | 192 | void *io_data, const char *data, size_t len) |
pcercuei | 0:df031b60ca29 | 193 | { |
pcercuei | 0:df031b60ca29 | 194 | ssize_t ret = (ssize_t) libserialport_to_errno(sp_blocking_write( |
pcercuei | 0:df031b60ca29 | 195 | pdata->port, data, len, pdata->timeout_ms)); |
pcercuei | 0:df031b60ca29 | 196 | |
pcercuei | 0:df031b60ca29 | 197 | DEBUG("Write returned %li: %s\n", (long) ret, data); |
pcercuei | 0:df031b60ca29 | 198 | return ret; |
pcercuei | 0:df031b60ca29 | 199 | } |
pcercuei | 0:df031b60ca29 | 200 | |
pcercuei | 0:df031b60ca29 | 201 | static ssize_t serial_read_data(struct iio_context_pdata *pdata, |
pcercuei | 0:df031b60ca29 | 202 | void *io_data, char *buf, size_t len) |
pcercuei | 0:df031b60ca29 | 203 | { |
pcercuei | 0:df031b60ca29 | 204 | ssize_t ret = (ssize_t) libserialport_to_errno(sp_blocking_read_next( |
pcercuei | 0:df031b60ca29 | 205 | pdata->port, buf, len, pdata->timeout_ms)); |
pcercuei | 0:df031b60ca29 | 206 | |
pcercuei | 0:df031b60ca29 | 207 | DEBUG("Read returned %li: %.*s\n", (long) ret, (int) ret, buf); |
pcercuei | 0:df031b60ca29 | 208 | return ret; |
pcercuei | 0:df031b60ca29 | 209 | } |
pcercuei | 0:df031b60ca29 | 210 | |
pcercuei | 0:df031b60ca29 | 211 | static ssize_t serial_read_line(struct iio_context_pdata *pdata, |
pcercuei | 0:df031b60ca29 | 212 | void *io_data, char *buf, size_t len) |
pcercuei | 0:df031b60ca29 | 213 | { |
pcercuei | 0:df031b60ca29 | 214 | size_t i; |
pcercuei | 0:df031b60ca29 | 215 | bool found = false; |
pcercuei | 0:df031b60ca29 | 216 | int ret; |
pcercuei | 0:df031b60ca29 | 217 | |
pcercuei | 0:df031b60ca29 | 218 | DEBUG("Readline size 0x%lx\n", (unsigned long) len); |
pcercuei | 0:df031b60ca29 | 219 | |
pcercuei | 0:df031b60ca29 | 220 | for (i = 0; i < len - 1; i++) { |
pcercuei | 0:df031b60ca29 | 221 | ret = libserialport_to_errno(sp_blocking_read_next( |
pcercuei | 0:df031b60ca29 | 222 | pdata->port, &buf[i], 1, |
pcercuei | 0:df031b60ca29 | 223 | pdata->timeout_ms)); |
pcercuei | 0:df031b60ca29 | 224 | if (ret < 0) { |
pcercuei | 0:df031b60ca29 | 225 | ERROR("sp_blocking_read_next returned %i\n", ret); |
pcercuei | 0:df031b60ca29 | 226 | return (ssize_t) ret; |
pcercuei | 0:df031b60ca29 | 227 | } |
pcercuei | 0:df031b60ca29 | 228 | |
pcercuei | 0:df031b60ca29 | 229 | DEBUG("Character: %c\n", buf[i]); |
pcercuei | 0:df031b60ca29 | 230 | |
pcercuei | 0:df031b60ca29 | 231 | if (buf[i] != '\n') |
pcercuei | 0:df031b60ca29 | 232 | found = true; |
pcercuei | 0:df031b60ca29 | 233 | else if (found) |
pcercuei | 0:df031b60ca29 | 234 | break; |
pcercuei | 0:df031b60ca29 | 235 | } |
pcercuei | 0:df031b60ca29 | 236 | |
pcercuei | 0:df031b60ca29 | 237 | /* No \n found? Just garbage data */ |
pcercuei | 0:df031b60ca29 | 238 | if (!found || i == len - 1) |
pcercuei | 0:df031b60ca29 | 239 | return -EIO; |
pcercuei | 0:df031b60ca29 | 240 | |
pcercuei | 0:df031b60ca29 | 241 | return (ssize_t) i + 1; |
pcercuei | 0:df031b60ca29 | 242 | } |
pcercuei | 0:df031b60ca29 | 243 | |
pcercuei | 0:df031b60ca29 | 244 | static void serial_shutdown(struct iio_context *ctx) |
pcercuei | 0:df031b60ca29 | 245 | { |
pcercuei | 0:df031b60ca29 | 246 | struct iio_context_pdata *ctx_pdata = ctx->pdata; |
pcercuei | 0:df031b60ca29 | 247 | unsigned int i; |
pcercuei | 0:df031b60ca29 | 248 | |
pcercuei | 0:df031b60ca29 | 249 | iiod_client_destroy(ctx_pdata->iiod_client); |
pcercuei | 0:df031b60ca29 | 250 | iio_mutex_destroy(ctx_pdata->lock); |
pcercuei | 0:df031b60ca29 | 251 | sp_close(ctx_pdata->port); |
pcercuei | 0:df031b60ca29 | 252 | sp_free_port(ctx_pdata->port); |
pcercuei | 0:df031b60ca29 | 253 | |
pcercuei | 0:df031b60ca29 | 254 | for (i = 0; i < iio_context_get_devices_count(ctx); i++) { |
pcercuei | 0:df031b60ca29 | 255 | const struct iio_device *dev = iio_context_get_device(ctx, i); |
pcercuei | 0:df031b60ca29 | 256 | struct iio_device_pdata *pdata = dev->pdata; |
pcercuei | 0:df031b60ca29 | 257 | |
pcercuei | 0:df031b60ca29 | 258 | free(pdata); |
pcercuei | 0:df031b60ca29 | 259 | } |
pcercuei | 0:df031b60ca29 | 260 | |
pcercuei | 0:df031b60ca29 | 261 | free(ctx_pdata); |
pcercuei | 0:df031b60ca29 | 262 | } |
pcercuei | 0:df031b60ca29 | 263 | |
pcercuei | 0:df031b60ca29 | 264 | static int serial_set_timeout(struct iio_context *ctx, unsigned int timeout) |
pcercuei | 0:df031b60ca29 | 265 | { |
pcercuei | 0:df031b60ca29 | 266 | ctx->pdata->timeout_ms = timeout; |
pcercuei | 0:df031b60ca29 | 267 | return 0; |
pcercuei | 0:df031b60ca29 | 268 | } |
pcercuei | 0:df031b60ca29 | 269 | |
pcercuei | 0:df031b60ca29 | 270 | static const struct iio_backend_ops serial_ops = { |
pcercuei | 0:df031b60ca29 | 271 | .get_version = serial_get_version, |
pcercuei | 0:df031b60ca29 | 272 | .open = serial_open, |
pcercuei | 0:df031b60ca29 | 273 | .close = serial_close, |
pcercuei | 0:df031b60ca29 | 274 | .read = serial_read, |
pcercuei | 0:df031b60ca29 | 275 | .write = serial_write, |
pcercuei | 0:df031b60ca29 | 276 | .read_device_attr = serial_read_dev_attr, |
pcercuei | 0:df031b60ca29 | 277 | .write_device_attr = serial_write_dev_attr, |
pcercuei | 0:df031b60ca29 | 278 | .read_channel_attr = serial_read_chn_attr, |
pcercuei | 0:df031b60ca29 | 279 | .write_channel_attr = serial_write_chn_attr, |
pcercuei | 0:df031b60ca29 | 280 | .set_kernel_buffers_count = serial_set_kernel_buffers_count, |
pcercuei | 0:df031b60ca29 | 281 | .shutdown = serial_shutdown, |
pcercuei | 0:df031b60ca29 | 282 | .set_timeout = serial_set_timeout, |
pcercuei | 0:df031b60ca29 | 283 | }; |
pcercuei | 0:df031b60ca29 | 284 | |
pcercuei | 0:df031b60ca29 | 285 | static const struct iiod_client_ops serial_iiod_client_ops = { |
pcercuei | 0:df031b60ca29 | 286 | .write = serial_write_data, |
pcercuei | 0:df031b60ca29 | 287 | .read = serial_read_data, |
pcercuei | 0:df031b60ca29 | 288 | .read_line = serial_read_line, |
pcercuei | 0:df031b60ca29 | 289 | }; |
pcercuei | 0:df031b60ca29 | 290 | |
pcercuei | 0:df031b60ca29 | 291 | static int apply_settings(struct sp_port *port, unsigned int baud_rate, |
pcercuei | 0:df031b60ca29 | 292 | unsigned int bits, unsigned int stop_bits, |
pcercuei | 0:df031b60ca29 | 293 | enum sp_parity parity, enum sp_flowcontrol flow) |
pcercuei | 0:df031b60ca29 | 294 | { |
pcercuei | 0:df031b60ca29 | 295 | int ret; |
pcercuei | 0:df031b60ca29 | 296 | |
pcercuei | 0:df031b60ca29 | 297 | ret = libserialport_to_errno(sp_set_baudrate(port, (int) baud_rate)); |
pcercuei | 0:df031b60ca29 | 298 | if (ret) |
pcercuei | 0:df031b60ca29 | 299 | return ret; |
pcercuei | 0:df031b60ca29 | 300 | |
pcercuei | 0:df031b60ca29 | 301 | ret = libserialport_to_errno(sp_set_bits(port, (int) bits)); |
pcercuei | 0:df031b60ca29 | 302 | if (ret) |
pcercuei | 0:df031b60ca29 | 303 | return ret; |
pcercuei | 0:df031b60ca29 | 304 | |
pcercuei | 0:df031b60ca29 | 305 | ret = libserialport_to_errno(sp_set_stopbits(port, (int) stop_bits)); |
pcercuei | 0:df031b60ca29 | 306 | if (ret) |
pcercuei | 0:df031b60ca29 | 307 | return ret; |
pcercuei | 0:df031b60ca29 | 308 | |
pcercuei | 0:df031b60ca29 | 309 | ret = libserialport_to_errno(sp_set_parity(port, parity)); |
pcercuei | 0:df031b60ca29 | 310 | if (ret) |
pcercuei | 0:df031b60ca29 | 311 | return ret; |
pcercuei | 0:df031b60ca29 | 312 | |
pcercuei | 0:df031b60ca29 | 313 | return libserialport_to_errno(sp_set_flowcontrol(port, flow)); |
pcercuei | 0:df031b60ca29 | 314 | } |
pcercuei | 0:df031b60ca29 | 315 | |
pcercuei | 0:df031b60ca29 | 316 | static struct iio_context * serial_create_context(const char *port_name, |
pcercuei | 0:df031b60ca29 | 317 | unsigned int baud_rate, unsigned int bits, |
pcercuei | 0:df031b60ca29 | 318 | enum sp_parity parity, enum sp_flowcontrol flow) |
pcercuei | 0:df031b60ca29 | 319 | { |
pcercuei | 0:df031b60ca29 | 320 | struct sp_port *port; |
pcercuei | 0:df031b60ca29 | 321 | struct iio_context_pdata *pdata; |
pcercuei | 0:df031b60ca29 | 322 | struct iio_context *ctx; |
pcercuei | 0:df031b60ca29 | 323 | char *name, *desc, *description; |
pcercuei | 0:df031b60ca29 | 324 | size_t desc_len; |
pcercuei | 0:df031b60ca29 | 325 | unsigned int i; |
pcercuei | 0:df031b60ca29 | 326 | int ret; |
pcercuei | 0:df031b60ca29 | 327 | |
pcercuei | 0:df031b60ca29 | 328 | ret = libserialport_to_errno(sp_get_port_by_name(port_name, &port)); |
pcercuei | 0:df031b60ca29 | 329 | if (ret) { |
pcercuei | 0:df031b60ca29 | 330 | errno = -ret; |
pcercuei | 0:df031b60ca29 | 331 | return NULL; |
pcercuei | 0:df031b60ca29 | 332 | } |
pcercuei | 0:df031b60ca29 | 333 | |
pcercuei | 0:df031b60ca29 | 334 | ret = libserialport_to_errno(sp_open(port, SP_MODE_READ_WRITE)); |
pcercuei | 0:df031b60ca29 | 335 | if (ret) { |
pcercuei | 0:df031b60ca29 | 336 | errno = -ret; |
pcercuei | 0:df031b60ca29 | 337 | goto err_free_port; |
pcercuei | 0:df031b60ca29 | 338 | } |
pcercuei | 0:df031b60ca29 | 339 | |
pcercuei | 0:df031b60ca29 | 340 | ret = apply_settings(port, baud_rate, bits, 1, parity, flow); |
pcercuei | 0:df031b60ca29 | 341 | if (ret) { |
pcercuei | 0:df031b60ca29 | 342 | errno = -ret; |
pcercuei | 0:df031b60ca29 | 343 | goto err_close_port; |
pcercuei | 0:df031b60ca29 | 344 | } |
pcercuei | 0:df031b60ca29 | 345 | |
pcercuei | 0:df031b60ca29 | 346 | /* Empty the buffers */ |
pcercuei | 0:df031b60ca29 | 347 | sp_flush(port, SP_BUF_BOTH); |
pcercuei | 0:df031b60ca29 | 348 | |
pcercuei | 0:df031b60ca29 | 349 | name = sp_get_port_name(port); |
pcercuei | 0:df031b60ca29 | 350 | desc = sp_get_port_description(port); |
pcercuei | 0:df031b60ca29 | 351 | |
pcercuei | 0:df031b60ca29 | 352 | desc_len = sizeof(": \0") + strlen(name) + strlen(desc); |
pcercuei | 0:df031b60ca29 | 353 | description = malloc(desc_len); |
pcercuei | 0:df031b60ca29 | 354 | if (!description) { |
pcercuei | 0:df031b60ca29 | 355 | errno = ENOMEM; |
pcercuei | 0:df031b60ca29 | 356 | goto err_close_port; |
pcercuei | 0:df031b60ca29 | 357 | } |
pcercuei | 0:df031b60ca29 | 358 | |
pcercuei | 3:d147beabba0e | 359 | iio_snprintf(description, desc_len, "%s: %s", name, desc); |
pcercuei | 0:df031b60ca29 | 360 | |
pcercuei | 0:df031b60ca29 | 361 | pdata = zalloc(sizeof(*pdata)); |
pcercuei | 0:df031b60ca29 | 362 | if (!pdata) { |
pcercuei | 0:df031b60ca29 | 363 | errno = ENOMEM; |
pcercuei | 0:df031b60ca29 | 364 | goto err_free_description; |
pcercuei | 0:df031b60ca29 | 365 | } |
pcercuei | 0:df031b60ca29 | 366 | |
pcercuei | 0:df031b60ca29 | 367 | pdata->port = port; |
pcercuei | 0:df031b60ca29 | 368 | pdata->timeout_ms = DEFAULT_TIMEOUT_MS; |
pcercuei | 0:df031b60ca29 | 369 | |
pcercuei | 0:df031b60ca29 | 370 | pdata->lock = iio_mutex_create(); |
pcercuei | 0:df031b60ca29 | 371 | if (!pdata->lock) { |
pcercuei | 0:df031b60ca29 | 372 | errno = ENOMEM; |
pcercuei | 0:df031b60ca29 | 373 | goto err_free_pdata; |
pcercuei | 0:df031b60ca29 | 374 | } |
pcercuei | 0:df031b60ca29 | 375 | |
pcercuei | 0:df031b60ca29 | 376 | pdata->iiod_client = iiod_client_new(pdata, pdata->lock, |
pcercuei | 0:df031b60ca29 | 377 | &serial_iiod_client_ops); |
pcercuei | 0:df031b60ca29 | 378 | if (!pdata->iiod_client) |
pcercuei | 0:df031b60ca29 | 379 | goto err_destroy_mutex; |
pcercuei | 0:df031b60ca29 | 380 | |
pcercuei | 0:df031b60ca29 | 381 | ctx = iiod_client_create_context(pdata->iiod_client, NULL); |
pcercuei | 0:df031b60ca29 | 382 | if (!ctx) |
pcercuei | 0:df031b60ca29 | 383 | goto err_destroy_iiod_client; |
pcercuei | 0:df031b60ca29 | 384 | |
pcercuei | 0:df031b60ca29 | 385 | ctx->name = "serial"; |
pcercuei | 0:df031b60ca29 | 386 | ctx->ops = &serial_ops; |
pcercuei | 0:df031b60ca29 | 387 | ctx->pdata = pdata; |
pcercuei | 0:df031b60ca29 | 388 | ctx->description = description; |
pcercuei | 0:df031b60ca29 | 389 | |
pcercuei | 0:df031b60ca29 | 390 | for (i = 0; i < iio_context_get_devices_count(ctx); i++) { |
pcercuei | 0:df031b60ca29 | 391 | struct iio_device *dev = iio_context_get_device(ctx, i); |
pcercuei | 0:df031b60ca29 | 392 | |
pcercuei | 0:df031b60ca29 | 393 | dev->pdata = zalloc(sizeof(*dev->pdata)); |
pcercuei | 0:df031b60ca29 | 394 | if (!dev->pdata) { |
pcercuei | 0:df031b60ca29 | 395 | ret = -ENOMEM; |
pcercuei | 0:df031b60ca29 | 396 | goto err_context_destroy; |
pcercuei | 0:df031b60ca29 | 397 | } |
pcercuei | 0:df031b60ca29 | 398 | } |
pcercuei | 0:df031b60ca29 | 399 | |
pcercuei | 0:df031b60ca29 | 400 | return ctx; |
pcercuei | 0:df031b60ca29 | 401 | |
pcercuei | 0:df031b60ca29 | 402 | err_context_destroy: |
pcercuei | 0:df031b60ca29 | 403 | iio_context_destroy(ctx); |
pcercuei | 0:df031b60ca29 | 404 | errno = -ret; |
pcercuei | 0:df031b60ca29 | 405 | return NULL; |
pcercuei | 0:df031b60ca29 | 406 | |
pcercuei | 0:df031b60ca29 | 407 | err_destroy_iiod_client: |
pcercuei | 0:df031b60ca29 | 408 | iiod_client_destroy(pdata->iiod_client); |
pcercuei | 0:df031b60ca29 | 409 | err_destroy_mutex: |
pcercuei | 0:df031b60ca29 | 410 | iio_mutex_destroy(pdata->lock); |
pcercuei | 0:df031b60ca29 | 411 | err_free_pdata: |
pcercuei | 0:df031b60ca29 | 412 | free(pdata); |
pcercuei | 0:df031b60ca29 | 413 | err_free_description: |
pcercuei | 0:df031b60ca29 | 414 | free(description); |
pcercuei | 0:df031b60ca29 | 415 | err_close_port: |
pcercuei | 0:df031b60ca29 | 416 | sp_close(port); |
pcercuei | 0:df031b60ca29 | 417 | err_free_port: |
pcercuei | 0:df031b60ca29 | 418 | sp_free_port(port); |
pcercuei | 0:df031b60ca29 | 419 | return NULL; |
pcercuei | 0:df031b60ca29 | 420 | } |
pcercuei | 0:df031b60ca29 | 421 | |
pcercuei | 0:df031b60ca29 | 422 | static int serial_parse_params(const char *params, |
pcercuei | 0:df031b60ca29 | 423 | unsigned int *baud_rate, unsigned int *bits, |
pcercuei | 0:df031b60ca29 | 424 | enum sp_parity *parity, enum sp_flowcontrol *flow) |
pcercuei | 0:df031b60ca29 | 425 | { |
pcercuei | 0:df031b60ca29 | 426 | char *end; |
pcercuei | 0:df031b60ca29 | 427 | |
pcercuei | 0:df031b60ca29 | 428 | *baud_rate = strtoul(params, &end, 10); |
pcercuei | 0:df031b60ca29 | 429 | if (params == end) |
pcercuei | 0:df031b60ca29 | 430 | return -EINVAL; |
pcercuei | 0:df031b60ca29 | 431 | |
pcercuei | 0:df031b60ca29 | 432 | switch (*end) { |
pcercuei | 0:df031b60ca29 | 433 | case '\0': |
pcercuei | 0:df031b60ca29 | 434 | /* Default settings */ |
pcercuei | 0:df031b60ca29 | 435 | *bits = 8; |
pcercuei | 0:df031b60ca29 | 436 | *parity = SP_PARITY_NONE; |
pcercuei | 0:df031b60ca29 | 437 | *flow = SP_FLOWCONTROL_NONE; |
pcercuei | 0:df031b60ca29 | 438 | return 0; |
pcercuei | 0:df031b60ca29 | 439 | case 'n': |
pcercuei | 0:df031b60ca29 | 440 | *parity = SP_PARITY_NONE; |
pcercuei | 0:df031b60ca29 | 441 | break; |
pcercuei | 0:df031b60ca29 | 442 | case 'o': |
pcercuei | 0:df031b60ca29 | 443 | *parity = SP_PARITY_ODD; |
pcercuei | 0:df031b60ca29 | 444 | break; |
pcercuei | 0:df031b60ca29 | 445 | case 'e': |
pcercuei | 0:df031b60ca29 | 446 | *parity = SP_PARITY_EVEN; |
pcercuei | 0:df031b60ca29 | 447 | break; |
pcercuei | 0:df031b60ca29 | 448 | case 'm': |
pcercuei | 0:df031b60ca29 | 449 | *parity = SP_PARITY_MARK; |
pcercuei | 0:df031b60ca29 | 450 | break; |
pcercuei | 0:df031b60ca29 | 451 | case 's': |
pcercuei | 0:df031b60ca29 | 452 | *parity = SP_PARITY_SPACE; |
pcercuei | 0:df031b60ca29 | 453 | break; |
pcercuei | 0:df031b60ca29 | 454 | default: |
pcercuei | 0:df031b60ca29 | 455 | return -EINVAL; |
pcercuei | 0:df031b60ca29 | 456 | } |
pcercuei | 0:df031b60ca29 | 457 | |
pcercuei | 0:df031b60ca29 | 458 | params = (const char *)((uintptr_t) end + 1); |
pcercuei | 0:df031b60ca29 | 459 | |
pcercuei | 0:df031b60ca29 | 460 | if (!*params) { |
pcercuei | 0:df031b60ca29 | 461 | *bits = 8; |
pcercuei | 0:df031b60ca29 | 462 | *flow = SP_FLOWCONTROL_NONE; |
pcercuei | 0:df031b60ca29 | 463 | return 0; |
pcercuei | 0:df031b60ca29 | 464 | } |
pcercuei | 0:df031b60ca29 | 465 | |
pcercuei | 0:df031b60ca29 | 466 | *bits = strtoul(params, &end, 10); |
pcercuei | 0:df031b60ca29 | 467 | if (params == end) |
pcercuei | 0:df031b60ca29 | 468 | return -EINVAL; |
pcercuei | 0:df031b60ca29 | 469 | |
pcercuei | 0:df031b60ca29 | 470 | switch (*end) { |
pcercuei | 0:df031b60ca29 | 471 | case '\0': |
pcercuei | 0:df031b60ca29 | 472 | *flow = SP_FLOWCONTROL_NONE; |
pcercuei | 0:df031b60ca29 | 473 | return 0; |
pcercuei | 0:df031b60ca29 | 474 | case 'x': |
pcercuei | 0:df031b60ca29 | 475 | *flow = SP_FLOWCONTROL_XONXOFF; |
pcercuei | 0:df031b60ca29 | 476 | break; |
pcercuei | 0:df031b60ca29 | 477 | case 'r': |
pcercuei | 0:df031b60ca29 | 478 | *flow = SP_FLOWCONTROL_RTSCTS; |
pcercuei | 0:df031b60ca29 | 479 | break; |
pcercuei | 0:df031b60ca29 | 480 | case 'd': |
pcercuei | 0:df031b60ca29 | 481 | *flow = SP_FLOWCONTROL_DTRDSR; |
pcercuei | 0:df031b60ca29 | 482 | break; |
pcercuei | 0:df031b60ca29 | 483 | default: |
pcercuei | 0:df031b60ca29 | 484 | return -EINVAL; |
pcercuei | 0:df031b60ca29 | 485 | } |
pcercuei | 0:df031b60ca29 | 486 | |
pcercuei | 0:df031b60ca29 | 487 | /* We should have a '\0' after the flow character */ |
pcercuei | 0:df031b60ca29 | 488 | if (end[1]) |
pcercuei | 0:df031b60ca29 | 489 | return -EINVAL; |
pcercuei | 0:df031b60ca29 | 490 | else |
pcercuei | 0:df031b60ca29 | 491 | return 0; |
pcercuei | 0:df031b60ca29 | 492 | } |
pcercuei | 0:df031b60ca29 | 493 | |
pcercuei | 0:df031b60ca29 | 494 | struct iio_context * serial_create_context_from_uri(const char *uri) |
pcercuei | 0:df031b60ca29 | 495 | { |
pcercuei | 0:df031b60ca29 | 496 | struct iio_context *ctx = NULL; |
pcercuei | 0:df031b60ca29 | 497 | char *comma, *uri_dup; |
pcercuei | 0:df031b60ca29 | 498 | unsigned int baud_rate, bits; |
pcercuei | 0:df031b60ca29 | 499 | enum sp_parity parity; |
pcercuei | 0:df031b60ca29 | 500 | enum sp_flowcontrol flow; |
pcercuei | 0:df031b60ca29 | 501 | int ret; |
pcercuei | 0:df031b60ca29 | 502 | |
pcercuei | 0:df031b60ca29 | 503 | if (strncmp(uri, "serial:", sizeof("serial:") - 1) != 0) |
pcercuei | 0:df031b60ca29 | 504 | goto err_bad_uri; |
pcercuei | 0:df031b60ca29 | 505 | |
pcercuei | 0:df031b60ca29 | 506 | uri_dup = iio_strdup((const char *) |
pcercuei | 0:df031b60ca29 | 507 | ((uintptr_t) uri + sizeof("serial:") - 1)); |
pcercuei | 0:df031b60ca29 | 508 | if (!uri_dup) { |
pcercuei | 0:df031b60ca29 | 509 | errno = ENOMEM; |
pcercuei | 0:df031b60ca29 | 510 | return NULL; |
pcercuei | 0:df031b60ca29 | 511 | } |
pcercuei | 0:df031b60ca29 | 512 | |
pcercuei | 0:df031b60ca29 | 513 | comma = strchr(uri_dup, ','); |
pcercuei | 0:df031b60ca29 | 514 | if (!comma) |
pcercuei | 0:df031b60ca29 | 515 | goto err_free_dup; |
pcercuei | 0:df031b60ca29 | 516 | |
pcercuei | 0:df031b60ca29 | 517 | *comma = '\0'; |
pcercuei | 0:df031b60ca29 | 518 | |
pcercuei | 0:df031b60ca29 | 519 | ret = serial_parse_params((char *)((uintptr_t) comma + 1), |
pcercuei | 0:df031b60ca29 | 520 | &baud_rate, &bits, &parity, &flow); |
pcercuei | 0:df031b60ca29 | 521 | if (ret) |
pcercuei | 0:df031b60ca29 | 522 | goto err_free_dup; |
pcercuei | 0:df031b60ca29 | 523 | |
pcercuei | 0:df031b60ca29 | 524 | ctx = serial_create_context(uri_dup, baud_rate, bits, parity, flow); |
pcercuei | 0:df031b60ca29 | 525 | |
pcercuei | 0:df031b60ca29 | 526 | free(uri_dup); |
pcercuei | 0:df031b60ca29 | 527 | return ctx; |
pcercuei | 0:df031b60ca29 | 528 | |
pcercuei | 0:df031b60ca29 | 529 | err_free_dup: |
pcercuei | 0:df031b60ca29 | 530 | free(uri_dup); |
pcercuei | 0:df031b60ca29 | 531 | err_bad_uri: |
pcercuei | 0:df031b60ca29 | 532 | ERROR("Bad URI: \'%s\'\n", uri); |
pcercuei | 3:d147beabba0e | 533 | errno = EINVAL; |
pcercuei | 0:df031b60ca29 | 534 | return NULL; |
pcercuei | 0:df031b60ca29 | 535 | } |
pcercuei | 0:df031b60ca29 | 536 |