1
0
mirror of https://github.com/stargieg/bacnet-stack synced 2025-10-19 23:25:23 +08:00

[r3164] esp32 support

This commit is contained in:
Steve Karg 2017-11-22 08:28:36 +01:00 committed by Patrick Grimm
parent 1172adba2c
commit fcded70c49
12 changed files with 5357 additions and 0 deletions

View File

@ -0,0 +1,36 @@
This directory is intended for the project specific (private) libraries.
PlatformIO will compile them to static libraries and link to executable file.
The source code of each library should be placed in separate directory, like
"lib/private_lib/[here are source files]".
For example, see how can be organized `Foo` and `Bar` libraries:
|--lib
| |--Bar
| | |--docs
| | |--examples
| | |--src
| | |- Bar.c
| | |- Bar.h
| |--Foo
| | |- Foo.c
| | |- Foo.h
| |- readme.txt --> THIS FILE
|- platformio.ini
|--src
|- main.c
Then in `src/main.c` you should use:
#include <Foo.h>
#include <Bar.h>
// rest H/C/CPP code
PlatformIO will find your libraries automatically, configure preprocessor's
include paths and build them.
More information about PlatformIO Library Dependency Finder
- http://docs.platformio.org/page/librarymanager/ldf.html

View File

@ -0,0 +1,19 @@
; PlatformIO Project Configuration File
;
; Build options: build flags, source filter
; Upload options: custom upload port, speed and extra flags
; Library options: dependencies, extra library storages
; Advanced options: extra scripting
;
; Please visit documentation for the other options and examples
; http://docs.platformio.org/page/projectconf.html
[env:esp32thing]
platform = espressif32
board = esp32thing
framework = espidf
upload_port = COM7
upload_speed = 1152000
monitor_baud = 115200

66
ports/esp32/readme.txt Normal file
View File

@ -0,0 +1,66 @@
Bacnet Server for Espressif ESP32
Steve Karg Bacnet stack using PlatformIO open source ecosystem for IoT development on VSCode or Atom
F. Chaxel 2017
TODO list :
(Install VSCode or Atom and add the PlatformIO extension)
Edit platformio.ini to adjust board, Com Port, ...
Goto lib/stack and copy the requested files from Steve code :
all .h from include directory (not all required by it's simple)
these .c files from src or demo/handlers
abort.c
address.c
apdu.c
bacaddr.c
bacapp.c
bacdcode.c
bacerror.c
bacint.c
bacreal.c
bacstr.c
bip.c
bvlc.c
cov.c
datetime.c
bacdevobjpropref.c
dcc.c
debug.c
h_cov.c
h_ucov.c
h_npdu.c
h_rp.c
h_rpm.c
h_whois.c
h_wp.c
iam.c
lighting.c
memcopy.c
noserv.c
npdu.c
proplist.c
reject.c
rp.c
rpm.c
s_iam.c
tsm.c
whois.c
wp.c
Modify
in config.h
MAX_TSM_TRANSACTIONS 255, set the value to 10 for instances
in main.c
wifi_config to fit your wifi network
BACNET_LED 5, set another IO number depending of your board
A lot of Warning will be issued at compile time due to the redefinition of BIT macros.
Could be removes by placing a #ifndef #BIT0 .. #endif arround the BIT macro in bits.h,
and moving to the top of include list
#include "datalink.h" in tsm.c, s_iam and in device.c
#include "net.h" in bip.c and in bip.h (redondant include in bip.c)
#include "bvlc.h" in bvlc.c

1472
ports/esp32/src/ai.c Normal file

File diff suppressed because it is too large Load Diff

174
ports/esp32/src/ai.h Normal file
View File

@ -0,0 +1,174 @@
/**************************************************************************
*
* Copyright (C) 2005 Steve Karg <skarg@users.sourceforge.net>
* Copyright (C) 2011 Krzysztof Malorny <malornykrzysztof@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*********************************************************************/
#ifndef AI_H
#define AI_H
#include <stdbool.h>
#include <stdint.h>
#include "bacdef.h"
#include "rp.h"
#include "wp.h"
#if defined(INTRINSIC_REPORTING)
#include "nc.h"
#include "getevent.h"
#include "alarm_ack.h"
#include "get_alarm_sum.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
typedef struct analog_input_descr {
unsigned Event_State:3;
float Present_Value;
BACNET_RELIABILITY Reliability;
bool Out_Of_Service;
uint8_t Units;
float Prior_Value;
float COV_Increment;
bool Changed;
#if defined(INTRINSIC_REPORTING)
uint32_t Time_Delay;
uint32_t Notification_Class;
float High_Limit;
float Low_Limit;
float Deadband;
unsigned Limit_Enable:2;
unsigned Event_Enable:3;
unsigned Notify_Type:1;
ACKED_INFO Acked_Transitions[MAX_BACNET_EVENT_TRANSITION];
BACNET_DATE_TIME Event_Time_Stamps[MAX_BACNET_EVENT_TRANSITION];
/* time to generate event notification */
uint32_t Remaining_Time_Delay;
/* AckNotification informations */
ACK_NOTIFICATION Ack_notify_data;
#endif
} ANALOG_INPUT_DESCR;
void Analog_Input_Property_Lists(
const int **pRequired,
const int **pOptional,
const int **pProprietary);
bool Analog_Input_Valid_Instance(
uint32_t object_instance);
unsigned Analog_Input_Count(
void);
uint32_t Analog_Input_Index_To_Instance(
unsigned index);
unsigned Analog_Input_Instance_To_Index(
uint32_t instance);
bool Analog_Input_Object_Instance_Add(
uint32_t instance);
bool Analog_Input_Object_Name(
uint32_t object_instance,
BACNET_CHARACTER_STRING * object_name);
bool Analog_Input_Name_Set(
uint32_t object_instance,
char *new_name);
char *Analog_Input_Description(
uint32_t instance);
bool Analog_Input_Description_Set(
uint32_t instance,
char *new_name);
bool Analog_Input_Units_Set(
uint32_t instance,
uint16_t units);
uint16_t Analog_Input_Units(
uint32_t instance);
int Analog_Input_Read_Property(
BACNET_READ_PROPERTY_DATA * rpdata);
bool Analog_Input_Write_Property(
BACNET_WRITE_PROPERTY_DATA * wp_data);
float Analog_Input_Present_Value(
uint32_t object_instance);
void Analog_Input_Present_Value_Set(
uint32_t object_instance,
float value);
bool Analog_Input_Out_Of_Service(
uint32_t object_instance);
void Analog_Input_Out_Of_Service_Set(
uint32_t object_instance,
bool oos_flag);
bool Analog_Input_Change_Of_Value(
uint32_t instance);
void Analog_Input_Change_Of_Value_Clear(
uint32_t instance);
bool Analog_Input_Encode_Value_List(
uint32_t object_instance,
BACNET_PROPERTY_VALUE * value_list);
float Analog_Input_COV_Increment(
uint32_t instance);
void Analog_Input_COV_Increment_Set(
uint32_t instance,
float value);
/* note: header of Intrinsic_Reporting function is required
even when INTRINSIC_REPORTING is not defined */
void Analog_Input_Intrinsic_Reporting(
uint32_t object_instance);
#if defined(INTRINSIC_REPORTING)
int Analog_Input_Event_Information(
unsigned index,
BACNET_GET_EVENT_INFORMATION_DATA * getevent_data);
int Analog_Input_Alarm_Ack(
BACNET_ALARM_ACK_DATA * alarmack_data,
BACNET_ERROR_CODE * error_code);
int Analog_Input_Alarm_Summary(
unsigned index,
BACNET_GET_ALARM_SUMMARY_DATA * getalarm_data);
#endif
bool Analog_Input_Create(
uint32_t object_instance);
bool Analog_Input_Delete(
uint32_t object_instance);
void Analog_Input_Cleanup(
void);
void Analog_Input_Init(
void);
#ifdef TEST
#include "ctest.h"
void testAnalogInput(
Test * pTest);
#endif
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif

View File

@ -0,0 +1,57 @@
//
// Copyleft F.Chaxel 2017
//
#include "esp_log.h"
#include "esp_wifi.h"
#include "lwip/sockets.h"
#include "lwip/netdb.h"
#include "bip.h"
long bip_getaddrbyname(
const char *host_name)
{
return 0;
}
void bip_set_interface(char *ifname)
{
}
void bip_cleanup (void)
{
close(bip_socket());
bip_set_socket(-1);
}
bool bip_init(char *ifname)
{
tcpip_adapter_ip_info_t ip_info = { 0 };
int value = 1;
tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_STA, &ip_info);
bip_set_interface(ifname);
bip_set_port(htons(0xBAC0));
bip_set_addr(ip_info.ip.addr);
bip_set_broadcast_addr((ip_info.ip.addr&ip_info.netmask.addr)|(~ip_info.netmask.addr));
int sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
struct sockaddr_in saddr = { 0 };
saddr.sin_family = PF_INET;
saddr.sin_port = htons(0xBAC0);
saddr.sin_addr.s_addr = htonl(INADDR_ANY);
bind(sock, (struct sockaddr *)&saddr, sizeof(struct sockaddr_in));
setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char *) &value, sizeof(value));
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &value, sizeof(value));
bip_set_socket(sock);
return true;
}

