/** Initialize the DataLink configuration from Environment variables, * or else to defaults. * @ingroup DataLink * The items configured depend on which BACDL_ the code is built for, * eg, BACDL_BIP. * * For most items, checks first for an environment variable, and, if * found, uses that to set the item's value. Otherwise, will set * to a default value. * * The Environment Variables, by BACDL_ type, are: * - BACDL_ALL: (the general-purpose solution) * - BACNET_DATALINK to set which BACDL_ type we are using. * - (Any): * - BACNET_APDU_TIMEOUT - set this value in milliseconds to change * the APDU timeout. APDU Timeout is how much time a client * waits for a response from a BACnet device. * - BACNET_APDU_RETRIES - indicate the maximum number of times that * an APDU shall be retransmitted. * - BACNET_IFACE - set this value to dotted IP address (Windows) of * the interface (see ipconfig command on Windows) for which you * want to bind. On Linux, set this to the /dev interface * (i.e. eth0, arc0). Default is eth0 on Linux, and the default * interface on Windows. Hence, if there is only a single network * interface on Windows, the applications will choose it, and this * setting will not be needed. * - BACDL_BIP: (BACnet/IP) * - BACNET_IP_PORT - UDP/IP port number (0..65534) used for BACnet/IP * communications. Default is 47808 (0xBAC0). * - BACNET_BBMD_PORT - UDP/IP port number (0..65534) used for Foreign * Device Registration. Defaults to 47808 (0xBAC0). * - BACNET_BBMD_TIMETOLIVE - number of seconds used in Foreign Device * Registration (0..65535). Defaults to 60000 seconds. * - BACNET_BBMD_ADDRESS - dotted IPv4 address of the BBMD or Foreign * Device Registrar. * - BACDL_MSTP: (BACnet MS/TP) * - BACNET_MAX_INFO_FRAMES * - BACNET_MAX_MASTER * - BACNET_MSTP_BAUD * - BACNET_MSTP_MAC */ void dlenv_init( void) { char *pEnv = NULL; #if defined(BACDL_ALL) pEnv = getenv("BACNET_DATALINK"); if (pEnv) { datalink_set(pEnv); } else { datalink_set(NULL); } #endif #if defined(BACDL_BIP) #if defined(BIP_DEBUG) BIP_Debug = true; #endif pEnv = getenv("BACNET_IP_PORT"); if (pEnv) { bip_set_port(htons((uint16_t) strtol(pEnv, NULL, 0))); } else { /* BIP_Port is statically initialized to 0xBAC0, * so if it is different, then it was programmatically altered, * and we shouldn't just stomp on it here. * Unless it is set below 1024, since: * "The range for well-known ports managed by the IANA is 0-1023." */ if (ntohs(bip_get_port()) < 1024) bip_set_port(htons(0xBAC0)); } #elif defined(BACDL_MSTP) pEnv = getenv("BACNET_MAX_INFO_FRAMES"); if (pEnv) { dlmstp_set_max_info_frames(strtol(pEnv, NULL, 0)); } else { dlmstp_set_max_info_frames(1); } pEnv = getenv("BACNET_MAX_MASTER"); if (pEnv) { dlmstp_set_max_master(strtol(pEnv, NULL, 0)); } else { dlmstp_set_max_master(127); } pEnv = getenv("BACNET_MSTP_BAUD"); if (pEnv) { dlmstp_set_baud_rate(strtol(pEnv, NULL, 0)); } else { dlmstp_set_baud_rate(38400); } pEnv = getenv("BACNET_MSTP_MAC"); if (pEnv) { dlmstp_set_mac_address(strtol(pEnv, NULL, 0)); } else { dlmstp_set_mac_address(127); } #endif pEnv = getenv("BACNET_APDU_TIMEOUT"); if (pEnv) { apdu_timeout_set((uint16_t) strtol(pEnv, NULL, 0)); } else { #if defined(BACDL_MSTP) apdu_timeout_set(60000); #endif } pEnv = getenv("BACNET_APDU_RETRIES"); if (pEnv) { apdu_retries_set((uint8_t) strtol(pEnv, NULL, 0)); } if (!datalink_init(getenv("BACNET_IFACE"))) { exit(1); } #if (MAX_TSM_TRANSACTIONS) pEnv = getenv("BACNET_INVOKE_ID"); if (pEnv) { tsm_invokeID_set((uint8_t) strtol(pEnv, NULL, 0)); } #endif dlenv_register_as_foreign_device(); }
/* 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; }