From 138cf30b2330add66098fa2921f6b78de4ed92c9 Mon Sep 17 00:00:00 2001 From: Joe Kearney Date: Sat, 22 Mar 2025 14:30:25 -0500 Subject: [PATCH] Resolved a problem double-receiving IR packets. --- components/IR/IR.c | 93 ++++++++++++++++++++++++++++++++++++++++------ components/IR/IR.h | 22 +++++++++++ components/SystemK | 2 +- main/Version.h | 22 +++++++++++ 4 files changed, 126 insertions(+), 13 deletions(-) diff --git a/components/IR/IR.c b/components/IR/IR.c index 6d393f8..9c54d99 100644 --- a/components/IR/IR.c +++ b/components/IR/IR.c @@ -1,3 +1,25 @@ +/* + * This program source code file is part of the KTag project, a DIY laser tag + * game with customizable features and wide interoperability. + * + * 🛡️ 🃞 + * + * Copyright © 2024-2025 Joseph P. Kearney and the KTag developers. + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more + * details. + * + * There should be a copy of the GNU Affero General Public License in the LICENSE + * file in the root of this repository. If not, see . + */ + #include #include #include @@ -53,6 +75,11 @@ static TimedPulseTrain_T Left_Rxd_RMT_Data; static TimedPulseTrain_T Forward_Rxd_RMT_Data; static TimedPulseTrain_T Right_Rxd_RMT_Data; +volatile TickType_t Last_Time_Checked_In_Ticks = 0; +TagSensorLocation_T Active_Tag_Sensor = TAG_SENSOR_NONE; +SemaphoreHandle_t Tag_Sensor_Mutex; +static const TickType_t LOCKOUT_TIME_IN_TICKS = pdMS_TO_TICKS(100); + #define IR_RX_STACK_SIZE 4096 static StaticTask_t xTaskBuffer; static StackType_t xStack[IR_RX_STACK_SIZE]; @@ -66,14 +93,45 @@ typedef struct TagSensorLocation_T location; } RxNotification_T; +// Prevent double-receiving (or triple-receiving!) IR packets by locking out the other sensors for a short time once one sensor becomes active. +// A sensor is allowed if it is the already-active sensor or the lockout period has expired. +static BaseType_t Is_Sensor_Allowed(TagSensorLocation_T sensor_location, BaseType_t *xHigherPriorityTaskWoken) +{ + BaseType_t is_allowed = pdFALSE; + TickType_t current_time_in_ticks = xTaskGetTickCountFromISR(); + + if (xSemaphoreTakeFromISR(Tag_Sensor_Mutex, xHigherPriorityTaskWoken) == pdTRUE) + { + if ((Active_Tag_Sensor != TAG_SENSOR_NONE) && (Active_Tag_Sensor != sensor_location) && + ((current_time_in_ticks - Last_Time_Checked_In_Ticks) < LOCKOUT_TIME_IN_TICKS)) + { + // We're in lockout period and this is not the active sensor--ignore this sensor. + is_allowed = pdFALSE; + } + else + { + // It's OK to allow this sensor. + Active_Tag_Sensor = sensor_location; + Last_Time_Checked_In_Ticks = current_time_in_ticks; + is_allowed = pdTRUE; + } + + xSemaphoreGiveFromISR(Tag_Sensor_Mutex, xHigherPriorityTaskWoken); + } + + return is_allowed; +} + static bool RMT_Rx_Left_Done_Callback(rmt_channel_handle_t channel, const rmt_rx_done_event_data_t *edata, void *user_data) { BaseType_t xHigherPriorityTaskWoken = pdFALSE; - RxNotification_T notice; - notice.count = edata->num_symbols * 2; - notice.location = TAG_SENSOR_LEFT; - xQueueSendFromISR(Receive_Queue, ¬ice, &xHigherPriorityTaskWoken); + if (Is_Sensor_Allowed(TAG_SENSOR_LEFT, &xHigherPriorityTaskWoken) == pdTRUE) + { + RxNotification_T notice = {.count = edata->num_symbols * 2, + .location = TAG_SENSOR_LEFT}; + xQueueSendFromISR(Receive_Queue, ¬ice, &xHigherPriorityTaskWoken); + } return xHigherPriorityTaskWoken; } @@ -81,11 +139,13 @@ static bool RMT_Rx_Left_Done_Callback(rmt_channel_handle_t channel, const rmt_rx static bool RMT_Rx_Forward_Done_Callback(rmt_channel_handle_t channel, const rmt_rx_done_event_data_t *edata, void *user_data) { BaseType_t xHigherPriorityTaskWoken = pdFALSE; - RxNotification_T notice; - notice.count = edata->num_symbols * 2; - notice.location = TAG_SENSOR_FORWARD; - xQueueSendFromISR(Receive_Queue, ¬ice, &xHigherPriorityTaskWoken); + if (Is_Sensor_Allowed(TAG_SENSOR_FORWARD, &xHigherPriorityTaskWoken) == pdTRUE) + { + RxNotification_T notice = {.count = edata->num_symbols * 2, + .location = TAG_SENSOR_FORWARD}; + xQueueSendFromISR(Receive_Queue, ¬ice, &xHigherPriorityTaskWoken); + } return xHigherPriorityTaskWoken; } @@ -93,11 +153,13 @@ static bool RMT_Rx_Forward_Done_Callback(rmt_channel_handle_t channel, const rmt static bool RMT_Rx_Right_Done_Callback(rmt_channel_handle_t channel, const rmt_rx_done_event_data_t *edata, void *user_data) { BaseType_t xHigherPriorityTaskWoken = pdFALSE; - RxNotification_T notice; - notice.count = edata->num_symbols * 2; - notice.location = TAG_SENSOR_RIGHT; - xQueueSendFromISR(Receive_Queue, ¬ice, &xHigherPriorityTaskWoken); + if (Is_Sensor_Allowed(TAG_SENSOR_RIGHT, &xHigherPriorityTaskWoken) == pdTRUE) + { + RxNotification_T notice = {.count = edata->num_symbols * 2, + .location = TAG_SENSOR_RIGHT}; + xQueueSendFromISR(Receive_Queue, ¬ice, &xHigherPriorityTaskWoken); + } return xHigherPriorityTaskWoken; } @@ -186,6 +248,13 @@ static void IR_Receive_Task(void *param) static void Initialize_Receive_Task(void) { + Tag_Sensor_Mutex = xSemaphoreCreateMutex(); + + if (Tag_Sensor_Mutex == NULL) + { + KLOG_ERROR(TAG, "Failed to create tag sensor mutex!"); + } + IR_Rx_Task_Handle = xTaskCreateStaticPinnedToCore( IR_Receive_Task, // Function that implements the task. "IR Rx", // Text name for the task. diff --git a/components/IR/IR.h b/components/IR/IR.h index c1f0132..6ad3b87 100644 --- a/components/IR/IR.h +++ b/components/IR/IR.h @@ -1,3 +1,25 @@ +/* + * This program source code file is part of the KTag project, a DIY laser tag + * game with customizable features and wide interoperability. + * + * 🛡️ 🃞 + * + * Copyright © 2024-2025 Joseph P. Kearney and the KTag developers. + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more + * details. + * + * There should be a copy of the GNU Affero General Public License in the LICENSE + * file in the root of this repository. If not, see . + */ + #include "esp_err.h" void Initialize_IR(SemaphoreHandle_t init_complete); \ No newline at end of file diff --git a/components/SystemK b/components/SystemK index c11206e..cb72042 160000 --- a/components/SystemK +++ b/components/SystemK @@ -1 +1 @@ -Subproject commit c11206e6255fef994c826fb446a234132571af4f +Subproject commit cb7204269140ba9c6dbe44ca5a5dbaf8c031f685 diff --git a/main/Version.h b/main/Version.h index 9880967..4625992 100644 --- a/main/Version.h +++ b/main/Version.h @@ -1,3 +1,25 @@ +/* + * This program source code file is part of the KTag project, a DIY laser tag + * game with customizable features and wide interoperability. + * + * 🛡️ 🃞 + * + * Copyright © 2024-2025 Joseph P. Kearney and the KTag developers. + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more + * details. + * + * There should be a copy of the GNU Affero General Public License in the LICENSE + * file in the root of this repository. If not, see . + */ + #ifndef VERSION_H #define VERSION_H