All checks were successful
Build Firmware / build (push) Successful in 2m30s
388 lines
12 KiB
C
388 lines
12 KiB
C
//
|
|
// Created by bruno on 25.2.2025.
|
|
//
|
|
|
|
#include "fskmodem.h"
|
|
//#include "messages.h"
|
|
#include "driver/uart.h"
|
|
#include "../ui/messages.h"
|
|
|
|
uint16_t TONE2_FREQ;
|
|
|
|
DataPacket dataPacket;
|
|
|
|
DataPacket inBoundPacket;
|
|
|
|
uint8_t *dataPTR = dataPacket.data;
|
|
|
|
SMSEnteringState gEnteringSMS = SMS_NOT_ENTERING;
|
|
|
|
typedef enum {
|
|
Receiving,
|
|
Ready
|
|
} RXState;
|
|
|
|
RXState rxState = Ready;
|
|
|
|
void MSG_ConfigureFSK(bool rx) {
|
|
BK4819_WriteRegister(BK4819_REG_70, TONE2_ENABLE_BIT | (96U << 0));
|
|
|
|
switch (gEeprom.FSKMode) {
|
|
case MOD_AFSK_2400:
|
|
TONE2_FREQ = 24779U; // Estimated
|
|
break;
|
|
case MOD_AFSK_1200:
|
|
TONE2_FREQ = 12389U;
|
|
break;
|
|
case MOD_FSK_700:
|
|
TONE2_FREQ = 7227U;
|
|
break;
|
|
case MOD_FSK_450:
|
|
TONE2_FREQ = 4646U;
|
|
break;
|
|
case MOD_FSK_1200_2400:
|
|
TONE2_FREQ = 12389U; // Default to 1200Hz, dynamic switching may be required
|
|
break;
|
|
case MOD_NOAA_SAME:
|
|
TONE2_FREQ = 2083U; // NOAA SAME uses 2083.3 Hz for mark and 1562.5 Hz for space
|
|
break;
|
|
}
|
|
|
|
|
|
BK4819_WriteRegister(BK4819_REG_72, TONE2_FREQ);
|
|
|
|
// uint16_t fskConfig = FSK_ENABLE_BIT | FSK_RX_BW_1_2K | FSK_RX_GAIN_DEFAULT | FSK_PREAMBLE_TYPE_AA;
|
|
// if (gEeprom.FSKMode == MOD_AFSK_1200) {
|
|
// fskConfig = FSK_ENABLE_BIT | FSK_TX_MODE_FSK_1_2K_2_4K | FSK_RX_MODE_FSK_1_2K_2_4K_NOAA;
|
|
// }
|
|
|
|
uint16_t fskConfig = FSK_ENABLE_BIT | FSK_PREAMBLE_TYPE_AA;
|
|
|
|
switch (gEeprom.FSKMode) {
|
|
case MOD_FSK_700:
|
|
case MOD_FSK_450:
|
|
case MOD_FSK_1200_2400:
|
|
fskConfig |= FSK_TX_MODE_FSK_1_2K_2_4K | FSK_RX_MODE_FSK_1_2K_2_4K_NOAA | FSK_RX_BW_1_2K;
|
|
break;
|
|
case MOD_AFSK_1200:
|
|
fskConfig |= FSK_TX_MODE_FFSK_1200_1800 | FSK_RX_MODE_FFSK_1200_1800 | FSK_RX_BW_FFSK_1200_1800;
|
|
break;
|
|
case MOD_AFSK_2400:
|
|
fskConfig |= FSK_TX_MODE_FFSK_1200_2400 | FSK_RX_MODE_FFSK_1200_2400 | FSK_RX_BW_2_4K_FFSK_1200_2400;
|
|
break;
|
|
case MOD_NOAA_SAME:
|
|
fskConfig |= FSK_TX_MODE_NOAA_SAME | FSK_RX_MODE_FSK_1_2K_2_4K_NOAA | FSK_RX_BW_NOAA_SAME;
|
|
break;
|
|
default:
|
|
// Unsupported mode; keep previous setting
|
|
break;
|
|
}
|
|
|
|
|
|
BK4819_WriteRegister(BK4819_REG_58, fskConfig);
|
|
|
|
BK4819_WriteRegister(BK4819_REG_5A, FSK_SYNC_BYTE0 << 8 | FSK_SYNC_BYTE1);
|
|
BK4819_WriteRegister(BK4819_REG_5B, FSK_SYNC_BYTE2 << 8 | FSK_SYNC_BYTE3);
|
|
BK4819_WriteRegister(BK4819_REG_5C, FSK_CRC_ON);
|
|
|
|
if (rx) {
|
|
BK4819_WriteRegister(BK4819_REG_5E, (64U << 3) | (1U << 0));
|
|
}
|
|
|
|
size_t size = sizeof(dataPacket);
|
|
if (rx) {
|
|
size = (((size + 1) / 2) * 2) + 2;
|
|
}
|
|
BK4819_WriteRegister(BK4819_REG_5D, (size << 8));
|
|
|
|
BK4819_FskClearFifo();
|
|
|
|
uint16_t fskParams = FSK_SYNC_LEN_BIT | ((rx ? 0U : 15U) << 4);
|
|
if (gCurrentVfo->SCRAMBLING_TYPE > 0) {
|
|
fskParams |= FSK_SCRAMBLE_ENABLE;
|
|
}
|
|
BK4819_WriteRegister(BK4819_REG_59, fskParams);
|
|
|
|
BK4819_WriteRegister(BK4819_REG_02, 0);
|
|
}
|
|
|
|
|
|
uint16_t calculateCRC(uint8_t *data, size_t length) {
|
|
uint16_t crc = 0xFFFF; // Example CRC-16 initialization
|
|
for (size_t i = 0; i < length; i++) {
|
|
crc ^= data[i];
|
|
for (uint8_t j = 0; j < 8; j++) {
|
|
if (crc & 1) {
|
|
crc = (crc >> 1) ^ 0xA001; // Example polynomial (CRC-16-IBM)
|
|
} else {
|
|
crc >>= 1;
|
|
}
|
|
}
|
|
}
|
|
return crc;
|
|
}
|
|
|
|
|
|
void processReceivedPacket(DataPacket *packet) {
|
|
char String[18];
|
|
char numBuf[11]; // Enough for any 64-bit unsigned integer
|
|
const unsigned int vfo = (gEeprom.CROSS_BAND_RX_TX == CROSS_BAND_OFF) ? gEeprom.RX_VFO
|
|
: gEeprom.TX_VFO;
|
|
|
|
if (packet->dest == gEeprom.FSKSRCAddress) {
|
|
AUDIO_PlayBeep(BEEP_500HZ_60MS_DOUBLE_BEEP);
|
|
BK4819_PlaySingleTone(1000, 250, 127, true);
|
|
strcpy(String, "SMS by ");
|
|
itoa(packet->src, numBuf); // Convert number to string
|
|
strcat(String, numBuf);
|
|
MESSAGES_SAVE();
|
|
UI_DisplayPopup(String);
|
|
#ifdef ENABLE_FEAT_F4HWN
|
|
if (isMainOnly()) {
|
|
UI_PrintStringSmallNormal(String, 2, 0, 5);
|
|
} else {
|
|
UI_PrintStringSmallNormal(String, 2, 0, 3);
|
|
}
|
|
#else
|
|
UI_PrintStringSmallNormal(String, 2, 0, 3);
|
|
|
|
#endif
|
|
|
|
} else if (VfoState[vfo] == VFO_STATE_NORMAL && !TX_freq_check(gCurrentVfo->freq_config_TX.Frequency)) {
|
|
if (packet->ttl--) {
|
|
BK4819_ToggleGpioOut(BK4819_GPIO5_PIN1_RED, true);
|
|
MSG_FSKSendData(packet);
|
|
BK4819_ToggleGpioOut(BK4819_GPIO5_PIN1_RED, false);
|
|
}
|
|
}
|
|
|
|
memset(packet, 0, sizeof(DataPacket)); // Clear data after processing (example action)
|
|
}
|
|
|
|
|
|
bool MSG_FSKReceiveData() {
|
|
if (!(BK4819_ReadRegister(BK4819_REG_0C) & (1U << 1))) {
|
|
return false; // No data available
|
|
}
|
|
|
|
// Read the received data from FIFO
|
|
uint16_t *ptr = (uint16_t *) &inBoundPacket;
|
|
size_t wordCount = sizeof(inBoundPacket) / sizeof(uint16_t);
|
|
|
|
for (size_t i = 0; i < wordCount; i++) {
|
|
ptr[i] = BK4819_ReadRegister(BK4819_REG_5F);
|
|
}
|
|
|
|
// Clear the RX interrupt flag
|
|
BK4819_WriteRegister(BK4819_REG_02, 0);
|
|
|
|
// Validate checksum (assuming last 2 bytes are CRC-16)
|
|
size_t dataLength = sizeof(inBoundPacket.data) - 2;
|
|
uint16_t receivedCRC = (inBoundPacket.data[dataLength] << 8) | inBoundPacket.data[dataLength + 1];
|
|
uint16_t calculatedCRC = calculateCRC(inBoundPacket.data, dataLength);
|
|
|
|
if (receivedCRC == calculatedCRC) {
|
|
processReceivedPacket(&inBoundPacket);
|
|
return true;
|
|
}
|
|
|
|
return false; // CRC check failed
|
|
}
|
|
|
|
void MSG_EnableRX(const bool enable) {
|
|
|
|
if (enable) {
|
|
MSG_ConfigureFSK(true);
|
|
|
|
//if(gEeprom.MESSENGER_CONFIG.data.receive)
|
|
BK4819_FskEnableRx();
|
|
} else {
|
|
BK4819_WriteRegister(BK4819_REG_70, 0);
|
|
BK4819_WriteRegister(BK4819_REG_58, 0);
|
|
}
|
|
}
|
|
|
|
void MSG_FSKSendData(DataPacket *dataPacketIn) {
|
|
|
|
bool isAudioOn = gEnableSpeaker;
|
|
if (gEnableSpeaker) {
|
|
AUDIO_AudioPathOff();
|
|
BK4819_EnterTxMute();
|
|
gEnableSpeaker = false;
|
|
}
|
|
// turn off CTCSS/CDCSS during FFSK
|
|
const uint16_t css_val = BK4819_ReadRegister(BK4819_REG_51);
|
|
BK4819_WriteRegister(BK4819_REG_51, 0);
|
|
|
|
// set the FM deviation level
|
|
const uint16_t dev_val = BK4819_ReadRegister(BK4819_REG_40);
|
|
|
|
{
|
|
uint16_t deviation;
|
|
switch (gEeprom.VfoInfo[gEeprom.TX_VFO].CHANNEL_BANDWIDTH) {
|
|
case BK4819_FILTER_BW_WIDE:
|
|
deviation = 1300;
|
|
break; // 20k // measurements by kamilsss655
|
|
case BK4819_FILTER_BW_NARROW:
|
|
deviation = 1200;
|
|
break; // 10k
|
|
// case BK4819_FILTER_BW_NARROWAVIATION: deviation = 850; break; // 5k
|
|
// case BK4819_FILTER_BW_NARROWER: deviation = 850; break; // 5k
|
|
// case BK4819_FILTER_BW_NARROWEST: deviation = 850; break; // 5k
|
|
default:
|
|
deviation = 850;
|
|
break; // 5k
|
|
}
|
|
|
|
//BK4819_WriteRegister(0x40, (3u << 12) | (deviation & 0xfff));
|
|
BK4819_WriteRegister(BK4819_REG_40, (dev_val & 0xf000) | (deviation & 0xfff));
|
|
}
|
|
|
|
// REG_2B 0
|
|
//
|
|
// <15> 1 Enable CTCSS/CDCSS DC cancellation after FM Demodulation 1 = enable 0 = disable
|
|
// <14> 1 Enable AF DC cancellation after FM Demodulation 1 = enable 0 = disable
|
|
// <10> 0 AF RX HPF 300Hz filter 0 = enable 1 = disable
|
|
// <9> 0 AF RX LPF 3kHz filter 0 = enable 1 = disable
|
|
// <8> 0 AF RX de-emphasis filter 0 = enable 1 = disable
|
|
// <2> 0 AF TX HPF 300Hz filter 0 = enable 1 = disable
|
|
// <1> 0 AF TX LPF filter 0 = enable 1 = disable
|
|
// <0> 0 AF TX pre-emphasis filter 0 = enable 1 = disable
|
|
//
|
|
// disable the 300Hz HPF and FM pre-emphasis filter
|
|
//
|
|
const uint16_t filt_val = BK4819_ReadRegister(BK4819_REG_2B);
|
|
BK4819_WriteRegister(BK4819_REG_2B, (1u << 2) | (1u << 0));
|
|
|
|
MSG_ConfigureFSK(false);
|
|
|
|
|
|
SYSTEM_DelayMs(100);
|
|
|
|
{ // load the entire packet data into the TX FIFO buffer
|
|
uint16_t *ptr = (uint16_t *) dataPacketIn;
|
|
size_t wordCount = sizeof(*dataPacketIn) / sizeof(uint16_t);
|
|
|
|
for (size_t i = 0; i < wordCount; i++) {
|
|
BK4819_WriteRegister(BK4819_REG_5F, ptr[i]);
|
|
}
|
|
}
|
|
|
|
// enable FSK TX
|
|
BK4819_FskEnableTx();
|
|
|
|
{
|
|
// allow up to 310ms for the TX to complete
|
|
// if it takes any longer then somethings gone wrong, we shut the TX down
|
|
unsigned int timeout = 1000 / 5;
|
|
|
|
while (timeout-- > 0) {
|
|
SYSTEM_DelayMs(5);
|
|
if (BK4819_ReadRegister(BK4819_REG_0C) & (1u << 0)) { // we have interrupt flags
|
|
BK4819_WriteRegister(BK4819_REG_02, 0);
|
|
if (BK4819_ReadRegister(BK4819_REG_02) & BK4819_REG_02_FSK_TX_FINISHED)
|
|
timeout = 0; // TX is complete
|
|
}
|
|
}
|
|
}
|
|
//BK4819_WriteRegister(BK4819_REG_02, 0);
|
|
|
|
SYSTEM_DelayMs(100);
|
|
|
|
// disable TX
|
|
MSG_ConfigureFSK(true);
|
|
|
|
// restore FM deviation level
|
|
BK4819_WriteRegister(BK4819_REG_40, dev_val);
|
|
|
|
// restore TX/RX filtering
|
|
BK4819_WriteRegister(BK4819_REG_2B, filt_val);
|
|
|
|
// restore the CTCSS/CDCSS setting
|
|
BK4819_WriteRegister(BK4819_REG_51, css_val);
|
|
|
|
SYSTEM_DelayMs(50);
|
|
APP_EndTransmission();
|
|
FUNCTION_Select(FUNCTION_FOREGROUND);
|
|
gUpdateStatus = true;
|
|
gUpdateDisplay = true;
|
|
gFlagEndTransmission = false;
|
|
|
|
if (isAudioOn) {
|
|
AUDIO_AudioPathOn();
|
|
gEnableSpeaker = true;
|
|
BK4819_ExitTxMute();
|
|
}
|
|
|
|
}
|
|
|
|
void prepareDataPacket() {
|
|
dataPacket.src = gEeprom.FSKSRCAddress;
|
|
uint8_t Data[8];
|
|
EEPROM_ReadBuffer(SEQParameterEEPROM, Data, 8);
|
|
dataPacket.seq = Data[0];
|
|
Data[0]++;
|
|
EEPROM_WriteBuffer(SEQParameterEEPROM, Data);
|
|
dataPacket.ttl = 20;
|
|
}
|
|
|
|
void FSK_HANDLE_IRQ(unsigned short irq) {
|
|
//const uint16_t rx_sync_flags = BK4819_ReadRegister(BK4819_REG_0B);
|
|
|
|
const bool rx_sync = (irq & BK4819_REG_02_FSK_RX_SYNC) != 0;
|
|
const bool rx_fifo_almost_full = (irq & BK4819_REG_02_FSK_FIFO_ALMOST_FULL) != 0;
|
|
const bool rx_finished = (irq & BK4819_REG_02_FSK_RX_FINISHED) != 0;
|
|
|
|
//UART_printf("\nMSG : S%i, F%i, E%i | %i", rx_sync, rx_fifo_almost_full, rx_finished, irq);
|
|
|
|
if (rx_sync) {
|
|
// prevent listening to fsk data and squelch (kamilsss655)
|
|
// CTCSS codes seem to false trigger the rx_sync
|
|
if (gCurrentCodeType == CODE_TYPE_OFF)
|
|
AUDIO_AudioPathOff();
|
|
gFSKWriteIndex = 0;
|
|
memset(&inBoundPacket, 0, sizeof(DataPacket));
|
|
rxState = Receiving;
|
|
UART_String("Sync\n");
|
|
}
|
|
|
|
if (rx_fifo_almost_full && rxState == Receiving) {
|
|
const uint16_t count = BK4819_ReadRegister(BK4819_REG_5E) & (7u << 0); // Almost full threshold
|
|
uint16_t *ptr = (uint16_t *) &inBoundPacket;
|
|
size_t wordCount = sizeof(inBoundPacket) / sizeof(uint16_t);
|
|
|
|
for (uint16_t i = 0; i < count && gFSKWriteIndex < wordCount; i++) {
|
|
ptr[gFSKWriteIndex++] = BK4819_ReadRegister(BK4819_REG_5F);
|
|
UART_Send((const void *) &ptr[gFSKWriteIndex - 1], 2);
|
|
}
|
|
|
|
SYSTEM_DelayMs(10);
|
|
}
|
|
|
|
if (rx_finished) {
|
|
// Turn off green LED
|
|
BK4819_FskClearFifo();
|
|
|
|
rxState = Ready;
|
|
UART_String("FSK end\n");
|
|
|
|
if (gFSKWriteIndex > 2) {
|
|
// Validate checksum (assuming last 2 bytes are CRC-16)
|
|
//size_t dataLength = sizeof(inBoundPacket.data) - 2;
|
|
//uint16_t receivedCRC = (inBoundPacket.data[dataLength] << 8) | inBoundPacket.data[dataLength + 1];
|
|
//uint16_t calculatedCRC = calculateCRC(inBoundPacket.data, dataLength);
|
|
|
|
//if (receivedCRC == calculatedCRC) {
|
|
processReceivedPacket(&inBoundPacket);
|
|
//}
|
|
}
|
|
|
|
APP_EndTransmission();
|
|
FUNCTION_Select(FUNCTION_FOREGROUND);
|
|
gUpdateStatus = true;
|
|
gUpdateDisplay = true;
|
|
gFlagEndTransmission = false;
|
|
|
|
gFSKWriteIndex = 0;
|
|
}
|
|
} |