556
ports/esp32/src/bo.c Normal file
View File

@ -0,0 +1,556 @@
/**************************************************************************
*
* Copyright (C) 2005 Steve Karg <skarg@users.sourceforge.net>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*********************************************************************/
/* Binary Output Objects - customize for your use */
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include "bacdef.h"
#include "bacdcode.h"
#include "bacenum.h"
#include "bacapp.h"
#include "config.h" /* the custom stuff */
#include "rp.h"
#include "wp.h"
#include "bo.h"
#include "handlers.h"
#ifndef MAX_BINARY_OUTPUTS
#define MAX_BINARY_OUTPUTS 1
#endif
/* When all the priorities are level null, the present value returns */
/* the Relinquish Default value */
#define RELINQUISH_DEFAULT BINARY_INACTIVE
/* Here is our Priority Array.*/
static BACNET_BINARY_PV
Binary_Output_Level[MAX_BINARY_OUTPUTS][BACNET_MAX_PRIORITY];
/* Writable out-of-service allows others to play with our Present Value */
/* without changing the physical output */
static bool Out_Of_Service[MAX_BINARY_OUTPUTS];
/* These three arrays are used by the ReadPropertyMultiple handler */
static const int Binary_Output_Properties_Required[] = {
PROP_OBJECT_IDENTIFIER,
PROP_OBJECT_NAME,
PROP_OBJECT_TYPE,
PROP_PRESENT_VALUE,
PROP_STATUS_FLAGS,
PROP_EVENT_STATE,
PROP_OUT_OF_SERVICE,
PROP_POLARITY,
PROP_PRIORITY_ARRAY,
PROP_RELINQUISH_DEFAULT,
-1
};
static const int Binary_Output_Properties_Optional[] = {
PROP_DESCRIPTION,
PROP_ACTIVE_TEXT,
PROP_INACTIVE_TEXT,
-1
};
static const int Binary_Output_Properties_Proprietary[] = {
-1
};
void Binary_Output_Property_Lists(
const int **pRequired,
const int **pOptional,
const int **pProprietary)
{
if (pRequired)
*pRequired = Binary_Output_Properties_Required;
if (pOptional)
*pOptional = Binary_Output_Properties_Optional;
if (pProprietary)
*pProprietary = Binary_Output_Properties_Proprietary;
return;
}
void Binary_Output_Init(
void)
{
unsigned i, j;
static bool initialized = false;
if (!initialized) {
initialized = true;
/* initialize all the analog output priority arrays to NULL */
for (i = 0; i < MAX_BINARY_OUTPUTS; i++) {
for (j = 0; j < BACNET_MAX_PRIORITY; j++) {
Binary_Output_Level[i][j] = BINARY_NULL;
}
}
}
return;
}
/* we simply have 0-n object instances. Yours might be */
/* more complex, and then you need validate that the */
/* given instance exists */
bool Binary_Output_Valid_Instance(
uint32_t object_instance)
{
if (object_instance < MAX_BINARY_OUTPUTS)
return true;
return false;
}
/* we simply have 0-n object instances. Yours might be */
/* more complex, and then count how many you have */
unsigned Binary_Output_Count(
void)
{
return MAX_BINARY_OUTPUTS;
}
/* we simply have 0-n object instances. Yours might be */
/* more complex, and then you need to return the instance */
/* that correlates to the correct index */
uint32_t Binary_Output_Index_To_Instance(
unsigned index)
{
return index;
}
/* we simply have 0-n object instances. Yours might be */
/* more complex, and then you need to return the index */
/* that correlates to the correct instance number */
unsigned Binary_Output_Instance_To_Index(
uint32_t object_instance)
{
unsigned index = MAX_BINARY_OUTPUTS;
if (object_instance < MAX_BINARY_OUTPUTS)
index = object_instance;
return index;
}
BACNET_BINARY_PV Binary_Output_Present_Value(
uint32_t object_instance)
{
BACNET_BINARY_PV value = RELINQUISH_DEFAULT;
unsigned index = 0;
unsigned i = 0;
index = Binary_Output_Instance_To_Index(object_instance);
if (index < MAX_BINARY_OUTPUTS) {
for (i = 0; i < BACNET_MAX_PRIORITY; i++) {
if (Binary_Output_Level[index][i] != BINARY_NULL) {
value = Binary_Output_Level[index][i];
break;
}
}
}
return value;
}
bool Binary_Output_Out_Of_Service(
uint32_t object_instance)
{
bool value = false;
unsigned index = 0;
index = Binary_Output_Instance_To_Index(object_instance);
if (index < MAX_BINARY_OUTPUTS) {
value = Out_Of_Service[index];
}
return value;
}
/* note: the object name must be unique within this device */
bool Binary_Output_Object_Name(
uint32_t object_instance,
BACNET_CHARACTER_STRING * object_name)
{
static char text_string[32] = "";
bool status = false;
if (object_instance==0)
status=characterstring_init_ansi(object_name, "Led");
else
{
if (object_instance < MAX_BINARY_OUTPUTS) {
sprintf(text_string, "BINARY OUTPUT %lu",
(unsigned long) object_instance);
status = characterstring_init_ansi(object_name, text_string);
}
}
return status;
}
/* return apdu len, or BACNET_STATUS_ERROR on error */
int Binary_Output_Read_Property(
BACNET_READ_PROPERTY_DATA * rpdata)
{
int len = 0;
int apdu_len = 0; /* return value */
BACNET_BIT_STRING bit_string;
BACNET_CHARACTER_STRING char_string;
BACNET_BINARY_PV present_value = BINARY_INACTIVE;
BACNET_POLARITY polarity = POLARITY_NORMAL;
unsigned object_index = 0;
unsigned i = 0;
bool state = false;
uint8_t *apdu = NULL;
if ((rpdata == NULL) || (rpdata->application_data == NULL) ||
(rpdata->application_data_len == 0)) {
return 0;
}
apdu = rpdata->application_data;
switch (rpdata->object_property) {
case PROP_OBJECT_IDENTIFIER:
apdu_len =
encode_application_object_id(&apdu[0], OBJECT_BINARY_OUTPUT,
rpdata->object_instance);
break;
/* note: Name and Description don't have to be the same.
You could make Description writable and different */
case PROP_OBJECT_NAME:
case PROP_DESCRIPTION:
Binary_Output_Object_Name(rpdata->object_instance, &char_string);
apdu_len =
encode_application_character_string(&apdu[0], &char_string);
break;
case PROP_OBJECT_TYPE:
apdu_len =
encode_application_enumerated(&apdu[0], OBJECT_BINARY_OUTPUT);
break;
case PROP_PRESENT_VALUE:
present_value =
Binary_Output_Present_Value(rpdata->object_instance);
apdu_len = encode_application_enumerated(&apdu[0], present_value);
break;
case PROP_STATUS_FLAGS:
/* note: see the details in the standard on how to use these */
bitstring_init(&bit_string);
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false);
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
break;
case PROP_EVENT_STATE:
/* note: see the details in the standard on how to use this */
apdu_len =
encode_application_enumerated(&apdu[0], EVENT_STATE_NORMAL);
break;
case PROP_OUT_OF_SERVICE:
object_index =
Binary_Output_Instance_To_Index(rpdata->object_instance);
state = Out_Of_Service[object_index];
apdu_len = encode_application_boolean(&apdu[0], state);
break;
case PROP_POLARITY:
apdu_len = encode_application_enumerated(&apdu[0], polarity);
break;
case PROP_PRIORITY_ARRAY:
/* Array element zero is the number of elements in the array */
if (rpdata->array_index == 0)
apdu_len =
encode_application_unsigned(&apdu[0], BACNET_MAX_PRIORITY);
/* if no index was specified, then try to encode the entire list */
/* into one packet. */
else if (rpdata->array_index == BACNET_ARRAY_ALL) {
object_index =
Binary_Output_Instance_To_Index(rpdata->object_instance);
for (i = 0; i < BACNET_MAX_PRIORITY; i++) {
/* FIXME: check if we have room before adding it to APDU */
if (Binary_Output_Level[object_index][i] == BINARY_NULL)
len = encode_application_null(&apdu[apdu_len]);
else {
present_value = Binary_Output_Level[object_index][i];
len =
encode_application_enumerated(&apdu[apdu_len],
present_value);
}
/* add it if we have room */
if ((apdu_len + len) < MAX_APDU)
apdu_len += len;
else {
rpdata->error_code =
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
apdu_len = BACNET_STATUS_ABORT;
break;
}
}
} else {
object_index =
Binary_Output_Instance_To_Index(rpdata->object_instance);
if (rpdata->array_index <= BACNET_MAX_PRIORITY) {
if (Binary_Output_Level[object_index][rpdata->array_index -
1] == BINARY_NULL)
apdu_len = encode_application_null(&apdu[apdu_len]);
else {
present_value = Binary_Output_Level[object_index]
[rpdata->array_index - 1];
apdu_len =
encode_application_enumerated(&apdu[apdu_len],
present_value);
}
} else {
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
apdu_len = BACNET_STATUS_ERROR;
}
}
break;
case PROP_RELINQUISH_DEFAULT:
present_value = RELINQUISH_DEFAULT;
apdu_len = encode_application_enumerated(&apdu[0], present_value);
break;
case PROP_ACTIVE_TEXT:
characterstring_init_ansi(&char_string, "on");
apdu_len =
encode_application_character_string(&apdu[0], &char_string);
break;
case PROP_INACTIVE_TEXT:
characterstring_init_ansi(&char_string, "off");
apdu_len =
encode_application_character_string(&apdu[0], &char_string);
break;
default:
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
apdu_len = BACNET_STATUS_ERROR;
break;
}
/* only array properties can have array options */
if ((apdu_len >= 0) && (rpdata->object_property != PROP_PRIORITY_ARRAY) &&
(rpdata->array_index != BACNET_ARRAY_ALL)) {
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
apdu_len = BACNET_STATUS_ERROR;
}
return apdu_len;
}
/* returns true if successful */
bool Binary_Output_Write_Property(
BACNET_WRITE_PROPERTY_DATA * wp_data)
{
bool status = false; /* return value */
unsigned int object_index = 0;
unsigned int priority = 0;
BACNET_BINARY_PV level = BINARY_NULL;
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);
/* 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_PRIORITY_ARRAY) &&
(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 (wp_data->object_property) {
case PROP_PRESENT_VALUE:
if (value.tag == BACNET_APPLICATION_TAG_ENUMERATED) {
priority = wp_data->priority;
/* Command priority 6 is reserved for use by Minimum On/Off
algorithm and may not be used for other purposes in any
object. */
if (priority && (priority <= BACNET_MAX_PRIORITY) &&
(priority != 6 /* reserved */ ) &&
(value.type.Enumerated <= MAX_BINARY_PV)) {
level = (BACNET_BINARY_PV) value.type.Enumerated;
object_index =
Binary_Output_Instance_To_Index
(wp_data->object_instance);
priority--;
Binary_Output_Level[object_index][priority] = level;
/* Note: you could set the physical output here if we
are the highest priority.
However, if Out of Service is TRUE, then don't set the
physical output. This comment may apply to the
main loop (i.e. check out of service before changing output) */
status = true;
} else if (priority == 6) {
/* Command priority 6 is reserved for use by Minimum On/Off
algorithm and may not be used for other purposes in any
object. */
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
} else {
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
}
} else {
status =
WPValidateArgType(&value, BACNET_APPLICATION_TAG_NULL,
&wp_data->error_class, &wp_data->error_code);
if (status) {
level = BINARY_NULL;
object_index =
Binary_Output_Instance_To_Index
(wp_data->object_instance);
priority = wp_data->priority;
if (priority && (priority <= BACNET_MAX_PRIORITY)) {
priority--;
Binary_Output_Level[object_index][priority] = level;
/* Note: you could set the physical output here to the next
highest priority, or to the relinquish default if no
priorities are set.
However, if Out of Service is TRUE, then don't set the
physical output. This comment may apply to the
main loop (i.e. check out of service before changing output) */
} else {
status = false;
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
}
}
}
break;
case PROP_OUT_OF_SERVICE:
status =
WPValidateArgType(&value, BACNET_APPLICATION_TAG_BOOLEAN,
&wp_data->error_class, &wp_data->error_code);
if (status) {
object_index =
Binary_Output_Instance_To_Index(wp_data->object_instance);
Out_Of_Service[object_index] =
value.type.Boolean;
}
break;
case PROP_OBJECT_IDENTIFIER:
case PROP_OBJECT_NAME:
case PROP_OBJECT_TYPE:
case PROP_STATUS_FLAGS:
case PROP_RELIABILITY:
case PROP_EVENT_STATE:
case PROP_POLARITY:
case PROP_PRIORITY_ARRAY:
case PROP_RELINQUISH_DEFAULT:
case PROP_ACTIVE_TEXT:
case PROP_INACTIVE_TEXT:
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;
}
#ifdef TEST
#include <assert.h>
#include <string.h>
#include "ctest.h"
bool WPValidateArgType(
BACNET_APPLICATION_DATA_VALUE * pValue,
uint8_t ucExpectedTag,
BACNET_ERROR_CLASS * pErrorClass,
BACNET_ERROR_CODE * pErrorCode)
{
pValue = pValue;
ucExpectedTag = ucExpectedTag;
pErrorClass = pErrorClass;
pErrorCode = pErrorCode;
return false;
}
void testBinaryOutput(
Test * pTest)
{
uint8_t apdu[MAX_APDU] = { 0 };
int len = 0;
uint32_t len_value = 0;
uint8_t tag_number = 0;
uint16_t decoded_type = 0;
uint32_t decoded_instance = 0;
BACNET_READ_PROPERTY_DATA rpdata;
Binary_Output_Init();
rpdata.application_data = &apdu[0];
rpdata.application_data_len = sizeof(apdu);
rpdata.object_type = OBJECT_BINARY_OUTPUT;
rpdata.object_instance = 1;
rpdata.object_property = PROP_OBJECT_IDENTIFIER;
rpdata.array_index = BACNET_ARRAY_ALL;
len = Binary_Output_Read_Property(&rpdata);
ct_test(pTest, len != 0);
len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value);
ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID);
len = decode_object_id(&apdu[len], &decoded_type, &decoded_instance);
ct_test(pTest, decoded_type == rpdata.object_type);
ct_test(pTest, decoded_instance == rpdata.object_instance);
return;
}
#ifdef TEST_BINARY_OUTPUT
int main(
void)
{
Test *pTest;
bool rc;
pTest = ct_create("BACnet Binary Output", NULL);
/* individual tests */
rc = ct_addTestFunction(pTest, testBinaryOutput);
assert(rc);
ct_setStream(pTest, stdout);
ct_run(pTest);
(void) ct_report(pTest);
ct_destroy(pTest);
return 0;
}
#endif /* TEST_BINARY_INPUT */
#endif /* TEST */

