#include "nfc_rpc_i.h"
 
#define TAG "NfcRpc"
 
static const NfcRpcCallbacks nfc_rpc_callbacks[] = {
    {
        .alloc = nfc_rpc_nfca_alloc,
        .free = NULL,
    },
    {
        .alloc = nfc_rpc_mf_ultralight_alloc,
        .free = NULL,
    },
    {
        .alloc = nfc_rpc_mf_classic_alloc,
        .free = NULL,
    }};
 
uint32_t nfc_rpc_exit_callback(void* context) {
    UNUSED(context);
    return VIEW_NONE;
}
 
void nfc_rpc_draw_callback(Canvas* canvas, void* context) {
    UNUSED(context);
    canvas_clear(canvas);
    canvas_set_color(canvas, ColorBlack);
    canvas_set_font(canvas, FontPrimary);
    canvas_draw_str(canvas, 32, 0, "NFC RPC Actor running...");
}
 
bool nfc_rpc_input_callback(InputEvent* event, void* context) {
    UNUSED(context);
    UNUSED(event);
    return false;
}
 
static void
    nfc_rpc_receive_data_exchange_callback(const uint8_t* data, size_t data_size, void* context) {
    NfcRpc* app = context;
    NfcRpcEvent event;
    FURI_LOG_I(TAG, "Received %d bytes", data_size);
    event.type = NfcRpcEventDataExchange;
    event.data = data;
    event.data_size = data_size;
    furi_message_queue_put(app->queue, &event, FuriWaitForever);
    view_dispatcher_send_custom_event(app->view_dispatcher, NfcRpcCustomEventMessageReceived);
}
 
static void nfc_rpc_rpc_command_callback(RpcAppSystemEvent event, void* context) {
    furi_assert(context);
    NfcRpc* app = context;
 
    if(event == RpcAppEventSessionClose) {
        rpc_system_app_set_callback(app->rpc, NULL, NULL);
        rpc_system_app_set_data_exchange_callback(app->rpc, NULL, NULL);
        view_dispatcher_stop(app->view_dispatcher);
        app->rpc = NULL;
    }
    if(event == RpcAppEventAppExit) {
        view_dispatcher_switch_to_view(app->view_dispatcher, VIEW_NONE);
        view_dispatcher_stop(app->view_dispatcher);
        rpc_system_app_confirm(app->rpc, RpcAppEventAppExit, true);
    }
}
 
static bool nfc_rpc_init_rpc(NfcRpc* app, const char* args) {
    bool ret = false;
    if(args && strlen(args)) {
        uint32_t rpc = 0;
        if(sscanf(args, "RPC %lX", &rpc) == 1) {
            app->rpc = (RpcAppSystem*)rpc;
            rpc_system_app_set_callback(app->rpc, nfc_rpc_rpc_command_callback, app);
            rpc_system_app_send_started(app->rpc);
            ret = true;
        }
    }
    return ret;
}
 
void nfc_rpc_add_handler(NfcRpc* instance, pb_size_t message_tag, NfcRpcHandler handler) {
    furi_assert(instance);
    furi_assert(instance->handlers);
    furi_assert(handler);
    furi_assert(NfcRpcHandlerDict_get(instance->handlers, message_tag) == NULL);
 
    NfcRpcHandlerDict_set_at(instance->handlers, message_tag, handler);
}
 
static void nfc_rpc_message_receive_handler(NfcRpc* instance) {
    furi_assert(instance);
    furi_assert(instance->queue);
    furi_assert(instance->rpc);
    NfcRpcEvent event;
    pb_istream_t istream;
    pb_ostream_t ostream;
    uint8_t response_buffer[512] = {};
 
    if(furi_message_queue_get(instance->queue, &event, FuriWaitForever) == FuriStatusOk) {
        Nfc_Main cmd = Nfc_Main_init_default;
        istream = pb_istream_from_buffer(event.data, event.data_size);
        if(pb_decode(&istream, Nfc_Main_fields, &cmd)) {
            FURI_LOG_I(TAG, "Which: %d", cmd.which_content);
            NfcRpcHandler handler = *NfcRpcHandlerDict_get(instance->handlers, cmd.which_content);
            if(handler) {
                handler(&cmd, instance);
            } else {
                cmd.command_status = Nfc_CommandStatus_ERROR_NOT_IMPLEMENTED;
            }
            ostream = pb_ostream_from_buffer(response_buffer, sizeof(response_buffer));
            pb_encode(&ostream, Nfc_Main_fields, &cmd);
            FURI_LOG_D("NfcRpc", "Sending %d bytes", ostream.bytes_written);
            rpc_system_app_exchange_data(instance->rpc, response_buffer, ostream.bytes_written);
        } else {
            FURI_LOG_E(TAG, "Failed to decode message: %s", istream.errmsg);
            Nfc_Main cmd = Nfc_Main_init_default;
            cmd.command_status = Nfc_CommandStatus_ERROR;
            ostream = pb_ostream_from_buffer(response_buffer, sizeof(response_buffer));
            pb_encode(&ostream, Nfc_Main_fields, &cmd);
            rpc_system_app_exchange_data(instance->rpc, response_buffer, ostream.bytes_written);
        }
    }
}
 
