Esempio n. 1
0
int wpm_encode_apdu_object_property(
    uint8_t * apdu,
    BACNET_WRITE_PROPERTY_DATA * wpdata)
{
    int apdu_len = 0;   /* total length of the apdu, return value */
    int len = 0;

    if (apdu) {
        apdu_len =
            encode_context_enumerated(&apdu[0], 0, wpdata->object_property);
        /* optional array index */
        if (wpdata->array_index != BACNET_ARRAY_ALL) {
            apdu_len +=
                encode_context_unsigned(&apdu[apdu_len], 1,
                wpdata->array_index);
        }
        apdu_len += encode_opening_tag(&apdu[apdu_len], 2);
        for (len = 0; len < wpdata->application_data_len; len++) {
            apdu[apdu_len] = wpdata->application_data[len];
            apdu_len++;
        }
        apdu_len += encode_closing_tag(&apdu[apdu_len], 2);
        if (wpdata->priority != BACNET_NO_PRIORITY) {
            encode_context_unsigned(&apdu[apdu_len], 3, wpdata->priority);
        }
    }

    return apdu_len;
}
Esempio n. 2
0
int wpm_error_ack_encode_apdu(
    uint8_t * apdu,
    uint8_t invoke_id,
    BACNET_WRITE_PROPERTY_DATA * wp_data)
{
    int len = 0;

    if (apdu) {
        apdu[len++] = PDU_TYPE_ERROR;
        apdu[len++] = invoke_id;
        apdu[len++] = SERVICE_CONFIRMED_WRITE_PROP_MULTIPLE;

        len += encode_opening_tag(&apdu[len], 0);
        len += encode_application_enumerated(&apdu[len], wp_data->error_class);
        len += encode_application_enumerated(&apdu[len], wp_data->error_code);
        len += encode_closing_tag(&apdu[len], 0);

        len += encode_opening_tag(&apdu[len], 1);
        len +=
            encode_context_object_id(&apdu[len], 0, wp_data->object_type,
            wp_data->object_instance);
        len +=
            encode_context_enumerated(&apdu[len], 1, wp_data->object_property);

        if (wp_data->array_index != BACNET_ARRAY_ALL)
            len +=
                encode_context_unsigned(&apdu[len], 2, wp_data->array_index);
        len += encode_closing_tag(&apdu[len], 1);
    }
    return len;
}
Esempio n. 3
0
/* encode service */
int rd_encode_apdu(
    uint8_t * apdu,
    uint8_t invoke_id,
    BACNET_REINITIALIZED_STATE state,
    BACNET_CHARACTER_STRING * password)
{
    int len = 0;        /* length of each encoding */
    int apdu_len = 0;   /* total length of the apdu, return value */

    if (apdu) {
        apdu[0] = PDU_TYPE_CONFIRMED_SERVICE_REQUEST;
        apdu[1] = encode_max_segs_max_apdu(0, MAX_APDU);
        apdu[2] = invoke_id;
        apdu[3] = SERVICE_CONFIRMED_REINITIALIZE_DEVICE;
        apdu_len = 4;
        len = encode_context_enumerated(&apdu[apdu_len], 0, state);
        apdu_len += len;
        /* optional password */
        if (password) {
            /* FIXME: must be at least 1 character, limited to 20 characters */
            len =
                encode_context_character_string(&apdu[apdu_len], 1, password);
            apdu_len += len;
        }
    }

    return apdu_len;
}
Esempio n. 4
0
int bacapp_encode_access_rule(
    uint8_t * apdu,
    BACNET_ACCESS_RULE * rule)
{
    int len;
    int apdu_len = 0;

    len = encode_context_enumerated(&apdu[0], 0, rule->time_range_specifier);
    apdu_len += len;

    if (rule->time_range_specifier == TIME_RANGE_SPECIFIER_SPECIFIED) {
        len =
            bacapp_encode_context_device_obj_property_ref(&apdu[apdu_len], 1,
            &rule->time_range);
        if (len > 0)
            apdu_len += len;
        else
            return -1;
    }

    len =
        encode_context_enumerated(&apdu[apdu_len], 2,
        rule->location_specifier);
    apdu_len += len;

    if (rule->location_specifier == LOCATION_SPECIFIER_SPECIFIED) {
        len =
            bacapp_encode_context_device_obj_property_ref(&apdu[apdu_len], 3,
            &rule->location);
        if (len > 0)
            apdu_len += len;
        else
            return -1;
    }

    len = encode_context_boolean(&apdu[apdu_len], 4, rule->enable);
    apdu_len += len;

    return apdu_len;
}
Esempio n. 5
0
/* encode service */
int wp_encode_apdu(
    uint8_t * apdu,
    uint8_t invoke_id,
    BACNET_WRITE_PROPERTY_DATA * wpdata)
{
    int apdu_len = 0;   /* total length of the apdu, return value */
    int len = 0;        /* total length of the apdu, return value */

    if (apdu) {
        apdu[0] = PDU_TYPE_CONFIRMED_SERVICE_REQUEST;
        apdu[1] = encode_max_segs_max_apdu(0, MAX_APDU);
        apdu[2] = invoke_id;
        apdu[3] = SERVICE_CONFIRMED_WRITE_PROPERTY;     /* service choice */
        apdu_len = 4;
        len =
            encode_context_object_id(&apdu[apdu_len], 0, wpdata->object_type,
            wpdata->object_instance);
        apdu_len += len;
        len =
            encode_context_enumerated(&apdu[apdu_len], 1,
            wpdata->object_property);
        apdu_len += len;
        /* optional array index; ALL is -1 which is assumed when missing */
        if (wpdata->array_index != BACNET_ARRAY_ALL) {
            len =
                encode_context_unsigned(&apdu[apdu_len], 2,
                wpdata->array_index);
            apdu_len += len;
        }
        /* propertyValue */
        len = encode_opening_tag(&apdu[apdu_len], 3);
        apdu_len += len;
        for (len = 0; len < wpdata->application_data_len; len++) {
            apdu[apdu_len + len] = wpdata->application_data[len];
        }
        apdu_len += wpdata->application_data_len;
        len = encode_closing_tag(&apdu[apdu_len], 3);
        apdu_len += len;
        /* optional priority - 0 if not set, 1..16 if set */
        if (wpdata->priority != BACNET_NO_PRIORITY) {
            len =
                encode_context_unsigned(&apdu[apdu_len], 4, wpdata->priority);
            apdu_len += len;
        }
    }

    return apdu_len;
}
Esempio n. 6
0
int rpm_encode_apdu_object_property(
    uint8_t * apdu,
    BACNET_PROPERTY_ID object_property,
    uint32_t array_index)
{
    int apdu_len = 0;   /* total length of the apdu, return value */

    if (apdu) {
        apdu_len = encode_context_enumerated(&apdu[0], 0, object_property);
        /* optional array index */
        if (array_index != BACNET_ARRAY_ALL)
            apdu_len +=
                encode_context_unsigned(&apdu[apdu_len], 1, array_index);
    }

    return apdu_len;
}
Esempio n. 7
0
int Lighting_Output_Encode_Lighting_Command(
    uint8_t * apdu,
    BACNET_LIGHTING_COMMAND * data)
{
    int apdu_len = 0;   /* total length of the apdu, return value */
    int len = 0;        /* total length of the apdu, return value */
    float real_value = 0.0;
    uint32_t unsigned_value = 0;

    if (apdu) {
        len = encode_context_enumerated(&apdu[apdu_len], 0, data->operation);
        apdu_len += len;
        /* optional level? */
        if (data->level != 255) {
            real_value = data->level;
            len = encode_context_real(&apdu[apdu_len], 1, real_value);
            apdu_len += len;
        }
        /* optional ramp-rate */
        if (data->ramp_rate != 255) {
            real_value = data->ramp_rate;
            len = encode_context_real(&apdu[apdu_len], 2, real_value);
            apdu_len += len;
        }
        /* optional step increment */
        if (data->step_increment != 255) {
            real_value = data->step_increment;
            len = encode_context_real(&apdu[apdu_len], 3, real_value);
            apdu_len += len;
        }
        /* optional fade time */
        if (data->fade_time != 0) {
            real_value = data->fade_time;
            len = encode_context_real(&apdu[apdu_len], 4, real_value);
            apdu_len += len;
        }
        /* optional duration */
        if (data->duration != 0) {
            unsigned_value = data->duration;
            len = encode_context_unsigned(&apdu[apdu_len], 5, unsigned_value);
            apdu_len += len;
        }
    }

    return apdu_len;
}
Esempio n. 8
0
/**
 * Encodes into bytes from the lighting-command structure
 *
 * @param apdu - buffer to hold the bytes
 * @param value - lighting command value to encode
 *
 * @return  number of bytes encoded, or 0 if unable to encode.
 */
