

6 changed files with 231 additions and 28 deletions
@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Kaspar Schleiser <kaspar@schleiser.de> |
||||
* |
||||
* This file is subject to the terms and conditions of the GNU Lesser |
||||
* General Public License v2.1. See the file LICENSE in the top level |
||||
* directory for more details. |
||||
*/ |
||||
|
||||
/**
|
||||
* @ingroup sys |
||||
* @{ |
||||
* @file |
||||
* @brief ISR -> userspace pipe interface |
||||
* |
||||
* @author Kaspar Schleiser <kaspar@schleiser.de> |
||||
* |
||||
*/ |
||||
|
||||
#ifndef ISRPIPE_H |
||||
#define ISRPIPE_H |
||||
|
||||
#include <stdint.h> |
||||
|
||||
#include "mutex.h" |
||||
#include "tsrb.h" |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
/**
|
||||
* @brief Context structure for isrpipe |
||||
*/ |
||||
typedef struct { |
||||
mutex_t mutex; /**< isrpipe mutex */ |
||||
tsrb_t tsrb; /**< isrpipe thread safe ringbuffer */ |
||||
} isrpipe_t; |
||||
|
||||
/**
|
||||
* @brief Static initializer for irspipe |
||||
*/ |
||||
#define ISRPIPE_INIT(tsrb_buf) { .mutex = MUTEX_INIT, .tsrb = TSRB_INIT(tsrb_buf) } |
||||
|
||||
/**
|
||||
* @brief Initialisation function for isrpipe |
||||
* |
||||
* @param[in] isrpipe isrpipe object to initialize |
||||
* @param[in] buf buffer to use as ringbuffer (must be power of two sized!) |
||||
* @param[in] bufsize size of @p buf |
||||
*/ |
||||
void isrpipe_init(isrpipe_t *isrpipe, char *buf, size_t bufsize); |
||||
|
||||
/**
|
||||
* @brief Put one character into the isrpipe's buffer |
||||
* |
||||
* @param[in] isrpipe isrpipe object to initialize |
||||
* @param[in] c character to add to isrpipe buffer |
||||
* |
||||
* @returns 0 if character could be added |
||||
* @returns -1 if buffer was full |
||||
*/ |
||||
int isrpipe_write_one(isrpipe_t *isrpipe, char c); |
||||
|
||||
/**
|
||||
* @brief Read data from isrpipe (blocking) |
||||
* |
||||
* @param[in] isrpipe isrpipe object to operate on |
||||
* @param[in] buf buffer to write to |
||||
* @param[in] count number of bytes to read |
||||
* |
||||
* @returns number of bytes read |
||||
*/ |
||||
int isrpipe_read(isrpipe_t *isrpipe, char *buf, size_t count); |
||||
|
||||
/**
|
||||
* @brief Read data from isrpipe (with timeout, blocking) |
||||
* |
||||
* Currently, the timeout parameter is applied on every underlying read, which |
||||
* might be *per single byte*. |
||||
* |
||||
* @note This function might return less than @p count bytes |
||||
* |
||||
* @param[in] isrpipe isrpipe object to operate on |
||||
* @param[in] buf buffer to write to |
||||
* @param[in] count number of bytes to read |
||||
* @param[in] timeout timeout in ms |
||||
* |
||||
* @returns number of bytes read |
||||
* @returns -ETIMEDOUT on timeout |
||||
*/ |
||||
int isrpipe_read_timeout(isrpipe_t *isrpipe, char *buf, size_t count, uint32_t timeout); |
||||
|
||||
/**
|
||||
* @brief Read data from isrpipe (with timeout, blocking, wait until all read) |
||||
* |
||||
* This function is like @ref isrpipe_read_timeout, but will only return on |
||||
* timeout or when @p count bytes have been received. |
||||
* |
||||
* @param[in] isrpipe isrpipe object to operate on |
||||
* @param[in] buf buffer to write to |
||||
* @param[in] count number of bytes to read |
||||
* @param[in] timeout timeout in ms |
||||
* |
||||
* @returns number of bytes read |
||||
* @returns -ETIMEDOUT on timeout |
||||
*/ |
||||
int isrpipe_read_all_timeout(isrpipe_t *isrpipe, char *buf, size_t count, uint32_t timeout); |
||||
|
||||
#ifdef __cplusplus |
||||
} |
||||
#endif |
||||
/** @} */ |
||||
#endif /* ISRPIPE_H */ |
@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Kaspar Schleiser <kaspar@schleiser.de> |
||||
* |
||||
* This file is subject to the terms and conditions of the GNU Lesser |
||||
* General Public License v2.1. See the file LICENSE in the top level |
||||
* directory for more details. |
||||
*/ |
||||
|
||||
/**
|
||||
* @ingroup sys |
||||
* @{ |
||||
* @file |
||||
* @brief ISR -> userspace pipe implementation |
||||
* |
||||
* @author Kaspar Schleiser <kaspar@schleiser.de> |
||||
* |
||||
* @} |
||||
*/ |
||||
|
||||
#include <errno.h> |
||||
|
||||
#include "isrpipe.h" |
||||
#include "xtimer.h" |
||||
|
||||
void isrpipe_init(isrpipe_t *isrpipe, char *buf, size_t bufsize) |
||||
{ |
||||
mutex_init(&isrpipe->mutex); |
||||
tsrb_init(&isrpipe->tsrb, buf, bufsize); |
||||
} |
||||
|
||||
int isrpipe_write_one(isrpipe_t *isrpipe, char c) |
||||
{ |
||||
int res = tsrb_add_one(&isrpipe->tsrb, c); |
||||
|
||||
/* `res` is either 0 on success or -1 when the buffer is full. Either way,
|
||||
* unlocking the mutex is fine. |
||||
*/ |
||||
mutex_unlock(&isrpipe->mutex); |
||||
|
||||
return res; |
||||
} |
||||
|
||||
int isrpipe_read(isrpipe_t *isrpipe, char *buffer, size_t count) |
||||
{ |
||||
int res; |
||||
|
||||
while (!(res = tsrb_get(&isrpipe->tsrb, buffer, count))) { |
||||
mutex_lock(&isrpipe->mutex); |
||||
} |
||||
return res; |
||||
} |
||||
|
||||
typedef struct { |
||||
mutex_t *mutex; |
||||
int flag; |
||||
} _isrpipe_timeout_t; |
||||
|
||||
static void _cb(void *arg) |
||||
{ |
||||
_isrpipe_timeout_t *_timeout = (_isrpipe_timeout_t *) arg; |
||||
|
||||
_timeout->flag = 1; |
||||
mutex_unlock(_timeout->mutex); |
||||
} |
||||
|
||||
int isrpipe_read_timeout(isrpipe_t *isrpipe, char *buffer, size_t count, uint32_t timeout) |
||||
{ |
||||
int res; |
||||
|
||||
_isrpipe_timeout_t _timeout = { .mutex = &isrpipe->mutex, .flag = 0 }; |
||||
|
||||
xtimer_t timer = { .callback = _cb, .arg = &_timeout }; |
||||
|
||||
xtimer_set(&timer, timeout); |
||||
while (!(res = tsrb_get(&isrpipe->tsrb, buffer, count))) { |
||||
mutex_lock(&isrpipe->mutex); |
||||
if (_timeout.flag) { |
||||
res = -ETIMEDOUT; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
xtimer_remove(&timer); |
||||
return res; |
||||
} |
||||
|
||||
|
||||
int isrpipe_read_all_timeout(isrpipe_t *isrpipe, char *buffer, size_t count, uint32_t timeout) |
||||
{ |
||||
char *pos = buffer; |
||||
|
||||
while (count) { |
||||
int res = isrpipe_read_timeout(isrpipe, pos, count, timeout); |
||||
if (res >= 0) { |
||||
count -= res; |
||||
pos += res; |
||||
} |
||||
else { |
||||
return res; |
||||
} |
||||
} |
||||
|
||||
return pos - buffer; |
||||
} |
Loading…
Reference in new issue