bool nfc_rpc_custom_event_callback(void* context, uint32_t event) {
    NfcRpc* instance = context;
    if(event == NfcRpcCustomEventMessageReceived) {
        nfc_rpc_message_receive_handler(instance);
    }
 
    return true;
}
 
static NfcRpc* nfc_rpc_app_alloc() {
    NfcRpc* instance = malloc(sizeof(NfcRpc));
 
    instance->nfc = nfc_alloc();
 
    NfcRpcHandlerDict_init(instance->handlers);
    for(size_t i = 0; i < COUNT_OF(nfc_rpc_callbacks); i++) {
        if(nfc_rpc_callbacks[i].alloc) {
            nfc_rpc_callbacks[i].alloc(instance);
        }
    }
 
    instance->gui = furi_record_open(RECORD_GUI);
    instance->view_dispatcher = view_dispatcher_alloc();
    instance->view = view_alloc();
 
    view_set_previous_callback(instance->view, nfc_rpc_exit_callback);
    view_set_input_callback(instance->view, nfc_rpc_input_callback);
    view_set_context(instance->view, instance);
    view_set_draw_callback(instance->view, nfc_rpc_draw_callback);
 
    view_dispatcher_enable_queue(instance->view_dispatcher);
    view_dispatcher_attach_to_gui(
        instance->view_dispatcher, instance->gui, ViewDispatcherTypeFullscreen);
    view_dispatcher_add_view(instance->view_dispatcher, NfcRpcViewMain, instance->view);
 
    view_dispatcher_set_event_callback_context(instance->view_dispatcher, instance);
    view_dispatcher_set_custom_event_callback(
        instance->view_dispatcher, nfc_rpc_custom_event_callback);
 
    instance->queue = furi_message_queue_alloc(8, sizeof(NfcRpcEvent));
 
    return instance;
}
 
void nfc_rpc_app_free(NfcRpc* instance) {
    furi_assert(instance);
 
    nfc_free(instance->nfc);
 
    for(size_t i = 0; i < COUNT_OF(nfc_rpc_callbacks); i++) {
        if(nfc_rpc_callbacks[i].free) {
            nfc_rpc_callbacks[i].free(instance);
        }
    }
    NfcRpcHandlerDict_clear(instance->handlers);
 
    view_dispatcher_remove_view(instance->view_dispatcher, NfcRpcViewMain);
    view_free(instance->view);
    view_dispatcher_free(instance->view_dispatcher);
    furi_message_queue_free(instance->queue);
    furi_record_close(RECORD_GUI);
    instance->gui = NULL;
    instance->view_dispatcher = NULL;
 
    if(instance->rpc) {
        rpc_system_app_set_callback(instance->rpc, NULL, NULL);
        rpc_system_app_send_exited(instance->rpc);
        instance->rpc = NULL;
    }
 
    free(instance);
}
 
int32_t nfc_rpc_app(void* p) {
    UNUSED(p);
    NfcRpc* app = nfc_rpc_app_alloc();
 
    nfc_rpc_init_rpc(app, p);
 
    rpc_system_app_set_data_exchange_callback(
        app->rpc, nfc_rpc_receive_data_exchange_callback, app);
 
    view_dispatcher_switch_to_view(app->view_dispatcher, NfcRpcViewMain);
    view_dispatcher_run(app->view_dispatcher);
 
    nfc_rpc_app_free(app);
 
    return 0;
}

V576 Incorrect format. Consider checking the fourth actual argument of the 'furi_log_print_format' function. The integer argument of 32-bit size is expected.

V576 Incorrect format. Consider checking the fourth actual argument of the 'furi_log_print_format' function. The integer argument of 32-bit size is expected.