/** * Sends a TimeSync message using the local time from the device. */ void Send_TimeSync_Device(void) { BACNET_DATE_TIME local_time; Device_getCurrentDateTime(&local_time); Send_TimeSync(&local_time.date, &local_time.time); }
/** * Sends a UTC TimeSync message using the local time from the device. */ void Send_TimeSyncUTC_Device(void) { int32_t utc_offset_minutes = 0; bool dst = false; BACNET_DATE_TIME local_time; BACNET_DATE_TIME utc_time; Device_getCurrentDateTime(&local_time); dst = Device_Daylight_Savings_Status(); utc_offset_minutes = Device_UTC_Offset(); datetime_copy(&utc_time, &local_time); datetime_add_minutes(&utc_time, utc_offset_minutes); if (dst) { datetime_add_minutes(&utc_time, -60); } Send_TimeSyncUTC(&utc_time.date, &utc_time.time); }
static bool IsRecipientActive( BACNET_DESTINATION * pBacDest, uint8_t EventToState) { BACNET_DATE_TIME DateTime; /* valid Transitions */ switch (EventToState) { case EVENT_STATE_OFFNORMAL: case EVENT_STATE_HIGH_LIMIT: case EVENT_STATE_LOW_LIMIT: if (!(pBacDest->Transitions & TRANSITION_TO_OFFNORMAL_MASKED)) return false; break; case EVENT_STATE_FAULT: if (!(pBacDest->Transitions & TRANSITION_TO_FAULT_MASKED)) return false; break; case EVENT_STATE_NORMAL: if (!(pBacDest->Transitions & TRANSITION_TO_NORMAL_MASKED)) return false; break; default: return false; /* shouldn't happen */ } /* get actual date and time */ Device_getCurrentDateTime(&DateTime); /* valid Days */ if (!((0x01 << (DateTime.date.wday - 1)) & pBacDest->ValidDays)) return false; /* valid FromTime */ if (datetime_compare_time(&DateTime.time, &pBacDest->FromTime) < 0) return false; /* valid ToTime */ if (datetime_compare_time(&pBacDest->ToTime, &DateTime.time) < 0) return false; return true; }
void Analog_Value_Intrinsic_Reporting( uint32_t object_instance) { #if defined(INTRINSIC_REPORTING) BACNET_EVENT_NOTIFICATION_DATA event_data; BACNET_CHARACTER_STRING msgText; ANALOG_VALUE_DESCR *CurrentAV; unsigned int object_index; uint8_t FromState = 0; uint8_t ToState; float ExceededLimit = 0.0f; float PresentVal = 0.0f; bool SendNotify = false; object_index = Analog_Value_Instance_To_Index(object_instance); if (object_index < MAX_ANALOG_VALUES) CurrentAV = &AV_Descr[object_index]; else return; /* check limits */ if (!CurrentAV->Limit_Enable) return; /* limits are not configured */ if (CurrentAV->Ack_notify_data.bSendAckNotify) { /* clean bSendAckNotify flag */ CurrentAV->Ack_notify_data.bSendAckNotify = false; /* copy toState */ ToState = CurrentAV->Ack_notify_data.EventState; #if PRINT_ENABLED fprintf(stderr, "Send Acknotification for (%s,%d).\n", bactext_object_type_name(OBJECT_ANALOG_VALUE), object_instance); #endif /* PRINT_ENABLED */ characterstring_init_ansi(&msgText, "AckNotification"); /* Notify Type */ event_data.notifyType = NOTIFY_ACK_NOTIFICATION; /* Send EventNotification. */ SendNotify = true; } else { /* actual Present_Value */ PresentVal = Analog_Value_Present_Value(object_instance); FromState = CurrentAV->Event_State; switch (CurrentAV->Event_State) { case EVENT_STATE_NORMAL: /* A TO-OFFNORMAL event is generated under these conditions: (a) the Present_Value must exceed the High_Limit for a minimum period of time, specified in the Time_Delay property, and (b) the HighLimitEnable flag must be set in the Limit_Enable property, and (c) the TO-OFFNORMAL flag must be set in the Event_Enable property. */ if ((PresentVal > CurrentAV->High_Limit) && ((CurrentAV->Limit_Enable & EVENT_HIGH_LIMIT_ENABLE) == EVENT_HIGH_LIMIT_ENABLE) && ((CurrentAV->Event_Enable & EVENT_ENABLE_TO_OFFNORMAL) == EVENT_ENABLE_TO_OFFNORMAL)) { if (!CurrentAV->Remaining_Time_Delay) CurrentAV->Event_State = EVENT_STATE_HIGH_LIMIT; else CurrentAV->Remaining_Time_Delay--; break; } /* A TO-OFFNORMAL event is generated under these conditions: (a) the Present_Value must exceed the Low_Limit plus the Deadband for a minimum period of time, specified in the Time_Delay property, and (b) the LowLimitEnable flag must be set in the Limit_Enable property, and (c) the TO-NORMAL flag must be set in the Event_Enable property. */ if ((PresentVal < CurrentAV->Low_Limit) && ((CurrentAV->Limit_Enable & EVENT_LOW_LIMIT_ENABLE) == EVENT_LOW_LIMIT_ENABLE) && ((CurrentAV->Event_Enable & EVENT_ENABLE_TO_OFFNORMAL) == EVENT_ENABLE_TO_OFFNORMAL)) { if (!CurrentAV->Remaining_Time_Delay) CurrentAV->Event_State = EVENT_STATE_LOW_LIMIT; else CurrentAV->Remaining_Time_Delay--; break; } /* value of the object is still in the same event state */ CurrentAV->Remaining_Time_Delay = CurrentAV->Time_Delay; break; case EVENT_STATE_HIGH_LIMIT: /* Once exceeded, the Present_Value must fall below the High_Limit minus the Deadband before a TO-NORMAL event is generated under these conditions: (a) the Present_Value must fall below the High_Limit minus the Deadband for a minimum period of time, specified in the Time_Delay property, and (b) the HighLimitEnable flag must be set in the Limit_Enable property, and (c) the TO-NORMAL flag must be set in the Event_Enable property. */ if ((PresentVal < CurrentAV->High_Limit - CurrentAV->Deadband) && ((CurrentAV->Limit_Enable & EVENT_HIGH_LIMIT_ENABLE) == EVENT_HIGH_LIMIT_ENABLE) && ((CurrentAV->Event_Enable & EVENT_ENABLE_TO_NORMAL) == EVENT_ENABLE_TO_NORMAL)) { if (!CurrentAV->Remaining_Time_Delay) CurrentAV->Event_State = EVENT_STATE_NORMAL; else CurrentAV->Remaining_Time_Delay--; break; } /* value of the object is still in the same event state */ CurrentAV->Remaining_Time_Delay = CurrentAV->Time_Delay; break; case EVENT_STATE_LOW_LIMIT: /* Once the Present_Value has fallen below the Low_Limit, the Present_Value must exceed the Low_Limit plus the Deadband before a TO-NORMAL event is generated under these conditions: (a) the Present_Value must exceed the Low_Limit plus the Deadband for a minimum period of time, specified in the Time_Delay property, and (b) the LowLimitEnable flag must be set in the Limit_Enable property, and (c) the TO-NORMAL flag must be set in the Event_Enable property. */ if ((PresentVal > CurrentAV->Low_Limit + CurrentAV->Deadband) && ((CurrentAV->Limit_Enable & EVENT_LOW_LIMIT_ENABLE) == EVENT_LOW_LIMIT_ENABLE) && ((CurrentAV->Event_Enable & EVENT_ENABLE_TO_NORMAL) == EVENT_ENABLE_TO_NORMAL)) { if (!CurrentAV->Remaining_Time_Delay) CurrentAV->Event_State = EVENT_STATE_NORMAL; else CurrentAV->Remaining_Time_Delay--; break; } /* value of the object is still in the same event state */ CurrentAV->Remaining_Time_Delay = CurrentAV->Time_Delay; break; default: return; /* shouldn't happen */ } /* switch (FromState) */ ToState = CurrentAV->Event_State; if (FromState != ToState) { /* Event_State has changed. Need to fill only the basic parameters of this type of event. Other parameters will be filled in common function. */ switch (ToState) { case EVENT_STATE_HIGH_LIMIT: ExceededLimit = CurrentAV->High_Limit; characterstring_init_ansi(&msgText, "Goes to high limit"); break; case EVENT_STATE_LOW_LIMIT: ExceededLimit = CurrentAV->Low_Limit; characterstring_init_ansi(&msgText, "Goes to low limit"); break; case EVENT_STATE_NORMAL: if (FromState == EVENT_STATE_HIGH_LIMIT) { ExceededLimit = CurrentAV->High_Limit; characterstring_init_ansi(&msgText, "Back to normal state from high limit"); } else { ExceededLimit = CurrentAV->Low_Limit; characterstring_init_ansi(&msgText, "Back to normal state from low limit"); } break; default: ExceededLimit = 0; break; } /* switch (ToState) */ #if PRINT_ENABLED fprintf(stderr, "Event_State for (%s,%d) goes from %s to %s.\n", bactext_object_type_name(OBJECT_ANALOG_VALUE), object_instance, bactext_event_state_name(FromState), bactext_event_state_name(ToState)); #endif /* PRINT_ENABLED */ /* Notify Type */ event_data.notifyType = CurrentAV->Notify_Type; /* Send EventNotification. */ SendNotify = true; } } if (SendNotify) { /* Event Object Identifier */ event_data.eventObjectIdentifier.type = OBJECT_ANALOG_VALUE; event_data.eventObjectIdentifier.instance = object_instance; /* Time Stamp */ event_data.timeStamp.tag = TIME_STAMP_DATETIME; Device_getCurrentDateTime(&event_data.timeStamp.value.dateTime); if (event_data.notifyType != NOTIFY_ACK_NOTIFICATION) { /* fill Event_Time_Stamps */ switch (ToState) { case EVENT_STATE_HIGH_LIMIT: case EVENT_STATE_LOW_LIMIT: CurrentAV->Event_Time_Stamps[TRANSITION_TO_OFFNORMAL] = event_data.timeStamp.value.dateTime; break; case EVENT_STATE_FAULT: CurrentAV->Event_Time_Stamps[TRANSITION_TO_FAULT] = event_data.timeStamp.value.dateTime; break; case EVENT_STATE_NORMAL: CurrentAV->Event_Time_Stamps[TRANSITION_TO_NORMAL] = event_data.timeStamp.value.dateTime; break; } } /* Notification Class */ event_data.notificationClass = CurrentAV->Notification_Class; /* Event Type */ event_data.eventType = EVENT_OUT_OF_RANGE; /* Message Text */ event_data.messageText = &msgText; /* Notify Type */ /* filled before */ /* From State */ if (event_data.notifyType != NOTIFY_ACK_NOTIFICATION) event_data.fromState = FromState; /* To State */ event_data.toState = CurrentAV->Event_State; /* Event Values */ if (event_data.notifyType != NOTIFY_ACK_NOTIFICATION) { /* Value that exceeded a limit. */ event_data.notificationParams.outOfRange.exceedingValue = PresentVal; /* Status_Flags of the referenced object. */ bitstring_init(&event_data.notificationParams.outOfRange. statusFlags); bitstring_set_bit(&event_data.notificationParams.outOfRange. statusFlags, STATUS_FLAG_IN_ALARM, CurrentAV->Event_State ? true : false); bitstring_set_bit(&event_data.notificationParams.outOfRange. statusFlags, STATUS_FLAG_FAULT, false); bitstring_set_bit(&event_data.notificationParams.outOfRange. statusFlags, STATUS_FLAG_OVERRIDDEN, false); bitstring_set_bit(&event_data.notificationParams.outOfRange. statusFlags, STATUS_FLAG_OUT_OF_SERVICE, CurrentAV->Out_Of_Service); /* Deadband used for limit checking. */ event_data.notificationParams.outOfRange.deadband = CurrentAV->Deadband; /* Limit that was exceeded. */ event_data.notificationParams.outOfRange.exceededLimit = ExceededLimit; } /* add data from notification class */ Notification_Class_common_reporting_function(&event_data); /* Ack required */ if ((event_data.notifyType != NOTIFY_ACK_NOTIFICATION) && (event_data.ackRequired == true)) { switch (event_data.toState) { case EVENT_STATE_OFFNORMAL: case EVENT_STATE_HIGH_LIMIT: case EVENT_STATE_LOW_LIMIT: CurrentAV->Acked_Transitions[TRANSITION_TO_OFFNORMAL]. bIsAcked = false; CurrentAV->Acked_Transitions[TRANSITION_TO_OFFNORMAL]. Time_Stamp = event_data.timeStamp.value.dateTime; break; case EVENT_STATE_FAULT: CurrentAV->Acked_Transitions[TRANSITION_TO_FAULT]. bIsAcked = false; CurrentAV->Acked_Transitions[TRANSITION_TO_FAULT]. Time_Stamp = event_data.timeStamp.value.dateTime; break; case EVENT_STATE_NORMAL: CurrentAV->Acked_Transitions[TRANSITION_TO_NORMAL]. bIsAcked = false; CurrentAV->Acked_Transitions[TRANSITION_TO_NORMAL]. Time_Stamp = event_data.timeStamp.value.dateTime; break; } } } #endif /* defined(INTRINSIC_REPORTING) */ }
/** Main function of server demo. * * @see Device_Set_Object_Instance_Number, dlenv_init, Send_I_Am, * datalink_receive, npdu_handler, * dcc_timer_seconds, bvlc_maintenance_timer, * Load_Control_State_Machine_Handler, handler_cov_task, * tsm_timer_milliseconds * * @param argc [in] Arg count. * @param argv [in] Takes one argument: the Device Instance #. * @return 0 on success. */ int main( int argc, char *argv[]) { BACNET_ADDRESS src = { 0 }; /* address where message came from */ uint16_t pdu_len = 0; unsigned timeout = 1; /* milliseconds */ time_t last_seconds = 0; time_t current_seconds = 0; uint32_t elapsed_seconds = 0; uint32_t elapsed_milliseconds = 0; uint32_t address_binding_tmr = 0; #if defined(INTRINSIC_REPORTING) uint32_t recipient_scan_tmr = 0; #endif #if defined(BACNET_TIME_MASTER) BACNET_DATE_TIME bdatetime; #endif #if defined(BAC_UCI) int uciId = 0; const char *uciName; struct uci_context *ctx; #if defined(AI) time_t ucimodtime_bacnet_ai = 0; #endif #if defined(AO) time_t ucimodtime_bacnet_ao = 0; #endif #if defined(AV) time_t ucimodtime_bacnet_av = 0; #endif #if defined(BI) time_t ucimodtime_bacnet_bi = 0; #endif #if defined(BO) time_t ucimodtime_bacnet_bo = 0; #endif #if defined(BV) time_t ucimodtime_bacnet_bv = 0; #endif #if defined(MSI) time_t ucimodtime_bacnet_mi = 0; #endif #if defined(MSO) time_t ucimodtime_bacnet_mo = 0; #endif #if defined(MSV) time_t ucimodtime_bacnet_mv = 0; #endif int rewrite = 0; #endif int argi = 0; const char *filename = NULL; filename = filename_remove_path(argv[0]); for (argi = 1; argi < argc; argi++) { if (strcmp(argv[argi], "--help") == 0) { print_usage(filename); print_help(filename); return 0; } if (strcmp(argv[argi], "--version") == 0) { printf("%s %s\n", filename, BACNET_VERSION_TEXT); printf("Copyright (C) 2014 by Steve Karg and others.\n" "This is free software; see the source for copying conditions.\n" "There is NO warranty; not even for MERCHANTABILITY or\n" "FITNESS FOR A PARTICULAR PURPOSE.\n"); return 0; } } #if defined(BAC_UCI) char *pEnv = getenv("UCI_SECTION"); if (!pEnv) { pEnv = "0"; #if PRINT_ENABLED fprintf(stderr, "Failed to getenv(UCI_SECTION)\n"); } else { fprintf(stderr, "load config file bacnet_dev %s\n",pEnv); #endif } ctx = ucix_init("bacnet_dev"); #if PRINT_ENABLED if(!ctx) fprintf(stderr, "Failed to load config file bacnet_dev\n"); #endif uciId = ucix_get_option_int(ctx, "bacnet_dev", pEnv, "Id", 0); uciName = ucix_get_option(ctx, "bacnet_dev", pEnv, "name"); if(ctx) ucix_cleanup(ctx); if (uciId != 0) { Device_Set_Object_Instance_Number(uciId); if (uciName) #if PRINT_ENABLED fprintf(stderr, "BACnet Device Name: %s\n", uciName); #endif Device_Object_Name_ANSI_Init(uciName); } else { #endif /* defined(BAC_UCI) */ /* allow the device ID to be set */ if (argc > 1) { Device_Set_Object_Instance_Number(strtol(argv[1], NULL, 0)); } if (argc > 2) { Device_Object_Name_ANSI_Init(argv[2]); } #if defined(BAC_UCI) } #if defined(AI) char ai_path[128]; struct stat ai_s; snprintf(ai_path, sizeof(ai_path), "/etc/config/bacnet_ai"); if( stat(ai_path, &ai_s) > -1 ) ucimodtime_bacnet_ai = ai_s.st_mtime; #endif #if defined(AO) char ao_path[128]; struct stat ao_s; snprintf(ao_path, sizeof(ao_path), "/etc/config/bacnet_ao"); if( stat(ao_path, &ao_s) > -1 ) ucimodtime_bacnet_ao = ao_s.st_mtime; #endif #if defined(AV) char av_path[128]; struct stat av_s; snprintf(av_path, sizeof(av_path), "/etc/config/bacnet_av"); if( stat(av_path, &av_s) > -1 ) ucimodtime_bacnet_av = av_s.st_mtime; #endif #if defined(BI) char bi_path[128]; struct stat bi_s; snprintf(bi_path, sizeof(bi_path), "/etc/config/bacnet_bi"); if( stat(bi_path, &bi_s) > -1 ) ucimodtime_bacnet_bi = bi_s.st_mtime; #endif #if defined(BO) char bo_path[128]; struct stat bo_s; snprintf(bo_path, sizeof(bo_path), "/etc/config/bacnet_bo"); if( stat(bo_path, &bo_s) > -1 ) ucimodtime_bacnet_bo = bo_s.st_mtime; #endif #if defined(BV) char bv_path[128]; struct stat bv_s; snprintf(bv_path, sizeof(bv_path), "/etc/config/bacnet_bv"); if( stat(bv_path, &bv_s) > -1 ) ucimodtime_bacnet_bv = bv_s.st_mtime; #endif #if defined(MSI) char msi_path[128]; struct stat msi_s; snprintf(msi_path, sizeof(msi_path), "/etc/config/bacnet_mi"); if( stat(msi_path, &msi_s) > -1 ) ucimodtime_bacnet_mi = msi_s.st_mtime; #endif #if defined(MSO) char mso_path[128]; struct stat mso_s; snprintf(mso_path, sizeof(mso_path), "/etc/config/bacnet_mo"); if( stat(mso_path, &mso_s) > -1 ) ucimodtime_bacnet_mo = mso_s.st_mtime; #endif #if defined(MSV) char msv_path[128]; struct stat msv_s; snprintf(msv_path, sizeof(msv_path), "/etc/config/bacnet_mv"); if( stat(msv_path, &msv_s) > -1 ) ucimodtime_bacnet_mv = msv_s.st_mtime; #endif #endif /* defined(BAC_UCI) */ #if PRINT_ENABLED printf("BACnet Server Demo\n" "BACnet Stack Version %s\n" "BACnet Device ID: %u\n" "Max APDU: %d\n", BACnet_Version, Device_Object_Instance_Number(), MAX_APDU); #endif /* load any static address bindings to show up in our device bindings list */ address_init(); Init_Service_Handlers(); dlenv_init(); atexit(datalink_cleanup); /* configure the timeout values */ last_seconds = time(NULL); /* broadcast an I-Am on startup */ Send_I_Am(&Handler_Transmit_Buffer[0]); /* loop forever */ for (;;) { /* input */ current_seconds = time(NULL); /* returns 0 bytes on timeout */ pdu_len = datalink_receive(&src, &Rx_Buf[0], MAX_MPDU, timeout); /* process */ if (pdu_len) { npdu_handler(&src, &Rx_Buf[0], pdu_len); } /* at least one second has passed */ elapsed_seconds = (uint32_t) (current_seconds - last_seconds); if (elapsed_seconds) { last_seconds = current_seconds; dcc_timer_seconds(elapsed_seconds); #if defined(BACDL_BIP) && BBMD_ENABLED bvlc_maintenance_timer(elapsed_seconds); #endif dlenv_maintenance_timer(elapsed_seconds); #if defined(LC) Load_Control_State_Machine_Handler(); #endif elapsed_milliseconds = elapsed_seconds * 1000; handler_cov_timer_seconds(elapsed_seconds); tsm_timer_milliseconds(elapsed_milliseconds); #if defined(TRENDLOG) trend_log_timer(elapsed_seconds); #endif #if defined(INTRINSIC_REPORTING) Device_local_reporting(); #endif #if defined(BACNET_TIME_MASTER) Device_getCurrentDateTime(&bdatetime); handler_timesync_task(&bdatetime); #endif } handler_cov_task(); /* scan cache address */ address_binding_tmr += elapsed_seconds; if (address_binding_tmr >= 60) { address_cache_timer(address_binding_tmr); address_binding_tmr = 0; } #if defined(INTRINSIC_REPORTING) /* try to find addresses of recipients */ recipient_scan_tmr += elapsed_seconds; if (recipient_scan_tmr >= NC_RESCAN_RECIPIENTS_SECS) { Notification_Class_find_recipient(); recipient_scan_tmr = 0; } #endif /* output */ #if defined(BAC_UCI) rewrite++; if (rewrite>100000) { #if PRINT_ENABLED printf("rewrite interval %i\n", rewrite); #endif rewrite=0; } #if defined(AI) /* update Analog Input from uci */ ucimodtime_bacnet_ai = uci_Update(ucimodtime_bacnet_ai,OBJECT_ANALOG_INPUT,rewrite); #endif #if defined(AO) /* update Analog Output from uci */ ucimodtime_bacnet_ao = uci_Update(ucimodtime_bacnet_ao,OBJECT_ANALOG_OUTPUT,rewrite); #endif #if defined(AV) /* update Analog Value from uci */ ucimodtime_bacnet_av = uci_Update(ucimodtime_bacnet_av,OBJECT_ANALOG_VALUE,rewrite); #endif #if defined(BI) /* update Binary Input from uci */ ucimodtime_bacnet_bi = uci_Update(ucimodtime_bacnet_bi,OBJECT_BINARY_INPUT,rewrite); #endif #if defined(BO) /* update Binary Output from uci */ ucimodtime_bacnet_bo = uci_Update(ucimodtime_bacnet_bo,OBJECT_BINARY_OUTPUT,rewrite); #endif #if defined(BV) /* update Binary Value from uci */ ucimodtime_bacnet_bv = uci_Update(ucimodtime_bacnet_bv,OBJECT_BINARY_VALUE,rewrite); #endif #if defined(MSI) /* update Multistate Input from uci */ ucimodtime_bacnet_mi = uci_Update(ucimodtime_bacnet_mi,OBJECT_MULTI_STATE_INPUT,rewrite); #endif #if defined(MSO) /* update Multistate Output from uci */ ucimodtime_bacnet_mo = uci_Update(ucimodtime_bacnet_mo,OBJECT_MULTI_STATE_OUTPUT,rewrite); #endif #if defined(MSV) /* update Multistate Value from uci */ ucimodtime_bacnet_mv = uci_Update(ucimodtime_bacnet_mv,OBJECT_MULTI_STATE_VALUE,rewrite); #endif #endif /* defined(BAC_UCI) */ /* blink LEDs, Turn on or off outputs, etc */ } return 0; }