int lighting_command_encode(
    uint8_t * apdu,
    BACNET_LIGHTING_COMMAND * data)
{
    int apdu_len = 0;   /* total length of the apdu, return value */
    int len = 0;        /* total length of the apdu, return value */

    if (apdu) {
        len = encode_context_enumerated(&apdu[apdu_len], 0,
            data->operation);
        apdu_len += len;
        /* optional target-level */
        if (data->use_target_level) {
            len = encode_context_real(&apdu[apdu_len], 1,
                data->target_level);
            apdu_len += len;
        }
        /* optional ramp-rate */
        if (data->use_ramp_rate) {
            len = encode_context_real(&apdu[apdu_len], 2,
                data->ramp_rate);
            apdu_len += len;
        }
        /* optional step increment */
        if (data->use_step_increment) {
            len = encode_context_real(&apdu[apdu_len], 3,
                data->step_increment);
            apdu_len += len;
        }
        /* optional fade time */
        if (data->use_fade_time) {
            len = encode_context_unsigned(&apdu[apdu_len], 4,
                data->fade_time);
            apdu_len += len;
        }
        /* optional priority */
        if (data->use_priority) {
            len = encode_context_unsigned(&apdu[apdu_len], 5,
                data->priority);
            apdu_len += len;
        }
    }

    return apdu_len;
}
Esempio n. 9
0
int rpm_ack_encode_apdu_object_property(
    uint8_t * apdu,
    BACNET_PROPERTY_ID object_property,
    uint32_t array_index)
{
    int apdu_len = 0;   /* total length of the apdu, return value */

    if (apdu) {
        /* Tag 2: propertyIdentifier */
        apdu_len = encode_context_enumerated(&apdu[0], 2, object_property);
        /* Tag 3: optional propertyArrayIndex */
        if (array_index != BACNET_ARRAY_ALL)
            apdu_len +=
                encode_context_unsigned(&apdu[apdu_len], 3, array_index);
    }

    return apdu_len;
}
Esempio n. 10
0
/***************************************************
**
** Encodes the service data part of Event Notification
**
****************************************************/
int alarm_ack_encode_service_request(
    uint8_t * apdu,
    BACNET_ALARM_ACK_DATA * data)
{
    int len = 0;        /* length of each encoding */
    int apdu_len = 0;   /* total length of the apdu, return value */

    if (apdu) {
        len =
            encode_context_unsigned(&apdu[apdu_len], 0,
                                    data->ackProcessIdentifier);
        apdu_len += len;

        len =
            encode_context_object_id(&apdu[apdu_len], 1,
                                     (int) data->eventObjectIdentifier.type,
                                     data->eventObjectIdentifier.instance);
        apdu_len += len;

        len =
            encode_context_enumerated(&apdu[apdu_len], 2,
                                      data->eventStateAcked);
        apdu_len += len;

        len =
            bacapp_encode_context_timestamp(&apdu[apdu_len], 3,
                                            &data->eventTimeStamp);
        apdu_len += len;

        len =
            encode_context_character_string(&apdu[apdu_len], 4,
                                            &data->ackSource);
        apdu_len += len;

        len =
            bacapp_encode_context_timestamp(&apdu[apdu_len], 5,
                                            &data->ackTimeStamp);
        apdu_len += len;
    }

    return apdu_len;
}
Esempio n. 11
0
/* encode service */
int rp_encode_apdu(
    uint8_t * apdu,
    uint8_t invoke_id,
    BACNET_READ_PROPERTY_DATA * rpdata)
{
    int len = 0;        /* length of each encoding */
    int apdu_len = 0;   /* total length of the apdu, return value */

    if (apdu) {
        apdu[0] = PDU_TYPE_CONFIRMED_SERVICE_REQUEST;
        apdu[1] = encode_max_segs_max_apdu(0, MAX_APDU);
        apdu[2] = invoke_id;
        apdu[3] = SERVICE_CONFIRMED_READ_PROPERTY;      /* service choice */
        apdu_len = 4;
        if (rpdata->object_type <= BACNET_MAX_OBJECT) {
            /* check bounds so that we could create malformed
               messages for testing */
            len =
                encode_context_object_id(&apdu[apdu_len], 0,
                rpdata->object_type, rpdata->object_instance);
            apdu_len += len;
        }
        if (rpdata->object_property <= 4194303) {
            /* check bounds so that we could create malformed
               messages for testing */
            len =
                encode_context_enumerated(&apdu[apdu_len], 1,
                rpdata->object_property);
            apdu_len += len;
        }
        /* optional array index */
        if (rpdata->array_index != BACNET_ARRAY_ALL) {
            len =
                encode_context_unsigned(&apdu[apdu_len], 2,
                rpdata->array_index);
            apdu_len += len;
        }
    }

    return apdu_len;
}
int lso_encode_apdu(
    uint8_t * apdu,
    uint8_t invoke_id,
    BACNET_LSO_DATA * data)
{
    int len = 0;        /* length of each encoding */
    int apdu_len = 0;   /* total length of the apdu, return value */

    if (apdu && data) {
        apdu[0] = PDU_TYPE_CONFIRMED_SERVICE_REQUEST;
        apdu[1] = encode_max_segs_max_apdu(0, MAX_APDU);
        apdu[2] = invoke_id;
        apdu[3] = SERVICE_CONFIRMED_LIFE_SAFETY_OPERATION;
        apdu_len = 4;
        /* tag 0 - requestingProcessId */
        len = encode_context_unsigned(&apdu[apdu_len], 0, data->processId);
        apdu_len += len;
        /* tag 1 - requestingSource */
        len =
            encode_context_character_string(&apdu[apdu_len], 1,
            &data->requestingSrc);
        apdu_len += len;
        /*
           Operation
         */
        len = encode_context_enumerated(&apdu[apdu_len], 2, data->operation);
        apdu_len += len;
        /*
           Object ID
         */

        len =
            encode_context_object_id(&apdu[apdu_len], 3,
            (int) data->targetObject.type, data->targetObject.instance);

        apdu_len += len;
    }

    return apdu_len;
}
Esempio n. 13
0
/* alternate method to encode the ack without extra buffer */
int rp_ack_encode_apdu_init(
    uint8_t * apdu,
    uint8_t invoke_id,
    BACNET_READ_PROPERTY_DATA * rpdata)
{
    int len = 0;        /* length of each encoding */
    int apdu_len = 0;   /* total length of the apdu, return value */

    if (apdu) {
        apdu[0] = PDU_TYPE_COMPLEX_ACK; /* complex ACK service */
        apdu[1] = invoke_id;    /* original invoke id from request */
        apdu[2] = SERVICE_CONFIRMED_READ_PROPERTY;      /* service choice */
        apdu_len = 3;

        /* service ack follows */
        len =
            encode_context_object_id(&apdu[apdu_len], 0, rpdata->object_type,
            rpdata->object_instance);
        apdu_len += len;
        len =
            encode_context_enumerated(&apdu[apdu_len], 1,
            rpdata->object_property);
        apdu_len += len;
        /* context 2 array index is optional */
        if (rpdata->array_index != BACNET_ARRAY_ALL) {
            len =
                encode_context_unsigned(&apdu[apdu_len], 2,
                rpdata->array_index);
            apdu_len += len;
        }
        len = encode_opening_tag(&apdu[apdu_len], 3);
        apdu_len += len;
    }

    return apdu_len;
}
Esempio n. 14
0
int bacapp_encode_device_obj_property_ref(
    uint8_t * apdu,
    BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE * value)
{
    int len;
    int apdu_len = 0;

    len =
        encode_context_object_id(&apdu[apdu_len], 0,
        (int) value->objectIdentifier.type, value->objectIdentifier.instance);
    apdu_len += len;

    len =
        encode_context_enumerated(&apdu[apdu_len], 1,
        value->propertyIdentifier);
    apdu_len += len;

    /* Array index is optional so check if needed before inserting */
    if (value->arrayIndex != BACNET_ARRAY_ALL) {
        len = encode_context_unsigned(&apdu[apdu_len], 2, value->arrayIndex);
        apdu_len += len;
    }

    /* Likewise, device id is optional so see if needed
     * (set type to BACNET_NO_DEV_TYPE or something other than OBJECT_DEVICE to
	 * omit */

    if (value->deviceIndentifier.type == OBJECT_DEVICE) {
        len =
            encode_context_object_id(&apdu[apdu_len], 3,
            (int) value->deviceIndentifier.type,
            value->deviceIndentifier.instance);
        apdu_len += len;
    }
    return apdu_len;
}
Esempio n. 15
0
/** Encode an RPM request, to be sent.
 *
 * @param apdu [in,out] Buffer to hold encoded bytes.
 * @param max_apdu [in] Length of apdu buffer.
 * @param invoke_id [in] The Invoke ID to use for this message.
 * @param read_access_data [in] The RPM data to be requested.
 * @return Length of encoded bytes, or 0 on failure.
 */
