From 1dbff96337dc64b16e9c5413251b9fb9a4bbd2b6 Mon Sep 17 00:00:00 2001 From: Martin ROGER Date: Sun, 15 Feb 2026 18:03:48 +0100 Subject: [PATCH 1/6] Class architecture update --- include/esPod.h | 64 +++++++++++-------------------------------------- src/esPod.cpp | 49 ++++++++++++++++++++++++++----------- 2 files changed, 49 insertions(+), 64 deletions(-) diff --git a/include/esPod.h b/include/esPod.h index bb98953..601b19c 100644 --- a/include/esPod.h +++ b/include/esPod.h @@ -101,63 +101,27 @@ class esPod const uint8_t _SWrevision = 0x00; const char *_serialNumber = "AB345F7HIJK"; - // MINI metadata - // bool _accessoryNameReceived = false; - // bool _accessoryNameRequested = false; - // bool _accessoryCapabilitiesReceived = false; - // bool _accessoryCapabilitiesRequested = false; - // bool _accessoryFirmwareReceived = false; - // bool _accessoryFirmwareRequested = false; - // bool _accessoryManufReceived = false; - // bool _accessoryManufRequested = false; - // bool _accessoryModelReceived = false; - // bool _accessoryModelRequested = false; - // bool _accessoryHardwareReceived = false; - // bool _accessoryHardwareRequested = false; - // Handler functions playStatusHandler_t *_playStatusHandler = nullptr; + // Boolean flags for track change management + bool _albumNameUpdated = false; + bool _artistNameUpdated = false; + bool _trackTitleUpdated = false; + bool _trackDurationUpdated = false; + public: esPod(Stream &targetSerial); ~esPod(); void resetState(); void attachPlayControlHandler(playStatusHandler_t playHandler); - // // Processors - // void processLingo0x00(const byte *byteArray, uint32_t len); - // void processLingo0x04(const byte *byteArray, uint32_t len); - - // // Lingo 0x00 - // void L0x00_0x00_RequestIdentify(); - // void L0x00_0x02_iPodAck(byte cmdStatus, byte cmdID); - // void L0x00_0x02_iPodAck(byte cmdStatus, byte cmdID, uint32_t numField); - // void L0x00_0x04_ReturnExtendedInterfaceMode(byte extendedModeByte); - // void L0x00_0x08_ReturniPodName(); - // void L0x00_0x0A_ReturniPodSoftwareVersion(); - // void L0x00_0x0C_ReturniPodSerialNum(); - // void L0x00_0x0E_ReturniPodModelNum(); - // void L0x00_0x10_ReturnLingoProtocolVersion(byte targetLingo); - // void L0x00_0x27_GetAccessoryInfo(byte desiredInfo); - // void L0x00_0x25_RetiPodOptions(); - - // // Lingo 0x04 - // void L0x04_0x01_iPodAck(byte cmdStatus, byte cmdID); - // void L0x04_0x01_iPodAck(byte cmdStatus, byte cmdID, uint32_t numField); - // void L0x04_0x0D_ReturnIndexedPlayingTrackInfo(byte trackInfoType, char *trackInfoChars); - // void L0x04_0x0D_ReturnIndexedPlayingTrackInfo(uint32_t trackDuration_ms); - // void L0x04_0x0D_ReturnIndexedPlayingTrackInfo(byte trackInfoType, uint16_t releaseYear); - // void L0x04_0x13_ReturnProtocolVersion(); - // void L0x04_0x19_ReturnNumberCategorizedDBRecords(uint32_t categoryDBRecords); - // void L0x04_0x1B_ReturnCategorizedDatabaseRecord(uint32_t index, char *recordString); - // void L0x04_0x1D_ReturnPlayStatus(uint32_t position, uint32_t duration, byte playStatus); - // void L0x04_0x1F_ReturnCurrentPlayingTrackIndex(uint32_t trackIndex); - // void L0x04_0x21_ReturnIndexedPlayingTrackTitle(char *trackTitle); - // void L0x04_0x23_ReturnIndexedPlayingTrackArtistName(char *trackArtistName); - // void L0x04_0x25_ReturnIndexedPlayingTrackAlbumName(char *trackAlbumName); - // void L0x04_0x27_PlayStatusNotification(byte notification, uint32_t numField); - // void L0x04_0x27_PlayStatusNotification(byte notification); - // void L0x04_0x2D_ReturnShuffle(byte shuffleStatus); - // void L0x04_0x30_ReturnRepeat(byte repeatStatus); - // void L0x04_0x36_ReturnNumPlayingTracks(uint32_t numPlayingTracks); + // Wrappers for A2DP and AVRC integration + void play(); + void pause(); + void updatePlayPosition(uint32_t position); + void updateAlbumName(const char *albumName); + void updateArtistName(const char *artistName); + void updateTrackTitle(const char *trackTitle); + void updateTrackDuration(uint32_t trackDuration); }; \ No newline at end of file diff --git a/src/esPod.cpp b/src/esPod.cpp index be9b4f9..0f5fe87 100644 --- a/src/esPod.cpp +++ b/src/esPod.cpp @@ -580,6 +580,12 @@ void esPod::resetState() prevTrackDuration = 1; playPosition = 0; + // Flags for track change management + _albumNameUpdated = false; + _artistNameUpdated = false; + _trackTitleUpdated = false; + _trackDurationUpdated = false; + // Playback Engine playStatus = PB_STATE_PAUSED; playStatusNotificationState = NOTIF_OFF; @@ -594,20 +600,6 @@ void esPod::resetState() trackList[i] = 0; trackListPosition = 0; - // Mini metadata - // _accessoryCapabilitiesReceived = false; - // _accessoryCapabilitiesRequested = false; - // _accessoryFirmwareReceived = false; - // _accessoryFirmwareRequested = false; - // _accessoryHardwareReceived = false; - // _accessoryHardwareRequested = false; - // _accessoryManufReceived = false; - // _accessoryManufRequested = false; - // _accessoryModelReceived = false; - // _accessoryModelRequested = false; - // _accessoryNameReceived = false; - // _accessoryNameRequested = false; - // Reset the queues aapCommand tempCmd; @@ -641,6 +633,35 @@ void esPod::attachPlayControlHandler(playStatusHandler_t playHandler) _playStatusHandler = playHandler; ESP_LOGD(IPOD_TAG, "PlayControlHandler attached."); } + +void esPod::play() +{ +} + +void esPod::pause() +{ +} + +void esPod::updatePlayPosition(uint32_t position) +{ +} + +void esPod::updateAlbumName(const char *albumName) +{ +} + +void esPod::updateArtistName(const char *artistName) +{ +} + +void esPod::updateTrackTitle(const char *trackTitle) +{ +} + +void esPod::updateTrackDuration(uint32_t trackDuration) +{ +} + #pragma endregion //----------------------------------------------------------------------- From fad73ce23f0db6c503a44c075586b703ce37e802 Mon Sep 17 00:00:00 2001 From: Martin ROGER Date: Tue, 17 Feb 2026 18:13:09 +0100 Subject: [PATCH 2/6] Pre-wrapper deployment --- .vscode/extensions.json | 2 + include/esPod.h | 180 +++-- src/L0x00.cpp | 60 +- src/L0x03.cpp | 94 +-- src/L0x04.cpp | 122 ++-- src/esPod.cpp | 1416 +++++---------------------------------- src/main.cpp | 43 +- 7 files changed, 465 insertions(+), 1452 deletions(-) diff --git a/.vscode/extensions.json b/.vscode/extensions.json index e3c551d..4ab1483 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,4 +1,6 @@ { + // See http://go.microsoft.com/fwlink/?LinkId=827846 + // for the documentation about the extensions.json format "recommendations": [ "cschlosser.doxdocgen", "dqisme.sync-scroll", diff --git a/include/esPod.h b/include/esPod.h index 601b19c..882d647 100644 --- a/include/esPod.h +++ b/include/esPod.h @@ -6,36 +6,32 @@ #include "esPod_conf.h" #include "esPod_utils.h" -#ifndef IPOD_TAG -#define IPOD_TAG "esPod" -#endif - class esPod { - friend class L0x00; - friend class L0x03; - friend class L0x04; + friend class L0x00; // Lingo 0x00 message handlers + friend class L0x03; // Lingo 0x03 message handlers + friend class L0x04; // Lingo 0x04 message handlers public: - typedef void playStatusHandler_t(byte playControlCommand); + typedef void playStatusHandler_t(byte playControlCommand); // Type definition for the external callback to control playback FROM the espod object // State variables - bool extendedInterfaceModeActive = false; - bool disabled = true; // espod starts disabled... it means it keeps flushing the Serial until it is ready to process something + bool extendedInterfaceModeActive = false; // Indicates if the extended interface mode is accessible (Lingo 0x04 mostly) + bool disabled = true; // espod starts disabled... it means it keeps flushing the Serial until it is ready to process something // Metadata variables - char trackTitle[255] = "Title"; - char prevTrackTitle[255] = " "; - char artistName[255] = "Artist"; - char prevArtistName[255] = " "; - char albumName[255] = "Album"; - char prevAlbumName[255] = " "; - char trackGenre[255] = "Genre"; - char playList[255] = "Spotify"; - char composer[255] = "Composer"; - uint32_t trackDuration = 1; // Track duration in ms - uint32_t prevTrackDuration = 1; - uint32_t playPosition = 0; // Current playing position of the track in ms + char trackTitle[255] = "Title"; // Current track Title + char prevTrackTitle[255] = " "; // Previous track Title + char artistName[255] = "Artist"; // Current track Artist Name + char prevArtistName[255] = " "; // Previous track Artist Name + char albumName[255] = "Album"; // Current track Album Name + char prevAlbumName[255] = " "; // Previous track Album Name + char trackGenre[255] = "Genre"; // Current track Genre + char playList[255] = "Spotify"; // Current playlist (always the same) + char composer[255] = "Composer"; // Current track's composer (sometimes gets requested) + uint32_t trackDuration = 1; // Track duration in ms + uint32_t prevTrackDuration = 1; // Previous track duration in ms + uint32_t playPosition = 0; // Current playing position of the track in ms // Playback Engine byte playStatus = PB_STATE_PAUSED; // Current state of the PBEngine @@ -46,82 +42,152 @@ class esPod byte repeatStatus = 0x02; // 00 Repeat off, 01 One track, 02 All tracks // TrackList variables - uint32_t currentTrackIndex = 0; - uint32_t prevTrackIndex = TOTAL_NUM_TRACKS - 1; // Starts at the end of the tracklist - const uint32_t totalNumberTracks = TOTAL_NUM_TRACKS; - uint32_t trackList[TOTAL_NUM_TRACKS] = {0}; - uint32_t trackListPosition = 0; // Locator for the position of the track ID in the TrackList (of IDS) + uint32_t currentTrackIndex = 0; // Current internal track index + uint32_t prevTrackIndex = TOTAL_NUM_TRACKS - 1; // Previous track index, starts at the end of the tracklist + const uint32_t totalNumberTracks = TOTAL_NUM_TRACKS; // Total number of tracks. Has little influence + uint32_t trackList[TOTAL_NUM_TRACKS] = {0}; // Initial track list is filled with 0 track indexs + uint32_t trackListPosition = 0; // Locator for the position of the track ID in the TrackList (of IDs) (i.e. cursor) private: // FreeRTOS Queues - QueueHandle_t _cmdQueue; - QueueHandle_t _txQueue; - QueueHandle_t _timerQueue; + QueueHandle_t _cmdQueue; // Incoming commands queue from accessory (car) + QueueHandle_t _txQueue; // Outgoing response/commands queue from espod to car + QueueHandle_t _timerQueue; // Queue for processing "pending" commands timer callbacks (rather than in-ISR processing) // FreeRTOS tasks (and methods...) - TaskHandle_t _rxTaskHandle; - TaskHandle_t _processTaskHandle; - TaskHandle_t _txTaskHandle; - TaskHandle_t _timerTaskHandle; + TaskHandle_t _rxTaskHandle; // RX task handle (from car) + TaskHandle_t _processTaskHandle; // Command dispatcher/processor task handle + TaskHandle_t _txTaskHandle; // TX task handle (to car) + TaskHandle_t _timerTaskHandle; // Pending command timer task handle + /// @brief RX Task, sifts through the incoming serial data and compiles packets that pass the checksum and passes them to the processing Queue _cmdQueue. Also handles timeouts and can trigger state resets. + /// @param pvParameters Unused static void _rxTask(void *pvParameters); + + /// @brief Processor task retrieving from the cmdQueue and processing the commands + /// @param pvParameters static void _processTask(void *pvParameters); + + /// @brief Transmit task, retrieves from the txQueue and sends the packets over Serial at high priority but wider timing + /// @param pvParameters static void _txTask(void *pvParameters); - static void _timerTask(void *pvParameters); // Add this line + + /// @brief Low priority task to queue acks *outside* of the timer interrupt context + /// @param pvParameters + static void _timerTask(void *pvParameters); // FreeRTOS timers for delayed acks TimerHandle_t _pendingTimer_0x00; TimerHandle_t _pendingTimer_0x03; TimerHandle_t _pendingTimer_0x04; - // Callbacks for each timer + /// @brief Callback for L0x00 pending Ack timer + /// @param xTimer static void _pendingTimerCallback_0x00(TimerHandle_t xTimer); + + /// @brief Callback for L0x03 pending Ack timer + /// @param xTimer static void _pendingTimerCallback_0x03(TimerHandle_t xTimer); + + /// @brief Callback for L0x04 pending Ack timer + /// @param xTimer static void _pendingTimerCallback_0x04(TimerHandle_t xTimer); - byte _pendingCmdId_0x00; - byte _pendingCmdId_0x03; - byte _pendingCmdId_0x04; - // Serial to the listening device + byte _pendingCmdId_0x00; // Command ID that is pending in Lingo 0x00 + byte _pendingCmdId_0x03; // Command ID that is pending in Lingo 0x03 + byte _pendingCmdId_0x04; // Command ID that is pending in Lingo 0x04 + + // Serial to the car Stream &_targetSerial; - // Packet utilities + /// @brief //Calculates the checksum of a packet that starts from i=0 ->Lingo to i=len -> Checksum + /// @param byteArray Array from Lingo byte to Checksum byte + /// @param len Length of array (Lingo byte to Checksum byte) + /// @return Calculated checksum for comparison static byte _checksum(const byte *byteArray, uint32_t len); + + /// @brief Composes and sends a packet over the _targetSerial + /// @param byteArray Array to send, starting with the Lingo byte and without the checksum byte + /// @param len Length of the array to send void _sendPacket(const byte *byteArray, uint32_t len); + + /// @brief Adds a packet to the transmit queue + /// @param byteArray Array of bytes to add to the queue + /// @param len Length of data in the array void _queuePacket(const byte *byteArray, uint32_t len); + + /// @brief Adds a packet to the transmit queue, but at the front for immediate processing + /// @param byteArray Array of bytes to add to the queue + /// @param len Length of data in the array void _queuePacketToFront(const byte *byteArray, uint32_t len); + + /// @brief Processes a valid packet and calls the relevant Lingo processor + /// @param byteArray Checksum-validated packet starting at LingoID + /// @param len Length of valid data in the packet void _processPacket(const byte *byteArray, uint32_t len); - bool _rxIncomplete = false; + bool _rxIncomplete = false; // Marker in case of incomplete command sequence reception // Device metadata - const char *_name = ESPIPOD_NAME; - const uint8_t _SWMajor = 0x01; - const uint8_t _SWMinor = 0x03; - const uint8_t _SWrevision = 0x00; - const char *_serialNumber = "AB345F7HIJK"; + const char *_name = ESPIPOD_NAME; // Published esPOD name + const uint8_t _SWMajor = 0x01; // Published SW Major version + const uint8_t _SWMinor = 0x03; // Published SW Minor version + const uint8_t _SWrevision = 0x00; // Published SW revision + const char *_serialNumber = "AB345F7HIJK"; // Made-up serial number // Handler functions - playStatusHandler_t *_playStatusHandler = nullptr; + playStatusHandler_t *_playStatusHandler = nullptr; // Pointer to external callback used to let the espod instance control playback // Boolean flags for track change management - bool _albumNameUpdated = false; - bool _artistNameUpdated = false; - bool _trackTitleUpdated = false; - bool _trackDurationUpdated = false; + bool _albumNameUpdated = false; // Internal flag if the albumName has been updated. Used to send relevant notifications if necessary + bool _artistNameUpdated = false; // Internal flag if the artistName has been updated. Used to send relevant notifications if necessary + bool _trackTitleUpdated = false; // Internal flag if the trackTitle has been updated. Used to send relevant notifications if necessary + bool _trackDurationUpdated = false; // Internal flag if the trackDuration has been updated. Used to send relevant notifications if necessary + void _checkAllMetaUpdated(); public: + /// @brief Constructor for the esPod class + /// @param targetSerial (Serial) stream on which the esPod will be communicating esPod(Stream &targetSerial); + + /// @brief Destructor for the esPod class. Normally not used. ~esPod(); + + /// @brief Resets the esPod instance to a "clean" startup state void resetState(); + + /// @brief Function to attach the playback controller that allows the espod instance to perform playback operations on the audio source + /// @param playHandler Type-function of a playStatusHandler, linking the espod instance to the audio source controls void attachPlayControlHandler(playStatusHandler_t playHandler); - // Wrappers for A2DP and AVRC integration + // Useful wrappers for A2DP and AVRC integration + + /// @brief Sets the esPod instance to "PLAY" void play(); + + /// @brief Sets the esPod instance to "PAUSED" void pause(); + + /// @brief Sets the esPod instance to "STOPPED" + void stop(); + + /// @brief Updates the play position (in ms) in the instance. Some internal checks are run to debounce double updates that might happen through AVRC + /// @param position Current play position in ms void updatePlayPosition(uint32_t position); - void updateAlbumName(const char *albumName); - void updateArtistName(const char *artistName); - void updateTrackTitle(const char *trackTitle); - void updateTrackDuration(uint32_t trackDuration); + + /// @brief Checks and updates the album name in the espod instance. + /// @param incAlbumName Char array of new album name + void updateAlbumName(const char *incAlbumName); + + /// @brief Checks and updates the artist name in the espod instance. + /// @param incArtistName Char array of new artist name + void updateArtistName(const char *incArtistName); + + /// @brief Checks and udpates the track title in the espod instance. + /// @param incTrackTitle Char array of new track title + void updateTrackTitle(const char *incTrackTitle); + + /// @brief Checks and updates the track duration in the espod instance. + /// @param incTrackDuration Track duration in ms. + void updateTrackDuration(uint32_t incTrackDuration); }; \ No newline at end of file diff --git a/src/L0x00.cpp b/src/L0x00.cpp index 792faec..d24ec03 100644 --- a/src/L0x00.cpp +++ b/src/L0x00.cpp @@ -15,7 +15,7 @@ void L0x00::processLingo(esPod *esp, const byte *byteArray, uint32_t len) { case L0x00_Identify: // Deprecated command observed on Audi by @BluCobalt { - ESP_LOGI(IPOD_TAG, "CMD: 0x%02x Identify with Lingo 0x%02x", cmdID, byteArray[1]); + ESP_LOGI(__func__, "CMD: 0x%02x Identify with Lingo 0x%02x", cmdID, byteArray[1]); // switch (byteArray[1]) // { // case 0x04: @@ -29,7 +29,7 @@ void L0x00::processLingo(esPod *esp, const byte *byteArray, uint32_t len) case L0x00_RequestExtendedInterfaceMode: // Mini requests extended interface mode status { - ESP_LOGD(IPOD_TAG, "CMD: 0x%02x RequestExtendedInterfaceMode", cmdID); + ESP_LOGD(__func__, "CMD: 0x%02x RequestExtendedInterfaceMode", cmdID); if (esp->extendedInterfaceModeActive) { L0x00::_0x04_ReturnExtendedInterfaceMode(esp, 0x01); // Report that extended interface mode is active @@ -43,7 +43,7 @@ void L0x00::processLingo(esPod *esp, const byte *byteArray, uint32_t len) case L0x00_EnterExtendedInterfaceMode: // Mini forces extended interface mode { - ESP_LOGI(IPOD_TAG, "CMD: 0x%02x EnterExtendedInterfaceMode", cmdID); + ESP_LOGI(__func__, "CMD: 0x%02x EnterExtendedInterfaceMode", cmdID); esp->extendedInterfaceModeActive = true; L0x00::_0x02_iPodAck(esp, iPodAck_OK, cmdID); } @@ -51,7 +51,7 @@ void L0x00::processLingo(esPod *esp, const byte *byteArray, uint32_t len) case L0x00_ExitExtendedInterfaceMode: // Mini exits extended interface mode { - ESP_LOGI(IPOD_TAG, "CMD: 0x%02x ExitExtendedInterfaceMode", cmdID); + ESP_LOGI(__func__, "CMD: 0x%02x ExitExtendedInterfaceMode", cmdID); if (esp->extendedInterfaceModeActive) { L0x00::_0x02_iPodAck(esp, iPodAck_OK, cmdID); @@ -67,42 +67,42 @@ void L0x00::processLingo(esPod *esp, const byte *byteArray, uint32_t len) case L0x00_RequestiPodName: // Mini requests ipod name { - ESP_LOGI(IPOD_TAG, "CMD: 0x%02x RequestiPodName", cmdID); + ESP_LOGI(__func__, "CMD: 0x%02x RequestiPodName", cmdID); L0x00::_0x08_ReturniPodName(esp); } break; case L0x00_RequestiPodSoftwareVersion: // Mini requests ipod software version { - ESP_LOGI(IPOD_TAG, "CMD: 0x%02x RequestiPodSoftwareVersion", cmdID); + ESP_LOGI(__func__, "CMD: 0x%02x RequestiPodSoftwareVersion", cmdID); L0x00::_0x0A_ReturniPodSoftwareVersion(esp); } break; case L0x00_RequestiPodSerialNum: // Mini requests ipod Serial Num { - ESP_LOGI(IPOD_TAG, "CMD: 0x%02x RequestiPodSerialNum", cmdID); + ESP_LOGI(__func__, "CMD: 0x%02x RequestiPodSerialNum", cmdID); L0x00::_0x0C_ReturniPodSerialNum(esp); } break; case L0x00_RequestiPodModelNum: // Mini requests ipod Model Num { - ESP_LOGI(IPOD_TAG, "CMD: 0x%02x RequestiPodModelNum", cmdID); + ESP_LOGI(__func__, "CMD: 0x%02x RequestiPodModelNum", cmdID); L0x00::_0x0E_ReturniPodModelNum(esp); } break; case L0x00_RequestLingoProtocolVersion: // Mini requestsLingo Protocol Version { - ESP_LOGI(IPOD_TAG, "CMD: 0x%02x RequestLingoProtocolVersion for Lingo 0x%02x", cmdID, byteArray[1]); + ESP_LOGI(__func__, "CMD: 0x%02x RequestLingoProtocolVersion for Lingo 0x%02x", cmdID, byteArray[1]); L0x00::_0x10_ReturnLingoProtocolVersion(esp, byteArray[1]); } break; case L0x00_IdentifyDeviceLingoes: // Mini identifies its lingoes, used as an ice-breaker { - ESP_LOGI(IPOD_TAG, "CMD: 0x%02x IdentifyDeviceLingoes : L 0x%02x - Opt 0x%02x - ID 0x%02x", cmdID, byteArray[1], byteArray[2], byteArray[3]); + ESP_LOGI(__func__, "CMD: 0x%02x IdentifyDeviceLingoes : L 0x%02x - Opt 0x%02x - ID 0x%02x", cmdID, byteArray[1], byteArray[2], byteArray[3]); L0x00::_0x02_iPodAck(esp, iPodAck_OK, cmdID); // Acknowledge, start capabilities pingpong // A bit spam-ish ? L0x00::_0x27_GetAccessoryInfo(esp, 0x00); // Immediately request general capabilities @@ -116,38 +116,38 @@ void L0x00::processLingo(esPod *esp, const byte *byteArray, uint32_t len) case L0x00_GetiPodOptions: // Mini requests iPod options { - ESP_LOGI(IPOD_TAG, "CMD: 0x%02x GetiPodOptions", cmdID); + ESP_LOGI(__func__, "CMD: 0x%02x GetiPodOptions", cmdID); // There might be some trickery triggered there with further options enquiries per Lingo L0x00::_0x25_RetiPodOptions(esp, iPodOptions); } case L0x00_RetAccessoryInfo: // Mini returns info after L0x00::_0x27 { - ESP_LOGI(IPOD_TAG, "CMD: 0x%02x RetAccessoryInfo: 0x%02x", cmdID, byteArray[1]); + ESP_LOGI(__func__, "CMD: 0x%02x RetAccessoryInfo: 0x%02x", cmdID, byteArray[1]); switch (byteArray[1]) // Ping-pong the next request based on the current response { case 0x00: - ESP_LOGI(IPOD_TAG, "\tAccessory Capabilities : 0x%02x", byteArray[2]); + ESP_LOGI(__func__, "\tAccessory Capabilities : 0x%02x", byteArray[2]); break; case 0x01: - ESP_LOGI(IPOD_TAG, "\tAccessory Name : %s", &byteArray[2]); + ESP_LOGI(__func__, "\tAccessory Name : %s", &byteArray[2]); break; case 0x04: - ESP_LOGI(IPOD_TAG, "\tAccessory Firmware : %d.%d.%d", byteArray[2], byteArray[3], byteArray[4]); + ESP_LOGI(__func__, "\tAccessory Firmware : %d.%d.%d", byteArray[2], byteArray[3], byteArray[4]); break; case 0x05: - ESP_LOGI(IPOD_TAG, "\tAccessory Hardware : %d.%d.%d", byteArray[2], byteArray[3], byteArray[4]); + ESP_LOGI(__func__, "\tAccessory Hardware : %d.%d.%d", byteArray[2], byteArray[3], byteArray[4]); break; case 0x06: - ESP_LOGI(IPOD_TAG, "\tAccessory Manufacturer : %s", &byteArray[2]); + ESP_LOGI(__func__, "\tAccessory Manufacturer : %s", &byteArray[2]); break; case 0x07: - ESP_LOGI(IPOD_TAG, "\tAccessory Model : %s", &byteArray[2]); + ESP_LOGI(__func__, "\tAccessory Model : %s", &byteArray[2]); break; default: @@ -159,7 +159,7 @@ void L0x00::processLingo(esPod *esp, const byte *byteArray, uint32_t len) default: // In case the command is not known { - ESP_LOGW(IPOD_TAG, "CMD 0x%02x not recognized.", cmdID); + ESP_LOGW(__func__, "CMD 0x%02x not recognized.", cmdID); L0x00::_0x02_iPodAck(esp, iPodAck_CmdFailed, cmdID); } break; @@ -170,7 +170,7 @@ void L0x00::processLingo(esPod *esp, const byte *byteArray, uint32_t len) /// @param esp Pointer to the esPod instance void L0x00::_0x00_RequestIdentify(esPod *esp) { - ESP_LOGI(IPOD_TAG, "iPod: RequestIdentify"); + ESP_LOGI(__func__, "iPod: RequestIdentify"); const byte txPacket[] = { 0x00, 0x00}; @@ -183,7 +183,7 @@ void L0x00::_0x00_RequestIdentify(esPod *esp) /// @param cmdID ID (single byte) of the Lingo 0x00 command replied to void L0x00::_0x02_iPodAck(esPod *esp, IPOD_ACK_CODE ackCode, byte cmdID) { - ESP_LOGI(IPOD_TAG, "Ack 0x%02x to command 0x%02x", ackCode, cmdID); + ESP_LOGI(__func__, "Ack 0x%02x to command 0x%02x", ackCode, cmdID); // Queue the packet const byte txPacket[] = { 0x00, @@ -208,7 +208,7 @@ void L0x00::_0x02_iPodAck(esPod *esp, IPOD_ACK_CODE ackCode, byte cmdID) /// @param numField Pending delay in milliseconds void L0x00::_0x02_iPodAck(esPod *esp, IPOD_ACK_CODE ackCode, byte cmdID, uint32_t numField) { - ESP_LOGI(IPOD_TAG, "Ack 0x%02x to command 0x%02x Numfield: %d", ackCode, cmdID, numField); + ESP_LOGI(__func__, "Ack 0x%02x to command 0x%02x Numfield: %d", ackCode, cmdID, numField); const byte txPacket[20] = { 0x00, 0x02, @@ -226,7 +226,7 @@ void L0x00::_0x02_iPodAck(esPod *esp, IPOD_ACK_CODE ackCode, byte cmdID, uint32_ /// @param extendedModeByte Direct value of the extendedInterfaceMode boolean void L0x00::_0x04_ReturnExtendedInterfaceMode(esPod *esp, byte extendedModeByte) { - ESP_LOGD(IPOD_TAG, "Extended Interface mode: 0x%02x", extendedModeByte); + ESP_LOGD(__func__, "Extended Interface mode: 0x%02x", extendedModeByte); const byte txPacket[] = { 0x00, 0x04, @@ -238,7 +238,7 @@ void L0x00::_0x04_ReturnExtendedInterfaceMode(esPod *esp, byte extendedModeByte) /// @param esp Pointer to the esPod instance void L0x00::_0x08_ReturniPodName(esPod *esp) { - ESP_LOGI(IPOD_TAG, "Name: %s", esp->_name); + ESP_LOGI(__func__, "Name: %s", esp->_name); byte txPacket[255] = {// Prealloc to len = FF 0x00, 0x08}; @@ -250,7 +250,7 @@ void L0x00::_0x08_ReturniPodName(esPod *esp) /// @param esp Pointer to the esPod instance void L0x00::_0x0A_ReturniPodSoftwareVersion(esPod *esp) { - ESP_LOGI(IPOD_TAG, "SW version: %d.%d.%d", esp->_SWMajor, esp->_SWMinor, esp->_SWrevision); + ESP_LOGI(__func__, "SW version: %d.%d.%d", esp->_SWMajor, esp->_SWMinor, esp->_SWrevision); byte txPacket[] = { 0x00, 0x0A, @@ -264,7 +264,7 @@ void L0x00::_0x0A_ReturniPodSoftwareVersion(esPod *esp) /// @param esp Pointer to the esPod instance void L0x00::_0x0C_ReturniPodSerialNum(esPod *esp) { - ESP_LOGI(IPOD_TAG, "Serial number: %s", esp->_serialNumber); + ESP_LOGI(__func__, "Serial number: %s", esp->_serialNumber); byte txPacket[255] = {// Prealloc to len = FF 0x00, 0x0C}; @@ -276,7 +276,7 @@ void L0x00::_0x0C_ReturniPodSerialNum(esPod *esp) /// @param esp Pointer to the esPod instance void L0x00::_0x0E_ReturniPodModelNum(esPod *esp) { - ESP_LOGI(IPOD_TAG, "Model number : PA146FD 720901"); + ESP_LOGI(__func__, "Model number : PA146FD 720901"); byte txPacket[] = { 0x00, 0x0E, @@ -308,7 +308,7 @@ void L0x00::_0x10_ReturnLingoProtocolVersion(esPod *esp, byte targetLingo) txPacket[4] = 0x00; break; } - ESP_LOGI(IPOD_TAG, "Lingo 0x%02x protocol version: 1.%d", targetLingo, txPacket[4]); + ESP_LOGI(__func__, "Lingo 0x%02x protocol version: 1.%d", targetLingo, txPacket[4]); esp->_queuePacket(txPacket, sizeof(txPacket)); } @@ -316,7 +316,7 @@ void L0x00::_0x10_ReturnLingoProtocolVersion(esPod *esp, byte targetLingo) /// @param esp Pointer to the esPod instance void L0x00::_0x25_RetiPodOptions(esPod *esp, uint64_t optBitField) { - ESP_LOGI(IPOD_TAG, "Returning iPod Options"); + ESP_LOGI(__func__, "Returning iPod Options"); byte txPacket[] = { 0x00, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; @@ -329,7 +329,7 @@ void L0x00::_0x25_RetiPodOptions(esPod *esp, uint64_t optBitField) /// @param desiredInfo Hex code for the type of information that is desired void L0x00::_0x27_GetAccessoryInfo(esPod *esp, byte desiredInfo) { - ESP_LOGI(IPOD_TAG, "Req'd info type: 0x%02x", desiredInfo); + ESP_LOGI(__func__, "Req'd info type: 0x%02x", desiredInfo); byte txPacket[] = { 0x00, 0x27, desiredInfo}; diff --git a/src/L0x03.cpp b/src/L0x03.cpp index b3ea9fd..415cd9b 100644 --- a/src/L0x03.cpp +++ b/src/L0x03.cpp @@ -11,7 +11,7 @@ void L0x03::processLingo(esPod *esp, const byte *byteArray, uint32_t len) { case L0x03_GetCurrentEQProfileIndex: { - ESP_LOGI(IPOD_TAG, "CMD: 0x%02x GetCurrentEQProfileIndex", cmdID); + ESP_LOGI(__func__, "CMD: 0x%02x GetCurrentEQProfileIndex", cmdID); L0x03::_0x02_RetCurrentEQProfileIndex(esp); } break; @@ -19,28 +19,28 @@ void L0x03::processLingo(esPod *esp, const byte *byteArray, uint32_t len) case L0x03_SetCurrentEQProfileIndex: { currentEQProfileIndex = swap_endian(*((uint32_t *)&byteArray[1])); - ESP_LOGI(IPOD_TAG, "CMD: 0x%02x SetCurrentEQProfileIndex 0x%02x", cmdID, currentEQProfileIndex); + ESP_LOGI(__func__, "CMD: 0x%02x SetCurrentEQProfileIndex 0x%02x", cmdID, currentEQProfileIndex); L0x03::_0x00_iPodAck(esp, iPodAck_OK, cmdID); } break; case L0x03_GetNumEQProfiles: { - ESP_LOGI(IPOD_TAG, "CMD: 0x%02x GetNumEQProfiles", cmdID); + ESP_LOGI(__func__, "CMD: 0x%02x GetNumEQProfiles", cmdID); L0x03::_0x05_RetNumEQProfiles(esp); } break; case L0x03_GetIndexedEQProfileName: { - ESP_LOGI(IPOD_TAG, "CMD: 0x%02x GetIndexedEQProfileName", cmdID); + ESP_LOGI(__func__, "CMD: 0x%02x GetIndexedEQProfileName", cmdID); L0x03::_0x07_RetIndexedEQProfileName(esp); } break; case L0x03_SetRemoteEventNotification: { - ESP_LOGI(IPOD_TAG, "CMD: 0x%02x SetRemoteEventNotification", cmdID); + ESP_LOGI(__func__, "CMD: 0x%02x SetRemoteEventNotification", cmdID); L0x03::_0x00_iPodAck(esp, iPodAck_OK, cmdID); // Not really implemented, should not be used L0x03::_0x09_RemoteEventNotification(esp); @@ -49,7 +49,7 @@ void L0x03::processLingo(esPod *esp, const byte *byteArray, uint32_t len) case L0x03_GetRemoteEventStatus: { - ESP_LOGI(IPOD_TAG, "CMD: 0x%02x GetRemoteEventStatus", cmdID); + ESP_LOGI(__func__, "CMD: 0x%02x GetRemoteEventStatus", cmdID); // Not implemented L0x03::_0x0B_RetRemoteEventStatus(esp, 0); } @@ -57,7 +57,7 @@ void L0x03::processLingo(esPod *esp, const byte *byteArray, uint32_t len) case L0x03_GetiPodStateInfo: { - ESP_LOGI(IPOD_TAG, "CMD: 0x%02x GetiPodStateInfo", cmdID); + ESP_LOGI(__func__, "CMD: 0x%02x GetiPodStateInfo", cmdID); // Not implemented L0x03::_0x0D_RetiPodStateInfo(esp); } @@ -65,7 +65,7 @@ void L0x03::processLingo(esPod *esp, const byte *byteArray, uint32_t len) case L0x03_SetiPodStateInfo: { - ESP_LOGI(IPOD_TAG, "CMD: 0x%02x SetiPodStateInfo", cmdID); + ESP_LOGI(__func__, "CMD: 0x%02x SetiPodStateInfo", cmdID); // Not implemented L0x03::_0x00_iPodAck(esp, iPodAck_OK, cmdID); } @@ -73,7 +73,7 @@ void L0x03::processLingo(esPod *esp, const byte *byteArray, uint32_t len) case L0x03_GetPlayStatus: { - ESP_LOGI(IPOD_TAG, "CMD: 0x%02x GetPlayStatus", cmdID); + ESP_LOGI(__func__, "CMD: 0x%02x GetPlayStatus", cmdID); L0x03::_0x10_RetPlayStatus(esp, esp->playStatus, esp->currentTrackIndex, esp->trackDuration, esp->playPosition); } break; @@ -81,7 +81,7 @@ void L0x03::processLingo(esPod *esp, const byte *byteArray, uint32_t len) case L0x03_SetCurrentPlayingTrack: { tempTrackIndex = swap_endian(*((uint32_t *)&byteArray[1])); - ESP_LOGI(IPOD_TAG, "CMD: 0x%02x SetCurrentPlayingTrack index %d", cmdID, tempTrackIndex); + ESP_LOGI(__func__, "CMD: 0x%02x SetCurrentPlayingTrack index %d", cmdID, tempTrackIndex); if (esp->playStatus != PB_STATE_PLAYING) { esp->playStatus = PB_STATE_PLAYING; // Playing status forced @@ -106,7 +106,7 @@ void L0x03::processLingo(esPod *esp, const byte *byteArray, uint32_t len) // Engage the pending ACK for expected metadata esp->trackChangeAckPending = cmdID; esp->trackChangeTimestamp = millis(); - ESP_LOGD(IPOD_TAG, "Prev. index %d New index %d Tracklist pos. %d Pending Meta %d Timestamp: %d --> PREV ", esp->prevTrackIndex, esp->currentTrackIndex, esp->trackListPosition, (esp->trackChangeAckPending > 0x00), esp->trackChangeTimestamp); + ESP_LOGD(__func__, "Prev. index %d New index %d Tracklist pos. %d Pending Meta %d Timestamp: %d --> PREV ", esp->prevTrackIndex, esp->currentTrackIndex, esp->trackListPosition, (esp->trackChangeAckPending > 0x00), esp->trackChangeTimestamp); L0x03::_0x00_iPodAck(esp, iPodAck_CmdPending, cmdID, TRACK_CHANGE_TIMEOUT); // Fire the A2DP when ready @@ -115,7 +115,7 @@ void L0x03::processLingo(esPod *esp, const byte *byteArray, uint32_t len) } else if (tempTrackIndex == esp->currentTrackIndex) // Somehow reselecting the current track { - ESP_LOGD(IPOD_TAG, "Selected same track as current: %d", tempTrackIndex); + ESP_LOGD(__func__, "Selected same track as current: %d", tempTrackIndex); L0x03::_0x00_iPodAck(esp, iPodAck_OK, cmdID); // Fire the A2DP when ready @@ -139,7 +139,7 @@ void L0x03::processLingo(esPod *esp, const byte *byteArray, uint32_t len) // Engage the pending ACK for expected metadata esp->trackChangeAckPending = cmdID; esp->trackChangeTimestamp = millis(); - ESP_LOGD(IPOD_TAG, "Prev. index %d New index %d Tracklist pos. %d Pending Meta %d Timestamp: %d --> NEXT ", esp->prevTrackIndex, esp->currentTrackIndex, esp->trackListPosition, (esp->trackChangeAckPending > 0x00), esp->trackChangeTimestamp); + ESP_LOGD(__func__, "Prev. index %d New index %d Tracklist pos. %d Pending Meta %d Timestamp: %d --> NEXT ", esp->prevTrackIndex, esp->currentTrackIndex, esp->trackListPosition, (esp->trackChangeAckPending > 0x00), esp->trackChangeTimestamp); L0x03::_0x00_iPodAck(esp, iPodAck_CmdPending, cmdID, TRACK_CHANGE_TIMEOUT); // Fire the A2DP when ready @@ -155,7 +155,7 @@ void L0x03::processLingo(esPod *esp, const byte *byteArray, uint32_t len) switch (byteArray[1]) // Switch on the type of track info requested (careful with overloads) { case 0x00: // General track Capabilities and Information - ESP_LOGI(IPOD_TAG, "CMD 0x%02x GetIndexedPlayingTrackInfo 0x%02x for index %d (previous %d) : Duration", cmdID, byteArray[1], tempTrackIndex, esp->prevTrackIndex); + ESP_LOGI(__func__, "CMD 0x%02x GetIndexedPlayingTrackInfo 0x%02x for index %d (previous %d) : Duration", cmdID, byteArray[1], tempTrackIndex, esp->prevTrackIndex); if (tempTrackIndex == esp->prevTrackIndex) { L0x03::_0x13_RetIndexedPlayingTrackInfo(esp, (uint32_t)esp->prevTrackDuration); @@ -167,7 +167,7 @@ void L0x03::processLingo(esPod *esp, const byte *byteArray, uint32_t len) break; case 0x02: // Artist Name - ESP_LOGI(IPOD_TAG, "CMD 0x%02x GetIndexedPlayingTrackInfo 0x%02x for index %d (previous %d) : Artist", cmdID, byteArray[1], tempTrackIndex, esp->prevTrackIndex); + ESP_LOGI(__func__, "CMD 0x%02x GetIndexedPlayingTrackInfo 0x%02x for index %d (previous %d) : Artist", cmdID, byteArray[1], tempTrackIndex, esp->prevTrackIndex); if (tempTrackIndex == esp->prevTrackIndex) { L0x03::_0x13_RetIndexedPlayingTrackInfo(esp, byteArray[1], esp->prevArtistName); @@ -179,7 +179,7 @@ void L0x03::processLingo(esPod *esp, const byte *byteArray, uint32_t len) break; case 0x03: // Album Name - ESP_LOGI(IPOD_TAG, "CMD 0x%02x GetIndexedPlayingTrackInfo 0x%02x for index %d (previous %d) : Album", cmdID, byteArray[1], tempTrackIndex, esp->prevTrackIndex); + ESP_LOGI(__func__, "CMD 0x%02x GetIndexedPlayingTrackInfo 0x%02x for index %d (previous %d) : Album", cmdID, byteArray[1], tempTrackIndex, esp->prevTrackIndex); if (tempTrackIndex == esp->prevTrackIndex) { L0x03::_0x13_RetIndexedPlayingTrackInfo(esp, byteArray[1], esp->prevAlbumName); @@ -191,11 +191,11 @@ void L0x03::processLingo(esPod *esp, const byte *byteArray, uint32_t len) break; case 0x04: // Track Genre - ESP_LOGI(IPOD_TAG, "CMD 0x%02x GetIndexedPlayingTrackInfo 0x%02x for index %d (previous %d) : Genre", cmdID, byteArray[1], tempTrackIndex, esp->prevTrackIndex); + ESP_LOGI(__func__, "CMD 0x%02x GetIndexedPlayingTrackInfo 0x%02x for index %d (previous %d) : Genre", cmdID, byteArray[1], tempTrackIndex, esp->prevTrackIndex); L0x03::_0x13_RetIndexedPlayingTrackInfo(esp, byteArray[1], esp->trackGenre); break; case 0x05: // Track Title - ESP_LOGI(IPOD_TAG, "CMD 0x%02x GetIndexedPlayingTrackInfo 0x%02x for index %d (previous %d) : Title", cmdID, byteArray[1], tempTrackIndex, esp->prevTrackIndex); + ESP_LOGI(__func__, "CMD 0x%02x GetIndexedPlayingTrackInfo 0x%02x for index %d (previous %d) : Title", cmdID, byteArray[1], tempTrackIndex, esp->prevTrackIndex); if (tempTrackIndex == esp->prevTrackIndex) { L0x03::_0x13_RetIndexedPlayingTrackInfo(esp, byteArray[1], esp->prevTrackTitle); @@ -206,11 +206,11 @@ void L0x03::processLingo(esPod *esp, const byte *byteArray, uint32_t len) } break; case 0x06: // Track Composer - ESP_LOGI(IPOD_TAG, "CMD 0x%042 GetIndexedPlayingTrackInfo 0x%02x for index %d (previous %d) : Composer", cmdID, byteArray[1], tempTrackIndex, esp->prevTrackIndex); + ESP_LOGI(__func__, "CMD 0x%042 GetIndexedPlayingTrackInfo 0x%02x for index %d (previous %d) : Composer", cmdID, byteArray[1], tempTrackIndex, esp->prevTrackIndex); L0x03::_0x13_RetIndexedPlayingTrackInfo(esp, byteArray[1], esp->composer); break; default: // In case the request is beyond the track capabilities - ESP_LOGW(IPOD_TAG, "CMD 0x%02x GetIndexedPlayingTrackInfo 0x%02x for index %d (previous %d) : Type not recognised!", cmdID, byteArray[1], tempTrackIndex, esp->prevTrackIndex); + ESP_LOGW(__func__, "CMD 0x%02x GetIndexedPlayingTrackInfo 0x%02x for index %d (previous %d) : Type not recognised!", cmdID, byteArray[1], tempTrackIndex, esp->prevTrackIndex); L0x03::_0x00_iPodAck(esp, iPodAck_BadParam, cmdID); break; } @@ -219,70 +219,70 @@ void L0x03::processLingo(esPod *esp, const byte *byteArray, uint32_t len) case L0x03_GetNumPlayingTracks: { - ESP_LOGI(IPOD_TAG, "CMD: 0x%02x GetNumPlayingTracks", cmdID); + ESP_LOGI(__func__, "CMD: 0x%02x GetNumPlayingTracks", cmdID); L0x03::_0x15_RetNumPlayingTracks(esp, TOTAL_NUM_TRACKS); } break; case L0x03_GetArtworkFormats: { - ESP_LOGI(IPOD_TAG, "CMD: 0x%02x GetArtworkFormats", cmdID); + ESP_LOGI(__func__, "CMD: 0x%02x GetArtworkFormats", cmdID); L0x03::_0x17_RetArtworkFormats(esp); } break; case L0x03_GetTrackArtworkData: { - ESP_LOGI(IPOD_TAG, "CMD: 0x%02x GetTrackArtworkData", cmdID); + ESP_LOGI(__func__, "CMD: 0x%02x GetTrackArtworkData", cmdID); L0x03::_0x19_RetTrackArtworkData(esp); } break; case L0x03_GetPowerBatteryState: { - ESP_LOGI(IPOD_TAG, "CMD: 0x%02x GetPowerBatteryState", cmdID); + ESP_LOGI(__func__, "CMD: 0x%02x GetPowerBatteryState", cmdID); L0x03::_0x1B_RetPowerBatteryState(esp, 0x05); } break; case L0x03_GetSoundCheckState: { - ESP_LOGI(IPOD_TAG, "CMD: 0x%02x GetSoundCheckState", cmdID); + ESP_LOGI(__func__, "CMD: 0x%02x GetSoundCheckState", cmdID); L0x03::_0x1D_RetSoundCheckState(esp, 0x00); } break; case L0x03_SetSoundCheckState: { - ESP_LOGI(IPOD_TAG, "CMD: 0x%02x SetSoundCheckState", cmdID); + ESP_LOGI(__func__, "CMD: 0x%02x SetSoundCheckState", cmdID); L0x03::_0x00_iPodAck(esp, iPodAck_OK, cmdID); } break; case L0x03_GetTrackArtworkTimes: { - ESP_LOGI(IPOD_TAG, "CMD: 0x%02x GetTrackArtworkTimes", cmdID); + ESP_LOGI(__func__, "CMD: 0x%02x GetTrackArtworkTimes", cmdID); L0x03::_0x20_RetTrackArtworkTimes(esp); } break; case L0x03_CreateGeniusPlaylist: { - ESP_LOGI(IPOD_TAG, "CMD: 0x%02x CreateGeniusPlaylist", cmdID); + ESP_LOGI(__func__, "CMD: 0x%02x CreateGeniusPlaylist", cmdID); L0x03::_0x00_iPodAck(esp, iPodAck_SelNotGenius, cmdID); } break; case L0x03_IsGeniusAvailableForTrack: { - ESP_LOGI(IPOD_TAG, "CMD: 0x%02x IsGeniusAvailableForTrack", cmdID); + ESP_LOGI(__func__, "CMD: 0x%02x IsGeniusAvailableForTrack", cmdID); L0x03::_0x00_iPodAck(esp, iPodAck_SelNotGenius, cmdID); } break; default: { - ESP_LOGW(IPOD_TAG, "CMD 0x%02x not recognized.", cmdID); + ESP_LOGW(__func__, "CMD 0x%02x not recognized.", cmdID); L0x03::_0x00_iPodAck(esp, iPodAck_CmdFailed, cmdID); } break; @@ -291,7 +291,7 @@ void L0x03::processLingo(esPod *esp, const byte *byteArray, uint32_t len) void L0x03::_0x00_iPodAck(esPod *esp, IPOD_ACK_CODE ackCode, byte cmdID) { - ESP_LOGI(IPOD_TAG, "Ack 0x%02x to command 0x%02x", ackCode, cmdID); + ESP_LOGI(__func__, "Ack 0x%02x to command 0x%02x", ackCode, cmdID); const byte txPacket[] = { 0x03, @@ -311,7 +311,7 @@ void L0x03::_0x00_iPodAck(esPod *esp, IPOD_ACK_CODE ackCode, byte cmdID) void L0x03::_0x00_iPodAck(esPod *esp, IPOD_ACK_CODE ackCode, byte cmdID, uint32_t numField) { - ESP_LOGI(IPOD_TAG, "Ack 0x%02x to command 0x%02x Numfield: %d", ackCode, cmdID, numField); + ESP_LOGI(__func__, "Ack 0x%02x to command 0x%02x Numfield: %d", ackCode, cmdID, numField); const byte txPacket[8] = { 0x03, 0x00, @@ -326,7 +326,7 @@ void L0x03::_0x00_iPodAck(esPod *esp, IPOD_ACK_CODE ackCode, byte cmdID, uint32_ void L0x03::_0x02_RetCurrentEQProfileIndex(esPod *esp) { - ESP_LOGI(IPOD_TAG, "Return EQ Profile Index 0x00 0x00 0x00 0x00"); + ESP_LOGI(__func__, "Return EQ Profile Index 0x00 0x00 0x00 0x00"); const byte txPacket[] = { 0x03, @@ -337,7 +337,7 @@ void L0x03::_0x02_RetCurrentEQProfileIndex(esPod *esp) void L0x03::_0x05_RetNumEQProfiles(esPod *esp) { - ESP_LOGI(IPOD_TAG, "Return Num Profiles : 1"); + ESP_LOGI(__func__, "Return Num Profiles : 1"); const byte txPacket[] = { 0x03, @@ -350,7 +350,7 @@ void L0x03::_0x05_RetNumEQProfiles(esPod *esp) void L0x03::_0x07_RetIndexedEQProfileName(esPod *esp) { const char *EQProfileName = "Base EQ"; - ESP_LOGI(IPOD_TAG, "Return EQ name : %s", EQProfileName); + ESP_LOGI(__func__, "Return EQ name : %s", EQProfileName); byte txPacket[255] = { 0x03, 0x07}; @@ -360,22 +360,22 @@ void L0x03::_0x07_RetIndexedEQProfileName(esPod *esp) void L0x03::_0x09_RemoteEventNotification(esPod *esp) { - ESP_LOGW(IPOD_TAG, "RemoteEventNotificiation not implemented"); + ESP_LOGW(__func__, "RemoteEventNotificiation not implemented"); } void L0x03::_0x0B_RetRemoteEventStatus(esPod *esp, uint32_t remEventStatus) { - ESP_LOGW(IPOD_TAG, "RetRemoveEventStatus not implemented"); + ESP_LOGW(__func__, "RetRemoveEventStatus not implemented"); } void L0x03::_0x0D_RetiPodStateInfo(esPod *esp) { - ESP_LOGW(IPOD_TAG, "RetiPodStateInfo not implemented"); + ESP_LOGW(__func__, "RetiPodStateInfo not implemented"); } void L0x03::_0x10_RetPlayStatus(esPod *esp, byte playState, uint32_t trackIndex, uint32_t trackTotMs, uint32_t trackPosMs) { - ESP_LOGI(IPOD_TAG, "Play status 0x%02x of index %d at pos. %d / %d ms", playState, trackIndex, trackPosMs, trackTotMs); + ESP_LOGI(__func__, "Play status 0x%02x of index %d at pos. %d / %d ms", playState, trackIndex, trackPosMs, trackTotMs); byte txPacket[] = { 0x03, 0x10, @@ -391,7 +391,7 @@ void L0x03::_0x10_RetPlayStatus(esPod *esp, byte playState, uint32_t trackIndex, void L0x03::_0x13_RetIndexedPlayingTrackInfo(esPod *esp, byte trackInfoType, char *trackInfoChars) { - ESP_LOGI(IPOD_TAG, "Req'd track info type: 0x%02x", trackInfoType); + ESP_LOGI(__func__, "Req'd track info type: 0x%02x", trackInfoType); byte txPacket[255] = { 0x03, 0x13, @@ -402,7 +402,7 @@ void L0x03::_0x13_RetIndexedPlayingTrackInfo(esPod *esp, byte trackInfoType, cha void L0x03::_0x13_RetIndexedPlayingTrackInfo(esPod *esp, uint32_t trackDuration_ms) { - ESP_LOGI(IPOD_TAG, "Track duration: %d", trackDuration_ms); + ESP_LOGI(__func__, "Track duration: %d", trackDuration_ms); byte txPacket[13] = { 0x03, 0x13, @@ -417,7 +417,7 @@ void L0x03::_0x13_RetIndexedPlayingTrackInfo(esPod *esp, uint32_t trackDuration_ void L0x03::_0x15_RetNumPlayingTracks(esPod *esp, uint32_t numPlayingTracks) { - ESP_LOGI(IPOD_TAG, "Playing tracks: %d", numPlayingTracks); + ESP_LOGI(__func__, "Playing tracks: %d", numPlayingTracks); byte txPacket[] = { 0x03, 0x15, @@ -428,17 +428,17 @@ void L0x03::_0x15_RetNumPlayingTracks(esPod *esp, uint32_t numPlayingTracks) void L0x03::_0x17_RetArtworkFormats(esPod *esp) { - ESP_LOGW(IPOD_TAG, "RetArtworkFormats not implemented"); + ESP_LOGW(__func__, "RetArtworkFormats not implemented"); } void L0x03::_0x19_RetTrackArtworkData(esPod *esp) { - ESP_LOGW(IPOD_TAG, "RetTrackArtworkData not implemented"); + ESP_LOGW(__func__, "RetTrackArtworkData not implemented"); } void L0x03::_0x1B_RetPowerBatteryState(esPod *esp, byte powerBatteryState) { - ESP_LOGI(IPOD_TAG, "RetPowerBatteryState 0x%02x", powerBatteryState); + ESP_LOGI(__func__, "RetPowerBatteryState 0x%02x", powerBatteryState); /* 0x00 -> Internal battery power, low power 0x01 -> Internal battery power @@ -472,7 +472,7 @@ void L0x03::_0x1B_RetPowerBatteryState(esPod *esp, byte powerBatteryState) void L0x03::_0x1D_RetSoundCheckState(esPod *esp, byte soundCheckState) { // Might need to introduce and internal variable for the sound check state here - ESP_LOGI(IPOD_TAG, "RetSoundCheckState 0x%02x", soundCheckState); + ESP_LOGI(__func__, "RetSoundCheckState 0x%02x", soundCheckState); byte txPacket[] = { 0x03, 0x1D, @@ -482,5 +482,5 @@ void L0x03::_0x1D_RetSoundCheckState(esPod *esp, byte soundCheckState) void L0x03::_0x20_RetTrackArtworkTimes(esPod *esp) { - ESP_LOGW(IPOD_TAG, "RetTrackArtworkTimes not implemented"); + ESP_LOGW(__func__, "RetTrackArtworkTimes not implemented"); } diff --git a/src/L0x04.cpp b/src/L0x04.cpp index 4b037ab..81b9632 100644 --- a/src/L0x04.cpp +++ b/src/L0x04.cpp @@ -16,7 +16,7 @@ void L0x04::processLingo(esPod *esp, const byte *byteArray, uint32_t len) if (!esp->extendedInterfaceModeActive) { // Complain if not in extended interface mode - ESP_LOGW(IPOD_TAG, "CMD 0x%04x not executed : Not in extendedInterfaceMode!", cmdID); + ESP_LOGW(__func__, "CMD 0x%04x not executed : Not in extendedInterfaceMode!", cmdID); L0x04::_0x01_iPodAck(esp, iPodAck_BadParam, cmdID); } // Good to go if in Extended Interface mode @@ -30,7 +30,7 @@ void L0x04::processLingo(esPod *esp, const byte *byteArray, uint32_t len) switch (byteArray[2]) // Switch on the type of track info requested (careful with overloads) { case 0x00: // General track Capabilities and Information - ESP_LOGI(IPOD_TAG, "CMD 0x%04x GetIndexedPlayingTrackInfo 0x%02x for index %d (previous %d) : Duration", cmdID, byteArray[2], tempTrackIndex, esp->prevTrackIndex); + ESP_LOGI(__func__, "CMD 0x%04x GetIndexedPlayingTrackInfo 0x%02x for index %d (previous %d) : Duration", cmdID, byteArray[2], tempTrackIndex, esp->prevTrackIndex); if (tempTrackIndex == esp->prevTrackIndex) { L0x04::_0x0D_ReturnIndexedPlayingTrackInfo(esp, (uint32_t)esp->prevTrackDuration); @@ -41,11 +41,11 @@ void L0x04::processLingo(esPod *esp, const byte *byteArray, uint32_t len) } break; case 0x02: // Track Release Date (fictional) - ESP_LOGI(IPOD_TAG, "CMD 0x%04x GetIndexedPlayingTrackInfo 0x%02x for index %d (previous %d) : Release date", cmdID, byteArray[2], tempTrackIndex, esp->prevTrackIndex); + ESP_LOGI(__func__, "CMD 0x%04x GetIndexedPlayingTrackInfo 0x%02x for index %d (previous %d) : Release date", cmdID, byteArray[2], tempTrackIndex, esp->prevTrackIndex); L0x04::_0x0D_ReturnIndexedPlayingTrackInfo(esp, byteArray[2], (uint16_t)2001); break; case 0x01: // Track Title - ESP_LOGI(IPOD_TAG, "CMD 0x%04x GetIndexedPlayingTrackInfo 0x%02x for index %d (previous %d) : Title", cmdID, byteArray[2], tempTrackIndex, esp->prevTrackIndex); + ESP_LOGI(__func__, "CMD 0x%04x GetIndexedPlayingTrackInfo 0x%02x for index %d (previous %d) : Title", cmdID, byteArray[2], tempTrackIndex, esp->prevTrackIndex); if (tempTrackIndex == esp->prevTrackIndex) { L0x04::_0x0D_ReturnIndexedPlayingTrackInfo(esp, byteArray[2], esp->prevTrackTitle); @@ -56,15 +56,15 @@ void L0x04::processLingo(esPod *esp, const byte *byteArray, uint32_t len) } break; case 0x05: // Track Genre - ESP_LOGI(IPOD_TAG, "CMD 0x%04x GetIndexedPlayingTrackInfo 0x%02x for index %d (previous %d) : Genre", cmdID, byteArray[2], tempTrackIndex, esp->prevTrackIndex); + ESP_LOGI(__func__, "CMD 0x%04x GetIndexedPlayingTrackInfo 0x%02x for index %d (previous %d) : Genre", cmdID, byteArray[2], tempTrackIndex, esp->prevTrackIndex); L0x04::_0x0D_ReturnIndexedPlayingTrackInfo(esp, byteArray[2], esp->trackGenre); break; case 0x06: // Track Composer - ESP_LOGI(IPOD_TAG, "CMD 0x%04x GetIndexedPlayingTrackInfo 0x%02x for index %d (previous %d) : Composer", cmdID, byteArray[2], tempTrackIndex, esp->prevTrackIndex); + ESP_LOGI(__func__, "CMD 0x%04x GetIndexedPlayingTrackInfo 0x%02x for index %d (previous %d) : Composer", cmdID, byteArray[2], tempTrackIndex, esp->prevTrackIndex); L0x04::_0x0D_ReturnIndexedPlayingTrackInfo(esp, byteArray[2], esp->composer); break; default: // In case the request is beyond the track capabilities - ESP_LOGW(IPOD_TAG, "CMD 0x%04x GetIndexedPlayingTrackInfo 0x%02x for index %d (previous %d) : Type not recognised!", cmdID, byteArray[2], tempTrackIndex, esp->prevTrackIndex); + ESP_LOGW(__func__, "CMD 0x%04x GetIndexedPlayingTrackInfo 0x%02x for index %d (previous %d) : Type not recognised!", cmdID, byteArray[2], tempTrackIndex, esp->prevTrackIndex); L0x04::_0x01_iPodAck(esp, iPodAck_BadParam, cmdID); break; } @@ -73,7 +73,7 @@ void L0x04::processLingo(esPod *esp, const byte *byteArray, uint32_t len) case L0x04_RequestProtocolVersion: // Hardcoded return for L0x04 { - ESP_LOGI(IPOD_TAG, "CMD 0x%04x RequestProtocolVersion", cmdID); + ESP_LOGI(__func__, "CMD 0x%04x RequestProtocolVersion", cmdID); L0x04::_0x13_ReturnProtocolVersion(esp); // Potentially should use L0x00_0x10 instead ? L0x00_0x10_ReturnLingoProtocolVersion(byteArray[2]); // L0x00_0x27_GetAccessoryInfo(0x00); // Attempting to start normal handshake } @@ -81,14 +81,14 @@ void L0x04::processLingo(esPod *esp, const byte *byteArray, uint32_t len) case L0x04_ResetDBSelection: // Not sure what to do here. Reset Current Track Index ? { - ESP_LOGI(IPOD_TAG, "CMD 0x%04x ResetDBSelection", cmdID); + ESP_LOGI(__func__, "CMD 0x%04x ResetDBSelection", cmdID); L0x04::_0x01_iPodAck(esp, iPodAck_OK, cmdID); } break; case L0x04_SelectDBRecord: // Used for browsing ? { - ESP_LOGI(IPOD_TAG, "CMD 0x%04x SelectDBRecord", cmdID); + ESP_LOGI(__func__, "CMD 0x%04x SelectDBRecord", cmdID); L0x04::_0x01_iPodAck(esp, iPodAck_OK, cmdID); } break; @@ -96,7 +96,7 @@ void L0x04::processLingo(esPod *esp, const byte *byteArray, uint32_t len) case L0x04_GetNumberCategorizedDBRecords: // Mini requests the number of records for a specific DB_CAT { category = byteArray[2]; - ESP_LOGI(IPOD_TAG, "CMD 0x%04x GetNumberCategorizedDBRecords category: 0x%02x", cmdID, category); + ESP_LOGI(__func__, "CMD 0x%04x GetNumberCategorizedDBRecords category: 0x%02x", cmdID, category); if (category == DB_CAT_TRACK) { L0x04::_0x19_ReturnNumberCategorizedDBRecords(esp, esp->totalNumberTracks); // Say there are fixed, large amount of tracks @@ -114,7 +114,7 @@ void L0x04::processLingo(esPod *esp, const byte *byteArray, uint32_t len) startIndex = swap_endian(*(uint32_t *)&byteArray[3]); counts = swap_endian(*(uint32_t *)&byteArray[7]); - ESP_LOGI(IPOD_TAG, "CMD 0x%04x RetrieveCategorizedDatabaseRecords category: 0x%02x from %d for %d counts", cmdID, category, startIndex, counts); + ESP_LOGI(__func__, "CMD 0x%04x RetrieveCategorizedDatabaseRecords category: 0x%02x from %d for %d counts", cmdID, category, startIndex, counts); switch (category) { case DB_CAT_PLAYLIST: @@ -166,7 +166,7 @@ void L0x04::processLingo(esPod *esp, const byte *byteArray, uint32_t len) } break; default: - ESP_LOGW(IPOD_TAG, "CMD 0x%04x RetrieveCategorizedDatabaseRecords category: 0x%02x not recognised", cmdID, category); + ESP_LOGW(__func__, "CMD 0x%04x RetrieveCategorizedDatabaseRecords category: 0x%02x not recognised", cmdID, category); L0x04::_0x01_iPodAck(esp, iPodAck_BadParam, cmdID); break; } @@ -175,14 +175,14 @@ void L0x04::processLingo(esPod *esp, const byte *byteArray, uint32_t len) case L0x04_GetPlayStatus: // Returns the current esp->playStatus and the position/duration of the current track { - ESP_LOGI(IPOD_TAG, "CMD 0x%04x GetPlayStatus", cmdID); + ESP_LOGI(__func__, "CMD 0x%04x GetPlayStatus", cmdID); L0x04::_0x1D_ReturnPlayStatus(esp, esp->playPosition, esp->trackDuration, esp->playStatus); } break; case L0x04_GetCurrentPlayingTrackIndex: // Get the uint32 index of the currently playing song { - ESP_LOGI(IPOD_TAG, "CMD 0x%04x GetCurrentPlayingTrackIndex", cmdID); + ESP_LOGI(__func__, "CMD 0x%04x GetCurrentPlayingTrackIndex", cmdID); L0x04::_0x1F_ReturnCurrentPlayingTrackIndex(esp, esp->currentTrackIndex); } break; @@ -190,7 +190,7 @@ void L0x04::processLingo(esPod *esp, const byte *byteArray, uint32_t len) case L0x04_GetIndexedPlayingTrackTitle: { tempTrackIndex = swap_endian(*((uint32_t *)&byteArray[2])); - ESP_LOGI(IPOD_TAG, "CMD 0x%04x GetIndexedPlayingTrackTitle for index %d (previous %d)", cmdID, tempTrackIndex, esp->prevTrackIndex); + ESP_LOGI(__func__, "CMD 0x%04x GetIndexedPlayingTrackTitle for index %d (previous %d)", cmdID, tempTrackIndex, esp->prevTrackIndex); if (tempTrackIndex == esp->prevTrackIndex) { L0x04::_0x21_ReturnIndexedPlayingTrackTitle(esp, esp->prevTrackTitle); @@ -206,7 +206,7 @@ void L0x04::processLingo(esPod *esp, const byte *byteArray, uint32_t len) { tempTrackIndex = swap_endian(*((uint32_t *)&byteArray[2])); - ESP_LOGI(IPOD_TAG, "CMD 0x%04x GetIndexedPlayingTrackArtistName for index %d (previous %d)", cmdID, tempTrackIndex, esp->prevTrackIndex); + ESP_LOGI(__func__, "CMD 0x%04x GetIndexedPlayingTrackArtistName for index %d (previous %d)", cmdID, tempTrackIndex, esp->prevTrackIndex); if (tempTrackIndex == esp->prevTrackIndex) { L0x04::_0x23_ReturnIndexedPlayingTrackArtistName(esp, esp->prevArtistName); @@ -221,7 +221,7 @@ void L0x04::processLingo(esPod *esp, const byte *byteArray, uint32_t len) case L0x04_GetIndexedPlayingTrackAlbumName: { tempTrackIndex = swap_endian(*((uint32_t *)&byteArray[2])); - ESP_LOGI(IPOD_TAG, "CMD 0x%04x GetIndexedPlayingTrackAlbumName for index %d (previous %d)", cmdID, tempTrackIndex, esp->prevTrackIndex); + ESP_LOGI(__func__, "CMD 0x%04x GetIndexedPlayingTrackAlbumName for index %d (previous %d)", cmdID, tempTrackIndex, esp->prevTrackIndex); if (tempTrackIndex == esp->prevTrackIndex) { L0x04::_0x25_ReturnIndexedPlayingTrackAlbumName(esp, esp->prevAlbumName); @@ -236,7 +236,7 @@ void L0x04::processLingo(esPod *esp, const byte *byteArray, uint32_t len) case L0x04_SetPlayStatusChangeNotification: // Turns on basic notifications { esp->playStatusNotificationState = byteArray[2]; - ESP_LOGI(IPOD_TAG, "CMD 0x%04x SetPlayStatusChangeNotification 0x%02x", cmdID, esp->playStatusNotificationState); + ESP_LOGI(__func__, "CMD 0x%04x SetPlayStatusChangeNotification 0x%02x", cmdID, esp->playStatusNotificationState); L0x04::_0x01_iPodAck(esp, iPodAck_OK, cmdID); } break; @@ -244,7 +244,7 @@ void L0x04::processLingo(esPod *esp, const byte *byteArray, uint32_t len) case L0x04_PlayCurrentSelection: // Used to play a specific index, usually for "next" commands, but may be used to actually jump anywhere { tempTrackIndex = swap_endian(*((uint32_t *)&byteArray[2])); - ESP_LOGI(IPOD_TAG, "CMD 0x%04x PlayCurrentSelection index %d", cmdID, tempTrackIndex); + ESP_LOGI(__func__, "CMD 0x%04x PlayCurrentSelection index %d", cmdID, tempTrackIndex); if (esp->playStatus != PB_STATE_PLAYING) { esp->playStatus = PB_STATE_PLAYING; // Playing status forced @@ -269,7 +269,7 @@ void L0x04::processLingo(esPod *esp, const byte *byteArray, uint32_t len) // Engage the pending ACK for expected metadata esp->trackChangeAckPending = cmdID; esp->trackChangeTimestamp = millis(); - ESP_LOGD(IPOD_TAG, "Prev. index %d New index %d Tracklist pos. %d Pending Meta %d Timestamp: %d --> PREV ", esp->prevTrackIndex, esp->currentTrackIndex, esp->trackListPosition, (esp->trackChangeAckPending > 0x00), esp->trackChangeTimestamp); + ESP_LOGD(__func__, "Prev. index %d New index %d Tracklist pos. %d Pending Meta %d Timestamp: %d --> PREV ", esp->prevTrackIndex, esp->currentTrackIndex, esp->trackListPosition, (esp->trackChangeAckPending > 0x00), esp->trackChangeTimestamp); L0x04::_0x01_iPodAck(esp, iPodAck_CmdPending, cmdID, TRACK_CHANGE_TIMEOUT); // Fire the A2DP when ready @@ -278,7 +278,7 @@ void L0x04::processLingo(esPod *esp, const byte *byteArray, uint32_t len) } else if (tempTrackIndex == esp->currentTrackIndex) // Somehow reselecting the current track { - ESP_LOGD(IPOD_TAG, "Selected same track as current: %d", tempTrackIndex); + ESP_LOGD(__func__, "Selected same track as current: %d", tempTrackIndex); L0x04::_0x01_iPodAck(esp, iPodAck_OK, cmdID); // Fire the A2DP when ready @@ -302,7 +302,7 @@ void L0x04::processLingo(esPod *esp, const byte *byteArray, uint32_t len) // Engage the pending ACK for expected metadata esp->trackChangeAckPending = cmdID; esp->trackChangeTimestamp = millis(); - ESP_LOGD(IPOD_TAG, "Prev. index %d New index %d Tracklist pos. %d Pending Meta %d Timestamp: %d --> NEXT ", esp->prevTrackIndex, esp->currentTrackIndex, esp->trackListPosition, (esp->trackChangeAckPending > 0x00), esp->trackChangeTimestamp); + ESP_LOGD(__func__, "Prev. index %d New index %d Tracklist pos. %d Pending Meta %d Timestamp: %d --> NEXT ", esp->prevTrackIndex, esp->currentTrackIndex, esp->trackListPosition, (esp->trackChangeAckPending > 0x00), esp->trackChangeTimestamp); L0x04::_0x01_iPodAck(esp, iPodAck_CmdPending, cmdID, TRACK_CHANGE_TIMEOUT); // Fire the A2DP when ready @@ -314,7 +314,7 @@ void L0x04::processLingo(esPod *esp, const byte *byteArray, uint32_t len) case L0x04_PlayControl: // Basic play control. Used for Prev, pause and play { - ESP_LOGI(IPOD_TAG, "CMD 0x%04x PlayControl req: 0x%02x vs esp->playStatus: 0x%02x", cmdID, byteArray[2], esp->playStatus); + ESP_LOGI(__func__, "CMD 0x%04x PlayControl req: 0x%02x vs esp->playStatus: 0x%02x", cmdID, byteArray[2], esp->playStatus); switch (byteArray[2]) // PlayControl byte { case PB_CMD_TOGGLE: // Just Toggle or start playing @@ -358,7 +358,7 @@ void L0x04::processLingo(esPod *esp, const byte *byteArray, uint32_t len) // Engage the pending ACK for expected metadata esp->trackChangeAckPending = cmdID; esp->trackChangeTimestamp = millis(); - ESP_LOGD(IPOD_TAG, "Prev. index %d New index %d Tracklist pos. %d Pending Meta %d Timestamp: %d --> EXPLICIT NEXT TRACK", esp->prevTrackIndex, esp->currentTrackIndex, esp->trackListPosition, (esp->trackChangeAckPending > 0x00), esp->trackChangeTimestamp); + ESP_LOGD(__func__, "Prev. index %d New index %d Tracklist pos. %d Pending Meta %d Timestamp: %d --> EXPLICIT NEXT TRACK", esp->prevTrackIndex, esp->currentTrackIndex, esp->trackListPosition, (esp->trackChangeAckPending > 0x00), esp->trackChangeTimestamp); L0x04::_0x01_iPodAck(esp, iPodAck_CmdPending, cmdID, TRACK_CHANGE_TIMEOUT); // Fire the A2DP when ready @@ -368,7 +368,7 @@ void L0x04::processLingo(esPod *esp, const byte *byteArray, uint32_t len) break; case PB_CMD_PREVIOUS_TRACK: // Prev track { - ESP_LOGD(IPOD_TAG, "Current index %d Tracklist pos. %d --> EXPLICIT SINGLE PREV TRACK", esp->currentTrackIndex, esp->trackListPosition); + ESP_LOGD(__func__, "Current index %d Tracklist pos. %d --> EXPLICIT SINGLE PREV TRACK", esp->currentTrackIndex, esp->trackListPosition); L0x04::_0x01_iPodAck(esp, iPodAck_OK, cmdID); // Fire the A2DP when ready @@ -392,7 +392,7 @@ void L0x04::processLingo(esPod *esp, const byte *byteArray, uint32_t len) // Engage the pending ACK for expected metadata esp->trackChangeAckPending = cmdID; esp->trackChangeTimestamp = millis(); - ESP_LOGD(IPOD_TAG, "Prev. index %d New index %d Tracklist pos. %d Pending Meta %d Timestamp: %d --> EXPLICIT NEXT", esp->prevTrackIndex, esp->currentTrackIndex, esp->trackListPosition, (esp->trackChangeAckPending > 0x00), esp->trackChangeTimestamp); + ESP_LOGD(__func__, "Prev. index %d New index %d Tracklist pos. %d Pending Meta %d Timestamp: %d --> EXPLICIT NEXT", esp->prevTrackIndex, esp->currentTrackIndex, esp->trackListPosition, (esp->trackChangeAckPending > 0x00), esp->trackChangeTimestamp); L0x04::_0x01_iPodAck(esp, iPodAck_CmdPending, cmdID, TRACK_CHANGE_TIMEOUT); // Fire the A2DP when ready @@ -402,7 +402,7 @@ void L0x04::processLingo(esPod *esp, const byte *byteArray, uint32_t len) break; case PB_CMD_PREV: // Prev track { - ESP_LOGD(IPOD_TAG, "Current index %d Tracklist pos. %d --> EXPLICIT SINGLE PREV", esp->currentTrackIndex, esp->trackListPosition); + ESP_LOGD(__func__, "Current index %d Tracklist pos. %d --> EXPLICIT SINGLE PREV", esp->currentTrackIndex, esp->trackListPosition); L0x04::_0x01_iPodAck(esp, iPodAck_OK, cmdID); // Fire the A2DP when ready @@ -439,14 +439,14 @@ void L0x04::processLingo(esPod *esp, const byte *byteArray, uint32_t len) case L0x04_GetShuffle: // Get Shuffle state from the PB Engine { - ESP_LOGI(IPOD_TAG, "CMD 0x%04x GetShuffle", cmdID); + ESP_LOGI(__func__, "CMD 0x%04x GetShuffle", cmdID); L0x04::_0x2D_ReturnShuffle(esp, esp->shuffleStatus); } break; case L0x04_SetShuffle: // Set Shuffle state { - ESP_LOGI(IPOD_TAG, "CMD 0x%04x SetShuffle req: 0x%02x vs shuffleStatus: 0x%02x", cmdID, byteArray[2], esp->shuffleStatus); + ESP_LOGI(__func__, "CMD 0x%04x SetShuffle req: 0x%02x vs shuffleStatus: 0x%02x", cmdID, byteArray[2], esp->shuffleStatus); esp->shuffleStatus = byteArray[2]; L0x04::_0x01_iPodAck(esp, iPodAck_OK, cmdID); } @@ -454,14 +454,14 @@ void L0x04::processLingo(esPod *esp, const byte *byteArray, uint32_t len) case L0x04_GetRepeat: // Get Repeat state { - ESP_LOGI(IPOD_TAG, "CMD 0x%04x GetRepeat", cmdID); + ESP_LOGI(__func__, "CMD 0x%04x GetRepeat", cmdID); L0x04::_0x30_ReturnRepeat(esp, esp->repeatStatus); } break; case L0x04_SetRepeat: // Set Repeat state { - ESP_LOGI(IPOD_TAG, "CMD 0x%04x SetRepeat req: 0x%02x vs repeatStatus: 0x%02x", cmdID, byteArray[2], esp->repeatStatus); + ESP_LOGI(__func__, "CMD 0x%04x SetRepeat req: 0x%02x vs repeatStatus: 0x%02x", cmdID, byteArray[2], esp->repeatStatus); esp->repeatStatus = byteArray[2]; L0x04::_0x01_iPodAck(esp, iPodAck_OK, cmdID); } @@ -469,14 +469,14 @@ void L0x04::processLingo(esPod *esp, const byte *byteArray, uint32_t len) case L0x04_GetMonoDisplayImageLimits: { - ESP_LOGI(IPOD_TAG, "CMD 0x0%04x GetMonoDisplayImageLimits", cmdID); + ESP_LOGI(__func__, "CMD 0x0%04x GetMonoDisplayImageLimits", cmdID); L0x04::_0x34_ReturnMonoDisplayImageLimits(esp, 0, 0, 0x01); // Not sure this is OK } break; case L0x04_GetNumPlayingTracks: // Systematically return TOTAL_NUM_TRACKS { - ESP_LOGI(IPOD_TAG, "CMD 0x%04x GetNumPlayingTracks", cmdID); + ESP_LOGI(__func__, "CMD 0x%04x GetNumPlayingTracks", cmdID); L0x04::_0x36_ReturnNumPlayingTracks(esp, esp->totalNumberTracks); } break; @@ -484,7 +484,7 @@ void L0x04::processLingo(esPod *esp, const byte *byteArray, uint32_t len) case L0x04_SetCurrentPlayingTrack: // Basically identical to PlayCurrentSelection { tempTrackIndex = swap_endian(*((uint32_t *)&byteArray[2])); - ESP_LOGI(IPOD_TAG, "CMD 0x%04x SetCurrentPlayingTrack index %d", cmdID, tempTrackIndex); + ESP_LOGI(__func__, "CMD 0x%04x SetCurrentPlayingTrack index %d", cmdID, tempTrackIndex); if (esp->playStatus != PB_STATE_PLAYING) { esp->playStatus = PB_STATE_PLAYING; // Playing status forced @@ -509,7 +509,7 @@ void L0x04::processLingo(esPod *esp, const byte *byteArray, uint32_t len) // Engage the pending ACK for expected metadata esp->trackChangeAckPending = cmdID; esp->trackChangeTimestamp = millis(); - ESP_LOGD(IPOD_TAG, "Prev. index %d New index %d Tracklist pos. %d Pending Meta %d Timestamp: %d --> PREV ", esp->prevTrackIndex, esp->currentTrackIndex, esp->trackListPosition, (esp->trackChangeAckPending > 0x00), esp->trackChangeTimestamp); + ESP_LOGD(__func__, "Prev. index %d New index %d Tracklist pos. %d Pending Meta %d Timestamp: %d --> PREV ", esp->prevTrackIndex, esp->currentTrackIndex, esp->trackListPosition, (esp->trackChangeAckPending > 0x00), esp->trackChangeTimestamp); L0x04::_0x01_iPodAck(esp, iPodAck_CmdPending, cmdID, TRACK_CHANGE_TIMEOUT); // Fire the A2DP when ready @@ -518,7 +518,7 @@ void L0x04::processLingo(esPod *esp, const byte *byteArray, uint32_t len) } else if (tempTrackIndex == esp->currentTrackIndex) // Somehow reselecting the current track { - ESP_LOGD(IPOD_TAG, "Selected same track as current: %d", tempTrackIndex); + ESP_LOGD(__func__, "Selected same track as current: %d", tempTrackIndex); L0x04::_0x01_iPodAck(esp, iPodAck_OK, cmdID); // Fire the A2DP when ready @@ -542,7 +542,7 @@ void L0x04::processLingo(esPod *esp, const byte *byteArray, uint32_t len) // Engage the pending ACK for expected metadata esp->trackChangeAckPending = cmdID; esp->trackChangeTimestamp = millis(); - ESP_LOGD(IPOD_TAG, "Prev. index %d New index %d Tracklist pos. %d Pending Meta %d Timestamp: %d --> NEXT ", esp->prevTrackIndex, esp->currentTrackIndex, esp->trackListPosition, (esp->trackChangeAckPending > 0x00), esp->trackChangeTimestamp); + ESP_LOGD(__func__, "Prev. index %d New index %d Tracklist pos. %d Pending Meta %d Timestamp: %d --> NEXT ", esp->prevTrackIndex, esp->currentTrackIndex, esp->trackListPosition, (esp->trackChangeAckPending > 0x00), esp->trackChangeTimestamp); L0x04::_0x01_iPodAck(esp, iPodAck_CmdPending, cmdID, TRACK_CHANGE_TIMEOUT); // Fire the A2DP when ready @@ -554,21 +554,21 @@ void L0x04::processLingo(esPod *esp, const byte *byteArray, uint32_t len) case L0x04_SelectSortDBRecord: // Used for browsing ? { - ESP_LOGI(IPOD_TAG, "CMD 0x%04x SelectSortDBRecord (deprecated)", cmdID); + ESP_LOGI(__func__, "CMD 0x%04x SelectSortDBRecord (deprecated)", cmdID); L0x04::_0x01_iPodAck(esp, iPodAck_OK, cmdID); } break; case L0x04_GetColorDisplayImageLimits: { - ESP_LOGI(IPOD_TAG, "CMD 0x0%04x GetColorDisplayImageLimits", cmdID); + ESP_LOGI(__func__, "CMD 0x0%04x GetColorDisplayImageLimits", cmdID); L0x04::_0x3A_ReturnColorDisplayImageLimits(esp, 0, 0, 0x01); // Not sure this is OK } break; default: { - ESP_LOGW(IPOD_TAG, "CMD 0x%04x not recognized.", cmdID); + ESP_LOGW(__func__, "CMD 0x%04x not recognized.", cmdID); L0x04::_0x01_iPodAck(esp, iPodAck_CmdFailed, cmdID); } break; @@ -582,7 +582,7 @@ void L0x04::processLingo(esPod *esp, const byte *byteArray, uint32_t len) /// @param cmdID last two ID bytes of the Lingo 0x04 command replied to void L0x04::_0x01_iPodAck(esPod *esp, IPOD_ACK_CODE ackCode, byte cmdID) { - ESP_LOGI(IPOD_TAG, "Ack 0x%02x to command 0x%04x", ackCode, cmdID); + ESP_LOGI(__func__, "Ack 0x%02x to command 0x%04x", ackCode, cmdID); // Queue the ack packet const byte txPacket[] = { 0x04, @@ -607,7 +607,7 @@ void L0x04::_0x01_iPodAck(esPod *esp, IPOD_ACK_CODE ackCode, byte cmdID) /// @param numField Pending delay in milliseconds void L0x04::_0x01_iPodAck(esPod *esp, IPOD_ACK_CODE ackCode, byte cmdID, uint32_t numField) { - ESP_LOGI(IPOD_TAG, "Ack 0x%02x to command 0x%04x Numfield: %d", ackCode, cmdID, numField); + ESP_LOGI(__func__, "Ack 0x%02x to command 0x%04x Numfield: %d", ackCode, cmdID, numField); const byte txPacket[20] = { 0x04, 0x00, 0x01, @@ -626,7 +626,7 @@ void L0x04::_0x01_iPodAck(esPod *esp, IPOD_ACK_CODE ackCode, byte cmdID, uint32_ /// @param trackInfoChars Character array to pass and package in the tail of the message void L0x04::_0x0D_ReturnIndexedPlayingTrackInfo(esPod *esp, byte trackInfoType, char *trackInfoChars) { - ESP_LOGI(IPOD_TAG, "Req'd track info type: 0x%02x", trackInfoType); + ESP_LOGI(__func__, "Req'd track info type: 0x%02x", trackInfoType); byte txPacket[255] = { 0x04, 0x00, 0x0D, @@ -640,7 +640,7 @@ void L0x04::_0x0D_ReturnIndexedPlayingTrackInfo(esPod *esp, byte trackInfoType, /// @param trackDuration_ms trackduration in ms void L0x04::_0x0D_ReturnIndexedPlayingTrackInfo(esPod *esp, uint32_t trackDuration_ms) { - ESP_LOGI(IPOD_TAG, "Track duration: %d", trackDuration_ms); + ESP_LOGI(__func__, "Track duration: %d", trackDuration_ms); byte txPacket[14] = { 0x04, 0x00, 0x0D, @@ -659,7 +659,7 @@ void L0x04::_0x0D_ReturnIndexedPlayingTrackInfo(esPod *esp, uint32_t trackDurati /// @param releaseYear Fictional release year of the song void L0x04::_0x0D_ReturnIndexedPlayingTrackInfo(esPod *esp, byte trackInfoType, uint16_t releaseYear) { - ESP_LOGI(IPOD_TAG, "Track info: 0x%02x Release Year: %d", trackInfoType, releaseYear); + ESP_LOGI(__func__, "Track info: 0x%02x Release Year: %d", trackInfoType, releaseYear); byte txPacket[12] = { 0x04, 0x00, 0x0D, @@ -676,7 +676,7 @@ void L0x04::_0x0D_ReturnIndexedPlayingTrackInfo(esPod *esp, byte trackInfoType, /// @param esp Pointer to the esPod instance void L0x04::_0x13_ReturnProtocolVersion(esPod *esp) { - ESP_LOGI(IPOD_TAG, "Lingo protocol version 1.12"); + ESP_LOGI(__func__, "Lingo protocol version 1.12"); byte txPacket[] = { 0x04, 0x00, 0x13, @@ -690,7 +690,7 @@ void L0x04::_0x13_ReturnProtocolVersion(esPod *esp) /// @param categoryDBRecords The number of records to return void L0x04::_0x19_ReturnNumberCategorizedDBRecords(esPod *esp, uint32_t categoryDBRecords) { - ESP_LOGI(IPOD_TAG, "Category DB Records: %d", categoryDBRecords); + ESP_LOGI(__func__, "Category DB Records: %d", categoryDBRecords); byte txPacket[7] = { 0x04, 0x00, 0x19, @@ -705,7 +705,7 @@ void L0x04::_0x19_ReturnNumberCategorizedDBRecords(esPod *esp, uint32_t category /// @param recordString Metadata to include in the return void L0x04::_0x1B_ReturnCategorizedDatabaseRecord(esPod *esp, uint32_t index, char *recordString) { - ESP_LOGI(IPOD_TAG, "Database record at index %d : %s", index, recordString); + ESP_LOGI(__func__, "Database record at index %d : %s", index, recordString); byte txPacket[255] = { 0x04, 0x00, 0x1B, @@ -723,7 +723,7 @@ void L0x04::_0x1B_ReturnCategorizedDatabaseRecord(esPod *esp, uint32_t index, ch /// @param playStatusArg Playback status (0x00 Stopped, 0x01 Playing, 0x02 Paused, 0xFF Error) void L0x04::_0x1D_ReturnPlayStatus(esPod *esp, uint32_t position, uint32_t duration, byte playStatusArg) { - ESP_LOGI(IPOD_TAG, "Play status 0x%02x at pos. %d / %d ms", playStatusArg, position, duration); + ESP_LOGI(__func__, "Play status 0x%02x at pos. %d / %d ms", playStatusArg, position, duration); byte txPacket[] = { 0x04, 0x00, 0x1D, @@ -740,7 +740,7 @@ void L0x04::_0x1D_ReturnPlayStatus(esPod *esp, uint32_t position, uint32_t durat /// @param trackIndex The trackIndex to return. This is different from the position in the tracklist when Shuffle is ON void L0x04::_0x1F_ReturnCurrentPlayingTrackIndex(esPod *esp, uint32_t trackIndex) { - ESP_LOGI(IPOD_TAG, "Track index: %d", trackIndex); + ESP_LOGI(__func__, "Track index: %d", trackIndex); byte txPacket[] = { 0x04, 0x00, 0x1F, @@ -754,7 +754,7 @@ void L0x04::_0x1F_ReturnCurrentPlayingTrackIndex(esPod *esp, uint32_t trackIndex /// @param trackTitle Character array to return void L0x04::_0x21_ReturnIndexedPlayingTrackTitle(esPod *esp, char *trackTitle) { - ESP_LOGI(IPOD_TAG, "Track title: %s", trackTitle); + ESP_LOGI(__func__, "Track title: %s", trackTitle); byte txPacket[255] = { 0x04, 0x00, 0x21}; @@ -767,7 +767,7 @@ void L0x04::_0x21_ReturnIndexedPlayingTrackTitle(esPod *esp, char *trackTitle) /// @param trackArtistName Character array to return void L0x04::_0x23_ReturnIndexedPlayingTrackArtistName(esPod *esp, char *trackArtistName) { - ESP_LOGI(IPOD_TAG, "Track artist: %s", trackArtistName); + ESP_LOGI(__func__, "Track artist: %s", trackArtistName); byte txPacket[255] = { 0x04, 0x00, 0x23}; @@ -780,7 +780,7 @@ void L0x04::_0x23_ReturnIndexedPlayingTrackArtistName(esPod *esp, char *trackArt /// @param trackAlbumName Character array to return void L0x04::_0x25_ReturnIndexedPlayingTrackAlbumName(esPod *esp, char *trackAlbumName) { - ESP_LOGI(IPOD_TAG, "Track album: %s", trackAlbumName); + ESP_LOGI(__func__, "Track album: %s", trackAlbumName); byte txPacket[255] = { 0x04, 0x00, 0x25}; @@ -794,7 +794,7 @@ void L0x04::_0x25_ReturnIndexedPlayingTrackAlbumName(esPod *esp, char *trackAlbu /// @param numField For 0x01 this is the new Track index, for 0x04 this is the current Track offset in ms void L0x04::_0x27_PlayStatusNotification(esPod *esp, byte notification, uint32_t numField) { - ESP_LOGI(IPOD_TAG, "Play status 0x%02x Numfield: %d", notification, numField); + ESP_LOGI(__func__, "Play status 0x%02x Numfield: %d", notification, numField); byte txPacket[] = { 0x04, 0x00, 0x27, @@ -809,7 +809,7 @@ void L0x04::_0x27_PlayStatusNotification(esPod *esp, byte notification, uint32_t /// @param notification Can only be 0x00 void L0x04::_0x27_PlayStatusNotification(esPod *esp, byte notification) { - ESP_LOGI(IPOD_TAG, "Play status 0x%02x STOPPED", notification); + ESP_LOGI(__func__, "Play status 0x%02x STOPPED", notification); byte txPacket[] = { 0x04, 0x00, 0x27, @@ -822,7 +822,7 @@ void L0x04::_0x27_PlayStatusNotification(esPod *esp, byte notification) /// @param currentShuffleStatus 0x00 No Shuffle, 0x01 Tracks, 0x02 Albums void L0x04::_0x2D_ReturnShuffle(esPod *esp, byte currentShuffleStatus) { - ESP_LOGI(IPOD_TAG, "Shuffle status: 0x%02x", currentShuffleStatus); + ESP_LOGI(__func__, "Shuffle status: 0x%02x", currentShuffleStatus); byte txPacket[] = { 0x04, 0x00, 0x2D, @@ -835,7 +835,7 @@ void L0x04::_0x2D_ReturnShuffle(esPod *esp, byte currentShuffleStatus) /// @param currentRepeatStatus 0x00 No Repeat, 0x01 One Track, 0x02 All tracks void L0x04::_0x30_ReturnRepeat(esPod *esp, byte currentRepeatStatus) { - ESP_LOGI(IPOD_TAG, "Repeat status: 0x%02x", currentRepeatStatus); + ESP_LOGI(__func__, "Repeat status: 0x%02x", currentRepeatStatus); byte txPacket[] = { 0x04, 0x00, 0x30, @@ -850,7 +850,7 @@ void L0x04::_0x30_ReturnRepeat(esPod *esp, byte currentRepeatStatus) /// @param dispPixelFmt void L0x04::_0x34_ReturnMonoDisplayImageLimits(esPod *esp, uint16_t maxImageW, uint16_t maxImageH, byte dispPixelFmt) { - ESP_LOGI(IPOD_TAG, "Return monochrome image limits : %d x %d x %d", maxImageW, maxImageH, dispPixelFmt); + ESP_LOGI(__func__, "Return monochrome image limits : %d x %d x %d", maxImageW, maxImageH, dispPixelFmt); byte txPacket[] = { 0x04, 0x00, 0x34, @@ -867,7 +867,7 @@ void L0x04::_0x34_ReturnMonoDisplayImageLimits(esPod *esp, uint16_t maxImageW, u /// @param numPlayingTracks Number of playing tracks to return void L0x04::_0x36_ReturnNumPlayingTracks(esPod *esp, uint32_t numPlayingTracks) { - ESP_LOGI(IPOD_TAG, "Playing tracks: %d", numPlayingTracks); + ESP_LOGI(__func__, "Playing tracks: %d", numPlayingTracks); byte txPacket[] = { 0x04, 0x00, 0x36, @@ -883,7 +883,7 @@ void L0x04::_0x36_ReturnNumPlayingTracks(esPod *esp, uint32_t numPlayingTracks) /// @param dispPixelFmt void L0x04::_0x3A_ReturnColorDisplayImageLimits(esPod *esp, uint16_t maxImageW, uint16_t maxImageH, byte dispPixelFmt) { - ESP_LOGI(IPOD_TAG, "Return color image limits : %d x %d x %d", maxImageW, maxImageH, dispPixelFmt); + ESP_LOGI(__func__, "Return color image limits : %d x %d x %d", maxImageW, maxImageH, dispPixelFmt); byte txPacket[] = { 0x04, 0x00, 0x3A, diff --git a/src/esPod.cpp b/src/esPod.cpp index 0f5fe87..fa8d2cb 100644 --- a/src/esPod.cpp +++ b/src/esPod.cpp @@ -1,62 +1,10 @@ #include "esPod.h" -//----------------------------------------------------------------------- -//| Local utilities | -//----------------------------------------------------------------------- -// #pragma region Local utilities -// // ESP32 is Little-Endian, iPod is Big-Endian -// template -// T swap_endian(T u) -// { -// static_assert(CHAR_BIT == 8, "CHAR_BIT != 8"); - -// union -// { -// T u; -// unsigned char u8[sizeof(T)]; -// } source, dest; - -// source.u = u; - -// for (size_t k = 0; k < sizeof(T); k++) -// dest.u8[k] = source.u8[sizeof(T) - k - 1]; - -// return dest.u; -// } - -// /// @brief (Re)starts a timer and changes the interval on the fly. -// /// @param timer Timer handle to (re)start. -// /// @param time_ms New interval in milliseconds. No verification is done if this is 0! Defaults to TRACK_CHANGE_TIMEOUT. -// void startTimer(TimerHandle_t timer, unsigned long time_ms = TRACK_CHANGE_TIMEOUT) -// { -// // If the timer is already active, it needs to be stopped without a callback call first -// if (xTimerIsTimerActive(timer) == pdTRUE) -// { -// xTimerStop(timer, 0); -// } -// // Change the period and start the timer -// xTimerChangePeriod(timer, pdMS_TO_TICKS(time_ms), 0); -// xTimerStart(timer, 0); -// } - -// /// @brief Stops a running timer. No status is returned if it was already stopped. -// /// @param timer Handle to the Timer that needs to be stopped. -// void stopTimer(TimerHandle_t timer) -// { -// // If the timer is already active, it needs to be stop without a callback call first -// if (xTimerIsTimerActive(timer) == pdTRUE) -// { -// xTimerStop(timer, 0); -// } -// } -// #pragma endregion - //----------------------------------------------------------------------- //| Cardinal tasks and Timers | //----------------------------------------------------------------------- #pragma region Tasks -/// @brief RX Task, sifts through the incoming serial data and compiles packets that pass the checksum and passes them to the processing Queue _cmdQueue. Also handles timeouts and can trigger state resets. -/// @param pvParameters Unused + void esPod::_rxTask(void *pvParameters) { esPod *esPodInstance = static_cast(pvParameters); @@ -201,8 +149,6 @@ void esPod::_rxTask(void *pvParameters) } } -/// @brief Processor task retrieving from the cmdQueue and processing the commands -/// @param pvParameters void esPod::_processTask(void *pvParameters) { esPod *esPodInstance = static_cast(pvParameters); @@ -251,8 +197,6 @@ void esPod::_processTask(void *pvParameters) } } -/// @brief Transmit task, retrieves from the txQueue and sends the packets over Serial at high priority but wider timing -/// @param pvParameters void esPod::_txTask(void *pvParameters) { esPod *esPodInstance = static_cast(pvParameters); @@ -310,8 +254,6 @@ void esPod::_txTask(void *pvParameters) } } -/// @brief Low priority task to queue acks *outside* of the timer interrupt context -/// @param pvParameters void esPod::_timerTask(void *pvParameters) { esPod *esPodInstance = static_cast(pvParameters); @@ -333,6 +275,10 @@ void esPod::_timerTask(void *pvParameters) if (msg.cmdID == esPodInstance->trackChangeAckPending) { esPodInstance->trackChangeAckPending = 0x00; + esPodInstance->_albumNameUpdated = false; + esPodInstance->_artistNameUpdated = false; + esPodInstance->_trackTitleUpdated = false; + esPodInstance->_trackDurationUpdated = false; } } else if (msg.targetLingo == 0x03) @@ -342,6 +288,10 @@ void esPod::_timerTask(void *pvParameters) if (msg.cmdID == esPodInstance->trackChangeAckPending) { esPodInstance->trackChangeAckPending = 0x00; + esPodInstance->_albumNameUpdated = false; + esPodInstance->_artistNameUpdated = false; + esPodInstance->_trackTitleUpdated = false; + esPodInstance->_trackDurationUpdated = false; } } } @@ -352,8 +302,6 @@ void esPod::_timerTask(void *pvParameters) #pragma region Timer Callbacks -/// @brief Callback for L0x00 pending Ack timer -/// @param xTimer void esPod::_pendingTimerCallback_0x00(TimerHandle_t xTimer) { esPod *esPodInstance = static_cast(pvTimerGetTimerID(xTimer)); @@ -361,8 +309,6 @@ void esPod::_pendingTimerCallback_0x00(TimerHandle_t xTimer) xQueueSendFromISR(esPodInstance->_timerQueue, &msg, NULL); } -/// @brief Callback for L0x03 pending Ack timer -/// @param xTimer void esPod::_pendingTimerCallback_0x03(TimerHandle_t xTimer) { esPod *esPodInstance = static_cast(pvTimerGetTimerID(xTimer)); @@ -370,8 +316,6 @@ void esPod::_pendingTimerCallback_0x03(TimerHandle_t xTimer) xQueueSendFromISR(esPodInstance->_timerQueue, &msg, NULL); } -/// @brief Callback for L0x04 pending Ack timer -/// @param xTimer void esPod::_pendingTimerCallback_0x04(TimerHandle_t xTimer) { esPod *esPodInstance = static_cast(pvTimerGetTimerID(xTimer)); @@ -384,10 +328,7 @@ void esPod::_pendingTimerCallback_0x04(TimerHandle_t xTimer) //| Packet management | //----------------------------------------------------------------------- #pragma region Packet management -/// @brief //Calculates the checksum of a packet that starts from i=0 ->Lingo to i=len -> Checksum -/// @param byteArray Array from Lingo byte to Checksum byte -/// @param len Length of array (Lingo byte to Checksum byte) -/// @return Calculated checksum for comparison + byte esPod::_checksum(const byte *byteArray, uint32_t len) { uint32_t tempChecksum = len; @@ -399,9 +340,6 @@ byte esPod::_checksum(const byte *byteArray, uint32_t len) return (byte)tempChecksum; } -/// @brief Composes and sends a packet over the _targetSerial -/// @param byteArray Array to send, starting with the Lingo byte and without the checksum byte -/// @param len Length of the array to send void esPod::_sendPacket(const byte *byteArray, uint32_t len) { uint32_t finalLength = len + 4; @@ -419,9 +357,6 @@ void esPod::_sendPacket(const byte *byteArray, uint32_t len) _targetSerial.write(tempBuf, finalLength); } -/// @brief Adds a packet to the transmit queue -/// @param byteArray Array of bytes to add to the queue -/// @param len Length of data in the array void esPod::_queuePacket(const byte *byteArray, uint32_t len) { aapCommand cmdToQueue; @@ -437,9 +372,6 @@ void esPod::_queuePacket(const byte *byteArray, uint32_t len) } } -/// @brief Adds a packet to the transmit queue, but at the front for immediate processing -/// @param byteArray Array of bytes to add to the queue -/// @param len Length of data in the array void esPod::_queuePacketToFront(const byte *byteArray, uint32_t len) { aapCommand cmdToQueue; @@ -455,9 +387,6 @@ void esPod::_queuePacketToFront(const byte *byteArray, uint32_t len) } } -/// @brief Processes a valid packet and calls the relevant Lingo processor -/// @param byteArray Checksum-validated packet starting at LingoID -/// @param len Length of valid data in the packet void esPod::_processPacket(const byte *byteArray, uint32_t len) { byte rxLingoID = byteArray[0]; @@ -466,22 +395,22 @@ void esPod::_processPacket(const byte *byteArray, uint32_t len) switch (rxLingoID) // 0x00 is general Lingo and 0x04 is extended Lingo. Nothing else is expected from the Mini { case 0x00: // General Lingo - ESP_LOGD(IPOD_TAG, "Lingo 0x00 Packet in processor,payload length: %d", subPayloadLen); + ESP_LOGD(__func__, "Lingo 0x00 Packet in processor,payload length: %d", subPayloadLen); L0x00::processLingo(this, subPayload, subPayloadLen); break; case 0x03: // Display Remote Lingo - ESP_LOGD(IPOD_TAG, "Lingo 0x03 Packet in processor,payload length: %d", subPayloadLen); + ESP_LOGD(__func__, "Lingo 0x03 Packet in processor,payload length: %d", subPayloadLen); L0x03::processLingo(this, subPayload, subPayloadLen); break; case 0x04: // Extended Interface Lingo - ESP_LOGD(IPOD_TAG, "Lingo 0x04 Packet in processor,payload length: %d", subPayloadLen); + ESP_LOGD(__func__, "Lingo 0x04 Packet in processor,payload length: %d", subPayloadLen); L0x04::processLingo(this, subPayload, subPayloadLen); break; default: - ESP_LOGW(IPOD_TAG, "Unknown Lingo packet : L0x%02x 0x%02x", rxLingoID, byteArray[1]); + ESP_LOGW(__func__, "Unknown Lingo packet : L0x%02x 0x%02x", rxLingoID, byteArray[1]); break; } } @@ -491,8 +420,40 @@ void esPod::_processPacket(const byte *byteArray, uint32_t len) //| Constructor, reset, attachCallback for PB control | //----------------------------------------------------------------------- #pragma region Constructor, destructor, reset and external PB Contoller attach -/// @brief Constructor for the esPod class -/// @param targetSerial (Serial) stream on which the esPod will be communicating +void esPod::_checkAllMetaUpdated() +{ + if (_albumNameUpdated && _artistNameUpdated && _trackTitleUpdated && _trackDurationUpdated) + { + // If all fields have received at least one update and the + // trackChangeAckPending is still hanging. The failsafe for this one is + // in the espod _processTask + if (trackChangeAckPending > 0x00) + { + ESP_LOGD(__func__, "Artist+Album+Title+Duration +++ ACK Pending 0x%x\n\tPending duration: %d", trackChangeAckPending, millis() - trackChangeTimestamp); + if (trackChangeAckPending == 0x11) + { + L0x03::_0x00_iPodAck(this, iPodAck_OK, trackChangeAckPending); + } + else + { + L0x04::_0x01_iPodAck(this, iPodAck_OK, trackChangeAckPending); + } + trackChangeAckPending = 0x00; + ESP_LOGD(__func__, "trackChangeAckPending reset to 0x00"); + } + _albumNameUpdated = false; + _artistNameUpdated = false; + _trackTitleUpdated = false; + _trackDurationUpdated = false; + ESP_LOGD(__func__, "Artist+Album+Title+Duration : True -> False"); + // Inform the car + if (playStatusNotificationState == NOTIF_ON) + { + L0x04::_0x27_PlayStatusNotification(this, 0x01, currentTrackIndex); + } + } +} + esPod::esPod(Stream &targetSerial) : _targetSerial(targetSerial) { @@ -503,7 +464,7 @@ esPod::esPod(Stream &targetSerial) if (_cmdQueue == NULL || _txQueue == NULL || _timerQueue == NULL) // Add _timerQueue check { - ESP_LOGE(IPOD_TAG, "Could not create queues"); + ESP_LOGE(__func__, "Could not create queues"); } // Create FreeRTOS tasks for compiling incoming commands, processing commands and transmitting commands @@ -516,7 +477,7 @@ esPod::esPod(Stream &targetSerial) if (_rxTaskHandle == NULL || _processTaskHandle == NULL || _txTaskHandle == NULL || _timerTaskHandle == NULL) { - ESP_LOGE(IPOD_TAG, "Could not create tasks"); + ESP_LOGE(__func__, "Could not create tasks"); } else { @@ -525,17 +486,16 @@ esPod::esPod(Stream &targetSerial) _pendingTimer_0x04 = xTimerCreate("Pending Timer 0x04", pdMS_TO_TICKS(1000), pdFALSE, this, esPod::_pendingTimerCallback_0x04); if (_pendingTimer_0x00 == NULL || _pendingTimer_0x03 == NULL || _pendingTimer_0x04 == NULL) { - ESP_LOGE(IPOD_TAG, "Could not create timers"); + ESP_LOGE(__func__, "Could not create timers"); } } } else { - ESP_LOGE(IPOD_TAG, "Could not create tasks, queues not created"); + ESP_LOGE(__func__, "Could not create tasks, queues not created"); } } -/// @brief Destructor for the esPod class. Normally not used. esPod::~esPod() { aapCommand tempCmd; @@ -571,7 +531,7 @@ esPod::~esPod() void esPod::resetState() { - ESP_LOGW(IPOD_TAG, "esPod resetState called"); + ESP_LOGW(__func__, "esPod resetState called"); // State variables extendedInterfaceModeActive = false; @@ -631,1174 +591,156 @@ void esPod::resetState() void esPod::attachPlayControlHandler(playStatusHandler_t playHandler) { _playStatusHandler = playHandler; - ESP_LOGD(IPOD_TAG, "PlayControlHandler attached."); + ESP_LOGD(__func__, "PlayControlHandler attached."); } void esPod::play() { + playStatus = PB_STATE_PLAYING; + ESP_LOGD(__func__, "esPod set to play."); } void esPod::pause() { + playStatus = PB_STATE_PAUSED; + ESP_LOGD(__func__, "esPod paused."); } -void esPod::updatePlayPosition(uint32_t position) +void esPod::stop() { + playStatus = PB_STATE_STOPPED; + ESP_LOGD(__func__, " esPod stopped."); } -void esPod::updateAlbumName(const char *albumName) +void esPod::updatePlayPosition(uint32_t position) { + playPosition = position; + if (playStatusNotificationState == NOTIF_ON && trackChangeAckPending == 0x00) + L0x04::_0x27_PlayStatusNotification(this, 0x04, position); } -void esPod::updateArtistName(const char *artistName) +void esPod::updateAlbumName(const char *incAlbumName) { + if (trackChangeAckPending > 0x00) // There is a pending track change ack + { + if (!_albumNameUpdated) + { + strcpy(albumName, incAlbumName); + _albumNameUpdated = true; + ESP_LOGD(__func__, "Album name update to %s", albumName); + } + else + ESP_LOGD(__func__, "Album name already updated to %s", albumName); + } + else // There is no pending track change ack : change is coming from phone/AVRC target + { + if (strcmp(incAlbumName, albumName) != 0) // New Album Name + { + strcpy(prevAlbumName, albumName); // Preserve the previous album name + strcpy(albumName, incAlbumName); // Copy new album name + _albumNameUpdated = true; + ESP_LOGD(__func__, "Album name updated to %s", albumName); + } + else // Not new album name + ESP_LOGD(__func__, "Album name already updated to %s", albumName); + } + _checkAllMetaUpdated(); } -void esPod::updateTrackTitle(const char *trackTitle) +void esPod::updateArtistName(const char *incArtistName) { + if (trackChangeAckPending > 0x00) // There is a pending track change ack + { + if (!_artistNameUpdated) + { + strcpy(artistName, incArtistName); + _artistNameUpdated = true; + ESP_LOGD(__func__, "Artist name update to %s", artistName); + } + else + ESP_LOGD(__func__, "Artist name already updated to %s", artistName); + } + else // There is no pending track change ack : change is coming from phone/AVRC target + { + if (strcmp(incArtistName, artistName) != 0) // New Artist Name + { + strcpy(prevArtistName, artistName); // Preserve the previous artist name + strcpy(artistName, incArtistName); // Copy new artist name + _artistNameUpdated = true; + ESP_LOGD(__func__, "Artist name updated to %s", artistName); + } + else // Not new artist name + ESP_LOGD(__func__, "Artist name already updated to %s", artistName); + } + _checkAllMetaUpdated(); } -void esPod::updateTrackDuration(uint32_t trackDuration) +void esPod::updateTrackTitle(const char *incTrackTitle) { + if (trackChangeAckPending > 0x00) // There is a pending metadata update + { + if (!_trackTitleUpdated) // Track title not yet updated + { + strcpy(trackTitle, incTrackTitle); + _trackTitleUpdated = true; + ESP_LOGD(__func__, "Title update to %s", trackTitle); + } + else + ESP_LOGD(__func__, "Title already updated to %s", trackTitle); + } + else // There is no pending track change ack : change is coming from phone/AVRC target. + { + if (strcmp(incTrackTitle, trackTitle) != 0) // New track title, we assume it's a NEXT track because otherwise the comparison logic becomes heavy + { + // Assume it is Next, perform cursor operations + trackListPosition = (trackListPosition + 1) % TOTAL_NUM_TRACKS; + prevTrackIndex = currentTrackIndex; + currentTrackIndex = (currentTrackIndex + 1) % TOTAL_NUM_TRACKS; + trackList[trackListPosition] = (currentTrackIndex); + + strcpy(prevTrackTitle, trackTitle); // Preserve the previous track title + strcpy(trackTitle, incTrackTitle); // Update the new track title + _trackTitleUpdated = true; + ESP_LOGD(__func__, "Title update to %s", trackTitle); + // ESP_LOGD("AVRC_CB", + // "Title rxed, NO ACK pending, AUTONEXT, trackTitleUpdated " + // "to %s\n\ttrackPos %d trackIndex %d", + // trackTitle, trackListPosition, currentTrackIndex); + } + else // Track title is identical, no movement + { + ESP_LOGD(__func__, "Title already updated to : %s", trackTitle); + } + } + _checkAllMetaUpdated(); } -#pragma endregion - -//----------------------------------------------------------------------- -//| Process Lingo 0x00 Requests | -//----------------------------------------------------------------------- -#pragma region 0x00 Processor - -// /// @brief This function processes a shortened byteArray packet identified as a valid Lingo 0x00 request -// /// @param byteArray Shortened packet, with byteArray[0] being the Lingo 0x00 command ID byte -// /// @param len Length of valid data in the byteArray -// void esPod::processLingo0x00(const byte *byteArray, uint32_t len) -// { -// byte cmdID = byteArray[0]; -// // Switch through expected commandIDs -// switch (cmdID) -// { -// case L0x00_Identify: // Deprecated command observed on Audi by @BluCobalt -// { -// ESP_LOGI(IPOD_TAG, "CMD: 0x%02x Identify with Lingo 0x%02x", cmdID, byteArray[1]); -// // switch (byteArray[1]) -// // { -// // case 0x04: -// // extendedInterfaceModeActive = true; // Pre-empt ? -// // break; -// // default: -// // break; -// // } -// } -// break; - -// case L0x00_RequestExtendedInterfaceMode: // Mini requests extended interface mode status -// { -// ESP_LOGD(IPOD_TAG, "CMD: 0x%02x RequestExtendedInterfaceMode", cmdID); -// if (extendedInterfaceModeActive) -// { -// L0x00_0x04_ReturnExtendedInterfaceMode(0x01); // Report that extended interface mode is active -// } -// else -// { -// L0x00_0x04_ReturnExtendedInterfaceMode(0x00); // Report that extended interface mode is not active -// } -// } -// break; - -// case L0x00_EnterExtendedInterfaceMode: // Mini forces extended interface mode -// { -// ESP_LOGI(IPOD_TAG, "CMD: 0x%02x EnterExtendedInterfaceMode", cmdID); -// extendedInterfaceModeActive = true; -// L0x00_0x02_iPodAck(iPodAck_OK, cmdID); -// } -// break; - -// case L0x00_ExitExtendedInterfaceMode: // Mini exits extended interface mode -// { -// ESP_LOGI(IPOD_TAG, "CMD: 0x%02x ExitExtendedInterfaceMode", cmdID); -// if (extendedInterfaceModeActive) -// { -// L0x00_0x02_iPodAck(iPodAck_OK, cmdID); -// extendedInterfaceModeActive = false; -// playStatusNotificationState = NOTIF_OFF; -// } -// else -// { -// L0x00_0x02_iPodAck(iPodAck_BadParam, cmdID); -// } -// } -// break; - -// case L0x00_RequestiPodName: // Mini requests ipod name -// { -// ESP_LOGI(IPOD_TAG, "CMD: 0x%02x RequestiPodName", cmdID); -// L0x00_0x08_ReturniPodName(); -// } -// break; - -// case L0x00_RequestiPodSoftwareVersion: // Mini requests ipod software version -// { -// ESP_LOGI(IPOD_TAG, "CMD: 0x%02x RequestiPodSoftwareVersion", cmdID); -// L0x00_0x0A_ReturniPodSoftwareVersion(); -// } -// break; - -// case L0x00_RequestiPodSerialNum: // Mini requests ipod Serial Num -// { -// ESP_LOGI(IPOD_TAG, "CMD: 0x%02x RequestiPodSerialNum", cmdID); -// L0x00_0x0C_ReturniPodSerialNum(); -// } -// break; - -// case L0x00_RequestiPodModelNum: // Mini requests ipod Model Num -// { -// ESP_LOGI(IPOD_TAG, "CMD: 0x%02x RequestiPodModelNum", cmdID); -// L0x00_0x0E_ReturniPodModelNum(); -// } -// break; - -// case L0x00_RequestLingoProtocolVersion: // Mini requestsLingo Protocol Version -// { -// ESP_LOGI(IPOD_TAG, "CMD: 0x%02x RequestLingoProtocolVersion for Lingo 0x%02x", cmdID, byteArray[1]); -// L0x00_0x10_ReturnLingoProtocolVersion(byteArray[1]); -// } -// break; - -// case L0x00_IdentifyDeviceLingoes: // Mini identifies its lingoes, used as an ice-breaker -// { -// ESP_LOGI(IPOD_TAG, "CMD: 0x%02x IdentifyDeviceLingoes : L 0x%02x - Opt 0x%02x - ID 0x%02x", cmdID, byteArray[1], byteArray[2], byteArray[3]); -// L0x00_0x02_iPodAck(iPodAck_OK, cmdID); // Acknowledge, start capabilities pingpong -// // A bit spam-ish ? -// L0x00_0x27_GetAccessoryInfo(0x00); // Immediately request general capabilities -// L0x00_0x27_GetAccessoryInfo(0x01); // Request the name -// L0x00_0x27_GetAccessoryInfo(0x04); // Request the firmware version -// L0x00_0x27_GetAccessoryInfo(0x05); // Request the hardware number -// L0x00_0x27_GetAccessoryInfo(0x06); // Request the manufacturer name -// L0x00_0x27_GetAccessoryInfo(0x07); // Request the model number -// } -// break; - -// case L0x00_GetiPodOptions: // Mini requests iPod options -// { -// ESP_LOGI(IPOD_TAG, "CMD: 0x%02x GetiPodOptions", cmdID); -// L0x00_0x25_RetiPodOptions(); -// } - -// case L0x00_RetAccessoryInfo: // Mini returns info after L0x00_0x27 -// { -// ESP_LOGI(IPOD_TAG, "CMD: 0x%02x RetAccessoryInfo: 0x%02x", cmdID, byteArray[1]); -// switch (byteArray[1]) // Ping-pong the next request based on the current response -// { -// case 0x00: -// ESP_LOGI(IPOD_TAG, "\tAccessory Capabilities : 0x%02x", byteArray[2]); -// break; - -// case 0x01: -// ESP_LOGI(IPOD_TAG, "\tAccessory Name : %s", &byteArray[2]); -// break; - -// case 0x04: -// ESP_LOGI(IPOD_TAG, "\tAccessory Firmware : %d.%d.%d", byteArray[2], byteArray[3], byteArray[4]); -// break; - -// case 0x05: -// ESP_LOGI(IPOD_TAG, "\tAccessory Hardware : %d.%d.%d", byteArray[2], byteArray[3], byteArray[4]); -// break; - -// case 0x06: -// ESP_LOGI(IPOD_TAG, "\tAccessory Manufacturer : %s", &byteArray[2]); -// break; - -// case 0x07: -// ESP_LOGI(IPOD_TAG, "\tAccessory Model : %s", &byteArray[2]); -// break; - -// default: -// L0x00_0x02_iPodAck(iPodAck_OK, cmdID); -// break; -// } -// } -// break; - -// default: // In case the command is not known -// { -// ESP_LOGW(IPOD_TAG, "CMD 0x%02x not recognized.", cmdID); -// L0x00_0x02_iPodAck(cmdID, iPodAck_CmdFailed); -// } -// break; -// } -// } -#pragma endregion - -//----------------------------------------------------------------------- -//| Process Lingo 0x04 Requests | -//----------------------------------------------------------------------- -#pragma region 0x04 Processor - -// /// @brief This function processes a shortened byteArray packet identified as a valid Lingo 0x04 request -// /// @param byteArray Shortened packet, with byteArray[1] being the last byte of the Lingo 0x04 command -// /// @param len Length of valid data in the byteArray -// void esPod::processLingo0x04(const byte *byteArray, uint32_t len) -// { -// byte cmdID = byteArray[1]; -// // Initialising handlers to understand what is happening in some parts of the switch. They cannot be initialised in the switch-case scope -// byte category; -// uint32_t startIndex, counts, tempTrackIndex; - -// if (!extendedInterfaceModeActive) -// { // Complain if not in extended interface mode -// ESP_LOGW(IPOD_TAG, "CMD 0x%04x not executed : Not in extendedInterfaceMode!", cmdID); -// L0x04_0x01_iPodAck(iPodAck_BadParam, cmdID); -// } -// // Good to go if in Extended Interface mode -// else -// { -// switch (cmdID) // Reminder : we are technically switching on byteArray[1] now -// { -// case L0x04_GetIndexedPlayingTrackInfo: -// { -// tempTrackIndex = swap_endian(*((uint32_t *)&byteArray[3])); -// switch (byteArray[2]) // Switch on the type of track info requested (careful with overloads) -// { -// case 0x00: // General track Capabilities and Information -// ESP_LOGI(IPOD_TAG, "CMD 0x%04x GetIndexedPlayingTrackInfo 0x%02x for index %d (previous %d) : Duration", cmdID, byteArray[2], tempTrackIndex, prevTrackIndex); -// if (tempTrackIndex == prevTrackIndex) -// { -// L0x04_0x0D_ReturnIndexedPlayingTrackInfo((uint32_t)prevTrackDuration); -// } -// else -// { -// L0x04_0x0D_ReturnIndexedPlayingTrackInfo((uint32_t)trackDuration); -// } -// break; -// case 0x02: // Track Release Date (fictional) -// ESP_LOGI(IPOD_TAG, "CMD 0x%04x GetIndexedPlayingTrackInfo 0x%02x for index %d (previous %d) : Release date", cmdID, byteArray[2], tempTrackIndex, prevTrackIndex); -// L0x04_0x0D_ReturnIndexedPlayingTrackInfo(byteArray[2], (uint16_t)2001); -// break; -// case 0x01: // Track Title -// ESP_LOGI(IPOD_TAG, "CMD 0x%04x GetIndexedPlayingTrackInfo 0x%02x for index %d (previous %d) : Title", cmdID, byteArray[2], tempTrackIndex, prevTrackIndex); -// if (tempTrackIndex == prevTrackIndex) -// { -// L0x04_0x0D_ReturnIndexedPlayingTrackInfo(byteArray[2], prevTrackTitle); -// } -// else -// { -// L0x04_0x0D_ReturnIndexedPlayingTrackInfo(byteArray[2], trackTitle); -// } -// break; -// case 0x05: // Track Genre -// ESP_LOGI(IPOD_TAG, "CMD 0x%04x GetIndexedPlayingTrackInfo 0x%02x for index %d (previous %d) : Genre", cmdID, byteArray[2], tempTrackIndex, prevTrackIndex); -// L0x04_0x0D_ReturnIndexedPlayingTrackInfo(byteArray[2], trackGenre); -// break; -// case 0x06: // Track Composer -// ESP_LOGI(IPOD_TAG, "CMD 0x%04x GetIndexedPlayingTrackInfo 0x%02x for index %d (previous %d) : Composer", cmdID, byteArray[2], tempTrackIndex, prevTrackIndex); -// L0x04_0x0D_ReturnIndexedPlayingTrackInfo(byteArray[2], composer); -// break; -// default: // In case the request is beyond the track capabilities -// ESP_LOGW(IPOD_TAG, "CMD 0x%04x GetIndexedPlayingTrackInfo 0x%02x for index %d (previous %d) : Type not recognised!", cmdID, byteArray[2], tempTrackIndex, prevTrackIndex); -// L0x04_0x01_iPodAck(iPodAck_BadParam, cmdID); -// break; -// } -// } -// break; - -// case L0x04_RequestProtocolVersion: // Hardcoded return for L0x04 -// { -// ESP_LOGI(IPOD_TAG, "CMD 0x%04x RequestProtocolVersion", cmdID); -// L0x04_0x13_ReturnProtocolVersion(); // Potentially should use L0x00_0x10 instead ? L0x00_0x10_ReturnLingoProtocolVersion(byteArray[2]); -// // L0x00_0x27_GetAccessoryInfo(0x00); // Attempting to start normal handshake -// } -// break; - -// case L0x04_ResetDBSelection: // Not sure what to do here. Reset Current Track Index ? -// { -// ESP_LOGI(IPOD_TAG, "CMD 0x%04x ResetDBSelection", cmdID); -// L0x04_0x01_iPodAck(iPodAck_OK, cmdID); -// } -// break; - -// case L0x04_SelectDBRecord: // Used for browsing ? -// { -// ESP_LOGI(IPOD_TAG, "CMD 0x%04x SelectDBRecord", cmdID); -// L0x04_0x01_iPodAck(iPodAck_OK, cmdID); -// } -// break; - -// case L0x04_GetNumberCategorizedDBRecords: // Mini requests the number of records for a specific DB_CAT -// { -// category = byteArray[2]; -// ESP_LOGI(IPOD_TAG, "CMD 0x%04x GetNumberCategorizedDBRecords category: 0x%02x", cmdID, category); -// if (category == DB_CAT_TRACK) -// { -// L0x04_0x19_ReturnNumberCategorizedDBRecords(totalNumberTracks); // Say there are fixed, large amount of tracks -// } -// else -// { // And only one of anything else (Playlist, album, artist etc...) -// L0x04_0x19_ReturnNumberCategorizedDBRecords(1); -// } -// } -// break; - -// case L0x04_RetrieveCategorizedDatabaseRecords: // Loops through the desired records for a given DB_CAT -// { -// category = byteArray[2]; // DBCat -// startIndex = swap_endian(*(uint32_t *)&byteArray[3]); -// counts = swap_endian(*(uint32_t *)&byteArray[7]); - -// ESP_LOGI(IPOD_TAG, "CMD 0x%04x RetrieveCategorizedDatabaseRecords category: 0x%02x from %d for %d counts", cmdID, category, startIndex, counts); -// switch (category) -// { -// case DB_CAT_PLAYLIST: -// for (uint32_t i = startIndex; i < startIndex + counts; i++) -// { -// L0x04_0x1B_ReturnCategorizedDatabaseRecord(i, playList); -// } -// break; -// case DB_CAT_ARTIST: -// for (uint32_t i = startIndex; i < startIndex + counts; i++) -// { -// L0x04_0x1B_ReturnCategorizedDatabaseRecord(i, artistName); -// } -// break; -// case DB_CAT_ALBUM: -// for (uint32_t i = startIndex; i < startIndex + counts; i++) -// { -// L0x04_0x1B_ReturnCategorizedDatabaseRecord(i, albumName); -// } -// break; -// case DB_CAT_GENRE: -// for (uint32_t i = startIndex; i < startIndex + counts; i++) -// { -// L0x04_0x1B_ReturnCategorizedDatabaseRecord(i, trackGenre); -// } -// break; -// case DB_CAT_TRACK: // Will sometimes return twice -// for (uint32_t i = startIndex; i < startIndex + counts; i++) -// { -// L0x04_0x1B_ReturnCategorizedDatabaseRecord(i, trackTitle); -// } -// break; -// case DB_CAT_COMPOSER: -// for (uint32_t i = startIndex; i < startIndex + counts; i++) -// { -// L0x04_0x1B_ReturnCategorizedDatabaseRecord(i, composer); -// } -// break; -// default: -// ESP_LOGW(IPOD_TAG, "CMD 0x%04x RetrieveCategorizedDatabaseRecords category: 0x%02x not recognised", cmdID, category); -// L0x04_0x01_iPodAck(iPodAck_BadParam, cmdID); -// break; -// } -// } -// break; - -// case L0x04_GetPlayStatus: // Returns the current playStatus and the position/duration of the current track -// { -// ESP_LOGI(IPOD_TAG, "CMD 0x%04x GetPlayStatus", cmdID); -// L0x04_0x1D_ReturnPlayStatus(playPosition, trackDuration, playStatus); -// } -// break; - -// case L0x04_GetCurrentPlayingTrackIndex: // Get the uint32 index of the currently playing song -// { -// ESP_LOGI(IPOD_TAG, "CMD 0x%04x GetCurrentPlayingTrackIndex", cmdID); -// L0x04_0x1F_ReturnCurrentPlayingTrackIndex(currentTrackIndex); -// } -// break; - -// case L0x04_GetIndexedPlayingTrackTitle: -// { -// tempTrackIndex = swap_endian(*((uint32_t *)&byteArray[2])); -// ESP_LOGI(IPOD_TAG, "CMD 0x%04x GetIndexedPlayingTrackTitle for index %d (previous %d)", cmdID, tempTrackIndex, prevTrackIndex); -// if (tempTrackIndex == prevTrackIndex) -// { -// L0x04_0x21_ReturnIndexedPlayingTrackTitle(prevTrackTitle); -// } -// else -// { -// L0x04_0x21_ReturnIndexedPlayingTrackTitle(trackTitle); -// } -// } -// break; - -// case L0x04_GetIndexedPlayingTrackArtistName: -// { -// tempTrackIndex = swap_endian(*((uint32_t *)&byteArray[2])); - -// ESP_LOGI(IPOD_TAG, "CMD 0x%04x GetIndexedPlayingTrackArtistName for index %d (previous %d)", cmdID, tempTrackIndex, prevTrackIndex); -// if (tempTrackIndex == prevTrackIndex) -// { -// L0x04_0x23_ReturnIndexedPlayingTrackArtistName(prevArtistName); -// } -// else -// { -// L0x04_0x23_ReturnIndexedPlayingTrackArtistName(artistName); -// } -// } -// break; - -// case L0x04_GetIndexedPlayingTrackAlbumName: -// { -// tempTrackIndex = swap_endian(*((uint32_t *)&byteArray[2])); -// ESP_LOGI(IPOD_TAG, "CMD 0x%04x GetIndexedPlayingTrackAlbumName for index %d (previous %d)", cmdID, tempTrackIndex, prevTrackIndex); -// if (tempTrackIndex == prevTrackIndex) -// { -// L0x04_0x25_ReturnIndexedPlayingTrackAlbumName(prevAlbumName); -// } -// else -// { -// L0x04_0x25_ReturnIndexedPlayingTrackAlbumName(albumName); -// } -// } -// break; - -// case L0x04_SetPlayStatusChangeNotification: // Turns on basic notifications -// { -// playStatusNotificationState = byteArray[2]; -// ESP_LOGI(IPOD_TAG, "CMD 0x%04x SetPlayStatusChangeNotification 0x%02x", cmdID, playStatusNotificationState); -// L0x04_0x01_iPodAck(iPodAck_OK, cmdID); -// } -// break; - -// case L0x04_PlayCurrentSelection: // Used to play a specific index, usually for "next" commands, but may be used to actually jump anywhere -// { -// tempTrackIndex = swap_endian(*((uint32_t *)&byteArray[2])); -// ESP_LOGI(IPOD_TAG, "CMD 0x%04x PlayCurrentSelection index %d", cmdID, tempTrackIndex); -// if (playStatus != PB_STATE_PLAYING) -// { -// playStatus = PB_STATE_PLAYING; // Playing status forced -// if (_playStatusHandler) -// { -// _playStatusHandler(A2DP_PLAY); // Send play to the a2dp -// } -// } -// if (tempTrackIndex == trackList[(trackListPosition + TOTAL_NUM_TRACKS - 1) % TOTAL_NUM_TRACKS]) // Desired trackIndex is the left entry -// { -// // This is only for when the system requires the data of the previously active track -// prevTrackIndex = currentTrackIndex; -// strcpy(prevAlbumName, albumName); -// strcpy(prevArtistName, artistName); -// strcpy(prevTrackTitle, trackTitle); -// prevTrackDuration = trackDuration; - -// // Cursor operations for PREV -// trackListPosition = (trackListPosition + TOTAL_NUM_TRACKS - 1) % TOTAL_NUM_TRACKS; // Shift trackListPosition one to the right -// currentTrackIndex = tempTrackIndex; - -// // Engage the pending ACK for expected metadata -// trackChangeAckPending = cmdID; -// trackChangeTimestamp = millis(); -// ESP_LOGD(IPOD_TAG, "Prev. index %d New index %d Tracklist pos. %d Pending Meta %d Timestamp: %d --> PREV ", prevTrackIndex, currentTrackIndex, trackListPosition, (trackChangeAckPending > 0x00), trackChangeTimestamp); -// L0x04_0x01_iPodAck(iPodAck_CmdPending, cmdID, TRACK_CHANGE_TIMEOUT); - -// // Fire the A2DP when ready -// if (_playStatusHandler) -// _playStatusHandler(A2DP_PREV); // Fire the metadata trigger indirectly -// } -// else if (tempTrackIndex == currentTrackIndex) // Somehow reselecting the current track -// { -// ESP_LOGD(IPOD_TAG, "Selected same track as current: %d", tempTrackIndex); -// L0x04_0x01_iPodAck(iPodAck_OK, cmdID); - -// // Fire the A2DP when ready -// if (_playStatusHandler) -// _playStatusHandler(A2DP_PREV); // Fire the metadata trigger indirectly -// } -// else // If it is not the previous or the current track, it automatically becomes a next track -// { -// // This is only for when the system requires the data of the previously active track -// prevTrackIndex = currentTrackIndex; -// strcpy(prevAlbumName, albumName); -// strcpy(prevArtistName, artistName); -// strcpy(prevTrackTitle, trackTitle); -// prevTrackDuration = trackDuration; - -// // Cursor operations for NEXT -// trackListPosition = (trackListPosition + 1) % TOTAL_NUM_TRACKS; -// trackList[trackListPosition] = tempTrackIndex; -// currentTrackIndex = tempTrackIndex; - -// // Engage the pending ACK for expected metadata -// trackChangeAckPending = cmdID; -// trackChangeTimestamp = millis(); -// ESP_LOGD(IPOD_TAG, "Prev. index %d New index %d Tracklist pos. %d Pending Meta %d Timestamp: %d --> NEXT ", prevTrackIndex, currentTrackIndex, trackListPosition, (trackChangeAckPending > 0x00), trackChangeTimestamp); -// L0x04_0x01_iPodAck(iPodAck_CmdPending, cmdID, TRACK_CHANGE_TIMEOUT); - -// // Fire the A2DP when ready -// if (_playStatusHandler) -// _playStatusHandler(A2DP_NEXT); // Fire the metadata trigger indirectly -// } -// } -// break; - -// case L0x04_PlayControl: // Basic play control. Used for Prev, pause and play -// { -// ESP_LOGI(IPOD_TAG, "CMD 0x%04x PlayControl req: 0x%02x vs playStatus: 0x%02x", cmdID, byteArray[2], playStatus); -// switch (byteArray[2]) // PlayControl byte -// { -// case PB_CMD_TOGGLE: // Just Toggle or start playing -// { -// if (playStatus == PB_STATE_PLAYING) -// { -// playStatus = PB_STATE_PAUSED; // Toggle to paused if playing -// if (_playStatusHandler) -// _playStatusHandler(A2DP_PAUSE); -// } -// else -// { -// playStatus = PB_STATE_PLAYING; // Switch to playing in any other case -// if (_playStatusHandler) -// _playStatusHandler(A2DP_PLAY); -// } -// L0x04_0x01_iPodAck(iPodAck_OK, cmdID); -// } -// break; -// case PB_CMD_STOP: // Stop -// { -// playStatus = PB_STATE_STOPPED; -// if (_playStatusHandler) -// _playStatusHandler(A2DP_STOP); -// L0x04_0x01_iPodAck(iPodAck_OK, cmdID); -// } -// break; -// case PB_CMD_NEXT_TRACK: // Next track.. never seems to happen ? -// { -// // This is only for when the system requires the data of the previously active track -// prevTrackIndex = currentTrackIndex; -// strcpy(prevAlbumName, albumName); -// strcpy(prevArtistName, artistName); -// strcpy(prevTrackTitle, trackTitle); -// prevTrackDuration = trackDuration; - -// // Cursor operations for NEXT -// trackListPosition = (trackListPosition + 1) % TOTAL_NUM_TRACKS; -// currentTrackIndex = trackList[trackListPosition]; - -// // Engage the pending ACK for expected metadata -// trackChangeAckPending = cmdID; -// trackChangeTimestamp = millis(); -// ESP_LOGD(IPOD_TAG, "Prev. index %d New index %d Tracklist pos. %d Pending Meta %d Timestamp: %d --> EXPLICIT NEXT TRACK", prevTrackIndex, currentTrackIndex, trackListPosition, (trackChangeAckPending > 0x00), trackChangeTimestamp); -// L0x04_0x01_iPodAck(iPodAck_CmdPending, cmdID, TRACK_CHANGE_TIMEOUT); - -// // Fire the A2DP when ready -// if (_playStatusHandler) -// _playStatusHandler(A2DP_NEXT); // Fire the metadata trigger indirectly -// } -// break; -// case PB_CMD_PREVIOUS_TRACK: // Prev track -// { -// ESP_LOGD(IPOD_TAG, "Current index %d Tracklist pos. %d --> EXPLICIT SINGLE PREV TRACK", currentTrackIndex, trackListPosition); -// L0x04_0x01_iPodAck(iPodAck_OK, cmdID); - -// // Fire the A2DP when ready -// if (_playStatusHandler) -// _playStatusHandler(A2DP_PREV); // Fire the metadata trigger indirectly -// } -// break; -// case PB_CMD_NEXT: // Next track -// { -// // This is only for when the system requires the data of the previously active track -// prevTrackIndex = currentTrackIndex; -// strcpy(prevAlbumName, albumName); -// strcpy(prevArtistName, artistName); -// strcpy(prevTrackTitle, trackTitle); -// prevTrackDuration = trackDuration; - -// // Cursor operations for NEXT -// trackListPosition = (trackListPosition + 1) % TOTAL_NUM_TRACKS; -// currentTrackIndex = trackList[trackListPosition]; - -// // Engage the pending ACK for expected metadata -// trackChangeAckPending = cmdID; -// trackChangeTimestamp = millis(); -// ESP_LOGD(IPOD_TAG, "Prev. index %d New index %d Tracklist pos. %d Pending Meta %d Timestamp: %d --> EXPLICIT NEXT", prevTrackIndex, currentTrackIndex, trackListPosition, (trackChangeAckPending > 0x00), trackChangeTimestamp); -// L0x04_0x01_iPodAck(iPodAck_CmdPending, cmdID, TRACK_CHANGE_TIMEOUT); - -// // Fire the A2DP when ready -// if (_playStatusHandler) -// _playStatusHandler(A2DP_NEXT); // Fire the metadata trigger indirectly -// } -// break; -// case PB_CMD_PREV: // Prev track -// { -// ESP_LOGD(IPOD_TAG, "Current index %d Tracklist pos. %d --> EXPLICIT SINGLE PREV", currentTrackIndex, trackListPosition); -// L0x04_0x01_iPodAck(iPodAck_OK, cmdID); - -// // Fire the A2DP when ready -// if (_playStatusHandler) -// _playStatusHandler(A2DP_PREV); // Fire the metadata trigger indirectly -// } -// break; -// case PB_CMD_PLAY: // Play... do we need to have an ack pending ? -// { -// playStatus = PB_STATE_PLAYING; - -// // Engage the pending ACK for expected metadata -// trackChangeAckPending = cmdID; -// trackChangeTimestamp = millis(); -// L0x04_0x01_iPodAck(iPodAck_CmdPending, cmdID, TRACK_CHANGE_TIMEOUT); - -// if (_playStatusHandler) -// _playStatusHandler(A2DP_PLAY); -// } -// break; -// case PB_CMD_PAUSE: // Pause -// { -// playStatus = PB_STATE_PAUSED; -// L0x04_0x01_iPodAck(iPodAck_OK, cmdID); -// if (_playStatusHandler) -// _playStatusHandler(A2DP_PAUSE); -// } -// break; -// } -// if ((playStatus == PB_STATE_STOPPED) && (playStatusNotificationState == NOTIF_ON)) -// L0x04_0x27_PlayStatusNotification(0x00); // Notify successful stop -// } -// break; - -// case L0x04_GetShuffle: // Get Shuffle state from the PB Engine -// { -// ESP_LOGI(IPOD_TAG, "CMD 0x%04x GetShuffle", cmdID); -// L0x04_0x2D_ReturnShuffle(shuffleStatus); -// } -// break; - -// case L0x04_SetShuffle: // Set Shuffle state -// { -// ESP_LOGI(IPOD_TAG, "CMD 0x%04x SetShuffle req: 0x%02x vs shuffleStatus: 0x%02x", cmdID, byteArray[2], shuffleStatus); -// shuffleStatus = byteArray[2]; -// L0x04_0x01_iPodAck(iPodAck_OK, cmdID); -// } -// break; - -// case L0x04_GetRepeat: // Get Repeat state -// { -// ESP_LOGI(IPOD_TAG, "CMD 0x%04x GetRepeat", cmdID); -// L0x04_0x30_ReturnRepeat(repeatStatus); -// } -// break; - -// case L0x04_SetRepeat: // Set Repeat state -// { -// ESP_LOGI(IPOD_TAG, "CMD 0x%04x SetRepeat req: 0x%02x vs repeatStatus: 0x%02x", cmdID, byteArray[2], repeatStatus); -// repeatStatus = byteArray[2]; -// L0x04_0x01_iPodAck(iPodAck_OK, cmdID); -// } -// break; - -// case L0x04_GetNumPlayingTracks: // Systematically return TOTAL_NUM_TRACKS -// { -// ESP_LOGI(IPOD_TAG, "CMD 0x%04x GetNumPlayingTracks", cmdID); -// L0x04_0x36_ReturnNumPlayingTracks(totalNumberTracks); -// } -// break; - -// case L0x04_SetCurrentPlayingTrack: // Basically identical to PlayCurrentSelection -// { -// tempTrackIndex = swap_endian(*((uint32_t *)&byteArray[2])); -// ESP_LOGI(IPOD_TAG, "CMD 0x%04x SetCurrentPlayingTrack index %d", cmdID, tempTrackIndex); -// if (playStatus != PB_STATE_PLAYING) -// { -// playStatus = PB_STATE_PLAYING; // Playing status forced -// if (_playStatusHandler) -// { -// _playStatusHandler(A2DP_PLAY); // Send play to the a2dp -// } -// } -// if (tempTrackIndex == trackList[(trackListPosition + TOTAL_NUM_TRACKS - 1) % TOTAL_NUM_TRACKS]) // Desired trackIndex is the left entry -// { -// // This is only for when the system requires the data of the previously active track -// prevTrackIndex = currentTrackIndex; -// strcpy(prevAlbumName, albumName); -// strcpy(prevArtistName, artistName); -// strcpy(prevTrackTitle, trackTitle); -// prevTrackDuration = trackDuration; - -// // Cursor operations for PREV -// trackListPosition = (trackListPosition + TOTAL_NUM_TRACKS - 1) % TOTAL_NUM_TRACKS; // Shift trackListPosition one to the right -// currentTrackIndex = tempTrackIndex; - -// // Engage the pending ACK for expected metadata -// trackChangeAckPending = cmdID; -// trackChangeTimestamp = millis(); -// ESP_LOGD(IPOD_TAG, "Prev. index %d New index %d Tracklist pos. %d Pending Meta %d Timestamp: %d --> PREV ", prevTrackIndex, currentTrackIndex, trackListPosition, (trackChangeAckPending > 0x00), trackChangeTimestamp); -// L0x04_0x01_iPodAck(iPodAck_CmdPending, cmdID, TRACK_CHANGE_TIMEOUT); - -// // Fire the A2DP when ready -// if (_playStatusHandler) -// _playStatusHandler(A2DP_PREV); // Fire the metadata trigger indirectly -// } -// else if (tempTrackIndex == currentTrackIndex) // Somehow reselecting the current track -// { -// ESP_LOGD(IPOD_TAG, "Selected same track as current: %d", tempTrackIndex); -// L0x04_0x01_iPodAck(iPodAck_OK, cmdID); - -// // Fire the A2DP when ready -// if (_playStatusHandler) -// _playStatusHandler(A2DP_PREV); // Fire the metadata trigger indirectly -// } -// else // If it is not the previous or the current track, it automatically becomes a next track -// { -// // This is only for when the system requires the data of the previously active track -// prevTrackIndex = currentTrackIndex; -// strcpy(prevAlbumName, albumName); -// strcpy(prevArtistName, artistName); -// strcpy(prevTrackTitle, trackTitle); -// prevTrackDuration = trackDuration; - -// // Cursor operations for NEXT -// trackListPosition = (trackListPosition + 1) % TOTAL_NUM_TRACKS; -// trackList[trackListPosition] = tempTrackIndex; -// currentTrackIndex = tempTrackIndex; - -// // Engage the pending ACK for expected metadata -// trackChangeAckPending = cmdID; -// trackChangeTimestamp = millis(); -// ESP_LOGD(IPOD_TAG, "Prev. index %d New index %d Tracklist pos. %d Pending Meta %d Timestamp: %d --> NEXT ", prevTrackIndex, currentTrackIndex, trackListPosition, (trackChangeAckPending > 0x00), trackChangeTimestamp); -// L0x04_0x01_iPodAck(iPodAck_CmdPending, cmdID, TRACK_CHANGE_TIMEOUT); - -// // Fire the A2DP when ready -// if (_playStatusHandler) -// _playStatusHandler(A2DP_NEXT); // Fire the metadata trigger indirectly -// } -// } -// break; -// } -// } -// } -#pragma endregion - -//----------------------------------------------------------------------- -//| Lingo 0x00 subfunctions | -//----------------------------------------------------------------------- -#pragma region LINGO 0x00 - -// /// @brief Deprecated function to force the Accessory to restart Identify with L0x00_IdentifyDeviceLingoes -// void esPod::L0x00_0x00_RequestIdentify() -// { -// ESP_LOGI(IPOD_TAG, "iPod: RequestIdentify"); -// const byte txPacket[] = { -// 0x00, -// 0x00}; -// _queuePacket(txPacket, sizeof(txPacket)); -// } - -// /// @brief General response command for Lingo 0x00 -// /// @param cmdStatus Has to obey to iPodAck_xxx format as defined in L0x00.h -// /// @param cmdID ID (single byte) of the Lingo 0x00 command replied to -// void esPod::L0x00_0x02_iPodAck(byte cmdStatus, byte cmdID) -// { -// ESP_LOGI(IPOD_TAG, "Ack 0x%02x to command 0x%02x", cmdStatus, cmdID); -// // Queue the packet -// const byte txPacket[] = { -// 0x00, -// 0x02, -// cmdStatus, -// cmdID}; -// // Stop the timer if the same command is acknowledged before the elapsed time -// if (cmdID == _pendingCmdId_0x00) // If the command ID is the same as the pending one -// { -// stopTimer(_pendingTimer_0x00); // Stop the timer -// _pendingCmdId_0x00 = 0x00; // Reset the pending command -// _queuePacketToFront(txPacket, sizeof(txPacket)); // Jump the queue -// } -// else -// _queuePacket(txPacket, sizeof(txPacket)); -// } - -// /// @brief General response command for Lingo 0x00 with numerical field (used for Ack Pending). Has to be followed up with a normal iPodAck -// /// @param cmdStatus Unprotected, but should only be iPodAck_CmdPending -// /// @param cmdID Single byte ID of the command being acknowledged with Pending -// /// @param numField Pending delay in milliseconds -// void esPod::L0x00_0x02_iPodAck(byte cmdStatus, byte cmdID, uint32_t numField) -// { -// ESP_LOGI(IPOD_TAG, "Ack 0x%02x to command 0x%02x Numfield: %d", cmdStatus, cmdID, numField); -// const byte txPacket[20] = { -// 0x00, -// 0x02, -// cmdStatus, -// cmdID}; -// *((uint32_t *)&txPacket[4]) = swap_endian(numField); -// _queuePacket(txPacket, 4 + 4); -// // Starting delayed timer for the iPodAck -// _pendingCmdId_0x00 = cmdID; -// startTimer(_pendingTimer_0x00, numField); -// } - -// /// @brief Returns 0x01 if the iPod is in extendedInterfaceMode, or 0x00 if not -// /// @param extendedModeByte Direct value of the extendedInterfaceMode boolean -// void esPod::L0x00_0x04_ReturnExtendedInterfaceMode(byte extendedModeByte) -// { -// ESP_LOGD(IPOD_TAG, "Extended Interface mode: 0x%02x", extendedModeByte); -// const byte txPacket[] = { -// 0x00, -// 0x04, -// extendedModeByte}; -// _queuePacket(txPacket, sizeof(txPacket)); -// } - -// /// @brief Returns as a UTF8 null-ended char array, the _name of the iPod (not changeable during runtime) -// void esPod::L0x00_0x08_ReturniPodName() -// { -// ESP_LOGI(IPOD_TAG, "Name: %s", _name); -// byte txPacket[255] = {// Prealloc to len = FF -// 0x00, -// 0x08}; -// strcpy((char *)&txPacket[2], _name); -// _queuePacket(txPacket, 3 + strlen(_name)); -// } - -// /// @brief Returns the iPod Software Version -// void esPod::L0x00_0x0A_ReturniPodSoftwareVersion() -// { -// ESP_LOGI(IPOD_TAG, "SW version: %d.%d.%d", _SWMajor, _SWMinor, _SWrevision); -// byte txPacket[] = { -// 0x00, -// 0x0A, -// (byte)_SWMajor, -// (byte)_SWMinor, -// (byte)_SWrevision}; -// _queuePacket(txPacket, sizeof(txPacket)); -// } - -// /// @brief Returns the iPod Serial Number (which is a string) -// void esPod::L0x00_0x0C_ReturniPodSerialNum() -// { -// ESP_LOGI(IPOD_TAG, "Serial number: %s", _serialNumber); -// byte txPacket[255] = {// Prealloc to len = FF -// 0x00, -// 0x0C}; -// strcpy((char *)&txPacket[2], _serialNumber); -// _queuePacket(txPacket, 3 + strlen(_serialNumber)); -// } - -// /// @brief Returns the iPod model number PA146FD 720901, which corresponds to an iPod 5.5G classic -// void esPod::L0x00_0x0E_ReturniPodModelNum() -// { -// ESP_LOGI(IPOD_TAG, "Model number : PA146FD 720901"); -// byte txPacket[] = { -// 0x00, -// 0x0E, -// 0x00, 0x0B, 0x00, 0x05, 0x50, 0x41, 0x31, 0x34, 0x36, 0x46, 0x44, 0x00}; -// _queuePacket(txPacket, sizeof(txPacket)); -// } - -// /// @brief Returns a preprogrammed value for the Lingo Protocol Version for 0x00, 0x03 or 0x04 -// /// @param targetLingo Target Lingo for which the Protocol Version is desired. -// void esPod::L0x00_0x10_ReturnLingoProtocolVersion(byte targetLingo) -// { -// byte txPacket[] = { -// 0x00, 0x10, -// targetLingo, -// 0x01, 0x00}; -// switch (targetLingo) -// { -// case 0x00: // For General Lingo 0x00, version 1.6 -// txPacket[4] = 0x06; -// break; -// case 0x03: // For Lingo 0x03, version 1.5 -// txPacket[4] = 0x05; -// break; -// case 0x04: // For Lingo 0x04 (Extended Interface), version 1.12 -// txPacket[4] = 0x0C; -// break; -// case 0x0A: // Lingo 0x0A, digital audio, need to return 1.0 -// txPacket[4] = 0x00; -// break; -// } -// ESP_LOGI(IPOD_TAG, "Lingo 0x%02x protocol version: 1.%d", targetLingo, txPacket[4]); -// _queuePacket(txPacket, sizeof(txPacket)); -// } - -// /// @brief Query the accessory Info (model number, manufacturer, firmware version ...) using the target Info category hex -// /// @param desiredInfo Hex code for the type of information that is desired -// void esPod::L0x00_0x27_GetAccessoryInfo(byte desiredInfo) -// { -// ESP_LOGI(IPOD_TAG, "Req'd info type: 0x%02x", desiredInfo); -// byte txPacket[] = { -// 0x00, 0x27, -// desiredInfo}; -// _queuePacket(txPacket, sizeof(txPacket)); -// } - -// void esPod::L0x00_0x25_RetiPodOptions() -// { -// ESP_LOGI(IPOD_TAG, "Returning iPod Options"); -// byte txPacket[] = { -// 0x00, 0x25, -// 0x00}; -// _queuePacket(txPacket, sizeof(txPacket)); -// } - -#pragma endregion - -//----------------------------------------------------------------------- -//| Lingo 0x04 subfunctions | -//----------------------------------------------------------------------- -#pragma region LINGO 0x04 - -// /// @brief General response command for Lingo 0x04 -// /// @param cmdStatus Has to obey to iPodAck_xxx format as defined in L0x00.h -// /// @param cmdID last two ID bytes of the Lingo 0x04 command replied to -// void esPod::L0x04_0x01_iPodAck(byte cmdStatus, byte cmdID) -// { -// ESP_LOGI(IPOD_TAG, "Ack 0x%02x to command 0x%04x", cmdStatus, cmdID); -// // Queue the ack packet -// const byte txPacket[] = { -// 0x04, -// 0x00, 0x01, -// cmdStatus, -// 0x00, cmdID}; -// // Stop the timer if the same command is acknowledged before the elapsed time -// if (cmdID == _pendingCmdId_0x04) // If the pending command is the one being acknowledged -// { -// stopTimer(_pendingTimer_0x04); -// _pendingCmdId_0x04 = 0x00; -// _queuePacketToFront(txPacket, sizeof(txPacket)); // Jump the queue -// } -// else -// _queuePacket(txPacket, sizeof(txPacket)); // Queue at the back -// } - -// /// @brief General response command for Lingo 0x04 with numerical field (used for Ack Pending). Has to be followed up with a normal iPodAck -// /// @param cmdStatus Unprotected, but should only be iPodAck_CmdPending -// /// @param cmdID Single end-byte ID of the command being acknowledged with Pending -// /// @param numField Pending delay in milliseconds -// void esPod::L0x04_0x01_iPodAck(byte cmdStatus, byte cmdID, uint32_t numField) -// { -// ESP_LOGI(IPOD_TAG, "Ack 0x%02x to command 0x%04x Numfield: %d", cmdStatus, cmdID, numField); -// const byte txPacket[20] = { -// 0x04, -// 0x00, 0x01, -// cmdStatus, -// cmdID}; -// *((uint32_t *)&txPacket[5]) = swap_endian(numField); -// _queuePacket(txPacket, 5 + 4); -// // Starting delayed timer for the iPodAck -// _pendingCmdId_0x04 = cmdID; -// startTimer(_pendingTimer_0x04, numField); -// } - -// /// @brief Returns the pseudo-UTF8 string for the track info types 01/05/06 -// /// @param trackInfoType 0x01 : Title / 0x05 : Genre / 0x06 : Composer -// /// @param trackInfoChars Character array to pass and package in the tail of the message -// void esPod::L0x04_0x0D_ReturnIndexedPlayingTrackInfo(byte trackInfoType, char *trackInfoChars) -// { -// ESP_LOGI(IPOD_TAG, "Req'd track info type: 0x%02x", trackInfoType); -// byte txPacket[255] = { -// 0x04, -// 0x00, 0x0D, -// trackInfoType}; -// strcpy((char *)&txPacket[4], trackInfoChars); -// _queuePacket(txPacket, 4 + strlen(trackInfoChars) + 1); -// } - -// /// @brief Returns the playing track total duration in milliseconds (Implicit track info 0x00) -// /// @param trackDuration_ms trackduration in ms -// void esPod::L0x04_0x0D_ReturnIndexedPlayingTrackInfo(uint32_t trackDuration_ms) -// { -// ESP_LOGI(IPOD_TAG, "Track duration: %d", trackDuration_ms); -// byte txPacket[14] = { -// 0x04, -// 0x00, 0x0D, -// 0x00, -// 0x00, 0x00, 0x00, 0x00, // This says it does not have artwork etc -// 0x00, 0x00, 0x00, 0x01, // Track length in ms -// 0x00, 0x00 // Chapter count (none) -// }; -// *((uint32_t *)&txPacket[8]) = swap_endian(trackDuration_ms); -// _queuePacket(txPacket, sizeof(txPacket)); -// } - -// /// @brief Overloaded return of the playing track info : release year -// /// @param trackInfoType Can only be 0x02 -// /// @param releaseYear Fictional release year of the song -// void esPod::L0x04_0x0D_ReturnIndexedPlayingTrackInfo(byte trackInfoType, uint16_t releaseYear) -// { -// ESP_LOGI(IPOD_TAG, "Track info: 0x%02x Release Year: %d", trackInfoType, releaseYear); -// byte txPacket[12] = { -// 0x04, -// 0x00, 0x0D, -// trackInfoType, -// 0x00, 0x00, 0x00, 0x01, 0x01, // First of Jan at 00:00:00 -// 0x00, 0x00, // year goes here -// 0x01 // it was a Monday -// }; -// *((uint16_t *)&txPacket[9]) = swap_endian(releaseYear); -// _queuePacket(txPacket, sizeof(txPacket)); -// } - -// /// @brief Returns the L0x04 Lingo Protocol Version : hardcoded to 1.12, consistent with an iPod Classic 5.5G -// void esPod::L0x04_0x13_ReturnProtocolVersion() -// { -// ESP_LOGI(IPOD_TAG, "Lingo protocol version 1.12"); -// byte txPacket[] = { -// 0x04, -// 0x00, 0x13, -// 0x01, 0x0C // Protocol version 1.12 -// }; -// _queuePacket(txPacket, sizeof(txPacket)); -// } - -// /// @brief Return the number of records of a given DBCategory (Playlist, tracks...) -// /// @param categoryDBRecords The number of records to return -// void esPod::L0x04_0x19_ReturnNumberCategorizedDBRecords(uint32_t categoryDBRecords) -// { -// ESP_LOGI(IPOD_TAG, "Category DB Records: %d", categoryDBRecords); -// byte txPacket[7] = { -// 0x04, -// 0x00, 0x19, -// 0x00, 0x00, 0x00, 0x00}; -// *((uint32_t *)&txPacket[3]) = swap_endian(categoryDBRecords); -// _queuePacket(txPacket, sizeof(txPacket)); -// } - -// /// @brief Returns the metadata for a certain database record. Category is implicit -// /// @param index Index of the DBRecord -// /// @param recordString Metadata to include in the return -// void esPod::L0x04_0x1B_ReturnCategorizedDatabaseRecord(uint32_t index, char *recordString) -// { -// ESP_LOGI(IPOD_TAG, "Database record at index %d : %s", index, recordString); -// byte txPacket[255] = { -// 0x04, -// 0x00, 0x1B, -// 0x00, 0x00, 0x00, 0x00 // Index goes here -// }; -// *((uint32_t *)&txPacket[3]) = swap_endian(index); -// strcpy((char *)&txPacket[7], recordString); -// _queuePacket(txPacket, 7 + strlen(recordString) + 1); -// } - -// /// @brief Returns the current playback status, indicating the position out of the duration -// /// @param position Playing position in ms in the track -// /// @param duration Total duration of the track in ms -// /// @param playStatusArg Playback status (0x00 Stopped, 0x01 Playing, 0x02 Paused, 0xFF Error) -// void esPod::L0x04_0x1D_ReturnPlayStatus(uint32_t position, uint32_t duration, byte playStatusArg) -// { -// ESP_LOGI(IPOD_TAG, "Play status 0x%02x at pos. %d / %d ms", playStatusArg, position, duration); -// byte txPacket[] = { -// 0x04, -// 0x00, 0x1D, -// 0x00, 0x00, 0x00, 0x00, -// 0x00, 0x00, 0x00, 0x00, -// playStatusArg}; -// *((uint32_t *)&txPacket[3]) = swap_endian(duration); -// *((uint32_t *)&txPacket[7]) = swap_endian(position); -// _queuePacket(txPacket, sizeof(txPacket)); -// } - -// /// @brief Returns the "Index" of the currently playing track, useful for pulling matching metadata -// /// @param trackIndex The trackIndex to return. This is different from the position in the tracklist when Shuffle is ON -// void esPod::L0x04_0x1F_ReturnCurrentPlayingTrackIndex(uint32_t trackIndex) -// { -// ESP_LOGI(IPOD_TAG, "Track index: %d", trackIndex); -// byte txPacket[] = { -// 0x04, -// 0x00, 0x1F, -// 0x00, 0x00, 0x00, 0x00}; -// *((uint32_t *)&txPacket[3]) = swap_endian(trackIndex); -// _queuePacket(txPacket, sizeof(txPacket)); -// } - -// /// @brief Returns the track Title after an implicit call for it -// /// @param trackTitle Character array to return -// void esPod::L0x04_0x21_ReturnIndexedPlayingTrackTitle(char *trackTitle) -// { -// ESP_LOGI(IPOD_TAG, "Track title: %s", trackTitle); -// byte txPacket[255] = { -// 0x04, -// 0x00, 0x21}; -// strcpy((char *)&txPacket[3], trackTitle); -// _queuePacket(txPacket, 3 + strlen(trackTitle) + 1); -// } - -// /// @brief Returns the track Artist Name after an implicit call for it -// /// @param trackArtistName Character array to return -// void esPod::L0x04_0x23_ReturnIndexedPlayingTrackArtistName(char *trackArtistName) -// { -// ESP_LOGI(IPOD_TAG, "Track artist: %s", trackArtistName); -// byte txPacket[255] = { -// 0x04, -// 0x00, 0x23}; -// strcpy((char *)&txPacket[3], trackArtistName); -// _queuePacket(txPacket, 3 + strlen(trackArtistName) + 1); -// } - -// /// @brief Returns the track Album Name after an implicit call for it -// /// @param trackAlbumName Character array to return -// void esPod::L0x04_0x25_ReturnIndexedPlayingTrackAlbumName(char *trackAlbumName) -// { -// ESP_LOGI(IPOD_TAG, "Track album: %s", trackAlbumName); -// byte txPacket[255] = { -// 0x04, -// 0x00, 0x25}; -// strcpy((char *)&txPacket[3], trackAlbumName); -// _queuePacket(txPacket, 3 + strlen(trackAlbumName) + 1); -// } - -// /// @brief Only supports currently two types : 0x00 Playback Stopped, 0x01 Track index, 0x04 Track offset -// /// @param notification Notification type that can be returned : 0x01 for track index change, 0x04 for the track offset -// /// @param numField For 0x01 this is the new Track index, for 0x04 this is the current Track offset in ms -// void esPod::L0x04_0x27_PlayStatusNotification(byte notification, uint32_t numField) -// { -// ESP_LOGI(IPOD_TAG, "Play status 0x%02x Numfield: %d", notification, numField); -// byte txPacket[] = { -// 0x04, -// 0x00, 0x27, -// notification, -// 0x00, 0x00, 0x00, 0x00}; -// *((uint32_t *)&txPacket[4]) = swap_endian(numField); -// _queuePacket(txPacket, sizeof(txPacket)); -// } - -// /// @brief Returns the PlayStatusNotification when it is STOPPED (0x00) -// /// @param notification Can only be 0x00 -// void esPod::L0x04_0x27_PlayStatusNotification(byte notification) -// { -// ESP_LOGI(IPOD_TAG, "Play status 0x%02x STOPPED", notification); -// byte txPacket[] = { -// 0x04, -// 0x00, 0x27, -// notification}; -// _queuePacket(txPacket, sizeof(txPacket)); -// } - -// /// @brief Returns the current shuffle status of the PBEngine -// /// @param currentShuffleStatus 0x00 No Shuffle, 0x01 Tracks, 0x02 Albums -// void esPod::L0x04_0x2D_ReturnShuffle(byte currentShuffleStatus) -// { -// ESP_LOGI(IPOD_TAG, "Shuffle status: 0x%02x", currentShuffleStatus); -// byte txPacket[] = { -// 0x04, -// 0x00, 0x2D, -// currentShuffleStatus}; -// _queuePacket(txPacket, sizeof(txPacket)); -// } - -// /// @brief Returns the current repeat status of the PBEngine -// /// @param currentRepeatStatus 0x00 No Repeat, 0x01 One Track, 0x02 All tracks -// void esPod::L0x04_0x30_ReturnRepeat(byte currentRepeatStatus) -// { -// ESP_LOGI(IPOD_TAG, "Repeat status: 0x%02x", currentRepeatStatus); -// byte txPacket[] = { -// 0x04, -// 0x00, 0x30, -// currentRepeatStatus}; -// _queuePacket(txPacket, sizeof(txPacket)); -// } - -// /// @brief Returns the number of playing tracks in the current selection (here it is all the tracks) -// /// @param numPlayingTracks Number of playing tracks to return -// void esPod::L0x04_0x36_ReturnNumPlayingTracks(uint32_t numPlayingTracks) -// { -// ESP_LOGI(IPOD_TAG, "Playing tracks: %d", numPlayingTracks); -// byte txPacket[] = { -// 0x04, -// 0x00, 0x36, -// 0x00, 0x00, 0x00, 0x00}; -// *((uint32_t *)&txPacket[3]) = swap_endian(numPlayingTracks); -// _queuePacket(txPacket, sizeof(txPacket)); -// } +void esPod::updateTrackDuration(uint32_t incTrackDuration) +{ + if (trackChangeAckPending > 0x00) // There is a pending metadata update + { + if (!_trackDurationUpdated) // Track duration not yet updated + { + trackDuration = incTrackDuration; + _trackDurationUpdated = true; + ESP_LOGD(__func__, "Track duration updated to %d", trackDuration); + } + else + ESP_LOGD(__func__, "Track duration already updated to %d", trackDuration); + } + else // There is no pending track change ack : change is coming from phone/AVRC target. + { + if (incTrackDuration != trackDuration) // Different incoming metadata + { + prevTrackDuration = trackDuration; // Preserve the current value + trackDuration = incTrackDuration; // Then updated it + _trackDurationUpdated = true; + ESP_LOGD(__func__, "Track duration updated to %d", trackDuration); + } + else + ESP_LOGD(__func__, "Track duration already updated to %d", trackDuration); + } + _checkAllMetaUpdated(); +} #pragma endregion diff --git a/src/main.cpp b/src/main.cpp index 579974e..7cfcbe0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -201,6 +201,7 @@ static void processAVRCTask(void *pvParameters) char incArtistName[255] = "incArtist"; char incTrackTitle[255] = "incTitle"; uint32_t incTrackDuration = 0; + bool albumNameUpdated = false; bool artistNameUpdated = false; bool trackTitleUpdated = false; @@ -231,6 +232,8 @@ static void processAVRCTask(void *pvParameters) switch (incMetadata.id) { case ESP_AVRC_MD_ATTR_ALBUM: + + // espod.updateAlbumName((char *)incMetadata.payload); strcpy(incAlbumName, (char *)incMetadata.payload); // Buffer the incoming album string if (espod.trackChangeAckPending > 0x00) @@ -264,6 +267,7 @@ static void processAVRCTask(void *pvParameters) break; case ESP_AVRC_MD_ATTR_ARTIST: + // espod.updateArtistName((char *)incMetadata.payload); strcpy(incArtistName, (char *)incMetadata.payload); // Buffer the incoming artist string if (espod.trackChangeAckPending > 0x00) @@ -295,12 +299,14 @@ static void processAVRCTask(void *pvParameters) ESP_LOGD("AVRC_CB", "Artist rxed, NO ACK pending, already updated to %s", espod.artistName); } } + break; case ESP_AVRC_MD_ATTR_TITLE: // Title change triggers the NEXT track - // assumption if unexpected. It is too - // intensive to try to do NEXT/PREV - // guesswork + // assumption if unexpected. It is too + // intensive to try to do NEXT/PREV + // guesswork + // espod.updateTrackTitle((char *)incMetadata.payload); strcpy(incTrackTitle, (char *)incMetadata.payload); // Buffer the incoming track title if (espod.trackChangeAckPending > 0x00) @@ -344,6 +350,7 @@ static void processAVRCTask(void *pvParameters) break; case ESP_AVRC_MD_ATTR_PLAYING_TIME: + // espod.updateTrackDuration(String((char *)incMetadata.payload).toInt()); incTrackDuration = String((char *)incMetadata.payload).toInt(); if (espod.trackChangeAckPending > 0x00) { // There is a pending metadata update @@ -380,6 +387,7 @@ static void processAVRCTask(void *pvParameters) } // Check if it is time to send a notification + // Implicitely called in the ones above. if (albumNameUpdated && artistNameUpdated && trackTitleUpdated && trackDurationUpdated) { // If all fields have received at least one update and the @@ -491,8 +499,6 @@ void initializeA2DPSink() ESP_LOGI("SETUP", "a2dp_sink started: %s", A2DP_SINK_NAME); delay(5); - - } /// @brief Initializes the AVRC metadata queue, and attempts to start the @@ -562,18 +568,14 @@ void audioStateChanged(esp_a2d_audio_state_t state, void *ptr) switch (state) { case ESP_A2D_AUDIO_STATE_STARTED: - espod.playStatus = PB_STATE_PLAYING; - ESP_LOGD("A2DP_CB", "ESP_A2D_AUDIO_STATE_STARTED, espod.playStatus = PB_STATE_PLAYING"); + espod.play(); break; case ESP_A2D_AUDIO_STATE_REMOTE_SUSPEND: - espod.playStatus = PB_STATE_PAUSED; - ESP_LOGD("A2DP_CB", "ESP_A2D_AUDIO_STATE_REMOTE_SUSPEND, espod.playStatus " - "= PB_STATE_PAUSED"); + espod.pause(); break; - // case ESP_A2D_AUDIO_STATE_STOPPED: - // espod.playStatus = PB_STATE_STOPPED; - // ESP_LOGD("A2DP_CB", "ESP_A2D_AUDIO_STATE_STOPPED, espod.playStatus = PB_STATE_STOPPED"); - // break; + // case ESP_A2D_AUDIO_STATE_STOPPED: + // espod.stop(); + // break; } } @@ -582,13 +584,14 @@ void audioStateChanged(esp_a2d_audio_state_t state, void *ptr) /// @param play_pos Playing Position in ms void avrc_rn_play_pos_callback(uint32_t play_pos) { - espod.playPosition = play_pos; + espod.updatePlayPosition(play_pos); + // espod.playPosition = play_pos; ESP_LOGV("AVRC_CB", "PlayPosition called"); - if (espod.playStatusNotificationState == NOTIF_ON && espod.trackChangeAckPending == 0x00) - { - // espod.L0x04_0x27_PlayStatusNotification(0x04, play_pos); - L0x04::_0x27_PlayStatusNotification(&espod, 0x04, play_pos); - } + // if (espod.playStatusNotificationState == NOTIF_ON && espod.trackChangeAckPending == 0x00) + // { + // // espod.L0x04_0x27_PlayStatusNotification(0x04, play_pos); + // L0x04::_0x27_PlayStatusNotification(&espod, 0x04, play_pos); + // } } /// @brief Catch callback for the AVRC metadata. There can be duplicates ! From 816b8b79f43e9db8a56917aa1d11ec4889e0699d Mon Sep 17 00:00:00 2001 From: Martin ROGER Date: Tue, 17 Feb 2026 20:08:21 +0100 Subject: [PATCH 3/6] Simplification --- platformio.ini | 101 +++++++++++++++------------ src/main.cpp | 185 ++----------------------------------------------- 2 files changed, 60 insertions(+), 226 deletions(-) diff --git a/platformio.ini b/platformio.ini index 33f82ca..01c2374 100644 --- a/platformio.ini +++ b/platformio.ini @@ -25,23 +25,23 @@ lib_deps = monitor_filters = esp32_exception_decoder monitor_speed = 115200 -[env:audioKit_topHat] -board = audioKit -build_flags = - ${env.build_flags} - -D BOARD_HAS_PSRAM - -D AUDIOKIT - -D INVERT_LED_LOGIC - -D LED_BUILTIN=18 - -D CORE_DEBUG_LEVEL=0 +; [env:audioKit_topHat] +; board = audioKit +; build_flags = +; ${env.build_flags} +; -D BOARD_HAS_PSRAM +; -D AUDIOKIT +; -D INVERT_LED_LOGIC +; -D LED_BUILTIN=18 +; -D CORE_DEBUG_LEVEL=0 -[env:audioKit_topHat_SDUpdaterOnly] -extends = env:audioKit_topHat -build_type = debug -board_build.partitions = min_spiffs.csv -build_flags = - ${env:audioKit_topHat.build_flags} - -D USE_SD +; [env:audioKit_topHat_SDUpdaterOnly] +; extends = env:audioKit_topHat +; build_type = debug +; board_build.partitions = min_spiffs.csv +; build_flags = +; ${env:audioKit_topHat.build_flags} +; -D USE_SD ; [env:audioKit_topHat_SDLogger] ; extends = env:audioKit_topHat @@ -66,18 +66,18 @@ build_flags = ; ${env:audioKit_topHat_SDLogger.build_flags} ; -D USE_ALT_SERIAL -[env:audioKit_topHat_altSerial] -extends = env:audioKit_topHat -build_type = debug -board_build.partitions = min_spiffs.csv -build_flags = - ${env.build_flags} - -D BOARD_HAS_PSRAM - -D AUDIOKIT - -D INVERT_LED_LOGIC - -D LED_BUILTIN=18 - -D CORE_DEBUG_LEVEL=3 - -D USE_ALT_SERIAL +; [env:audioKit_topHat_altSerial] +; extends = env:audioKit_topHat +; build_type = debug +; board_build.partitions = min_spiffs.csv +; build_flags = +; ${env.build_flags} +; -D BOARD_HAS_PSRAM +; -D AUDIOKIT +; -D INVERT_LED_LOGIC +; -D LED_BUILTIN=18 +; -D CORE_DEBUG_LEVEL=3 +; -D USE_ALT_SERIAL [env:SBC_ESP32DevKitC] build_flags = @@ -95,7 +95,16 @@ board = nodemcu-32s lib_ignore = audio-driver [env:a1sMini] -extends = env:audioKit_topHat +; board = audioKit +; build_flags = +; ${env.build_flags} +; -D BOARD_HAS_PSRAM +; -D AUDIOKIT +; -D INVERT_LED_LOGIC +; -D LED_BUILTIN=18 +; -D CORE_DEBUG_LEVEL=0 +; extends = env:audioKit_topHat +board = audioKit build_type = debug board_build.partitions = min_spiffs.csv build_flags = @@ -131,20 +140,20 @@ lib_ignore = audio-driver -[env:BluCobalt] -build_flags = - ${env.build_flags} - -D CORE_DEBUG_LEVEL=3 - ;-D INVERT_LED_LOGIC - -D IPOD_SERIAL_BAUDRATE=57600 - ; -D SERIAL_TIMEOUT=60000 - ; -D INVERT_DCD_LOGIC - ; -D ENABLE_ACTIVE_DCD - -D RX_TASK_INTERVAL_MS=5 - -D PROCESS_INTERVAL_MS=7 - -D TX_INTERVAL_MS=10 - -D TIMER_INTERVAL_MS=2 - -D NO_RESET_ON_SERIAL_TIMEOUT - -D ESPIPOD_NAME="\"BluCobalt-o-pod"\" -board = esp32dev -lib_ignore = audio-driver +; [env:BluCobalt] +; build_flags = +; ${env.build_flags} +; -D CORE_DEBUG_LEVEL=3 +; ;-D INVERT_LED_LOGIC +; -D IPOD_SERIAL_BAUDRATE=57600 +; ; -D SERIAL_TIMEOUT=60000 +; ; -D INVERT_DCD_LOGIC +; ; -D ENABLE_ACTIVE_DCD +; -D RX_TASK_INTERVAL_MS=5 +; -D PROCESS_INTERVAL_MS=7 +; -D TX_INTERVAL_MS=10 +; -D TIMER_INTERVAL_MS=2 +; -D NO_RESET_ON_SERIAL_TIMEOUT +; -D ESPIPOD_NAME="\"BluCobalt-o-pod"\" +; board = esp32dev +; lib_ignore = audio-driver diff --git a/src/main.cpp b/src/main.cpp index 7cfcbe0..6dce7a9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -233,197 +233,22 @@ static void processAVRCTask(void *pvParameters) { case ESP_AVRC_MD_ATTR_ALBUM: - // espod.updateAlbumName((char *)incMetadata.payload); - strcpy(incAlbumName, - (char *)incMetadata.payload); // Buffer the incoming album string - if (espod.trackChangeAckPending > 0x00) - { // There is a pending metadata update - if (!albumNameUpdated) - { // The album Name has not been updated yet - strcpy(espod.albumName, incAlbumName); - albumNameUpdated = true; - ESP_LOGD("AVRC_CB", "Album rxed, ACK pending, albumNameUpdated to %s", espod.albumName); - } - else - { - ESP_LOGD("AVRC_CB", "Album rxed, ACK pending, already updated to %s", espod.albumName); - } - } - else - { // There is no pending track change from iPod : active or - // passive track change from avrc target - if (strcmp(incAlbumName, espod.albumName) != 0) - { // Different incoming metadata - strcpy(espod.prevAlbumName, espod.albumName); - strcpy(espod.albumName, incAlbumName); - albumNameUpdated = true; - ESP_LOGD("AVRC_CB", "Album rxed, NO ACK pending, albumNameUpdated to %s", espod.albumName); - } - else - { // Despammer for double sends - ESP_LOGD("AVRC_CB", "Album rxed, NO ACK pending, already updated to %s", espod.albumName); - } - } + espod.updateAlbumName((char *)incMetadata.payload); break; case ESP_AVRC_MD_ATTR_ARTIST: - // espod.updateArtistName((char *)incMetadata.payload); - strcpy(incArtistName, - (char *)incMetadata.payload); // Buffer the incoming artist string - if (espod.trackChangeAckPending > 0x00) - { // There is a pending metadata update - if (!artistNameUpdated) - { // The artist name has not been updated - // yet - strcpy(espod.artistName, incArtistName); - artistNameUpdated = true; - ESP_LOGD("AVRC_CB", "Artist rxed, ACK pending, artistNameUpdated to %s", espod.artistName); - } - else - { - ESP_LOGD("AVRC_CB", "Artist rxed, ACK pending, already updated to %s", espod.artistName); - } - } - else - { // There is no pending track change from iPod : active or - // passive track change from avrc target - if (strcmp(incArtistName, espod.artistName) != 0) - { // Different incoming metadata - strcpy(espod.prevArtistName, espod.artistName); - strcpy(espod.artistName, incArtistName); - artistNameUpdated = true; - ESP_LOGD("AVRC_CB", "Artist rxed, NO ACK pending, artistNameUpdated to %s", espod.artistName); - } - else - { // Despammer for double sends - ESP_LOGD("AVRC_CB", "Artist rxed, NO ACK pending, already updated to %s", espod.artistName); - } - } - + espod.updateArtistName((char *)incMetadata.payload); break; - case ESP_AVRC_MD_ATTR_TITLE: // Title change triggers the NEXT track - // assumption if unexpected. It is too - // intensive to try to do NEXT/PREV - // guesswork - // espod.updateTrackTitle((char *)incMetadata.payload); - strcpy(incTrackTitle, - (char *)incMetadata.payload); // Buffer the incoming track title - if (espod.trackChangeAckPending > 0x00) - { // There is a pending metadata update - if (!trackTitleUpdated) - { // The track title has not been updated - // yet - strcpy(espod.trackTitle, incTrackTitle); - trackTitleUpdated = true; - ESP_LOGD("AVRC_CB", "Title rxed, ACK pending, trackTitleUpdated to %s", espod.trackTitle); - } - else - { - ESP_LOGD("AVRC_CB", "Title rxed, ACK pending, already updated to %s", espod.trackTitle); - } - } - else - { // There is no pending track change from iPod : active or - // passive track change from avrc target - if (strcmp(incTrackTitle, espod.trackTitle) != 0) - { // Different from current track Title -> Systematic NEXT - // Assume it is Next, perform cursor operations - espod.trackListPosition = (espod.trackListPosition + 1) % TOTAL_NUM_TRACKS; - espod.prevTrackIndex = espod.currentTrackIndex; - espod.currentTrackIndex = (espod.currentTrackIndex + 1) % TOTAL_NUM_TRACKS; - espod.trackList[espod.trackListPosition] = (espod.currentTrackIndex); - // Copy new title and flag that data has been updated - strcpy(espod.prevTrackTitle, espod.trackTitle); - strcpy(espod.trackTitle, incTrackTitle); - trackTitleUpdated = true; - ESP_LOGD("AVRC_CB", - "Title rxed, NO ACK pending, AUTONEXT, trackTitleUpdated " - "to %s\n\ttrackPos %d trackIndex %d", - espod.trackTitle, espod.trackListPosition, espod.currentTrackIndex); - } - else - { // Despammer for double sends - ESP_LOGD("AVRC_CB", "Title rxed, NO ACK pending, same name : %s", espod.trackTitle); - } - } + case ESP_AVRC_MD_ATTR_TITLE: // Title change triggers the NEXT track if unexpected + espod.updateTrackTitle((char *)incMetadata.payload); break; case ESP_AVRC_MD_ATTR_PLAYING_TIME: - // espod.updateTrackDuration(String((char *)incMetadata.payload).toInt()); - incTrackDuration = String((char *)incMetadata.payload).toInt(); - if (espod.trackChangeAckPending > 0x00) - { // There is a pending metadata update - if (!trackDurationUpdated) - { // The duration has not been updated - // yet - espod.trackDuration = incTrackDuration; - trackDurationUpdated = true; - ESP_LOGD("AVRC_CB", "Duration rxed, ACK pending, trackDurationUpdated to %d", - espod.trackDuration); - } - else - { - ESP_LOGD("AVRC_CB", "Duration rxed, ACK pending, already updated to %d", espod.trackDuration); - } - } - else - { // There is no pending track change from iPod : active or - // passive track change from avrc target - if (incTrackDuration != espod.trackDuration) - { // Different incoming metadata - espod.trackDuration = incTrackDuration; - trackDurationUpdated = true; - ESP_LOGD("AVRC_CB", "Duration rxed, NO ACK pending, trackDurationUpdated to %d", - espod.trackDuration); - } - else - { // Despammer for double sends - ESP_LOGD("AVRC_CB", "Duration rxed, NO ACK pending, already updated to %d", - espod.trackDuration); - } - } + espod.updateTrackDuration(String((char *)incMetadata.payload).toInt()); break; } - // Check if it is time to send a notification - // Implicitely called in the ones above. - if (albumNameUpdated && artistNameUpdated && trackTitleUpdated && trackDurationUpdated) - { - // If all fields have received at least one update and the - // trackChangeAckPending is still hanging. The failsafe for this one is - // in the espod _processTask - if (espod.trackChangeAckPending > 0x00) - { - ESP_LOGD("AVRC_CB", - "Artist+Album+Title+Duration +++ ACK Pending " - "0x%x\n\tPending duration: %d", - espod.trackChangeAckPending, millis() - espod.trackChangeTimestamp); - // espod.L0x04_0x01_iPodAck(iPodAck_OK, espod.trackChangeAckPending); - if (espod.trackChangeAckPending == 0x11) - { - L0x03::_0x00_iPodAck(&espod, iPodAck_OK, espod.trackChangeAckPending); - } - else - { - L0x04::_0x01_iPodAck(&espod, iPodAck_OK, espod.trackChangeAckPending); - } - espod.trackChangeAckPending = 0x00; - ESP_LOGD("AVRC_CB", "trackChangeAckPending reset to 0x00"); - } - albumNameUpdated = false; - artistNameUpdated = false; - trackTitleUpdated = false; - trackDurationUpdated = false; - ESP_LOGD("AVRC_CB", "Artist+Album+Title+Duration : True -> False"); - // Inform the car - if (espod.playStatusNotificationState == NOTIF_ON) - { - // espod.L0x04_0x27_PlayStatusNotification(0x01, espod.currentTrackIndex); - L0x04::_0x27_PlayStatusNotification(&espod, 0x01, espod.currentTrackIndex); - } - } - // End Processing, deallocate memory delete[] incMetadata.payload; incMetadata.payload = nullptr; From 08c66492e1a96bdd3c4f92eac501f6b147b4c86c Mon Sep 17 00:00:00 2001 From: Martin ROGER Date: Tue, 17 Feb 2026 21:01:40 +0100 Subject: [PATCH 4/6] Configuration correction --- include/esPod_conf.h | 5 ----- src/main.cpp | 24 +++++++++++++++--------- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/include/esPod_conf.h b/include/esPod_conf.h index dee7578..1e25e8b 100644 --- a/include/esPod_conf.h +++ b/include/esPod_conf.h @@ -1,11 +1,6 @@ #pragma once #include "Arduino.h" -// A2DP instance name -#ifndef A2DP_SINK_NAME -#define A2DP_SINK_NAME "espiPod" -#endif - // ESPiPod instance name #ifndef ESPIPOD_NAME #define ESPIPOD_NAME "ipodESP32" diff --git a/src/main.cpp b/src/main.cpp index 6dce7a9..8492042 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4,6 +4,12 @@ #include "BluetoothA2DPSink.h" #include "esPod.h" +// A2DP instance name +#ifndef A2DP_SINK_NAME +#define A2DP_SINK_NAME "espiPod" +#endif + + #pragma region Board IO Macros // LED Logic inversion #ifndef INVERT_LED_LOGIC @@ -197,15 +203,15 @@ static void processAVRCTask(void *pvParameters) { avrcMetadata incMetadata; // Incoming metadata (pointer to payload) // Metadata buffers - char incAlbumName[255] = "incAlbum"; - char incArtistName[255] = "incArtist"; - char incTrackTitle[255] = "incTitle"; - uint32_t incTrackDuration = 0; - - bool albumNameUpdated = false; - bool artistNameUpdated = false; - bool trackTitleUpdated = false; - bool trackDurationUpdated = false; + // char incAlbumName[255] = "incAlbum"; + // char incArtistName[255] = "incArtist"; + // char incTrackTitle[255] = "incTitle"; + // uint32_t incTrackDuration = 0; + + // bool albumNameUpdated = false; + // bool artistNameUpdated = false; + // bool trackTitleUpdated = false; + // bool trackDurationUpdated = false; #ifdef STACK_HIGH_WATERMARK_LOG UBaseType_t uxHighWaterMark; From f9eb6315257453563db179bbac88f4c64f664f1c Mon Sep 17 00:00:00 2001 From: Martin ROGER Date: Tue, 17 Feb 2026 21:23:45 +0100 Subject: [PATCH 5/6] External esPod library --- include/L0x00.h | 58 --- include/L0x03.h | 49 --- include/L0x04.h | 71 ---- include/esPod.h | 193 --------- include/esPod_conf.h | 75 ---- include/esPod_utils.h | 157 -------- platformio.ini | 145 +++---- src/L0x00.cpp | 337 ---------------- src/L0x03.cpp | 486 ----------------------- src/L0x04.cpp | 896 ------------------------------------------ src/esPod.cpp | 746 ----------------------------------- 11 files changed, 64 insertions(+), 3149 deletions(-) delete mode 100644 include/L0x00.h delete mode 100644 include/L0x03.h delete mode 100644 include/L0x04.h delete mode 100644 include/esPod.h delete mode 100644 include/esPod_conf.h delete mode 100644 include/esPod_utils.h delete mode 100644 src/L0x00.cpp delete mode 100644 src/L0x03.cpp delete mode 100644 src/L0x04.cpp delete mode 100644 src/esPod.cpp diff --git a/include/L0x00.h b/include/L0x00.h deleted file mode 100644 index b6695bb..0000000 --- a/include/L0x00.h +++ /dev/null @@ -1,58 +0,0 @@ -#pragma once -#include "Arduino.h" -#include "esPod_utils.h" -class esPod; - -#define L0x00_Identify 0x01 -#define L0x00_RequestExtendedInterfaceMode 0x03 -#define L0x00_EnterExtendedInterfaceMode 0x05 -#define L0x00_ExitExtendedInterfaceMode 0x06 -#define L0x00_RequestiPodName 0x07 -#define L0x00_RequestiPodSoftwareVersion 0x09 -#define L0x00_RequestiPodSerialNum 0x0B -#define L0x00_RequestiPodModelNum 0x0D -#define L0x00_RequestLingoProtocolVersion 0x0F -#define L0x00_IdentifyDeviceLingoes 0x13 -#define L0x00_GetiPodOptions 0x24 -#define L0x00_RetAccessoryInfo 0x28 - -class L0x00 -{ -public: - static void processLingo(esPod *esp, const byte *byteArray, uint32_t len); - - static void _0x00_RequestIdentify(esPod *esp); - static void _0x02_iPodAck(esPod *esp, IPOD_ACK_CODE ackCode, byte cmdID); - static void _0x02_iPodAck(esPod *esp, IPOD_ACK_CODE ackCode, byte cmdID, uint32_t numField); - static void _0x04_ReturnExtendedInterfaceMode(esPod *esp, byte extendedModeByte); - static void _0x08_ReturniPodName(esPod *esp); - static void _0x0A_ReturniPodSoftwareVersion(esPod *esp); - static void _0x0C_ReturniPodSerialNum(esPod *esp); - static void _0x0E_ReturniPodModelNum(esPod *esp); - static void _0x10_ReturnLingoProtocolVersion(esPod *esp, byte targetLingo); - // static void _0x12_ReturnTransportMaxPayloadSize(esPod *esp); - // static void _0x14_GetAccessoryAuthenticationInfo(esPod *esp); - // static void _0x16_AckAccessoryAuthenticationInfo(esPod *esp); - // static void _0x17_GetAccessoryAuthenticationSignature(esPod *esp); - // static void _0x19_AckAccessoryAuthenticationStatus(esPod *esp); - // static void _0x1B_RetiPodAuthenticationInfo(esPod *esp); - // static void _0x1E_RetiPodAuthenticationSignature(esPod *esp); - // static void _0x23_NotifyiPodStateChange(esPod *esp, byte stateChg); - static void _0x25_RetiPodOptions(esPod *esp, uint64_t optBitField); - static void _0x27_GetAccessoryInfo(esPod *esp, byte desiredInfo); - // static void _0x2A_RetiPodPreferences(esPod *esp); - // static void _0x36_RetUIMode(esPod *esp); - // static void _0x3A_AckFIDTokenValues(esPod *esp); - // static void _0x3C_IDPSStatus(esPod *esp); - // static void _0x3F_OpenDataSessionForProtocol(esPod *esp); - // static void _0x40_CloseDataSession(esPod *esp); - // static void _0x43_iPodDataTransfer(esPod *esp); - // static void _0x46_SetAccessoryStatusNotification(esPod *esp); - // static void _0x4A_iPodNotification(esPod *esp); - // static void _0x4C_RetiPodOptionsForLingo(esPod *esp); - // static void _0x4E_RetEventNotification(esPod *esp); - // static void _0x51_RetSupportedEventNotification(esPod *esp); - // static void _0x66_RetNowPlayingApplicationBundleName(esPod *esp); - // static void _0x68_RetLocalizationInfo(esPod *esp); - // static void _0x6A_WiFiConnectionInfo(esPod *esp); -}; diff --git a/include/L0x03.h b/include/L0x03.h deleted file mode 100644 index 5a2018b..0000000 --- a/include/L0x03.h +++ /dev/null @@ -1,49 +0,0 @@ -#pragma once -#include "Arduino.h" -#include "esPod_utils.h" -class esPod; - -#define L0x03_GetCurrentEQProfileIndex 0x01 -#define L0x03_SetCurrentEQProfileIndex 0x03 -#define L0x03_GetNumEQProfiles 0x04 -#define L0x03_GetIndexedEQProfileName 0x06 -#define L0x03_SetRemoteEventNotification 0x08 -#define L0x03_GetRemoteEventStatus 0x0A -#define L0x03_GetiPodStateInfo 0x0C -#define L0x03_SetiPodStateInfo 0x0E -#define L0x03_GetPlayStatus 0x0F -#define L0x03_SetCurrentPlayingTrack 0x11 -#define L0x03_GetIndexedPlayingTrackInfo 0x12 -#define L0x03_GetNumPlayingTracks 0x14 -#define L0x03_GetArtworkFormats 0x16 -#define L0x03_GetTrackArtworkData 0x18 -#define L0x03_GetPowerBatteryState 0x1A -#define L0x03_GetSoundCheckState 0x1C -#define L0x03_SetSoundCheckState 0x1E -#define L0x03_GetTrackArtworkTimes 0x1F -#define L0x03_CreateGeniusPlaylist 0x21 -#define L0x03_IsGeniusAvailableForTrack 0x22 - -class L0x03 -{ - -public: - static void processLingo(esPod *esp, const byte *byteArray, uint32_t len); - static void _0x00_iPodAck(esPod *esp, IPOD_ACK_CODE ackCode, byte cmdID); - static void _0x00_iPodAck(esPod *esp, IPOD_ACK_CODE ackCode, byte cmdID, uint32_t numField); - static void _0x02_RetCurrentEQProfileIndex(esPod *esp); - static void _0x05_RetNumEQProfiles(esPod *esp); - static void _0x07_RetIndexedEQProfileName(esPod *esp); - static void _0x09_RemoteEventNotification(esPod *esp); - static void _0x0B_RetRemoteEventStatus(esPod *esp, uint32_t remEventStatus); - static void _0x0D_RetiPodStateInfo(esPod *esp); - static void _0x10_RetPlayStatus(esPod *esp, byte playState, uint32_t trackIndex, uint32_t trackTotMs, uint32_t trackPosMs); - static void _0x13_RetIndexedPlayingTrackInfo(esPod *esp, byte trackInfoType, char *trackInfoChars); - static void _0x13_RetIndexedPlayingTrackInfo(esPod *esp, uint32_t trackDuration_ms); - static void _0x15_RetNumPlayingTracks(esPod *esp, uint32_t numPlayingTracks); - static void _0x17_RetArtworkFormats(esPod *esp); - static void _0x19_RetTrackArtworkData(esPod *esp); - static void _0x1B_RetPowerBatteryState(esPod *esp, byte powerBatteryState); - static void _0x1D_RetSoundCheckState(esPod *esp, byte soundCheckState); - static void _0x20_RetTrackArtworkTimes(esPod *esp); -}; diff --git a/include/L0x04.h b/include/L0x04.h deleted file mode 100644 index a617b60..0000000 --- a/include/L0x04.h +++ /dev/null @@ -1,71 +0,0 @@ -#pragma once -#include "Arduino.h" -#include "esPod_utils.h" -class esPod; - -#define L0x04_GetIndexedPlayingTrackInfo 0x0C -#define L0x04_RequestProtocolVersion 0x12 -#define L0x04_ResetDBSelection 0x16 -#define L0x04_SelectDBRecord 0x17 -#define L0x04_GetNumberCategorizedDBRecords 0x18 -#define L0x04_RetrieveCategorizedDatabaseRecords 0x1A -#define L0x04_GetPlayStatus 0x1C -#define L0x04_GetCurrentPlayingTrackIndex 0x1E -#define L0x04_GetIndexedPlayingTrackTitle 0x20 -#define L0x04_GetIndexedPlayingTrackArtistName 0x22 -#define L0x04_GetIndexedPlayingTrackAlbumName 0x24 -#define L0x04_SetPlayStatusChangeNotification 0x26 -#define L0x04_PlayCurrentSelection 0x28 -#define L0x04_PlayControl 0x29 -#define L0x04_GetShuffle 0x2C -#define L0x04_SetShuffle 0x2E -#define L0x04_GetRepeat 0x2F -#define L0x04_SetRepeat 0x31 -#define L0x04_GetMonoDisplayImageLimits 0x33 -#define L0x04_GetNumPlayingTracks 0x35 -#define L0x04_SetCurrentPlayingTrack 0x37 -#define L0x04_SelectSortDBRecord 0x38 -#define L0x04_GetColorDisplayImageLimits 0x39 - -class L0x04 -{ -public: - static void processLingo(esPod *esp, const byte *byteArray, uint32_t len); - - // Lingo 0x04 Handlers - static void _0x01_iPodAck(esPod *esp, IPOD_ACK_CODE ackCode, byte cmdID); - static void _0x01_iPodAck(esPod *esp, IPOD_ACK_CODE ackCode, byte cmdID, uint32_t numField); - // static void _0x03_ReturnCurrentPlayingTrackChapterInfo(esPod *esp); - // static void _0x06_ReturnCurrentPlayingTrackChapterPlayStatus(esPod *esp); - // static void _0x08_ReturnCurrentPlayingTrackChapterName(esPod *esp); - // static void _0x0A_ReturnAudiobookSpeed(esPod *esp); - static void _0x0D_ReturnIndexedPlayingTrackInfo(esPod *esp, byte trackInfoType, char *trackInfoChars); - static void _0x0D_ReturnIndexedPlayingTrackInfo(esPod *esp, uint32_t trackDuration_ms); - static void _0x0D_ReturnIndexedPlayingTrackInfo(esPod *esp, byte trackInfoType, uint16_t releaseYear); - // static void _0x0F_RetArtworkFormats(esPod *esp); - // static void _0x11_RetTrackArtworkData(esPod *esp); - static void _0x13_ReturnProtocolVersion(esPod *esp); - // static void _0x15_ReturniPodName(esPod *esp); - static void _0x19_ReturnNumberCategorizedDBRecords(esPod *esp, uint32_t categoryDBRecords); - static void _0x1B_ReturnCategorizedDatabaseRecord(esPod *esp, uint32_t index, char *recordString); - static void _0x1D_ReturnPlayStatus(esPod *esp, uint32_t position, uint32_t duration, byte playStatus); - static void _0x1F_ReturnCurrentPlayingTrackIndex(esPod *esp, uint32_t trackIndex); - static void _0x21_ReturnIndexedPlayingTrackTitle(esPod *esp, char *trackTitle); - static void _0x23_ReturnIndexedPlayingTrackArtistName(esPod *esp, char *trackArtistName); - static void _0x25_ReturnIndexedPlayingTrackAlbumName(esPod *esp, char *trackAlbumName); - static void _0x27_PlayStatusNotification(esPod *esp, byte notification, uint32_t numField); - static void _0x27_PlayStatusNotification(esPod *esp, byte notification); - // static void _0x2B_RetTrackArtworkTimes(esPod *esp); - static void _0x2D_ReturnShuffle(esPod *esp, byte shuffleStatus); - static void _0x30_ReturnRepeat(esPod *esp, byte repeatStatus); - static void _0x34_ReturnMonoDisplayImageLimits(esPod *esp, uint16_t maxImageW, uint16_t maxImageH, byte dispPixelFmt); - static void _0x36_ReturnNumPlayingTracks(esPod *esp, uint32_t numPlayingTracks); - static void _0x3A_ReturnColorDisplayImageLimits(esPod *esp, uint16_t maxImageW, uint16_t maxImageH, byte dispPixelFmt); - // static void _0x3D_RetDBiTunesInfo(esPod *esp); - // static void _0x3F_RetUIDTrackInfo(esPod *esp); - // static void _0x41_RetDBTrackInfo(esPod *esp); - // static void _0x43_RetPBTrackInfo(esPod *esp); - // static void _0x49_RetPlaylistInfo(esPod *esp); - // static void _0x4D_RetArtworkTimes(esPod *esp); - // static void _0x4F_RetArtworkData(esPod *esp); -}; \ No newline at end of file diff --git a/include/esPod.h b/include/esPod.h deleted file mode 100644 index 882d647..0000000 --- a/include/esPod.h +++ /dev/null @@ -1,193 +0,0 @@ -#pragma once -#include "Arduino.h" -#include "L0x00.h" -#include "L0x03.h" -#include "L0x04.h" -#include "esPod_conf.h" -#include "esPod_utils.h" - -class esPod -{ - friend class L0x00; // Lingo 0x00 message handlers - friend class L0x03; // Lingo 0x03 message handlers - friend class L0x04; // Lingo 0x04 message handlers - -public: - typedef void playStatusHandler_t(byte playControlCommand); // Type definition for the external callback to control playback FROM the espod object - - // State variables - bool extendedInterfaceModeActive = false; // Indicates if the extended interface mode is accessible (Lingo 0x04 mostly) - bool disabled = true; // espod starts disabled... it means it keeps flushing the Serial until it is ready to process something - - // Metadata variables - char trackTitle[255] = "Title"; // Current track Title - char prevTrackTitle[255] = " "; // Previous track Title - char artistName[255] = "Artist"; // Current track Artist Name - char prevArtistName[255] = " "; // Previous track Artist Name - char albumName[255] = "Album"; // Current track Album Name - char prevAlbumName[255] = " "; // Previous track Album Name - char trackGenre[255] = "Genre"; // Current track Genre - char playList[255] = "Spotify"; // Current playlist (always the same) - char composer[255] = "Composer"; // Current track's composer (sometimes gets requested) - uint32_t trackDuration = 1; // Track duration in ms - uint32_t prevTrackDuration = 1; // Previous track duration in ms - uint32_t playPosition = 0; // Current playing position of the track in ms - - // Playback Engine - byte playStatus = PB_STATE_PAUSED; // Current state of the PBEngine - byte playStatusNotificationState = NOTIF_OFF; // Current state of the Notifications engine - byte trackChangeAckPending = 0x00; // Indicate there is a pending track change. - uint64_t trackChangeTimestamp = 0; // Trigger for the last track change request. Time outs the pending track change. - byte shuffleStatus = 0x00; // 00 No Shuffle, 0x01 Tracks 0x02 Albums - byte repeatStatus = 0x02; // 00 Repeat off, 01 One track, 02 All tracks - - // TrackList variables - uint32_t currentTrackIndex = 0; // Current internal track index - uint32_t prevTrackIndex = TOTAL_NUM_TRACKS - 1; // Previous track index, starts at the end of the tracklist - const uint32_t totalNumberTracks = TOTAL_NUM_TRACKS; // Total number of tracks. Has little influence - uint32_t trackList[TOTAL_NUM_TRACKS] = {0}; // Initial track list is filled with 0 track indexs - uint32_t trackListPosition = 0; // Locator for the position of the track ID in the TrackList (of IDs) (i.e. cursor) - -private: - // FreeRTOS Queues - QueueHandle_t _cmdQueue; // Incoming commands queue from accessory (car) - QueueHandle_t _txQueue; // Outgoing response/commands queue from espod to car - QueueHandle_t _timerQueue; // Queue for processing "pending" commands timer callbacks (rather than in-ISR processing) - - // FreeRTOS tasks (and methods...) - TaskHandle_t _rxTaskHandle; // RX task handle (from car) - TaskHandle_t _processTaskHandle; // Command dispatcher/processor task handle - TaskHandle_t _txTaskHandle; // TX task handle (to car) - TaskHandle_t _timerTaskHandle; // Pending command timer task handle - - /// @brief RX Task, sifts through the incoming serial data and compiles packets that pass the checksum and passes them to the processing Queue _cmdQueue. Also handles timeouts and can trigger state resets. - /// @param pvParameters Unused - static void _rxTask(void *pvParameters); - - /// @brief Processor task retrieving from the cmdQueue and processing the commands - /// @param pvParameters - static void _processTask(void *pvParameters); - - /// @brief Transmit task, retrieves from the txQueue and sends the packets over Serial at high priority but wider timing - /// @param pvParameters - static void _txTask(void *pvParameters); - - /// @brief Low priority task to queue acks *outside* of the timer interrupt context - /// @param pvParameters - static void _timerTask(void *pvParameters); - - // FreeRTOS timers for delayed acks - TimerHandle_t _pendingTimer_0x00; - TimerHandle_t _pendingTimer_0x03; - TimerHandle_t _pendingTimer_0x04; - - /// @brief Callback for L0x00 pending Ack timer - /// @param xTimer - static void _pendingTimerCallback_0x00(TimerHandle_t xTimer); - - /// @brief Callback for L0x03 pending Ack timer - /// @param xTimer - static void _pendingTimerCallback_0x03(TimerHandle_t xTimer); - - /// @brief Callback for L0x04 pending Ack timer - /// @param xTimer - static void _pendingTimerCallback_0x04(TimerHandle_t xTimer); - - byte _pendingCmdId_0x00; // Command ID that is pending in Lingo 0x00 - byte _pendingCmdId_0x03; // Command ID that is pending in Lingo 0x03 - byte _pendingCmdId_0x04; // Command ID that is pending in Lingo 0x04 - - // Serial to the car - Stream &_targetSerial; - - /// @brief //Calculates the checksum of a packet that starts from i=0 ->Lingo to i=len -> Checksum - /// @param byteArray Array from Lingo byte to Checksum byte - /// @param len Length of array (Lingo byte to Checksum byte) - /// @return Calculated checksum for comparison - static byte _checksum(const byte *byteArray, uint32_t len); - - /// @brief Composes and sends a packet over the _targetSerial - /// @param byteArray Array to send, starting with the Lingo byte and without the checksum byte - /// @param len Length of the array to send - void _sendPacket(const byte *byteArray, uint32_t len); - - /// @brief Adds a packet to the transmit queue - /// @param byteArray Array of bytes to add to the queue - /// @param len Length of data in the array - void _queuePacket(const byte *byteArray, uint32_t len); - - /// @brief Adds a packet to the transmit queue, but at the front for immediate processing - /// @param byteArray Array of bytes to add to the queue - /// @param len Length of data in the array - void _queuePacketToFront(const byte *byteArray, uint32_t len); - - /// @brief Processes a valid packet and calls the relevant Lingo processor - /// @param byteArray Checksum-validated packet starting at LingoID - /// @param len Length of valid data in the packet - void _processPacket(const byte *byteArray, uint32_t len); - - bool _rxIncomplete = false; // Marker in case of incomplete command sequence reception - - // Device metadata - const char *_name = ESPIPOD_NAME; // Published esPOD name - const uint8_t _SWMajor = 0x01; // Published SW Major version - const uint8_t _SWMinor = 0x03; // Published SW Minor version - const uint8_t _SWrevision = 0x00; // Published SW revision - const char *_serialNumber = "AB345F7HIJK"; // Made-up serial number - - // Handler functions - playStatusHandler_t *_playStatusHandler = nullptr; // Pointer to external callback used to let the espod instance control playback - - // Boolean flags for track change management - bool _albumNameUpdated = false; // Internal flag if the albumName has been updated. Used to send relevant notifications if necessary - bool _artistNameUpdated = false; // Internal flag if the artistName has been updated. Used to send relevant notifications if necessary - bool _trackTitleUpdated = false; // Internal flag if the trackTitle has been updated. Used to send relevant notifications if necessary - bool _trackDurationUpdated = false; // Internal flag if the trackDuration has been updated. Used to send relevant notifications if necessary - void _checkAllMetaUpdated(); - -public: - /// @brief Constructor for the esPod class - /// @param targetSerial (Serial) stream on which the esPod will be communicating - esPod(Stream &targetSerial); - - /// @brief Destructor for the esPod class. Normally not used. - ~esPod(); - - /// @brief Resets the esPod instance to a "clean" startup state - void resetState(); - - /// @brief Function to attach the playback controller that allows the espod instance to perform playback operations on the audio source - /// @param playHandler Type-function of a playStatusHandler, linking the espod instance to the audio source controls - void attachPlayControlHandler(playStatusHandler_t playHandler); - - // Useful wrappers for A2DP and AVRC integration - - /// @brief Sets the esPod instance to "PLAY" - void play(); - - /// @brief Sets the esPod instance to "PAUSED" - void pause(); - - /// @brief Sets the esPod instance to "STOPPED" - void stop(); - - /// @brief Updates the play position (in ms) in the instance. Some internal checks are run to debounce double updates that might happen through AVRC - /// @param position Current play position in ms - void updatePlayPosition(uint32_t position); - - /// @brief Checks and updates the album name in the espod instance. - /// @param incAlbumName Char array of new album name - void updateAlbumName(const char *incAlbumName); - - /// @brief Checks and updates the artist name in the espod instance. - /// @param incArtistName Char array of new artist name - void updateArtistName(const char *incArtistName); - - /// @brief Checks and udpates the track title in the espod instance. - /// @param incTrackTitle Char array of new track title - void updateTrackTitle(const char *incTrackTitle); - - /// @brief Checks and updates the track duration in the espod instance. - /// @param incTrackDuration Track duration in ms. - void updateTrackDuration(uint32_t incTrackDuration); -}; \ No newline at end of file diff --git a/include/esPod_conf.h b/include/esPod_conf.h deleted file mode 100644 index 1e25e8b..0000000 --- a/include/esPod_conf.h +++ /dev/null @@ -1,75 +0,0 @@ -#pragma once -#include "Arduino.h" - -// ESPiPod instance name -#ifndef ESPIPOD_NAME -#define ESPIPOD_NAME "ipodESP32" -#endif - -// Serial settings -#ifndef MAX_PACKET_SIZE -#define MAX_PACKET_SIZE 1024 -#endif -#ifndef SERIAL_TIMEOUT -#define SERIAL_TIMEOUT 8000 -#endif -#ifndef INTERBYTE_TIMEOUT -#define INTERBYTE_TIMEOUT 500 -#endif -// FreeRTOS Queues -#ifndef CMD_QUEUE_SIZE -#define CMD_QUEUE_SIZE 32 -#endif -#ifndef TX_QUEUE_SIZE -#define TX_QUEUE_SIZE 32 -#endif -#ifndef TIMER_QUEUE_SIZE -#define TIMER_QUEUE_SIZE 10 -#endif -// RX Task settings -#ifndef RX_TASK_STACK_SIZE -#define RX_TASK_STACK_SIZE 4096 -#endif -#ifndef RX_TASK_PRIORITY -#define RX_TASK_PRIORITY 2 -#endif -#ifndef RX_TASK_INTERVAL_MS -#define RX_TASK_INTERVAL_MS 10 -#endif -// Process Task settings -#ifndef PROCESS_TASK_STACK_SIZE -#define PROCESS_TASK_STACK_SIZE 4096 -#endif -#ifndef PROCESS_TASK_PRIORITY -#define PROCESS_TASK_PRIORITY 5 -#endif -#ifndef PROCESS_INTERVAL_MS -#define PROCESS_INTERVAL_MS 15 -#endif -// TX Task settings -#ifndef TX_TASK_STACK_SIZE -#define TX_TASK_STACK_SIZE 4096 -#endif -#ifndef TX_TASK_PRIORITY -#define TX_TASK_PRIORITY 20 -#endif -#ifndef TX_INTERVAL_MS -#define TX_INTERVAL_MS 20 -#endif -// Timer Task settings -#ifndef TIMER_TASK_STACK_SIZE -#define TIMER_TASK_STACK_SIZE 2048 -#endif -#ifndef TIMER_TASK_PRIORITY -#define TIMER_TASK_PRIORITY 1 -#endif -#ifndef TIMER_INTERVAL_MS -#define TIMER_INTERVAL_MS 5 -#endif -// General iPod settings -#ifndef TOTAL_NUM_TRACKS -#define TOTAL_NUM_TRACKS 3000 -#endif -#ifndef TRACK_CHANGE_TIMEOUT -#define TRACK_CHANGE_TIMEOUT 1100 -#endif \ No newline at end of file diff --git a/include/esPod_utils.h b/include/esPod_utils.h deleted file mode 100644 index 3008388..0000000 --- a/include/esPod_utils.h +++ /dev/null @@ -1,157 +0,0 @@ -#pragma once -#include "Arduino.h" -#include "esPod_conf.h" - -// // Possible values for L0x00 0x02 iPodAck -// #define iPodAck_OK 0x00 -// #define iPodAck_CmdFailed 0x02 -// #define iPodAck_BadParam 0x04 -// #define iPodAck_UnknownID 0x05 -// #define iPodAck_CmdPending 0x06 -// #define iPodAck_TimedOut 0x0F -// #define iPodAck_CmdUnavail 0x10 -// #define iPodAck_LingoBusy 0x14 - -#pragma region ENUMS - -enum IPOD_ACK_CODE : byte -{ - iPodAck_OK = 0x00, - iPodAck_UnknownDBCat = 0x01, - iPodAck_CmdFailed = 0x02, - iPodAck_OutOfResources = 0x03, - iPodAck_BadParam = 0x04, - iPodAck_UnknownID = 0x05, - iPodAck_CmdPending = 0x06, - iPodAck_NotAuthenticated = 0x07, - iPodAck_BadAuthVersion = 0x08, - iPodAck_AccPowerModeReqFailed = 0x09, - iPodAck_CertificateInvalid = 0x0A, - iPodAck_CertPermissionsInvalid = 0x0B, - iPodAck_FileInUse = 0x0C, - iPodAck_FileHndlInvalid = 0x0D, - iPodAck_DirNotEmpty = 0x0E, - iPodAck_TimedOut = 0x0F, - iPodAck_CmdUnavail = 0x10, - iPodAck_DetectFloat_BadResistor = 0x11, - iPodAck_SelNotGenius = 0x12, - iPodAck_MultiDataSection_OK = 0x13, - iPodAck_LingoBusy = 0x14, - iPodAck_MaxConnections = 0x15, - iPodAck_HIDAlreadyInUse = 0x16, - iPodAck_DroppedData = 0x17, - iPodAck_OutModeError = 0x18 -}; - -enum PB_STATUS : byte -{ - PB_STATE_STOPPED = 0x00, - PB_STATE_PLAYING = 0x01, - PB_STATE_PAUSED = 0x02, - PB_STATE_ERROR = 0xFF -}; - -enum PB_COMMAND : byte -{ - PB_CMD_TOGGLE = 0x01, - PB_CMD_STOP = 0x02, - PB_CMD_NEXT_TRACK = 0x03, - PB_CMD_PREVIOUS_TRACK = 0x04, - PB_CMD_SEEK_FF = 0x05, - PB_CMD_SEEK_RW = 0x06, - PB_CMD_STOP_SEEK = 0x07, - PB_CMD_NEXT = 0x08, - PB_CMD_PREV = 0x09, - PB_CMD_PLAY = 0x0A, - PB_CMD_PAUSE = 0x0B -}; - -enum DB_CATEGORY : byte -{ - DB_CAT_PLAYLIST = 0x01, - DB_CAT_ARTIST = 0x02, - DB_CAT_ALBUM = 0x03, - DB_CAT_GENRE = 0x04, - DB_CAT_TRACK = 0x05, - DB_CAT_COMPOSER = 0x06, - DB_CAT_AUDIOBOOK = 0x07, - DB_CAT_PODCAST = 0x08 -}; // Just a small selection - -enum A2DP_PB_CMD : byte -{ - A2DP_STOP = 0x00, - A2DP_PLAY = 0x01, - A2DP_PAUSE = 0x02, - A2DP_REWIND = 0x03, - A2DP_NEXT = 0x04, - A2DP_PREV = 0x05 -}; - -enum NOTIF_STATES : byte -{ - NOTIF_OFF = 0x00, - NOTIF_ON = 0x01 -}; - -#pragma endregion - -struct aapCommand -{ - byte *payload = nullptr; - uint32_t length = 0; -}; - -struct TimerCallbackMessage -{ - byte cmdID; // Command ID to be acked - byte targetLingo; // Targeted Lingo -}; - -#pragma region Local utilities -// ESP32 is Little-Endian, iPod is Big-Endian -template -T swap_endian(T u) -{ - static_assert(CHAR_BIT == 8, "CHAR_BIT != 8"); - - union - { - T u; - unsigned char u8[sizeof(T)]; - } source, dest; - - source.u = u; - - for (size_t k = 0; k < sizeof(T); k++) - dest.u8[k] = source.u8[sizeof(T) - k - 1]; - - return dest.u; -} - -/// @brief (Re)starts a timer and changes the interval on the fly. -/// @param timer Timer handle to (re)start. -/// @param time_ms New interval in milliseconds. No verification is done if this is 0! Defaults to TRACK_CHANGE_TIMEOUT. -inline void startTimer(TimerHandle_t timer, unsigned long time_ms = TRACK_CHANGE_TIMEOUT) -{ - // If the timer is already active, it needs to be stopped without a callback call first - if (xTimerIsTimerActive(timer) == pdTRUE) - { - xTimerStop(timer, 0); - } - // Change the period and start the timer - xTimerChangePeriod(timer, pdMS_TO_TICKS(time_ms), 0); - xTimerStart(timer, 0); -} - -/// @brief Stops a running timer. No status is returned if it was already stopped. -/// @param timer Handle to the Timer that needs to be stopped. -inline void stopTimer(TimerHandle_t timer) -{ - // If the timer is already active, it needs to be stop without a callback call first - if (xTimerIsTimerActive(timer) == pdTRUE) - { - xTimerStop(timer, 0); - } -} -#pragma endregion \ No newline at end of file diff --git a/platformio.ini b/platformio.ini index 01c2374..980b5c1 100644 --- a/platformio.ini +++ b/platformio.ini @@ -1,13 +1,3 @@ -; PlatformIO Project Configuration File -; -; Build options: build flags, source filter -; Upload options: custom upload port, speed and extra flags -; Library options: dependencies, extra library storages -; Advanced options: extra scripting -; -; Please visit documentation for the other options and examples -; https://docs.platformio.org/page/projectconf.html - [platformio] [env] @@ -22,70 +12,10 @@ lib_deps = https://github.com/pschatzmann/ESP32-A2DP.git#v1.8.8 https://github.com/pschatzmann/arduino-audio-tools.git#v1.2.0 https://github.com/pschatzmann/arduino-audio-driver.git#v0.1.4 + https://github.com/martinroger/espod.git monitor_filters = esp32_exception_decoder monitor_speed = 115200 -; [env:audioKit_topHat] -; board = audioKit -; build_flags = -; ${env.build_flags} -; -D BOARD_HAS_PSRAM -; -D AUDIOKIT -; -D INVERT_LED_LOGIC -; -D LED_BUILTIN=18 -; -D CORE_DEBUG_LEVEL=0 - -; [env:audioKit_topHat_SDUpdaterOnly] -; extends = env:audioKit_topHat -; build_type = debug -; board_build.partitions = min_spiffs.csv -; build_flags = -; ${env:audioKit_topHat.build_flags} -; -D USE_SD - -; [env:audioKit_topHat_SDLogger] -; extends = env:audioKit_topHat -; build_type = debug -; board_build.partitions = min_spiffs.csv -; build_flags = -; ${env.build_flags} -; -D BOARD_HAS_PSRAM -; -D AUDIOKIT -; -D INVERT_LED_LOGIC -; -D LED_BUILTIN=18 -; -D USE_SD -; -D LOG_TO_SD -; -D USE_ESP_IDF_LOG -; -D CORE_DEBUG_LEVEL=3 - -; [env:audioKit_topHat_SDLogger_altSerial] -; extends = env:audioKit_topHat -; build_type = debug -; board_build.partitions = min_spiffs.csv -; build_flags = -; ${env:audioKit_topHat_SDLogger.build_flags} -; -D USE_ALT_SERIAL - -; [env:audioKit_topHat_altSerial] -; extends = env:audioKit_topHat -; build_type = debug -; board_build.partitions = min_spiffs.csv -; build_flags = -; ${env.build_flags} -; -D BOARD_HAS_PSRAM -; -D AUDIOKIT -; -D INVERT_LED_LOGIC -; -D LED_BUILTIN=18 -; -D CORE_DEBUG_LEVEL=3 -; -D USE_ALT_SERIAL - -[env:SBC_ESP32DevKitC] -build_flags = - ${env.build_flags} - -D CORE_DEBUG_LEVEL=2 -board = az-delivery-devkit-v4 -lib_ignore = audio-driver - [env:SBC_NodeMCU32S] build_flags = ${env.build_flags} @@ -95,15 +25,6 @@ board = nodemcu-32s lib_ignore = audio-driver [env:a1sMini] -; board = audioKit -; build_flags = -; ${env.build_flags} -; -D BOARD_HAS_PSRAM -; -D AUDIOKIT -; -D INVERT_LED_LOGIC -; -D LED_BUILTIN=18 -; -D CORE_DEBUG_LEVEL=0 -; extends = env:audioKit_topHat board = audioKit build_type = debug board_build.partitions = min_spiffs.csv @@ -138,7 +59,7 @@ build_flags = -D UART1_TX=21 lib_ignore = audio-driver - +; Legacy or special configurations ; [env:BluCobalt] ; build_flags = @@ -157,3 +78,65 @@ lib_ignore = audio-driver ; -D ESPIPOD_NAME="\"BluCobalt-o-pod"\" ; board = esp32dev ; lib_ignore = audio-driver + +; [env:audioKit_topHat] +; board = audioKit +; build_flags = +; ${env.build_flags} +; -D BOARD_HAS_PSRAM +; -D AUDIOKIT +; -D INVERT_LED_LOGIC +; -D LED_BUILTIN=18 +; -D CORE_DEBUG_LEVEL=0 + +; [env:audioKit_topHat_SDUpdaterOnly] +; extends = env:audioKit_topHat +; build_type = debug +; board_build.partitions = min_spiffs.csv +; build_flags = +; ${env:audioKit_topHat.build_flags} +; -D USE_SD + +; [env:audioKit_topHat_SDLogger] +; extends = env:audioKit_topHat +; build_type = debug +; board_build.partitions = min_spiffs.csv +; build_flags = +; ${env.build_flags} +; -D BOARD_HAS_PSRAM +; -D AUDIOKIT +; -D INVERT_LED_LOGIC +; -D LED_BUILTIN=18 +; -D USE_SD +; -D LOG_TO_SD +; -D USE_ESP_IDF_LOG +; -D CORE_DEBUG_LEVEL=3 + +; [env:audioKit_topHat_SDLogger_altSerial] +; extends = env:audioKit_topHat +; build_type = debug +; board_build.partitions = min_spiffs.csv +; build_flags = +; ${env:audioKit_topHat_SDLogger.build_flags} +; -D USE_ALT_SERIAL + +; [env:audioKit_topHat_altSerial] +; extends = env:audioKit_topHat +; build_type = debug +; board_build.partitions = min_spiffs.csv +; build_flags = +; ${env.build_flags} +; -D BOARD_HAS_PSRAM +; -D AUDIOKIT +; -D INVERT_LED_LOGIC +; -D LED_BUILTIN=18 +; -D CORE_DEBUG_LEVEL=3 +; -D USE_ALT_SERIAL + + +; [env:SBC_ESP32DevKitC] +; build_flags = +; ${env.build_flags} +; -D CORE_DEBUG_LEVEL=2 +; board = az-delivery-devkit-v4 +; lib_ignore = audio-driver \ No newline at end of file diff --git a/src/L0x00.cpp b/src/L0x00.cpp deleted file mode 100644 index d24ec03..0000000 --- a/src/L0x00.cpp +++ /dev/null @@ -1,337 +0,0 @@ -#include "Arduino.h" -#include "L0x00.h" -#include "esPod.h" - -/// @brief -/// @param esp Pointer to the esPod instance -/// @param byteArray -/// @param len -void L0x00::processLingo(esPod *esp, const byte *byteArray, uint32_t len) -{ - byte cmdID = byteArray[0]; - uint64_t iPodOptions = 0; - // Switch through expected commandIDs - switch (cmdID) - { - case L0x00_Identify: // Deprecated command observed on Audi by @BluCobalt - { - ESP_LOGI(__func__, "CMD: 0x%02x Identify with Lingo 0x%02x", cmdID, byteArray[1]); - // switch (byteArray[1]) - // { - // case 0x04: - // esp->extendedInterfaceModeActive = true; // Pre-empt ? - // break; - // default: - // break; - // } - } - break; - - case L0x00_RequestExtendedInterfaceMode: // Mini requests extended interface mode status - { - ESP_LOGD(__func__, "CMD: 0x%02x RequestExtendedInterfaceMode", cmdID); - if (esp->extendedInterfaceModeActive) - { - L0x00::_0x04_ReturnExtendedInterfaceMode(esp, 0x01); // Report that extended interface mode is active - } - else - { - L0x00::_0x04_ReturnExtendedInterfaceMode(esp, 0x00); // Report that extended interface mode is not active - } - } - break; - - case L0x00_EnterExtendedInterfaceMode: // Mini forces extended interface mode - { - ESP_LOGI(__func__, "CMD: 0x%02x EnterExtendedInterfaceMode", cmdID); - esp->extendedInterfaceModeActive = true; - L0x00::_0x02_iPodAck(esp, iPodAck_OK, cmdID); - } - break; - - case L0x00_ExitExtendedInterfaceMode: // Mini exits extended interface mode - { - ESP_LOGI(__func__, "CMD: 0x%02x ExitExtendedInterfaceMode", cmdID); - if (esp->extendedInterfaceModeActive) - { - L0x00::_0x02_iPodAck(esp, iPodAck_OK, cmdID); - esp->extendedInterfaceModeActive = false; - esp->playStatusNotificationState = NOTIF_OFF; - } - else - { - L0x00::_0x02_iPodAck(esp, iPodAck_BadParam, cmdID); - } - } - break; - - case L0x00_RequestiPodName: // Mini requests ipod name - { - ESP_LOGI(__func__, "CMD: 0x%02x RequestiPodName", cmdID); - L0x00::_0x08_ReturniPodName(esp); - } - break; - - case L0x00_RequestiPodSoftwareVersion: // Mini requests ipod software version - { - ESP_LOGI(__func__, "CMD: 0x%02x RequestiPodSoftwareVersion", cmdID); - L0x00::_0x0A_ReturniPodSoftwareVersion(esp); - } - break; - - case L0x00_RequestiPodSerialNum: // Mini requests ipod Serial Num - { - ESP_LOGI(__func__, "CMD: 0x%02x RequestiPodSerialNum", cmdID); - L0x00::_0x0C_ReturniPodSerialNum(esp); - } - break; - - case L0x00_RequestiPodModelNum: // Mini requests ipod Model Num - { - ESP_LOGI(__func__, "CMD: 0x%02x RequestiPodModelNum", cmdID); - L0x00::_0x0E_ReturniPodModelNum(esp); - } - break; - - case L0x00_RequestLingoProtocolVersion: // Mini requestsLingo Protocol Version - { - ESP_LOGI(__func__, "CMD: 0x%02x RequestLingoProtocolVersion for Lingo 0x%02x", cmdID, byteArray[1]); - L0x00::_0x10_ReturnLingoProtocolVersion(esp, byteArray[1]); - } - break; - - case L0x00_IdentifyDeviceLingoes: // Mini identifies its lingoes, used as an ice-breaker - { - ESP_LOGI(__func__, "CMD: 0x%02x IdentifyDeviceLingoes : L 0x%02x - Opt 0x%02x - ID 0x%02x", cmdID, byteArray[1], byteArray[2], byteArray[3]); - L0x00::_0x02_iPodAck(esp, iPodAck_OK, cmdID); // Acknowledge, start capabilities pingpong - // A bit spam-ish ? - L0x00::_0x27_GetAccessoryInfo(esp, 0x00); // Immediately request general capabilities - L0x00::_0x27_GetAccessoryInfo(esp, 0x01); // Request the name - L0x00::_0x27_GetAccessoryInfo(esp, 0x04); // Request the firmware version - L0x00::_0x27_GetAccessoryInfo(esp, 0x05); // Request the hardware number - L0x00::_0x27_GetAccessoryInfo(esp, 0x06); // Request the manufacturer name - L0x00::_0x27_GetAccessoryInfo(esp, 0x07); // Request the model number - } - break; - - case L0x00_GetiPodOptions: // Mini requests iPod options - { - ESP_LOGI(__func__, "CMD: 0x%02x GetiPodOptions", cmdID); - // There might be some trickery triggered there with further options enquiries per Lingo - L0x00::_0x25_RetiPodOptions(esp, iPodOptions); - } - - case L0x00_RetAccessoryInfo: // Mini returns info after L0x00::_0x27 - { - ESP_LOGI(__func__, "CMD: 0x%02x RetAccessoryInfo: 0x%02x", cmdID, byteArray[1]); - switch (byteArray[1]) // Ping-pong the next request based on the current response - { - case 0x00: - ESP_LOGI(__func__, "\tAccessory Capabilities : 0x%02x", byteArray[2]); - break; - - case 0x01: - ESP_LOGI(__func__, "\tAccessory Name : %s", &byteArray[2]); - break; - - case 0x04: - ESP_LOGI(__func__, "\tAccessory Firmware : %d.%d.%d", byteArray[2], byteArray[3], byteArray[4]); - break; - - case 0x05: - ESP_LOGI(__func__, "\tAccessory Hardware : %d.%d.%d", byteArray[2], byteArray[3], byteArray[4]); - break; - - case 0x06: - ESP_LOGI(__func__, "\tAccessory Manufacturer : %s", &byteArray[2]); - break; - - case 0x07: - ESP_LOGI(__func__, "\tAccessory Model : %s", &byteArray[2]); - break; - - default: - L0x00::_0x02_iPodAck(esp, iPodAck_OK, cmdID); - break; - } - } - break; - - default: // In case the command is not known - { - ESP_LOGW(__func__, "CMD 0x%02x not recognized.", cmdID); - L0x00::_0x02_iPodAck(esp, iPodAck_CmdFailed, cmdID); - } - break; - } -} - -/// @brief Deprecated function to force the Accessory to restart Identify with L0x00_IdentifyDeviceLingoes -/// @param esp Pointer to the esPod instance -void L0x00::_0x00_RequestIdentify(esPod *esp) -{ - ESP_LOGI(__func__, "iPod: RequestIdentify"); - const byte txPacket[] = { - 0x00, - 0x00}; - esp->_queuePacket(txPacket, sizeof(txPacket)); -} - -/// @brief General response command for Lingo 0x00 -/// @param esp Pointer to the esPod instance -/// @param cmdStatus Has to obey to iPodAck_xxx format as defined in L0x00.h -/// @param cmdID ID (single byte) of the Lingo 0x00 command replied to -void L0x00::_0x02_iPodAck(esPod *esp, IPOD_ACK_CODE ackCode, byte cmdID) -{ - ESP_LOGI(__func__, "Ack 0x%02x to command 0x%02x", ackCode, cmdID); - // Queue the packet - const byte txPacket[] = { - 0x00, - 0x02, - ackCode, - cmdID}; - // Stop the timer if the same command is acknowledged before the elapsed time - if (cmdID == esp->_pendingCmdId_0x00) // If the command ID is the same as the pending one - { - stopTimer(esp->_pendingTimer_0x00); // Stop the timer - esp->_pendingCmdId_0x00 = 0x00; // Reset the pending command - esp->_queuePacketToFront(txPacket, sizeof(txPacket)); // Jump the queue - } - else - esp->_queuePacket(txPacket, sizeof(txPacket)); -} - -/// @brief General response command for Lingo 0x00 with numerical field (used for Ack Pending). Has to be followed up with a normal iPodAck -/// @param esp Pointer to the esPod instance -/// @param cmdStatus Unprotected, but should only be iPodAck_CmdPending -/// @param cmdID Single byte ID of the command being acknowledged with Pending -/// @param numField Pending delay in milliseconds -void L0x00::_0x02_iPodAck(esPod *esp, IPOD_ACK_CODE ackCode, byte cmdID, uint32_t numField) -{ - ESP_LOGI(__func__, "Ack 0x%02x to command 0x%02x Numfield: %d", ackCode, cmdID, numField); - const byte txPacket[20] = { - 0x00, - 0x02, - ackCode, - cmdID}; - *((uint32_t *)&txPacket[4]) = swap_endian(numField); - esp->_queuePacket(txPacket, 4 + 4); - // Starting delayed timer for the iPodAck - esp->_pendingCmdId_0x00 = cmdID; - startTimer(esp->_pendingTimer_0x00, numField); -} - -/// @brief Returns 0x01 if the iPod is in extendedInterfaceMode, or 0x00 if not -/// @param esp Pointer to the esPod instance -/// @param extendedModeByte Direct value of the extendedInterfaceMode boolean -void L0x00::_0x04_ReturnExtendedInterfaceMode(esPod *esp, byte extendedModeByte) -{ - ESP_LOGD(__func__, "Extended Interface mode: 0x%02x", extendedModeByte); - const byte txPacket[] = { - 0x00, - 0x04, - extendedModeByte}; - esp->_queuePacket(txPacket, sizeof(txPacket)); -} - -/// @brief Returns as a UTF8 null-ended char array, the esp->_name of the iPod (not changeable during runtime) -/// @param esp Pointer to the esPod instance -void L0x00::_0x08_ReturniPodName(esPod *esp) -{ - ESP_LOGI(__func__, "Name: %s", esp->_name); - byte txPacket[255] = {// Prealloc to len = FF - 0x00, - 0x08}; - strcpy((char *)&txPacket[2], esp->_name); - esp->_queuePacket(txPacket, 3 + strlen(esp->_name)); -} - -/// @brief Returns the iPod Software Version -/// @param esp Pointer to the esPod instance -void L0x00::_0x0A_ReturniPodSoftwareVersion(esPod *esp) -{ - ESP_LOGI(__func__, "SW version: %d.%d.%d", esp->_SWMajor, esp->_SWMinor, esp->_SWrevision); - byte txPacket[] = { - 0x00, - 0x0A, - (byte)esp->_SWMajor, - (byte)esp->_SWMinor, - (byte)esp->_SWrevision}; - esp->_queuePacket(txPacket, sizeof(txPacket)); -} - -/// @brief Returns the iPod Serial Number (which is a string) -/// @param esp Pointer to the esPod instance -void L0x00::_0x0C_ReturniPodSerialNum(esPod *esp) -{ - ESP_LOGI(__func__, "Serial number: %s", esp->_serialNumber); - byte txPacket[255] = {// Prealloc to len = FF - 0x00, - 0x0C}; - strcpy((char *)&txPacket[2], esp->_serialNumber); - esp->_queuePacket(txPacket, 3 + strlen(esp->_serialNumber)); -} - -/// @brief Returns the iPod model number PA146FD 720901, which corresponds to an iPod 5.5G classic -/// @param esp Pointer to the esPod instance -void L0x00::_0x0E_ReturniPodModelNum(esPod *esp) -{ - ESP_LOGI(__func__, "Model number : PA146FD 720901"); - byte txPacket[] = { - 0x00, - 0x0E, - 0x00, 0x0B, 0x00, 0x05, 0x50, 0x41, 0x31, 0x34, 0x36, 0x46, 0x44, 0x00}; - esp->_queuePacket(txPacket, sizeof(txPacket)); -} - -/// @brief Returns a preprogrammed value for the Lingo Protocol Version for 0x00, 0x03 or 0x04 -/// @param esp Pointer to the esPod instance -/// @param targetLingo Target Lingo for which the Protocol Version is desired. -void L0x00::_0x10_ReturnLingoProtocolVersion(esPod *esp, byte targetLingo) -{ - byte txPacket[] = { - 0x00, 0x10, - targetLingo, - 0x01, 0x00}; - switch (targetLingo) - { - case 0x00: // For General Lingo 0x00, version 1.6 - txPacket[4] = 0x06; - break; - case 0x03: // For Lingo 0x03, version 1.5 - txPacket[4] = 0x05; - break; - case 0x04: // For Lingo 0x04 (Extended Interface), version 1.12 - txPacket[4] = 0x0C; - break; - case 0x0A: // Lingo 0x0A, digital audio, need to return 1.0 - txPacket[4] = 0x00; - break; - } - ESP_LOGI(__func__, "Lingo 0x%02x protocol version: 1.%d", targetLingo, txPacket[4]); - esp->_queuePacket(txPacket, sizeof(txPacket)); -} - -/// @brief Return iPod Options. In this case not much. -/// @param esp Pointer to the esPod instance -void L0x00::_0x25_RetiPodOptions(esPod *esp, uint64_t optBitField) -{ - ESP_LOGI(__func__, "Returning iPod Options"); - byte txPacket[] = { - 0x00, 0x25, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - *((uint64_t *)&txPacket[2]) = swap_endian(optBitField); // Hehhhh not sure about that one - esp->_queuePacket(txPacket, sizeof(txPacket)); -} - -/// @brief Query the accessory Info (model number, manufacturer, firmware version ...) using the target Info category hex -/// @param esp Pointer to the esPod instance -/// @param desiredInfo Hex code for the type of information that is desired -void L0x00::_0x27_GetAccessoryInfo(esPod *esp, byte desiredInfo) -{ - ESP_LOGI(__func__, "Req'd info type: 0x%02x", desiredInfo); - byte txPacket[] = { - 0x00, 0x27, - desiredInfo}; - esp->_queuePacket(txPacket, sizeof(txPacket)); -} diff --git a/src/L0x03.cpp b/src/L0x03.cpp deleted file mode 100644 index 415cd9b..0000000 --- a/src/L0x03.cpp +++ /dev/null @@ -1,486 +0,0 @@ -#include "Arduino.h" -#include "L0x03.h" -#include "esPod.h" - -void L0x03::processLingo(esPod *esp, const byte *byteArray, uint32_t len) -{ - byte cmdID = byteArray[0]; - // byte category; - uint32_t currentEQProfileIndex, startIndex, counts, tempTrackIndex; - switch (cmdID) - { - case L0x03_GetCurrentEQProfileIndex: - { - ESP_LOGI(__func__, "CMD: 0x%02x GetCurrentEQProfileIndex", cmdID); - L0x03::_0x02_RetCurrentEQProfileIndex(esp); - } - break; - - case L0x03_SetCurrentEQProfileIndex: - { - currentEQProfileIndex = swap_endian(*((uint32_t *)&byteArray[1])); - ESP_LOGI(__func__, "CMD: 0x%02x SetCurrentEQProfileIndex 0x%02x", cmdID, currentEQProfileIndex); - L0x03::_0x00_iPodAck(esp, iPodAck_OK, cmdID); - } - break; - - case L0x03_GetNumEQProfiles: - { - ESP_LOGI(__func__, "CMD: 0x%02x GetNumEQProfiles", cmdID); - L0x03::_0x05_RetNumEQProfiles(esp); - } - break; - - case L0x03_GetIndexedEQProfileName: - { - ESP_LOGI(__func__, "CMD: 0x%02x GetIndexedEQProfileName", cmdID); - L0x03::_0x07_RetIndexedEQProfileName(esp); - } - break; - - case L0x03_SetRemoteEventNotification: - { - ESP_LOGI(__func__, "CMD: 0x%02x SetRemoteEventNotification", cmdID); - L0x03::_0x00_iPodAck(esp, iPodAck_OK, cmdID); - // Not really implemented, should not be used - L0x03::_0x09_RemoteEventNotification(esp); - } - break; - - case L0x03_GetRemoteEventStatus: - { - ESP_LOGI(__func__, "CMD: 0x%02x GetRemoteEventStatus", cmdID); - // Not implemented - L0x03::_0x0B_RetRemoteEventStatus(esp, 0); - } - break; - - case L0x03_GetiPodStateInfo: - { - ESP_LOGI(__func__, "CMD: 0x%02x GetiPodStateInfo", cmdID); - // Not implemented - L0x03::_0x0D_RetiPodStateInfo(esp); - } - break; - - case L0x03_SetiPodStateInfo: - { - ESP_LOGI(__func__, "CMD: 0x%02x SetiPodStateInfo", cmdID); - // Not implemented - L0x03::_0x00_iPodAck(esp, iPodAck_OK, cmdID); - } - break; - - case L0x03_GetPlayStatus: - { - ESP_LOGI(__func__, "CMD: 0x%02x GetPlayStatus", cmdID); - L0x03::_0x10_RetPlayStatus(esp, esp->playStatus, esp->currentTrackIndex, esp->trackDuration, esp->playPosition); - } - break; - - case L0x03_SetCurrentPlayingTrack: - { - tempTrackIndex = swap_endian(*((uint32_t *)&byteArray[1])); - ESP_LOGI(__func__, "CMD: 0x%02x SetCurrentPlayingTrack index %d", cmdID, tempTrackIndex); - if (esp->playStatus != PB_STATE_PLAYING) - { - esp->playStatus = PB_STATE_PLAYING; // Playing status forced - if (esp->_playStatusHandler) - { - esp->_playStatusHandler(A2DP_PLAY); // Send play to the a2dp - } - } - if (tempTrackIndex == esp->trackList[(esp->trackListPosition + TOTAL_NUM_TRACKS - 1) % TOTAL_NUM_TRACKS]) // Desired trackIndex is the left entry - { - // This is only for when the system requires the data of the previously active track - esp->prevTrackIndex = esp->currentTrackIndex; - strcpy(esp->prevAlbumName, esp->albumName); - strcpy(esp->prevArtistName, esp->artistName); - strcpy(esp->prevTrackTitle, esp->trackTitle); - esp->prevTrackDuration = esp->trackDuration; - - // Cursor operations for PREV - esp->trackListPosition = (esp->trackListPosition + TOTAL_NUM_TRACKS - 1) % TOTAL_NUM_TRACKS; // Shift esp->trackListPosition one to the right - esp->currentTrackIndex = tempTrackIndex; - - // Engage the pending ACK for expected metadata - esp->trackChangeAckPending = cmdID; - esp->trackChangeTimestamp = millis(); - ESP_LOGD(__func__, "Prev. index %d New index %d Tracklist pos. %d Pending Meta %d Timestamp: %d --> PREV ", esp->prevTrackIndex, esp->currentTrackIndex, esp->trackListPosition, (esp->trackChangeAckPending > 0x00), esp->trackChangeTimestamp); - L0x03::_0x00_iPodAck(esp, iPodAck_CmdPending, cmdID, TRACK_CHANGE_TIMEOUT); - - // Fire the A2DP when ready - if (esp->_playStatusHandler) - esp->_playStatusHandler(A2DP_PREV); // Fire the metadata trigger indirectly - } - else if (tempTrackIndex == esp->currentTrackIndex) // Somehow reselecting the current track - { - ESP_LOGD(__func__, "Selected same track as current: %d", tempTrackIndex); - L0x03::_0x00_iPodAck(esp, iPodAck_OK, cmdID); - - // Fire the A2DP when ready - if (esp->_playStatusHandler) - esp->_playStatusHandler(A2DP_PREV); // Fire the metadata trigger indirectly - } - else // If it is not the previous or the current track, it automatically becomes a next track - { - // This is only for when the system requires the data of the previously active track - esp->prevTrackIndex = esp->currentTrackIndex; - strcpy(esp->prevAlbumName, esp->albumName); - strcpy(esp->prevArtistName, esp->artistName); - strcpy(esp->prevTrackTitle, esp->trackTitle); - esp->prevTrackDuration = esp->trackDuration; - - // Cursor operations for NEXT - esp->trackListPosition = (esp->trackListPosition + 1) % TOTAL_NUM_TRACKS; - esp->trackList[esp->trackListPosition] = tempTrackIndex; - esp->currentTrackIndex = tempTrackIndex; - - // Engage the pending ACK for expected metadata - esp->trackChangeAckPending = cmdID; - esp->trackChangeTimestamp = millis(); - ESP_LOGD(__func__, "Prev. index %d New index %d Tracklist pos. %d Pending Meta %d Timestamp: %d --> NEXT ", esp->prevTrackIndex, esp->currentTrackIndex, esp->trackListPosition, (esp->trackChangeAckPending > 0x00), esp->trackChangeTimestamp); - L0x03::_0x00_iPodAck(esp, iPodAck_CmdPending, cmdID, TRACK_CHANGE_TIMEOUT); - - // Fire the A2DP when ready - if (esp->_playStatusHandler) - esp->_playStatusHandler(A2DP_NEXT); // Fire the metadata trigger indirectly - } - } - break; - - case L0x03_GetIndexedPlayingTrackInfo: - { - tempTrackIndex = swap_endian(*((uint32_t *)&byteArray[2])); - switch (byteArray[1]) // Switch on the type of track info requested (careful with overloads) - { - case 0x00: // General track Capabilities and Information - ESP_LOGI(__func__, "CMD 0x%02x GetIndexedPlayingTrackInfo 0x%02x for index %d (previous %d) : Duration", cmdID, byteArray[1], tempTrackIndex, esp->prevTrackIndex); - if (tempTrackIndex == esp->prevTrackIndex) - { - L0x03::_0x13_RetIndexedPlayingTrackInfo(esp, (uint32_t)esp->prevTrackDuration); - } - else - { - L0x03::_0x13_RetIndexedPlayingTrackInfo(esp, (uint32_t)esp->trackDuration); - } - break; - - case 0x02: // Artist Name - ESP_LOGI(__func__, "CMD 0x%02x GetIndexedPlayingTrackInfo 0x%02x for index %d (previous %d) : Artist", cmdID, byteArray[1], tempTrackIndex, esp->prevTrackIndex); - if (tempTrackIndex == esp->prevTrackIndex) - { - L0x03::_0x13_RetIndexedPlayingTrackInfo(esp, byteArray[1], esp->prevArtistName); - } - else - { - L0x03::_0x13_RetIndexedPlayingTrackInfo(esp, byteArray[1], esp->artistName); - } - break; - - case 0x03: // Album Name - ESP_LOGI(__func__, "CMD 0x%02x GetIndexedPlayingTrackInfo 0x%02x for index %d (previous %d) : Album", cmdID, byteArray[1], tempTrackIndex, esp->prevTrackIndex); - if (tempTrackIndex == esp->prevTrackIndex) - { - L0x03::_0x13_RetIndexedPlayingTrackInfo(esp, byteArray[1], esp->prevAlbumName); - } - else - { - L0x03::_0x13_RetIndexedPlayingTrackInfo(esp, byteArray[1], esp->albumName); - } - break; - - case 0x04: // Track Genre - ESP_LOGI(__func__, "CMD 0x%02x GetIndexedPlayingTrackInfo 0x%02x for index %d (previous %d) : Genre", cmdID, byteArray[1], tempTrackIndex, esp->prevTrackIndex); - L0x03::_0x13_RetIndexedPlayingTrackInfo(esp, byteArray[1], esp->trackGenre); - break; - case 0x05: // Track Title - ESP_LOGI(__func__, "CMD 0x%02x GetIndexedPlayingTrackInfo 0x%02x for index %d (previous %d) : Title", cmdID, byteArray[1], tempTrackIndex, esp->prevTrackIndex); - if (tempTrackIndex == esp->prevTrackIndex) - { - L0x03::_0x13_RetIndexedPlayingTrackInfo(esp, byteArray[1], esp->prevTrackTitle); - } - else - { - L0x03::_0x13_RetIndexedPlayingTrackInfo(esp, byteArray[1], esp->trackTitle); - } - break; - case 0x06: // Track Composer - ESP_LOGI(__func__, "CMD 0x%042 GetIndexedPlayingTrackInfo 0x%02x for index %d (previous %d) : Composer", cmdID, byteArray[1], tempTrackIndex, esp->prevTrackIndex); - L0x03::_0x13_RetIndexedPlayingTrackInfo(esp, byteArray[1], esp->composer); - break; - default: // In case the request is beyond the track capabilities - ESP_LOGW(__func__, "CMD 0x%02x GetIndexedPlayingTrackInfo 0x%02x for index %d (previous %d) : Type not recognised!", cmdID, byteArray[1], tempTrackIndex, esp->prevTrackIndex); - L0x03::_0x00_iPodAck(esp, iPodAck_BadParam, cmdID); - break; - } - } - break; - - case L0x03_GetNumPlayingTracks: - { - ESP_LOGI(__func__, "CMD: 0x%02x GetNumPlayingTracks", cmdID); - L0x03::_0x15_RetNumPlayingTracks(esp, TOTAL_NUM_TRACKS); - } - break; - - case L0x03_GetArtworkFormats: - { - ESP_LOGI(__func__, "CMD: 0x%02x GetArtworkFormats", cmdID); - L0x03::_0x17_RetArtworkFormats(esp); - } - break; - - case L0x03_GetTrackArtworkData: - { - ESP_LOGI(__func__, "CMD: 0x%02x GetTrackArtworkData", cmdID); - L0x03::_0x19_RetTrackArtworkData(esp); - } - break; - - case L0x03_GetPowerBatteryState: - { - ESP_LOGI(__func__, "CMD: 0x%02x GetPowerBatteryState", cmdID); - L0x03::_0x1B_RetPowerBatteryState(esp, 0x05); - } - break; - - case L0x03_GetSoundCheckState: - { - ESP_LOGI(__func__, "CMD: 0x%02x GetSoundCheckState", cmdID); - L0x03::_0x1D_RetSoundCheckState(esp, 0x00); - } - break; - - case L0x03_SetSoundCheckState: - { - ESP_LOGI(__func__, "CMD: 0x%02x SetSoundCheckState", cmdID); - L0x03::_0x00_iPodAck(esp, iPodAck_OK, cmdID); - } - break; - - case L0x03_GetTrackArtworkTimes: - { - ESP_LOGI(__func__, "CMD: 0x%02x GetTrackArtworkTimes", cmdID); - L0x03::_0x20_RetTrackArtworkTimes(esp); - } - break; - - case L0x03_CreateGeniusPlaylist: - { - ESP_LOGI(__func__, "CMD: 0x%02x CreateGeniusPlaylist", cmdID); - L0x03::_0x00_iPodAck(esp, iPodAck_SelNotGenius, cmdID); - } - break; - - case L0x03_IsGeniusAvailableForTrack: - { - ESP_LOGI(__func__, "CMD: 0x%02x IsGeniusAvailableForTrack", cmdID); - L0x03::_0x00_iPodAck(esp, iPodAck_SelNotGenius, cmdID); - } - break; - - default: - { - ESP_LOGW(__func__, "CMD 0x%02x not recognized.", cmdID); - L0x03::_0x00_iPodAck(esp, iPodAck_CmdFailed, cmdID); - } - break; - } -} - -void L0x03::_0x00_iPodAck(esPod *esp, IPOD_ACK_CODE ackCode, byte cmdID) -{ - ESP_LOGI(__func__, "Ack 0x%02x to command 0x%02x", ackCode, cmdID); - - const byte txPacket[] = { - 0x03, - 0x00, - ackCode, - cmdID}; - // Stop the timer if the same command is acknowledged before the elapsed time - if (cmdID == esp->_pendingCmdId_0x03) // If the pending command is the one being acknowledged - { - stopTimer(esp->_pendingTimer_0x03); - esp->_pendingCmdId_0x03 = 0x00; - esp->_queuePacketToFront(txPacket, sizeof(txPacket)); // Jump the queue - } - else - esp->_queuePacket(txPacket, sizeof(txPacket)); -} - -void L0x03::_0x00_iPodAck(esPod *esp, IPOD_ACK_CODE ackCode, byte cmdID, uint32_t numField) -{ - ESP_LOGI(__func__, "Ack 0x%02x to command 0x%02x Numfield: %d", ackCode, cmdID, numField); - const byte txPacket[8] = { - 0x03, - 0x00, - ackCode, - cmdID}; - *((uint32_t *)&txPacket[4]) = swap_endian(numField); - esp->_queuePacket(txPacket, sizeof(txPacket)); - // Starting delayed timer for the iPodAck - esp->_pendingCmdId_0x03 = cmdID; - startTimer(esp->_pendingTimer_0x03, numField); -} - -void L0x03::_0x02_RetCurrentEQProfileIndex(esPod *esp) -{ - ESP_LOGI(__func__, "Return EQ Profile Index 0x00 0x00 0x00 0x00"); - - const byte txPacket[] = { - 0x03, - 0x02, - 0x00, 0x00, 0x00, 0x00}; - esp->_queuePacket(txPacket, sizeof(txPacket)); -} - -void L0x03::_0x05_RetNumEQProfiles(esPod *esp) -{ - ESP_LOGI(__func__, "Return Num Profiles : 1"); - - const byte txPacket[] = { - 0x03, - 0x05, - 0x00, 0x00, 0x00, 0x00}; - *((uint32_t *)&txPacket[2]) = swap_endian(1); - esp->_queuePacket(txPacket, sizeof(txPacket)); -} - -void L0x03::_0x07_RetIndexedEQProfileName(esPod *esp) -{ - const char *EQProfileName = "Base EQ"; - ESP_LOGI(__func__, "Return EQ name : %s", EQProfileName); - byte txPacket[255] = { - 0x03, - 0x07}; - strcpy((char *)&txPacket[2], EQProfileName); - esp->_queuePacket(txPacket, 3 + strlen(EQProfileName)); -} - -void L0x03::_0x09_RemoteEventNotification(esPod *esp) -{ - ESP_LOGW(__func__, "RemoteEventNotificiation not implemented"); -} - -void L0x03::_0x0B_RetRemoteEventStatus(esPod *esp, uint32_t remEventStatus) -{ - ESP_LOGW(__func__, "RetRemoveEventStatus not implemented"); -} - -void L0x03::_0x0D_RetiPodStateInfo(esPod *esp) -{ - ESP_LOGW(__func__, "RetiPodStateInfo not implemented"); -} - -void L0x03::_0x10_RetPlayStatus(esPod *esp, byte playState, uint32_t trackIndex, uint32_t trackTotMs, uint32_t trackPosMs) -{ - ESP_LOGI(__func__, "Play status 0x%02x of index %d at pos. %d / %d ms", playState, trackIndex, trackPosMs, trackTotMs); - byte txPacket[] = { - 0x03, - 0x10, - playState, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00}; - *((uint32_t *)&txPacket[3]) = swap_endian(trackIndex); - *((uint32_t *)&txPacket[7]) = swap_endian(trackTotMs); - *((uint32_t *)&txPacket[11]) = swap_endian(trackPosMs); - esp->_queuePacket(txPacket, sizeof(txPacket)); -} - -void L0x03::_0x13_RetIndexedPlayingTrackInfo(esPod *esp, byte trackInfoType, char *trackInfoChars) -{ - ESP_LOGI(__func__, "Req'd track info type: 0x%02x", trackInfoType); - byte txPacket[255] = { - 0x03, - 0x13, - trackInfoType}; - strcpy((char *)&txPacket[3], trackInfoChars); - esp->_queuePacket(txPacket, 3 + strlen(trackInfoChars) + 1); -} - -void L0x03::_0x13_RetIndexedPlayingTrackInfo(esPod *esp, uint32_t trackDuration_ms) -{ - ESP_LOGI(__func__, "Track duration: %d", trackDuration_ms); - byte txPacket[13] = { - 0x03, - 0x13, - 0x00, // Info type - 0x00, 0x00, 0x00, 0x00, // This says it does not have artwork etc - 0x00, 0x00, 0x00, 0x01, // Track length in ms - 0x00, 0x00 // Chapter count (none) - }; - *((uint32_t *)&txPacket[7]) = swap_endian(trackDuration_ms); - esp->_queuePacket(txPacket, sizeof(txPacket)); -} - -void L0x03::_0x15_RetNumPlayingTracks(esPod *esp, uint32_t numPlayingTracks) -{ - ESP_LOGI(__func__, "Playing tracks: %d", numPlayingTracks); - byte txPacket[] = { - 0x03, - 0x15, - 0x00, 0x00, 0x00, 0x00}; - *((uint32_t *)&txPacket[2]) = swap_endian(numPlayingTracks); - esp->_queuePacket(txPacket, sizeof(txPacket)); -} - -void L0x03::_0x17_RetArtworkFormats(esPod *esp) -{ - ESP_LOGW(__func__, "RetArtworkFormats not implemented"); -} - -void L0x03::_0x19_RetTrackArtworkData(esPod *esp) -{ - ESP_LOGW(__func__, "RetTrackArtworkData not implemented"); -} - -void L0x03::_0x1B_RetPowerBatteryState(esPod *esp, byte powerBatteryState) -{ - ESP_LOGI(__func__, "RetPowerBatteryState 0x%02x", powerBatteryState); - /* - 0x00 -> Internal battery power, low power - 0x01 -> Internal battery power - 0x02 -> External power, battery pack, no charging - 0x03 -> External power, no charging - 0x04 -> External power, battery charging - 0x05 -> External power, battery charged - */ - byte batteryLevel = 0x00; - switch (powerBatteryState) - { - case 0x00: - batteryLevel = (29 / 100) * 255; - break; - case 0x01: - batteryLevel = 255 / 2; - break; - default: - batteryLevel = 0xFF; - break; - } - - byte txPacket[] = { - 0x03, - 0x1B, - powerBatteryState, - batteryLevel}; - esp->_queuePacket(txPacket, sizeof(txPacket)); -} - -void L0x03::_0x1D_RetSoundCheckState(esPod *esp, byte soundCheckState) -{ - // Might need to introduce and internal variable for the sound check state here - ESP_LOGI(__func__, "RetSoundCheckState 0x%02x", soundCheckState); - byte txPacket[] = { - 0x03, - 0x1D, - soundCheckState}; - esp->_queuePacket(txPacket, sizeof(txPacket)); -} - -void L0x03::_0x20_RetTrackArtworkTimes(esPod *esp) -{ - ESP_LOGW(__func__, "RetTrackArtworkTimes not implemented"); -} diff --git a/src/L0x04.cpp b/src/L0x04.cpp deleted file mode 100644 index 81b9632..0000000 --- a/src/L0x04.cpp +++ /dev/null @@ -1,896 +0,0 @@ -#include "Arduino.h" -#include "L0x04.h" -#include "esPod.h" - -/// @brief -/// @param esp Pointer to the esPod instance -/// @param byteArray -/// @param len -void L0x04::processLingo(esPod *esp, const byte *byteArray, uint32_t len) -{ - byte cmdID = byteArray[1]; - // Initialising handlers to understand what is happening in some parts of the switch. They cannot be initialised in the switch-case scope - byte category; - uint32_t startIndex, counts, tempTrackIndex; - char noCat[25] = "--"; - - if (!esp->extendedInterfaceModeActive) - { // Complain if not in extended interface mode - ESP_LOGW(__func__, "CMD 0x%04x not executed : Not in extendedInterfaceMode!", cmdID); - L0x04::_0x01_iPodAck(esp, iPodAck_BadParam, cmdID); - } - // Good to go if in Extended Interface mode - else - { - switch (cmdID) // Reminder : we are technically switching on byteArray[1] now - { - case L0x04_GetIndexedPlayingTrackInfo: - { - tempTrackIndex = swap_endian(*((uint32_t *)&byteArray[3])); - switch (byteArray[2]) // Switch on the type of track info requested (careful with overloads) - { - case 0x00: // General track Capabilities and Information - ESP_LOGI(__func__, "CMD 0x%04x GetIndexedPlayingTrackInfo 0x%02x for index %d (previous %d) : Duration", cmdID, byteArray[2], tempTrackIndex, esp->prevTrackIndex); - if (tempTrackIndex == esp->prevTrackIndex) - { - L0x04::_0x0D_ReturnIndexedPlayingTrackInfo(esp, (uint32_t)esp->prevTrackDuration); - } - else - { - L0x04::_0x0D_ReturnIndexedPlayingTrackInfo(esp, (uint32_t)esp->trackDuration); - } - break; - case 0x02: // Track Release Date (fictional) - ESP_LOGI(__func__, "CMD 0x%04x GetIndexedPlayingTrackInfo 0x%02x for index %d (previous %d) : Release date", cmdID, byteArray[2], tempTrackIndex, esp->prevTrackIndex); - L0x04::_0x0D_ReturnIndexedPlayingTrackInfo(esp, byteArray[2], (uint16_t)2001); - break; - case 0x01: // Track Title - ESP_LOGI(__func__, "CMD 0x%04x GetIndexedPlayingTrackInfo 0x%02x for index %d (previous %d) : Title", cmdID, byteArray[2], tempTrackIndex, esp->prevTrackIndex); - if (tempTrackIndex == esp->prevTrackIndex) - { - L0x04::_0x0D_ReturnIndexedPlayingTrackInfo(esp, byteArray[2], esp->prevTrackTitle); - } - else - { - L0x04::_0x0D_ReturnIndexedPlayingTrackInfo(esp, byteArray[2], esp->trackTitle); - } - break; - case 0x05: // Track Genre - ESP_LOGI(__func__, "CMD 0x%04x GetIndexedPlayingTrackInfo 0x%02x for index %d (previous %d) : Genre", cmdID, byteArray[2], tempTrackIndex, esp->prevTrackIndex); - L0x04::_0x0D_ReturnIndexedPlayingTrackInfo(esp, byteArray[2], esp->trackGenre); - break; - case 0x06: // Track Composer - ESP_LOGI(__func__, "CMD 0x%04x GetIndexedPlayingTrackInfo 0x%02x for index %d (previous %d) : Composer", cmdID, byteArray[2], tempTrackIndex, esp->prevTrackIndex); - L0x04::_0x0D_ReturnIndexedPlayingTrackInfo(esp, byteArray[2], esp->composer); - break; - default: // In case the request is beyond the track capabilities - ESP_LOGW(__func__, "CMD 0x%04x GetIndexedPlayingTrackInfo 0x%02x for index %d (previous %d) : Type not recognised!", cmdID, byteArray[2], tempTrackIndex, esp->prevTrackIndex); - L0x04::_0x01_iPodAck(esp, iPodAck_BadParam, cmdID); - break; - } - } - break; - - case L0x04_RequestProtocolVersion: // Hardcoded return for L0x04 - { - ESP_LOGI(__func__, "CMD 0x%04x RequestProtocolVersion", cmdID); - L0x04::_0x13_ReturnProtocolVersion(esp); // Potentially should use L0x00_0x10 instead ? L0x00_0x10_ReturnLingoProtocolVersion(byteArray[2]); - // L0x00_0x27_GetAccessoryInfo(0x00); // Attempting to start normal handshake - } - break; - - case L0x04_ResetDBSelection: // Not sure what to do here. Reset Current Track Index ? - { - ESP_LOGI(__func__, "CMD 0x%04x ResetDBSelection", cmdID); - L0x04::_0x01_iPodAck(esp, iPodAck_OK, cmdID); - } - break; - - case L0x04_SelectDBRecord: // Used for browsing ? - { - ESP_LOGI(__func__, "CMD 0x%04x SelectDBRecord", cmdID); - L0x04::_0x01_iPodAck(esp, iPodAck_OK, cmdID); - } - break; - - case L0x04_GetNumberCategorizedDBRecords: // Mini requests the number of records for a specific DB_CAT - { - category = byteArray[2]; - ESP_LOGI(__func__, "CMD 0x%04x GetNumberCategorizedDBRecords category: 0x%02x", cmdID, category); - if (category == DB_CAT_TRACK) - { - L0x04::_0x19_ReturnNumberCategorizedDBRecords(esp, esp->totalNumberTracks); // Say there are fixed, large amount of tracks - } - else - { // And only one of anything else (Playlist, album, artist etc...) - L0x04::_0x19_ReturnNumberCategorizedDBRecords(esp, 1); - } - } - break; - - case L0x04_RetrieveCategorizedDatabaseRecords: // Loops through the desired records for a given DB_CAT - { - category = byteArray[2]; // DBCat - startIndex = swap_endian(*(uint32_t *)&byteArray[3]); - counts = swap_endian(*(uint32_t *)&byteArray[7]); - - ESP_LOGI(__func__, "CMD 0x%04x RetrieveCategorizedDatabaseRecords category: 0x%02x from %d for %d counts", cmdID, category, startIndex, counts); - switch (category) - { - case DB_CAT_PLAYLIST: - for (uint32_t i = startIndex; i < startIndex + counts; i++) - { - L0x04::_0x1B_ReturnCategorizedDatabaseRecord(esp, i, esp->playList); - } - break; - case DB_CAT_ARTIST: - for (uint32_t i = startIndex; i < startIndex + counts; i++) - { - L0x04::_0x1B_ReturnCategorizedDatabaseRecord(esp, i, esp->artistName); - } - break; - case DB_CAT_ALBUM: - for (uint32_t i = startIndex; i < startIndex + counts; i++) - { - L0x04::_0x1B_ReturnCategorizedDatabaseRecord(esp, i, esp->albumName); - } - break; - case DB_CAT_GENRE: - for (uint32_t i = startIndex; i < startIndex + counts; i++) - { - L0x04::_0x1B_ReturnCategorizedDatabaseRecord(esp, i, esp->trackGenre); - } - break; - case DB_CAT_TRACK: // Will sometimes return twice - for (uint32_t i = startIndex; i < startIndex + counts; i++) - { - L0x04::_0x1B_ReturnCategorizedDatabaseRecord(esp, i, esp->trackTitle); - } - break; - case DB_CAT_COMPOSER: - for (uint32_t i = startIndex; i < startIndex + counts; i++) - { - L0x04::_0x1B_ReturnCategorizedDatabaseRecord(esp, i, esp->composer); - } - break; - case DB_CAT_AUDIOBOOK: - for (uint32_t i = startIndex; i < startIndex + counts; i++) - { - L0x04::_0x1B_ReturnCategorizedDatabaseRecord(esp, i, noCat); - } - break; - case DB_CAT_PODCAST: - for (uint32_t i = startIndex; i < startIndex + counts; i++) - { - L0x04::_0x1B_ReturnCategorizedDatabaseRecord(esp, i, noCat); - } - break; - default: - ESP_LOGW(__func__, "CMD 0x%04x RetrieveCategorizedDatabaseRecords category: 0x%02x not recognised", cmdID, category); - L0x04::_0x01_iPodAck(esp, iPodAck_BadParam, cmdID); - break; - } - } - break; - - case L0x04_GetPlayStatus: // Returns the current esp->playStatus and the position/duration of the current track - { - ESP_LOGI(__func__, "CMD 0x%04x GetPlayStatus", cmdID); - L0x04::_0x1D_ReturnPlayStatus(esp, esp->playPosition, esp->trackDuration, esp->playStatus); - } - break; - - case L0x04_GetCurrentPlayingTrackIndex: // Get the uint32 index of the currently playing song - { - ESP_LOGI(__func__, "CMD 0x%04x GetCurrentPlayingTrackIndex", cmdID); - L0x04::_0x1F_ReturnCurrentPlayingTrackIndex(esp, esp->currentTrackIndex); - } - break; - - case L0x04_GetIndexedPlayingTrackTitle: - { - tempTrackIndex = swap_endian(*((uint32_t *)&byteArray[2])); - ESP_LOGI(__func__, "CMD 0x%04x GetIndexedPlayingTrackTitle for index %d (previous %d)", cmdID, tempTrackIndex, esp->prevTrackIndex); - if (tempTrackIndex == esp->prevTrackIndex) - { - L0x04::_0x21_ReturnIndexedPlayingTrackTitle(esp, esp->prevTrackTitle); - } - else - { - L0x04::_0x21_ReturnIndexedPlayingTrackTitle(esp, esp->trackTitle); - } - } - break; - - case L0x04_GetIndexedPlayingTrackArtistName: - { - tempTrackIndex = swap_endian(*((uint32_t *)&byteArray[2])); - - ESP_LOGI(__func__, "CMD 0x%04x GetIndexedPlayingTrackArtistName for index %d (previous %d)", cmdID, tempTrackIndex, esp->prevTrackIndex); - if (tempTrackIndex == esp->prevTrackIndex) - { - L0x04::_0x23_ReturnIndexedPlayingTrackArtistName(esp, esp->prevArtistName); - } - else - { - L0x04::_0x23_ReturnIndexedPlayingTrackArtistName(esp, esp->artistName); - } - } - break; - - case L0x04_GetIndexedPlayingTrackAlbumName: - { - tempTrackIndex = swap_endian(*((uint32_t *)&byteArray[2])); - ESP_LOGI(__func__, "CMD 0x%04x GetIndexedPlayingTrackAlbumName for index %d (previous %d)", cmdID, tempTrackIndex, esp->prevTrackIndex); - if (tempTrackIndex == esp->prevTrackIndex) - { - L0x04::_0x25_ReturnIndexedPlayingTrackAlbumName(esp, esp->prevAlbumName); - } - else - { - L0x04::_0x25_ReturnIndexedPlayingTrackAlbumName(esp, esp->albumName); - } - } - break; - - case L0x04_SetPlayStatusChangeNotification: // Turns on basic notifications - { - esp->playStatusNotificationState = byteArray[2]; - ESP_LOGI(__func__, "CMD 0x%04x SetPlayStatusChangeNotification 0x%02x", cmdID, esp->playStatusNotificationState); - L0x04::_0x01_iPodAck(esp, iPodAck_OK, cmdID); - } - break; - - case L0x04_PlayCurrentSelection: // Used to play a specific index, usually for "next" commands, but may be used to actually jump anywhere - { - tempTrackIndex = swap_endian(*((uint32_t *)&byteArray[2])); - ESP_LOGI(__func__, "CMD 0x%04x PlayCurrentSelection index %d", cmdID, tempTrackIndex); - if (esp->playStatus != PB_STATE_PLAYING) - { - esp->playStatus = PB_STATE_PLAYING; // Playing status forced - if (esp->_playStatusHandler) - { - esp->_playStatusHandler(A2DP_PLAY); // Send play to the a2dp - } - } - if (tempTrackIndex == esp->trackList[(esp->trackListPosition + TOTAL_NUM_TRACKS - 1) % TOTAL_NUM_TRACKS]) // Desired trackIndex is the left entry - { - // This is only for when the system requires the data of the previously active track - esp->prevTrackIndex = esp->currentTrackIndex; - strcpy(esp->prevAlbumName, esp->albumName); - strcpy(esp->prevArtistName, esp->artistName); - strcpy(esp->prevTrackTitle, esp->trackTitle); - esp->prevTrackDuration = esp->trackDuration; - - // Cursor operations for PREV - esp->trackListPosition = (esp->trackListPosition + TOTAL_NUM_TRACKS - 1) % TOTAL_NUM_TRACKS; // Shift esp->trackListPosition one to the right - esp->currentTrackIndex = tempTrackIndex; - - // Engage the pending ACK for expected metadata - esp->trackChangeAckPending = cmdID; - esp->trackChangeTimestamp = millis(); - ESP_LOGD(__func__, "Prev. index %d New index %d Tracklist pos. %d Pending Meta %d Timestamp: %d --> PREV ", esp->prevTrackIndex, esp->currentTrackIndex, esp->trackListPosition, (esp->trackChangeAckPending > 0x00), esp->trackChangeTimestamp); - L0x04::_0x01_iPodAck(esp, iPodAck_CmdPending, cmdID, TRACK_CHANGE_TIMEOUT); - - // Fire the A2DP when ready - if (esp->_playStatusHandler) - esp->_playStatusHandler(A2DP_PREV); // Fire the metadata trigger indirectly - } - else if (tempTrackIndex == esp->currentTrackIndex) // Somehow reselecting the current track - { - ESP_LOGD(__func__, "Selected same track as current: %d", tempTrackIndex); - L0x04::_0x01_iPodAck(esp, iPodAck_OK, cmdID); - - // Fire the A2DP when ready - if (esp->_playStatusHandler) - esp->_playStatusHandler(A2DP_PREV); // Fire the metadata trigger indirectly - } - else // If it is not the previous or the current track, it automatically becomes a next track - { - // This is only for when the system requires the data of the previously active track - esp->prevTrackIndex = esp->currentTrackIndex; - strcpy(esp->prevAlbumName, esp->albumName); - strcpy(esp->prevArtistName, esp->artistName); - strcpy(esp->prevTrackTitle, esp->trackTitle); - esp->prevTrackDuration = esp->trackDuration; - - // Cursor operations for NEXT - esp->trackListPosition = (esp->trackListPosition + 1) % TOTAL_NUM_TRACKS; - esp->trackList[esp->trackListPosition] = tempTrackIndex; - esp->currentTrackIndex = tempTrackIndex; - - // Engage the pending ACK for expected metadata - esp->trackChangeAckPending = cmdID; - esp->trackChangeTimestamp = millis(); - ESP_LOGD(__func__, "Prev. index %d New index %d Tracklist pos. %d Pending Meta %d Timestamp: %d --> NEXT ", esp->prevTrackIndex, esp->currentTrackIndex, esp->trackListPosition, (esp->trackChangeAckPending > 0x00), esp->trackChangeTimestamp); - L0x04::_0x01_iPodAck(esp, iPodAck_CmdPending, cmdID, TRACK_CHANGE_TIMEOUT); - - // Fire the A2DP when ready - if (esp->_playStatusHandler) - esp->_playStatusHandler(A2DP_NEXT); // Fire the metadata trigger indirectly - } - } - break; - - case L0x04_PlayControl: // Basic play control. Used for Prev, pause and play - { - ESP_LOGI(__func__, "CMD 0x%04x PlayControl req: 0x%02x vs esp->playStatus: 0x%02x", cmdID, byteArray[2], esp->playStatus); - switch (byteArray[2]) // PlayControl byte - { - case PB_CMD_TOGGLE: // Just Toggle or start playing - { - if (esp->playStatus == PB_STATE_PLAYING) - { - esp->playStatus = PB_STATE_PAUSED; // Toggle to paused if playing - if (esp->_playStatusHandler) - esp->_playStatusHandler(A2DP_PAUSE); - } - else - { - esp->playStatus = PB_STATE_PLAYING; // Switch to playing in any other case - if (esp->_playStatusHandler) - esp->_playStatusHandler(A2DP_PLAY); - } - L0x04::_0x01_iPodAck(esp, iPodAck_OK, cmdID); - } - break; - case PB_CMD_STOP: // Stop - { - esp->playStatus = PB_STATE_STOPPED; - if (esp->_playStatusHandler) - esp->_playStatusHandler(A2DP_STOP); - L0x04::_0x01_iPodAck(esp, iPodAck_OK, cmdID); - } - break; - case PB_CMD_NEXT_TRACK: // Next track.. never seems to happen ? - { - // This is only for when the system requires the data of the previously active track - esp->prevTrackIndex = esp->currentTrackIndex; - strcpy(esp->prevAlbumName, esp->albumName); - strcpy(esp->prevArtistName, esp->artistName); - strcpy(esp->prevTrackTitle, esp->trackTitle); - esp->prevTrackDuration = esp->trackDuration; - - // Cursor operations for NEXT - esp->trackListPosition = (esp->trackListPosition + 1) % TOTAL_NUM_TRACKS; - esp->currentTrackIndex = esp->trackList[esp->trackListPosition]; - - // Engage the pending ACK for expected metadata - esp->trackChangeAckPending = cmdID; - esp->trackChangeTimestamp = millis(); - ESP_LOGD(__func__, "Prev. index %d New index %d Tracklist pos. %d Pending Meta %d Timestamp: %d --> EXPLICIT NEXT TRACK", esp->prevTrackIndex, esp->currentTrackIndex, esp->trackListPosition, (esp->trackChangeAckPending > 0x00), esp->trackChangeTimestamp); - L0x04::_0x01_iPodAck(esp, iPodAck_CmdPending, cmdID, TRACK_CHANGE_TIMEOUT); - - // Fire the A2DP when ready - if (esp->_playStatusHandler) - esp->_playStatusHandler(A2DP_NEXT); // Fire the metadata trigger indirectly - } - break; - case PB_CMD_PREVIOUS_TRACK: // Prev track - { - ESP_LOGD(__func__, "Current index %d Tracklist pos. %d --> EXPLICIT SINGLE PREV TRACK", esp->currentTrackIndex, esp->trackListPosition); - L0x04::_0x01_iPodAck(esp, iPodAck_OK, cmdID); - - // Fire the A2DP when ready - if (esp->_playStatusHandler) - esp->_playStatusHandler(A2DP_PREV); // Fire the metadata trigger indirectly - } - break; - case PB_CMD_NEXT: // Next track - { - // This is only for when the system requires the data of the previously active track - esp->prevTrackIndex = esp->currentTrackIndex; - strcpy(esp->prevAlbumName, esp->albumName); - strcpy(esp->prevArtistName, esp->artistName); - strcpy(esp->prevTrackTitle, esp->trackTitle); - esp->prevTrackDuration = esp->trackDuration; - - // Cursor operations for NEXT - esp->trackListPosition = (esp->trackListPosition + 1) % TOTAL_NUM_TRACKS; - esp->currentTrackIndex = esp->trackList[esp->trackListPosition]; - - // Engage the pending ACK for expected metadata - esp->trackChangeAckPending = cmdID; - esp->trackChangeTimestamp = millis(); - ESP_LOGD(__func__, "Prev. index %d New index %d Tracklist pos. %d Pending Meta %d Timestamp: %d --> EXPLICIT NEXT", esp->prevTrackIndex, esp->currentTrackIndex, esp->trackListPosition, (esp->trackChangeAckPending > 0x00), esp->trackChangeTimestamp); - L0x04::_0x01_iPodAck(esp, iPodAck_CmdPending, cmdID, TRACK_CHANGE_TIMEOUT); - - // Fire the A2DP when ready - if (esp->_playStatusHandler) - esp->_playStatusHandler(A2DP_NEXT); // Fire the metadata trigger indirectly - } - break; - case PB_CMD_PREV: // Prev track - { - ESP_LOGD(__func__, "Current index %d Tracklist pos. %d --> EXPLICIT SINGLE PREV", esp->currentTrackIndex, esp->trackListPosition); - L0x04::_0x01_iPodAck(esp, iPodAck_OK, cmdID); - - // Fire the A2DP when ready - if (esp->_playStatusHandler) - esp->_playStatusHandler(A2DP_PREV); // Fire the metadata trigger indirectly - } - break; - case PB_CMD_PLAY: // Play... do we need to have an ack pending ? - { - esp->playStatus = PB_STATE_PLAYING; - - // Engage the pending ACK for expected metadata - esp->trackChangeAckPending = cmdID; - esp->trackChangeTimestamp = millis(); - L0x04::_0x01_iPodAck(esp, iPodAck_CmdPending, cmdID, TRACK_CHANGE_TIMEOUT); - - if (esp->_playStatusHandler) - esp->_playStatusHandler(A2DP_PLAY); - } - break; - case PB_CMD_PAUSE: // Pause - { - esp->playStatus = PB_STATE_PAUSED; - L0x04::_0x01_iPodAck(esp, iPodAck_OK, cmdID); - if (esp->_playStatusHandler) - esp->_playStatusHandler(A2DP_PAUSE); - } - break; - } - if ((esp->playStatus == PB_STATE_STOPPED) && (esp->playStatusNotificationState == NOTIF_ON)) - L0x04::_0x27_PlayStatusNotification(esp, 0x00); // Notify successful stop - } - break; - - case L0x04_GetShuffle: // Get Shuffle state from the PB Engine - { - ESP_LOGI(__func__, "CMD 0x%04x GetShuffle", cmdID); - L0x04::_0x2D_ReturnShuffle(esp, esp->shuffleStatus); - } - break; - - case L0x04_SetShuffle: // Set Shuffle state - { - ESP_LOGI(__func__, "CMD 0x%04x SetShuffle req: 0x%02x vs shuffleStatus: 0x%02x", cmdID, byteArray[2], esp->shuffleStatus); - esp->shuffleStatus = byteArray[2]; - L0x04::_0x01_iPodAck(esp, iPodAck_OK, cmdID); - } - break; - - case L0x04_GetRepeat: // Get Repeat state - { - ESP_LOGI(__func__, "CMD 0x%04x GetRepeat", cmdID); - L0x04::_0x30_ReturnRepeat(esp, esp->repeatStatus); - } - break; - - case L0x04_SetRepeat: // Set Repeat state - { - ESP_LOGI(__func__, "CMD 0x%04x SetRepeat req: 0x%02x vs repeatStatus: 0x%02x", cmdID, byteArray[2], esp->repeatStatus); - esp->repeatStatus = byteArray[2]; - L0x04::_0x01_iPodAck(esp, iPodAck_OK, cmdID); - } - break; - - case L0x04_GetMonoDisplayImageLimits: - { - ESP_LOGI(__func__, "CMD 0x0%04x GetMonoDisplayImageLimits", cmdID); - L0x04::_0x34_ReturnMonoDisplayImageLimits(esp, 0, 0, 0x01); // Not sure this is OK - } - break; - - case L0x04_GetNumPlayingTracks: // Systematically return TOTAL_NUM_TRACKS - { - ESP_LOGI(__func__, "CMD 0x%04x GetNumPlayingTracks", cmdID); - L0x04::_0x36_ReturnNumPlayingTracks(esp, esp->totalNumberTracks); - } - break; - - case L0x04_SetCurrentPlayingTrack: // Basically identical to PlayCurrentSelection - { - tempTrackIndex = swap_endian(*((uint32_t *)&byteArray[2])); - ESP_LOGI(__func__, "CMD 0x%04x SetCurrentPlayingTrack index %d", cmdID, tempTrackIndex); - if (esp->playStatus != PB_STATE_PLAYING) - { - esp->playStatus = PB_STATE_PLAYING; // Playing status forced - if (esp->_playStatusHandler) - { - esp->_playStatusHandler(A2DP_PLAY); // Send play to the a2dp - } - } - if (tempTrackIndex == esp->trackList[(esp->trackListPosition + TOTAL_NUM_TRACKS - 1) % TOTAL_NUM_TRACKS]) // Desired trackIndex is the left entry - { - // This is only for when the system requires the data of the previously active track - esp->prevTrackIndex = esp->currentTrackIndex; - strcpy(esp->prevAlbumName, esp->albumName); - strcpy(esp->prevArtistName, esp->artistName); - strcpy(esp->prevTrackTitle, esp->trackTitle); - esp->prevTrackDuration = esp->trackDuration; - - // Cursor operations for PREV - esp->trackListPosition = (esp->trackListPosition + TOTAL_NUM_TRACKS - 1) % TOTAL_NUM_TRACKS; // Shift esp->trackListPosition one to the right - esp->currentTrackIndex = tempTrackIndex; - - // Engage the pending ACK for expected metadata - esp->trackChangeAckPending = cmdID; - esp->trackChangeTimestamp = millis(); - ESP_LOGD(__func__, "Prev. index %d New index %d Tracklist pos. %d Pending Meta %d Timestamp: %d --> PREV ", esp->prevTrackIndex, esp->currentTrackIndex, esp->trackListPosition, (esp->trackChangeAckPending > 0x00), esp->trackChangeTimestamp); - L0x04::_0x01_iPodAck(esp, iPodAck_CmdPending, cmdID, TRACK_CHANGE_TIMEOUT); - - // Fire the A2DP when ready - if (esp->_playStatusHandler) - esp->_playStatusHandler(A2DP_PREV); // Fire the metadata trigger indirectly - } - else if (tempTrackIndex == esp->currentTrackIndex) // Somehow reselecting the current track - { - ESP_LOGD(__func__, "Selected same track as current: %d", tempTrackIndex); - L0x04::_0x01_iPodAck(esp, iPodAck_OK, cmdID); - - // Fire the A2DP when ready - if (esp->_playStatusHandler) - esp->_playStatusHandler(A2DP_PREV); // Fire the metadata trigger indirectly - } - else // If it is not the previous or the current track, it automatically becomes a next track - { - // This is only for when the system requires the data of the previously active track - esp->prevTrackIndex = esp->currentTrackIndex; - strcpy(esp->prevAlbumName, esp->albumName); - strcpy(esp->prevArtistName, esp->artistName); - strcpy(esp->prevTrackTitle, esp->trackTitle); - esp->prevTrackDuration = esp->trackDuration; - - // Cursor operations for NEXT - esp->trackListPosition = (esp->trackListPosition + 1) % TOTAL_NUM_TRACKS; - esp->trackList[esp->trackListPosition] = tempTrackIndex; - esp->currentTrackIndex = tempTrackIndex; - - // Engage the pending ACK for expected metadata - esp->trackChangeAckPending = cmdID; - esp->trackChangeTimestamp = millis(); - ESP_LOGD(__func__, "Prev. index %d New index %d Tracklist pos. %d Pending Meta %d Timestamp: %d --> NEXT ", esp->prevTrackIndex, esp->currentTrackIndex, esp->trackListPosition, (esp->trackChangeAckPending > 0x00), esp->trackChangeTimestamp); - L0x04::_0x01_iPodAck(esp, iPodAck_CmdPending, cmdID, TRACK_CHANGE_TIMEOUT); - - // Fire the A2DP when ready - if (esp->_playStatusHandler) - esp->_playStatusHandler(A2DP_NEXT); // Fire the metadata trigger indirectly - } - } - break; - - case L0x04_SelectSortDBRecord: // Used for browsing ? - { - ESP_LOGI(__func__, "CMD 0x%04x SelectSortDBRecord (deprecated)", cmdID); - L0x04::_0x01_iPodAck(esp, iPodAck_OK, cmdID); - } - break; - - case L0x04_GetColorDisplayImageLimits: - { - ESP_LOGI(__func__, "CMD 0x0%04x GetColorDisplayImageLimits", cmdID); - L0x04::_0x3A_ReturnColorDisplayImageLimits(esp, 0, 0, 0x01); // Not sure this is OK - } - break; - - default: - { - ESP_LOGW(__func__, "CMD 0x%04x not recognized.", cmdID); - L0x04::_0x01_iPodAck(esp, iPodAck_CmdFailed, cmdID); - } - break; - } - } -} - -/// @brief General response command for Lingo 0x04 -/// @param esp Pointer to the esPod instance -/// @param cmdStatus Has to obey to iPodAck_xxx format as defined in L0x00.h -/// @param cmdID last two ID bytes of the Lingo 0x04 command replied to -void L0x04::_0x01_iPodAck(esPod *esp, IPOD_ACK_CODE ackCode, byte cmdID) -{ - ESP_LOGI(__func__, "Ack 0x%02x to command 0x%04x", ackCode, cmdID); - // Queue the ack packet - const byte txPacket[] = { - 0x04, - 0x00, 0x01, - ackCode, - 0x00, cmdID}; - // Stop the timer if the same command is acknowledged before the elapsed time - if (cmdID == esp->_pendingCmdId_0x04) // If the pending command is the one being acknowledged - { - stopTimer(esp->_pendingTimer_0x04); - esp->_pendingCmdId_0x04 = 0x00; - esp->_queuePacketToFront(txPacket, sizeof(txPacket)); // Jump the queue - } - else - esp->_queuePacket(txPacket, sizeof(txPacket)); // Queue at the back -} - -/// @brief General response command for Lingo 0x04 with numerical field (used for Ack Pending). Has to be followed up with a normal iPodAck -/// @param esp Pointer to the esPod instance -/// @param cmdStatus Unprotected, but should only be iPodAck_CmdPending -/// @param cmdID Single end-byte ID of the command being acknowledged with Pending -/// @param numField Pending delay in milliseconds -void L0x04::_0x01_iPodAck(esPod *esp, IPOD_ACK_CODE ackCode, byte cmdID, uint32_t numField) -{ - ESP_LOGI(__func__, "Ack 0x%02x to command 0x%04x Numfield: %d", ackCode, cmdID, numField); - const byte txPacket[20] = { - 0x04, - 0x00, 0x01, - ackCode, - cmdID}; - *((uint32_t *)&txPacket[5]) = swap_endian(numField); - esp->_queuePacket(txPacket, 5 + 4); - // Starting delayed timer for the iPodAck - esp->_pendingCmdId_0x04 = cmdID; - startTimer(esp->_pendingTimer_0x04, numField); -} - -/// @brief Returns the pseudo-UTF8 string for the track info types 01/05/06 -/// @param esp Pointer to the esPod instance -/// @param trackInfoType 0x01 : Title / 0x05 : Genre / 0x06 : Composer -/// @param trackInfoChars Character array to pass and package in the tail of the message -void L0x04::_0x0D_ReturnIndexedPlayingTrackInfo(esPod *esp, byte trackInfoType, char *trackInfoChars) -{ - ESP_LOGI(__func__, "Req'd track info type: 0x%02x", trackInfoType); - byte txPacket[255] = { - 0x04, - 0x00, 0x0D, - trackInfoType}; - strcpy((char *)&txPacket[4], trackInfoChars); - esp->_queuePacket(txPacket, 4 + strlen(trackInfoChars) + 1); -} - -/// @brief Returns the playing track total duration in milliseconds (Implicit track info 0x00) -/// @param esp Pointer to the esPod instance -/// @param trackDuration_ms trackduration in ms -void L0x04::_0x0D_ReturnIndexedPlayingTrackInfo(esPod *esp, uint32_t trackDuration_ms) -{ - ESP_LOGI(__func__, "Track duration: %d", trackDuration_ms); - byte txPacket[14] = { - 0x04, - 0x00, 0x0D, - 0x00, - 0x00, 0x00, 0x00, 0x00, // This says it does not have artwork etc - 0x00, 0x00, 0x00, 0x01, // Track length in ms - 0x00, 0x00 // Chapter count (none) - }; - *((uint32_t *)&txPacket[8]) = swap_endian(trackDuration_ms); - esp->_queuePacket(txPacket, sizeof(txPacket)); -} - -/// @brief Overloaded return of the playing track info : release year -/// @param esp Pointer to the esPod instance -/// @param trackInfoType Can only be 0x02 -/// @param releaseYear Fictional release year of the song -void L0x04::_0x0D_ReturnIndexedPlayingTrackInfo(esPod *esp, byte trackInfoType, uint16_t releaseYear) -{ - ESP_LOGI(__func__, "Track info: 0x%02x Release Year: %d", trackInfoType, releaseYear); - byte txPacket[12] = { - 0x04, - 0x00, 0x0D, - trackInfoType, - 0x00, 0x00, 0x00, 0x01, 0x01, // First of Jan at 00:00:00 - 0x00, 0x00, // year goes here - 0x01 // it was a Monday - }; - *((uint16_t *)&txPacket[9]) = swap_endian(releaseYear); - esp->_queuePacket(txPacket, sizeof(txPacket)); -} - -/// @brief Returns the L0x04 Lingo Protocol Version : hardcoded to 1.12, consistent with an iPod Classic 5.5G -/// @param esp Pointer to the esPod instance -void L0x04::_0x13_ReturnProtocolVersion(esPod *esp) -{ - ESP_LOGI(__func__, "Lingo protocol version 1.12"); - byte txPacket[] = { - 0x04, - 0x00, 0x13, - 0x01, 0x0C // Protocol version 1.12 - }; - esp->_queuePacket(txPacket, sizeof(txPacket)); -} - -/// @brief Return the number of records of a given DBCategory (Playlist, tracks...) -/// @param esp Pointer to the esPod instance -/// @param categoryDBRecords The number of records to return -void L0x04::_0x19_ReturnNumberCategorizedDBRecords(esPod *esp, uint32_t categoryDBRecords) -{ - ESP_LOGI(__func__, "Category DB Records: %d", categoryDBRecords); - byte txPacket[7] = { - 0x04, - 0x00, 0x19, - 0x00, 0x00, 0x00, 0x00}; - *((uint32_t *)&txPacket[3]) = swap_endian(categoryDBRecords); - esp->_queuePacket(txPacket, sizeof(txPacket)); -} - -/// @brief Returns the metadata for a certain database record. Category is implicit -/// @param esp Pointer to the esPod instance -/// @param index Index of the DBRecord -/// @param recordString Metadata to include in the return -void L0x04::_0x1B_ReturnCategorizedDatabaseRecord(esPod *esp, uint32_t index, char *recordString) -{ - ESP_LOGI(__func__, "Database record at index %d : %s", index, recordString); - byte txPacket[255] = { - 0x04, - 0x00, 0x1B, - 0x00, 0x00, 0x00, 0x00 // Index goes here - }; - *((uint32_t *)&txPacket[3]) = swap_endian(index); - strcpy((char *)&txPacket[7], recordString); - esp->_queuePacket(txPacket, 7 + strlen(recordString) + 1); -} - -/// @brief Returns the current playback status, indicating the position out of the duration -/// @param esp Pointer to the esPod instance -/// @param position Playing position in ms in the track -/// @param duration Total duration of the track in ms -/// @param playStatusArg Playback status (0x00 Stopped, 0x01 Playing, 0x02 Paused, 0xFF Error) -void L0x04::_0x1D_ReturnPlayStatus(esPod *esp, uint32_t position, uint32_t duration, byte playStatusArg) -{ - ESP_LOGI(__func__, "Play status 0x%02x at pos. %d / %d ms", playStatusArg, position, duration); - byte txPacket[] = { - 0x04, - 0x00, 0x1D, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - playStatusArg}; - *((uint32_t *)&txPacket[3]) = swap_endian(duration); - *((uint32_t *)&txPacket[7]) = swap_endian(position); - esp->_queuePacket(txPacket, sizeof(txPacket)); -} - -/// @brief Returns the "Index" of the currently playing track, useful for pulling matching metadata -/// @param esp Pointer to the esPod instance -/// @param trackIndex The trackIndex to return. This is different from the position in the tracklist when Shuffle is ON -void L0x04::_0x1F_ReturnCurrentPlayingTrackIndex(esPod *esp, uint32_t trackIndex) -{ - ESP_LOGI(__func__, "Track index: %d", trackIndex); - byte txPacket[] = { - 0x04, - 0x00, 0x1F, - 0x00, 0x00, 0x00, 0x00}; - *((uint32_t *)&txPacket[3]) = swap_endian(trackIndex); - esp->_queuePacket(txPacket, sizeof(txPacket)); -} - -/// @brief Returns the track Title after an implicit call for it -/// @param esp Pointer to the esPod instance -/// @param trackTitle Character array to return -void L0x04::_0x21_ReturnIndexedPlayingTrackTitle(esPod *esp, char *trackTitle) -{ - ESP_LOGI(__func__, "Track title: %s", trackTitle); - byte txPacket[255] = { - 0x04, - 0x00, 0x21}; - strcpy((char *)&txPacket[3], trackTitle); - esp->_queuePacket(txPacket, 3 + strlen(trackTitle) + 1); -} - -/// @brief Returns the track Artist Name after an implicit call for it -/// @param esp Pointer to the esPod instance -/// @param trackArtistName Character array to return -void L0x04::_0x23_ReturnIndexedPlayingTrackArtistName(esPod *esp, char *trackArtistName) -{ - ESP_LOGI(__func__, "Track artist: %s", trackArtistName); - byte txPacket[255] = { - 0x04, - 0x00, 0x23}; - strcpy((char *)&txPacket[3], trackArtistName); - esp->_queuePacket(txPacket, 3 + strlen(trackArtistName) + 1); -} - -/// @brief Returns the track Album Name after an implicit call for it -/// @param esp Pointer to the esPod instance -/// @param trackAlbumName Character array to return -void L0x04::_0x25_ReturnIndexedPlayingTrackAlbumName(esPod *esp, char *trackAlbumName) -{ - ESP_LOGI(__func__, "Track album: %s", trackAlbumName); - byte txPacket[255] = { - 0x04, - 0x00, 0x25}; - strcpy((char *)&txPacket[3], trackAlbumName); - esp->_queuePacket(txPacket, 3 + strlen(trackAlbumName) + 1); -} - -/// @brief Only supports currently two types : 0x00 Playback Stopped, 0x01 Track index, 0x04 Track offset -/// @param esp Pointer to the esPod instance -/// @param notification Notification type that can be returned : 0x01 for track index change, 0x04 for the track offset -/// @param numField For 0x01 this is the new Track index, for 0x04 this is the current Track offset in ms -void L0x04::_0x27_PlayStatusNotification(esPod *esp, byte notification, uint32_t numField) -{ - ESP_LOGI(__func__, "Play status 0x%02x Numfield: %d", notification, numField); - byte txPacket[] = { - 0x04, - 0x00, 0x27, - notification, - 0x00, 0x00, 0x00, 0x00}; - *((uint32_t *)&txPacket[4]) = swap_endian(numField); - esp->_queuePacket(txPacket, sizeof(txPacket)); -} - -/// @brief Returns the PlayStatusNotification when it is STOPPED (0x00) -/// @param esp Pointer to the esPod instance -/// @param notification Can only be 0x00 -void L0x04::_0x27_PlayStatusNotification(esPod *esp, byte notification) -{ - ESP_LOGI(__func__, "Play status 0x%02x STOPPED", notification); - byte txPacket[] = { - 0x04, - 0x00, 0x27, - notification}; - esp->_queuePacket(txPacket, sizeof(txPacket)); -} - -/// @brief Returns the current shuffle status of the PBEngine -/// @param esp Pointer to the esPod instance -/// @param currentShuffleStatus 0x00 No Shuffle, 0x01 Tracks, 0x02 Albums -void L0x04::_0x2D_ReturnShuffle(esPod *esp, byte currentShuffleStatus) -{ - ESP_LOGI(__func__, "Shuffle status: 0x%02x", currentShuffleStatus); - byte txPacket[] = { - 0x04, - 0x00, 0x2D, - currentShuffleStatus}; - esp->_queuePacket(txPacket, sizeof(txPacket)); -} - -/// @brief Returns the current repeat status of the PBEngine -/// @param esp Pointer to the esPod instance -/// @param currentRepeatStatus 0x00 No Repeat, 0x01 One Track, 0x02 All tracks -void L0x04::_0x30_ReturnRepeat(esPod *esp, byte currentRepeatStatus) -{ - ESP_LOGI(__func__, "Repeat status: 0x%02x", currentRepeatStatus); - byte txPacket[] = { - 0x04, - 0x00, 0x30, - currentRepeatStatus}; - esp->_queuePacket(txPacket, sizeof(txPacket)); -} - -/// @brief -/// @param esp Pointer to the esPod instance -/// @param maxImageW -/// @param maxImageH -/// @param dispPixelFmt -void L0x04::_0x34_ReturnMonoDisplayImageLimits(esPod *esp, uint16_t maxImageW, uint16_t maxImageH, byte dispPixelFmt) -{ - ESP_LOGI(__func__, "Return monochrome image limits : %d x %d x %d", maxImageW, maxImageH, dispPixelFmt); - byte txPacket[] = { - 0x04, - 0x00, 0x34, - 0x00, 0x00, - 0x00, 0x00, - dispPixelFmt}; - *((uint16_t *)&txPacket[3]) = swap_endian(maxImageW); - *((uint16_t *)&txPacket[5]) = swap_endian(maxImageH); - esp->_queuePacket(txPacket, sizeof(txPacket)); -} - -/// @brief Returns the number of playing tracks in the current selection (here it is all the tracks) -/// @param esp Pointer to the esPod instance -/// @param numPlayingTracks Number of playing tracks to return -void L0x04::_0x36_ReturnNumPlayingTracks(esPod *esp, uint32_t numPlayingTracks) -{ - ESP_LOGI(__func__, "Playing tracks: %d", numPlayingTracks); - byte txPacket[] = { - 0x04, - 0x00, 0x36, - 0x00, 0x00, 0x00, 0x00}; - *((uint32_t *)&txPacket[3]) = swap_endian(numPlayingTracks); - esp->_queuePacket(txPacket, sizeof(txPacket)); -} - -/// @brief -/// @param esp Pointer to the esPod instance -/// @param maxImageW -/// @param maxImageH -/// @param dispPixelFmt -void L0x04::_0x3A_ReturnColorDisplayImageLimits(esPod *esp, uint16_t maxImageW, uint16_t maxImageH, byte dispPixelFmt) -{ - ESP_LOGI(__func__, "Return color image limits : %d x %d x %d", maxImageW, maxImageH, dispPixelFmt); - byte txPacket[] = { - 0x04, - 0x00, 0x3A, - 0x00, 0x00, - 0x00, 0x00, - dispPixelFmt}; - *((uint16_t *)&txPacket[3]) = swap_endian(maxImageW); - *((uint16_t *)&txPacket[5]) = swap_endian(maxImageH); - esp->_queuePacket(txPacket, sizeof(txPacket)); -} diff --git a/src/esPod.cpp b/src/esPod.cpp deleted file mode 100644 index fa8d2cb..0000000 --- a/src/esPod.cpp +++ /dev/null @@ -1,746 +0,0 @@ -#include "esPod.h" - -//----------------------------------------------------------------------- -//| Cardinal tasks and Timers | -//----------------------------------------------------------------------- -#pragma region Tasks - -void esPod::_rxTask(void *pvParameters) -{ - esPod *esPodInstance = static_cast(pvParameters); - - byte prevByte = 0x00; - byte incByte = 0x00; - byte buf[MAX_PACKET_SIZE] = {0x00}; - uint32_t expLength = 0; - uint32_t cursor = 0; - - unsigned long lastByteRX = millis(); // Last time a byte was RXed in a packet - unsigned long lastActivity = millis(); // Last time any RX activity was detected - - aapCommand cmd; - -#ifdef STACK_HIGH_WATERMARK_LOG - UBaseType_t uxHighWaterMark; - UBaseType_t minHightWaterMark = RX_TASK_STACK_SIZE; -#endif - - while (true) - { -// Stack high watermark logging -#ifdef STACK_HIGH_WATERMARK_LOG - uxHighWaterMark = uxTaskGetStackHighWaterMark(NULL); - if (uxHighWaterMark < minHightWaterMark) - { - minHightWaterMark = uxHighWaterMark; - ESP_LOGI("HWM", "RX Task High Watermark: %d, used stack: %d", minHightWaterMark, RX_TASK_STACK_SIZE - minHightWaterMark); - } -#endif - - // If the esPod is disabled, flush the RX buffer and wait for 2*RX_TASK_INTERVAL_MS before checking again - if (esPodInstance->disabled) - { - while (esPodInstance->_targetSerial.available()) - { - esPodInstance->_targetSerial.read(); - } - vTaskDelay(pdMS_TO_TICKS(2 * RX_TASK_INTERVAL_MS)); - continue; - } - else // esPod is enabled, process away ! - { - // Use of while instead of if() - while (esPodInstance->_targetSerial.available()) - { - // Timestamping the last activity on RX - lastActivity = millis(); - incByte = esPodInstance->_targetSerial.read(); - // If we are not in the middle of a RX, and we receive a 0xFF 0x55, start sequence, reset expected length and position cursor - if (prevByte == 0xFF && incByte == 0x55 && !esPodInstance->_rxIncomplete) - { - lastByteRX = millis(); - esPodInstance->_rxIncomplete = true; - expLength = 0; - cursor = 0; - } - else if (esPodInstance->_rxIncomplete) - { - // Timestamping the last byte received - lastByteRX = millis(); - // Expected length has not been received yet - if (expLength == 0 && cursor == 0) - { - expLength = incByte; // First byte after 0xFF 0x55 - if (expLength > MAX_PACKET_SIZE) - { - ESP_LOGW(__func__, "Expected length is too long, discarding packet"); - esPodInstance->_rxIncomplete = false; - // TODO: Send a NACK to the Accessory - } - else if (expLength == 0) - { - ESP_LOGW(__func__, "Expected length is 0, discarding packet"); - esPodInstance->_rxIncomplete = false; - // TODO: Send a NACK to the Accessory - } - } - else // Length is already received - { - buf[cursor++] = incByte; - if (cursor == expLength + 1) - { - // We have received the expected length + checksum - esPodInstance->_rxIncomplete = false; - // Check the checksum - byte calcChecksum = esPod::_checksum(buf, expLength); - if (calcChecksum == incByte) - { - // Checksum is correct, send the packet to the processing queue - // Allocate memory for the payload so it doesn't become out of scope - cmd.payload = new byte[expLength]; - cmd.length = expLength; - memcpy(cmd.payload, buf, expLength); - if (xQueueSend(esPodInstance->_cmdQueue, &cmd, pdMS_TO_TICKS(5)) == pdTRUE) - { - ESP_LOGD(__func__, "Packet received and sent to processing queue"); - } - else - { - ESP_LOGW(__func__, "Packet received but could not be sent to processing queue. Discarding"); - delete[] cmd.payload; - cmd.payload = nullptr; - cmd.length = 0; - } - } - else // Checksum mismatch - { - ESP_LOGW(__func__, "Checksum mismatch, discarding packet"); - // TODO: Send a NACK to the Accessory - } - } - } - } - else // We are not in the middle of a packet, but we received a byte - { - ESP_LOGD(__func__, "Received byte 0x%02X outside of a packet, discarding", incByte); - } - // Always update the previous byte - prevByte = incByte; - } - if (esPodInstance->_rxIncomplete && millis() - lastByteRX > INTERBYTE_TIMEOUT) // If we are in the middle of a packet and we haven't received a byte in 1s, discard the packet - { - ESP_LOGW(__func__, "Packet incomplete, discarding"); - esPodInstance->_rxIncomplete = false; - // cmd.payload = nullptr; - // cmd.length = 0; - // TODO: Send a NACK to the Accessory - } - if (millis() - lastActivity > SERIAL_TIMEOUT) // If we haven't received any byte in 30s, reset the RX state - { - // Reset the timestamp for next Serial timeout - lastActivity = millis(); -#ifndef NO_RESET_ON_SERIAL_TIMEOUT - ESP_LOGW(__func__, "No activity in %lu ms, resetting RX state", SERIAL_TIMEOUT); - esPodInstance->resetState(); -#endif - } - vTaskDelay(pdMS_TO_TICKS(RX_TASK_INTERVAL_MS)); - } - } -} - -void esPod::_processTask(void *pvParameters) -{ - esPod *esPodInstance = static_cast(pvParameters); - aapCommand incCmd; - -#ifdef STACK_HIGH_WATERMARK_LOG - UBaseType_t uxHighWaterMark; - UBaseType_t minHightWaterMark = PROCESS_TASK_STACK_SIZE; -#endif - - while (true) - { -// Stack high watermark logging -#ifdef STACK_HIGH_WATERMARK_LOG - uxHighWaterMark = uxTaskGetStackHighWaterMark(NULL); - if (uxHighWaterMark < minHightWaterMark) - { - minHightWaterMark = uxHighWaterMark; - ESP_LOGI("HWM", "Process Task High Watermark: %d, used stack: %d", minHightWaterMark, PROCESS_TASK_STACK_SIZE - minHightWaterMark); - } -#endif - - // If the esPod is disabled, check the queue and purge it before jumping to the next cycle - if (esPodInstance->disabled) - { - while (xQueueReceive(esPodInstance->_cmdQueue, &incCmd, 0) == pdTRUE) // Non blocking receive - { - // Do not process, just free the memory - delete[] incCmd.payload; - incCmd.payload = nullptr; - incCmd.length = 0; - } - vTaskDelay(pdMS_TO_TICKS(2 * PROCESS_INTERVAL_MS)); - continue; - } - if (xQueueReceive(esPodInstance->_cmdQueue, &incCmd, 0) == pdTRUE) // Non blocking receive - { - // Process the command - esPodInstance->_processPacket(incCmd.payload, incCmd.length); - // Free the memory allocated for the payload - delete[] incCmd.payload; - incCmd.payload = nullptr; - incCmd.length = 0; - } - vTaskDelay(pdMS_TO_TICKS(PROCESS_INTERVAL_MS)); - } -} - -void esPod::_txTask(void *pvParameters) -{ - esPod *esPodInstance = static_cast(pvParameters); - aapCommand txCmd; - -#ifdef STACK_HIGH_WATERMARK_LOG - UBaseType_t uxHighWaterMark; - UBaseType_t minHightWaterMark = TX_TASK_STACK_SIZE; -#endif - - while (true) - { -// Stack high watermark logging -#ifdef STACK_HIGH_WATERMARK_LOG - uxHighWaterMark = uxTaskGetStackHighWaterMark(NULL); - if (uxHighWaterMark < minHightWaterMark) - { - minHightWaterMark = uxHighWaterMark; - ESP_LOGI("HWM", "TX Task High Watermark: %d, used stack: %d", minHightWaterMark, TX_TASK_STACK_SIZE - minHightWaterMark); - } -#endif - - // If the esPod is disabled, check the queue and purge it before jumping to the next cycle - if (esPodInstance->disabled) - { - while (xQueueReceive(esPodInstance->_txQueue, &txCmd, 0) == pdTRUE) - { - // Do not process, just free the memory - delete[] txCmd.payload; - txCmd.payload = nullptr; - txCmd.length = 0; - } - vTaskDelay(pdMS_TO_TICKS(TX_INTERVAL_MS)); - continue; - } - if (!esPodInstance->_rxIncomplete && esPodInstance->_pendingCmdId_0x00 == 0x00 && esPodInstance->_pendingCmdId_0x03 == 0x00 && esPodInstance->_pendingCmdId_0x04 == 0x00) //_rxTask is not in the middle of a packet, there isn't a valid pending for either lingoes - { - // Retrieve from the queue and send the packet - if (xQueueReceive(esPodInstance->_txQueue, &txCmd, 0) == pdTRUE) - { - // vTaskDelay(pdMS_TO_TICKS(TX_INTERVAL_MS)); - // Send the packet - esPodInstance->_sendPacket(txCmd.payload, txCmd.length); - // Free the memory allocated for the payload - delete[] txCmd.payload; - txCmd.payload = nullptr; - txCmd.length = 0; - } - vTaskDelay(pdMS_TO_TICKS(TX_INTERVAL_MS)); - } - else - { - vTaskDelay(pdMS_TO_TICKS(RX_TASK_INTERVAL_MS)); - } - } -} - -void esPod::_timerTask(void *pvParameters) -{ - esPod *esPodInstance = static_cast(pvParameters); - TimerCallbackMessage msg; - - while (true) - { - if (xQueueReceive(esPodInstance->_timerQueue, &msg, 0) == pdTRUE) - { - if (msg.targetLingo == 0x00) - { - // esPodInstance->L0x00_0x02_iPodAck(iPodAck_OK, msg.cmdID); - L0x00::_0x02_iPodAck(esPodInstance, iPodAck_OK, msg.cmdID); - } - else if (msg.targetLingo == 0x04) - { - // esPodInstance->L0x04_0x01_iPodAck(iPodAck_OK, msg.cmdID); - L0x04::_0x01_iPodAck(esPodInstance, iPodAck_OK, msg.cmdID); - if (msg.cmdID == esPodInstance->trackChangeAckPending) - { - esPodInstance->trackChangeAckPending = 0x00; - esPodInstance->_albumNameUpdated = false; - esPodInstance->_artistNameUpdated = false; - esPodInstance->_trackTitleUpdated = false; - esPodInstance->_trackDurationUpdated = false; - } - } - else if (msg.targetLingo == 0x03) - { - // esPodInstance->L0x04_0x01_iPodAck(iPodAck_OK, msg.cmdID); - L0x03::_0x00_iPodAck(esPodInstance, iPodAck_OK, msg.cmdID); - if (msg.cmdID == esPodInstance->trackChangeAckPending) - { - esPodInstance->trackChangeAckPending = 0x00; - esPodInstance->_albumNameUpdated = false; - esPodInstance->_artistNameUpdated = false; - esPodInstance->_trackTitleUpdated = false; - esPodInstance->_trackDurationUpdated = false; - } - } - } - vTaskDelay(pdMS_TO_TICKS(TIMER_INTERVAL_MS)); - } -} -#pragma endregion - -#pragma region Timer Callbacks - -void esPod::_pendingTimerCallback_0x00(TimerHandle_t xTimer) -{ - esPod *esPodInstance = static_cast(pvTimerGetTimerID(xTimer)); - TimerCallbackMessage msg = {esPodInstance->_pendingCmdId_0x00, 0x00}; - xQueueSendFromISR(esPodInstance->_timerQueue, &msg, NULL); -} - -void esPod::_pendingTimerCallback_0x03(TimerHandle_t xTimer) -{ - esPod *esPodInstance = static_cast(pvTimerGetTimerID(xTimer)); - TimerCallbackMessage msg = {esPodInstance->_pendingCmdId_0x03, 0x03}; - xQueueSendFromISR(esPodInstance->_timerQueue, &msg, NULL); -} - -void esPod::_pendingTimerCallback_0x04(TimerHandle_t xTimer) -{ - esPod *esPodInstance = static_cast(pvTimerGetTimerID(xTimer)); - TimerCallbackMessage msg = {esPodInstance->_pendingCmdId_0x04, 0x04}; - xQueueSendFromISR(esPodInstance->_timerQueue, &msg, NULL); -} -#pragma endregion - -//----------------------------------------------------------------------- -//| Packet management | -//----------------------------------------------------------------------- -#pragma region Packet management - -byte esPod::_checksum(const byte *byteArray, uint32_t len) -{ - uint32_t tempChecksum = len; - for (int i = 0; i < len; i++) - { - tempChecksum += byteArray[i]; - } - tempChecksum = 0x100 - (tempChecksum & 0xFF); - return (byte)tempChecksum; -} - -void esPod::_sendPacket(const byte *byteArray, uint32_t len) -{ - uint32_t finalLength = len + 4; - byte tempBuf[finalLength] = {0x00}; - - tempBuf[0] = 0xFF; - tempBuf[1] = 0x55; - tempBuf[2] = (byte)len; - for (uint32_t i = 0; i < len; i++) - { - tempBuf[3 + i] = byteArray[i]; - } - tempBuf[3 + len] = esPod::_checksum(byteArray, len); - - _targetSerial.write(tempBuf, finalLength); -} - -void esPod::_queuePacket(const byte *byteArray, uint32_t len) -{ - aapCommand cmdToQueue; - cmdToQueue.payload = new byte[len]; - cmdToQueue.length = len; - memcpy(cmdToQueue.payload, byteArray, len); - if (xQueueSend(_txQueue, &cmdToQueue, pdMS_TO_TICKS(5)) != pdTRUE) - { - ESP_LOGW(__func__, "Could not queue packet"); - delete[] cmdToQueue.payload; - cmdToQueue.payload = nullptr; - cmdToQueue.length = 0; - } -} - -void esPod::_queuePacketToFront(const byte *byteArray, uint32_t len) -{ - aapCommand cmdToQueue; - cmdToQueue.payload = new byte[len]; - cmdToQueue.length = len; - memcpy(cmdToQueue.payload, byteArray, len); - if (xQueueSendToFront(_txQueue, &cmdToQueue, pdMS_TO_TICKS(5)) != pdTRUE) - { - ESP_LOGW(__func__, "Could not queue packet"); - delete[] cmdToQueue.payload; - cmdToQueue.payload = nullptr; - cmdToQueue.length = 0; - } -} - -void esPod::_processPacket(const byte *byteArray, uint32_t len) -{ - byte rxLingoID = byteArray[0]; - const byte *subPayload = byteArray + 1; // Squeeze the Lingo out - uint32_t subPayloadLen = len - 1; - switch (rxLingoID) // 0x00 is general Lingo and 0x04 is extended Lingo. Nothing else is expected from the Mini - { - case 0x00: // General Lingo - ESP_LOGD(__func__, "Lingo 0x00 Packet in processor,payload length: %d", subPayloadLen); - L0x00::processLingo(this, subPayload, subPayloadLen); - break; - - case 0x03: // Display Remote Lingo - ESP_LOGD(__func__, "Lingo 0x03 Packet in processor,payload length: %d", subPayloadLen); - L0x03::processLingo(this, subPayload, subPayloadLen); - break; - - case 0x04: // Extended Interface Lingo - ESP_LOGD(__func__, "Lingo 0x04 Packet in processor,payload length: %d", subPayloadLen); - L0x04::processLingo(this, subPayload, subPayloadLen); - break; - - default: - ESP_LOGW(__func__, "Unknown Lingo packet : L0x%02x 0x%02x", rxLingoID, byteArray[1]); - break; - } -} -#pragma endregion - -//----------------------------------------------------------------------- -//| Constructor, reset, attachCallback for PB control | -//----------------------------------------------------------------------- -#pragma region Constructor, destructor, reset and external PB Contoller attach -void esPod::_checkAllMetaUpdated() -{ - if (_albumNameUpdated && _artistNameUpdated && _trackTitleUpdated && _trackDurationUpdated) - { - // If all fields have received at least one update and the - // trackChangeAckPending is still hanging. The failsafe for this one is - // in the espod _processTask - if (trackChangeAckPending > 0x00) - { - ESP_LOGD(__func__, "Artist+Album+Title+Duration +++ ACK Pending 0x%x\n\tPending duration: %d", trackChangeAckPending, millis() - trackChangeTimestamp); - if (trackChangeAckPending == 0x11) - { - L0x03::_0x00_iPodAck(this, iPodAck_OK, trackChangeAckPending); - } - else - { - L0x04::_0x01_iPodAck(this, iPodAck_OK, trackChangeAckPending); - } - trackChangeAckPending = 0x00; - ESP_LOGD(__func__, "trackChangeAckPending reset to 0x00"); - } - _albumNameUpdated = false; - _artistNameUpdated = false; - _trackTitleUpdated = false; - _trackDurationUpdated = false; - ESP_LOGD(__func__, "Artist+Album+Title+Duration : True -> False"); - // Inform the car - if (playStatusNotificationState == NOTIF_ON) - { - L0x04::_0x27_PlayStatusNotification(this, 0x01, currentTrackIndex); - } - } -} - -esPod::esPod(Stream &targetSerial) - : _targetSerial(targetSerial) -{ - // Create queues with pointer structures to byte arrays - _cmdQueue = xQueueCreate(CMD_QUEUE_SIZE, sizeof(aapCommand)); - _txQueue = xQueueCreate(TX_QUEUE_SIZE, sizeof(aapCommand)); - _timerQueue = xQueueCreate(TIMER_QUEUE_SIZE, sizeof(TimerCallbackMessage)); - - if (_cmdQueue == NULL || _txQueue == NULL || _timerQueue == NULL) // Add _timerQueue check - { - ESP_LOGE(__func__, "Could not create queues"); - } - - // Create FreeRTOS tasks for compiling incoming commands, processing commands and transmitting commands - if (_cmdQueue != NULL && _txQueue != NULL && _timerQueue != NULL) // Add _timerQueue check - { - xTaskCreatePinnedToCore(_rxTask, "RX Task", RX_TASK_STACK_SIZE, this, RX_TASK_PRIORITY, &_rxTaskHandle, 1); - xTaskCreatePinnedToCore(_processTask, "Processor Task", PROCESS_TASK_STACK_SIZE, this, PROCESS_TASK_PRIORITY, &_processTaskHandle, 1); - xTaskCreatePinnedToCore(_txTask, "Transmit Task", TX_TASK_STACK_SIZE, this, TX_TASK_PRIORITY, &_txTaskHandle, 1); - xTaskCreatePinnedToCore(_timerTask, "Timer Task", TIMER_TASK_STACK_SIZE, this, TIMER_TASK_PRIORITY, &_timerTaskHandle, 1); - - if (_rxTaskHandle == NULL || _processTaskHandle == NULL || _txTaskHandle == NULL || _timerTaskHandle == NULL) - { - ESP_LOGE(__func__, "Could not create tasks"); - } - else - { - _pendingTimer_0x00 = xTimerCreate("Pending Timer 0x00", pdMS_TO_TICKS(1000), pdFALSE, this, esPod::_pendingTimerCallback_0x00); - _pendingTimer_0x03 = xTimerCreate("Pending Timer 0x03", pdMS_TO_TICKS(1000), pdFALSE, this, esPod::_pendingTimerCallback_0x03); - _pendingTimer_0x04 = xTimerCreate("Pending Timer 0x04", pdMS_TO_TICKS(1000), pdFALSE, this, esPod::_pendingTimerCallback_0x04); - if (_pendingTimer_0x00 == NULL || _pendingTimer_0x03 == NULL || _pendingTimer_0x04 == NULL) - { - ESP_LOGE(__func__, "Could not create timers"); - } - } - } - else - { - ESP_LOGE(__func__, "Could not create tasks, queues not created"); - } -} - -esPod::~esPod() -{ - aapCommand tempCmd; - vTaskDelete(_rxTaskHandle); - vTaskDelete(_processTaskHandle); - vTaskDelete(_txTaskHandle); - vTaskDelete(_timerTaskHandle); - // Stop timers that might be running - stopTimer(_pendingTimer_0x00); - stopTimer(_pendingTimer_0x03); - stopTimer(_pendingTimer_0x04); - xTimerDelete(_pendingTimer_0x00, 0); - xTimerDelete(_pendingTimer_0x03, 0); - xTimerDelete(_pendingTimer_0x04, 0); - // Remember to deallocate memory - while (xQueueReceive(_cmdQueue, &tempCmd, 0) == pdTRUE) - { - delete[] tempCmd.payload; - tempCmd.payload = nullptr; - tempCmd.length = 0; - } - while (xQueueReceive(_txQueue, &tempCmd, 0) == pdTRUE) - { - delete[] tempCmd.payload; - tempCmd.payload = nullptr; - tempCmd.length = 0; - } - vQueueDelete(_cmdQueue); - vQueueDelete(_txQueue); - vQueueDelete(_timerQueue); -} - -void esPod::resetState() -{ - - ESP_LOGW(__func__, "esPod resetState called"); - // State variables - extendedInterfaceModeActive = false; - - // Metadata variables - trackDuration = 1; - prevTrackDuration = 1; - playPosition = 0; - - // Flags for track change management - _albumNameUpdated = false; - _artistNameUpdated = false; - _trackTitleUpdated = false; - _trackDurationUpdated = false; - - // Playback Engine - playStatus = PB_STATE_PAUSED; - playStatusNotificationState = NOTIF_OFF; - trackChangeAckPending = 0x00; - shuffleStatus = 0x00; - repeatStatus = 0x02; - - // TrackList variables - currentTrackIndex = 0; - prevTrackIndex = TOTAL_NUM_TRACKS - 1; - for (uint16_t i = 0; i < TOTAL_NUM_TRACKS; i++) - trackList[i] = 0; - trackListPosition = 0; - - // Reset the queues - aapCommand tempCmd; - - // Remember to deallocate memory - while (xQueueReceive(_cmdQueue, &tempCmd, 0) == pdTRUE) - { - delete[] tempCmd.payload; - tempCmd.payload = nullptr; - tempCmd.length = 0; - } - while (xQueueReceive(_txQueue, &tempCmd, 0) == pdTRUE) - { - delete[] tempCmd.payload; - tempCmd.payload = nullptr; - tempCmd.length = 0; - } - xQueueReset(_cmdQueue); - xQueueReset(_txQueue); - - // Stop timers - stopTimer(_pendingTimer_0x00); - stopTimer(_pendingTimer_0x03); - stopTimer(_pendingTimer_0x04); - _pendingCmdId_0x00 = 0x00; - _pendingCmdId_0x03 = 0x00; - _pendingCmdId_0x04 = 0x00; -} - -void esPod::attachPlayControlHandler(playStatusHandler_t playHandler) -{ - _playStatusHandler = playHandler; - ESP_LOGD(__func__, "PlayControlHandler attached."); -} - -void esPod::play() -{ - playStatus = PB_STATE_PLAYING; - ESP_LOGD(__func__, "esPod set to play."); -} - -void esPod::pause() -{ - playStatus = PB_STATE_PAUSED; - ESP_LOGD(__func__, "esPod paused."); -} - -void esPod::stop() -{ - playStatus = PB_STATE_STOPPED; - ESP_LOGD(__func__, " esPod stopped."); -} - -void esPod::updatePlayPosition(uint32_t position) -{ - playPosition = position; - if (playStatusNotificationState == NOTIF_ON && trackChangeAckPending == 0x00) - L0x04::_0x27_PlayStatusNotification(this, 0x04, position); -} - -void esPod::updateAlbumName(const char *incAlbumName) -{ - if (trackChangeAckPending > 0x00) // There is a pending track change ack - { - if (!_albumNameUpdated) - { - strcpy(albumName, incAlbumName); - _albumNameUpdated = true; - ESP_LOGD(__func__, "Album name update to %s", albumName); - } - else - ESP_LOGD(__func__, "Album name already updated to %s", albumName); - } - else // There is no pending track change ack : change is coming from phone/AVRC target - { - if (strcmp(incAlbumName, albumName) != 0) // New Album Name - { - strcpy(prevAlbumName, albumName); // Preserve the previous album name - strcpy(albumName, incAlbumName); // Copy new album name - _albumNameUpdated = true; - ESP_LOGD(__func__, "Album name updated to %s", albumName); - } - else // Not new album name - ESP_LOGD(__func__, "Album name already updated to %s", albumName); - } - _checkAllMetaUpdated(); -} - -void esPod::updateArtistName(const char *incArtistName) -{ - if (trackChangeAckPending > 0x00) // There is a pending track change ack - { - if (!_artistNameUpdated) - { - strcpy(artistName, incArtistName); - _artistNameUpdated = true; - ESP_LOGD(__func__, "Artist name update to %s", artistName); - } - else - ESP_LOGD(__func__, "Artist name already updated to %s", artistName); - } - else // There is no pending track change ack : change is coming from phone/AVRC target - { - if (strcmp(incArtistName, artistName) != 0) // New Artist Name - { - strcpy(prevArtistName, artistName); // Preserve the previous artist name - strcpy(artistName, incArtistName); // Copy new artist name - _artistNameUpdated = true; - ESP_LOGD(__func__, "Artist name updated to %s", artistName); - } - else // Not new artist name - ESP_LOGD(__func__, "Artist name already updated to %s", artistName); - } - _checkAllMetaUpdated(); -} - -void esPod::updateTrackTitle(const char *incTrackTitle) -{ - if (trackChangeAckPending > 0x00) // There is a pending metadata update - { - if (!_trackTitleUpdated) // Track title not yet updated - { - strcpy(trackTitle, incTrackTitle); - _trackTitleUpdated = true; - ESP_LOGD(__func__, "Title update to %s", trackTitle); - } - else - ESP_LOGD(__func__, "Title already updated to %s", trackTitle); - } - else // There is no pending track change ack : change is coming from phone/AVRC target. - { - if (strcmp(incTrackTitle, trackTitle) != 0) // New track title, we assume it's a NEXT track because otherwise the comparison logic becomes heavy - { - // Assume it is Next, perform cursor operations - trackListPosition = (trackListPosition + 1) % TOTAL_NUM_TRACKS; - prevTrackIndex = currentTrackIndex; - currentTrackIndex = (currentTrackIndex + 1) % TOTAL_NUM_TRACKS; - trackList[trackListPosition] = (currentTrackIndex); - - strcpy(prevTrackTitle, trackTitle); // Preserve the previous track title - strcpy(trackTitle, incTrackTitle); // Update the new track title - _trackTitleUpdated = true; - ESP_LOGD(__func__, "Title update to %s", trackTitle); - // ESP_LOGD("AVRC_CB", - // "Title rxed, NO ACK pending, AUTONEXT, trackTitleUpdated " - // "to %s\n\ttrackPos %d trackIndex %d", - // trackTitle, trackListPosition, currentTrackIndex); - } - else // Track title is identical, no movement - { - ESP_LOGD(__func__, "Title already updated to : %s", trackTitle); - } - } - _checkAllMetaUpdated(); -} - -void esPod::updateTrackDuration(uint32_t incTrackDuration) -{ - if (trackChangeAckPending > 0x00) // There is a pending metadata update - { - if (!_trackDurationUpdated) // Track duration not yet updated - { - trackDuration = incTrackDuration; - _trackDurationUpdated = true; - ESP_LOGD(__func__, "Track duration updated to %d", trackDuration); - } - else - ESP_LOGD(__func__, "Track duration already updated to %d", trackDuration); - } - else // There is no pending track change ack : change is coming from phone/AVRC target. - { - if (incTrackDuration != trackDuration) // Different incoming metadata - { - prevTrackDuration = trackDuration; // Preserve the current value - trackDuration = incTrackDuration; // Then updated it - _trackDurationUpdated = true; - ESP_LOGD(__func__, "Track duration updated to %d", trackDuration); - } - else - ESP_LOGD(__func__, "Track duration already updated to %d", trackDuration); - } - _checkAllMetaUpdated(); -} - -#pragma endregion From 21e8b04204987773a0f4b87c3f36d452a6435a90 Mon Sep 17 00:00:00 2001 From: Martin ROGER Date: Tue, 17 Feb 2026 21:36:56 +0100 Subject: [PATCH 6/6] Legacy PCB relocation --- pcbs/AiO-i2s-DAC/.gitignore | 5 ++++- pcbs/{ => legacy boards}/a1s-mini/.gitignore | 4 ++++ .../a1s-mini/CP2102-GM.kicad_sch | 0 pcbs/{ => legacy boards}/a1s-mini/CP2102.kicad_sch | 0 pcbs/{ => legacy boards}/a1s-mini/USBC.kicad_sch | 0 .../{ => legacy boards}/a1s-mini/a1s-mini.kicad_pcb | 0 .../a1s-mini/a1s-mini.kicad_pcb.zip | Bin .../{ => legacy boards}/a1s-mini/a1s-mini.kicad_prl | 0 .../{ => legacy boards}/a1s-mini/a1s-mini.kicad_pro | 0 .../{ => legacy boards}/a1s-mini/a1s-mini.kicad_sch | 0 pcbs/{ => legacy boards}/a1s-mini/a1s-mini.sch | 0 pcbs/{ => legacy boards}/a1s-mini/a1s-mini.step | 0 .../bom/2025-03-01_01-09-41_a1s-mini_ibom_0.2.html | 0 pcbs/{ => legacy boards}/a1s-mini/docs/1-clone.png | Bin pcbs/{ => legacy boards}/a1s-mini/docs/2-pref.png | Bin pcbs/{ => legacy boards}/a1s-mini/docs/3-path.png | Bin .../a1s-mini/docs/4-newproject.png | Bin .../a1s-mini/docs/5-selecttemplate.png | Bin pcbs/{ => legacy boards}/a1s-mini/fp-info-cache | 0 pcbs/{ => legacy boards}/a1s-mini/readme.md | 0 .../a1s-mini/replicate_layout.log | 0 pcbs/{ => legacy boards}/hautDeForme/.gitignore | 4 ++++ .../hautDeForme/CP2102-GM.kicad_sch | 0 .../hautDeForme/CP2102.kicad_sch | 0 pcbs/{ => legacy boards}/hautDeForme/USBC.kicad_sch | 0 .../2025-03-03_00-34-14_hautDeForme_ibom_0.1.0.html | 0 .../hautDeForme/docs/1-clone.png | Bin .../{ => legacy boards}/hautDeForme/docs/2-pref.png | Bin .../{ => legacy boards}/hautDeForme/docs/3-path.png | Bin .../hautDeForme/docs/4-newproject.png | Bin .../hautDeForme/docs/5-selecttemplate.png | Bin pcbs/{ => legacy boards}/hautDeForme/fp-info-cache | 0 .../hautDeForme/hautDeForme-hautDeForme.step | 0 .../hautDeForme/hautDeForme.FCStd | Bin .../hautDeForme/hautDeForme.kicad_pcb | 0 .../hautDeForme/hautDeForme.kicad_pcb.zip | Bin .../hautDeForme/hautDeForme.kicad_prl | 0 .../hautDeForme/hautDeForme.kicad_pro | 0 .../hautDeForme/hautDeForme.kicad_sch | 0 .../{ => legacy boards}/hautDeForme/hautDeForme.sch | 0 .../hautDeForme/hautDeForme_log_missing3Dmodels.txt | 0 .../hautDeForme/hautDeForme_missing3Dmodels.txt | 0 pcbs/{ => legacy boards}/hautDeForme/readme.md | 0 .../{ => legacy boards}/ipodesp32 PL2303/.gitignore | 4 ++++ ...-06-04_11-59-24_ipodesp32 PL2303_ibom_0.2.0.html | 0 .../ipodesp32 PL2303/PL2303G Carrier.pdf | Bin ...-06-04_12-14-32_ipodesp32 PL2303_ibom_0.2.0.html | 0 ...-07-16_09-28-20_ipodesp32 PL2303_ibom_0.2.1.html | 0 .../ipodesp32 PL2303/fp-info-cache | 0 .../ipodesp32 PL2303/iPodEsp32_BOM_PCBWay.xlsx | Bin .../ipodesp32 PL2303/ipodesp32 PL2303.kicad_pcb | 0 .../ipodesp32 PL2303/ipodesp32 PL2303.kicad_pcb.zip | Bin .../ipodesp32 PL2303/ipodesp32 PL2303.kicad_prl | 0 .../ipodesp32 PL2303/ipodesp32 PL2303.kicad_pro | 0 .../ipodesp32 PL2303/ipodesp32 PL2303.kicad_sch | 0 .../ipodesp32 PL2303/ipodesp32 PL2303.sch | 0 pcbs/sandwichCircuit/.gitignore | 4 ++++ 57 files changed, 20 insertions(+), 1 deletion(-) rename pcbs/{ => legacy boards}/a1s-mini/.gitignore (89%) rename pcbs/{ => legacy boards}/a1s-mini/CP2102-GM.kicad_sch (100%) rename pcbs/{ => legacy boards}/a1s-mini/CP2102.kicad_sch (100%) rename pcbs/{ => legacy boards}/a1s-mini/USBC.kicad_sch (100%) rename pcbs/{ => legacy boards}/a1s-mini/a1s-mini.kicad_pcb (100%) rename pcbs/{ => legacy boards}/a1s-mini/a1s-mini.kicad_pcb.zip (100%) rename pcbs/{ => legacy boards}/a1s-mini/a1s-mini.kicad_prl (100%) rename pcbs/{ => legacy boards}/a1s-mini/a1s-mini.kicad_pro (100%) rename pcbs/{ => legacy boards}/a1s-mini/a1s-mini.kicad_sch (100%) rename pcbs/{ => legacy boards}/a1s-mini/a1s-mini.sch (100%) rename pcbs/{ => legacy boards}/a1s-mini/a1s-mini.step (100%) rename pcbs/{ => legacy boards}/a1s-mini/bom/2025-03-01_01-09-41_a1s-mini_ibom_0.2.html (100%) rename pcbs/{ => legacy boards}/a1s-mini/docs/1-clone.png (100%) rename pcbs/{ => legacy boards}/a1s-mini/docs/2-pref.png (100%) rename pcbs/{ => legacy boards}/a1s-mini/docs/3-path.png (100%) rename pcbs/{ => legacy boards}/a1s-mini/docs/4-newproject.png (100%) rename pcbs/{ => legacy boards}/a1s-mini/docs/5-selecttemplate.png (100%) rename pcbs/{ => legacy boards}/a1s-mini/fp-info-cache (100%) rename pcbs/{ => legacy boards}/a1s-mini/readme.md (100%) rename pcbs/{ => legacy boards}/a1s-mini/replicate_layout.log (100%) rename pcbs/{ => legacy boards}/hautDeForme/.gitignore (89%) rename pcbs/{ => legacy boards}/hautDeForme/CP2102-GM.kicad_sch (100%) rename pcbs/{ => legacy boards}/hautDeForme/CP2102.kicad_sch (100%) rename pcbs/{ => legacy boards}/hautDeForme/USBC.kicad_sch (100%) rename pcbs/{ => legacy boards}/hautDeForme/bom/2025-03-03_00-34-14_hautDeForme_ibom_0.1.0.html (100%) rename pcbs/{ => legacy boards}/hautDeForme/docs/1-clone.png (100%) rename pcbs/{ => legacy boards}/hautDeForme/docs/2-pref.png (100%) rename pcbs/{ => legacy boards}/hautDeForme/docs/3-path.png (100%) rename pcbs/{ => legacy boards}/hautDeForme/docs/4-newproject.png (100%) rename pcbs/{ => legacy boards}/hautDeForme/docs/5-selecttemplate.png (100%) rename pcbs/{ => legacy boards}/hautDeForme/fp-info-cache (100%) rename pcbs/{ => legacy boards}/hautDeForme/hautDeForme-hautDeForme.step (100%) rename pcbs/{ => legacy boards}/hautDeForme/hautDeForme.FCStd (100%) rename pcbs/{ => legacy boards}/hautDeForme/hautDeForme.kicad_pcb (100%) rename pcbs/{ => legacy boards}/hautDeForme/hautDeForme.kicad_pcb.zip (100%) rename pcbs/{ => legacy boards}/hautDeForme/hautDeForme.kicad_prl (100%) rename pcbs/{ => legacy boards}/hautDeForme/hautDeForme.kicad_pro (100%) rename pcbs/{ => legacy boards}/hautDeForme/hautDeForme.kicad_sch (100%) rename pcbs/{ => legacy boards}/hautDeForme/hautDeForme.sch (100%) rename pcbs/{ => legacy boards}/hautDeForme/hautDeForme_log_missing3Dmodels.txt (100%) rename pcbs/{ => legacy boards}/hautDeForme/hautDeForme_missing3Dmodels.txt (100%) rename pcbs/{ => legacy boards}/hautDeForme/readme.md (100%) rename pcbs/{ => legacy boards}/ipodesp32 PL2303/.gitignore (89%) rename pcbs/{ => legacy boards}/ipodesp32 PL2303/2024-06-04_11-59-24_ipodesp32 PL2303_ibom_0.2.0.html (100%) rename pcbs/{ => legacy boards}/ipodesp32 PL2303/PL2303G Carrier.pdf (100%) rename pcbs/{ => legacy boards}/ipodesp32 PL2303/bom/2024-06-04_12-14-32_ipodesp32 PL2303_ibom_0.2.0.html (100%) rename pcbs/{ => legacy boards}/ipodesp32 PL2303/bom/2024-07-16_09-28-20_ipodesp32 PL2303_ibom_0.2.1.html (100%) rename pcbs/{ => legacy boards}/ipodesp32 PL2303/fp-info-cache (100%) rename pcbs/{ => legacy boards}/ipodesp32 PL2303/iPodEsp32_BOM_PCBWay.xlsx (100%) rename pcbs/{ => legacy boards}/ipodesp32 PL2303/ipodesp32 PL2303.kicad_pcb (100%) rename pcbs/{ => legacy boards}/ipodesp32 PL2303/ipodesp32 PL2303.kicad_pcb.zip (100%) rename pcbs/{ => legacy boards}/ipodesp32 PL2303/ipodesp32 PL2303.kicad_prl (100%) rename pcbs/{ => legacy boards}/ipodesp32 PL2303/ipodesp32 PL2303.kicad_pro (100%) rename pcbs/{ => legacy boards}/ipodesp32 PL2303/ipodesp32 PL2303.kicad_sch (100%) rename pcbs/{ => legacy boards}/ipodesp32 PL2303/ipodesp32 PL2303.sch (100%) diff --git a/pcbs/AiO-i2s-DAC/.gitignore b/pcbs/AiO-i2s-DAC/.gitignore index 2407672..6092ea7 100644 --- a/pcbs/AiO-i2s-DAC/.gitignore +++ b/pcbs/AiO-i2s-DAC/.gitignore @@ -23,4 +23,7 @@ _autosave-* # Exported BOM files *.xml *.csv -/production/backups/* \ No newline at end of file +/*-backups + +# Production files +/production/* \ No newline at end of file diff --git a/pcbs/a1s-mini/.gitignore b/pcbs/legacy boards/a1s-mini/.gitignore similarity index 89% rename from pcbs/a1s-mini/.gitignore rename to pcbs/legacy boards/a1s-mini/.gitignore index 15fdf72..6092ea7 100644 --- a/pcbs/a1s-mini/.gitignore +++ b/pcbs/legacy boards/a1s-mini/.gitignore @@ -23,3 +23,7 @@ _autosave-* # Exported BOM files *.xml *.csv +/*-backups + +# Production files +/production/* \ No newline at end of file diff --git a/pcbs/a1s-mini/CP2102-GM.kicad_sch b/pcbs/legacy boards/a1s-mini/CP2102-GM.kicad_sch similarity index 100% rename from pcbs/a1s-mini/CP2102-GM.kicad_sch rename to pcbs/legacy boards/a1s-mini/CP2102-GM.kicad_sch diff --git a/pcbs/a1s-mini/CP2102.kicad_sch b/pcbs/legacy boards/a1s-mini/CP2102.kicad_sch similarity index 100% rename from pcbs/a1s-mini/CP2102.kicad_sch rename to pcbs/legacy boards/a1s-mini/CP2102.kicad_sch diff --git a/pcbs/a1s-mini/USBC.kicad_sch b/pcbs/legacy boards/a1s-mini/USBC.kicad_sch similarity index 100% rename from pcbs/a1s-mini/USBC.kicad_sch rename to pcbs/legacy boards/a1s-mini/USBC.kicad_sch diff --git a/pcbs/a1s-mini/a1s-mini.kicad_pcb b/pcbs/legacy boards/a1s-mini/a1s-mini.kicad_pcb similarity index 100% rename from pcbs/a1s-mini/a1s-mini.kicad_pcb rename to pcbs/legacy boards/a1s-mini/a1s-mini.kicad_pcb diff --git a/pcbs/a1s-mini/a1s-mini.kicad_pcb.zip b/pcbs/legacy boards/a1s-mini/a1s-mini.kicad_pcb.zip similarity index 100% rename from pcbs/a1s-mini/a1s-mini.kicad_pcb.zip rename to pcbs/legacy boards/a1s-mini/a1s-mini.kicad_pcb.zip diff --git a/pcbs/a1s-mini/a1s-mini.kicad_prl b/pcbs/legacy boards/a1s-mini/a1s-mini.kicad_prl similarity index 100% rename from pcbs/a1s-mini/a1s-mini.kicad_prl rename to pcbs/legacy boards/a1s-mini/a1s-mini.kicad_prl diff --git a/pcbs/a1s-mini/a1s-mini.kicad_pro b/pcbs/legacy boards/a1s-mini/a1s-mini.kicad_pro similarity index 100% rename from pcbs/a1s-mini/a1s-mini.kicad_pro rename to pcbs/legacy boards/a1s-mini/a1s-mini.kicad_pro diff --git a/pcbs/a1s-mini/a1s-mini.kicad_sch b/pcbs/legacy boards/a1s-mini/a1s-mini.kicad_sch similarity index 100% rename from pcbs/a1s-mini/a1s-mini.kicad_sch rename to pcbs/legacy boards/a1s-mini/a1s-mini.kicad_sch diff --git a/pcbs/a1s-mini/a1s-mini.sch b/pcbs/legacy boards/a1s-mini/a1s-mini.sch similarity index 100% rename from pcbs/a1s-mini/a1s-mini.sch rename to pcbs/legacy boards/a1s-mini/a1s-mini.sch diff --git a/pcbs/a1s-mini/a1s-mini.step b/pcbs/legacy boards/a1s-mini/a1s-mini.step similarity index 100% rename from pcbs/a1s-mini/a1s-mini.step rename to pcbs/legacy boards/a1s-mini/a1s-mini.step diff --git a/pcbs/a1s-mini/bom/2025-03-01_01-09-41_a1s-mini_ibom_0.2.html b/pcbs/legacy boards/a1s-mini/bom/2025-03-01_01-09-41_a1s-mini_ibom_0.2.html similarity index 100% rename from pcbs/a1s-mini/bom/2025-03-01_01-09-41_a1s-mini_ibom_0.2.html rename to pcbs/legacy boards/a1s-mini/bom/2025-03-01_01-09-41_a1s-mini_ibom_0.2.html diff --git a/pcbs/a1s-mini/docs/1-clone.png b/pcbs/legacy boards/a1s-mini/docs/1-clone.png similarity index 100% rename from pcbs/a1s-mini/docs/1-clone.png rename to pcbs/legacy boards/a1s-mini/docs/1-clone.png diff --git a/pcbs/a1s-mini/docs/2-pref.png b/pcbs/legacy boards/a1s-mini/docs/2-pref.png similarity index 100% rename from pcbs/a1s-mini/docs/2-pref.png rename to pcbs/legacy boards/a1s-mini/docs/2-pref.png diff --git a/pcbs/a1s-mini/docs/3-path.png b/pcbs/legacy boards/a1s-mini/docs/3-path.png similarity index 100% rename from pcbs/a1s-mini/docs/3-path.png rename to pcbs/legacy boards/a1s-mini/docs/3-path.png diff --git a/pcbs/a1s-mini/docs/4-newproject.png b/pcbs/legacy boards/a1s-mini/docs/4-newproject.png similarity index 100% rename from pcbs/a1s-mini/docs/4-newproject.png rename to pcbs/legacy boards/a1s-mini/docs/4-newproject.png diff --git a/pcbs/a1s-mini/docs/5-selecttemplate.png b/pcbs/legacy boards/a1s-mini/docs/5-selecttemplate.png similarity index 100% rename from pcbs/a1s-mini/docs/5-selecttemplate.png rename to pcbs/legacy boards/a1s-mini/docs/5-selecttemplate.png diff --git a/pcbs/a1s-mini/fp-info-cache b/pcbs/legacy boards/a1s-mini/fp-info-cache similarity index 100% rename from pcbs/a1s-mini/fp-info-cache rename to pcbs/legacy boards/a1s-mini/fp-info-cache diff --git a/pcbs/a1s-mini/readme.md b/pcbs/legacy boards/a1s-mini/readme.md similarity index 100% rename from pcbs/a1s-mini/readme.md rename to pcbs/legacy boards/a1s-mini/readme.md diff --git a/pcbs/a1s-mini/replicate_layout.log b/pcbs/legacy boards/a1s-mini/replicate_layout.log similarity index 100% rename from pcbs/a1s-mini/replicate_layout.log rename to pcbs/legacy boards/a1s-mini/replicate_layout.log diff --git a/pcbs/hautDeForme/.gitignore b/pcbs/legacy boards/hautDeForme/.gitignore similarity index 89% rename from pcbs/hautDeForme/.gitignore rename to pcbs/legacy boards/hautDeForme/.gitignore index 15fdf72..6092ea7 100644 --- a/pcbs/hautDeForme/.gitignore +++ b/pcbs/legacy boards/hautDeForme/.gitignore @@ -23,3 +23,7 @@ _autosave-* # Exported BOM files *.xml *.csv +/*-backups + +# Production files +/production/* \ No newline at end of file diff --git a/pcbs/hautDeForme/CP2102-GM.kicad_sch b/pcbs/legacy boards/hautDeForme/CP2102-GM.kicad_sch similarity index 100% rename from pcbs/hautDeForme/CP2102-GM.kicad_sch rename to pcbs/legacy boards/hautDeForme/CP2102-GM.kicad_sch diff --git a/pcbs/hautDeForme/CP2102.kicad_sch b/pcbs/legacy boards/hautDeForme/CP2102.kicad_sch similarity index 100% rename from pcbs/hautDeForme/CP2102.kicad_sch rename to pcbs/legacy boards/hautDeForme/CP2102.kicad_sch diff --git a/pcbs/hautDeForme/USBC.kicad_sch b/pcbs/legacy boards/hautDeForme/USBC.kicad_sch similarity index 100% rename from pcbs/hautDeForme/USBC.kicad_sch rename to pcbs/legacy boards/hautDeForme/USBC.kicad_sch diff --git a/pcbs/hautDeForme/bom/2025-03-03_00-34-14_hautDeForme_ibom_0.1.0.html b/pcbs/legacy boards/hautDeForme/bom/2025-03-03_00-34-14_hautDeForme_ibom_0.1.0.html similarity index 100% rename from pcbs/hautDeForme/bom/2025-03-03_00-34-14_hautDeForme_ibom_0.1.0.html rename to pcbs/legacy boards/hautDeForme/bom/2025-03-03_00-34-14_hautDeForme_ibom_0.1.0.html diff --git a/pcbs/hautDeForme/docs/1-clone.png b/pcbs/legacy boards/hautDeForme/docs/1-clone.png similarity index 100% rename from pcbs/hautDeForme/docs/1-clone.png rename to pcbs/legacy boards/hautDeForme/docs/1-clone.png diff --git a/pcbs/hautDeForme/docs/2-pref.png b/pcbs/legacy boards/hautDeForme/docs/2-pref.png similarity index 100% rename from pcbs/hautDeForme/docs/2-pref.png rename to pcbs/legacy boards/hautDeForme/docs/2-pref.png diff --git a/pcbs/hautDeForme/docs/3-path.png b/pcbs/legacy boards/hautDeForme/docs/3-path.png similarity index 100% rename from pcbs/hautDeForme/docs/3-path.png rename to pcbs/legacy boards/hautDeForme/docs/3-path.png diff --git a/pcbs/hautDeForme/docs/4-newproject.png b/pcbs/legacy boards/hautDeForme/docs/4-newproject.png similarity index 100% rename from pcbs/hautDeForme/docs/4-newproject.png rename to pcbs/legacy boards/hautDeForme/docs/4-newproject.png diff --git a/pcbs/hautDeForme/docs/5-selecttemplate.png b/pcbs/legacy boards/hautDeForme/docs/5-selecttemplate.png similarity index 100% rename from pcbs/hautDeForme/docs/5-selecttemplate.png rename to pcbs/legacy boards/hautDeForme/docs/5-selecttemplate.png diff --git a/pcbs/hautDeForme/fp-info-cache b/pcbs/legacy boards/hautDeForme/fp-info-cache similarity index 100% rename from pcbs/hautDeForme/fp-info-cache rename to pcbs/legacy boards/hautDeForme/fp-info-cache diff --git a/pcbs/hautDeForme/hautDeForme-hautDeForme.step b/pcbs/legacy boards/hautDeForme/hautDeForme-hautDeForme.step similarity index 100% rename from pcbs/hautDeForme/hautDeForme-hautDeForme.step rename to pcbs/legacy boards/hautDeForme/hautDeForme-hautDeForme.step diff --git a/pcbs/hautDeForme/hautDeForme.FCStd b/pcbs/legacy boards/hautDeForme/hautDeForme.FCStd similarity index 100% rename from pcbs/hautDeForme/hautDeForme.FCStd rename to pcbs/legacy boards/hautDeForme/hautDeForme.FCStd diff --git a/pcbs/hautDeForme/hautDeForme.kicad_pcb b/pcbs/legacy boards/hautDeForme/hautDeForme.kicad_pcb similarity index 100% rename from pcbs/hautDeForme/hautDeForme.kicad_pcb rename to pcbs/legacy boards/hautDeForme/hautDeForme.kicad_pcb diff --git a/pcbs/hautDeForme/hautDeForme.kicad_pcb.zip b/pcbs/legacy boards/hautDeForme/hautDeForme.kicad_pcb.zip similarity index 100% rename from pcbs/hautDeForme/hautDeForme.kicad_pcb.zip rename to pcbs/legacy boards/hautDeForme/hautDeForme.kicad_pcb.zip diff --git a/pcbs/hautDeForme/hautDeForme.kicad_prl b/pcbs/legacy boards/hautDeForme/hautDeForme.kicad_prl similarity index 100% rename from pcbs/hautDeForme/hautDeForme.kicad_prl rename to pcbs/legacy boards/hautDeForme/hautDeForme.kicad_prl diff --git a/pcbs/hautDeForme/hautDeForme.kicad_pro b/pcbs/legacy boards/hautDeForme/hautDeForme.kicad_pro similarity index 100% rename from pcbs/hautDeForme/hautDeForme.kicad_pro rename to pcbs/legacy boards/hautDeForme/hautDeForme.kicad_pro diff --git a/pcbs/hautDeForme/hautDeForme.kicad_sch b/pcbs/legacy boards/hautDeForme/hautDeForme.kicad_sch similarity index 100% rename from pcbs/hautDeForme/hautDeForme.kicad_sch rename to pcbs/legacy boards/hautDeForme/hautDeForme.kicad_sch diff --git a/pcbs/hautDeForme/hautDeForme.sch b/pcbs/legacy boards/hautDeForme/hautDeForme.sch similarity index 100% rename from pcbs/hautDeForme/hautDeForme.sch rename to pcbs/legacy boards/hautDeForme/hautDeForme.sch diff --git a/pcbs/hautDeForme/hautDeForme_log_missing3Dmodels.txt b/pcbs/legacy boards/hautDeForme/hautDeForme_log_missing3Dmodels.txt similarity index 100% rename from pcbs/hautDeForme/hautDeForme_log_missing3Dmodels.txt rename to pcbs/legacy boards/hautDeForme/hautDeForme_log_missing3Dmodels.txt diff --git a/pcbs/hautDeForme/hautDeForme_missing3Dmodels.txt b/pcbs/legacy boards/hautDeForme/hautDeForme_missing3Dmodels.txt similarity index 100% rename from pcbs/hautDeForme/hautDeForme_missing3Dmodels.txt rename to pcbs/legacy boards/hautDeForme/hautDeForme_missing3Dmodels.txt diff --git a/pcbs/hautDeForme/readme.md b/pcbs/legacy boards/hautDeForme/readme.md similarity index 100% rename from pcbs/hautDeForme/readme.md rename to pcbs/legacy boards/hautDeForme/readme.md diff --git a/pcbs/ipodesp32 PL2303/.gitignore b/pcbs/legacy boards/ipodesp32 PL2303/.gitignore similarity index 89% rename from pcbs/ipodesp32 PL2303/.gitignore rename to pcbs/legacy boards/ipodesp32 PL2303/.gitignore index 15fdf72..6092ea7 100644 --- a/pcbs/ipodesp32 PL2303/.gitignore +++ b/pcbs/legacy boards/ipodesp32 PL2303/.gitignore @@ -23,3 +23,7 @@ _autosave-* # Exported BOM files *.xml *.csv +/*-backups + +# Production files +/production/* \ No newline at end of file diff --git a/pcbs/ipodesp32 PL2303/2024-06-04_11-59-24_ipodesp32 PL2303_ibom_0.2.0.html b/pcbs/legacy boards/ipodesp32 PL2303/2024-06-04_11-59-24_ipodesp32 PL2303_ibom_0.2.0.html similarity index 100% rename from pcbs/ipodesp32 PL2303/2024-06-04_11-59-24_ipodesp32 PL2303_ibom_0.2.0.html rename to pcbs/legacy boards/ipodesp32 PL2303/2024-06-04_11-59-24_ipodesp32 PL2303_ibom_0.2.0.html diff --git a/pcbs/ipodesp32 PL2303/PL2303G Carrier.pdf b/pcbs/legacy boards/ipodesp32 PL2303/PL2303G Carrier.pdf similarity index 100% rename from pcbs/ipodesp32 PL2303/PL2303G Carrier.pdf rename to pcbs/legacy boards/ipodesp32 PL2303/PL2303G Carrier.pdf diff --git a/pcbs/ipodesp32 PL2303/bom/2024-06-04_12-14-32_ipodesp32 PL2303_ibom_0.2.0.html b/pcbs/legacy boards/ipodesp32 PL2303/bom/2024-06-04_12-14-32_ipodesp32 PL2303_ibom_0.2.0.html similarity index 100% rename from pcbs/ipodesp32 PL2303/bom/2024-06-04_12-14-32_ipodesp32 PL2303_ibom_0.2.0.html rename to pcbs/legacy boards/ipodesp32 PL2303/bom/2024-06-04_12-14-32_ipodesp32 PL2303_ibom_0.2.0.html diff --git a/pcbs/ipodesp32 PL2303/bom/2024-07-16_09-28-20_ipodesp32 PL2303_ibom_0.2.1.html b/pcbs/legacy boards/ipodesp32 PL2303/bom/2024-07-16_09-28-20_ipodesp32 PL2303_ibom_0.2.1.html similarity index 100% rename from pcbs/ipodesp32 PL2303/bom/2024-07-16_09-28-20_ipodesp32 PL2303_ibom_0.2.1.html rename to pcbs/legacy boards/ipodesp32 PL2303/bom/2024-07-16_09-28-20_ipodesp32 PL2303_ibom_0.2.1.html diff --git a/pcbs/ipodesp32 PL2303/fp-info-cache b/pcbs/legacy boards/ipodesp32 PL2303/fp-info-cache similarity index 100% rename from pcbs/ipodesp32 PL2303/fp-info-cache rename to pcbs/legacy boards/ipodesp32 PL2303/fp-info-cache diff --git a/pcbs/ipodesp32 PL2303/iPodEsp32_BOM_PCBWay.xlsx b/pcbs/legacy boards/ipodesp32 PL2303/iPodEsp32_BOM_PCBWay.xlsx similarity index 100% rename from pcbs/ipodesp32 PL2303/iPodEsp32_BOM_PCBWay.xlsx rename to pcbs/legacy boards/ipodesp32 PL2303/iPodEsp32_BOM_PCBWay.xlsx diff --git a/pcbs/ipodesp32 PL2303/ipodesp32 PL2303.kicad_pcb b/pcbs/legacy boards/ipodesp32 PL2303/ipodesp32 PL2303.kicad_pcb similarity index 100% rename from pcbs/ipodesp32 PL2303/ipodesp32 PL2303.kicad_pcb rename to pcbs/legacy boards/ipodesp32 PL2303/ipodesp32 PL2303.kicad_pcb diff --git a/pcbs/ipodesp32 PL2303/ipodesp32 PL2303.kicad_pcb.zip b/pcbs/legacy boards/ipodesp32 PL2303/ipodesp32 PL2303.kicad_pcb.zip similarity index 100% rename from pcbs/ipodesp32 PL2303/ipodesp32 PL2303.kicad_pcb.zip rename to pcbs/legacy boards/ipodesp32 PL2303/ipodesp32 PL2303.kicad_pcb.zip diff --git a/pcbs/ipodesp32 PL2303/ipodesp32 PL2303.kicad_prl b/pcbs/legacy boards/ipodesp32 PL2303/ipodesp32 PL2303.kicad_prl similarity index 100% rename from pcbs/ipodesp32 PL2303/ipodesp32 PL2303.kicad_prl rename to pcbs/legacy boards/ipodesp32 PL2303/ipodesp32 PL2303.kicad_prl diff --git a/pcbs/ipodesp32 PL2303/ipodesp32 PL2303.kicad_pro b/pcbs/legacy boards/ipodesp32 PL2303/ipodesp32 PL2303.kicad_pro similarity index 100% rename from pcbs/ipodesp32 PL2303/ipodesp32 PL2303.kicad_pro rename to pcbs/legacy boards/ipodesp32 PL2303/ipodesp32 PL2303.kicad_pro diff --git a/pcbs/ipodesp32 PL2303/ipodesp32 PL2303.kicad_sch b/pcbs/legacy boards/ipodesp32 PL2303/ipodesp32 PL2303.kicad_sch similarity index 100% rename from pcbs/ipodesp32 PL2303/ipodesp32 PL2303.kicad_sch rename to pcbs/legacy boards/ipodesp32 PL2303/ipodesp32 PL2303.kicad_sch diff --git a/pcbs/ipodesp32 PL2303/ipodesp32 PL2303.sch b/pcbs/legacy boards/ipodesp32 PL2303/ipodesp32 PL2303.sch similarity index 100% rename from pcbs/ipodesp32 PL2303/ipodesp32 PL2303.sch rename to pcbs/legacy boards/ipodesp32 PL2303/ipodesp32 PL2303.sch diff --git a/pcbs/sandwichCircuit/.gitignore b/pcbs/sandwichCircuit/.gitignore index 15fdf72..6092ea7 100644 --- a/pcbs/sandwichCircuit/.gitignore +++ b/pcbs/sandwichCircuit/.gitignore @@ -23,3 +23,7 @@ _autosave-* # Exported BOM files *.xml *.csv +/*-backups + +# Production files +/production/* \ No newline at end of file