mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-05-15 04:19:26 -07:00
* Abstract primitive type from main logic in FuriEventLoop * Remove message_queue_i.h * Add stream buffer support for event loop * Add semaphore support for event loop * Add temporary unit test workaround * Make the linter happy * Add mutex support for event loop * Implement event subscription and unsubscription while the event loop is running * Implement edge events * Fix leftover logical errors * Add event loop timer example application * Implement flag-based edge trigger and one-shot mode * Add event loop mutex example application * Only notify the event loop if stream buffer is at or above its trigger level * Reformat comments * Add event loop stream buffer example application * Add event loop multiple elements example application * Improve event loop flag names * Remove redundant signal handler as it is already handled by the event loop * Refactor Power service, improve ViewHolder * Use ViewHolder instead of ViewDispatcher in About app * Enable ViewDispatcher queue on construction, deprecate view_dispatcher_enable_queue() * Remove all invocations of view_dispatcher_enable_queue() * Remove app-scened-template * Remove missing library from target.json * Port Accessor app to ViewHolder * Make the linter happy * Add example_view_holder application, update ViewHolder docs * Add example_view_dispatcher application, update ViewDispatcher docs * Replace FuriSemaphore with FuriApiLock, remove workaround delay * Fix logical error * Fix another logical error * Use the sources directive to speed up compilation * Use constant define macro * Improve FuriEventLoop documentation * Improve FuriEventLoop documentation once more * Bump API Version * Gui: remove redundant checks from ViewDispatcher * Gui: remove dead ifs from ViewDispatcher Co-authored-by: Silent <CookiePLMonster@users.noreply.github.com> Co-authored-by: hedger <hedger@users.noreply.github.com> Co-authored-by: あく <alleteam@gmail.com>
1866 lines
67 KiB
C
1866 lines
67 KiB
C
#include <furi.h>
|
||
#include <stdint.h>
|
||
|
||
#include <rpc/rpc.h>
|
||
#include <rpc/rpc_i.h>
|
||
#include <cli/cli.h>
|
||
#include <storage/storage.h>
|
||
#include <loader/loader.h>
|
||
#include <storage/filesystem_api_defines.h>
|
||
|
||
#include <lib/toolbox/api_lock.h>
|
||
#include <lib/toolbox/md5_calc.h>
|
||
#include <lib/toolbox/path.h>
|
||
|
||
#include <m-list.h>
|
||
#include "../test.h" // IWYU pragma: keep
|
||
|
||
#include <protobuf_version.h>
|
||
#include <pb.h>
|
||
#include <pb_encode.h>
|
||
#include <pb_decode.h>
|
||
#include <storage.pb.h>
|
||
#include <flipper.pb.h>
|
||
|
||
LIST_DEF(MsgList, PB_Main, M_POD_OPLIST)
|
||
#define M_OPL_MsgList_t() LIST_OPLIST(MsgList)
|
||
|
||
#define TEST_RPC_SESSIONS 2
|
||
|
||
/* MinUnit test framework doesn't allow passing context into tests,
|
||
* so we have to use global variables
|
||
*/
|
||
static Rpc* rpc = NULL;
|
||
static uint32_t command_id = 0;
|
||
|
||
typedef struct {
|
||
RpcSession* session;
|
||
FuriStreamBuffer* output_stream;
|
||
FuriApiLock session_close_lock;
|
||
FuriApiLock session_terminate_lock;
|
||
uint32_t timeout;
|
||
} RpcSessionContext;
|
||
|
||
static RpcSessionContext rpc_session[TEST_RPC_SESSIONS];
|
||
|
||
#define TAG "UnitTestsRpc"
|
||
|
||
#define MAX_RECEIVE_OUTPUT_TIMEOUT 3000
|
||
#define MAX_NAME_LENGTH 255
|
||
#define MAX_DATA_SIZE 512u // have to be exact as in rpc_storage.c
|
||
#define TEST_DIR_NAME EXT_PATH(".tmp/unit_tests/rpc")
|
||
#define TEST_DIR TEST_DIR_NAME "/"
|
||
#define MD5SUM_SIZE 16
|
||
|
||
#define PING_REQUEST 0
|
||
#define PING_RESPONSE 1
|
||
#define WRITE_REQUEST 0
|
||
#define READ_RESPONSE 1
|
||
|
||
#define DEBUG_PRINT 0
|
||
|
||
#define BYTES(x) (x), sizeof(x)
|
||
|
||
#define DISABLE_TEST(code) \
|
||
do { \
|
||
volatile int a = 0; \
|
||
if(a) { \
|
||
code \
|
||
} \
|
||
} while(0)
|
||
|
||
static void output_bytes_callback(void* ctx, uint8_t* got_bytes, size_t got_size);
|
||
static void
|
||
test_rpc_add_empty_to_list(MsgList_t msg_list, PB_CommandStatus status, uint32_t command_id);
|
||
static void test_rpc_encode_and_feed(MsgList_t msg_list, uint8_t session);
|
||
static void test_rpc_encode_and_feed_one(PB_Main* request, uint8_t session);
|
||
static void test_rpc_compare_messages(PB_Main* result, PB_Main* expected);
|
||
static void test_rpc_decode_and_compare(MsgList_t expected_msg_list, uint8_t session);
|
||
static void test_rpc_free_msg_list(MsgList_t msg_list);
|
||
static void test_rpc_session_close_callback(void* context);
|
||
static void test_rpc_session_terminated_callback(void* context);
|
||
|
||
static void test_rpc_setup(void) {
|
||
furi_check(!rpc);
|
||
furi_check(!(rpc_session[0].session));
|
||
|
||
rpc = furi_record_open(RECORD_RPC);
|
||
for(int i = 0; !(rpc_session[0].session) && (i < 10000); ++i) {
|
||
rpc_session[0].session = rpc_session_open(rpc, RpcOwnerUnknown);
|
||
furi_delay_tick(1);
|
||
}
|
||
furi_check(rpc_session[0].session);
|
||
|
||
rpc_session[0].output_stream = furi_stream_buffer_alloc(4096, 1);
|
||
rpc_session_set_send_bytes_callback(rpc_session[0].session, output_bytes_callback);
|
||
rpc_session[0].session_close_lock = api_lock_alloc_locked();
|
||
rpc_session[0].session_terminate_lock = api_lock_alloc_locked();
|
||
rpc_session_set_close_callback(rpc_session[0].session, test_rpc_session_close_callback);
|
||
rpc_session_set_terminated_callback(
|
||
rpc_session[0].session, test_rpc_session_terminated_callback);
|
||
rpc_session_set_context(rpc_session[0].session, &rpc_session[0]);
|
||
}
|
||
|
||
static void test_rpc_setup_second_session(void) {
|
||
furi_check(rpc);
|
||
furi_check(!(rpc_session[1].session));
|
||
|
||
for(int i = 0; !(rpc_session[1].session) && (i < 10000); ++i) {
|
||
rpc_session[1].session = rpc_session_open(rpc, RpcOwnerUnknown);
|
||
furi_delay_tick(1);
|
||
}
|
||
furi_check(rpc_session[1].session);
|
||
|
||
rpc_session[1].output_stream = furi_stream_buffer_alloc(1000, 1);
|
||
rpc_session_set_send_bytes_callback(rpc_session[1].session, output_bytes_callback);
|
||
rpc_session[1].session_close_lock = api_lock_alloc_locked();
|
||
rpc_session[1].session_terminate_lock = api_lock_alloc_locked();
|
||
rpc_session_set_close_callback(rpc_session[1].session, test_rpc_session_close_callback);
|
||
rpc_session_set_terminated_callback(
|
||
rpc_session[1].session, test_rpc_session_terminated_callback);
|
||
rpc_session_set_context(rpc_session[1].session, &rpc_session[1]);
|
||
}
|
||
|
||
static void test_rpc_teardown(void) {
|
||
furi_check(rpc_session[0].session_close_lock);
|
||
api_lock_relock(rpc_session[0].session_terminate_lock);
|
||
rpc_session_close(rpc_session[0].session);
|
||
api_lock_wait_unlock(rpc_session[0].session_terminate_lock);
|
||
furi_record_close(RECORD_RPC);
|
||
furi_stream_buffer_free(rpc_session[0].output_stream);
|
||
api_lock_free(rpc_session[0].session_close_lock);
|
||
api_lock_free(rpc_session[0].session_terminate_lock);
|
||
++command_id;
|
||
rpc_session[0].output_stream = NULL;
|
||
|