141
ports/esp32/src/bo.h Normal file
View File

@ -0,0 +1,141 @@
/**************************************************************************
*
* Copyright (C) 2005 Steve Karg <skarg@users.sourceforge.net>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*********************************************************************/
#ifndef BO_H
#define BO_H
#include <stdbool.h>
#include <stdint.h>
#include "bacdef.h"
#include "bacerror.h"
#include "rp.h"
#include "wp.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
void Binary_Output_Init(
void);
void Binary_Output_Property_Lists(
const int **pRequired,
const int **pOptional,
const int **pProprietary);
bool Binary_Output_Valid_Instance(
uint32_t object_instance);
unsigned Binary_Output_Count(
void);
uint32_t Binary_Output_Index_To_Instance(
unsigned index);
unsigned Binary_Output_Instance_To_Index(
uint32_t instance);
bool Binary_Output_Object_Instance_Add(
uint32_t instance);
bool Binary_Output_Object_Name(
uint32_t object_instance,
BACNET_CHARACTER_STRING * object_name);
bool Binary_Output_Name_Set(
uint32_t object_instance,
char *new_name);
char *Binary_Output_Description(
uint32_t instance);
bool Binary_Output_Description_Set(
uint32_t instance,
char *new_name);
char *Binary_Output_Inactive_Text(
uint32_t instance);
bool Binary_Output_Inactive_Text_Set(
uint32_t instance,
char *new_name);
char *Binary_Output_Active_Text(
uint32_t instance);
bool Binary_Output_Active_Text_Set(
uint32_t instance,
char *new_name);
BACNET_BINARY_PV Binary_Output_Present_Value(
uint32_t instance);
bool Binary_Output_Present_Value_Set(
uint32_t instance,
BACNET_BINARY_PV binary_value,
unsigned priority);
bool Binary_Output_Present_Value_Relinquish(
uint32_t instance,
unsigned priority);
unsigned Binary_Output_Present_Value_Priority(
uint32_t object_instance);
BACNET_POLARITY Binary_Output_Polarity(
uint32_t instance);
bool Binary_Output_Polarity_Set(
uint32_t object_instance,
BACNET_POLARITY polarity);
bool Binary_Output_Out_Of_Service(
uint32_t instance);
void Binary_Output_Out_Of_Service_Set(
uint32_t object_instance,
bool value);
BACNET_BINARY_PV Binary_Output_Relinquish_Default(
uint32_t object_instance);
bool Binary_Output_Relinquish_Default_Set(
uint32_t object_instance,
BACNET_BINARY_PV value);
bool Binary_Output_Encode_Value_List(
uint32_t object_instance,
BACNET_PROPERTY_VALUE * value_list);
bool Binary_Output_Change_Of_Value(
uint32_t instance);
void Binary_Output_Change_Of_Value_Clear(
uint32_t instance);
int Binary_Output_Read_Property(
BACNET_READ_PROPERTY_DATA * rpdata);
bool Binary_Output_Write_Property(
BACNET_WRITE_PROPERTY_DATA * wp_data);
bool Binary_Output_Create(
uint32_t object_instance);
bool Binary_Output_Delete(
uint32_t object_instance);
void Binary_Output_Cleanup(
void);
#ifdef TEST
#include "ctest.h"
void testBinaryOutput(
Test * pTest);
#endif
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif

