/** Encode the RPM property returning the length of the encoding,
   or 0 if there is no room to fit the encoding.  */
static int RPM_Encode_Property(
    uint8_t * apdu,
    uint16_t offset,
    uint16_t max_apdu,
    BACNET_RPM_DATA * rpmdata)
{
    int len = 0;
    size_t copy_len = 0;
    int apdu_len = 0;
    BACNET_READ_PROPERTY_DATA rpdata;

    len =
        rpm_ack_encode_apdu_object_property(&Temp_Buf[0],
                                            rpmdata->object_property, rpmdata->array_index);
    copy_len = memcopy(&apdu[0], &Temp_Buf[0], offset, len, max_apdu);
    if (copy_len == 0) {
        rpmdata->error_code = ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
        return BACNET_STATUS_ABORT;
    }
    apdu_len += len;
    len = 0;
    rpdata.error_class = ERROR_CLASS_OBJECT;
    rpdata.error_code = ERROR_CODE_UNKNOWN_OBJECT;
    rpdata.object_type = rpmdata->object_type;
    rpdata.object_instance = rpmdata->object_instance;
    rpdata.object_property = rpmdata->object_property;
    rpdata.array_index = rpmdata->array_index;
    rpdata.application_data = &Temp_Buf[0];
    rpdata.application_data_len = sizeof(Temp_Buf);
    len = Device_Read_Property(&rpdata);
    if (len < 0) {
        if ((len == BACNET_STATUS_ABORT) || (len == BACNET_STATUS_REJECT)) {
            rpmdata->error_code = rpdata.error_code;
            /* pass along aborts and rejects for now */
            return len; /* Ie, Abort */
        }
        /* error was returned - encode that for the response */
        len =
            rpm_ack_encode_apdu_object_property_error(&Temp_Buf[0],
                    rpdata.error_class, rpdata.error_code);
        copy_len =
            memcopy(&apdu[0], &Temp_Buf[0], offset + apdu_len, len, max_apdu);

        if (copy_len == 0) {
            rpmdata->error_code = ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
            return BACNET_STATUS_ABORT;
        }
    } else if ((offset + apdu_len + 1 + len + 1) < max_apdu) {
        /* enough room to fit the property value and tags */
        len =
            rpm_ack_encode_apdu_object_property_value(&apdu[offset + apdu_len],
                    &Temp_Buf[0], len);
    } else {
        /* not enough room - abort! */
        rpmdata->error_code = ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
        return BACNET_STATUS_ABORT;
    }
    apdu_len += len;

    return apdu_len;
}
Пример #2
0
void testReadPropertyMultipleAck(
    Test * pTest)
{
    uint8_t apdu[480] = { 0 };
    int len = 0;
    int test_len = 0;
    int apdu_len = 0;
    uint8_t invoke_id = 12;
    uint8_t test_invoke_id = 0;
    uint8_t *service_request = NULL;
    unsigned service_request_len = 0;
    BACNET_OBJECT_TYPE object_type = OBJECT_DEVICE;
    uint32_t object_instance = 0;
    BACNET_PROPERTY_ID object_property = PROP_OBJECT_IDENTIFIER;
    uint32_t array_index = 0;
    BACNET_APPLICATION_DATA_VALUE application_data[4] = { {0} };
    BACNET_APPLICATION_DATA_VALUE test_application_data = { 0 };
    uint8_t application_data_buffer[MAX_APDU] = { 0 };
    int application_data_buffer_len = 0;
    BACNET_ERROR_CLASS error_class;
    BACNET_ERROR_CODE error_code;
    BACNET_RPM_DATA rpmdata;

    /* build the RPM - try to make it easy for the
       Application Layer development */
    /* IDEA: similar construction, but pass apdu, apdu_len pointer,
       size of apdu to let the called function handle the out of
       space problem that these get into  by returning a boolean
       of success/failure.
       It almost needs to use the keylist library or something similar.
       Also check case of storing a backoff point
       (i.e. save enough room for object_end) */
    apdu_len = rpm_ack_encode_apdu_init(&apdu[0], invoke_id);
    /* object beginning */
    rpmdata.object_type = OBJECT_DEVICE;
    rpmdata.object_instance = 123;
    apdu_len += rpm_ack_encode_apdu_object_begin(&apdu[apdu_len], &rpmdata);
    /* reply property */
    apdu_len +=
        rpm_ack_encode_apdu_object_property(&apdu[apdu_len],
        PROP_OBJECT_IDENTIFIER, BACNET_ARRAY_ALL);
    /* reply value */
    application_data[0].tag = BACNET_APPLICATION_TAG_OBJECT_ID;
    application_data[0].type.Object_Id.type = OBJECT_DEVICE;
    application_data[0].type.Object_Id.instance = 123;
    application_data_buffer_len =
        bacapp_encode_application_data(&application_data_buffer[0],
        &application_data[0]);
    apdu_len +=
        rpm_ack_encode_apdu_object_property_value(&apdu[apdu_len],
        &application_data_buffer[0], application_data_buffer_len);
    /* reply property */
    apdu_len +=
        rpm_ack_encode_apdu_object_property(&apdu[apdu_len], PROP_OBJECT_TYPE,
        BACNET_ARRAY_ALL);
    /* reply value */
    application_data[1].tag = BACNET_APPLICATION_TAG_ENUMERATED;
    application_data[1].type.Enumerated = OBJECT_DEVICE;
    application_data_buffer_len =
        bacapp_encode_application_data(&application_data_buffer[0],
        &application_data[1]);
    apdu_len +=
        rpm_ack_encode_apdu_object_property_value(&apdu[apdu_len],
        &application_data_buffer[0], application_data_buffer_len);
    /* object end */
    apdu_len += rpm_ack_encode_apdu_object_end(&apdu[apdu_len]);

    /* object beginning */
    rpmdata.object_type = OBJECT_ANALOG_INPUT;
    rpmdata.object_instance = 33;
    apdu_len += rpm_ack_encode_apdu_object_begin(&apdu[apdu_len], &rpmdata);
    /* reply property */
    apdu_len +=
        rpm_ack_encode_apdu_object_property(&apdu[apdu_len],
        PROP_PRESENT_VALUE, BACNET_ARRAY_ALL);
    /* reply value */
    application_data[2].tag = BACNET_APPLICATION_TAG_REAL;
    application_data[2].type.Real = 0.0;
    application_data_buffer_len =
        bacapp_encode_application_data(&application_data_buffer[0],
        &application_data[2]);
    apdu_len +=
        rpm_ack_encode_apdu_object_property_value(&apdu[apdu_len],
        &application_data_buffer[0], application_data_buffer_len);
    /* reply property */
    apdu_len +=
        rpm_ack_encode_apdu_object_property(&apdu[apdu_len], PROP_DEADBAND,
        BACNET_ARRAY_ALL);
    /* reply error */
    apdu_len +=
        rpm_ack_encode_apdu_object_property_error(&apdu[apdu_len],
        ERROR_CLASS_PROPERTY, ERROR_CODE_UNKNOWN_PROPERTY);
    /* object end */
    apdu_len += rpm_ack_encode_apdu_object_end(&apdu[apdu_len]);
    ct_test(pTest, apdu_len != 0);

  /****** decode the packet ******/
    test_len = rpm_ack_decode_apdu(&apdu[0], apdu_len, &test_invoke_id, &service_request,       /* will point to the service request in the apdu */
        &service_request_len);
    ct_test(pTest, test_len != -1);
    ct_test(pTest, test_invoke_id == invoke_id);
    ct_test(pTest, service_request != NULL);
    ct_test(pTest, service_request_len > 0);
    /* the first part should be the first object id */
    test_len =
        rpm_ack_decode_object_id(service_request, service_request_len,
        &object_type, &object_instance);
    ct_test(pTest, test_len != -1);
    ct_test(pTest, object_type == OBJECT_DEVICE);
    ct_test(pTest, object_instance == 123);
    len = test_len;
    /* extract the property */
    test_len =
        rpm_ack_decode_object_property(&service_request[len],
        service_request_len - len, &object_property, &array_index);
    ct_test(pTest, object_property == PROP_OBJECT_IDENTIFIER);
    ct_test(pTest, array_index == BACNET_ARRAY_ALL);
    len += test_len;
    /* what is the result? An error or a value? */
    ct_test(pTest, decode_is_opening_tag_number(&service_request[len], 4));
    len++;
    /* decode the object property portion of the service request */
    /* note: if this was an array, there could have been
       more than one element to decode */
    test_len =
        bacapp_decode_application_data(&service_request[len],
        service_request_len - len, &test_application_data);
    ct_test(pTest, test_len > 0);
    ct_test(pTest, bacapp_same_value(&application_data[0],
            &test_application_data));
    len += test_len;
    ct_test(pTest, decode_is_closing_tag_number(&service_request[len], 4));
    len++;
    /* see if there is another property */
    test_len =
        rpm_ack_decode_object_property(&service_request[len],
        service_request_len - len, &object_property, &array_index);
    ct_test(pTest, test_len != -1);
    ct_test(pTest, object_property == PROP_OBJECT_TYPE);
    ct_test(pTest, array_index == BACNET_ARRAY_ALL);
    len += test_len;
    /* what is the result value? */
    ct_test(pTest, decode_is_opening_tag_number(&service_request[len], 4));
    len++;
    /* decode the object property portion of the service request */
    test_len =
        bacapp_decode_application_data(&service_request[len],
        service_request_len - len, &test_application_data);
    ct_test(pTest, test_len > 0);
    ct_test(pTest, bacapp_same_value(&application_data[1],
            &test_application_data));
    len += test_len;
    ct_test(pTest, decode_is_closing_tag_number(&service_request[len], 4));
    len++;
    /* see if there is another property */
    /* this time we should fail */
    test_len =
        rpm_ack_decode_object_property(&service_request[len],
        service_request_len - len, &object_property, &array_index);
    ct_test(pTest, test_len == -1);
    /* see if it is the end of this object */
    test_len =
        rpm_ack_decode_object_end(&service_request[len],
        service_request_len - len);
    ct_test(pTest, test_len == 1);
    len += test_len;
    /* try to decode another object id */
    test_len =
        rpm_ack_decode_object_id(&service_request[len],
        service_request_len - len, &object_type, &object_instance);
    ct_test(pTest, test_len != -1);
    ct_test(pTest, object_type == OBJECT_ANALOG_INPUT);
    ct_test(pTest, object_instance == 33);
    len += test_len;
    /* decode the object property portion of the service request only */
    test_len =
        rpm_ack_decode_object_property(&service_request[len],
        service_request_len - len, &object_property, &array_index);
    ct_test(pTest, test_len != -1);
    ct_test(pTest, object_property == PROP_PRESENT_VALUE);
    ct_test(pTest, array_index == BACNET_ARRAY_ALL);
    len += test_len;
    /* what is the result value? */
    ct_test(pTest, decode_is_opening_tag_number(&service_request[len], 4));
    len++;
    /* decode the object property portion of the service request */
    test_len =
        bacapp_decode_application_data(&service_request[len],
        service_request_len - len, &test_application_data);
    ct_test(pTest, test_len > 0);
    ct_test(pTest, bacapp_same_value(&application_data[2],
            &test_application_data));
    len += test_len;
    ct_test(pTest, decode_is_closing_tag_number(&service_request[len], 4));
    len++;
    /* see if there is another property */
    test_len =
        rpm_ack_decode_object_property(&service_request[len],
        service_request_len - len, &object_property, &array_index);
    ct_test(pTest, test_len != -1);
    ct_test(pTest, object_property == PROP_DEADBAND);
    ct_test(pTest, array_index == BACNET_ARRAY_ALL);
    len += test_len;
    /* what is the result value? */
    ct_test(pTest, decode_is_opening_tag_number(&service_request[len], 5));
    len++;
    /* it was an error reply */
    test_len =
        bacerror_decode_error_class_and_code(&service_request[len],
        service_request_len - len, &error_class, &error_code);
    ct_test(pTest, test_len != 0);
    ct_test(pTest, error_class == ERROR_CLASS_PROPERTY);
    ct_test(pTest, error_code == ERROR_CODE_UNKNOWN_PROPERTY);
    len += test_len;
    ct_test(pTest, decode_is_closing_tag_number(&service_request[len], 5));
    len++;
    /* is there another property? */
    test_len =
        rpm_ack_decode_object_property(&service_request[len],
        service_request_len - len, &object_property, &array_index);
    ct_test(pTest, test_len == -1);
    /* got an error -1, is it the end of this object? */
    test_len =
        rpm_ack_decode_object_end(&service_request[len],
        service_request_len - len);
    ct_test(pTest, test_len == 1);
    len += test_len;
    /* check for another object */
    test_len =
        rpm_ack_decode_object_id(&service_request[len],
        service_request_len - len, &object_type, &object_instance);
    ct_test(pTest, test_len == 0);
    ct_test(pTest, len == service_request_len);
}