void main( void) { RCONbits.NOT_POR = 1; RCONbits.NOT_RI = 1; Hardware_Initialize(); Initialize_Variables(); /* initialize BACnet Data Link Layer */ dlmstp_set_my_address(42); dlmstp_set_max_info_frames(1); dlmstp_set_max_master(127); RS485_Set_Baud_Rate(38400); dlmstp_init(); /* Handle anything that needs to be done on powerup */ /* Greet the BACnet world! */ Send_I_Am(&Handler_Transmit_Buffer[0]); /* Main loop */ while (TRUE) { RESTART_WDT(); dlmstp_task(); MainTasks(); Global_Int(INT_ENABLED); ENABLE_TIMER4_INT(); } }
static void bacnet_init( void) { #if defined(BACDL_MSTP) RS485_Set_Baud_Rate(38400); dlmstp_set_mac_address(57); dlmstp_set_max_master(127); dlmstp_set_max_info_frames(1); dlmstp_init(NULL); #endif Device_Set_Object_Instance_Number(11111); #ifndef DLMSTP_TEST /* we need to handle who-is to support dynamic device binding */ apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is); /* Set the handlers for any confirmed services that we support. */ /* We must implement read property - it's required! */ apdu_set_confirmed_handler(SERVICE_CONFIRMED_READ_PROPERTY, handler_read_property); apdu_set_confirmed_handler(SERVICE_CONFIRMED_REINITIALIZE_DEVICE, handler_reinitialize_device); apdu_set_confirmed_handler(SERVICE_CONFIRMED_WRITE_PROPERTY, handler_write_property); /* handle communication so we can shutup when asked */ apdu_set_confirmed_handler(SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL, handler_device_communication_control); #endif }
int main( int argc, char *argv[]) { uint16_t pdu_len = 0; /* argv has the "COM4" or some other device */ if (argc > 1) { Network_Interface = argv[1]; } dlmstp_set_baud_rate(38400); dlmstp_set_mac_address(0x05); dlmstp_set_max_info_frames(DEFAULT_MAX_INFO_FRAMES); dlmstp_set_max_master(DEFAULT_MAX_MASTER); dlmstp_init(Network_Interface); /* forever task */ for (;;) { pdu_len = dlmstp_receive(NULL, NULL, 0, INFINITE); #if 0 MSTP_Create_And_Send_Frame(&MSTP_Port, FRAME_TYPE_TEST_REQUEST, MSTP_Port.SourceAddress, MSTP_Port.This_Station, NULL, 0); #endif } return 0; }
void dlmstp_reinit( void) { /*RS485_Reinit(); */ dlmstp_set_mac_address(DEFAULT_MAC_ADDRESS); dlmstp_set_max_info_frames(DEFAULT_MAX_INFO_FRAMES); dlmstp_set_max_master(DEFAULT_MAX_MASTER); }
void dlmstp_reinit( void) { /*RS485_Reinit(); */ dlmstp_set_mac_address(DEFAULT_MAC_ADDRESS); dlmstp_set_max_info_frames(DEFAULT_MAX_INFO_FRAMES); dlmstp_set_max_master(DEFAULT_MAX_MASTER); /* reset timer resolution */ timeEndPeriod(TimeBeginPeriod); }
void dlmstp_set_mac_address( uint8_t mac_address) { /* Master Nodes can only have address 0-127 */ if (mac_address <= 127) { MSTP_Port.This_Station = mac_address; /* FIXME: implement your data storage */ /* I2C_Write_Byte( EEPROM_DEVICE_ADDRESS, mac_address, EEPROM_MSTP_MAC_ADDR); */ if (mac_address > MSTP_Port.Nmax_master) dlmstp_set_max_master(mac_address); } return; }
bool Device_Write_Property_Local(BACNET_WRITE_PROPERTY_DATA * wp_data) { bool status = false; /* return value - false=error */ int len = 0; BACNET_APPLICATION_DATA_VALUE value; uint8_t max_master = 0; /* 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? */ 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; } if ((wp_data->object_property != PROP_OBJECT_LIST) && (wp_data->array_index != BACNET_ARRAY_ALL)) { /* only array properties can have array options */ wp_data->error_class = ERROR_CLASS_PROPERTY; wp_data->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY; return false; } switch ((int) 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))) { nvm_write(NVM_DEVICE_0, (uint8_t *) & value.type.Object_Id.instance, 4); /* we could send an I-Am broadcast to let the world know */ status = true; } else { wp_data->error_class = ERROR_CLASS_PROPERTY; wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; } } else { wp_data->error_class = ERROR_CLASS_PROPERTY; wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE; } break; case PROP_MAX_INFO_FRAMES: if (value.tag == BACNET_APPLICATION_TAG_UNSIGNED_INT) { if (value.type.Unsigned_Int <= 255) { dlmstp_set_max_info_frames(value.type.Unsigned_Int); status = true; } else { wp_data->error_class = ERROR_CLASS_PROPERTY; wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; } } else { wp_data->error_class = ERROR_CLASS_PROPERTY; wp_data->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)) { max_master = value.type.Unsigned_Int; dlmstp_set_max_master(max_master); nvm_write(NVM_MAX_MASTER, &max_master, 1); status = true; } else { wp_data->error_class = ERROR_CLASS_PROPERTY; wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; } } else { wp_data->error_class = ERROR_CLASS_PROPERTY; wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE; } break; case PROP_OBJECT_NAME: if (value.tag == BACNET_APPLICATION_TAG_CHARACTER_STRING) { status = bacnet_name_write_unique(NVM_DEVICE_NAME, wp_data->object_type, wp_data->object_instance, &value.type.Character_String, &wp_data->error_class, &wp_data->error_code); } else { wp_data->error_class = ERROR_CLASS_PROPERTY; wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE; } break; case PROP_DESCRIPTION: if (value.tag == BACNET_APPLICATION_TAG_CHARACTER_STRING) { status = bacnet_name_write(NVM_DEVICE_DESCRIPTION, &value.type.Character_String, &wp_data->error_class, &wp_data->error_code); } else { wp_data->error_class = ERROR_CLASS_PROPERTY; wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE; } break; case PROP_LOCATION: if (value.tag == BACNET_APPLICATION_TAG_CHARACTER_STRING) { status = bacnet_name_write(NVM_DEVICE_LOCATION, &value.type.Character_String, &wp_data->error_class, &wp_data->error_code); } else { wp_data->error_class = ERROR_CLASS_PROPERTY; wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE; } break; case PROP_OBJECT_TYPE: case PROP_VENDOR_NAME: case PROP_FIRMWARE_REVISION: case PROP_APPLICATION_SOFTWARE_VERSION: case PROP_DAYLIGHT_SAVINGS_STATUS: case PROP_PROTOCOL_VERSION: case PROP_PROTOCOL_REVISION: case PROP_PROTOCOL_SERVICES_SUPPORTED: case PROP_PROTOCOL_OBJECT_TYPES_SUPPORTED: case PROP_OBJECT_LIST: case PROP_MAX_APDU_LENGTH_ACCEPTED: case PROP_SEGMENTATION_SUPPORTED: case PROP_DEVICE_ADDRESS_BINDING: case PROP_DATABASE_REVISION: case 512: case 513: wp_data->error_class = ERROR_CLASS_PROPERTY; wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED; break; default: wp_data->error_class = ERROR_CLASS_PROPERTY; wp_data->error_code = ERROR_CODE_UNKNOWN_PROPERTY; break; } return status; }
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))) { /* 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_MAX_INFO_FRAMES: if (value.tag == BACNET_APPLICATION_TAG_UNSIGNED_INT) { if (value.type.Unsigned_Int <= 255) { dlmstp_set_max_info_frames(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(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_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) { if (characterstring_ansi_copy(&Object_Name[0], sizeof(Object_Name), &value.type.Character_String)) { status = true; } else { *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; case 9600: if (value.tag == BACNET_APPLICATION_TAG_UNSIGNED_INT) { if (value.type.Unsigned_Int > 115200) { RS485_Set_Baud_Rate(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; default: *error_class = ERROR_CLASS_PROPERTY; *error_code = ERROR_CODE_WRITE_ACCESS_DENIED; break; } return status; }
/** 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(); }
bool Device_Write_Property_Local( BACNET_WRITE_PROPERTY_DATA * wp_data) { bool status = false; /* return value - false=error */ int len = 0; uint8_t encoding = 0; size_t length = 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); /* FIXME: len < application_data_len: more data? */ 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; } if ((wp_data->object_property != PROP_OBJECT_LIST) && (wp_data->array_index != BACNET_ARRAY_ALL)) { /* only array properties can have array options */ wp_data->error_class = ERROR_CLASS_PROPERTY; wp_data->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY; return false; } switch ((int) 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))) { /* we could send an I-Am broadcast to let the world know */ status = true; } else { wp_data->error_class = ERROR_CLASS_PROPERTY; wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; } } else { wp_data->error_class = ERROR_CLASS_PROPERTY; wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE; } break; case PROP_MAX_INFO_FRAMES: if (value.tag == BACNET_APPLICATION_TAG_UNSIGNED_INT) { if (value.type.Unsigned_Int <= 255) { dlmstp_set_max_info_frames(value.type.Unsigned_Int); status = true; } else { wp_data->error_class = ERROR_CLASS_PROPERTY; wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; } } else { wp_data->error_class = ERROR_CLASS_PROPERTY; wp_data->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(value.type.Unsigned_Int); status = true; } else { wp_data->error_class = ERROR_CLASS_PROPERTY; wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; } } else { wp_data->error_class = ERROR_CLASS_PROPERTY; wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE; } break; case PROP_OBJECT_NAME: if (value.tag == BACNET_APPLICATION_TAG_CHARACTER_STRING) { length = characterstring_length(&value.type.Character_String); if (length < 1) { wp_data->error_class = ERROR_CLASS_PROPERTY; wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; } else if (length < characterstring_capacity(&My_Object_Name)) { encoding = characterstring_encoding(&value.type.Character_String); if (encoding < MAX_CHARACTER_STRING_ENCODING) { /* All the object names in a device must be unique. */ if (Device_Valid_Object_Name(&value.type. Character_String, NULL, NULL)) { wp_data->error_class = ERROR_CLASS_PROPERTY; wp_data->error_code = ERROR_CODE_DUPLICATE_NAME; } else { Device_Set_Object_Name(&value.type. Character_String); status = true; } } else { wp_data->error_class = ERROR_CLASS_PROPERTY; wp_data->error_code = ERROR_CODE_CHARACTER_SET_NOT_SUPPORTED; } } else { wp_data->error_class = ERROR_CLASS_PROPERTY; wp_data->error_code = ERROR_CODE_NO_SPACE_TO_WRITE_PROPERTY; } } else { wp_data->error_class = ERROR_CLASS_PROPERTY; wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE; } break; case 9600: if (value.tag == BACNET_APPLICATION_TAG_UNSIGNED_INT) { if (value.type.Unsigned_Int <= 115200) { RS485_Set_Baud_Rate(value.type.Unsigned_Int); status = true; } else { wp_data->error_class = ERROR_CLASS_PROPERTY; wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; } } else { wp_data->error_class = ERROR_CLASS_PROPERTY; wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE; } break; case PROP_NUMBER_OF_APDU_RETRIES: case PROP_APDU_TIMEOUT: case PROP_VENDOR_IDENTIFIER: case PROP_SYSTEM_STATUS: case PROP_LOCATION: case PROP_DESCRIPTION: case PROP_MODEL_NAME: case PROP_VENDOR_NAME: case PROP_FIRMWARE_REVISION: case PROP_APPLICATION_SOFTWARE_VERSION: case PROP_LOCAL_TIME: case PROP_UTC_OFFSET: case PROP_LOCAL_DATE: case PROP_DAYLIGHT_SAVINGS_STATUS: case PROP_PROTOCOL_VERSION: case PROP_PROTOCOL_REVISION: case PROP_PROTOCOL_SERVICES_SUPPORTED: case PROP_PROTOCOL_OBJECT_TYPES_SUPPORTED: case PROP_OBJECT_LIST: case PROP_MAX_APDU_LENGTH_ACCEPTED: case PROP_SEGMENTATION_SUPPORTED: case PROP_DEVICE_ADDRESS_BINDING: case PROP_DATABASE_REVISION: case PROP_ACTIVE_COV_SUBSCRIPTIONS: wp_data->error_class = ERROR_CLASS_PROPERTY; wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED; break; default: wp_data->error_class = ERROR_CLASS_PROPERTY; wp_data->error_code = ERROR_CODE_UNKNOWN_PROPERTY; break; } /* not using len at this time */ len = len; return status; }
bool dlmstp_init( char *ifname) { unsigned long hThread = 0; int rv = 0; /* initialize packet queue */ Receive_Packet.ready = false; Receive_Packet.pdu_len = 0; rv = pthread_cond_init(&Receive_Packet_Flag, NULL); if (rv == -1) { fprintf(stderr, "MS/TP Interface: %s\n cannot allocate PThread Condition.\n", ifname); exit(1); } rv = pthread_cond_init(&Received_Frame_Flag, NULL); if (rv == -1) { fprintf(stderr, "MS/TP Interface: %s\n cannot allocate PThread Condition.\n", ifname); exit(1); } rv = pthread_mutex_init(&Receive_Packet_Mutex, NULL); if (rv == -1) { fprintf(stderr, "MS/TP Interface: %s\n cannot allocate PThread Mutex.\n", ifname); exit(1); } rv = pthread_mutex_init(&Received_Frame_Mutex, NULL); if (rv == -1) { fprintf(stderr, "MS/TP Interface: %s\n cannot allocate PThread Mutex.\n", ifname); exit(1); } /* initialize hardware */ if (ifname) { RS485_Set_Interface(ifname); #if PRINT_ENABLED fprintf(stderr, "MS/TP Interface: %s\n", ifname); #endif } RS485_Initialize(); MSTP_Port.InputBuffer = &RxBuffer[0]; MSTP_Port.InputBufferSize = sizeof(RxBuffer); MSTP_Port.OutputBuffer = &TxBuffer[0]; MSTP_Port.OutputBufferSize = sizeof(TxBuffer); MSTP_Port.SilenceTimer = Timer_Silence; MSTP_Port.SilenceTimerReset = Timer_Silence_Reset; MSTP_Init(&MSTP_Port); #if 0 uint8_t data; /* FIXME: implement your data storage */ data = 64; /* I2C_Read_Byte( EEPROM_DEVICE_ADDRESS, EEPROM_MSTP_MAC_ADDR); */ if (data <= 127) MSTP_Port.This_Station = data; else dlmstp_set_my_address(DEFAULT_MAC_ADDRESS); /* FIXME: implement your data storage */ data = 127; /* I2C_Read_Byte( EEPROM_DEVICE_ADDRESS, EEPROM_MSTP_MAX_MASTER_ADDR); */ if ((data <= 127) && (data >= MSTP_Port.This_Station)) MSTP_Port.Nmax_master = data; else dlmstp_set_max_master(DEFAULT_MAX_MASTER); /* FIXME: implement your data storage */ data = 1; /* I2C_Read_Byte( EEPROM_DEVICE_ADDRESS, EEPROM_MSTP_MAX_INFO_FRAMES_ADDR); */ if (data >= 1) MSTP_Port.Nmax_info_frames = data; else dlmstp_set_max_info_frames(DEFAULT_MAX_INFO_FRAMES); #endif #if PRINT_ENABLED fprintf(stderr, "MS/TP MAC: %02X\n", MSTP_Port.This_Station); fprintf(stderr, "MS/TP Max_Master: %02X\n", MSTP_Port.Nmax_master); fprintf(stderr, "MS/TP Max_Info_Frames: %u\n", MSTP_Port.Nmax_info_frames); #endif /* start the threads */ rv = pthread_create(&hThread, NULL, dlmstp_milliseconds_task, NULL); if (rv != 0) { fprintf(stderr, "Failed to start timer task\n"); } rv = pthread_create(&hThread, NULL, dlmstp_receive_fsm_task, NULL); if (rv != 0) { fprintf(stderr, "Failed to start recive FSM task\n"); } rv = pthread_create(&hThread, NULL, dlmstp_master_fsm_task, NULL); if (rv != 0) { fprintf(stderr, "Failed to start Master Node FSM task\n"); } return true; }
bool dlmstp_init( char *ifname) { unsigned long hThread = 0; uint32_t arg_value = 0; TIMECAPS tc; /* initialize packet queue */ Receive_Packet.ready = false; Receive_Packet.pdu_len = 0; Receive_Packet_Flag = CreateSemaphore(NULL, 0, 1, "dlmstpReceivePacket"); if (Receive_Packet_Flag == NULL) exit(1); Received_Frame_Flag = CreateSemaphore(NULL, 0, 1, "dlsmtpReceiveFrame"); if (Received_Frame_Flag == NULL) { CloseHandle(Receive_Packet_Flag); exit(1); } /* initialize hardware */ /* initialize hardware */ if (ifname) { RS485_Set_Interface(ifname); #if PRINT_ENABLED fprintf(stderr, "MS/TP Interface: %s\n", ifname); #endif } RS485_Initialize(); MSTP_Port.InputBuffer = &RxBuffer[0]; MSTP_Port.InputBufferSize = sizeof(RxBuffer); MSTP_Port.OutputBuffer = &TxBuffer[0]; MSTP_Port.OutputBufferSize = sizeof(TxBuffer); MSTP_Port.SilenceTimer = Timer_Silence; MSTP_Port.SilenceTimerReset = Timer_Silence_Reset; MSTP_Init(&MSTP_Port); #if 0 uint8_t data; /* FIXME: implement your data storage */ data = 64; /* I2C_Read_Byte( EEPROM_DEVICE_ADDRESS, EEPROM_MSTP_MAC_ADDR); */ if (data <= 127) MSTP_Port.This_Station = data; else dlmstp_set_my_address(DEFAULT_MAC_ADDRESS); /* FIXME: implement your data storage */ data = 127; /* I2C_Read_Byte( EEPROM_DEVICE_ADDRESS, EEPROM_MSTP_MAX_MASTER_ADDR); */ if ((data <= 127) && (data >= MSTP_Port.This_Station)) MSTP_Port.Nmax_master = data; else dlmstp_set_max_master(DEFAULT_MAX_MASTER); /* FIXME: implement your data storage */ data = 1; /* I2C_Read_Byte( EEPROM_DEVICE_ADDRESS, EEPROM_MSTP_MAX_INFO_FRAMES_ADDR); */ if (data >= 1) MSTP_Port.Nmax_info_frames = data; else dlmstp_set_max_info_frames(DEFAULT_MAX_INFO_FRAMES); #endif #if PRINT_ENABLED fprintf(stderr, "MS/TP MAC: %02X\n", MSTP_Port.This_Station); fprintf(stderr, "MS/TP Max_Master: %02X\n", MSTP_Port.Nmax_master); fprintf(stderr, "MS/TP Max_Info_Frames: %u\n", MSTP_Port.Nmax_info_frames); #endif /* set timer resolution */ if (timeGetDevCaps(&tc, sizeof(TIMECAPS)) != TIMERR_NOERROR) { fprintf(stderr, "Failed to set timer resolution\n"); } TimeBeginPeriod = min(max(tc.wPeriodMin, TARGET_RESOLUTION), tc.wPeriodMax); timeBeginPeriod(TimeBeginPeriod); /* start the threads */ hThread = _beginthread(dlmstp_receive_fsm_task, 4096, &arg_value); if (hThread == 0) { fprintf(stderr, "Failed to start recive FSM task\n"); } hThread = _beginthread(dlmstp_master_fsm_task, 4096, &arg_value); if (hThread == 0) { fprintf(stderr, "Failed to start Master Node FSM task\n"); } return true; }
/* 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; }