Files
mr-library/source/service.c
MacRsh bce4d10943 1.修复跟设备ops空指针访问。
2.新增设备手动设置操作者api。
3.PIN设备读写成功获得操作权后将释放操作锁(操作锁仅对PIN的open、close、ioctl时有效)。
4.日志输出优化。
2024-04-28 23:51:14 +08:00

681 lines
14 KiB
C

/*
* @copyright (c) 2023-2024, MR Development Team
*
* @license SPDX-License-Identifier: Apache-2.0
*
* @date 2023-10-20 MacRsh First version
*/
#include "../mr-library/include/mr_api.h"
#include <stdio.h>
static volatile int _mr_critical_level = 0;
static void start(void)
{
}
MR_INIT_EXPORT(start, "0");
static void end(void)
{
}
MR_INIT_EXPORT(end, "5.end");
/**
* @brief This function is auto initialized.
*/
void mr_auto_init(void)
{
/* Auto-initialization */
for (const mr_init_fn_t *fn = &_mr_auto_init_start; fn < &_mr_auto_init_end;
fn++)
{
(*fn)();
}
}
/**
* @brief This function disable the interrupt.
*/
MR_WEAK void mr_interrupt_disable(void)
{
}
/**
* @brief This function enable the interrupt.
*/
MR_WEAK void mr_interrupt_enable(void)
{
}
/**
* @brief This function enter the critical section.
*/
void mr_critical_enter(void)
{
if (_mr_critical_level == 0)
{
mr_interrupt_disable();
_mr_critical_level++;
}
}
/**
* @brief This function exit the critical section.
*/
void mr_critical_exit(void)
{
if (_mr_critical_level > 0)
{
_mr_critical_level--;
if (_mr_critical_level == 0)
{
mr_interrupt_enable();
}
}
}
/**
* @brief This function delay us.
*
* @param us The us to delay.
*/
MR_WEAK void mr_delay_us(size_t us)
{
#ifndef MR_CFG_SYSCLK_FREQ
#define MR_CFG_SYSCLK_FREQ (72000000)
#endif /* MR_CFG_SYSCLK_FREQ */
for (volatile size_t i = 0; i < us * (MR_CFG_SYSCLK_FREQ / 1000000); i++)
{
__asm__("nop");
}
#undef MR_CFG_SYSCLK_FREQ
}
/**
* @brief This function delay ms.
*
* @param ms The ms to delay.
*/
MR_WEAK void mr_delay_ms(size_t ms)
{
for (size_t i = 0; i < ms; i++)
{
mr_delay_us(1000);
}
}
/**
* @brief This function returns the error message.
*
* @param error The error code.
*
* @return The error message.
*/
const char *mr_strerror(int error)
{
switch (error)
{
case MR_EOK:
{
return "no error";
}
case MR_EPERM:
{
return "operation not permitted";
}
case MR_ENOENT:
{
return "no such file or directory";
}
case MR_EIO:
{
return "input/output error";
}
case MR_ENOMEM:
{
return "Out of resources";
}
case MR_EACCES:
{
return "permission denied";
}
case MR_EBUSY:
{
return "resource busy";
}
case MR_EEXIST:
{
return "resource already exists";
}
case MR_EINVAL:
{
return "invalid argument";
}
case MR_ETIMEOUT:
{
return "operation timed out";
}
default:
{
return "unknown error";
}
}
}
/**
* @brief This function printf output.
*
* @param buf The buffer to output.
* @param size The size of the buffer.
*
* @return The size of the actual output, otherwise an error code.
*/
MR_WEAK int mr_printf_output(const char *buf, size_t size)
{
static int descriptor = -1;
/* Try to open the serial device */
if (descriptor == -1)
{
#ifndef MR_CFG_PRINTF_NAME
#define MR_CFG_PRINTF_NAME ("serial1")
#endif /* MR_CFG_PRINTF_NAME */
int ret = mr_device_open(MR_CFG_PRINTF_NAME, MR_FLAG_WRONLY);
if (ret < 0)
{
return ret;
}
descriptor = ret;
}
/* Write data to the device */
return (int)mr_device_write(descriptor, buf, size);
}
/**
* @brief This function printf.
*
* @param fmt The format string.
* @param ... The arguments.
*
* @return The actual output size.
*/
int mr_printf(const char *fmt, ...)
{
#ifndef MR_CFG_PRINTF_BUFSZ
#define MR_CFG_PRINTF_BUFSZ (256)
#endif /* MR_CFG_PRINTF_BUFSZ */
char buf[MR_CFG_PRINTF_BUFSZ] = {0};
va_list args;
/* Format the string */
va_start(args, fmt);
int ret = vsnprintf(buf, sizeof(buf), fmt, args);
va_end(args);
/* Output the string */
return mr_printf_output(buf, ret);
}
/**
* @brief This function log printf output.
*
* @param buf The buffer to output.
* @param size The size of the buffer.
*
* @return The size of the actual output, otherwise an error code.
*/
MR_WEAK int mr_log_printf_output(const char *buf, size_t size)
{
static int descriptor = -1;
/* Try to open the serial device */
if (descriptor == -1)
{
#ifndef MR_CFG_LOG_PRINTF_NAME
#define MR_CFG_LOG_PRINTF_NAME ("serial1")
#endif /* MR_CFG_LOG_PRINTF_NAME */
int ret = mr_device_open(MR_CFG_LOG_PRINTF_NAME, MR_FLAG_WRONLY);
if (ret < 0)
{
return ret;
}
descriptor = ret;
}
/* Write data to the device */
return (int)mr_device_write(descriptor, buf, size);
}
/**
* @brief This function log printf.
*
* @param tag The log tag.
* @param fmt The format string.
* @param ... The arguments.
*
* @return The actual output size.
*/
int mr_log_printf(const char *tag, const char *fmt, ...)
{
#ifndef MR_CFG_LOG_PRINTF_BUFSZ
#define MR_CFG_LOG_PRINTF_BUFSZ (256)
#endif /* MR_CFG_LOG_PRINTF_BUFSZ */
char buf[MR_CFG_LOG_PRINTF_BUFSZ] = {0};
va_list args;
if (strcmp(tag, "null") == 0)
{
return 0;
}
/* Format the string */
va_start(args, fmt);
int ret = vsnprintf(buf, sizeof(buf), fmt, args);
va_end(args);
/* Output the string */
return mr_log_printf_output(buf, ret);
}
/**
* @brief This function assert handler.
*
* @param ex The assert expression.
* @param tag The assert tag.
* @param fn The assert function.
* @param file The assert file.
* @param line The assert line.
*/
MR_WEAK void mr_assert_handler(const char *ex, const char *tag, const char *fn,
const char *file, int line)
{
mr_printf("[A/%s] : %s %s %s:%d\n", ex, tag, fn, file, line);
while (1)
{
}
}
/**
* @brief This function initializes a fifo.
*
* @param fifo The fifo.
* @param buf The fifo buffer.
* @param size The fifo buffer size.
*
* @return The error code.
*/
int mr_fifo_init(struct mr_fifo *fifo, void *buf, size_t size)
{
MR_ASSERT(fifo != NULL);
MR_ASSERT((buf != NULL) || (size == 0));
/* Initialize the fifo */
fifo->in = 0;
fifo->out = 0;
fifo->in_mirror = false;
fifo->out_mirror = false;
fifo->dynamic = false;
fifo->buf = buf;
fifo->size = size;
return MR_EOK;
}
/**
* @brief This function resets a fifo.
*
* @param fifo The fifo.
*/
void mr_fifo_reset(struct mr_fifo *fifo)
{
MR_ASSERT(fifo != NULL);
fifo->in = 0;
fifo->out = 0;
fifo->in_mirror = false;
fifo->out_mirror = false;
}
/**
* @brief This function allocates a fifo.
*
* @param fifo The fifo.
* @param size The fifo buffer size.
*
* @return The error code.
*/
int mr_fifo_allocate(struct mr_fifo *fifo, size_t size)
{
MR_ASSERT(fifo != NULL);
/* Free the old buffer, if buffer is dynamic */
if ((fifo->dynamic == true) && (fifo->buf != NULL))
{
mr_free(fifo->buf);
mr_fifo_init(fifo, NULL, 0);
}
if (size == 0)
{
return MR_EOK;
}
/* Allocate a new buffer */
void *_buf = mr_malloc(size);
if (_buf == NULL)
{
return MR_ENOMEM;
}
mr_fifo_init(fifo, _buf, size);
fifo->dynamic = true;
return MR_EOK;
}
/**
* @brief This function frees a fifo.
*
* @param fifo The fifo.
*/
void mr_fifo_free(struct mr_fifo *fifo)
{
MR_ASSERT(fifo != NULL);
/* Free the old buffer, if buffer is dynamic */
if (fifo->dynamic == true)
{
mr_free(fifo->buf);
mr_fifo_init(fifo, NULL, 0);
}
}
/**
* @brief This function gets the used space of a fifo.
*
* @param fifo The fifo.
*
* @return The used space.
*/
size_t mr_fifo_used_get(struct mr_fifo *fifo)
{
MR_ASSERT(fifo != NULL);
if (fifo->in == fifo->out)
{
/* If in/out flags are the same, the fifo is empty */
return (fifo->in_mirror == fifo->out_mirror) ? 0 : fifo->size;
}
/* Return the used space */
return (fifo->in > fifo->out) ? fifo->in - fifo->out :
fifo->size - fifo->out + fifo->in;
}
/**
* @brief This function gets the free space of a fifo.
*
* @param fifo The fifo.
*
* @return The free space.
*/
size_t mr_fifo_space_get(struct mr_fifo *fifo)
{
MR_ASSERT(fifo != NULL);
return fifo->size - mr_fifo_used_get(fifo);
}
/**
* @brief This function gets the size of a fifo.
*
* @param fifo The fifo.
*
* @return The size.
*/
size_t mr_fifo_size_get(struct mr_fifo *fifo)
{
MR_ASSERT(fifo != NULL);
return fifo->size;
}
/**
* @brief This function peeks data from a fifo.
*
* @param fifo The fifo.
* @param buf The buffer to store the data.
* @param count The number of bytes to peek.
*
* @return The number of bytes peeked.
*/
size_t mr_fifo_peek(struct mr_fifo *fifo, void *buf, size_t count)
{
MR_ASSERT(fifo != NULL);
MR_ASSERT((buf != NULL) || (count == 0));
uint8_t *_buf = (uint8_t *)buf;
/* Get used space, limit by count */
size_t used = mr_fifo_used_get(fifo);
if (used < count)
{
count = used;
}
if (count == 0)
{
return 0;
}
/* Read data */
size_t end = fifo->size - fifo->out;
if (end > count)
{
/* If there is enough space at the end, read it all at once */
memcpy(_buf, &fifo->buf[fifo->out], count);
return count;
}
/* If there is not enough space at the end, read it in two parts */
memcpy(_buf, &fifo->buf[fifo->out], end);
memcpy(&_buf[end], fifo->buf, count - end);
return count;
}
/**
* @brief This function discards data from a fifo.
*
* @param fifo The fifo.
* @param count The number of bytes to discard.
*
* @return The number of bytes discarded.
*/
size_t mr_fifo_discard(struct mr_fifo *fifo, size_t count)
{
MR_ASSERT(fifo != NULL);
/* Get used space, limit by count */
size_t used = mr_fifo_used_get(fifo);
if (used < count)
{
count = used;
}
if (count == 0)
{
return 0;
}
/* Read data */
size_t end = fifo->size - fifo->out;
if (end > count)
{
fifo->out += count;
return count;
}
/* Mirror flag */
fifo->out_mirror = ~fifo->out_mirror;
fifo->out = count - end;
return count;
}
/**
* @brief This function reads data from a fifo.
*
* @param fifo The fifo.
* @param buf The buffer to store the data.
* @param count The number of bytes to read.
*
* @return The number of bytes read.
*/
size_t mr_fifo_read(struct mr_fifo *fifo, void *buf, size_t count)
{
MR_ASSERT(fifo != NULL);
MR_ASSERT((buf != NULL) || (count == 0));
uint8_t *_buf = (uint8_t *)buf;
/* Get used space, limit by count */
size_t used = mr_fifo_used_get(fifo);
if (used < count)
{
count = used;
}
if (count == 0)
{
return 0;
}
/* Read data */
size_t end = fifo->size - fifo->out;
if (end > count)
{
/* If there is enough space at the end, read it all at once */
memcpy(_buf, &fifo->buf[fifo->out], count);
fifo->out += count;
return count;
}
/* If there is not enough space at the end, read it in two parts */
memcpy(_buf, &fifo->buf[fifo->out], end);
memcpy(&_buf[end], fifo->buf, count - end);
/* Mirror flag */
fifo->out_mirror = ~fifo->out_mirror;
fifo->out = count - end;
return count;
}
/**
* @brief This function writes data to a fifo.
*
* @param fifo The fifo.
* @param buf The buffer to store the data.
* @param count The number of bytes to write.
*
* @return The number of bytes written.
*/
size_t mr_fifo_write(struct mr_fifo *fifo, const void *buf, size_t count)
{
MR_ASSERT(fifo != NULL);
MR_ASSERT((buf != NULL) || (count == 0));
uint8_t *_buf = (uint8_t *)buf;
/* Get free space, limit by count */
size_t space = mr_fifo_space_get(fifo);
if (space < count)
{
count = space;
}
if (count == 0)
{
return 0;
}
/* Write data */
size_t end = fifo->size - fifo->in;
if (end > count)
{
/* If there is enough space at the end, write it all at once */
memcpy(&fifo->buf[fifo->in], _buf, count);
fifo->in += count;
return count;
}
/* If there is not enough space at the end, write it in two parts */
memcpy(&fifo->buf[fifo->in], _buf, end);
memcpy(fifo->buf, &_buf[end], count - end);
/* Mirror flag */
fifo->in_mirror = ~fifo->in_mirror;
fifo->in = count - end;
return count;
}
/**
* @brief This function writes data to a fifo without checking for space.
*
* @param fifo The fifo.
* @param buf The buffer to store the data.
* @param count The number of bytes to write.
*
* @return The number of bytes written.
*/
size_t mr_fifo_write_force(struct mr_fifo *fifo, const void *buf, size_t count)
{
MR_ASSERT(fifo != NULL);
MR_ASSERT((buf != NULL) || (count == 0));
uint8_t *_buf = (uint8_t *)buf;
if (count == 0)
{
return 0;
}
/* Skip data that will be overwritten */
if (count > fifo->size)
{
_buf = &_buf[count - fifo->size];
count = fifo->size;
}
size_t space = mr_fifo_space_get(fifo);
size_t end = fifo->size - fifo->in;
if (end > count)
{
/* If there is enough space at the end, write it all at once */
memcpy(&fifo->buf[fifo->in], _buf, count);
fifo->in += count;
/* If free space is exceeded, move the out index to the in index */
if (count > space)
{
fifo->out = fifo->in;
}
return count;
}
/* If there is not enough space at the end, write it in two parts */
memcpy(&fifo->buf[fifo->in], _buf, end);
memcpy(fifo->buf, &_buf[end], count - end);
/* Mirror flag */
fifo->in_mirror = ~fifo->in_mirror;
fifo->in = count - end;
/* If free space is exceeded, move the out index to the in index */
if (count > space)
{
/* If the in index crosses the out index, the in flag is mirrored */
if (fifo->in <= fifo->out)
{
fifo->in_mirror = ~fifo->in_mirror;
}
fifo->out = fifo->in;
}
return count;
}