Đức Thanh Nguyễn
Đức Thanh Nguyễn

Reputation: 9365

ANCS ESP32 BLE Arduino Invalid command (0xA1). The command was improperly formatted. When write value to Control Point Characteristic

I'm now trying to write to the Control Point Characteristic according to the ANCS - Apple Notification Center Service using an Arduino ESP32.

This is my current definition for the notification attributes command to send to the Control Point Characteristic:

        uint8_t notificationAttributesCommand[7];

        notificationAttributesCommand[0] = 0x00;  // Command ID: Get Notification Attributes
        notificationAttributesCommand[1] = (uint8_t)(notificationUID >> 24);  // Notification UID (Most significant byte)
        notificationAttributesCommand[2] = (uint8_t)(notificationUID >> 16);  // Second byte
        notificationAttributesCommand[3] = (uint8_t)(notificationUID >> 8);   // Third byte
        notificationAttributesCommand[4] = (uint8_t)(notificationUID);        // Least significant byte

        // Attribute IDs and their maximum length (as per your specification)
        notificationAttributesCommand[5] = 0x01;  // Attribute ID for App Identifier

And this is how I send it in my loop() function:

void loop() {
    if (newNotificationFlag) {
        // Send the command to the Control Point characteristic
        if (pControlPointCharacteristic != nullptr) {
            Serial.println("Sending Get Notification Attributes command to Control Point...");
            if (pControlPointCharacteristic->canWrite()) {
                Serial.println("before writing to pControlPointCharacteristic!");
                pControlPointCharacteristic->writeValue(notificationAttributesCommand, sizeof(notificationAttributesCommand), true);
                Serial.println("after writing to pControlPointCharacteristic!");
            } else {
              Serial.println("loop(): Control Point Characteristic cannot be written.");
            }
        } else {
            Serial.println("Control Point characteristic is null");
        }
        // Reset the flag
        newNotificationFlag = false;
    }
}

I have modified the code from BLERemoteCharacteristic.cpp to output the log like this:

case ESP_GATTC_WRITE_CHAR_EVT:
    {
      log_d("case ESP_GATTC_WRITE_CHAR_EVT");
      // Determine if this event is for us and, if not, pass onwards.
      if (evtParam->write.handle != getHandle()) {
        break;
      }

      // Check the write status to confirm if it was successful
      // Check the write status to confirm if it was successful or if an error occurred
      if (evtParam->write.status == ESP_GATT_OK) {
          log_d("Write to Control Point characteristic was successful.");
      } else {
          // Handle specific ANCS error codes
          switch (evtParam->write.status) {
              case 0xA0:
                  log_d("Write to Control Point characteristic failed. Error: Unknown command (0xA0). The commandID was not recognized by the NP.");
                  break;
              case 0xA1:
                  log_d("Write to Control Point characteristic failed. Error: Invalid command (0xA1). The command was improperly formatted.");
                  break;
              case 0xA2:
                  log_d("Write to Control Point characteristic failed. Error: Invalid parameter (0xA2). One of the parameters (e.g., NotificationUID) does not refer to an existing object on the NP.");
                  break;
              case 0xA3:
                  log_d("Write to Control Point characteristic failed. Error: Action failed (0xA3). The action was not performed.");
                  break;
              default:
                  log_d("Write to Control Point characteristic failed. Unknown error status: %d", evtParam->write.status);
                  break;
          }
      }

      // Error Codes
      // https://developer.apple.com/library/archive/documentation/CoreBluetooth/Reference/AppleNotificationCenterServiceSpecification/Specification/Specification.html#//apple_ref/doc/uid/TP40013460-CH1-SW7
      // When writing to the Control Point characteristic, an NC may receive the following ANCS-specific error codes:

      // There is nothing further we need to do here.  This is merely an indication
      // that the write has completed and we can unlock the caller.
      m_semaphoreWriteCharEvt.give();
      log_d("after m_semaphoreWriteCharEvt.give, There is nothing further we need to do here.  This is merely an indication that the write has completed and we can unlock the caller.");
      break;
    }  // ESP_GATTC_WRITE_CHAR_EVT

Upon deployment and testing, I get this log:

