0
mirror of https://github.com/OneOfEleven/uv-k5-firmware-custom.git synced 2025-04-28 22:31:25 +03:00

465 lines
11 KiB
C
Raw Normal View History

2023-09-09 08:03:56 +01:00
/* Copyright 2023 Dual Tachyon
* https://github.com/DualTachyon
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <string.h>
#include <stdio.h> // NULL
2023-09-09 08:03:56 +01:00
#ifdef ENABLE_FMRADIO
2023-09-14 09:56:30 +01:00
#include "app/fm.h"
#endif
#include "app/search.h"
2023-09-09 08:03:56 +01:00
#include "bsp/dp32g030/gpio.h"
2023-09-30 11:22:19 +01:00
#include "audio.h"
2023-09-09 08:03:56 +01:00
#include "driver/bk4819.h"
#include "driver/eeprom.h"
#include "driver/gpio.h"
#include "driver/system.h"
#include "dtmf.h"
#include "external/printf/printf.h"
#include "misc.h"
#include "settings.h"
#include "ui/ui.h"
2023-10-08 20:23:37 +01:00
char g_dtmf_string[15];
char g_dtmf_input_box[15];
uint8_t g_dtmf_input_box_index;
bool g_dtmf_input_mode;
uint8_t g_dtmf_prev_index;
char g_dtmf_rx[17];
uint8_t g_dtmf_rx_index;
uint8_t g_dtmf_rx_timeout;
bool g_dtmf_rx_pending;
char g_dtmf_rx_live[20];
uint8_t g_dtmf_rx_live_timeout;
bool g_dtmf_is_contact_valid;
char g_dtmf_id[4];
char g_dtmf_caller[4];
char g_dtmf_callee[4];
dtmf_state_t g_dtmf_state;
uint8_t g_dtmf_decode_ring_tick_500ms;
2023-10-08 20:23:37 +01:00
uint8_t g_dtmf_chosen_contact;
uint8_t g_dtmf_auto_reset_time_500ms;
dtmf_call_state_t g_dtmf_call_state;
dtmf_reply_state_t g_dtmf_reply_state;
dtmf_call_mode_t g_dtmf_call_mode;
bool g_dtmf_is_tx;
uint8_t g_dtmf_tx_stop_tick_500ms;
2023-10-08 20:23:37 +01:00
bool g_dtmf_IsGroupCall;
2023-09-09 08:03:56 +01:00
2023-09-30 11:22:19 +01:00
void DTMF_clear_RX(void)
{
2023-10-08 20:23:37 +01:00
g_dtmf_rx_timeout = 0;
g_dtmf_rx_index = 0;
g_dtmf_rx_pending = false;
memset(g_dtmf_rx, 0, sizeof(g_dtmf_rx));
2023-09-30 11:22:19 +01:00
}
bool DTMF_ValidateCodes(char *pCode, const unsigned int size)
2023-09-09 08:03:56 +01:00
{
2023-09-12 11:49:16 +01:00
unsigned int i;
2023-09-09 08:03:56 +01:00
if (pCode[0] == 0xFF || pCode[0] == 0)
return false;
2023-09-30 11:22:19 +01:00
for (i = 0; i < size; i++)
2023-09-09 08:03:56 +01:00
{
if (pCode[i] == 0xFF || pCode[i] == 0)
{
pCode[i] = 0;
break;
}
if ((pCode[i] < '0' || pCode[i] > '9') && (pCode[i] < 'A' || pCode[i] > 'D') && pCode[i] != '*' && pCode[i] != '#')
return false;
}
return true;
}
2023-09-12 11:49:16 +01:00
bool DTMF_GetContact(const int Index, char *pContact)
2023-09-09 08:03:56 +01:00
{
2023-09-12 11:49:16 +01:00
int i = -1;
if (Index >= 0 && Index < MAX_DTMF_CONTACTS && pContact != NULL)
2023-09-12 11:49:16 +01:00
{
EEPROM_ReadBuffer(0x1C00 + (Index * 16), pContact, 16);
i = (int)pContact[0] - ' ';
}
return (i < 0 || i >= 95) ? false : true;
2023-09-09 08:03:56 +01:00
}
bool DTMF_FindContact(const char *pContact, char *pResult)
{
char Contact[16];
2023-09-12 11:49:16 +01:00
unsigned int i;
2023-09-09 08:03:56 +01:00
for (i = 0; i < MAX_DTMF_CONTACTS; i++)
2023-09-09 08:03:56 +01:00
{
2023-09-12 11:49:16 +01:00
unsigned int j;
2023-09-09 08:03:56 +01:00
if (!DTMF_GetContact(i, Contact))
return false;
for (j = 0; j < 3; j++)
if (pContact[j] != Contact[j + 8])
break;
if (j == 3)
{
memcpy(pResult, Contact, 8);
2023-09-09 08:03:56 +01:00
pResult[8] = 0;
return true;
}
}
return false;
}
2023-09-30 11:22:19 +01:00
char DTMF_GetCharacter(const unsigned int code)
2023-09-09 08:03:56 +01:00
{
switch (code)
{
case KEY_0: return '0';
case KEY_1: return '1';
case KEY_2: return '2';
case KEY_3: return '3';
case KEY_4: return '4';
case KEY_5: return '5';
case KEY_6: return '6';
case KEY_7: return '7';
case KEY_8: return '8';
case KEY_9: return '9';
case KEY_MENU: return 'A';
case KEY_UP: return 'B';
case KEY_DOWN: return 'C';
case KEY_EXIT: return 'D';
case KEY_STAR: return '*';
case KEY_F: return '#';
default: return 0xff;
}
2023-09-09 08:03:56 +01:00
}
2023-09-30 11:22:19 +01:00
bool DTMF_CompareMessage(const char *pMsg, const char *pTemplate, const unsigned int size, const bool bCheckGroup)
2023-09-09 08:03:56 +01:00
{
2023-09-12 11:49:16 +01:00
unsigned int i;
2023-09-30 11:22:19 +01:00
for (i = 0; i < size; i++)
2023-09-09 08:03:56 +01:00
{
if (pMsg[i] != pTemplate[i])
{
2023-10-08 20:23:37 +01:00
if (!bCheckGroup || pMsg[i] != g_eeprom.dtmf_group_call_code)
2023-09-09 08:03:56 +01:00
return false;
2023-10-08 20:23:37 +01:00
g_dtmf_IsGroupCall = true;
2023-09-09 08:03:56 +01:00
}
}
2023-09-30 11:22:19 +01:00
return true;
2023-09-09 08:03:56 +01:00
}
2023-10-08 20:23:37 +01:00
dtmf_call_mode_t DTMF_CheckGroupCall(const char *pMsg, const unsigned int size)
2023-09-09 08:03:56 +01:00
{
2023-09-30 11:22:19 +01:00
unsigned int i;
for (i = 0; i < size; i++)
2023-10-08 20:23:37 +01:00
if (pMsg[i] == g_eeprom.dtmf_group_call_code)
2023-09-09 08:03:56 +01:00
break;
2023-10-02 19:23:37 +01:00
2023-09-30 11:22:19 +01:00
return (i < size) ? DTMF_CALL_MODE_GROUP : DTMF_CALL_MODE_NOT_GROUP;
2023-09-09 08:03:56 +01:00
}
void DTMF_clear_input_box(void)
{
2023-10-08 20:23:37 +01:00
memset(g_dtmf_input_box, 0, sizeof(g_dtmf_input_box));
g_dtmf_input_box_index = 0;
g_dtmf_input_mode = false;
}
2023-09-30 11:22:19 +01:00
void DTMF_Append(const char code)
2023-09-09 08:03:56 +01:00
{
2023-10-08 20:23:37 +01:00
if (g_dtmf_input_box_index == 0)
2023-09-09 08:03:56 +01:00
{
2023-10-08 20:23:37 +01:00
memset(g_dtmf_input_box, '-', sizeof(g_dtmf_input_box) - 1);
g_dtmf_input_box[sizeof(g_dtmf_input_box) - 1] = 0;
2023-09-09 08:03:56 +01:00
}
2023-10-08 20:23:37 +01:00
if (g_dtmf_input_box_index < (sizeof(g_dtmf_input_box) - 1))
g_dtmf_input_box[g_dtmf_input_box_index++] = code;
2023-09-09 08:03:56 +01:00
}
void DTMF_HandleRequest(void)
2023-09-30 11:22:19 +01:00
{ // proccess the RX'ed DTMF characters
2023-09-09 08:03:56 +01:00
char String[21];
2023-09-30 11:22:19 +01:00
unsigned int Offset;
2023-09-09 08:03:56 +01:00
2023-10-08 20:23:37 +01:00
if (!g_dtmf_rx_pending)
2023-09-30 11:22:19 +01:00
return; // nothing new received
2023-09-09 08:03:56 +01:00
if (g_scan_state_dir != SCAN_STATE_DIR_OFF || g_css_scan_mode != CSS_SCAN_MODE_OFF)
2023-09-30 11:22:19 +01:00
{ // we're busy scanning
DTMF_clear_RX();
2023-09-09 08:03:56 +01:00
return;
2023-09-30 11:22:19 +01:00
}
2023-10-02 19:23:37 +01:00
#ifdef ENABLE_KILL_REVIVE
if (!g_rx_vfo->dtmf_decoding_enable && !g_setting_radio_disabled)
#else
if (!g_rx_vfo->dtmf_decoding_enable)
#endif
{ // D-DCD is disabled or we're enabled
2023-09-30 11:22:19 +01:00
DTMF_clear_RX();
2023-09-09 08:03:56 +01:00
return;
2023-09-30 11:22:19 +01:00
}
2023-10-08 20:23:37 +01:00
g_dtmf_rx_pending = false;
2023-09-30 11:22:19 +01:00
#ifdef ENABLE_KILL_REVIVE
if (g_dtmf_rx_index >= 9)
{ // look for the RADIO DISABLE code
sprintf(String, "%s%c%s", g_eeprom.ani_dtmf_id, g_eeprom.dtmf_separate_code, g_eeprom.kill_code);
Offset = g_dtmf_rx_index - strlen(String);
if (DTMF_CompareMessage(g_dtmf_rx + Offset, String, strlen(String), true))
{ // bugger
if (g_eeprom.permit_remote_kill)
{
g_setting_radio_disabled = true; // :(
DTMF_clear_RX();
2023-10-19 14:21:37 +01:00
SETTINGS_save();
g_dtmf_reply_state = DTMF_REPLY_AB;
#ifdef ENABLE_FMRADIO
if (g_fm_radio_mode)
{
FM_TurnOff();
GUI_SelectNextDisplay(DISPLAY_MAIN);
}
#endif
}
else
{
g_dtmf_reply_state = DTMF_REPLY_NONE;
}
g_dtmf_call_state = DTMF_CALL_STATE_NONE;
g_update_display = true;
g_update_status = true;
return;
}
}
2023-09-30 11:22:19 +01:00
if (g_dtmf_rx_index >= 9)
{ // look for the REVIVE code
sprintf(String, "%s%c%s", g_eeprom.ani_dtmf_id, g_eeprom.dtmf_separate_code, g_eeprom.revive_code);
Offset = g_dtmf_rx_index - strlen(String);
if (DTMF_CompareMessage(g_dtmf_rx + Offset, String, strlen(String), true))
{ // shit, we're back !
g_setting_radio_disabled = false;
2023-09-30 11:22:19 +01:00
DTMF_clear_RX();
2023-10-19 14:21:37 +01:00
SETTINGS_save();
2023-10-08 20:23:37 +01:00
g_dtmf_reply_state = DTMF_REPLY_AB;
g_dtmf_call_state = DTMF_CALL_STATE_NONE;
g_update_display = true;
g_update_status = true;
return;
2023-09-09 08:03:56 +01:00
}
}
#endif
2023-09-09 08:03:56 +01:00
2023-10-08 20:23:37 +01:00
if (g_dtmf_rx_index >= 2)
2023-09-30 11:22:19 +01:00
{ // look for ACK reply
strcpy(String, "AB");
2023-10-02 19:23:37 +01:00
2023-10-08 20:23:37 +01:00
Offset = g_dtmf_rx_index - strlen(String);
2023-09-30 11:22:19 +01:00
2023-10-08 20:23:37 +01:00
if (DTMF_CompareMessage(g_dtmf_rx + Offset, String, strlen(String), true))
2023-09-30 11:22:19 +01:00
{ // ends with "AB"
2023-10-08 20:23:37 +01:00
if (g_dtmf_reply_state != DTMF_REPLY_NONE) // 1of11
// if (g_dtmf_call_state == DTMF_CALL_STATE_CALL_OUT) // 1of11
2023-09-30 11:22:19 +01:00
{
2023-10-08 20:23:37 +01:00
g_dtmf_state = DTMF_STATE_TX_SUCC;
2023-09-30 11:22:19 +01:00
DTMF_clear_RX();
2023-10-08 20:23:37 +01:00
g_update_display = true;
2023-09-30 11:22:19 +01:00
return;
}
2023-09-09 08:03:56 +01:00
}
}
2023-10-08 20:23:37 +01:00
if (g_dtmf_call_state == DTMF_CALL_STATE_CALL_OUT &&
g_dtmf_call_mode == DTMF_CALL_MODE_NOT_GROUP &&
g_dtmf_rx_index >= 9)
2023-09-30 11:22:19 +01:00
{ // waiting for a reply
2023-10-02 19:23:37 +01:00
2023-10-08 20:23:37 +01:00
sprintf(String, "%s%c%s", g_dtmf_string, g_eeprom.dtmf_separate_code, "AAAAA");
2023-10-08 20:23:37 +01:00
Offset = g_dtmf_rx_index - strlen(String);
2023-09-30 11:22:19 +01:00
2023-10-08 20:23:37 +01:00
if (DTMF_CompareMessage(g_dtmf_rx + Offset, String, strlen(String), false))
2023-09-30 11:22:19 +01:00
{ // we got a response
2023-10-08 20:23:37 +01:00
g_dtmf_state = DTMF_STATE_CALL_OUT_RSP;
2023-09-30 11:22:19 +01:00
DTMF_clear_RX();
2023-10-08 20:23:37 +01:00
g_update_display = true;
2023-09-09 08:03:56 +01:00
}
}
#ifdef ENABLE_KILL_REVIVE
if (g_setting_radio_disabled)
return; // we've been disabled
#endif
2023-09-09 08:03:56 +01:00
2023-10-08 20:23:37 +01:00
if (g_dtmf_rx_index >= 7)
2023-09-30 11:22:19 +01:00
{ // see if we're being called
2023-10-08 20:23:37 +01:00
g_dtmf_IsGroupCall = false;
2023-10-08 20:23:37 +01:00
sprintf(String, "%s%c", g_eeprom.ani_dtmf_id, g_eeprom.dtmf_separate_code);
2023-10-08 20:23:37 +01:00
Offset = g_dtmf_rx_index - strlen(String) - 3;
2023-09-30 11:22:19 +01:00
2023-10-08 20:23:37 +01:00
if (DTMF_CompareMessage(g_dtmf_rx + Offset, String, strlen(String), true))
2023-09-30 11:22:19 +01:00
{ // it's for us !
2023-10-08 20:23:37 +01:00
g_dtmf_call_state = DTMF_CALL_STATE_RECEIVED;
2023-10-08 20:23:37 +01:00
memset(g_dtmf_callee, 0, sizeof(g_dtmf_callee));
memset(g_dtmf_caller, 0, sizeof(g_dtmf_caller));
memcpy(g_dtmf_callee, g_dtmf_rx + Offset + 0, 3);
memcpy(g_dtmf_caller, g_dtmf_rx + Offset + 4, 3);
2023-09-30 11:22:19 +01:00
DTMF_clear_RX();
2023-09-09 08:03:56 +01:00
2023-10-08 20:23:37 +01:00
g_update_display = true;
2023-09-09 08:03:56 +01:00
2023-10-08 20:23:37 +01:00
switch (g_eeprom.dtmf_decode_response)
2023-09-09 08:03:56 +01:00
{
2023-09-30 11:22:19 +01:00
case DTMF_DEC_RESPONSE_BOTH:
g_dtmf_decode_ring_tick_500ms = dtmf_decode_ring_500ms;
2023-10-28 23:11:57 +01:00
// Fallthrough
2023-09-30 11:22:19 +01:00
case DTMF_DEC_RESPONSE_REPLY:
2023-10-08 20:23:37 +01:00
g_dtmf_reply_state = DTMF_REPLY_AAAAA;
2023-09-09 08:03:56 +01:00
break;
2023-09-30 11:22:19 +01:00
case DTMF_DEC_RESPONSE_RING:
g_dtmf_decode_ring_tick_500ms = dtmf_decode_ring_500ms;
2023-09-09 08:03:56 +01:00
break;
default:
2023-09-30 11:22:19 +01:00
case DTMF_DEC_RESPONSE_NONE:
g_dtmf_decode_ring_tick_500ms = 0;
2023-10-08 20:23:37 +01:00
g_dtmf_reply_state = DTMF_REPLY_NONE;
2023-09-09 08:03:56 +01:00
break;
}
2023-10-08 20:23:37 +01:00
if (g_dtmf_IsGroupCall)
g_dtmf_reply_state = DTMF_REPLY_NONE;
2023-09-09 08:03:56 +01:00
}
}
}
2023-10-18 11:31:30 +01:00
bool DTMF_Reply(void)
2023-09-09 08:03:56 +01:00
{
2023-10-18 21:22:12 +01:00
const uint16_t Delay = (g_eeprom.dtmf_preload_time < 150) ? 150 : g_eeprom.dtmf_preload_time;
const char *pString = NULL;
char String[23];
2023-09-09 08:03:56 +01:00
2023-10-08 20:23:37 +01:00
switch (g_dtmf_reply_state)
2023-09-09 08:03:56 +01:00
{
case DTMF_REPLY_ANI:
2023-10-08 20:23:37 +01:00
if (g_dtmf_call_mode == DTMF_CALL_MODE_DTMF)
2023-09-09 08:03:56 +01:00
{
2023-10-08 20:23:37 +01:00
pString = g_dtmf_string;
2023-09-09 08:03:56 +01:00
}
else
2023-09-18 00:48:40 +01:00
{ // append our ID code onto the end of the DTMF code to send
2023-10-08 20:23:37 +01:00
sprintf(String, "%s%c%s", g_dtmf_string, g_eeprom.dtmf_separate_code, g_eeprom.ani_dtmf_id);
2023-09-09 08:03:56 +01:00
pString = String;
}
break;
2023-10-02 19:23:37 +01:00
2023-09-09 08:03:56 +01:00
case DTMF_REPLY_AB:
pString = "AB";
break;
2023-10-02 19:23:37 +01:00
2023-09-09 08:03:56 +01:00
case DTMF_REPLY_AAAAA:
2023-10-08 20:23:37 +01:00
sprintf(String, "%s%c%s", g_eeprom.ani_dtmf_id, g_eeprom.dtmf_separate_code, "AAAAA");
2023-09-09 08:03:56 +01:00
pString = String;
break;
2023-10-02 19:23:37 +01:00
2023-09-09 08:03:56 +01:00
default:
2023-10-01 21:50:05 +01:00
case DTMF_REPLY_NONE:
2023-10-08 20:23:37 +01:00
if (g_dtmf_call_state != DTMF_CALL_STATE_NONE ||
g_current_vfo->dtmf_ptt_id_tx_mode == PTT_ID_APOLLO ||
g_current_vfo->dtmf_ptt_id_tx_mode == PTT_ID_OFF ||
g_current_vfo->dtmf_ptt_id_tx_mode == PTT_ID_TX_DOWN)
2023-09-09 08:03:56 +01:00
{
2023-10-08 20:23:37 +01:00
g_dtmf_reply_state = DTMF_REPLY_NONE;
2023-10-18 11:31:30 +01:00
return false;
2023-09-09 08:03:56 +01:00
}
2023-10-02 19:23:37 +01:00
// send TX-UP DTMF
pString = g_eeprom.dtmf_key_up_code;
2023-09-09 08:03:56 +01:00
break;
}
2023-10-08 20:23:37 +01:00
g_dtmf_reply_state = DTMF_REPLY_NONE;
2023-09-09 08:03:56 +01:00
if (pString == NULL)
2023-10-18 11:31:30 +01:00
return false;
2023-10-02 19:23:37 +01:00
2023-10-08 20:23:37 +01:00
if (g_eeprom.dtmf_side_tone)
{ // the user will also hear the transmitted tones
2023-10-18 11:31:30 +01:00
GPIO_SetBit(&GPIOC->DATA, GPIOC_PIN_SPEAKER);
2023-10-23 14:02:54 +01:00
g_speaker_enabled = true;
2023-09-09 08:03:56 +01:00
}
2023-10-02 19:23:37 +01:00
2023-09-09 08:03:56 +01:00
SYSTEM_DelayMs(Delay);
2023-10-08 20:23:37 +01:00
BK4819_EnterDTMF_TX(g_eeprom.dtmf_side_tone);
2023-09-09 08:03:56 +01:00
BK4819_PlayDTMFString(
pString,
1,
2023-10-08 20:23:37 +01:00
g_eeprom.dtmf_first_code_persist_time,
g_eeprom.dtmf_hash_code_persist_time,
g_eeprom.dtmf_code_persist_time,
g_eeprom.dtmf_code_interval_time);
2023-09-09 08:03:56 +01:00
2023-10-18 11:31:30 +01:00
GPIO_ClearBit(&GPIOC->DATA, GPIOC_PIN_SPEAKER);
2023-10-23 14:02:54 +01:00
g_speaker_enabled = false;
2023-09-09 08:03:56 +01:00
BK4819_ExitDTMF_TX(false);
2023-10-18 11:31:30 +01:00
return true;
2023-09-09 08:03:56 +01:00
}