bool Routed_Device_Write_Property_Local( BACNET_WRITE_PROPERTY_DATA * wp_data) { bool status = false; /* return value */ int len = 0; BACNET_APPLICATION_DATA_VALUE value; /* decode the some of the request */ len = bacapp_decode_application_data(wp_data->application_data, wp_data->application_data_len, &value); if (len < 0) { /* error while decoding - a value larger than we can handle */ wp_data->error_class = ERROR_CLASS_PROPERTY; wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; return false; } /* only array properties can have array options */ if ((wp_data->object_property != PROP_OBJECT_LIST) && (wp_data->array_index != BACNET_ARRAY_ALL)) { wp_data->error_class = ERROR_CLASS_PROPERTY; wp_data->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY; return false; } /* FIXME: len < application_data_len: more data? */ switch (wp_data->object_property) { case PROP_OBJECT_IDENTIFIER: status = WPValidateArgType(&value, BACNET_APPLICATION_TAG_OBJECT_ID, &wp_data->error_class, &wp_data->error_code); if (status) { if ((value.type.Object_Id.type == OBJECT_DEVICE) && (Routed_Device_Set_Object_Instance_Number(value.type. Object_Id.instance))) { /* FIXME: we could send an I-Am broadcast to let the world know */ } else { status = false; wp_data->error_class = ERROR_CLASS_PROPERTY; wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; } } break; case PROP_OBJECT_NAME: status = WPValidateString(&value, MAX_DEV_NAME_LEN, false, &wp_data->error_class, &wp_data->error_code); if (status) { Routed_Device_Set_Object_Name(characterstring_encoding(&value. type.Character_String), characterstring_value(&value.type.Character_String), characterstring_length(&value.type.Character_String)); } break; default: status = Device_Write_Property_Local(wp_data); break; } return status; }
bool bacnet_name_set(uint16_t offset, BACNET_CHARACTER_STRING * char_string) { uint8_t encoding = 0; uint8_t length = 0; char *str = NULL; length = characterstring_length(char_string); encoding = characterstring_encoding(char_string); str = characterstring_value(char_string); return bacnet_name_save(offset, encoding, str, length); }
void handler_who_has( uint8_t * service_request, uint16_t service_len, BACNET_ADDRESS * src) { int len = 0; BACNET_WHO_HAS_DATA data; bool directed_to_me = false; int object_type = 0; uint32_t object_instance = 0; char *object_name = NULL; bool found = false; (void) src; len = whohas_decode_service_request(service_request, service_len, &data); if (len > 0) { if ((data.low_limit == -1) || (data.high_limit == -1)) directed_to_me = true; else if ((Device_Object_Instance_Number() >= (uint32_t) data.low_limit) && (Device_Object_Instance_Number() <= (uint32_t) data.high_limit)) directed_to_me = true; if (directed_to_me) { /* do we have such an object? If so, send an I-Have. note: we should have only 1 of such an object */ if (data.object_name) { /* valid name in my device? */ object_name = characterstring_value(&data.object.name); found = Device_Valid_Object_Name(object_name, &object_type, &object_instance); if (found) Send_I_Have(Device_Object_Instance_Number(), object_type, object_instance, object_name); } else { /* valid object in my device? */ object_name = Device_Valid_Object_Id(data.object.identifier.type, data.object.identifier.instance); if (object_name) Send_I_Have(Device_Object_Instance_Number(), data.object.identifier.type, data.object.identifier.instance, object_name); } } } return; }
/** Handler for a Reinitialize Device (RD) request. * @ingroup DMRD * This handler will be invoked by apdu_handler() if it has been enabled * by a call to apdu_set_confirmed_handler(). * This handler builds a response packet, which is * - an Abort if * - the message is segmented * - if decoding fails * - an Error if * - the RD password is incorrect * - the Reinitialize Device operation fails * - a Reject if the request state is invalid * - else tries to send a simple ACK for the RD on success. * * @param service_request [in] The contents of the service request. * @param service_len [in] The length of the service_request. * @param src [in] BACNET_ADDRESS of the source of the message * @param service_data [in] The BACNET_CONFIRMED_SERVICE_DATA information * decoded from the APDU header of this message. */ void handler_reinitialize_device( uint8_t * service_request, uint16_t service_len, BACNET_ADDRESS * src, BACNET_CONFIRMED_SERVICE_DATA * service_data) { BACNET_REINITIALIZE_DEVICE_DATA rd_data; int len = 0; int pdu_len = 0; BACNET_NPDU_DATA npdu_data; BACNET_ADDRESS my_address; /* encode the NPDU portion of the packet */ datalink_get_my_address(&my_address); npdu_encode_npdu_data(&npdu_data, false, MESSAGE_PRIORITY_NORMAL); pdu_len = npdu_encode_pdu(&Handler_Transmit_Buffer[0], src, &my_address, &npdu_data); #if PRINT_ENABLED fprintf(stderr, "ReinitializeDevice!\n"); #endif if (service_data->segmented_message) { len = abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id, ABORT_REASON_SEGMENTATION_NOT_SUPPORTED, true); #if PRINT_ENABLED fprintf(stderr, "ReinitializeDevice: Sending Abort - segmented message.\n"); #endif goto RD_ABORT; } /* decode the service request only */ len = rd_decode_service_request(service_request, service_len, &rd_data.state, &rd_data.password); #if PRINT_ENABLED if (len > 0) { fprintf(stderr, "ReinitializeDevice: state=%u password=%s\n", (unsigned) rd_data.state, characterstring_value(&rd_data.password)); } else { fprintf(stderr, "ReinitializeDevice: Unable to decode request!\n"); } #endif /* bad decoding or something we didn't understand - send an abort */ if (len < 0) { len = abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id, ABORT_REASON_OTHER, true); #if PRINT_ENABLED fprintf(stderr, "ReinitializeDevice: Sending Abort - could not decode.\n"); #endif goto RD_ABORT; } /* check the data from the request */ if (rd_data.state >= MAX_BACNET_REINITIALIZED_STATE) { len = reject_encode_apdu(&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id, REJECT_REASON_UNDEFINED_ENUMERATION); #if PRINT_ENABLED fprintf(stderr, "ReinitializeDevice: Sending Reject - undefined enumeration\n"); #endif } else { #if BAC_ROUTING /* Check to see if the current Device supports this service. */ len = Routed_Device_Service_Approval (SERVICE_CONFIRMED_REINITIALIZE_DEVICE, (int) rd_data.state, &Handler_Transmit_Buffer[pdu_len], service_data->invoke_id); if (len > 0) goto RD_ABORT; #endif if (Device_Reinitialize(&rd_data)) { len = encode_simple_ack(&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id, SERVICE_CONFIRMED_REINITIALIZE_DEVICE); #if PRINT_ENABLED fprintf(stderr, "ReinitializeDevice: Sending Simple Ack!\n"); #endif } else { len = bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id, SERVICE_CONFIRMED_REINITIALIZE_DEVICE, rd_data.error_class, rd_data.error_code); #if PRINT_ENABLED fprintf(stderr, "ReinitializeDevice: Sending Error.\n"); #endif } } RD_ABORT: pdu_len += len; len = datalink_send_pdu(src, &npdu_data, &Handler_Transmit_Buffer[0], pdu_len); if (len <= 0) { #if PRINT_ENABLED fprintf(stderr, "ReinitializeDevice: Failed to send PDU (%s)!\n", strerror(errno)); #endif } return; }
void DecodeBlock( char cBlockNum, uint8_t * pData) { int iLen; uint32_t ulTemp; int tag_len; uint8_t tag_number; uint32_t len_value_type; BACNET_CHARACTER_STRING bsName; DATABLOCK Response; iLen = 0; if (cBlockNum >= MY_MAX_BLOCK) return; tag_len = decode_tag_number_and_value(&pData[iLen], &tag_number, &len_value_type); iLen += tag_len; if (tag_number != BACNET_APPLICATION_TAG_UNSIGNED_INT) return; iLen += decode_unsigned(&pData[iLen], len_value_type, &ulTemp); Response.cMyByte1 = (char) ulTemp; tag_len = decode_tag_number_and_value(&pData[iLen], &tag_number, &len_value_type); iLen += tag_len; if (tag_number != BACNET_APPLICATION_TAG_UNSIGNED_INT) return; iLen += decode_unsigned(&pData[iLen], len_value_type, &ulTemp); Response.cMyByte2 = (char) ulTemp; tag_len = decode_tag_number_and_value(&pData[iLen], &tag_number, &len_value_type); iLen += tag_len; if (tag_number != BACNET_APPLICATION_TAG_REAL) return; iLen += decode_real(&pData[iLen], &Response.fMyReal); tag_len = decode_tag_number_and_value(&pData[iLen], &tag_number, &len_value_type); iLen += tag_len; if (tag_number != BACNET_APPLICATION_TAG_CHARACTER_STRING) return; iLen += decode_character_string(&pData[iLen], len_value_type, &bsName); strncpy(Response.sMyString, characterstring_value(&bsName), MY_MAX_STR); Response.sMyString[MY_MAX_STR] = '\0'; /* Make sure it is nul terminated */ printf("Private Transfer Read Block Response\n"); printf("Data Block: %d\n", (int) cBlockNum); printf(" First Byte : %d\n", (int) Response.cMyByte1); printf(" Second Byte : %d\n", (int) Response.cMyByte2); printf(" Real : %f\n", Response.fMyReal); printf(" String : %s\n\n", Response.sMyString); }
static void ProcessPT( BACNET_PRIVATE_TRANSFER_DATA * data) { int iLen; /* Index to current location in data */ char cBlockNumber; uint32_t ulTemp; int tag_len; uint8_t tag_number; uint32_t len_value_type; BACNET_CHARACTER_STRING bsTemp; iLen = 0; /* Decode the block number */ tag_len = decode_tag_number_and_value(&data->serviceParameters[iLen], &tag_number, &len_value_type); iLen += tag_len; if (tag_number != BACNET_APPLICATION_TAG_UNSIGNED_INT) { /* Bail out early if wrong type */ /* and signal unexpected error */ data->serviceParametersLen = 0; return; } iLen += decode_unsigned(&data->serviceParameters[iLen], len_value_type, &ulTemp); cBlockNumber = (char) ulTemp; if (cBlockNumber < MY_MAX_BLOCK) { if (data->serviceNumber == MY_SVC_READ) { /* Read Response is an unsigned int with 0 for success or a non 0 error code For a successful read the 0 success code is followed by the block number and then the block contents which consist of 2 unsigned ints (in 0 to 255 range as they are really chars) a single precision real and a string which will be up to 32 chars + a nul */ iLen = 0; /* Signal success */ iLen += encode_application_unsigned(&IOBufferPT[iLen], MY_ERR_OK); /* Followed by the block number */ iLen += encode_application_unsigned(&IOBufferPT[iLen], cBlockNumber); /* And Then the block contents */ iLen += encode_application_unsigned(&IOBufferPT[iLen], MyData[(int8_t) cBlockNumber].cMyByte1); iLen += encode_application_unsigned(&IOBufferPT[iLen], MyData[(int8_t) cBlockNumber].cMyByte2); iLen += encode_application_real(&IOBufferPT[iLen], MyData[(int8_t) cBlockNumber].fMyReal); characterstring_init_ansi(&bsTemp, (char *) MyData[(int8_t) cBlockNumber].sMyString); iLen += encode_application_character_string(&IOBufferPT[iLen], &bsTemp); } else { /* Write operation */ /* Write block consists of the block number followed by the block contents as described above for the read operation. The returned result is an unsigned response which is 0 for success and a non 0 error code otherwise. */ tag_len = decode_tag_number_and_value(&data->serviceParameters[iLen], &tag_number, &len_value_type); iLen += tag_len; if (tag_number != BACNET_APPLICATION_TAG_UNSIGNED_INT) { data->serviceParametersLen = 0; return; } iLen += decode_unsigned(&data->serviceParameters[iLen], len_value_type, &ulTemp); MyData[(int8_t) cBlockNumber].cMyByte1 = (char) ulTemp; tag_len = decode_tag_number_and_value(&data->serviceParameters[iLen], &tag_number, &len_value_type); iLen += tag_len; if (tag_number != BACNET_APPLICATION_TAG_UNSIGNED_INT) { data->serviceParametersLen = 0; return; } iLen += decode_unsigned(&data->serviceParameters[iLen], len_value_type, &ulTemp); MyData[(int8_t) cBlockNumber].cMyByte2 = (char) ulTemp; tag_len = decode_tag_number_and_value(&data->serviceParameters[iLen], &tag_number, &len_value_type); iLen += tag_len; if (tag_number != BACNET_APPLICATION_TAG_REAL) { data->serviceParametersLen = 0; return; } iLen += decode_real(&data->serviceParameters[iLen], &MyData[(int8_t) cBlockNumber].fMyReal); tag_len = decode_tag_number_and_value(&data->serviceParameters[iLen], &tag_number, &len_value_type); iLen += tag_len; if (tag_number != BACNET_APPLICATION_TAG_CHARACTER_STRING) { data->serviceParametersLen = 0; return; } decode_character_string(&data->serviceParameters[iLen], len_value_type, &bsTemp); /* Only copy as much as we can accept */ strncpy((char *) MyData[(int8_t) cBlockNumber].sMyString, characterstring_value(&bsTemp), MY_MAX_STR); /* Make sure it is nul terminated */ MyData[(int8_t) cBlockNumber].sMyString[MY_MAX_STR] = '\0'; /* Signal success */ iLen = encode_application_unsigned(&IOBufferPT[0], MY_ERR_OK); } } else { /* Signal bad index */ iLen = encode_application_unsigned(&IOBufferPT[0], MY_ERR_BAD_INDEX); } data->serviceParametersLen = iLen; data->serviceParameters = IOBufferPT; }
/** Handler for a Device Communication Control (DCC) request. * @ingroup DMDCC * This handler will be invoked by apdu_handler() if it has been enabled * by a call to apdu_set_confirmed_handler(). * This handler builds a response packet, which is * - an Abort if * - the message is segmented * - if decoding fails * - if not a known DCC state * - an Error if the DCC password is incorrect * - else tries to send a simple ACK for the DCC on success, * and sets the DCC state requested. * * @param service_request [in] The contents of the service request. * @param service_len [in] The length of the service_request. * @param src [in] BACNET_ADDRESS of the source of the message * @param service_data [in] The BACNET_CONFIRMED_SERVICE_DATA information * decoded from the APDU header of this message. */ void handler_device_communication_control( uint8_t * service_request, uint16_t service_len, BACNET_ADDRESS * src, BACNET_CONFIRMED_SERVICE_DATA * service_data) { uint16_t timeDuration = 0; BACNET_COMMUNICATION_ENABLE_DISABLE state = COMMUNICATION_ENABLE; BACNET_CHARACTER_STRING password; int len = 0; int pdu_len = 0; BACNET_NPDU_DATA npdu_data; BACNET_ADDRESS my_address; /* encode the NPDU portion of the reply packet */ datalink_get_my_address(&my_address); npdu_encode_npdu_data(&npdu_data, false, MESSAGE_PRIORITY_NORMAL); pdu_len = npdu_encode_pdu(&Handler_Transmit_Buffer[0], src, &my_address, &npdu_data); #if PRINT_ENABLED fprintf(stderr, "DeviceCommunicationControl!\n"); #endif if (service_data->segmented_message) { len = abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id, ABORT_REASON_SEGMENTATION_NOT_SUPPORTED, true); #if PRINT_ENABLED fprintf(stderr, "DeviceCommunicationControl: " "Sending Abort - segmented message.\n"); #endif goto DCC_ABORT; } /* decode the service request only */ len = dcc_decode_service_request(service_request, service_len, &timeDuration, &state, &password); #if PRINT_ENABLED if (len > 0) fprintf(stderr, "DeviceCommunicationControl: " "timeout=%u state=%u password=%s\n", (unsigned) timeDuration, (unsigned) state, characterstring_value(&password)); #endif /* bad decoding or something we didn't understand - send an abort */ if (len < 0) { len = abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id, ABORT_REASON_OTHER, true); #if PRINT_ENABLED fprintf(stderr, "DeviceCommunicationControl: " "Sending Abort - could not decode.\n"); #endif goto DCC_ABORT; } if (state >= MAX_BACNET_COMMUNICATION_ENABLE_DISABLE) { len = reject_encode_apdu(&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id, REJECT_REASON_UNDEFINED_ENUMERATION); #if PRINT_ENABLED fprintf(stderr, "DeviceCommunicationControl: " "Sending Reject - undefined enumeration\n"); #endif } else { #if BAC_ROUTING /* Check to see if the current Device supports this service. */ len = Routed_Device_Service_Approval (SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL, (int) state, &Handler_Transmit_Buffer[pdu_len], service_data->invoke_id); if (len > 0) goto DCC_ABORT; #endif if (characterstring_ansi_same(&password, My_Password)) { len = encode_simple_ack(&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id, SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL); #if PRINT_ENABLED fprintf(stderr, "DeviceCommunicationControl: " "Sending Simple Ack!\n"); #endif dcc_set_status_duration(state, timeDuration); } else { len = bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id, SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL, ERROR_CLASS_SECURITY, ERROR_CODE_PASSWORD_FAILURE); #if PRINT_ENABLED fprintf(stderr, "DeviceCommunicationControl: " "Sending Error - password failure.\n"); #endif } } DCC_ABORT: pdu_len += len; len = datalink_send_pdu(src, &npdu_data, &Handler_Transmit_Buffer[0], pdu_len); if (len <= 0) { #if PRINT_ENABLED fprintf(stderr, "DeviceCommunicationControl: " "Failed to send PDU (%s)!\n", strerror(errno)); #endif } return; }
/* returns true if successful */ bool Device_Write_Property( BACNET_WRITE_PROPERTY_DATA * wp_data, BACNET_ERROR_CLASS * error_class, BACNET_ERROR_CODE * error_code) { bool status = false; /* return value */ int len = 0; BACNET_APPLICATION_DATA_VALUE value; if (!Device_Valid_Object_Instance_Number(wp_data->object_instance)) { *error_class = ERROR_CLASS_OBJECT; *error_code = ERROR_CODE_UNKNOWN_OBJECT; return false; } /* decode the some of the request */ len = bacapp_decode_application_data(wp_data->application_data, wp_data->application_data_len, &value); /* FIXME: len < application_data_len: more data? */ /* FIXME: len == 0: unable to decode? */ switch (wp_data->object_property) { case PROP_OBJECT_IDENTIFIER: if (value.tag == BACNET_APPLICATION_TAG_OBJECT_ID) { if ((value.type.Object_Id.type == OBJECT_DEVICE) && (Device_Set_Object_Instance_Number(value.type. Object_Id.instance))) { /* FIXME: we could send an I-Am broadcast to let the world know */ status = true; } else { *error_class = ERROR_CLASS_PROPERTY; *error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; } } else { *error_class = ERROR_CLASS_PROPERTY; *error_code = ERROR_CODE_INVALID_DATA_TYPE; } break; case PROP_NUMBER_OF_APDU_RETRIES: if (value.tag == BACNET_APPLICATION_TAG_UNSIGNED_INT) { /* FIXME: bounds check? */ apdu_retries_set((uint8_t) value.type.Unsigned_Int); status = true; } else { *error_class = ERROR_CLASS_PROPERTY; *error_code = ERROR_CODE_INVALID_DATA_TYPE; } break; case PROP_APDU_TIMEOUT: if (value.tag == BACNET_APPLICATION_TAG_UNSIGNED_INT) { /* FIXME: bounds check? */ apdu_timeout_set((uint16_t) value.type.Unsigned_Int); status = true; } else { *error_class = ERROR_CLASS_PROPERTY; *error_code = ERROR_CODE_INVALID_DATA_TYPE; } break; case PROP_VENDOR_IDENTIFIER: if (value.tag == BACNET_APPLICATION_TAG_UNSIGNED_INT) { /* FIXME: bounds check? */ Device_Set_Vendor_Identifier((uint16_t) value. type.Unsigned_Int); status = true; } else { *error_class = ERROR_CLASS_PROPERTY; *error_code = ERROR_CODE_INVALID_DATA_TYPE; } break; case PROP_SYSTEM_STATUS: if (value.tag == BACNET_APPLICATION_TAG_ENUMERATED) { /* FIXME: bounds check? */ Device_Set_System_Status((BACNET_DEVICE_STATUS) value. type.Enumerated); status = true; } else { *error_class = ERROR_CLASS_PROPERTY; *error_code = ERROR_CODE_INVALID_DATA_TYPE; } break; case PROP_OBJECT_NAME: if (value.tag == BACNET_APPLICATION_TAG_CHARACTER_STRING) { uint8_t encoding; encoding = characterstring_encoding(&value.type.Character_String); if (encoding == CHARACTER_ANSI_X34) { status = Device_Set_Object_Name(characterstring_value (&value.type.Character_String), characterstring_length(&value.type.Character_String)); if (!status) { *error_class = ERROR_CLASS_PROPERTY; *error_code = ERROR_CODE_NO_SPACE_TO_WRITE_PROPERTY; } } else { *error_class = ERROR_CLASS_PROPERTY; *error_code = ERROR_CODE_CHARACTER_SET_NOT_SUPPORTED; } } else { *error_class = ERROR_CLASS_PROPERTY; *error_code = ERROR_CODE_INVALID_DATA_TYPE; } break; #if defined(BACDL_MSTP) case PROP_MAX_INFO_FRAMES: if (value.tag == BACNET_APPLICATION_TAG_UNSIGNED_INT) { if (value.type.Unsigned_Int <= 255) { dlmstp_set_max_info_frames((uint8_t) value. type.Unsigned_Int); status = true; } else { *error_class = ERROR_CLASS_PROPERTY; *error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; } } else { *error_class = ERROR_CLASS_PROPERTY; *error_code = ERROR_CODE_INVALID_DATA_TYPE; } break; case PROP_MAX_MASTER: if (value.tag == BACNET_APPLICATION_TAG_UNSIGNED_INT) { if ((value.type.Unsigned_Int > 0) && (value.type.Unsigned_Int <= 127)) { dlmstp_set_max_master((uint8_t) value.type.Unsigned_Int); status = true; } else { *error_class = ERROR_CLASS_PROPERTY; *error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; } } else { *error_class = ERROR_CLASS_PROPERTY; *error_code = ERROR_CODE_INVALID_DATA_TYPE; } break; #endif default: *error_class = ERROR_CLASS_PROPERTY; *error_code = ERROR_CODE_WRITE_ACCESS_DENIED; break; } return status; }