2020
ports/esp32/src/device.c Normal file

File diff suppressed because it is too large Load Diff

476
ports/esp32/src/device.h Normal file
View File

@ -0,0 +1,476 @@
/**************************************************************************
*
* Copyright (C) 2005 Steve Karg <skarg@users.sourceforge.net>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*********************************************************************/
/** @file device.h Defines functions for handling all BACnet objects belonging
* to a BACnet device, as well as Device-specific properties. */
#ifndef DEVICE_H
#define DEVICE_H
#include <stdbool.h>
#include <stdint.h>
#include "bacdef.h"
#include "bacenum.h"
#include "wp.h"
#include "rd.h"
#include "rp.h"
#include "rpm.h"
#include "readrange.h"
/** Called so a BACnet object can perform any necessary initialization.
* @ingroup ObjHelpers
*/
typedef void (
*object_init_function) (
void);
/** Counts the number of objects of this type.
* @ingroup ObjHelpers
* @return Count of implemented objects of this type.
*/
typedef unsigned (
*object_count_function) (
void);
/** Maps an object index position to its corresponding BACnet object instance number.
* @ingroup ObjHelpers
* @param index [in] The index of the object, in the array of objects of its type.
* @return The BACnet object instance number to be used in a BACNET_OBJECT_ID.
*/
typedef uint32_t(
*object_index_to_instance_function)
(
unsigned index);
/** Provides the BACnet Object_Name for a given object instance of this type.
* @ingroup ObjHelpers
* @param object_instance [in] The object instance number to be looked up.
* @param object_name [in,out] Pointer to a character_string structure that
* will hold a copy of the object name if this is a valid object_instance.
* @return True if the object_instance is valid and object_name has been
* filled with a copy of the Object's name.
*/
typedef bool(
*object_name_function)
(
uint32_t object_instance,
BACNET_CHARACTER_STRING * object_name);
/** Look in the table of objects of this type, and see if this is a valid
* instance number.
* @ingroup ObjHelpers
* @param [in] The object instance number to be looked up.
* @return True if the object instance refers to a valid object of this type.
*/
typedef bool(
*object_valid_instance_function) (
uint32_t object_instance);
/** Helper function to step through an array of objects and find either the
* first one or the next one of a given type. Used to step through an array
* of objects which is not necessarily contiguious for each type i.e. the
* index for the 'n'th object of a given type is not necessarily 'n'.
* @ingroup ObjHelpers
* @param [in] The index of the current object or a value of ~0 to indicate
* start at the beginning.
* @return The index of the next object of the required type or ~0 (all bits
* == 1) to indicate no more objects found.
*/
typedef unsigned (
*object_iterate_function) (
unsigned current_index);
/** Look in the table of objects of this type, and get the COV Value List.
* @ingroup ObjHelpers
* @param [in] The object instance number to be looked up.
* @param [out] The value list
* @return True if the object instance supports this feature, and has changed.
*/
typedef bool(
*object_value_list_function) (
uint32_t object_instance,
BACNET_PROPERTY_VALUE * value_list);
/** Look in the table of objects for this instance to see if value changed.
* @ingroup ObjHelpers
* @param [in] The object instance number to be looked up.
* @return True if the object instance has changed.
*/
typedef bool(
*object_cov_function) (
uint32_t object_instance);
/** Look in the table of objects for this instance to clear the changed flag.
* @ingroup ObjHelpers
* @param [in] The object instance number to be looked up.
*/
typedef void (
*object_cov_clear_function) (
uint32_t object_instance);
/** Intrinsic Reporting funcionality.
* @ingroup ObjHelpers
* @param [in] Object instance.
*/
typedef void (
*object_intrinsic_reporting_function) (
uint32_t object_instance);
/** Defines the group of object helper functions for any supported Object.
* @ingroup ObjHelpers
* Each Object must provide some implementation of each of these helpers
* in order to properly support the handlers. Eg, the ReadProperty handler
* handler_read_property() relies on the instance of Object_Read_Property
* for each Object type, or configure the function as NULL.
* In both appearance and operation, this group of functions acts like
* they are member functions of a C++ Object base class.
*/
typedef struct object_functions {
BACNET_OBJECT_TYPE Object_Type;
object_init_function Object_Init;
object_count_function Object_Count;
object_index_to_instance_function Object_Index_To_Instance;
object_valid_instance_function Object_Valid_Instance;
object_name_function Object_Name;
read_property_function Object_Read_Property;
write_property_function Object_Write_Property;
rpm_property_lists_function Object_RPM_List;
rr_info_function Object_RR_Info;
object_iterate_function Object_Iterator;
object_value_list_function Object_Value_List;
object_cov_function Object_COV;
object_cov_clear_function Object_COV_Clear;
object_intrinsic_reporting_function Object_Intrinsic_Reporting;
} object_functions_t;
/* String Lengths - excluding any nul terminator */
#define MAX_DEV_NAME_LEN 32
#define MAX_DEV_LOC_LEN 64
#define MAX_DEV_MOD_LEN 32
#define MAX_DEV_VER_LEN 16
#define MAX_DEV_DESC_LEN 64
/** Structure to define the Object Properties common to all Objects. */
typedef struct commonBacObj_s {
/** The BACnet type of this object (ie, what class is this object from?).
* This property, of type BACnetObjectType, indicates membership in a
* particular object type class. Each inherited class will be of one type.
*/
BACNET_OBJECT_TYPE mObject_Type;
/** The instance number for this class instance. */
uint32_t Object_Instance_Number;
/** Object Name; must be unique.
* This property, of type CharacterString, shall represent a name for
* the object that is unique within the BACnet Device that maintains it.
*/
char Object_Name[MAX_DEV_NAME_LEN];
} COMMON_BAC_OBJECT;
/** Structure to define the Properties of Device Objects which distinguish
* one instance from another.
* This structure only defines fields for properties that are unique to
* a given Device object. The rest may be fixed in device.c or hard-coded
* into the read-property encoding.
* This may be useful for implementations which manage multiple Devices,
* eg, a Gateway.
*/
typedef struct devObj_s {
/** The BACnet Device Address for this device; ->len depends on DLL type. */
BACNET_ADDRESS bacDevAddr;
/** Structure for the Object Properties common to all Objects. */
COMMON_BAC_OBJECT bacObj;
/** Device Description. */
char Description[MAX_DEV_DESC_LEN];
/** The upcounter that shows if the Device ID or object structure has changed. */
uint32_t Database_Revision;
} DEVICE_OBJECT_DATA;
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
void Device_Init(
object_functions_t * object_table);
bool Device_Reinitialize(
BACNET_REINITIALIZE_DEVICE_DATA * rd_data);
bool Device_Reinitialize_State_Set(BACNET_REINITIALIZED_STATE state);
BACNET_REINITIALIZED_STATE Device_Reinitialized_State(
void);
rr_info_function Device_Objects_RR_Info(
BACNET_OBJECT_TYPE object_type);
void Device_getCurrentDateTime(
BACNET_DATE_TIME * DateTime);
int32_t Device_UTC_Offset(void);
void Device_UTC_Offset_Set(int16_t offset);
bool Device_Daylight_Savings_Status(void);
bool Device_Align_Intervals(void);
bool Device_Align_Intervals_Set(bool flag);
uint32_t Device_Time_Sync_Interval(void);
bool Device_Time_Sync_Interval_Set(uint32_t value);
uint32_t Device_Interval_Offset(void);
bool Device_Interval_Offset_Set(uint32_t value);
void Device_Property_Lists(
const int **pRequired,
const int **pOptional,
const int **pProprietary);
void Device_Objects_Property_List(
BACNET_OBJECT_TYPE object_type,
uint32_t object_instance,
struct special_property_list_t *pPropertyList);
/* functions to support COV */
bool Device_Encode_Value_List(
BACNET_OBJECT_TYPE object_type,
uint32_t object_instance,
BACNET_PROPERTY_VALUE * value_list);
bool Device_Value_List_Supported(
BACNET_OBJECT_TYPE object_type);
bool Device_COV(
BACNET_OBJECT_TYPE object_type,
uint32_t object_instance);
void Device_COV_Clear(
BACNET_OBJECT_TYPE object_type,
uint32_t object_instance);
uint32_t Device_Object_Instance_Number(
void);
bool Device_Set_Object_Instance_Number(
uint32_t object_id);
bool Device_Valid_Object_Instance_Number(
uint32_t object_id);
unsigned Device_Object_List_Count(
void);
bool Device_Object_List_Identifier(
uint32_t array_index,
int *object_type,
uint32_t * instance);
unsigned Device_Count(
void);
uint32_t Device_Index_To_Instance(
unsigned index);
bool Device_Object_Name(
uint32_t object_instance,
BACNET_CHARACTER_STRING * object_name);
bool Device_Set_Object_Name(
BACNET_CHARACTER_STRING * object_name);
/* Copy a child object name, given its ID. */
bool Device_Object_Name_Copy(
BACNET_OBJECT_TYPE object_type,
uint32_t object_instance,
BACNET_CHARACTER_STRING * object_name);
bool Device_Object_Name_ANSI_Init(const char * object_name);
char * Device_Object_Name_ANSI(void);
BACNET_DEVICE_STATUS Device_System_Status(
void);
int Device_Set_System_Status(
BACNET_DEVICE_STATUS status,
bool local);
const char *Device_Vendor_Name(
void);
uint16_t Device_Vendor_Identifier(
void);
void Device_Set_Vendor_Identifier(
uint16_t vendor_id);
const char *Device_Model_Name(
void);
bool Device_Set_Model_Name(
const char *name,
size_t length);
const char *Device_Firmware_Revision(
void);
const char *Device_Application_Software_Version(
void);
bool Device_Set_Application_Software_Version(
const char *name,
size_t length);
const char *Device_Description(
void);
bool Device_Set_Description(
const char *name,
size_t length);
const char *Device_Location(
void);
bool Device_Set_Location(
const char *name,
size_t length);
/* some stack-centric constant values - no set methods */
uint8_t Device_Protocol_Version(
void);
uint8_t Device_Protocol_Revision(
void);
BACNET_SEGMENTATION Device_Segmentation_Supported(
void);
uint32_t Device_Database_Revision(
void);
void Device_Set_Database_Revision(
uint32_t revision);
void Device_Inc_Database_Revision(
void);
bool Device_Valid_Object_Name(
BACNET_CHARACTER_STRING * object_name,
int *object_type,
uint32_t * object_instance);
bool Device_Valid_Object_Id(
int object_type,
uint32_t object_instance);
int Device_Read_Property(
BACNET_READ_PROPERTY_DATA * rpdata);
bool Device_Write_Property(
BACNET_WRITE_PROPERTY_DATA * wp_data);
bool DeviceGetRRInfo(
BACNET_READ_RANGE_DATA * pRequest, /* Info on the request */
RR_PROP_INFO * pInfo); /* Where to put the information */
int Device_Read_Property_Local(
BACNET_READ_PROPERTY_DATA * rpdata);
bool Device_Write_Property_Local(
BACNET_WRITE_PROPERTY_DATA * wp_data);
#if defined(INTRINSIC_REPORTING)
void Device_local_reporting(
void);
#endif
/* Prototypes for Routing functionality in the Device Object.
* Enable by defining BAC_ROUTING in config.h and including gw_device.c
* in the build (lib/Makefile).
*/
void Routing_Device_Init(
uint32_t first_object_instance);
uint16_t Add_Routed_Device(
uint32_t Object_Instance,
BACNET_CHARACTER_STRING * Object_Name,
const char *Description);
DEVICE_OBJECT_DATA *Get_Routed_Device_Object(
int idx);
BACNET_ADDRESS *Get_Routed_Device_Address(
int idx);
void routed_get_my_address(
BACNET_ADDRESS * my_address);
bool Routed_Device_Address_Lookup(
int idx,
uint8_t address_len,
uint8_t * mac_adress);
bool Routed_Device_GetNext(
BACNET_ADDRESS * dest,
int *DNET_list,
int *cursor);
bool Routed_Device_Is_Valid_Network(
uint16_t dest_net,
int *DNET_list);
uint32_t Routed_Device_Index_To_Instance(
unsigned index);
bool Routed_Device_Valid_Object_Instance_Number(
uint32_t object_id);
bool Routed_Device_Name(
uint32_t object_instance,
BACNET_CHARACTER_STRING * object_name);
uint32_t Routed_Device_Object_Instance_Number(
void);
bool Routed_Device_Set_Object_Instance_Number(
uint32_t object_id);
bool Routed_Device_Set_Object_Name(
uint8_t encoding,
const char *value,
size_t length);
bool Routed_Device_Set_Description(
const char *name,
size_t length);
void Routed_Device_Inc_Database_Revision(
void);
int Routed_Device_Service_Approval(
BACNET_CONFIRMED_SERVICE service,
int service_argument,
uint8_t * apdu_buff,
uint8_t invoke_id);
#ifdef __cplusplus
}
#endif /* __cplusplus */
/** @defgroup ObjFrmwk Object Framework
* The modules in this section describe the BACnet-stack's framework for
* BACnet-defined Objects (Device, Analog Input, etc). There are two submodules
* to describe this arrangement:
* - The "object helper functions" which provide C++-like common functionality
* to all supported object types.
* - The interface between the implemented Objects and the BAC-stack services,
* specifically the handlers, which are mediated through function calls to
* the Device object.
*//** @defgroup ObjHelpers Object Helper Functions
* @ingroup ObjFrmwk
* This section describes the function templates for the helper functions that
* provide common object support.
*//** @defgroup ObjIntf Handler-to-Object Interface Functions
* @ingroup ObjFrmwk
* This section describes the fairly limited set of functions that link the
* BAC-stack handlers to the BACnet Object instances. All of these calls are
* situated in the Device Object, which "knows" how to reach its child Objects.
*
* Most of these calls have a common operation:
* -# Call Device_Objects_Find_Functions( for the desired Object_Type )
* - Gets a pointer to the object_functions for this Type of Object.
* -# Call the Object's Object_Valid_Instance( for the desired object_instance )
* to make sure there is such an instance.
* -# Call the Object helper function needed by the handler,
* eg Object_Read_Property() for the RP handler.
*
*/
#endif

