Diff between 9af28350c15134dce630c12b26758f7e9e23abb7 and cb9780d0512e314cc14157e272f0b7d490d7321c

Changed Files

File Additions Deletions Status
tools/parser/avrcp.c +79 -15 modified

Full Patch

diff --git a/tools/parser/avrcp.c b/tools/parser/avrcp.c
index 3a16315..c83b70f 100644
--- a/tools/parser/avrcp.c
+++ b/tools/parser/avrcp.c
@@ -84,6 +84,12 @@
 #define AVC_PANEL_FORWARD		0x4b
 #define AVC_PANEL_BACKWARD		0x4c
 
+/* Packet types */
+#define AVRCP_PACKET_TYPE_SINGLE	0x00
+#define AVRCP_PACKET_TYPE_START		0x01
+#define AVRCP_PACKET_TYPE_CONTINUING	0x02
+#define AVRCP_PACKET_TYPE_END		0x03
+
 /* pdu ids */
 #define AVRCP_GET_CAPABILITIES		0x10
 #define AVRCP_LIST_PLAYER_ATTRIBUTES	0x11
@@ -173,6 +179,11 @@
 #define AVRCP_PLAY_STATUS_REV_SEEK	0x04
 #define AVRCP_PLAY_STATUS_ERROR		0xFF
 
+static struct avrcp_continuing {
+	uint16_t num;
+	uint16_t size;
+} avrcp_continuing;
+
 static const char *ctype2str(uint8_t ctype)
 {
 	switch (ctype & 0x0f) {
@@ -221,6 +232,22 @@ static const char *opcode2str(uint8_t opcode)
 	}
 }
 
+static const char *pt2str(uint8_t pt)
+{
+	switch (pt) {
+	case AVRCP_PACKET_TYPE_SINGLE:
+		return "Single";
+	case AVRCP_PACKET_TYPE_START:
+		return "Start";
+	case AVRCP_PACKET_TYPE_CONTINUING:
+		return "Continuing";
+	case AVRCP_PACKET_TYPE_END:
+		return "End";
+	default:
+		return "Unknown";
+	}
+}
+
 static const char *pdu2str(uint8_t pduid)
 {
 	switch (pduid) {
@@ -914,7 +941,8 @@ static const char *mediattr2str(uint32_t attr)
 }
 
 static void avrcp_get_element_attributes_dump(int level, struct frame *frm,
-						uint8_t ctype, uint16_t len)
+						uint8_t ctype, uint16_t len,
+						uint8_t pt)
 {
 	uint64_t id;
 	uint8_t num;
@@ -950,18 +978,45 @@ static void avrcp_get_element_attributes_dump(int level, struct frame *frm,
 	return;
 
 response:
-	if (len < 1) {
-		printf("PDU Malformed\n");
-		raw_dump(level, frm);
-		return;
-	}
+	if (pt == AVRCP_PACKET_TYPE_SINGLE || pt == AVRCP_PACKET_TYPE_START) {
+		if (len < 1) {
+			printf("PDU Malformed\n");
+			raw_dump(level, frm);
+			return;
+		}
 
-	num = get_u8(frm);
-	printf("AttributeCount: 0x%02x\n", num);
+		num = get_u8(frm);
+		avrcp_continuing.num = num;
+		printf("AttributeCount: 0x%02x\n", num);
+		len--;
+	} else {
+		num = avrcp_continuing.num;
+
+		if (avrcp_continuing.size > 0) {
+			uint16_t size;
+
+			if (avrcp_continuing.size > len) {
+				size = len;
+				avrcp_continuing.size -= len;
+			} else {
+				size = avrcp_continuing.size;
+				avrcp_continuing.size = 0;
+			}
+
+			printf("ContinuingAttributeValue: ");
+			for (; size > 0; size--) {
+				uint8_t c = get_u8(frm);
+				printf("%1c", isprint(c) ? c : '.');
+			}
+			printf("\n");
 
-	for (; num > 0; num--) {
+			len -= size;
+		}
+	}
+
+	while (num > 0 && len > 0) {
 		uint32_t attr;
-		uint16_t charset, len;
+		uint16_t charset, attrlen;
 
 		p_indent(level, frm);
 
@@ -975,19 +1030,26 @@ response:
 							charset2str(charset));
 
 		p_indent(level, frm);
+		attrlen = get_u16(frm);
+		printf("AttributeValueLength: 0x%04x\n", attrlen);
 
-		len = get_u16(frm);
-		printf("AttributeValueLength: 0x%04x\n", len);
+		len -= sizeof(attr) + sizeof(charset) + sizeof(attrlen);
+		num--;
 
 		p_indent(level, frm);
 
 		printf("AttributeValue: ");
-		for (; len > 0; len--) {
+		for (; attrlen > 0 && len > 0; attrlen--, len--) {
 			uint8_t c = get_u8(frm);
 			printf("%1c", isprint(c) ? c : '.');
 		}
 		printf("\n");
+
+		if (attrlen > 0)
+			avrcp_continuing.size = attrlen;
 	}
+
+	avrcp_continuing.num = num;
 }
 
 static const char *playstatus2str(uint8_t status)
@@ -1150,7 +1212,8 @@ static void avrcp_pdu_dump(int level, struct frame *frm, uint8_t ctype)
 	pt = get_u8(frm);
 	len = get_u16(frm);
 
-	printf("AVRCP: %s: pt 0x%02x len 0x%04x\n", pdu2str(pduid), pt, len);
+	printf("AVRCP: %s: pt %s len 0x%04x\n", pdu2str(pduid),
+							pt2str(pt), len);
 
 	if (len != frm->len) {
 		p_indent(level, frm);
@@ -1195,7 +1258,8 @@ static void avrcp_pdu_dump(int level, struct frame *frm, uint8_t ctype)
 		avrcp_ct_battery_status_dump(level + 1, frm, ctype, len);
 		break;
 	case AVRCP_GET_ELEMENT_ATTRIBUTES:
-		avrcp_get_element_attributes_dump(level + 1, frm, ctype, len);
+		avrcp_get_element_attributes_dump(level + 1, frm, ctype, len,
+									pt);
 		break;
 	case AVRCP_GET_PLAY_STATUS:
 		avrcp_get_play_status_dump(level + 1, frm, ctype, len);