/* Include Files */ #include "KTag.h" QueueHandle_t xQueueAudio; TaskHandle_t Audio_Task_Handle; static const uint8_t START_BYTE = 0x7E; static const uint8_t VERSION_BYTE = 0xFF; static const uint8_t END_BYTE = 0xEF; // Valid volumes are 0 - 30. static const uint8_t COMMAND_SPECIFY_VOLUME = 0x06; static const uint8_t COMMAND_PAUSE = 0x0E; static const uint8_t COMMAND_PLAY_TRACK_IN_FOLDER = 0x0F; __attribute__((always_inline)) inline uint16_t CalculateChecksum(uint8_t * buffer, uint8_t length) { uint16_t checksum = 0; for (uint_fast8_t i = 0; i < length; i++) { checksum += buffer[i]; } return (0 - checksum); } static void Send_Command(uint8_t command, bool requireFeedback, uint16_t parameter) { uint8_t buffer[10]; uint16_t checksum; buffer[0] = START_BYTE; buffer[1] = VERSION_BYTE; buffer[2] = 6; // count buffer[3] = command; buffer[4] = requireFeedback; buffer[5] = (uint8_t)(parameter >> 8); buffer[6] = (uint8_t)(parameter); checksum = CalculateChecksum(&buffer[1], 6); buffer[7] = (uint8_t)(checksum >> 8); buffer[8] = (uint8_t)(checksum); buffer[9] = END_BYTE; for (uint_fast8_t i = 0; i < 10; i++) { UART_Audio_Put(buffer[i]); } } SystemKResult_T Perform_Audio_Action(AudioAction_T * action) { if (xQueueSend(xQueueAudio, action, 0) == pdTRUE) { return SYSTEMK_RESULT_SUCCESS; } else { return SYSTEMK_RESULT_QUEUE_IS_FULL; } } void Init_Audio(void) { UART_Audio_Start(); xQueueAudio = xQueueCreate(5, sizeof(AudioAction_T)); } void Audio_Task(void * pvParameters) { portBASE_TYPE xStatus; while (IsNVMInitialized() == false) { vTaskDelay(100 / portTICK_PERIOD_MS); } Send_Command(COMMAND_SPECIFY_VOLUME, false, NVM_VOLUME); while (true) { AudioAction_T action; xStatus = xQueueReceive(xQueueAudio, &action, 0); if (xStatus == pdPASS) { switch (action.ID) { case AUDIO_SET_VOLUME: { uint8_t volume = *((uint8_t *)action.Data); if (volume <= 30) { Send_Command(COMMAND_SPECIFY_VOLUME, false, volume); } } break; case AUDIO_SILENCE: Send_Command(COMMAND_PAUSE, false, 0x0000); break; case AUDIO_PLAY_STARTUP_SOUND: // Play track "001" in folder "01". Send_Command(COMMAND_PLAY_TRACK_IN_FOLDER, false, 0x0101); break; case AUDIO_PLAY_SHOT_FIRED: // Play track "002" in folder "01". Send_Command(COMMAND_PLAY_TRACK_IN_FOLDER, false, 0x0102); break; case AUDIO_PLAY_TAG_RECEIVED: // Play track "003" in folder "01". Send_Command(COMMAND_PLAY_TRACK_IN_FOLDER, false, 0x0103); break; case AUDIO_PLAY_TAGGED_OUT: // Play track "004" in folder "01". Send_Command(COMMAND_PLAY_TRACK_IN_FOLDER, false, 0x0104); break; case AUDIO_PLAY_MISFIRE: // Play track "005" in folder "01". Send_Command(COMMAND_PLAY_TRACK_IN_FOLDER, false, 0x0105); break; case AUDIO_PRONOUNCE_NUMBER_0_TO_100: { uint8_t file_index = *((uint8_t *)action.Data); if (file_index > 100) { file_index = 100; } else if (file_index == 0) { file_index = 101; } // The numbers are stored in folder "10". // 001.mp3 is "one", 100.mp3 is "one hundred", and 101.mp3 is "zero". uint16_t filenumber = 0x0A00 + file_index; Send_Command(COMMAND_PLAY_TRACK_IN_FOLDER, false, filenumber); } break; case AUDIO_PLAY_MENU_PROMPT: // Play track "006" in folder "01". Send_Command(COMMAND_PLAY_TRACK_IN_FOLDER, false, 0x0106); break; case AUDIO_PLAY_SELECTION_INDICATOR: // Play track "007" in folder "01". Send_Command(COMMAND_PLAY_TRACK_IN_FOLDER, false, 0x0107); break; case AUDIO_PLAY_HEALTH_REMAINING: // Play track "008" in folder "01". Send_Command(COMMAND_PLAY_TRACK_IN_FOLDER, false, 0x0108); break; case AUDIO_PLAY_ELECTRONIC_DANCE_MUSIC: // Play track "009" in folder "01". Send_Command(COMMAND_PLAY_TRACK_IN_FOLDER, false, 0x0109); break; default: case AUDIO_PLAY_GENERIC_ERROR: // Play track "010" in folder "01". Send_Command(COMMAND_PLAY_TRACK_IN_FOLDER, false, 0x010A); break; case AUDIO_PLAY_VOLUME_PROMPT: // Play track "011" in folder "01". Send_Command(COMMAND_PLAY_TRACK_IN_FOLDER, false, 0x010B); break; case AUDIO_PLAY_RIGHT_HANDED: // Play track "012" in folder "01". Send_Command(COMMAND_PLAY_TRACK_IN_FOLDER, false, 0x010C); break; case AUDIO_PLAY_LEFT_HANDED: // Play track "013" in folder "01". Send_Command(COMMAND_PLAY_TRACK_IN_FOLDER, false, 0x010D); break; case AUDIO_PLAY_GAME_ON: // Play track "014" in folder "01". Send_Command(COMMAND_PLAY_TRACK_IN_FOLDER, false, 0x010E); break; case AUDIO_PLAY_HARDWARE_SETTINGS_PROMPT: // Play track "015" in folder "01". Send_Command(COMMAND_PLAY_TRACK_IN_FOLDER, false, 0x010F); break; case AUDIO_PLAY_GAME_SETTINGS_PROMPT: // Play track "016" in folder "01". Send_Command(COMMAND_PLAY_TRACK_IN_FOLDER, false, 0x0110); break; case AUDIO_PLAY_BONK: // Play track "017" in folder "01". Send_Command(COMMAND_PLAY_TRACK_IN_FOLDER, false, 0x0111); break; case AUDIO_PLAY_NEAR_MISS: // Play track "018" in folder "01". Send_Command(COMMAND_PLAY_TRACK_IN_FOLDER, false, 0x0112); break; case AUDIO_PLAY_PLAYER_ID_PROMPT: // Play track "019" in folder "01". Send_Command(COMMAND_PLAY_TRACK_IN_FOLDER, false, 0x0113); break; case AUDIO_PLAY_TEAM_ID_PROMPT: // Play track "020" in folder "01". Send_Command(COMMAND_PLAY_TRACK_IN_FOLDER, false, 0x0114); break; case AUDIO_PLAY_FRIENDLY_FIRE: // Play track "021" in folder "01". Send_Command(COMMAND_PLAY_TRACK_IN_FOLDER, false, 0x0115); break; case AUDIO_PLAY_STARTING_THEME: // Play track "022" in folder "01". Send_Command(COMMAND_PLAY_TRACK_IN_FOLDER, false, 0x0116); break; case AUDIO_PLAY_BOOP: // Play track "023" in folder "01". Send_Command(COMMAND_PLAY_TRACK_IN_FOLDER, false, 0x0117); break; case AUDIO_PLAY_BEEP: // Play track "024" in folder "01". Send_Command(COMMAND_PLAY_TRACK_IN_FOLDER, false, 0x0118); break; case AUDIO_PLAY_REPROGRAMMING: // Play track "025" in folder "01". Send_Command(COMMAND_PLAY_TRACK_IN_FOLDER, false, 0x0119); break; case AUDIO_PLAY_BOMB: // Play track "026" in folder "01". Send_Command(COMMAND_PLAY_TRACK_IN_FOLDER, false, 0x011A); break; case AUDIO_PLAY_GAME_OVER: // Play track "027" in folder "01". Send_Command(COMMAND_PLAY_TRACK_IN_FOLDER, false, 0x011B); break; } if (action.Play_To_Completion == true) { do { vTaskDelay(100 / portTICK_PERIOD_MS); } while (Is_Audio_Playing() == true); KEvent_T command_received_event = {.ID = KEVENT_AUDIO_COMPLETED, .Data = (void *)action.ID}; Post_KEvent(&command_received_event); } } vTaskDelay(100 / portTICK_PERIOD_MS); } } bool Is_Audio_Playing() { bool result = false; // The signal is active low. if (Cy_GPIO_Read(Pin_Audio_Busy_PORT, Pin_Audio_Busy_NUM) == 0) { result = true; } return result; }