1.添加首个组件:事件循环。

This commit is contained in:
MacRsh
2023-09-16 23:31:30 +08:00
parent 410d89d17e
commit 6b5650cb63
3 changed files with 354 additions and 0 deletions

BIN
document/resource/eloop.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

307
module/eloop/eloop.c Normal file
View File

@@ -0,0 +1,307 @@
/*
* Copyright (c) 2023, mr-library Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2023-09-16 MacRsh first version
*/
#include "eloop.h"
#if (MR_CFG_ELOOP == MR_CFG_ENABLE)
#define DEBUG_TAG "eloop"
/**
* @struct eloop event
*/
struct mr_event
{
struct mr_avl list; /* Event list */
mr_err_t (*cb)(mr_eloop_t loop, void *args); /* Event callback */
void *args; /* Event args */
};
typedef struct mr_event *mr_event_t; /* Type for event */
/**
* @brief This function finds a eloop.
*
* @param name The name of the eloop.
*
* @return A pointer to the found eloop, or MR_NULL if not found.
*/
mr_eloop_t mr_eloop_find(const char *name)
{
MR_ASSERT(name != MR_NULL);
/* Find the eloop object from the container */
return (mr_eloop_t)mr_object_find(name, Mr_Object_Type_Module);
}
/**
* @brief This function adds an eloop to the container.
*
* @param eloop The eloop to be added.
* @param name The name of the eloop.
* @param queue_size The size of the queue.
*
* @return MR_ERR_OK on success, otherwise an error code.
*
* @note If events are lost, increase the queue size or processing frequency.
*/
mr_err_t mr_eloop_add(mr_eloop_t eloop, const char *name, mr_size_t queue_size)
{
mr_uint32_t *mem = MR_NULL;
mr_err_t ret = MR_ERR_OK;
MR_ASSERT(eloop != MR_NULL);
MR_ASSERT(name != MR_NULL);
MR_ASSERT(queue_size != 0);
mem = mr_malloc(queue_size * sizeof(*mem));
if (mem == MR_NULL)
{
MR_DEBUG_D(DEBUG_TAG, "[%s] add failed: [%d]\r\n", name, -MR_ERR_NO_MEMORY);
return -MR_ERR_NO_MEMORY;
}
/* Initialize the private fields */
mr_rb_init(&eloop->queue, mem, queue_size * sizeof(*mem));
eloop->list = MR_NULL;
/* Add the object to the container */
ret = mr_object_add(&eloop->object, name, Mr_Object_Type_Module);
if (ret != MR_ERR_OK)
{
MR_DEBUG_D(DEBUG_TAG, "[%s] add failed: [%d]\r\n", name, ret);
mr_rb_init(&eloop->queue, MR_NULL, 0);
mr_free(mem);
}
return ret;
}
/**
* @brief This function removes an eloop from the container.
*
* @param eloop The eloop to be removed.
*
* @return MR_ERR_OK on success, otherwise an error code.
*/
mr_err_t mr_eloop_remove(mr_eloop_t eloop)
{
mr_err_t ret = MR_ERR_OK;
MR_ASSERT(eloop != MR_NULL);
MR_ASSERT(eloop->object.type == Mr_Object_Type_Module);
/* Remove the object from the container */
ret = mr_object_remove(&eloop->object);
if (ret != MR_ERR_OK)
{
MR_DEBUG_D(DEBUG_TAG, "[%s] remove failed: [%d]\r\n", eloop->object.name, ret);
return ret;
}
/* Reset the private fields */
mr_free(eloop->queue.buffer);
mr_rb_init(&eloop->queue, MR_NULL, 0);
eloop->list = MR_NULL;
return MR_ERR_OK;
}
/**
* @brief This function handles events.
*
* @param eloop The eloop to be handled.
*
* @note Only events that have already occurred will be handled.
*/
void mr_eloop_handle(mr_eloop_t eloop)
{
mr_size_t count = 0;
mr_uint32_t id = 0;
MR_ASSERT(eloop != MR_NULL);
MR_ASSERT(eloop->object.type == Mr_Object_Type_Module);
/* Get the number of current events */
count = mr_rb_get_data_size(&eloop->queue);
/* Read the event id from the queue */
while (count != 0)
{
/* Read the event id */
mr_rb_read(&eloop->queue, &id, sizeof(id));
count -= sizeof(id);
/* Find the event */
mr_event_t event = (mr_event_t)mr_avl_find(eloop->list, id);
if (event == NULL)
{
MR_DEBUG_D(DEBUG_TAG, "[%s] handle failed: [%d]\r\n", eloop->object.name, -MR_ERR_NOT_FOUND);
continue;
}
/* Call the event callback */
event->cb(eloop, event->args);
}
}
/**
* @brief This function creates an event.
*
* @param eloop The eloop to be created.
* @param id The id of the event.
* @param cb The callback of the event.
* @param args The args of the event.
*
* @return MR_ERR_OK on success, otherwise an error code.
*/
mr_err_t mr_eloop_create_event(mr_eloop_t eloop, mr_uint32_t id, mr_err_t (*cb)(mr_eloop_t ep, void *args), void *args)
{
mr_event_t event = MR_NULL;
MR_ASSERT(eloop != MR_NULL);
MR_ASSERT(eloop->object.type == Mr_Object_Type_Module);
MR_ASSERT(cb != MR_NULL);
/* Check if the event already exists */
if (mr_avl_find(eloop->list, id) != MR_NULL)
{
MR_DEBUG_D(DEBUG_TAG, "[%s] watch event failed: [%d]\r\n", eloop->object.name, -MR_ERR_BUSY);
return -MR_ERR_BUSY;
}
event = (mr_event_t)mr_malloc(sizeof(struct mr_event));
if (event == MR_NULL)
{
MR_DEBUG_D(DEBUG_TAG, "[%s] watch event failed: [%d]\r\n", eloop->object.name, -MR_ERR_NO_MEMORY);
return -MR_ERR_NO_MEMORY;
}
/* Initialize the private fields */
mr_avl_init(&event->list, id);
event->cb = cb;
event->args = args;
/* Disable interrupt */
mr_interrupt_disable();
/* Insert the event into the eloop list */
mr_avl_insert(&(eloop->list), &(event->list));
/* Enable interrupt */
mr_interrupt_enable();
return MR_ERR_OK;
}
/**
* @brief This function deletes an event.
*
* @param eloop The eloop to be deleted.
* @param id The id of the event.
*
* @return MR_ERR_OK on success, otherwise an error code.
*/
mr_err_t mr_eloop_delete_event(mr_eloop_t eloop, mr_uint32_t id)
{
mr_event_t event = MR_NULL;
MR_ASSERT(eloop != MR_NULL);
MR_ASSERT(eloop->object.type == Mr_Object_Type_Module);
/* Check if the event already exists */
event = (mr_event_t)mr_avl_find(eloop->list, id);
/* Disable interrupt */
mr_interrupt_disable();
/* Insert the event into the eloop list */
mr_avl_remove(&(eloop->list), &(event->list));
/* Enable interrupt */
mr_interrupt_enable();
/* Free the event memory */
mr_free(event);
return MR_ERR_OK;
}
/**
* @brief This function notifies an event.
*
* @param eloop The eloop to be notified.
* @param id The id of the event.
*
* @return MR_ERR_OK on success, otherwise an error code.
*/
mr_err_t mr_eloop_notify_event(mr_eloop_t eloop, mr_uint32_t id)
{
MR_ASSERT(eloop != MR_NULL);
MR_ASSERT(eloop->object.type == Mr_Object_Type_Module);
if (mr_rb_write(&eloop->queue, &id, sizeof(id)) != sizeof(id))
{
MR_DEBUG_D(DEBUG_TAG, "[%s] post event failed: [%d]\r\n", eloop->object.name, -MR_ERR_BUSY);
return -MR_ERR_BUSY;
}
return MR_ERR_OK;
}
/**
* @brief This function triggers an event.
*
* @param eloop The eloop to be triggered.
* @param id The id of the event.
*
* @return MR_ERR_OK on success, otherwise an error code.
*/
mr_err_t mr_eloop_trigger_event(mr_eloop_t eloop, mr_uint32_t id)
{
MR_ASSERT(eloop != MR_NULL);
MR_ASSERT(eloop->object.type == Mr_Object_Type_Module);
/* Find the event */
mr_event_t event = (mr_event_t)mr_avl_find(eloop->list, id);
if (event == NULL)
{
MR_DEBUG_D(DEBUG_TAG, "[%s] handle failed: [%d]\r\n", eloop->object.name, -MR_ERR_NOT_FOUND);
return -MR_ERR_NOT_FOUND;
}
/* Call the event callback */
event->cb(eloop, event->args);
return MR_ERR_OK;
}
/**
* @brief This function converts a string to an id.
*
* @param string The string to be converted.
* @param size The size of the string.
*
* @return The id of the string.
*/
mr_uint32_t mr_eloop_string_to_id(const char *string, mr_size_t size)
{
mr_uint32_t id = 2166136261u;
for (mr_size_t count = 0; count < size; count++)
{
id ^= (mr_uint32_t)string[count];
id *= 16777619u;
}
return id;
}
#endif

