diff --git a/framework/include/csimanager/csifw_api.h b/framework/include/csimanager/csifw_api.h index 85c63bdf72..aa8405ae81 100644 --- a/framework/include/csimanager/csifw_api.h +++ b/framework/include/csimanager/csifw_api.h @@ -26,22 +26,22 @@ extern "C" { #include typedef enum _CSIFW_RES { - CSIFW_ERROR_MAX_NUM_SERVICE_REGISTERED = -11, /* ERROR: MAX number of Services is alreay Registered */ - CSIFW_ERROR_NOT_INITIALIZED = -10, /* ERROR: Not Initialized */ - CSIFW_ERROR_INVALID_SERVICE_STATE = -9, /* ERROR: Invalid Service State */ - CSIFW_ERROR_ALREADY_INIT_WITH_DIFFERENT_CONFIG = -8, /* ERROR: Service already initialized with different CSI_Configuration */ - CSIFW_ERROR_SERVICE_NOT_REGISTERED = -7, /* ERROR: Service not registered. Cannot start/stop/deinit */ - CSIFW_ERROR_WIFI_DIS_CONNECTED = -6, /* ERROR: WIFI WIFI_DISCONNECTED */ - CSIFW_INVALID_RAWDATA = -5, /* Invalid Raw Data */ - CSIFW_INVALID_ARG = -4, /* Invalid argument */ - CSIFW_NOT_ENOUGH_SPACE = -3, /* read/write/other buffer has empty space less than required size */ - CSIFW_NO_MEM = -2, /* Memory allocation (malloc/calloc) failed */ - CSIFW_ERROR = -1, /* ERROR: All other types of error not specified by any following enum */ - CSIFW_OK = 0, /* OK: Without any error */ - CSIFW_OK_WIFI_CONNECTED = 1, /* OK: Without any error */ - CSIFW_OK_ALREADY_STOPPED = 2, /* CSIFW already stopped by running service, but no error */ - CSIFW_OK_ALREADY_STARTED = 3, /* CSIFW already started by running service, but no error */ - CSIFW_OK_WIFI_NOT_CONNECTED = 4 /* CSIFW already started but WIFI not connected */ + CSIFW_ERROR_MAX_NUM_SERVICE_REGISTERED = -11, /* ERROR: MAX number of Services is alreay Registered */ + CSIFW_ERROR_NOT_INITIALIZED = -10, /* ERROR: Not Initialized */ + CSIFW_ERROR_INVALID_SERVICE_STATE = -9, /* ERROR: Invalid Service State */ + CSIFW_ERROR_ALREADY_INIT_WITH_DIFFERENT_CONFIG = -8, /* ERROR: Service already initialized with different CSI_Configuration*/ + CSIFW_ERROR_SERVICE_NOT_REGISTERED = -7, /* ERROR: Service not registered. Cannot start/stop/deinit */ + CSIFW_ERROR_WIFI_DIS_CONNECTED = -6, /* ERROR: WIFI WIFI_DISCONNECTED */ + CSIFW_ERROR_DATA_NOT_AVAILABLE = -5, /* ERROR: CSI Data Not Available */ + CSIFW_INVALID_ARG = -4, /* Invalid argument */ + CSIFW_NOT_ENOUGH_SPACE = -3, /* read/write/other buffer has empty space less than required size */ + CSIFW_NO_MEM = -2, /* Memory allocation (malloc/calloc) failed */ + CSIFW_ERROR = -1, /* ERROR: All other types of error not specified by any following enum */ + CSIFW_OK = 0, /* OK: Without any error */ + CSIFW_OK_WIFI_CONNECTED = 1, /* OK: Without any error */ + CSIFW_OK_ALREADY_STOPPED = 2, /* CSIFW already stopped by running service, but no error */ + CSIFW_OK_ALREADY_STARTED = 3, /* CSIFW already started by running service, but no error */ + CSIFW_OK_WIFI_NOT_CONNECTED = 4 /* CSIFW already started but WIFI not connected */ } CSIFW_RES; typedef int csifw_service_handle; diff --git a/framework/src/csimanager/CSIFrameworkMain.c b/framework/src/csimanager/CSIFrameworkMain.c index df32175fc6..3fffab9d87 100644 --- a/framework/src/csimanager/CSIFrameworkMain.c +++ b/framework/src/csimanager/CSIFrameworkMain.c @@ -42,6 +42,7 @@ const static int CSIFW_TASK_PRIORITY = 100; const static int CSIFW_TASK_PERMISSION = TM_APP_PERMISSION_ALL; int csifw_task_Main(int argc, char *argv[]); +static void task_manager_stop_and_unregister(int m_task_handle); int start_csi_framework(csifw_context_t *p_ctx) { @@ -84,8 +85,14 @@ int start_csi_framework(csifw_context_t *p_ctx) int result = task_manager_start(handle, TM_RESPONSE_WAIT_INF); if (result < 0) { CSIFW_LOGE("Failed to start %s (handle=%d). Return: %d. Cleaning up...", CSIFW_TASK_NAME, handle, result); - task_manager_unregister(handle, TM_RESPONSE_WAIT_INF); - CSIFW_LOGD("Unregistered task %s (handle=%d) after failed start", CSIFW_TASK_NAME, handle); + CSIFW_LOGD("Unregistering task %s (handle=%d)", CSIFW_TASK_NAME, handle); + int tm_unregister_return = task_manager_unregister(handle, TM_RESPONSE_WAIT_INF); + if (tm_unregister_return < 0) { + CSIFW_LOGE("Failed to unregister csifw task to the task manager! Return: %d", tm_unregister_return); + //To-Do: Error handling logic to be addressed later. + } else { + CSIFW_LOGD("Unregistered successfully csifw task to the task manager! Return: %d", tm_unregister_return); + } sem_destroy(&p_ctx->csifw_task_sema); CSIFW_LOGD("Destroyed semaphore for %s after failed start", CSIFW_TASK_NAME); } else { @@ -94,7 +101,7 @@ int start_csi_framework(csifw_context_t *p_ctx) if (!p_ctx->task_run_success) { CSIFW_LOGE("CSI framework task initialization failed"); - task_manager_unregister(handle, TM_RESPONSE_WAIT_INF); + task_manager_stop_and_unregister(p_ctx->task_handle); sem_destroy(&p_ctx->csifw_task_sema); return -1; } @@ -113,8 +120,7 @@ int stop_csi_framework(csifw_context_t *p_ctx) p_ctx->task_run_state = STOPPED; //stop the main loop of the task CSIFW_LOGD("Waiting for csifw_task to complete..."); sem_wait(&p_ctx->csifw_task_sema); - CSIFW_LOGD("Unregistering task %s (handle=%d)", CSIFW_TASK_NAME, p_ctx->task_handle); - task_manager_unregister(p_ctx->task_handle, TM_RESPONSE_WAIT_INF); + task_manager_stop_and_unregister(p_ctx->task_handle); CSIFW_LOGD("Destroying semaphore for %s", CSIFW_TASK_NAME); sem_destroy(&p_ctx->csifw_task_sema); return 0; @@ -136,7 +142,6 @@ int csifw_task_Main(int argc, char *argv[]) sem_post(&p_csifw_ctx->csifw_task_sema); return -1; } - if (csi_ping_generator_initialize() != CSIFW_OK) { CSIFW_LOGE("CSI ping generator initialize failed"); csi_packet_receiver_stop_collect(); @@ -173,9 +178,72 @@ int csifw_task_Main(int argc, char *argv[]) CSIFW_LOGE("CSI packet receiver stop failed"); } if (csi_packet_receiver_cleanup() == CSIFW_ERROR){ - CSIFW_LOGD("CSI packet receiver cleanup failed"); + CSIFW_LOGE("CSI packet receiver cleanup failed"); } //to unlock stop_csi_framework() sem_post(&p_csifw_ctx->csifw_task_sema); return 0; } + +static void task_manager_stop_and_unregister(int m_task_handle) +{ + CSIFW_LOGD("Stopping task %s (Task_Handle=%d)", CSIFW_TASK_NAME, m_task_handle); + tm_appinfo_t *info = task_manager_getinfo_with_handle(m_task_handle, TM_RESPONSE_WAIT_INF); + if (info == NULL) { + CSIFW_LOGE("Failed to get task info for handle %d", m_task_handle); + return; + } + + //Print task status + switch (info->status) { + case TM_APP_STATE_RUNNING: + CSIFW_LOGI("Task (handle=%d) status: RUNNING", m_task_handle); + break; + case TM_APP_STATE_PAUSE: + CSIFW_LOGI("Task (handle=%d) status: PAUSED", m_task_handle); + break; + case TM_APP_STATE_STOP: + CSIFW_LOGI("Task (handle=%d) status: STOPPED", m_task_handle); + break; + case TM_APP_STATE_UNREGISTERED: + CSIFW_LOGI("Task (handle=%d) status: UNREGISTERED", m_task_handle); + break; + case TM_APP_STATE_CANCELLING: + CSIFW_LOGI("Task (handle=%d) status: CANCELLING", m_task_handle); + break; + case TM_APP_STATE_WAIT_UNREGISTER: + CSIFW_LOGI("Task (handle=%d) status: WAIT_UNREGISTER", m_task_handle); + break; + default: + CSIFW_LOGE("Task (handle=%d) status: UNKNOWN (%d)", m_task_handle, info->status); + break; + } + + if (info->status == TM_APP_STATE_RUNNING) { + int tm_stop_return = task_manager_stop(m_task_handle, TM_RESPONSE_WAIT_INF); + if (tm_stop_return != 0) { + CSIFW_LOGE("Failed to stop (Task_Handle=%d). Return: %d.", m_task_handle, tm_stop_return); + } else { + CSIFW_LOGD("Stopped successfully (Task_Handle=%d). Return: %d.", m_task_handle, tm_stop_return); + } + } else if (info->status == TM_APP_STATE_STOP) { + CSIFW_LOGD("Task already stopped (Task_Handle=%d)", m_task_handle); + } else { + CSIFW_LOGD("Task state unknown Failed to stop (Task_Handle=%d)", m_task_handle); + } + + CSIFW_LOGD("Unregistering task %s (Task_Handle=%d)", CSIFW_TASK_NAME, m_task_handle); + int tm_unregister_return = task_manager_unregister(m_task_handle, TM_RESPONSE_WAIT_INF); + if (tm_unregister_return < 0) { + CSIFW_LOGE("Failed to unregister csifw task to the task manager! Return: %d", tm_unregister_return); + //To-Do: Error handling logic to be addressed later. + } else { + CSIFW_LOGD("Unregistered successfully csifw task to the task manager! Return: %d", tm_unregister_return); + } + + task_manager_clean_info(&info); + if (info != NULL) { + CSIFW_LOGE("Failed to clean task info memory"); + } +} + diff --git a/framework/src/csimanager/CSIManager.c b/framework/src/csimanager/CSIManager.c index 87363474ae..aefd34e0c5 100644 --- a/framework/src/csimanager/CSIManager.c +++ b/framework/src/csimanager/CSIManager.c @@ -117,8 +117,11 @@ static void CSIRawDataListener(CSIFW_RES res, int raw_csi_buff_len, unsigned cha &g_pcsifw_context->ParsedDataBufferLen); } - // we use this service state but if its called parelly this is will stuck + // CSIRawDataListener callback can be invoked from a background thread when CSI data arrives. + // Simultaneously, application threads may call `csifw_start()/csifw_stop()` to modify service states. + // Without this mutex, race conditions will occur CSIFW_MUTEX_LOCK(&g_pcsifw_context->data_reciever_mutex); + for (int i = 0; i < CSIFW_MAX_NUM_APPS; i++) { // send raw if (g_pcsifw_context->csi_services[i].svc_id != 0 && g_pcsifw_context->csi_services[i].svc_state == CSI_SERVICE_START) { @@ -401,6 +404,10 @@ CSIFW_RES csifw_set_interval(csifw_service_handle hnd, unsigned int interval) ping_generator_change_interval(g_pcsifw_context->csi_interval); } else { res = csi_packet_receiver_change_interval(); + if (res != CSIFW_OK) { + CSIFW_LOGE("Interval update Failed %d", res); + goto on_error; + } } CSIFW_LOGD("Interval updated : %u", g_pcsifw_context->csi_interval); @@ -482,6 +489,10 @@ CSIFW_RES csifw_get_ap_mac_addr(csifw_service_handle hnd, csifw_mac_info *p_mac_ } res = csi_packet_receiver_get_mac_addr(p_mac_info); + if (res != CSIFW_OK) { + CSIFW_LOGE("Failed to get AP MAC %d", res); + goto on_error; + } on_error: CSIFW_MUTEX_UNLOCK(&g_api_mutex); @@ -702,3 +713,4 @@ static int all_services_stopped(void) CSIFW_LOGI("All services are stopped\n"); return 1; } + diff --git a/framework/src/csimanager/CSIPacketReceiver.c b/framework/src/csimanager/CSIPacketReceiver.c index e1d4a4fcbd..8c49432b7b 100644 --- a/framework/src/csimanager/CSIPacketReceiver.c +++ b/framework/src/csimanager/CSIPacketReceiver.c @@ -25,6 +25,8 @@ #include #define RCVR_TH_NAME "csifw_data_receiver_th" +#define MAX_CONSECUTIVE_FAILURES 50 +static unsigned long long get_monotonic_time_us(void); static inline CSIFW_RES open_driver(int *fd) { *fd = open(CONFIG_WIFICSI_CUSTOM_DEV_PATH, O_RDONLY); @@ -68,16 +70,23 @@ static void *dataReceiverThread(void *vargp) int prio; size_t size; int csi_data_len = 0; + int timeout_count = 0; struct wifi_csi_msg_s msg; + int consecutive_failures = 0; + struct timespec st_time = {0,}; int fd = p_csifw_ctx->data_receiver_fd; mqd_t mq_handle = p_csifw_ctx->mq_handle; + unsigned long long last_data_read_timestamp_us = 0; unsigned char *get_data_buffptr = p_csifw_ctx->get_data_buffptr; while (!p_csifw_ctx->data_receiver_thread_stop) { - size = mq_receive(mq_handle, (char *)&msg, sizeof(msg), &prio); - if (size != sizeof(msg)) { - CSIFW_LOGE("Interrupted while waiting for deque message from kernel %zu, errno: %d (%s)", size, get_errno(), strerror(get_errno())); - } else { + last_data_read_timestamp_us = get_monotonic_time_us(); + CSIFW_LOGD("last_data_read_timestamp_us before mq_timedreceive:%llu",last_data_read_timestamp_us); + clock_gettime(CLOCK_REALTIME, &st_time); + st_time.tv_sec += 1; + size = mq_timedreceive(mq_handle, (char *)&msg, sizeof(msg), &prio, &st_time); + if (size >= 0) { + CSIFW_LOGD("Message received - msgId: %d, data_len: %d, size: %zu: %d", msg.msgId, msg.data_len, size); switch (msg.msgId) { case CSI_MSG_DATA_READY_CB: if (msg.data_len == 0 || msg.data_len > CSIFW_MAX_RAW_BUFF_LEN) { @@ -86,6 +95,8 @@ static void *dataReceiverThread(void *vargp) } csi_data_len = msg.data_len; len = readCSIData(fd, get_data_buffptr, csi_data_len); + last_data_read_timestamp_us = get_monotonic_time_us(); + CSIFW_LOGD("last_data_read_timestamp_us after readCSIData:%llu",last_data_read_timestamp_us); if (len < 0) { CSIFW_LOGE("Skipping packet: error: %d", len); continue; @@ -218,7 +229,6 @@ CSIFW_RES csi_packet_receiver_start_collect(void) } if (p_csifw_ctx->disable_required) { CSIFW_LOGD("WiFi reconnected: Disabling CSI config"); - csi_packet_receiver_set_csi_config(CSI_CONFIG_ENABLE); csi_packet_receiver_set_csi_config(CSI_CONFIG_DISABLE); p_csifw_ctx->disable_required = false; } @@ -229,6 +239,17 @@ CSIFW_RES csi_packet_receiver_start_collect(void) } p_csifw_ctx->data_receiver_thread_stop = false; + // allocate buffer for receiveing data from driver + if (!p_csifw_ctx->get_data_buffptr) { + p_csifw_ctx->get_data_buffptr = (unsigned char *)malloc(CSIFW_MAX_RAW_BUFF_LEN); + if (!p_csifw_ctx->get_data_buffptr) { + csi_packet_receiver_set_csi_config(CSI_CONFIG_DISABLE); + CSIFW_LOGE("Buffer allocation Fail."); + return CSIFW_ERROR; + } + CSIFW_LOGD("CSI data buffer allocated successfully, size: %d bytes", CSIFW_MAX_RAW_BUFF_LEN); + } + pthread_attr_t recv_th_attr; if (pthread_attr_init(&recv_th_attr) != 0) { CSIFW_LOGE("Failed to initialize receiver thread attributes - errno: %d (%s)", get_errno(), strerror(get_errno())); @@ -369,3 +390,11 @@ CSIFW_RES csi_packet_receiver_deinit(void) CSIFW_LOGD("CSI packet receiver successfully deinitialized (callback: %p)", p_csifw_ctx->CSI_DataCallback); return CSIFW_OK; } + +static unsigned long long get_monotonic_time_us(void) +{ + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return (unsigned long long)ts.tv_sec * 1000000ULL + ts.tv_nsec / 1000ULL; +} + diff --git a/framework/src/csimanager/inc/CSIManager.h b/framework/src/csimanager/inc/CSIManager.h index 51b9b73780..3f7d8ba6ab 100644 --- a/framework/src/csimanager/inc/CSIManager.h +++ b/framework/src/csimanager/inc/CSIManager.h @@ -34,6 +34,10 @@ #define CSIFW_MIN_INTERVAL_MS 30 // Minimum supported CSI interval in milliseconds #define CSIFW_MAX_RAW_BUFF_LEN 1024 // CSI data buffer xax size +#ifndef CONFIG_CSI_DATA_TIMEOUT_SEC /* In case not defined in defconfig, force it to default value*/ +#define CONFIG_CSI_DATA_TIMEOUT_SEC 15 +#endif + typedef unsigned long long u64; // for u64 typedef void (*CSIDataListener)(CSIFW_RES res, int csi_buff_len, unsigned char *csi_buff, int csi_data_len);