15:35:25.617 -> [577839][D][BLEDevice.cpp:138] gattClientEventHandler(): gattClientEventHandler [esp_gatt_if: 5] ... ESP_GATTC_NOTIFY_EVT
15:35:25.617 -> [577852][D][BLEClient.cpp:185] gattClientEventHandler(): gattClientEventHandler [esp_gatt_if: 5] ... ESP_GATTC_NOTIFY_EVT
15:35:25.661 -> [577863][D][BLERemoteCharacteristic.cpp:154] gattClientEventHandler(): case ESP_GATTC_NOTIFY_EVT
15:35:25.661 -> [577871][D][BLERemoteCharacteristic.cpp:154] gattClientEventHandler(): case ESP_GATTC_NOTIFY_EVT
15:35:25.661 -> [577880][D][BLERemoteCharacteristic.cpp:159] gattClientEventHandler(): @Invoking callback for notification on characteristic Characteristic: uuid: 9fbf120d-6301-42d9-8c58-25e699a21dbd, handle: 40 0x0028, props: broadcast: 0, read: 0, write_nr: 0, write: 0, notify: 1, indicate: 0, auth: 0
15:35:25.681 -> 0x00 0x10 0x00 0x0C 0x0D 0x00 0x00 0x00 
15:35:25.681 -> New notification!
15:35:25.681 -> Notification UID: 218103808
15:35:25.681 ->   Category: Other
15:35:25.681 -> Sending Get Notification Attr[577906][D][BLERemoteCharacteristic.cpp:154] gattClientEventHandler(): case ESP_GATTC_NOTIFY_EVT
15:35:25.713 -> ibutes command to Control Point...
15:35:25.713 -> before writing to pControlPointCharacteristic!
15:35:25.713 -> [577925][D][BLERemoteCharacteristic.cpp:598] writeValue(): >> writeValue(), length: 7
15:35:25.713 -> [577941][D][BLERemoteCharacteristic.cpp:606] writeValue(): 1. Before m_semaphoreWriteCharEvt.take
15:35:25.713 -> [577949][D][BLERemoteCharacteristic.cpp:610] writeValue(): 2. After m_semaphoreWriteCharEvt.take
15:35:25.746 -> [577958][D][BLERemoteCharacteristic.cpp:617] writeValue(): 3. Before errRc != ESP_OK
15:35:25.746 -> [577966][D][BLERemoteCharacteristic.cpp:624] writeValue(): 4. Before m_semaphoreWriteCharEvt.wait
15:35:25.811 -> [578051][D][BLEDevice.cpp:138] gattClientEventHandler(): gattClientEventHandler [esp_gatt_if: 5] ... ESP_GATTC_WRITE_CHAR_EVT
15:35:25.843 -> [578062][D][BLEClient.cpp:185] gattClientEventHandler(): gattClientEventHandler [esp_gatt_if: 5] ... ESP_GATTC_WRITE_CHAR_EVT
15:35:25.843 -> [578073][D][BLERemoteCharacteristic.cpp:241] gattClientEventHandler(): case ESP_GATTC_WRITE_CHAR_EVT
15:35:25.843 -> [578082][D][BLERemoteCharacteristic.cpp:258] gattClientEventHandler(): Write to Control Point characteristic failed. Error: Invalid command (0xA1). The command was improperly formatted.
15:35:25.875 -> [578098][D][BLERemoteCharacteristic.cpp:626] writeValue():[ 557.8 0A9f8t]e[rD ]m[_BsLeEmRaepmhootreeCWhrairtaecCthearriEsvtti.cw.ait:279] gattClientEventHandler(): after m_semaphoreWriteCharEvt.give, There is nothing further we need to do here.  This is merely an indication that the write has completed and we can unlock the caller.
15:35:25.907 -> after writing to pControlPointCharacteristic!
15:35:25.907 -> [578127][D][BLERemoteCharacteristic.cpp:241] gattClientEventHandler(): case ESP_GATTC_WRITE_CHAR_EVT
15:35:25.907 -> [578140][D][BLERemoteCharacteristic.cpp:241] gattClientEventHandler(): case ESP_GATTC_WRITE_CHAR_EVT

I'm focusing on this particular line:

Write to Control Point characteristic failed. Error: Invalid command (0xA1). The command was improperly formatted.

Can someone tell me what is wrong with my get command definition? Thank you

Upvotes: 1

Views: 29

Answers (0)

Related Questions