/*******************************************************************************
**
** Function         avrc_bld_notify_rsp
**
** Description      This function builds the Notification response.
**
** Returns          AVRC_STS_NO_ERROR, if the response is built successfully
**                  Otherwise, the error code.
**
*******************************************************************************/
static tAVRC_STS avrc_bld_notify_rsp (tAVRC_REG_NOTIF_RSP *p_rsp, BT_HDR *p_pkt)
{
    UINT8   *p_data, *p_start;
    UINT8   *p_len;
    UINT16  len = 0;
    UINT8   xx;
    tAVRC_STS status = AVRC_STS_NO_ERROR;

    AVRC_TRACE_API0("avrc_bld_notify_rsp");

    p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
    p_data = p_len = p_start + 2; /* pdu + rsvd */
    p_data += 2;

    UINT8_TO_BE_STREAM(p_data, p_rsp->event_id);
    switch (p_rsp->event_id)
    {
    case AVRC_EVT_PLAY_STATUS_CHANGE:       /* 0x01 */
        /* p_rsp->param.play_status >= AVRC_PLAYSTATE_STOPPED is always TRUE */
        if ((p_rsp->param.play_status <= AVRC_PLAYSTATE_REV_SEEK) ||
            (p_rsp->param.play_status == AVRC_PLAYSTATE_ERROR) )
        {
            UINT8_TO_BE_STREAM(p_data, p_rsp->param.play_status);
            len = 2;
        }
        else
        {
            AVRC_TRACE_ERROR0("bad play state");
            status = AVRC_STS_BAD_PARAM;
        }
        break;

    case AVRC_EVT_TRACK_CHANGE:             /* 0x02 */
        ARRAY_TO_BE_STREAM(p_data, p_rsp->param.track, AVRC_UID_SIZE);
        len = (UINT8)(AVRC_UID_SIZE + 1);
        break;

    case AVRC_EVT_TRACK_REACHED_END:        /* 0x03 */
    case AVRC_EVT_TRACK_REACHED_START:      /* 0x04 */
        len = 1;
        break;

    case AVRC_EVT_PLAY_POS_CHANGED:         /* 0x05 */
        UINT32_TO_BE_STREAM(p_data, p_rsp->param.play_pos);
        len = 5;
        break;

    case AVRC_EVT_BATTERY_STATUS_CHANGE:    /* 0x06 */
        if (AVRC_IS_VALID_BATTERY_STATUS(p_rsp->param.battery_status))
        {
            UINT8_TO_BE_STREAM(p_data, p_rsp->param.battery_status);
            len = 2;
        }
        else
        {
            AVRC_TRACE_ERROR0("bad battery status");
            status = AVRC_STS_BAD_PARAM;
        }
        break;

    case AVRC_EVT_SYSTEM_STATUS_CHANGE:     /* 0x07 */
        if (AVRC_IS_VALID_SYSTEM_STATUS(p_rsp->param.system_status))
        {
            UINT8_TO_BE_STREAM(p_data, p_rsp->param.system_status);
            len = 2;
        }
        else
        {
            AVRC_TRACE_ERROR0("bad system status");
            status = AVRC_STS_BAD_PARAM;
        }
        break;

    case AVRC_EVT_APP_SETTING_CHANGE:       /* 0x08 */
        if (p_rsp->param.player_setting.num_attr > AVRC_MAX_APP_SETTINGS)
            p_rsp->param.player_setting.num_attr = AVRC_MAX_APP_SETTINGS;

        if (p_rsp->param.player_setting.num_attr > 0)
        {
            UINT8_TO_BE_STREAM(p_data, p_rsp->param.player_setting.num_attr);
            len = 2;
            for (xx=0; xx<p_rsp->param.player_setting.num_attr; xx++)
            {
                if (avrc_is_valid_player_attrib_value(p_rsp->param.player_setting.attr_id[xx],
                    p_rsp->param.player_setting.attr_value[xx]))
                {
                    UINT8_TO_BE_STREAM(p_data, p_rsp->param.player_setting.attr_id[xx]);
                    UINT8_TO_BE_STREAM(p_data, p_rsp->param.player_setting.attr_value[xx]);
                }
                else
                {
                    AVRC_TRACE_ERROR0("bad player app seeting attribute or value");
                    status = AVRC_STS_BAD_PARAM;
                    break;
                }
                len += 2;
            }
        }
        else
            status = AVRC_STS_BAD_PARAM;
        break;

    default:
        status = AVRC_STS_BAD_PARAM;
        AVRC_TRACE_ERROR0("unknown event_id");
    }

    UINT16_TO_BE_STREAM(p_len, len);
    p_pkt->len = (p_data - p_start);

    return status;
}
Exemple #2
0
/*******************************************************************************
**
** Function         avrc_pars_vendor_cmd
**
** Description      This function parses the vendor specific commands defined by
**                  Bluetooth SIG
**
** Returns          AVRC_STS_NO_ERROR, if the message in p_data is parsed successfully.
**                  Otherwise, the error code defined by AVRCP 1.4
**
*******************************************************************************/
static tAVRC_STS avrc_pars_vendor_cmd(tAVRC_MSG_VENDOR *p_msg, tAVRC_COMMAND *p_result,
                                      UINT8 *p_buf, UINT16 buf_len)
{
    tAVRC_STS  status = AVRC_STS_NO_ERROR;
    UINT8   *p;
    UINT16  len;
    UINT8   xx, yy;
    UINT8   *p_u8;
    UINT16  *p_u16;
    UINT32  u32, u32_2, *p_u32;
    tAVRC_APP_SETTING       *p_app_set;
    UINT16  size_needed;

    /* Check the vendor data */
    if (p_msg->vendor_len == 0) {
        return AVRC_STS_NO_ERROR;
    }
    if (p_msg->p_vendor_data == NULL) {
        return AVRC_STS_INTERNAL_ERR;
    }

    p = p_msg->p_vendor_data;
    p_result->pdu = *p++;
    AVRC_TRACE_DEBUG("avrc_pars_vendor_cmd() pdu:0x%x", p_result->pdu);
    if (!AVRC_IsValidAvcType (p_result->pdu, p_msg->hdr.ctype)) {
        AVRC_TRACE_DEBUG("avrc_pars_vendor_cmd() detects wrong AV/C type!");
        status = AVRC_STS_BAD_CMD;
    }

    p++; /* skip the reserved byte */
    BE_STREAM_TO_UINT16 (len, p);
    if ((len + 4) != (p_msg->vendor_len)) {
        status = AVRC_STS_INTERNAL_ERR;
    }

    if (status != AVRC_STS_NO_ERROR) {
        return status;
    }

    switch (p_result->pdu) {
    case AVRC_PDU_GET_CAPABILITIES:         /* 0x10 */
        p_result->get_caps.capability_id = *p++;
        if (!AVRC_IS_VALID_CAP_ID(p_result->get_caps.capability_id)) {
            status = AVRC_STS_BAD_PARAM;
        } else if (len != 1) {
            status = AVRC_STS_INTERNAL_ERR;
        }
        break;

    case AVRC_PDU_LIST_PLAYER_APP_ATTR:     /* 0x11 */
        /* no additional parameters */
        if (len != 0) {
            status = AVRC_STS_INTERNAL_ERR;
        }
        break;

    case AVRC_PDU_LIST_PLAYER_APP_VALUES:   /* 0x12 */
        p_result->list_app_values.attr_id = *p++;
        if (!AVRC_IS_VALID_ATTRIBUTE(p_result->list_app_values.attr_id)) {
            status = AVRC_STS_BAD_PARAM;
        } else if (len != 1) {
            status = AVRC_STS_INTERNAL_ERR;
        }
        break;

    case AVRC_PDU_GET_CUR_PLAYER_APP_VALUE: /* 0x13 */
    case AVRC_PDU_GET_PLAYER_APP_ATTR_TEXT: /* 0x15 */
        BE_STREAM_TO_UINT8 (p_result->get_cur_app_val.num_attr, p);
        if (len != (p_result->get_cur_app_val.num_attr + 1)) {
            status = AVRC_STS_INTERNAL_ERR;
            break;
        }
        p_u8 = p_result->get_cur_app_val.attrs;
        for (xx = 0, yy = 0; xx < p_result->get_cur_app_val.num_attr; xx++) {
            /* only report the valid player app attributes */
            if (AVRC_IsValidPlayerAttr(*p)) {
                p_u8[yy++] = *p;
            }
            p++;
        }
        p_result->get_cur_app_val.num_attr = yy;
        if (yy == 0) {
            status = AVRC_STS_BAD_PARAM;
        }
        break;

    case AVRC_PDU_SET_PLAYER_APP_VALUE:     /* 0x14 */
        BE_STREAM_TO_UINT8 (p_result->set_app_val.num_val, p);
        size_needed = sizeof(tAVRC_APP_SETTING);
        if (p_buf && (len == ((p_result->set_app_val.num_val << 1) + 1))) {
            p_result->set_app_val.p_vals = (tAVRC_APP_SETTING *)p_buf;
            p_app_set = p_result->set_app_val.p_vals;
            for (xx = 0; ((xx < p_result->set_app_val.num_val) && (buf_len > size_needed)); xx++) {
                p_app_set[xx].attr_id = *p++;
                p_app_set[xx].attr_val = *p++;
                if (!avrc_is_valid_player_attrib_value(p_app_set[xx].attr_id, p_app_set[xx].attr_val)) {
                    status = AVRC_STS_BAD_PARAM;
                }
            }
            if (xx != p_result->set_app_val.num_val) {
                AVRC_TRACE_ERROR("AVRC_PDU_SET_PLAYER_APP_VALUE not enough room:%d orig num_val:%d",
                                 xx, p_result->set_app_val.num_val);
                p_result->set_app_val.num_val = xx;
            }
        } else {
            AVRC_TRACE_ERROR("AVRC_PDU_SET_PLAYER_APP_VALUE NULL decode buffer or bad len");
            status = AVRC_STS_INTERNAL_ERR;
        }
        break;

    case AVRC_PDU_GET_PLAYER_APP_VALUE_TEXT:/* 0x16 */
        if (len < 3) {
            status = AVRC_STS_INTERNAL_ERR;
        } else {
            BE_STREAM_TO_UINT8 (p_result->get_app_val_txt.attr_id, p);
            if (!AVRC_IS_VALID_ATTRIBUTE(p_result->get_app_val_txt.attr_id)) {
                status = AVRC_STS_BAD_PARAM;
            } else {
                BE_STREAM_TO_UINT8 (p_result->get_app_val_txt.num_val, p);
                if ( (len - 2/* attr_id & num_val */) != p_result->get_app_val_txt.num_val) {
                    status = AVRC_STS_INTERNAL_ERR;
                } else {
                    p_u8 = p_result->get_app_val_txt.vals;
                    for (xx = 0; xx < p_result->get_app_val_txt.num_val; xx++) {
                        p_u8[xx] = *p++;
                        if (!avrc_is_valid_player_attrib_value(p_result->get_app_val_txt.attr_id,
                                                               p_u8[xx])) {
                            status = AVRC_STS_BAD_PARAM;
                            break;
                        }
                    }
                }
            }
        }
        break;

    case AVRC_PDU_INFORM_DISPLAY_CHARSET:  /* 0x17 */
        if (len < 3) {
            status = AVRC_STS_INTERNAL_ERR;
        } else {
            BE_STREAM_TO_UINT8 (p_result->inform_charset.num_id, p);
            if ( (len - 1/* num_id */) != p_result->inform_charset.num_id * 2) {
                status = AVRC_STS_INTERNAL_ERR;
            } else {
                p_u16 = p_result->inform_charset.charsets;
                if (p_result->inform_charset.num_id > AVRC_MAX_CHARSET_SIZE) {
                    p_result->inform_charset.num_id = AVRC_MAX_CHARSET_SIZE;
                }
                for (xx = 0; xx < p_result->inform_charset.num_id; xx++) {
                    BE_STREAM_TO_UINT16 (p_u16[xx], p);
                }
            }
        }
        break;

    case AVRC_PDU_INFORM_BATTERY_STAT_OF_CT:/* 0x18 */
        if (len != 1) {
            status = AVRC_STS_INTERNAL_ERR;
        } else {
            p_result->inform_battery_status.battery_status = *p++;
            if (!AVRC_IS_VALID_BATTERY_STATUS(p_result->inform_battery_status.battery_status)) {
                status = AVRC_STS_BAD_PARAM;
            }
        }
        break;

    case AVRC_PDU_GET_ELEMENT_ATTR:         /* 0x20 */
        if (len < 9) { /* UID/8 and num_attr/1 */
            status = AVRC_STS_INTERNAL_ERR;
        } else {
            BE_STREAM_TO_UINT32 (u32, p);
            BE_STREAM_TO_UINT32 (u32_2, p);
            if (u32 == 0 && u32_2 == 0) {
                BE_STREAM_TO_UINT8 (p_result->get_elem_attrs.num_attr, p);
                if ( (len - 9/* UID/8 and num_attr/1 */) != (p_result->get_elem_attrs.num_attr * 4)) {
                    status = AVRC_STS_INTERNAL_ERR;
                } else {
                    p_u32 = p_result->get_elem_attrs.attrs;
                    if (p_result->get_elem_attrs.num_attr > AVRC_MAX_ELEM_ATTR_SIZE) {
                        p_result->get_elem_attrs.num_attr = AVRC_MAX_ELEM_ATTR_SIZE;
                    }
                    for (xx = 0; xx < p_result->get_elem_attrs.num_attr; xx++) {
                        BE_STREAM_TO_UINT32 (p_u32[xx], p);
                    }
                }
            } else {
                status = AVRC_STS_NOT_FOUND;
            }
        }
        break;

    case AVRC_PDU_GET_PLAY_STATUS:          /* 0x30 */
        /* no additional parameters */
        if (len != 0) {
            status = AVRC_STS_INTERNAL_ERR;
        }
        break;

    case AVRC_PDU_REGISTER_NOTIFICATION:    /* 0x31 */
        if (len != 5) {
            status = AVRC_STS_INTERNAL_ERR;
        } else {
            BE_STREAM_TO_UINT8 (p_result->reg_notif.event_id, p);
            BE_STREAM_TO_UINT32 (p_result->reg_notif.param, p);
        }
        break;

    case AVRC_PDU_SET_ABSOLUTE_VOLUME: {
        if (len != 1) {
            status = AVRC_STS_INTERNAL_ERR;
        }
        break;
    }

    /* case AVRC_PDU_REQUEST_CONTINUATION_RSP: 0x40 */
    /* case AVRC_PDU_ABORT_CONTINUATION_RSP:   0x41 */

    default:
        status = AVRC_STS_BAD_CMD;
        break;
    }

    return status;
}