Files
2026-08-24 10:03:24 +08:00

238 lines
4.5 KiB
C

/*
* Copyright (c) 2021-2022 Amlogic, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*/
#include <string.h>
#include <stdio.h>
#include <stdbool.h>
#include <stdint.h>
#include <common.h>
#include <FreeRTOS.h>
#include <task.h>
#include <semphr.h>
#include <mailbox-api.h>
#include "watchkey.h"
#define WATCHKEY_PREFIX "WATCHKEY: "
/* Operation command definition */
#define WATCHKEY_CMD_STATE 0x0001
#define WATCHKEY_CMD_DISABLE 0x0002
#define WATCHKEY_CMD_ENABLE 0x0003
#define WATCHKEY_CMD_DUMP 0x0004
#define WATCHKEY_CMD_TEST 0x0005
struct watchkey_ctrl {
bool valid;
bool active;
bool test;
ctrl_callback ctrl;
uint32_t buff[3];
};
static struct watchkey_ctrl keys[] = {
[WATCHKEY_ID_ADCKEY] = { 0 }, /* adc keypad */
[WATCHKEY_ID_GPIOKEY] = { 0 }, /* gpio keypad */
};
#define KEYS_ARRAY_SIZE ARRAY_SIZE(keys)
static SemaphoreHandle_t mutex;
static volatile bool scheduler_ready;
#pragma pack(push, 1)
struct mbox_payload {
uint16_t id;
uint16_t cmd;
uint32_t data[3];
};
#pragma pack(pop)
static bool prvCheckValid(uint16_t id, bool valid, const char *label)
{
if (id >= KEYS_ARRAY_SIZE) {
printf(WATCHKEY_PREFIX "%s: UNK ID %d\n", label, id);
return false;
}
if (keys[id].valid != valid) {
printf(WATCHKEY_PREFIX "%s INVAL ID %d\n", label, id);
return false;
}
return true;
}
static bool prvCheckValidAndLock(uint16_t id, bool valid, const char *label)
{
xSemaphoreTake(mutex, portMAX_DELAY);
if (!prvCheckValid(id, valid, label)) {
xSemaphoreGive(mutex);
return false;
}
return true;
}
static void prvWatchKeyEnable(uint16_t id)
{
if (keys[id].active)
return;
keys[id].active = true;
if (keys[id].ctrl)
keys[id].ctrl(id, true);
}
static void prvWatchKeyDisable(uint16_t id)
{
if (!keys[id].active)
return;
keys[id].active = false;
if (keys[id].ctrl)
keys[id].ctrl(id, false);
}
static void *xMboxWatchKeyCtrl(void *msg)
{
struct mbox_payload *op = (struct mbox_payload *)msg;
if (!prvCheckValidAndLock(op->id, true, "CTRL"))
return NULL;
switch (op->cmd) {
case WATCHKEY_CMD_STATE:
op->data[0] = (uint32_t)keys[op->id].active;
break;
case WATCHKEY_CMD_DISABLE:
prvWatchKeyDisable(op->id);
break;
case WATCHKEY_CMD_ENABLE:
prvWatchKeyEnable(op->id);
break;
case WATCHKEY_CMD_DUMP:
memcpy(op->data, keys[op->id].buff, sizeof(op->data));
break;
case WATCHKEY_CMD_TEST:
op->data[0] = (uint32_t)keys[op->id].test;
break;
default:
printf(WATCHKEY_PREFIX "FAIL: UNK CMD 0x%x\n", op->cmd);
}
xSemaphoreGive(mutex);
return NULL;
}
void vWatchKeyCreate(uint16_t id, ctrl_callback ctrl)
{
if (!prvCheckValidAndLock(id, false, "CRT"))
return;
keys[id].valid = true;
keys[id].ctrl = ctrl;
/* Enable by default */
if (scheduler_ready)
prvWatchKeyEnable(id);
else
keys[id].active = true;
xSemaphoreGive(mutex);
}
void vWatchKeyDestroy(uint16_t id)
{
if (!prvCheckValidAndLock(id, true, "DST"))
return;
prvWatchKeyDisable(id);
keys[id].ctrl = NULL;
keys[id].valid = false;
xSemaphoreGive(mutex);
}
static void prvWatchKeyInitTask(void *pvParameters)
{
uint16_t id;
for (id = 0; id < KEYS_ARRAY_SIZE; id++) {
if (!keys[id].active)
continue;
if (keys[id].ctrl)
keys[id].ctrl(id, true);
}
scheduler_ready = true;
printf(WATCHKEY_PREFIX "EN\n");
vTaskDelete(NULL);
}
void vWatchKeyInit(void)
{
int ret;
TaskHandle_t xHandle;
mutex = xSemaphoreCreateMutex();
configASSERT(mutex != NULL);
ret = xInstallRemoteMessageCallbackFeedBack(REE2AO_CHANNEL, CMD_WATCHKEY_CTRL,
xMboxWatchKeyCtrl, 1);
configASSERT(ret == 0);
/*
* ADC can only be enabled when the task scheduling function is ready,
* so we create a task and enable ADC in the task.
*/
xTaskCreate(prvWatchKeyInitTask, "WatchKeyInitTask", configMINIMAL_STACK_SIZE,
NULL, tskIDLE_PRIORITY + 3, &xHandle);
configASSERT(xHandle);
}
void vWatchKeyDeinit(void)
{
uint16_t id;
xUninstallRemoteMessageCallback(REE2AO_CHANNEL, CMD_WATCHKEY_CTRL);
for (id = 0; id < KEYS_ARRAY_SIZE; id++) {
prvWatchKeyDisable(id);
keys[id].ctrl = NULL;
keys[id].valid = false;
}
vSemaphoreDelete(mutex);
printf(WATCHKEY_PREFIX "DIS\n");
}
void vWatchKeySetTest(uint16_t id, bool value)
{
if (!prvCheckValidAndLock(id, true, "TEST"))
return;
keys[id].test = value;
xSemaphoreGive(mutex);
}
void vWatchKeySetData(uint16_t id, uint32_t d0, uint32_t d1, uint32_t d2)
{
if (!prvCheckValidAndLock(id, true, "DATA"))
return;
keys[id].buff[0] = d0;
keys[id].buff[1] = d1;
keys[id].buff[2] = d2;
xSemaphoreGive(mutex);
}
bool xWatchKeyIsActive(uint16_t id)
{
return keys[id].active;
}