int rpm_encode_apdu(
    uint8_t * apdu,
    size_t max_apdu,
    uint8_t invoke_id,
    BACNET_READ_ACCESS_DATA * read_access_data)
{
    int apdu_len = 0;   /* total length of the apdu, return value */
    int len = 0;        /* length of the data */
    BACNET_READ_ACCESS_DATA *rpm_object;        /* current object */
    uint8_t apdu_temp[16];      /* temp for data before copy */
    BACNET_PROPERTY_REFERENCE *rpm_property;    /* current property */

    len = rpm_encode_apdu_init(&apdu_temp[0], invoke_id);
    len =
        (int) memcopy(&apdu[0], &apdu_temp[0], (size_t) apdu_len, (size_t) len,
        (size_t) max_apdu);
    if (len == 0) {
        return 0;
    }
    apdu_len += len;
    rpm_object = read_access_data;
    while (rpm_object) {
        len =
            encode_context_object_id(&apdu_temp[0], 0, rpm_object->object_type,
            rpm_object->object_instance);
        len =
            (int) memcopy(&apdu[0], &apdu_temp[0], (size_t) apdu_len,
            (size_t) len, (size_t) max_apdu);
        if (len == 0) {
            return 0;
        }
        apdu_len += len;
        /* Tag 1: sequence of ReadAccessSpecification */
        len = encode_opening_tag(&apdu_temp[0], 1);
        len =
            (int) memcopy(&apdu[0], &apdu_temp[0], (size_t) apdu_len,
            (size_t) len, (size_t) max_apdu);
        if (len == 0) {
            return 0;
        }
        apdu_len += len;
        rpm_property = rpm_object->listOfProperties;
        while (rpm_property) {
            /* stuff as many properties into it as APDU length will allow */
            len =
                encode_context_enumerated(&apdu_temp[0], 0,
                rpm_property->propertyIdentifier);
            len =
                (int) memcopy(&apdu[0], &apdu_temp[0], (size_t) apdu_len,
                (size_t) len, (size_t) max_apdu);
            if (len == 0) {
                return 0;
            }
            apdu_len += len;
            /* optional array index */
            if (rpm_property->propertyArrayIndex != BACNET_ARRAY_ALL) {
                len =
                    encode_context_unsigned(&apdu_temp[0], 1,
                    rpm_property->propertyArrayIndex);
                len =
                    (int) memcopy(&apdu[0], &apdu_temp[0], (size_t) apdu_len,
                    (size_t) len, (size_t) max_apdu);
                if (len == 0) {
                    return 0;
                }
                apdu_len += len;
            }
            rpm_property = rpm_property->next;
        }
        len = encode_closing_tag(&apdu_temp[0], 1);
        len =
            (int) memcopy(&apdu[0], &apdu_temp[0], (size_t) apdu_len,
            (size_t) len, (size_t) max_apdu);
        if (len == 0) {
            return 0;
        }
        apdu_len += len;
        rpm_object = rpm_object->next;
    }

    return apdu_len;
}
Esempio n. 16
0
int bacapp_encode_property_state(
    uint8_t * apdu,
    BACNET_PROPERTY_STATE * value)
{
    int len = 0;        /* length of each encoding */
    if (value && apdu) {
        switch (value->tag) {
            case BOOLEAN_VALUE:
                len =
                    encode_context_boolean(&apdu[0], 0,
                    value->state.booleanValue);
                break;

            case BINARY_VALUE:
                len =
                    encode_context_enumerated(&apdu[0], 1,
                    value->state.binaryValue);
                break;

            case EVENT_TYPE:
                len =
                    encode_context_enumerated(&apdu[0], 2,
                    value->state.eventType);
                break;

            case POLARITY:
                len =
                    encode_context_enumerated(&apdu[0], 3,
                    value->state.polarity);
                break;

            case PROGRAM_CHANGE:
                len =
                    encode_context_enumerated(&apdu[0], 4,
                    value->state.programChange);
                break;

            case PROGRAM_STATE:
                len =
                    encode_context_enumerated(&apdu[0], 5,
                    value->state.programState);
                break;

            case REASON_FOR_HALT:
                len =
                    encode_context_enumerated(&apdu[0], 6,
                    value->state.programError);
                break;

            case RELIABILITY:
                len =
                    encode_context_enumerated(&apdu[0], 7,
                    value->state.reliability);
                break;

            case STATE:
                len =
                    encode_context_enumerated(&apdu[0], 8, value->state.state);
                break;

            case SYSTEM_STATUS:
                len =
                    encode_context_enumerated(&apdu[0], 9,
                    value->state.systemStatus);
                break;

            case UNITS:
                len =
                    encode_context_enumerated(&apdu[0], 10,
                    value->state.units);
                break;

            case UNSIGNED_VALUE:
                len =
                    encode_context_unsigned(&apdu[0], 11,
                    value->state.unsignedValue);
                break;

            case LIFE_SAFETY_MODE:
                len =
                    encode_context_enumerated(&apdu[0], 12,
                    value->state.lifeSafetyMode);
                break;

            case LIFE_SAFETY_STATE:
                len =
                    encode_context_enumerated(&apdu[0], 13,
                    value->state.lifeSafetyState);
                break;

            default:
                assert(0);
                break;
        }
    }
    return len;
}
Esempio n. 17
0
static int cov_encode_subscription(
    uint8_t * apdu,
    int max_apdu,
    BACNET_COV_SUBSCRIPTION * cov_subscription)
{
    int len = 0;
    int apdu_len = 0;
    BACNET_OCTET_STRING octet_string;

    /* FIXME: unused parameter */
    max_apdu = max_apdu;
    /* Recipient [0] BACnetRecipientProcess - opening */
    len = encode_opening_tag(&apdu[apdu_len], 0);
    apdu_len += len;
    /*  recipient [0] BACnetRecipient - opening */
    len = encode_opening_tag(&apdu[apdu_len], 0);
    apdu_len += len;
    /* CHOICE - address [1] BACnetAddress - opening */
    len = encode_opening_tag(&apdu[apdu_len], 1);
    apdu_len += len;
    /* network-number Unsigned16, */
    /* -- A value of 0 indicates the local network */
    len =
        encode_application_unsigned(&apdu[apdu_len],
        cov_subscription->dest.net);
    apdu_len += len;
    /* mac-address OCTET STRING */
    /* -- A string of length 0 indicates a broadcast */
    if (cov_subscription->dest.net) {
        octetstring_init(&octet_string, &cov_subscription->dest.adr[0],
            cov_subscription->dest.len);
    } else {
        octetstring_init(&octet_string, &cov_subscription->dest.mac[0],
            cov_subscription->dest.mac_len);
    }
    len = encode_application_octet_string(&apdu[apdu_len], &octet_string);
    apdu_len += len;
    /* CHOICE - address [1] BACnetAddress - closing */
    len = encode_closing_tag(&apdu[apdu_len], 1);
    apdu_len += len;
    /*  recipient [0] BACnetRecipient - closing */
    len = encode_closing_tag(&apdu[apdu_len], 0);
    apdu_len += len;
    /* processIdentifier [1] Unsigned32 */
    len =
        encode_context_unsigned(&apdu[apdu_len], 1,
        cov_subscription->subscriberProcessIdentifier);
    apdu_len += len;
    /* Recipient [0] BACnetRecipientProcess - closing */
    len = encode_closing_tag(&apdu[apdu_len], 0);
    apdu_len += len;
    /*  MonitoredPropertyReference [1] BACnetObjectPropertyReference, */
    len = encode_opening_tag(&apdu[apdu_len], 1);
    apdu_len += len;
    /* objectIdentifier [0] */
    len =
        encode_context_object_id(&apdu[apdu_len], 0,
        cov_subscription->monitoredObjectIdentifier.type,
        cov_subscription->monitoredObjectIdentifier.instance);
    apdu_len += len;
    /* propertyIdentifier [1] */
    /* FIXME: we are monitoring 2 properties! How to encode? */
    len = encode_context_enumerated(&apdu[apdu_len], 1, PROP_PRESENT_VALUE);
    apdu_len += len;
    /* MonitoredPropertyReference [1] - closing */
    len = encode_closing_tag(&apdu[apdu_len], 1);
    apdu_len += len;
    /* IssueConfirmedNotifications [2] BOOLEAN, */
    len =
        encode_context_boolean(&apdu[apdu_len], 2,
        cov_subscription->flag.issueConfirmedNotifications);
    apdu_len += len;
    /* TimeRemaining [3] Unsigned, */
    len =
        encode_context_unsigned(&apdu[apdu_len], 3,
        cov_subscription->lifetime);
    apdu_len += len;

    return apdu_len;
}