47
module/eloop/eloop.h Normal file
View File

@@ -0,0 +1,47 @@
/*
* Copyright (c) 2023, mr-library Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2023-09-16 MacRsh first version
*/
#ifndef _ELOOP_H_
#define _ELOOP_H_
#include "mrapi.h"
#if (MR_CFG_ELOOP == MR_CFG_ENABLE)
/**
* @struct Event loop
*/
struct mr_eloop
{
struct mr_object object; /* Eloop object */
struct mr_rb queue; /* Event queue */
mr_avl_t list; /* Event list */
};
typedef struct mr_eloop *mr_eloop_t; /* Type for event loop */
/**
* @addtogroup Eloop
* @{
*/
mr_eloop_t mr_eloop_find(const char *name);
mr_err_t mr_eloop_add(mr_eloop_t eloop, const char *name, mr_size_t queue_size);
mr_err_t mr_eloop_remove(mr_eloop_t eloop);
void mr_eloop_handle(mr_eloop_t eloop);
mr_err_t mr_eloop_create_event(mr_eloop_t eloop, mr_uint32_t id, mr_err_t (*cb)(mr_eloop_t ep, void *args), void *args);
mr_err_t mr_eloop_delete_event(mr_eloop_t eloop, mr_uint32_t id);
mr_err_t mr_eloop_notify_event(mr_eloop_t eloop, mr_uint32_t id);
mr_err_t mr_eloop_trigger_event(mr_eloop_t eloop, mr_uint32_t id);
mr_uint32_t mr_eloop_string_to_id(const char *string, mr_size_t size);
/** @} */
#endif
#endif /* _ELOOP_H_ */