OSDN Git Service

Monitor: Add AVRCP RegisterNotification support
authorVikrampal Yadav <vikram.pal@samsung.com>
Thu, 25 Sep 2014 10:18:19 +0000 (15:48 +0530)
committerLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Fri, 26 Sep 2014 07:02:55 +0000 (10:02 +0300)
Support for decoding AVRCP RegisterNotification added in Bluetooth
monitor.

monitor/avctp.c

index 3356cf9..1ffcb7e 100644 (file)
@@ -591,6 +591,24 @@ static const char *playstatus2str(uint8_t status)
        }
 }
 
+static const char *status2str(uint8_t status)
+{
+       switch (status) {
+       case 0x0:
+               return "NORMAL";
+       case 0x1:
+               return "WARNING";
+       case 0x2:
+               return "CRITICAL";
+       case 0x3:
+               return "EXTERNAL";
+       case 0x4:
+               return "FULL_CHARGE";
+       default:
+               return "Reserved";
+       }
+}
+
 static bool avrcp_passthrough_packet(struct avctp_frame *avctp_frame)
 {
        struct l2cap_frame *frame = &avctp_frame->l2cap_frame;
@@ -1131,6 +1149,148 @@ static bool avrcp_get_play_status(struct avctp_frame *avctp_frame,
        return true;
 }
 
+static bool avrcp_register_notification(struct avctp_frame *avctp_frame,
+                                       uint8_t ctype, uint8_t len,
+                                       uint8_t indent)
+{
+       struct l2cap_frame *frame = &avctp_frame->l2cap_frame;
+       uint8_t event, status;
+       uint16_t uid;
+       uint32_t interval;
+       uint64_t id;
+
+       if (ctype > AVC_CTYPE_GENERAL_INQUIRY)
+               goto response;
+
+       if (!l2cap_frame_get_u8(frame, &event))
+               return false;
+
+       print_field("%*cEventID: 0x%02x (%s)", (indent - 8),
+                                               ' ', event, event2str(event));
+
+       if (!l2cap_frame_get_be32(frame, &interval))
+               return false;
+
+       print_field("%*cInterval: 0x%08x (%u seconds)",
+                                       (indent - 8), ' ', interval, interval);
+
+       return true;
+
+response:
+       if (!l2cap_frame_get_u8(frame, &event))
+               return false;
+
+       print_field("%*cEventID: 0x%02x (%s)", (indent - 8),
+                                               ' ', event, event2str(event));
+
+       switch (event) {
+       case AVRCP_EVENT_PLAYBACK_STATUS_CHANGED:
+               if (!l2cap_frame_get_u8(frame, &status))
+                       return false;
+
+               print_field("%*cPlayStatus: 0x%02x (%s)", (indent - 8),
+                                       ' ', status, playstatus2str(status));
+               break;
+       case AVRCP_EVENT_TRACK_CHANGED:
+               if (!l2cap_frame_get_be64(frame, &id))
+                       return false;
+
+               print_field("%*cIdentifier: 0x%16" PRIx64 " (%" PRIu64 ")",
+                                               (indent - 8), ' ', id, id);
+               break;
+       case AVRCP_EVENT_PLAYBACK_POS_CHANGED:
+               if (!l2cap_frame_get_be32(frame, &interval))
+                       return false;
+
+               print_field("%*cPosition: 0x%08x (%u miliseconds)",
+                                       (indent - 8), ' ', interval, interval);
+               break;
+       case AVRCP_EVENT_BATT_STATUS_CHANGED:
+               if (!l2cap_frame_get_u8(frame, &status))
+                       return false;
+
+               print_field("%*cBatteryStatus: 0x%02x (%s)", (indent - 8),
+                                       ' ', status, status2str(status));
+
+               break;
+       case AVRCP_EVENT_SYSTEM_STATUS_CHANGED:
+               if (!l2cap_frame_get_u8(frame, &status))
+                       return false;
+
+               print_field("%*cSystemStatus: 0x%02x ", (indent - 8),
+                                                               ' ', status);
+               switch (status) {
+               case 0x00:
+                       printf("(POWER_ON)\n");
+                       break;
+               case 0x01:
+                       printf("(POWER_OFF)\n");
+                       break;
+               case 0x02:
+                       printf("(UNPLUGGED)\n");
+                       break;
+               default:
+                       printf("(UNKOWN)\n");
+                       break;
+               }
+               break;
+       case AVRCP_EVENT_PLAYER_APPLICATION_SETTING_CHANGED:
+               if (!l2cap_frame_get_u8(frame, &status))
+                       return false;
+
+               print_field("%*cAttributeCount: 0x%02x", (indent - 8),
+                                                               ' ', status);
+
+               for (; status > 0; status--) {
+                       uint8_t attr, value;
+
+                       if (!l2cap_frame_get_u8(frame, &attr))
+                               return false;
+
+                       print_field("%*cAttributeID: 0x%02x (%s)",
+                               (indent - 8), ' ', attr, attr2str(attr));
+
+                       if (!l2cap_frame_get_u8(frame, &value))
+                               return false;
+
+                       print_field("%*cValueID: 0x%02x (%s)", (indent - 8),
+                                       ' ', value, value2str(attr, value));
+               }
+               break;
+       case AVRCP_EVENT_VOLUME_CHANGED:
+               if (!l2cap_frame_get_u8(frame, &status))
+                       return false;
+
+               status &= 0x7F;
+
+               print_field("%*cVolume: %.2f%% (%d/127)", (indent - 8),
+                                               ' ', status/1.27, status);
+               break;
+       case AVRCP_EVENT_ADDRESSED_PLAYER_CHANGED:
+               if (!l2cap_frame_get_be16(frame, &uid))
+                       return false;
+
+               print_field("%*cPlayerID: 0x%04x (%u)", (indent - 8),
+                                                               ' ', uid, uid);
+
+               if (!l2cap_frame_get_be16(frame, &uid))
+                       return false;
+
+               print_field("%*cUIDCounter: 0x%04x (%u)", (indent - 8),
+                                                               ' ', uid, uid);
+               break;
+       case AVRCP_EVENT_UIDS_CHANGED:
+               if (!l2cap_frame_get_be16(frame, &uid))
+                       return false;
+
+               print_field("%*cUIDCounter: 0x%04x (%u)", (indent - 8),
+                                                               ' ', uid, uid);
+               break;
+       }
+
+       return true;
+}
+
 struct avrcp_ctrl_pdu_data {
        uint8_t pduid;
        bool (*func) (struct avctp_frame *avctp_frame, uint8_t ctype,
@@ -1148,6 +1308,7 @@ static const struct avrcp_ctrl_pdu_data avrcp_ctrl_pdu_table[] = {
        { 0x17, avrcp_displayable_charset               },
        { 0x20, avrcp_get_element_attributes            },
        { 0x30, avrcp_get_play_status                   },
+       { 0x31, avrcp_register_notification             },
        { }
 };