238 lines
4.5 KiB
C
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;
|
|
}
|