215
ports/esp32/src/main.c Normal file
View File

@ -0,0 +1,215 @@
//
// Copyleft F.Chaxel 2017
//
#include "config.h"
#include "txbuf.h"
#include "client.h"
#include "handlers.h"
#include "datalink.h"
#include "dcc.h"
#include "tsm.h"
// conflict filename address.h with another file in default include paths
#include "../lib/stack/address.h"
#include "bip.h"
#include "device.h"
#include "ai.h"
#include "bo.h"
#include "esp_log.h"
#include "esp_wifi.h"
#include "esp_event_loop.h"
#include "nvs_flash.h"
#include "driver/gpio.h"
#include "lwip/sockets.h"
#include "lwip/netdb.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
// hidden function not in any .h files
extern uint8_t temprature_sens_read();
extern uint32_t hall_sens_read();
// Wifi params
wifi_config_t wifi_config = {
.sta = {
.ssid = "myWifi",
.password = "myPass",
},
};
// GPIO 5 has a Led on Sparkfun ESP32 board
#define BACNET_LED 5
uint8_t Handler_Transmit_Buffer[MAX_PDU] = { 0 };
uint8_t Rx_Buf[MAX_MPDU] = { 0 };
EventGroupHandle_t wifi_event_group;
const static int CONNECTED_BIT = BIT0;
/* BACnet handler, stack init, IAm */
void StartBACnet()
{
/* we need to handle who-is to support dynamic device binding */
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is);
/* set the handler for all the services we don't implement */
/* It is required to send the proper reject message... */
apdu_set_unrecognized_service_handler_handler
(handler_unrecognized_service);
/* 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_READ_PROP_MULTIPLE,
handler_read_property_multiple);
apdu_set_confirmed_handler(SERVICE_CONFIRMED_WRITE_PROPERTY,
handler_write_property);
apdu_set_confirmed_handler(SERVICE_CONFIRMED_SUBSCRIBE_COV,
handler_cov_subscribe);
address_init();
bip_init(NULL);
Send_I_Am(&Handler_Transmit_Buffer[0]);
}
/* wifi events handler : start & stop bacnet with an event */
esp_err_t wifi_event_handler(void *ctx, system_event_t *event)
{
switch(event->event_id) {
case SYSTEM_EVENT_STA_START:
esp_wifi_connect();
break;
case SYSTEM_EVENT_STA_CONNECTED:
break ;
case SYSTEM_EVENT_STA_GOT_IP:
if (xEventGroupGetBits(wifi_event_group)!=CONNECTED_BIT)
{
xEventGroupSetBits(wifi_event_group, CONNECTED_BIT);
StartBACnet();
}
break;
case SYSTEM_EVENT_STA_DISCONNECTED:
/* This is a workaround as ESP32 WiFi libs don't currently
auto-reassociate. */
esp_wifi_connect();
xEventGroupClearBits(wifi_event_group, CONNECTED_BIT);
bip_cleanup();
break;
default:
break;
}
return ESP_OK;
}
/* tcpip & wifi station start */
void wifi_init_station(void)
{
tcpip_adapter_init();
wifi_event_group = xEventGroupCreate();
esp_event_loop_init(wifi_event_handler, NULL);
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
esp_wifi_init(&cfg);
esp_wifi_set_storage(WIFI_STORAGE_RAM);
esp_wifi_set_mode(WIFI_MODE_STA);
esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config);
esp_wifi_start() ;
}
/* setup gpio & nv flash, call wifi init code */
void setup()
{
gpio_pad_select_gpio(BACNET_LED);
gpio_set_direction(BACNET_LED, GPIO_MODE_OUTPUT);
gpio_set_level(BACNET_LED,0);
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES)
{
nvs_flash_erase();
ret = nvs_flash_init();
}
wifi_init_station();
}
/* Bacnet Task */
void BACnetTask(void *pvParameters)
{
uint16_t pdu_len = 0;
BACNET_ADDRESS src = {
0
};
unsigned timeout = 1;
// Init Bacnet objets dictionnary
Device_Init(NULL);
Device_Set_Object_Instance_Number(12);
setup();
uint32_t tickcount=xTaskGetTickCount();
for (;;)
{
vTaskDelay(10 / portTICK_PERIOD_MS); // could be remove to speed the code
// do nothing if not connected to wifi
xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT, false, true, portMAX_DELAY);
{
uint32_t newtick=xTaskGetTickCount();
// one second elapse at least (maybe much more if Wifi was deconnected for a long)
if ((newtick<tickcount)||((newtick-tickcount)>=configTICK_RATE_HZ))
{
tickcount=newtick;
dcc_timer_seconds(1);
bvlc_maintenance_timer(1);
handler_cov_timer_seconds(1);
tsm_timer_milliseconds(1000);
// Read analog values from internal sensors
Analog_Input_Present_Value_Set(0,temprature_sens_read());
Analog_Input_Present_Value_Set(1,hall_sens_read());
}
pdu_len = datalink_receive(&src, &Rx_Buf[0], MAX_MPDU, timeout);
if (pdu_len)
{
npdu_handler(&src, &Rx_Buf[0], pdu_len);
if(Binary_Output_Present_Value(0)==BINARY_ACTIVE)
gpio_set_level(BACNET_LED,1);
else
gpio_set_level(BACNET_LED,0);
}
handler_cov_task();
}
}
}
/* Entry point */
void app_main()
{
// Cannot run BACnet code here, the default stack size is to small : 4096 byte
xTaskCreate(
BACnetTask, /* Function to implement the task */
"BACnetTask", /* Name of the task */
10000, /* Stack size in words */
NULL, /* Task input parameter */
20, /* Priority of the task */
NULL); /* Task handle. */
}

