// // Created by bruno on 3/30/25. // #include "messages.h" #include "ui/ui.h" #include "driver/uart.h" #include "driver/systick.h" #define T9Count 9 const char T9Table[10][T9Count] = { {'#', '(', ')', ';', ':', '<', '>', '/', '0'}, {',', '.', '?', '&', '!', ' ', '-', '_', '1'}, {'a', 'b', 'c', 'A', 'B', 'C', '[', ']', '2'}, {'d', 'e', 'f', 'D', 'E', 'F', '@', '%', '3'}, {'g', 'h', 'i', 'G', 'H', 'I', '~', '$', '4'}, {'j', 'k', 'l', 'J', 'K', 'L', '|', '*', '5'}, {'m', 'n', 'o', 'M', 'N', 'O', '{', '}', '6'}, {'p', 'q', 'r', 's', 'P', 'Q', 'R', 'S', '7'}, {'t', 'u', 'v', 'T', 'U', 'V', '"', '\'', '8'}, {'w', 'x', 'y', 'z', 'W', 'X', 'Y', 'Z', '9'} }; uint8_t gActiveMessage = 0; StoredPacket loadedPacket; uint8_t gKeyTimeout = 0; void MESSAGES_SAVE() { uint8_t Data[8]; EEPROM_ReadBuffer(SEQParameterEEPROM, Data, 8); uint8_t msgIndex = Data[1]; if (msgIndex >= MESSAGES_COUNT) { msgIndex = 0; } Data[1]++; EEPROM_WriteBuffer(SEQParameterEEPROM, Data); EEPROM_WriteBuffer(MESSAGES_START + (msgIndex * sizeof(StoredPacket)) + 0, (uint8_t *) &inBoundPacket + 4); // metadata EEPROM_WriteBuffer(MESSAGES_START + (msgIndex * sizeof(StoredPacket)) + 8, (uint8_t *) &inBoundPacket + 12); // message part 1 EEPROM_WriteBuffer(MESSAGES_START + (msgIndex * sizeof(StoredPacket)) + 16, (uint8_t *) &inBoundPacket + 20); // message part 2 EEPROM_WriteBuffer(MESSAGES_START + (msgIndex * sizeof(StoredPacket)) + 24, (uint8_t *) &inBoundPacket + 28); // message part 3 EEPROM_WriteBuffer(MESSAGES_START + (msgIndex * sizeof(StoredPacket)) + 32, (uint8_t *) &inBoundPacket + 36); // message part 4 } void MESSAGES_GET() { if (gActiveMessage == MESSAGES_COUNT) { memcpy(&loadedPacket, (uint8_t *) &dataPacket + (sizeof(DataPacket) - sizeof(StoredPacket)), sizeof(StoredPacket)); } else { EEPROM_ReadBuffer(MESSAGES_START + (gActiveMessage * sizeof(StoredPacket)), &loadedPacket, sizeof(StoredPacket)); } } void MESSAGES_DELETE() { } void updatePrevChar(KEY_Code_t Key) { if (Key != prevKey) { prevKey = Key; } } void MESSAGES_TimeSlice500ms(void) { if (gKeyTimeout && gKeyTimeout++ > 2) { gKeyTimeout = 0; prevKey = KEY_EXIT; } } void MESSAGES_ProcessKeys(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld) { gKeyTimeout = 1; if (gEnteringSMS != SMS_NOT_ENTERING && !bKeyHeld && Key <= KEY_9) { if (!dataPTR || dataPTR < dataPacket.data) { dataPTR = dataPacket.data; } if (gEnteringSMS == SMS_ENTERING_MESSAGE) { if (bKeyPressed) { if (prevKey != Key) { dataPTR++; if (dataPTR - dataPacket.data >= DataPacketDataSize) { dataPTR = dataPacket.data; } prevLetter = 0; } *(dataPTR - 1) = T9Table[Key][(prevLetter++) % T9Count]; updatePrevChar(Key); } return; } else if (gEnteringSMS == SMS_ENTERING_DEST) { if (bKeyPressed) { dataPacket.dest *= 10; dataPacket.dest += Key; prevLetter = 0; } return; } } switch (Key) { case KEY_PTT: case KEY_MENU: if (gEnteringSMS == SMS_NOT_ENTERING) { if (bKeyPressed) { gEnteringSMS = SMS_ENTERING_DEST; updatePrevChar(Key); } } else if (gEnteringSMS == SMS_ENTERING_DEST) { if (bKeyPressed) { memset(dataPacket.data, 0, DataPacketDataSize); prepareDataPacket(); //dataPacket.flags = 0x80 | (gCurrentVfo->OUTPUT_POWER & 0x07); if (dataPacket.src == 665 || dataPacket.src == 664) { uint8_t out[5]; if (dataPacket.src == 665) { const uint32_t id24 = 0xFFFFFF & (dataPacket.dest >> 4); const uint8_t btn = 0x0F & (dataPacket.dest); // mask just in case // uint32_t id24 = 0x00A38C; // uint8_t btn = 0x04; // 3-byte big-endian ID out[0] = (id24 >> 16) & 0xFF; out[1] = (id24 >> 8) & 0xFF; out[2] = (id24 >> 0) & 0xFF; // first nibble redundancy copy: 0xBB if btn=0xB out[3] = (btn << 4) | 0x04; // second copy with MSB flipped (btn ^ 0x8) in the high nibble out[4] = ((btn ^ 0x8) << 4); } else { out[0] = (dataPacket.dest >> 8) & 0xFF; out[1] = dataPacket.dest & 0xFF; } BK4819_EnterTxMute(); RADIO_SetTxParameters(); uint16_t datX = BK4819_REG_30_ENABLE_VCO_CALIB | BK4819_REG_30_ENABLE_UNKNOWN | BK4819_REG_30_DISABLE_RX_LINK | BK4819_REG_30_DISABLE_AF_DAC | BK4819_REG_30_ENABLE_DISC_MODE | BK4819_REG_30_ENABLE_PLL_VCO | BK4819_REG_30_ENABLE_PA_GAIN | BK4819_REG_30_DISABLE_MIC_ADC | BK4819_REG_30_ENABLE_TX_DSP | BK4819_REG_30_DISABLE_RX_DSP; BK4819_WriteRegister(BK4819_REG_30, datX); BK4819_ToggleGpioOut(BK4819_GPIO1_PIN29_PA_ENABLE, false); SYSTEM_DelayMs(20); for (unsigned int x = 0; x < 15; x++) { for (unsigned int y = 0; y < (dataPacket.src == 665 ? 5 : 2); y++) { for (unsigned char i = 7; i < 8; i--) { if ((out[y] >> i) & 1) { // datX |= BK4819_REG_30_ENABLE_PA_GAIN; BK4819_ToggleGpioOut(BK4819_GPIO1_PIN29_PA_ENABLE, true); SYSTICK_DelayUs(400 * (dataPacket.src == 665 ? 3 : 2) - 325); BK4819_ToggleGpioOut(BK4819_GPIO1_PIN29_PA_ENABLE, false); // datX &= ~BK4819_REG_30_ENABLE_PA_GAIN; SYSTICK_DelayUs(400 * 1 - 325); } else { BK4819_ToggleGpioOut(BK4819_GPIO1_PIN29_PA_ENABLE, true); // datX |= BK4819_REG_30_ENABLE_PA_GAIN; SYSTICK_DelayUs(400 * 1 - 325); BK4819_ToggleGpioOut(BK4819_GPIO1_PIN29_PA_ENABLE, false); // datX &= ~BK4819_REG_30_ENABLE_PA_GAIN; SYSTICK_DelayUs(400 * (dataPacket.src == 665 ? 3 : 2) - 325); } } } BK4819_ToggleGpioOut(BK4819_GPIO1_PIN29_PA_ENABLE, false); SYSTEM_DelayMs((dataPacket.src == 665 ? 3 : 15)); } BK4819_ToggleGpioOut(BK4819_GPIO1_PIN29_PA_ENABLE, false); SYSTEM_DelayMs(100); BK4819_WriteRegister(BK4819_REG_30, 0xC1FE); gEnteringSMS = SMS_NOT_ENTERING; } else { gEnteringSMS = SMS_ENTERING_MESSAGE; } } return; } else if (gEnteringSMS == SMS_ENTERING_MESSAGE) { if (bKeyPressed) { if (strlen((char *) dataPacket.data)) { MSG_FSKSendData(&dataPacket); gEnteringSMS = SMS_NOT_ENTERING; } } return; } break; case KEY_UP: if (bKeyPressed) { gActiveMessage++; if (gActiveMessage > MESSAGES_COUNT) { gActiveMessage = 0; } MESSAGES_GET(); } break; case KEY_DOWN: if (bKeyPressed) { gActiveMessage--; if (gActiveMessage > MESSAGES_COUNT) { gActiveMessage = MESSAGES_COUNT - 1; } MESSAGES_GET(); } break; case KEY_EXIT: if (gEnteringSMS != SMS_NOT_ENTERING) { if (bKeyHeld) { if (bKeyPressed) { gEnteringSMS = SMS_NOT_ENTERING; dataPTR = dataPacket.data; memset(dataPacket.data, 0, DataPacketDataSize); } } else { if (bKeyPressed) { if (gEnteringSMS == SMS_ENTERING_MESSAGE) { if (dataPacket.data <= dataPTR) { *dataPTR = '\0'; if (dataPacket.data < dataPTR) { dataPTR--; } *dataPTR = '\0'; } } else if (gEnteringSMS == SMS_ENTERING_DEST) { dataPacket.dest /= 10; } } } } else { if (bKeyPressed) { gRequestDisplayScreen = DISPLAY_MAIN; } } updatePrevChar(Key); break; default: if (!bKeyHeld && bKeyPressed) gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL; break; } }