mirror of
https://github.com/openmv/openmv.git
synced 2025-11-04 14:49:50 +08:00
255 lines
7.1 KiB
C
Executable File
255 lines
7.1 KiB
C
Executable File
/**
|
|
* @file services_host_handler.c
|
|
* @brief Services handler file
|
|
*
|
|
* Copyright (C) 2022 Alif Semiconductor - All Rights Reserved.
|
|
* Use, distribution and modification of this code is permitted under the
|
|
* terms stated in the Alif Semiconductor Software License Agreement
|
|
*
|
|
* You should have received a copy of the Alif Semiconductor Software
|
|
* License Agreement with this file. If not, please write to:
|
|
* contact@alifsemi.com, or visit: https://alifsemi.com/license
|
|
*
|
|
* @ingroup host_services
|
|
*/
|
|
#include <stdint.h>
|
|
#include <stdbool.h>
|
|
#include <stddef.h>
|
|
#include <string.h>
|
|
#include "services_lib_bare_metal.h"
|
|
#include "services_lib_protocol.h"
|
|
#if defined(A32)
|
|
#include "a32_device.h"
|
|
#else
|
|
#include "system_utils.h"
|
|
#endif
|
|
|
|
#define SERVICES_REQ_TIMEOUT_MS 0x20
|
|
#define SEND_MSG_ACK_TIMEOUT 1000000ul
|
|
#define UNUSED(x) (void)(x)
|
|
|
|
static services_lib_t s_services_host = {0};
|
|
|
|
static uint32_t s_pkt_buffer_address_global = 0x0;
|
|
static volatile bool s_service_req_ack_received = false;
|
|
static volatile bool s_new_msg_received = false;
|
|
|
|
/**
|
|
* @brief Function to initialize the services library
|
|
* @param init_params Initialization parameters
|
|
*/
|
|
void SERVICES_initialize(services_lib_t * init_params)
|
|
{
|
|
s_services_host.packet_buffer_address = init_params->packet_buffer_address;
|
|
s_pkt_buffer_address_global =
|
|
LocalToGlobal((void *)s_services_host.packet_buffer_address);
|
|
s_services_host.fn_send_mhu_message = init_params->fn_send_mhu_message;
|
|
s_services_host.fn_wait_ms = init_params->fn_wait_ms;
|
|
s_services_host.wait_timeout = init_params->wait_timeout,
|
|
s_services_host.fn_print_msg = init_params->fn_print_msg;
|
|
}
|
|
|
|
/**
|
|
* @brief Function to synchronize with SE
|
|
* @param services_handle Services library handle
|
|
* @return total number of retries
|
|
* if nonnegative, success
|
|
* if negative, failure
|
|
*/
|
|
int SERVICES_synchronize_with_se(uint32_t services_handle)
|
|
{
|
|
const int MAX_RETRY = 100;
|
|
uint32_t error_code = SERVICES_REQ_SUCCESS;
|
|
int retry_count = 0;
|
|
|
|
while (1)
|
|
{
|
|
retry_count ++;
|
|
error_code = SERVICES_heartbeat(services_handle);
|
|
if (error_code == SERVICES_REQ_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
if (retry_count > MAX_RETRY)
|
|
{
|
|
return -retry_count;
|
|
}
|
|
}
|
|
|
|
return retry_count;
|
|
}
|
|
|
|
/**
|
|
* @brief prepare the packet buffer ()
|
|
* @return
|
|
*/
|
|
uintptr_t SERVICES_prepare_packet_buffer(uint32_t size)
|
|
{
|
|
memset((void *)s_services_host.packet_buffer_address, 0x0, size);
|
|
return s_services_host.packet_buffer_address;
|
|
}
|
|
|
|
/**
|
|
* @fn uint32_t SERVICES_register_channel(uint32_t mhu_id,
|
|
* uint32_t channel_number)
|
|
* @brief Register a MHU communication channel with the Services library
|
|
* @param mhu_id
|
|
* @param channel_number
|
|
* @return Handle to be used in subsequent service calls
|
|
*/
|
|
uint32_t SERVICES_register_channel(uint32_t mhu_id,
|
|
uint32_t channel_number)
|
|
{
|
|
return mhu_id * MHU_NUMBER_OF_CHANNELS_MAX + channel_number;
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param services_handle
|
|
* @return
|
|
*/
|
|
static uint32_t services_get_mhu_id(uint32_t services_handle)
|
|
{
|
|
return services_handle / MHU_NUMBER_OF_CHANNELS_MAX;
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param services_handle
|
|
* @return
|
|
*/
|
|
static uint32_t services_get_channel_number(uint32_t services_handle)
|
|
{
|
|
return services_handle % MHU_NUMBER_OF_CHANNELS_MAX;
|
|
}
|
|
|
|
/**
|
|
* @brief Callback function for sent msg ACK
|
|
* @fn void SERVICES_send_msg_acked_callback(uint32_t sender_id,
|
|
* uint32_t channel_number)
|
|
*/
|
|
void SERVICES_send_msg_acked_callback(uint32_t sender_id,
|
|
uint32_t channel_number)
|
|
{
|
|
s_service_req_ack_received = true;
|
|
UNUSED(sender_id);
|
|
UNUSED(channel_number);
|
|
}
|
|
|
|
/**
|
|
* @fn void SERVICES_rx_msg_callback(uint32_t receiver_id,
|
|
* uint32_t channel_number,
|
|
* uint32_t service_data)
|
|
* @brief Callback function for response message reception
|
|
* @param receiver_id
|
|
* @param channel_number
|
|
* @param service_data
|
|
*/
|
|
void SERVICES_rx_msg_callback(uint32_t receiver_id,
|
|
uint32_t channel_number,
|
|
uint32_t service_data)
|
|
{
|
|
UNUSED(receiver_id);
|
|
UNUSED(channel_number);
|
|
|
|
// Validate response by checking the message
|
|
if (s_pkt_buffer_address_global == service_data)
|
|
{
|
|
s_services_host.fn_print_msg("[SERVICESLIB] rx_msg=0x%x \n", service_data);
|
|
s_new_msg_received = true;
|
|
}
|
|
else
|
|
{
|
|
// @todo: handle invalid message
|
|
s_services_host.fn_print_msg("[SERVICESLIB] Invalid msg=0x%x\n",
|
|
service_data);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @fn uint32_t SERVICES_send_msg(uint32_t services_handle, uint32_t service_data)
|
|
* @brief Send the MHU message pointed by 'service_data'
|
|
*/
|
|
uint32_t SERVICES_send_msg(uint32_t services_handle, uint32_t services_data)
|
|
{
|
|
s_service_req_ack_received = false;
|
|
|
|
// Send a MHU message
|
|
uint32_t global_address = services_data;
|
|
s_services_host.fn_send_mhu_message(services_get_mhu_id(services_handle),
|
|
services_get_channel_number(services_handle),
|
|
global_address);
|
|
|
|
// Wait for a MHU 'send' ACK
|
|
uint32_t timeout = SEND_MSG_ACK_TIMEOUT;
|
|
while (!s_service_req_ack_received)
|
|
{
|
|
timeout--;
|
|
if (0 == timeout) // ACK not received
|
|
{
|
|
s_services_host.fn_print_msg("[ERROR][SERVICESLIB] SERVICES_REQ_NOT_ACKNOWLEDGE \n");
|
|
return SERVICES_REQ_NOT_ACKNOWLEDGE;
|
|
}
|
|
}
|
|
return SERVICES_REQ_SUCCESS;
|
|
}
|
|
/**
|
|
* @brief Send services request to MHU
|
|
* @param services_handle
|
|
* @param service_id
|
|
* @param service_timeout
|
|
* @return
|
|
*/
|
|
uint32_t SERVICES_send_request(uint32_t services_handle,
|
|
uint16_t service_id,
|
|
uint32_t service_timeout)
|
|
{
|
|
s_services_host.fn_print_msg("[SERVICESLIB] Send service request 0x%x\n",
|
|
service_id);
|
|
|
|
s_new_msg_received = false;
|
|
|
|
/**
|
|
* Initialize the service request common header
|
|
*/
|
|
service_header_t * p_header = (service_header_t *)s_services_host.packet_buffer_address;
|
|
p_header->hdr_service_id = service_id;
|
|
p_header->hdr_flags = 0;
|
|
|
|
/**
|
|
* Send a message to the SE
|
|
*/
|
|
|
|
RTSS_CleanDCache_by_Addr((uint32_t *)s_services_host.packet_buffer_address,
|
|
SERVICES_MAX_PACKET_BUFFER_SIZE);
|
|
|
|
uint32_t ret = SERVICES_send_msg(services_handle, s_pkt_buffer_address_global);
|
|
if (ret != SERVICES_REQ_SUCCESS)
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
// Wait for response from SE
|
|
uint32_t timeout = service_timeout != DEFAULT_TIMEOUT
|
|
? service_timeout :
|
|
s_services_host.wait_timeout;
|
|
while (!s_new_msg_received)
|
|
{
|
|
timeout--;
|
|
if (0 == timeout) // No response from SE
|
|
{
|
|
return SERVICES_REQ_TIMEOUT;
|
|
}
|
|
|
|
//if (0 != s_services_host.fn_wait_ms(SERVICES_REQ_TIMEOUT_MS))
|
|
//{
|
|
// break;
|
|
//}
|
|
}
|
|
|
|
RTSS_InvalidateDCache_by_Addr((uint32_t*)s_services_host.packet_buffer_address,
|
|
SERVICES_MAX_PACKET_BUFFER_SIZE);
|
|
|
|
return p_header->hdr_error_code;
|
|
}
|