125
ports/esp32/src/sdkconfig.h Normal file
View File

@ -0,0 +1,125 @@
/*
*
* Automatically generated file; DO NOT EDIT.
* Espressif IoT Development Framework Configuration
*
*/
#define CONFIG_GATTC_ENABLE 1
#define CONFIG_ESP32_PHY_MAX_TX_POWER 20
#define CONFIG_PHY_ENABLED 1
#define CONFIG_TRACEMEM_RESERVE_DRAM 0x0
#define CONFIG_FREERTOS_MAX_TASK_NAME_LEN 16
#define CONFIG_BLE_SMP_ENABLE 1
#define CONFIG_IPC_TASK_STACK_SIZE 1024
#define CONFIG_ESPTOOLPY_FLASHFREQ "40m"
#define CONFIG_NEWLIB_STDOUT_ADDCR 1
#define CONFIG_TASK_WDT_CHECK_IDLE_TASK 1
#define CONFIG_ESPTOOLPY_FLASHSIZE "2MB"
#define CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER 1
#define CONFIG_ETHERNET 1
#define CONFIG_INT_WDT 1
#define CONFIG_ESPTOOLPY_FLASHFREQ_40M 1
#define CONFIG_LOG_BOOTLOADER_LEVEL_INFO 1
#define CONFIG_ESPTOOLPY_FLASHSIZE_2MB 1
#define CONFIG_AWS_IOT_MQTT_PORT 8883
#define CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS 1
#define CONFIG_ESP32_WIFI_STATIC_RX_BUFFER_NUM 10
#define CONFIG_LOG_DEFAULT_LEVEL_INFO 1
#define CONFIG_BT_RESERVE_DRAM 0x10000
#define CONFIG_ESP32_PANIC_PRINT_REBOOT 1
#define CONFIG_CONSOLE_UART_BAUDRATE 115200
#define CONFIG_LWIP_MAX_SOCKETS 10
#define CONFIG_EMAC_TASK_PRIORITY 20
#define CONFIG_TIMER_TASK_STACK_DEPTH 2048
#define CONFIG_FATFS_CODEPAGE 1
#define CONFIG_ESP32_DEFAULT_CPU_FREQ_160 1
#define CONFIG_ULP_COPROC_RESERVE_MEM 0
#define CONFIG_ESPTOOLPY_BAUD 115200
#define CONFIG_INT_WDT_CHECK_CPU1 1
#define CONFIG_FLASHMODE_DIO 1
#define CONFIG_ESPTOOLPY_AFTER_RESET 1
#define CONFIG_TOOLPREFIX "xtensa-esp32-elf-"
#define CONFIG_FREERTOS_IDLE_TASK_STACKSIZE 1024
#define CONFIG_ESP32_WIFI_AMPDU_ENABLED 1
#define CONFIG_CONSOLE_UART_NUM 0
#define CONFIG_ESP32_RTC_CLOCK_SOURCE_INTERNAL_RC 1
#define CONFIG_ESPTOOLPY_BAUD_115200B 1
#define CONFIG_LWIP_THREAD_LOCAL_STORAGE_INDEX 0
#define CONFIG_FOUR_UNIVERSAL_MAC_ADDRESS 1
#define CONFIG_CONSOLE_UART_DEFAULT 1
#define CONFIG_MBEDTLS_SSL_MAX_CONTENT_LEN 16384
#define CONFIG_NUMBER_OF_UNIVERSAL_MAC_ADDRESS 4
#define CONFIG_ESPTOOLPY_FLASHSIZE_DETECT 1
#define CONFIG_ESP32_ENABLE_COREDUMP_TO_NONE 1
#define CONFIG_BTDM_CONTROLLER_RUN_CPU 0
#define CONFIG_TCPIP_TASK_STACK_SIZE 2560
#define CONFIG_TASK_WDT 1
#define CONFIG_MAIN_TASK_STACK_SIZE 4096
#define CONFIG_TASK_WDT_TIMEOUT_S 5
#define CONFIG_INT_WDT_TIMEOUT_MS 300
#define CONFIG_ESPTOOLPY_FLASHMODE "dio"
#define CONFIG_BTC_TASK_STACK_SIZE 3072
#define CONFIG_BLUEDROID_ENABLED 1
#define CONFIG_ESPTOOLPY_BEFORE "default_reset"
#define CONFIG_LOG_DEFAULT_LEVEL 3
#define CONFIG_FREERTOS_ASSERT_ON_UNTESTED_FUNCTION 1
#define CONFIG_TIMER_QUEUE_LENGTH 10
#define CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM 32
#define CONFIG_ESP32_PHY_MAX_WIFI_TX_POWER 20
#define CONFIG_ESP32_RTC_CLK_CAL_CYCLES 1024
#define CONFIG_ESP32_WIFI_NVS_ENABLED 1
#define CONFIG_AWS_IOT_SDK 1
#define CONFIG_DMA_RX_BUF_NUM 10
#define CONFIG_TCP_SYNMAXRTX 6
#define CONFIG_PYTHON "python"
#define CONFIG_ESP32_TIME_SYSCALL_USE_RTC_FRC1 1
#define CONFIG_ESPTOOLPY_COMPRESSED 1
#define CONFIG_PARTITION_TABLE_FILENAME "partitions_singleapp.csv"
#define CONFIG_LWIP_DHCP_MAX_NTP_SERVERS 1
#define CONFIG_PARTITION_TABLE_SINGLE_APP 1
#define CONFIG_WIFI_ENABLED 1
#define CONFIG_LWIP_DHCP_DOES_ARP_CHECK 1
#define CONFIG_SYSTEM_EVENT_TASK_STACK_SIZE 4096
#define CONFIG_ESP32_DEEP_SLEEP_WAKEUP_DELAY 2000
#define CONFIG_ESP32_APPTRACE_DEST_NONE 1
#define CONFIG_PARTITION_TABLE_CUSTOM_APP_BIN_OFFSET 0x10000
#define CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER_NUM 32
#define CONFIG_FATFS_CODEPAGE_ASCII 1
#define CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU1 1
#define CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ 160
#define CONFIG_FREERTOS_HZ 100
#define CONFIG_LOG_COLORS 1
#define CONFIG_ESP32_PHY_CALIBRATION_AND_DATA_STORAGE 1
#define CONFIG_FREERTOS_ASSERT_FAIL_ABORT 1
#define CONFIG_ESP32_XTAL_FREQ 0
#define CONFIG_MONITOR_BAUD_115200B 1
#define CONFIG_LOG_BOOTLOADER_LEVEL 3
#define CONFIG_SMP_ENABLE 1
#define CONFIG_ESPTOOLPY_BEFORE_RESET 1
#define CONFIG_ESPTOOLPY_BAUD_OTHER_VAL 115200
#define CONFIG_ESP32_XTAL_FREQ_AUTO 1
#define CONFIG_TCP_MAXRTX 12
#define CONFIG_ESPTOOLPY_AFTER "hard_reset"
#define CONFIG_DMA_TX_BUF_NUM 10
#define CONFIG_ESP32_DEBUG_OCDAWARE 1
#define CONFIG_TIMER_TASK_PRIORITY 1
#define CONFIG_BT_ENABLED 1
#define CONFIG_MONITOR_BAUD 115200
#define CONFIG_FREERTOS_CORETIMER_0 1
#define CONFIG_PARTITION_TABLE_CUSTOM_FILENAME "partitions.csv"
#define CONFIG_MBEDTLS_HAVE_TIME 1
#define CONFIG_FREERTOS_CHECK_STACKOVERFLOW_CANARY 1
#define CONFIG_GATTS_ENABLE 1
#define CONFIG_FREERTOS_ISR_STACKSIZE 1536
#define CONFIG_OPENSSL_ASSERT_DO_NOTHING 1
#define CONFIG_AWS_IOT_MQTT_HOST ""
#define CONFIG_SYSTEM_EVENT_QUEUE_SIZE 32
#define CONFIG_BT_ACL_CONNECTIONS 4
#define CONFIG_FATFS_MAX_LFN 255
#define CONFIG_ESP32_WIFI_TX_BUFFER_TYPE 1
#define CONFIG_APP_OFFSET 0x10000
#define CONFIG_MEMMAP_SMP 1
#define CONFIG_SPI_FLASH_ROM_DRIVER_PATCH 1
#define CONFIG_MONITOR_BAUD_OTHER_VAL 115200
#define CONFIG_ESPTOOLPY_PORT "/dev/ttyUSB0"
#define CONFIG_OPTIMIZATION_LEVEL_RELEASE 1