Removed file/folder
This commit is contained in:
@@ -1,4 +0,0 @@
|
||||
set print pretty on
|
||||
set print union on
|
||||
set print address on
|
||||
list
|
||||
Vendored
-1
@@ -1 +0,0 @@
|
||||
-kr -nut -nlp
|
||||
@@ -1,56 +0,0 @@
|
||||
all: readprop writeprop readfile writefile reinit server dcc whohas whois ucov timesync
|
||||
@echo "utilities are in the utils directory"
|
||||
|
||||
clean: \
|
||||
demo/readprop/Makefile \
|
||||
demo/writeprop/Makefile \
|
||||
demo/readfile/Makefile \
|
||||
demo/writefile/Makefile \
|
||||
demo/server/Makefile \
|
||||
demo/dcc/Makefile \
|
||||
demo/whohas/Makefile \
|
||||
demo/timesync/Makefile \
|
||||
demo/whois/Makefile
|
||||
( cd demo/readprop ; make clean )
|
||||
( cd demo/writeprop ; make clean )
|
||||
( cd demo/readfile ; make clean )
|
||||
( cd demo/writefile ; make clean )
|
||||
( cd demo/reinit ; make clean )
|
||||
( cd demo/server ; make clean )
|
||||
( cd demo/dcc ; make clean )
|
||||
( cd demo/whohas ; make clean )
|
||||
( cd demo/timesync ; make clean )
|
||||
( cd demo/whois ; make clean )
|
||||
|
||||
readprop: demo/readprop/Makefile
|
||||
( cd demo/readprop ; make clean ; make ; cp bacrp ../../utils )
|
||||
|
||||
writeprop: demo/writeprop/Makefile
|
||||
( cd demo/writeprop ; make clean ; make ; cp bacwp ../../utils )
|
||||
|
||||
readfile: demo/readfile/Makefile
|
||||
( cd demo/readfile ; make clean ; make ; cp bacarf ../../utils )
|
||||
|
||||
writefile: demo/writefile/Makefile
|
||||
( cd demo/writefile ; make clean ; make ; cp bacawf ../../utils )
|
||||
|
||||
reinit: demo/reinit/Makefile
|
||||
( cd demo/reinit ; make clean ; make ; cp bacrd ../../utils )
|
||||
|
||||
server: demo/server/Makefile
|
||||
( cd demo/server ; make clean ; make ; cp bacserv ../../utils )
|
||||
|
||||
dcc: demo/dcc/Makefile
|
||||
( cd demo/dcc ; make clean ; make ; cp bacdcc ../../utils )
|
||||
|
||||
whohas: demo/whohas/Makefile
|
||||
( cd demo/whohas ; make clean ; make ; cp bacwh ../../utils )
|
||||
|
||||
timesync: demo/timesync/Makefile
|
||||
( cd demo/timesync ; make clean ; make ; cp bacts ../../utils )
|
||||
|
||||
ucov: demo/ucov/Makefile
|
||||
( cd demo/ucov ; make clean ; make ; cp bacucov ../../utils )
|
||||
|
||||
whois: demo/whois/Makefile
|
||||
( cd demo/whois ; make clean ; make ; cp bacwi ../../utils )
|
||||
@@ -1,195 +0,0 @@
|
||||
/*####COPYRIGHTBEGIN####
|
||||
-------------------------------------------
|
||||
Copyright (C) 2005 Steve Karg
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to:
|
||||
The Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330
|
||||
Boston, MA 02111-1307, USA.
|
||||
|
||||
As a special exception, if other files instantiate templates or
|
||||
use macros or inline functions from this file, or you compile
|
||||
this file and link it with other works to produce a work based
|
||||
on this file, this file does not by itself cause the resulting
|
||||
work to be covered by the GNU General Public License. However
|
||||
the source code for this file must still be made available in
|
||||
accordance with section (3) of the GNU General Public License.
|
||||
|
||||
This exception does not invalidate any other reasons why a work
|
||||
based on this file might be covered by the GNU General Public
|
||||
License.
|
||||
-------------------------------------------
|
||||
####COPYRIGHTEND####*/
|
||||
#include <stdint.h>
|
||||
#include "bacenum.h"
|
||||
#include "bacdcode.h"
|
||||
#include "bacdef.h"
|
||||
|
||||
/* encode service */
|
||||
int abort_encode_apdu(uint8_t * apdu,
|
||||
uint8_t invoke_id, uint8_t abort_reason, bool server)
|
||||
{
|
||||
int apdu_len = 0; /* total length of the apdu, return value */
|
||||
|
||||
if (apdu) {
|
||||
if (server)
|
||||
apdu[0] = PDU_TYPE_ABORT | 1;
|
||||
else
|
||||
apdu[0] = PDU_TYPE_ABORT;
|
||||
apdu[1] = invoke_id;
|
||||
apdu[2] = abort_reason;
|
||||
apdu_len = 3;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
/* decode the service request only */
|
||||
int abort_decode_service_request(uint8_t * apdu,
|
||||
unsigned apdu_len, uint8_t * invoke_id, uint8_t * abort_reason)
|
||||
{
|
||||
int len = 0;
|
||||
|
||||
if (apdu_len) {
|
||||
if (invoke_id)
|
||||
*invoke_id = apdu[0];
|
||||
if (abort_reason)
|
||||
*abort_reason = apdu[1];
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include "ctest.h"
|
||||
|
||||
/* decode the whole APDU - mainly used for unit testing */
|
||||
int abort_decode_apdu(uint8_t * apdu,
|
||||
unsigned apdu_len, uint8_t * invoke_id, uint8_t * abort_reason,
|
||||
bool * server)
|
||||
{
|
||||
int len = 0;
|
||||
|
||||
if (!apdu)
|
||||
return -1;
|
||||
/* optional checking - most likely was already done prior to this call */
|
||||
if (apdu_len) {
|
||||
if ((apdu[0] & 0xF0) != PDU_TYPE_ABORT)
|
||||
return -1;
|
||||
if (apdu[0] & 1)
|
||||
*server = true;
|
||||
else
|
||||
*server = false;
|
||||
if (apdu_len > 1) {
|
||||
len = abort_decode_service_request(&apdu[1],
|
||||
apdu_len - 1, invoke_id, abort_reason);
|
||||
}
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
void testAbortAPDU(Test * pTest,
|
||||
uint8_t invoke_id, uint8_t abort_reason, bool server)
|
||||
{
|
||||
uint8_t apdu[480] = { 0 };
|
||||
int len = 0;
|
||||
int apdu_len = 0;
|
||||
uint8_t test_invoke_id = 0;
|
||||
uint8_t test_abort_reason = 0;
|
||||
bool test_server = false;
|
||||
|
||||
len = abort_encode_apdu(&apdu[0], invoke_id, abort_reason, server);
|
||||
apdu_len = len;
|
||||
ct_test(pTest, len != 0);
|
||||
len = abort_decode_apdu(&apdu[0],
|
||||
apdu_len, &test_invoke_id, &test_abort_reason, &test_server);
|
||||
ct_test(pTest, len != -1);
|
||||
ct_test(pTest, test_invoke_id == invoke_id);
|
||||
ct_test(pTest, test_abort_reason == abort_reason);
|
||||
ct_test(pTest, test_server == server);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void testAbort(Test * pTest)
|
||||
{
|
||||
uint8_t apdu[480] = { 0 };
|
||||
int len = 0;
|
||||
int apdu_len = 0;
|
||||
uint8_t invoke_id = 0;
|
||||
uint8_t test_invoke_id = 0;
|
||||
uint8_t abort_reason = 0;
|
||||
uint8_t test_abort_reason = 0;
|
||||
bool server = false;
|
||||
bool test_server = false;
|
||||
|
||||
len = abort_encode_apdu(&apdu[0], invoke_id, abort_reason, server);
|
||||
ct_test(pTest, len != 0);
|
||||
apdu_len = len;
|
||||
len = abort_decode_apdu(&apdu[0],
|
||||
apdu_len, &test_invoke_id, &test_abort_reason, &test_server);
|
||||
ct_test(pTest, len != -1);
|
||||
ct_test(pTest, test_invoke_id == invoke_id);
|
||||
ct_test(pTest, test_abort_reason == abort_reason);
|
||||
ct_test(pTest, test_server == server);
|
||||
|
||||
/* change type to get negative response */
|
||||
apdu[0] = PDU_TYPE_REJECT;
|
||||
len = abort_decode_apdu(&apdu[0],
|
||||
apdu_len, &test_invoke_id, &test_abort_reason, &test_server);
|
||||
ct_test(pTest, len == -1);
|
||||
|
||||
/* test NULL APDU */
|
||||
len = abort_decode_apdu(NULL,
|
||||
apdu_len, &test_invoke_id, &test_abort_reason, &test_server);
|
||||
ct_test(pTest, len == -1);
|
||||
|
||||
/* force a zero length */
|
||||
len = abort_decode_apdu(&apdu[0],
|
||||
0, &test_invoke_id, &test_abort_reason, &test_server);
|
||||
ct_test(pTest, len == 0);
|
||||
|
||||
/* check them all... */
|
||||
for (invoke_id = 0; invoke_id < 255; invoke_id++) {
|
||||
for (abort_reason = 0; abort_reason < 255; abort_reason++) {
|
||||
testAbortAPDU(pTest, invoke_id, abort_reason, false);
|
||||
testAbortAPDU(pTest, invoke_id, abort_reason, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef TEST_ABORT
|
||||
int main(void)
|
||||
{
|
||||
Test *pTest;
|
||||
bool rc;
|
||||
|
||||
pTest = ct_create("BACnet Abort", NULL);
|
||||
/* individual tests */
|
||||
rc = ct_addTestFunction(pTest, testAbort);
|
||||
assert(rc);
|
||||
|
||||
ct_setStream(pTest, stdout);
|
||||
ct_run(pTest);
|
||||
(void) ct_report(pTest);
|
||||
ct_destroy(pTest);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* TEST_ABORT */
|
||||
#endif /* TEST */
|
||||
@@ -1,62 +0,0 @@
|
||||
/*####COPYRIGHTBEGIN####
|
||||
-------------------------------------------
|
||||
Copyright (C) 2005 Steve Karg
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to:
|
||||
The Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330
|
||||
Boston, MA 02111-1307, USA.
|
||||
|
||||
As a special exception, if other files instantiate templates or
|
||||
use macros or inline functions from this file, or you compile
|
||||
this file and link it with other works to produce a work based
|
||||
on this file, this file does not by itself cause the resulting
|
||||
work to be covered by the GNU General Public License. However
|
||||
the source code for this file must still be made available in
|
||||
accordance with section (3) of the GNU General Public License.
|
||||
|
||||
This exception does not invalidate any other reasons why a work
|
||||
based on this file might be covered by the GNU General Public
|
||||
License.
|
||||
-------------------------------------------
|
||||
####COPYRIGHTEND####*/
|
||||
#ifndef ABORT_H
|
||||
#define ABORT_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
int abort_encode_apdu(uint8_t * apdu,
|
||||
uint8_t invoke_id, uint8_t abort_reason, bool server);
|
||||
|
||||
int abort_decode_service_request(uint8_t * apdu,
|
||||
unsigned apdu_len, uint8_t * invoke_id, uint8_t * abort_reason);
|
||||
|
||||
#ifdef TEST
|
||||
#include "ctest.h"
|
||||
int abort_decode_apdu(uint8_t * apdu,
|
||||
unsigned apdu_len, uint8_t * invoke_id, uint8_t * abort_reason,
|
||||
bool * server);
|
||||
|
||||
void testAbort(Test * pTest);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
@@ -1,34 +0,0 @@
|
||||
#Makefile to build test case
|
||||
CC = gcc
|
||||
BASEDIR = .
|
||||
#CFLAGS = -Wall -I.
|
||||
# -g for debugging with gdb
|
||||
#CFLAGS = -Wall -I. -g
|
||||
CFLAGS = -Wall -I. -Itest -DTEST -DTEST_ABORT -g
|
||||
|
||||
SRCS = bacdcode.c \
|
||||
bacstr.c \
|
||||
bigend.c \
|
||||
abort.c \
|
||||
test/ctest.c
|
||||
|
||||
OBJS = ${SRCS:.c=.o}
|
||||
|
||||
TARGET = abort
|
||||
|
||||
all: ${TARGET}
|
||||
|
||||
${TARGET}: ${OBJS}
|
||||
${CC} -o $@ ${OBJS}
|
||||
|
||||
.c.o:
|
||||
${CC} -c ${CFLAGS} $*.c -o $@
|
||||
|
||||
depend:
|
||||
rm -f .depend
|
||||
${CC} -MM ${CFLAGS} *.c >> .depend
|
||||
|
||||
clean:
|
||||
rm -rf core ${TARGET} $(OBJS) *.bak *.1 *.ini
|
||||
|
||||
include: .depend
|
||||
@@ -1,366 +0,0 @@
|
||||
/*####COPYRIGHTBEGIN####
|
||||
-------------------------------------------
|
||||
Copyright (C) 2004 Steve Karg
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to:
|
||||
The Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330
|
||||
Boston, MA 02111-1307, USA.
|
||||
|
||||
As a special exception, if other files instantiate templates or
|
||||
use macros or inline functions from this file, or you compile
|
||||
this file and link it with other works to produce a work based
|
||||
on this file, this file does not by itself cause the resulting
|
||||
work to be covered by the GNU General Public License. However
|
||||
the source code for this file must still be made available in
|
||||
accordance with section (3) of the GNU General Public License.
|
||||
|
||||
This exception does not invalidate any other reasons why a work
|
||||
based on this file might be covered by the GNU General Public
|
||||
License.
|
||||
-------------------------------------------
|
||||
####COPYRIGHTEND####*/
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include "config.h"
|
||||
#include "address.h"
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
|
||||
/* This module is used to handle the address binding that */
|
||||
/* occurs in BACnet. A device id is bound to a MAC address. */
|
||||
/* The normal method is using Who-Is, and using the data from I-Am */
|
||||
|
||||
static struct Address_Cache_Entry {
|
||||
bool valid;
|
||||
bool bind_request;
|
||||
uint32_t device_id;
|
||||
unsigned max_apdu;
|
||||
BACNET_ADDRESS address;
|
||||
} Address_Cache[MAX_ADDRESS_CACHE];
|
||||
|
||||
void address_copy(BACNET_ADDRESS * dest, BACNET_ADDRESS * src)
|
||||
{
|
||||
unsigned i = 0; /* counter */
|
||||
|
||||
if (dest && src) {
|
||||
for (i = 0; i < MAX_MAC_LEN; i++) {
|
||||
dest->mac[i] = src->mac[i];
|
||||
}
|
||||
dest->mac_len = src->mac_len;
|
||||
dest->net = src->net;
|
||||
dest->len = src->len;
|
||||
for (i = 0; i < MAX_MAC_LEN; i++) {
|
||||
dest->adr[i] = src->adr[i];
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void address_remove_device(uint32_t device_id)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < MAX_ADDRESS_CACHE; i++) {
|
||||
if ((Address_Cache[i].valid ||
|
||||
Address_Cache[i].bind_request) &&
|
||||
(Address_Cache[i].device_id == device_id)) {
|
||||
Address_Cache[i].valid = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void address_init(void)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < MAX_ADDRESS_CACHE; i++) {
|
||||
Address_Cache[i].valid = false;
|
||||
Address_Cache[i].bind_request = false;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
bool address_get_by_device(uint32_t device_id,
|
||||
unsigned *max_apdu, BACNET_ADDRESS * src)
|
||||
{
|
||||
unsigned i;
|
||||
bool found = false; /* return value */
|
||||
|
||||
for (i = 0; i < MAX_ADDRESS_CACHE; i++) {
|
||||
if (Address_Cache[i].valid &&
|
||||
(Address_Cache[i].device_id == device_id)) {
|
||||
address_copy(src, &Address_Cache[i].address);
|
||||
*max_apdu = Address_Cache[i].max_apdu;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
void address_add(uint32_t device_id,
|
||||
unsigned max_apdu, BACNET_ADDRESS * src)
|
||||
{
|
||||
unsigned i;
|
||||
bool found = false; /* return value */
|
||||
|
||||
/* existing device - update address */
|
||||
for (i = 0; i < MAX_ADDRESS_CACHE; i++) {
|
||||
if (Address_Cache[i].valid &&
|
||||
(Address_Cache[i].device_id == device_id)) {
|
||||
address_copy(&Address_Cache[i].address, src);
|
||||
Address_Cache[i].max_apdu = max_apdu;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* new device */
|
||||
if (!found) {
|
||||
for (i = 0; i < MAX_ADDRESS_CACHE; i++) {
|
||||
if (!Address_Cache[i].valid) {
|
||||
Address_Cache[i].valid = true;
|
||||
Address_Cache[i].device_id = device_id;
|
||||
Address_Cache[i].max_apdu = max_apdu;
|
||||
address_copy(&Address_Cache[i].address, src);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* returns true if device is already bound */
|
||||
/* also returns the address and max apdu if already bound */
|
||||
bool address_bind_request(uint32_t device_id,
|
||||
unsigned *max_apdu, BACNET_ADDRESS * src)
|
||||
{
|
||||
unsigned i;
|
||||
bool found = false; /* return value */
|
||||
|
||||
/* existing device - update address */
|
||||
for (i = 0; i < MAX_ADDRESS_CACHE; i++) {
|
||||
if (Address_Cache[i].valid &&
|
||||
(Address_Cache[i].device_id == device_id)) {
|
||||
found = true;
|
||||
address_copy(src, &Address_Cache[i].address);
|
||||
*max_apdu = Address_Cache[i].max_apdu;
|
||||
break;
|
||||
}
|
||||
/* already have a bind request active for this puppy */
|
||||
else if (Address_Cache[i].bind_request &&
|
||||
(Address_Cache[i].device_id == device_id)) {
|
||||
return found;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
for (i = 0; i < MAX_ADDRESS_CACHE; i++) {
|
||||
if (!(Address_Cache[i].bind_request || Address_Cache[i].valid)) {
|
||||
Address_Cache[i].bind_request = true;
|
||||
Address_Cache[i].device_id = device_id;
|
||||
/* now would be a good time to do a Who-Is request */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
void address_add_binding(uint32_t device_id,
|
||||
unsigned max_apdu, BACNET_ADDRESS * src)
|
||||
{
|
||||
unsigned i;
|
||||
bool found = false; /* return value */
|
||||
|
||||
/* existing device - update address */
|
||||
for (i = 0; i < MAX_ADDRESS_CACHE; i++) {
|
||||
if (Address_Cache[i].valid &&
|
||||
(Address_Cache[i].device_id == device_id)) {
|
||||
address_copy(&Address_Cache[i].address, src);
|
||||
Address_Cache[i].max_apdu = max_apdu;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* add new device - but only if bind requested */
|
||||
if (!found) {
|
||||
for (i = 0; i < MAX_ADDRESS_CACHE; i++) {
|
||||
if (!Address_Cache[i].valid && Address_Cache[i].bind_request) {
|
||||
Address_Cache[i].valid = true;
|
||||
Address_Cache[i].bind_request = false;
|
||||
Address_Cache[i].device_id = device_id;
|
||||
Address_Cache[i].max_apdu = max_apdu;
|
||||
address_copy(&Address_Cache[i].address, src);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
bool address_get_by_index(unsigned index,
|
||||
uint32_t * device_id, unsigned *max_apdu, BACNET_ADDRESS * src)
|
||||
{
|
||||
bool found = false; /* return value */
|
||||
|
||||
if (index < MAX_ADDRESS_CACHE) {
|
||||
if (Address_Cache[index].valid) {
|
||||
address_copy(src, &Address_Cache[index].address);
|
||||
*device_id = Address_Cache[index].device_id;
|
||||
*max_apdu = Address_Cache[index].max_apdu;
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
unsigned address_count(void)
|
||||
{
|
||||
unsigned i;
|
||||
unsigned count = 0; /* return value */
|
||||
|
||||
for (i = 0; i < MAX_ADDRESS_CACHE; i++) {
|
||||
if (Address_Cache[i].valid)
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
bool address_match(BACNET_ADDRESS * dest, BACNET_ADDRESS * src)
|
||||
{
|
||||
unsigned i;
|
||||
unsigned max_len;
|
||||
bool match = true; /* return value */
|
||||
|
||||
if (dest->mac_len != src->mac_len)
|
||||
match = false;
|
||||
max_len = dest->mac_len;
|
||||
if (max_len > MAX_MAC_LEN)
|
||||
max_len = MAX_MAC_LEN;
|
||||
for (i = 0; i < max_len; i++) {
|
||||
if (dest->mac[i] != src->mac[i])
|
||||
match = false;
|
||||
}
|
||||
if (dest->net != src->net)
|
||||
match = false;
|
||||
if (dest->len != src->len)
|
||||
match = false;
|
||||
max_len = dest->len;
|
||||
if (max_len > MAX_MAC_LEN)
|
||||
max_len = MAX_MAC_LEN;
|
||||
for (i = 0; i < max_len; i++) {
|
||||
if (dest->adr[i] != src->adr[i])
|
||||
match = false;
|
||||
}
|
||||
|
||||
return match;
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include "ctest.h"
|
||||
|
||||
static void set_address(unsigned index, BACNET_ADDRESS * dest)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < MAX_MAC_LEN; i++) {
|
||||
dest->mac[i] = index;
|
||||
}
|
||||
dest->mac_len = MAX_MAC_LEN;
|
||||
dest->net = 7;
|
||||
dest->len = MAX_MAC_LEN;
|
||||
for (i = 0; i < MAX_MAC_LEN; i++) {
|
||||
dest->adr[i] = index;
|
||||
}
|
||||
}
|
||||
|
||||
void testAddress(Test * pTest)
|
||||
{
|
||||
unsigned i, count;
|
||||
BACNET_ADDRESS src;
|
||||
uint32_t device_id = 0;
|
||||
unsigned max_apdu = 480;
|
||||
BACNET_ADDRESS test_address;
|
||||
uint32_t test_device_id = 0;
|
||||
unsigned test_max_apdu = 0;
|
||||
|
||||
for (i = 0; i < MAX_ADDRESS_CACHE; i++) {
|
||||
set_address(i, &src);
|
||||
device_id = i * 255;
|
||||
address_add(device_id, max_apdu, &src);
|
||||
count = address_count();
|
||||
ct_test(pTest, count == (i + 1));
|
||||
}
|
||||
|
||||
for (i = 0; i < MAX_ADDRESS_CACHE; i++) {
|
||||
device_id = i * 255;
|
||||
ct_test(pTest, address_get_by_device(device_id, &test_max_apdu,
|
||||
&test_address));
|
||||
set_address(i, &src);
|
||||
ct_test(pTest, test_max_apdu == max_apdu);
|
||||
ct_test(pTest, address_match(&test_address, &src));
|
||||
ct_test(pTest, address_get_by_index(i, &test_device_id,
|
||||
&test_max_apdu, &test_address));
|
||||
ct_test(pTest, test_device_id == device_id);
|
||||
ct_test(pTest, test_max_apdu == max_apdu);
|
||||
ct_test(pTest, address_match(&test_address, &src));
|
||||
ct_test(pTest, address_count() == MAX_ADDRESS_CACHE);
|
||||
}
|
||||
|
||||
for (i = 0; i < MAX_ADDRESS_CACHE; i++) {
|
||||
device_id = i * 255;
|
||||
address_remove_device(device_id);
|
||||
ct_test(pTest, !address_get_by_device(device_id, &test_max_apdu,
|
||||
&test_address));
|
||||
count = address_count();
|
||||
ct_test(pTest, count == (MAX_ADDRESS_CACHE - i - 1));
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef TEST_ADDRESS
|
||||
int main(void)
|
||||
{
|
||||
Test *pTest;
|
||||
bool rc;
|
||||
|
||||
pTest = ct_create("BACnet Address", NULL);
|
||||
/* individual tests */
|
||||
rc = ct_addTestFunction(pTest, testAddress);
|
||||
assert(rc);
|
||||
|
||||
ct_setStream(pTest, stdout);
|
||||
ct_run(pTest);
|
||||
(void) ct_report(pTest);
|
||||
ct_destroy(pTest);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* TEST_ADDRESS */
|
||||
#endif /* TEST */
|
||||
@@ -1,74 +0,0 @@
|
||||
/*####COPYRIGHTBEGIN####
|
||||
-------------------------------------------
|
||||
Copyright (C) 2004 Steve Karg
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to:
|
||||
The Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330
|
||||
Boston, MA 02111-1307, USA.
|
||||
|
||||
As a special exception, if other files instantiate templates or
|
||||
use macros or inline functions from this file, or you compile
|
||||
this file and link it with other works to produce a work based
|
||||
on this file, this file does not by itself cause the resulting
|
||||
work to be covered by the GNU General Public License. However
|
||||
the source code for this file must still be made available in
|
||||
accordance with section (3) of the GNU General Public License.
|
||||
|
||||
This exception does not invalidate any other reasons why a work
|
||||
based on this file might be covered by the GNU General Public
|
||||
License.
|
||||
-------------------------------------------
|
||||
####COPYRIGHTEND####*/
|
||||
#ifndef ADDRESS_H
|
||||
#define ADDRESS_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "bacdef.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
void address_init(void);
|
||||
|
||||
void address_copy(BACNET_ADDRESS * dest, BACNET_ADDRESS * src);
|
||||
|
||||
void address_add(uint32_t device_id,
|
||||
unsigned max_apdu, BACNET_ADDRESS * src);
|
||||
|
||||
void address_remove_device(uint32_t device_id);
|
||||
|
||||
bool address_get_by_device(uint32_t device_id,
|
||||
unsigned *max_apdu, BACNET_ADDRESS * src);
|
||||
|
||||
bool address_get_by_index(unsigned index,
|
||||
uint32_t * device_id, unsigned *max_apdu, BACNET_ADDRESS * src);
|
||||
|
||||
unsigned address_count(void);
|
||||
|
||||
bool address_match(BACNET_ADDRESS * dest, BACNET_ADDRESS * src);
|
||||
|
||||
bool address_bind_request(uint32_t device_id,
|
||||
unsigned *max_apdu, BACNET_ADDRESS * src);
|
||||
|
||||
void address_add_binding(uint32_t device_id,
|
||||
unsigned max_apdu, BACNET_ADDRESS * src);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
@@ -1,31 +0,0 @@
|
||||
#Makefile to build test case
|
||||
CC = gcc
|
||||
BASEDIR = .
|
||||
#CFLAGS = -Wall -I.
|
||||
# -g for debugging with gdb
|
||||
#CFLAGS = -Wall -I. -g
|
||||
CFLAGS = -Wall -I. -Itest -DTEST -DTEST_ADDRESS -g
|
||||
|
||||
SRCS = address.c \
|
||||
test/ctest.c
|
||||
|
||||
OBJS = ${SRCS:.c=.o}
|
||||
|
||||
TARGET = address
|
||||
|
||||
all: ${TARGET}
|
||||
|
||||
${TARGET}: ${OBJS}
|
||||
${CC} -o $@ ${OBJS}
|
||||
|
||||
.c.o:
|
||||
${CC} -c ${CFLAGS} $*.c -o $@
|
||||
|
||||
depend:
|
||||
rm -f .depend
|
||||
${CC} -MM ${CFLAGS} *.c >> .depend
|
||||
|
||||
clean:
|
||||
rm -rf core ${TARGET} $(OBJS) *.bak *.1 *.ini
|
||||
|
||||
include: .depend
|
||||
@@ -1,455 +0,0 @@
|
||||
/*####COPYRIGHTBEGIN####
|
||||
-------------------------------------------
|
||||
Copyright (C) 2005 Steve Karg
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to:
|
||||
The Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330
|
||||
Boston, MA 02111-1307, USA.
|
||||
|
||||
As a special exception, if other files instantiate templates or
|
||||
use macros or inline functions from this file, or you compile
|
||||
this file and link it with other works to produce a work based
|
||||
on this file, this file does not by itself cause the resulting
|
||||
work to be covered by the GNU General Public License. However
|
||||
the source code for this file must still be made available in
|
||||
accordance with section (3) of the GNU General Public License.
|
||||
|
||||
This exception does not invalidate any other reasons why a work
|
||||
based on this file might be covered by the GNU General Public
|
||||
License.
|
||||
-------------------------------------------
|
||||
####COPYRIGHTEND####*/
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "bits.h"
|
||||
#include "apdu.h"
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "bacenum.h"
|
||||
#include "tsm.h"
|
||||
#include "dcc.h"
|
||||
#include "iam.h"
|
||||
|
||||
/* a simple table for crossing the services supported */
|
||||
static BACNET_SERVICES_SUPPORTED
|
||||
confirmed_service_supported[MAX_BACNET_CONFIRMED_SERVICE] = {
|
||||
SERVICE_SUPPORTED_ACKNOWLEDGE_ALARM,
|
||||
SERVICE_SUPPORTED_CONFIRMED_COV_NOTIFICATION,
|
||||
SERVICE_SUPPORTED_CONFIRMED_EVENT_NOTIFICATION,
|
||||
SERVICE_SUPPORTED_GET_ALARM_SUMMARY,
|
||||
SERVICE_SUPPORTED_GET_ENROLLMENT_SUMMARY,
|
||||
SERVICE_SUPPORTED_SUBSCRIBE_COV,
|
||||
SERVICE_SUPPORTED_ATOMIC_READ_FILE,
|
||||
SERVICE_SUPPORTED_ATOMIC_WRITE_FILE,
|
||||
SERVICE_SUPPORTED_ADD_LIST_ELEMENT,
|
||||
SERVICE_SUPPORTED_REMOVE_LIST_ELEMENT,
|
||||
SERVICE_SUPPORTED_CREATE_OBJECT,
|
||||
SERVICE_SUPPORTED_DELETE_OBJECT,
|
||||
SERVICE_SUPPORTED_READ_PROPERTY,
|
||||
SERVICE_SUPPORTED_READ_PROPERTY_CONDITIONAL,
|
||||
SERVICE_SUPPORTED_READ_PROPERTY_MULTIPLE,
|
||||
SERVICE_SUPPORTED_WRITE_PROPERTY,
|
||||
SERVICE_SUPPORTED_WRITE_PROPERTY_MULTIPLE,
|
||||
SERVICE_SUPPORTED_DEVICE_COMMUNICATION_CONTROL,
|
||||
SERVICE_SUPPORTED_PRIVATE_TRANSFER,
|
||||
SERVICE_SUPPORTED_TEXT_MESSAGE,
|
||||
SERVICE_SUPPORTED_REINITIALIZE_DEVICE,
|
||||
SERVICE_SUPPORTED_VT_OPEN,
|
||||
SERVICE_SUPPORTED_VT_CLOSE,
|
||||
SERVICE_SUPPORTED_VT_DATA,
|
||||
SERVICE_SUPPORTED_AUTHENTICATE,
|
||||
SERVICE_SUPPORTED_REQUEST_KEY,
|
||||
SERVICE_SUPPORTED_READ_RANGE,
|
||||
SERVICE_SUPPORTED_LIFE_SAFETY_OPERATION,
|
||||
SERVICE_SUPPORTED_SUBSCRIBE_COV_PROPERTY,
|
||||
SERVICE_SUPPORTED_GET_EVENT_INFORMATION
|
||||
};
|
||||
|
||||
/* a simple table for crossing the services supported */
|
||||
static BACNET_SERVICES_SUPPORTED
|
||||
unconfirmed_service_supported[MAX_BACNET_UNCONFIRMED_SERVICE] = {
|
||||
SERVICE_SUPPORTED_I_AM,
|
||||
SERVICE_SUPPORTED_I_HAVE,
|
||||
SERVICE_SUPPORTED_UNCONFIRMED_COV_NOTIFICATION,
|
||||
SERVICE_SUPPORTED_UNCONFIRMED_EVENT_NOTIFICATION,
|
||||
SERVICE_SUPPORTED_UNCONFIRMED_PRIVATE_TRANSFER,
|
||||
SERVICE_SUPPORTED_UNCONFIRMED_TEXT_MESSAGE,
|
||||
SERVICE_SUPPORTED_TIME_SYNCHRONIZATION,
|
||||
SERVICE_SUPPORTED_WHO_HAS,
|
||||
SERVICE_SUPPORTED_WHO_IS,
|
||||
SERVICE_SUPPORTED_UTC_TIME_SYNCHRONIZATION
|
||||
};
|
||||
|
||||
/* Confirmed Function Handlers */
|
||||
/* If they are not set, they are handled by a reject message */
|
||||
static confirmed_function Confirmed_Function[MAX_BACNET_CONFIRMED_SERVICE];
|
||||
|
||||
void apdu_set_confirmed_handler(BACNET_CONFIRMED_SERVICE service_choice,
|
||||
confirmed_function pFunction)
|
||||
{
|
||||
if (service_choice < MAX_BACNET_CONFIRMED_SERVICE)
|
||||
Confirmed_Function[service_choice] = pFunction;
|
||||
}
|
||||
|
||||
/* Allow the APDU handler to automatically reject */
|
||||
static confirmed_function Unrecognized_Service_Handler;
|
||||
|
||||
void apdu_set_unrecognized_service_handler_handler(confirmed_function
|
||||
pFunction)
|
||||
{
|
||||
Unrecognized_Service_Handler = pFunction;
|
||||
}
|
||||
|
||||
/* Unconfirmed Function Handlers */
|
||||
/* If they are not set, they are not handled */
|
||||
static unconfirmed_function
|
||||
Unconfirmed_Function[MAX_BACNET_UNCONFIRMED_SERVICE] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
void apdu_set_unconfirmed_handler(BACNET_UNCONFIRMED_SERVICE
|
||||
service_choice, unconfirmed_function pFunction)
|
||||
{
|
||||
if (service_choice < MAX_BACNET_UNCONFIRMED_SERVICE)
|
||||
Unconfirmed_Function[service_choice] = pFunction;
|
||||
}
|
||||
|
||||
bool apdu_service_supported(BACNET_SERVICES_SUPPORTED service_supported)
|
||||
{
|
||||
int i = 0;
|
||||
bool status = false;
|
||||
bool found = false;
|
||||
|
||||
if (service_supported < MAX_BACNET_SERVICES_SUPPORTED) {
|
||||
/* is it a confirmed service? */
|
||||
for (i = 0; i < MAX_BACNET_CONFIRMED_SERVICE; i++) {
|
||||
if (confirmed_service_supported[i] == service_supported) {
|
||||
if (Confirmed_Function[i] != NULL)
|
||||
status = true;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
/* is it an unconfirmed service? */
|
||||
for (i = 0; i < MAX_BACNET_UNCONFIRMED_SERVICE; i++) {
|
||||
if (unconfirmed_service_supported[i] == service_supported) {
|
||||
if (Unconfirmed_Function[i] != NULL)
|
||||
status = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Confirmed ACK Function Handlers */
|
||||
static void *Confirmed_ACK_Function[MAX_BACNET_CONFIRMED_SERVICE];
|
||||
|
||||
void apdu_set_confirmed_simple_ack_handler(BACNET_CONFIRMED_SERVICE
|
||||
service_choice, confirmed_simple_ack_function pFunction)
|
||||
{
|
||||
switch (service_choice) {
|
||||
case SERVICE_CONFIRMED_ACKNOWLEDGE_ALARM:
|
||||
case SERVICE_CONFIRMED_COV_NOTIFICATION:
|
||||
case SERVICE_CONFIRMED_EVENT_NOTIFICATION:
|
||||
case SERVICE_CONFIRMED_SUBSCRIBE_COV:
|
||||
case SERVICE_CONFIRMED_SUBSCRIBE_COV_PROPERTY:
|
||||
case SERVICE_CONFIRMED_LIFE_SAFETY_OPERATION:
|
||||
/* Object Access Services */
|
||||
case SERVICE_CONFIRMED_ADD_LIST_ELEMENT:
|
||||
case SERVICE_CONFIRMED_REMOVE_LIST_ELEMENT:
|
||||
case SERVICE_CONFIRMED_DELETE_OBJECT:
|
||||
case SERVICE_CONFIRMED_WRITE_PROPERTY:
|
||||
case SERVICE_CONFIRMED_WRITE_PROPERTY_MULTIPLE:
|
||||
/* Remote Device Management Services */
|
||||
case SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL:
|
||||
case SERVICE_CONFIRMED_TEXT_MESSAGE:
|
||||
case SERVICE_CONFIRMED_REINITIALIZE_DEVICE:
|
||||
/* Virtual Terminal Services */
|
||||
case SERVICE_CONFIRMED_VT_CLOSE:
|
||||
/* Security Services */
|
||||
case SERVICE_CONFIRMED_REQUEST_KEY:
|
||||
Confirmed_ACK_Function[service_choice] = (void *) pFunction;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void apdu_set_confirmed_ack_handler(BACNET_CONFIRMED_SERVICE
|
||||
service_choice, confirmed_ack_function pFunction)
|
||||
{
|
||||
switch (service_choice) {
|
||||
case SERVICE_CONFIRMED_GET_ALARM_SUMMARY:
|
||||
case SERVICE_CONFIRMED_GET_ENROLLMENT_SUMMARY:
|
||||
case SERVICE_CONFIRMED_GET_EVENT_INFORMATION:
|
||||
/* File Access Services */
|
||||
case SERVICE_CONFIRMED_ATOMIC_READ_FILE:
|
||||
case SERVICE_CONFIRMED_ATOMIC_WRITE_FILE:
|
||||
/* Object Access Services */
|
||||
case SERVICE_CONFIRMED_CREATE_OBJECT:
|
||||
case SERVICE_CONFIRMED_READ_PROPERTY:
|
||||
case SERVICE_CONFIRMED_READ_PROPERTY_CONDITIONAL:
|
||||
case SERVICE_CONFIRMED_READ_PROPERTY_MULTIPLE:
|
||||
case SERVICE_CONFIRMED_READ_RANGE:
|
||||
/* Remote Device Management Services */
|
||||
case SERVICE_CONFIRMED_PRIVATE_TRANSFER:
|
||||
/* Virtual Terminal Services */
|
||||
case SERVICE_CONFIRMED_VT_OPEN:
|
||||
case SERVICE_CONFIRMED_VT_DATA:
|
||||
/* Security Services */
|
||||
case SERVICE_CONFIRMED_AUTHENTICATE:
|
||||
Confirmed_ACK_Function[service_choice] = (void *) pFunction;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static error_function Error_Function[MAX_BACNET_CONFIRMED_SERVICE];
|
||||
|
||||
void apdu_set_error_handler(BACNET_CONFIRMED_SERVICE service_choice,
|
||||
error_function pFunction)
|
||||
{
|
||||
if (service_choice < MAX_BACNET_CONFIRMED_SERVICE)
|
||||
Error_Function[service_choice] = pFunction;
|
||||
}
|
||||
|
||||
static abort_function Abort_Function;
|
||||
|
||||
void apdu_set_abort_handler(abort_function pFunction)
|
||||
{
|
||||
Abort_Function = pFunction;
|
||||
}
|
||||
|
||||
static reject_function Reject_Function;
|
||||
|
||||
void apdu_set_reject_handler(reject_function pFunction)
|
||||
{
|
||||
Reject_Function = pFunction;
|
||||
}
|
||||
|
||||
uint16_t apdu_decode_confirmed_service_request(uint8_t * apdu, /* APDU data */
|
||||
uint16_t apdu_len,
|
||||
BACNET_CONFIRMED_SERVICE_DATA * service_data,
|
||||
uint8_t * service_choice,
|
||||
uint8_t ** service_request, uint16_t * service_request_len)
|
||||
{
|
||||
uint16_t len = 0; /* counts where we are in PDU */
|
||||
|
||||
service_data->segmented_message = (apdu[0] & BIT3) ? true : false;
|
||||
service_data->more_follows = (apdu[0] & BIT2) ? true : false;
|
||||
service_data->segmented_response_accepted =
|
||||
(apdu[0] & BIT1) ? true : false;
|
||||
service_data->max_segs = decode_max_segs(apdu[1]);
|
||||
service_data->max_resp = decode_max_apdu(apdu[1]);
|
||||
service_data->invoke_id = apdu[2];
|
||||
len = 3;
|
||||
if (service_data->segmented_message) {
|
||||
service_data->sequence_number = apdu[len++];
|
||||
service_data->proposed_window_number = apdu[len++];
|
||||
}
|
||||
*service_choice = apdu[len++];
|
||||
*service_request = &apdu[len];
|
||||
*service_request_len = apdu_len - len;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
void apdu_handler(BACNET_ADDRESS * src, uint8_t * apdu, /* APDU data */
|
||||
uint16_t apdu_len)
|
||||
{
|
||||
BACNET_CONFIRMED_SERVICE_DATA service_data = { 0 };
|
||||
BACNET_CONFIRMED_SERVICE_ACK_DATA service_ack_data = { 0 };
|
||||
uint8_t invoke_id = 0;
|
||||
uint8_t service_choice = 0;
|
||||
uint8_t *service_request = NULL;
|
||||
uint16_t service_request_len = 0;
|
||||
uint16_t len = 0; /* counts where we are in PDU */
|
||||
uint8_t tag_number = 0;
|
||||
uint32_t len_value = 0;
|
||||
int error_code = 0;
|
||||
int error_class = 0;
|
||||
uint8_t reason = 0;
|
||||
bool server = false;
|
||||
|
||||
if (apdu) {
|
||||
/* PDU Type */
|
||||
switch (apdu[0] & 0xF0) {
|
||||
case PDU_TYPE_CONFIRMED_SERVICE_REQUEST:
|
||||
len = apdu_decode_confirmed_service_request(&apdu[0], /* APDU data */
|
||||
apdu_len,
|
||||
&service_data,
|
||||
&service_choice, &service_request, &service_request_len);
|
||||
/* When network communications are completely disabled,
|
||||
only DeviceCommunicationControl and ReinitializeDevice APDUs
|
||||
shall be processed and no messages shall be initiated. */
|
||||
if (dcc_communication_disabled() &&
|
||||
((service_choice !=
|
||||
SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL)
|
||||
&& (service_choice !=
|
||||
SERVICE_CONFIRMED_REINITIALIZE_DEVICE)))
|
||||
break;
|
||||
if ((service_choice < MAX_BACNET_CONFIRMED_SERVICE) &&
|
||||
(Confirmed_Function[service_choice]))
|
||||
Confirmed_Function[service_choice] (service_request,
|
||||
service_request_len, src, &service_data);
|
||||
else if (Unrecognized_Service_Handler)
|
||||
Unrecognized_Service_Handler(service_request,
|
||||
service_request_len, src, &service_data);
|
||||
break;
|
||||
case PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST:
|
||||
if (dcc_communication_disabled())
|
||||
break;
|
||||
service_choice = apdu[1];
|
||||
service_request = &apdu[2];
|
||||
service_request_len = apdu_len - 2;
|
||||
if (service_choice < MAX_BACNET_UNCONFIRMED_SERVICE) {
|
||||
if (Unconfirmed_Function[service_choice])
|
||||
Unconfirmed_Function[service_choice] (service_request,
|
||||
service_request_len, src);
|
||||
}
|
||||
break;
|
||||
case PDU_TYPE_SIMPLE_ACK:
|
||||
invoke_id = apdu[1];
|
||||
service_choice = apdu[2];
|
||||
switch (service_choice) {
|
||||
case SERVICE_CONFIRMED_ACKNOWLEDGE_ALARM:
|
||||
case SERVICE_CONFIRMED_COV_NOTIFICATION:
|
||||
case SERVICE_CONFIRMED_EVENT_NOTIFICATION:
|
||||
case SERVICE_CONFIRMED_SUBSCRIBE_COV:
|
||||
case SERVICE_CONFIRMED_SUBSCRIBE_COV_PROPERTY:
|
||||
case SERVICE_CONFIRMED_LIFE_SAFETY_OPERATION:
|
||||
/* Object Access Services */
|
||||
case SERVICE_CONFIRMED_ADD_LIST_ELEMENT:
|
||||
case SERVICE_CONFIRMED_REMOVE_LIST_ELEMENT:
|
||||
case SERVICE_CONFIRMED_DELETE_OBJECT:
|
||||
case SERVICE_CONFIRMED_WRITE_PROPERTY:
|
||||
case SERVICE_CONFIRMED_WRITE_PROPERTY_MULTIPLE:
|
||||
/* Remote Device Management Services */
|
||||
case SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL:
|
||||
case SERVICE_CONFIRMED_REINITIALIZE_DEVICE:
|
||||
case SERVICE_CONFIRMED_TEXT_MESSAGE:
|
||||
/* Virtual Terminal Services */
|
||||
case SERVICE_CONFIRMED_VT_CLOSE:
|
||||
/* Security Services */
|
||||
case SERVICE_CONFIRMED_REQUEST_KEY:
|
||||
if (Confirmed_ACK_Function[service_choice]) {
|
||||
((confirmed_simple_ack_function)
|
||||
Confirmed_ACK_Function[service_choice]) (src,
|
||||
invoke_id);
|
||||
}
|
||||
tsm_free_invoke_id(invoke_id);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case PDU_TYPE_COMPLEX_ACK:
|
||||
service_ack_data.segmented_message =
|
||||
(apdu[0] & BIT3) ? true : false;
|
||||
service_ack_data.more_follows =
|
||||
(apdu[0] & BIT2) ? true : false;
|
||||
invoke_id = service_ack_data.invoke_id = apdu[1];
|
||||
len = 2;
|
||||
if (service_ack_data.segmented_message) {
|
||||
service_ack_data.sequence_number = apdu[len++];
|
||||
service_ack_data.proposed_window_number = apdu[len++];
|
||||
}
|
||||
service_choice = apdu[len++];
|
||||
service_request = &apdu[len];
|
||||
service_request_len = apdu_len - len;
|
||||
switch (service_choice) {
|
||||
case SERVICE_CONFIRMED_GET_ALARM_SUMMARY:
|
||||
case SERVICE_CONFIRMED_GET_ENROLLMENT_SUMMARY:
|
||||
case SERVICE_CONFIRMED_GET_EVENT_INFORMATION:
|
||||
/* File Access Services */
|
||||
case SERVICE_CONFIRMED_ATOMIC_READ_FILE:
|
||||
case SERVICE_CONFIRMED_ATOMIC_WRITE_FILE:
|
||||
/* Object Access Services */
|
||||
case SERVICE_CONFIRMED_CREATE_OBJECT:
|
||||
case SERVICE_CONFIRMED_READ_PROPERTY:
|
||||
case SERVICE_CONFIRMED_READ_PROPERTY_CONDITIONAL:
|
||||
case SERVICE_CONFIRMED_READ_PROPERTY_MULTIPLE:
|
||||
case SERVICE_CONFIRMED_READ_RANGE:
|
||||
case SERVICE_CONFIRMED_PRIVATE_TRANSFER:
|
||||
/* Virtual Terminal Services */
|
||||
case SERVICE_CONFIRMED_VT_OPEN:
|
||||
case SERVICE_CONFIRMED_VT_DATA:
|
||||
/* Security Services */
|
||||
case SERVICE_CONFIRMED_AUTHENTICATE:
|
||||
if (Confirmed_ACK_Function[service_choice]) {
|
||||
((confirmed_ack_function)
|
||||
Confirmed_ACK_Function[service_choice])
|
||||
(service_request, service_request_len, src,
|
||||
&service_ack_data);
|
||||
}
|
||||
tsm_free_invoke_id(invoke_id);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case PDU_TYPE_SEGMENT_ACK:
|
||||
/* FIXME: what about a denial of service attack here?
|
||||
we could check src to see if that matched the tsm */
|
||||
tsm_free_invoke_id(invoke_id);
|
||||
break;
|
||||
case PDU_TYPE_ERROR:
|
||||
invoke_id = apdu[1];
|
||||
service_choice = apdu[2];
|
||||
len = 3;
|
||||
len +=
|
||||
decode_tag_number_and_value(&apdu[len], &tag_number,
|
||||
&len_value);
|
||||
/* FIXME: we could validate that the tag is enumerated... */
|
||||
len += decode_enumerated(&apdu[len], len_value, &error_class);
|
||||
len +=
|
||||
decode_tag_number_and_value(&apdu[len], &tag_number,
|
||||
&len_value);
|
||||
/* FIXME: we could validate that the tag is enumerated... */
|
||||
len += decode_enumerated(&apdu[len], len_value, &error_code);
|
||||
if (service_choice < MAX_BACNET_CONFIRMED_SERVICE) {
|
||||
if (Error_Function[service_choice])
|
||||
Error_Function[service_choice] (src,
|
||||
invoke_id, error_class, error_code);
|
||||
}
|
||||
tsm_free_invoke_id(invoke_id);
|
||||
break;
|
||||
case PDU_TYPE_REJECT:
|
||||
invoke_id = apdu[1];
|
||||
reason = apdu[2];
|
||||
if (Reject_Function)
|
||||
Reject_Function(src, invoke_id, reason);
|
||||
tsm_free_invoke_id(invoke_id);
|
||||
break;
|
||||
case PDU_TYPE_ABORT:
|
||||
server = apdu[0] & 0x01;
|
||||
invoke_id = apdu[1];
|
||||
reason = apdu[2];
|
||||
if (Abort_Function)
|
||||
Abort_Function(src, invoke_id, reason, server);
|
||||
tsm_free_invoke_id(invoke_id);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -1,158 +0,0 @@
|
||||
/*####COPYRIGHTBEGIN####
|
||||
-------------------------------------------
|
||||
Copyright (C) 2005 Steve Karg
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to:
|
||||
The Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330
|
||||
Boston, MA 02111-1307, USA.
|
||||
|
||||
As a special exception, if other files instantiate templates or
|
||||
use macros or inline functions from this file, or you compile
|
||||
this file and link it with other works to produce a work based
|
||||
on this file, this file does not by itself cause the resulting
|
||||
work to be covered by the GNU General Public License. However
|
||||
the source code for this file must still be made available in
|
||||
accordance with section (3) of the GNU General Public License.
|
||||
|
||||
This exception does not invalidate any other reasons why a work
|
||||
based on this file might be covered by the GNU General Public
|
||||
License.
|
||||
-------------------------------------------
|
||||
####COPYRIGHTEND####*/
|
||||
#ifndef APDU_H
|
||||
#define APDU_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacenum.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
typedef struct _confirmed_service_data {
|
||||
bool segmented_message;
|
||||
bool more_follows;
|
||||
bool segmented_response_accepted;
|
||||
int max_segs;
|
||||
int max_resp;
|
||||
uint8_t invoke_id;
|
||||
uint8_t sequence_number;
|
||||
uint8_t proposed_window_number;
|
||||
} BACNET_CONFIRMED_SERVICE_DATA;
|
||||
|
||||
typedef struct _confirmed_service_ack_data {
|
||||
bool segmented_message;
|
||||
bool more_follows;
|
||||
uint8_t invoke_id;
|
||||
uint8_t sequence_number;
|
||||
uint8_t proposed_window_number;
|
||||
} BACNET_CONFIRMED_SERVICE_ACK_DATA;
|
||||
|
||||
/* generic unconfirmed function handler */
|
||||
/* Suitable to handle the following services: */
|
||||
/* I_Am, Who_Is, Unconfirmed_COV_Notification, I_Have, */
|
||||
/* Unconfirmed_Event_Notification, Unconfirmed_Private_Transfer, */
|
||||
/* Unconfirmed_Text_Message, Time_Synchronization, Who_Has, */
|
||||
/* UTC_Time_Synchronization */
|
||||
typedef void (*unconfirmed_function) (uint8_t * service_request,
|
||||
uint16_t len, BACNET_ADDRESS * src);
|
||||
|
||||
/* generic confirmed function handler */
|
||||
/* Suitable to handle the following services: */
|
||||
/* Acknowledge_Alarm, Confirmed_COV_Notification, */
|
||||
/* Confirmed_Event_Notification, Get_Alarm_Summary, */
|
||||
/* Get_Enrollment_Summary_Handler, Get_Event_Information, */
|
||||
/* Subscribe_COV_Handler, Subscribe_COV_Property, */
|
||||
/* Life_Safety_Operation, Atomic_Read_File, */
|
||||
/* Confirmed_Atomic_Write_File, Add_List_Element, */
|
||||
/* Remove_List_Element, Create_Object_Handler, */
|
||||
/* Delete_Object_Handler, Read_Property, */
|
||||
/* Read_Property_Conditional, Read_Property_Multiple, Read_Range, */
|
||||
/* Write_Property, Write_Property_Multiple, */
|
||||
/* Device_Communication_Control, Confirmed_Private_Transfer, */
|
||||
/* Confirmed_Text_Message, Reinitialize_Device, */
|
||||
/* VT_Open, VT_Close, VT_Data_Handler, */
|
||||
/* Authenticate, Request_Key */
|
||||
typedef void (*confirmed_function) (uint8_t * service_request,
|
||||
uint16_t service_len,
|
||||
BACNET_ADDRESS * src,
|
||||
BACNET_CONFIRMED_SERVICE_DATA * service_data);
|
||||
|
||||
/* generic confirmed simple ack function handler */
|
||||
typedef void (*confirmed_simple_ack_function) (BACNET_ADDRESS * src,
|
||||
uint8_t invoke_id);
|
||||
|
||||
/* generic confirmed ack function handler */
|
||||
typedef void (*confirmed_ack_function) (uint8_t * service_request,
|
||||
uint16_t service_len,
|
||||
BACNET_ADDRESS * src,
|
||||
BACNET_CONFIRMED_SERVICE_ACK_DATA * service_data);
|
||||
|
||||
/* generic error reply function */
|
||||
typedef void (*error_function) (BACNET_ADDRESS * src,
|
||||
uint8_t invoke_id,
|
||||
BACNET_ERROR_CLASS error_class, BACNET_ERROR_CODE error_code);
|
||||
|
||||
/* generic abort reply function */
|
||||
typedef void (*abort_function) (BACNET_ADDRESS * src,
|
||||
uint8_t invoke_id, uint8_t abort_reason, bool server);
|
||||
|
||||
/* generic reject reply function */
|
||||
typedef void (*reject_function) (BACNET_ADDRESS * src,
|
||||
uint8_t invoke_id, uint8_t reject_reason);
|
||||
|
||||
void apdu_set_confirmed_ack_handler(BACNET_CONFIRMED_SERVICE
|
||||
service_choice, confirmed_ack_function pFunction);
|
||||
|
||||
void apdu_set_confirmed_simple_ack_handler(BACNET_CONFIRMED_SERVICE
|
||||
service_choice, confirmed_simple_ack_function pFunction);
|
||||
|
||||
/* configure reject for confirmed services that are not supported */
|
||||
void apdu_set_unrecognized_service_handler_handler(confirmed_function
|
||||
pFunction);
|
||||
|
||||
void apdu_set_confirmed_handler(BACNET_CONFIRMED_SERVICE
|
||||
service_choice, confirmed_function pFunction);
|
||||
|
||||
void apdu_set_unconfirmed_handler(BACNET_UNCONFIRMED_SERVICE
|
||||
service_choice, unconfirmed_function pFunction);
|
||||
|
||||
/* returns true if the service is supported by a handler */
|
||||
bool apdu_service_supported(BACNET_SERVICES_SUPPORTED
|
||||
service_supported);
|
||||
|
||||
void apdu_set_error_handler(BACNET_CONFIRMED_SERVICE service_choice,
|
||||
error_function pFunction);
|
||||
|
||||
void apdu_set_abort_handler(abort_function pFunction);
|
||||
|
||||
void apdu_set_reject_handler(reject_function pFunction);
|
||||
|
||||
uint16_t apdu_decode_confirmed_service_request(uint8_t * apdu, /* APDU data */
|
||||
uint16_t apdu_len,
|
||||
BACNET_CONFIRMED_SERVICE_DATA * service_data,
|
||||
uint8_t * service_choice,
|
||||
uint8_t ** service_request, uint16_t * service_request_len);
|
||||
|
||||
void apdu_handler(BACNET_ADDRESS * src, /* source address */
|
||||
uint8_t * apdu, /* APDU data */
|
||||
uint16_t pdu_len); /* for confirmed messages */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
@@ -1,75 +0,0 @@
|
||||
/*####COPYRIGHTBEGIN####
|
||||
-------------------------------------------
|
||||
Copyright (C) 2005 Steve Karg
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to:
|
||||
The Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330
|
||||
Boston, MA 02111-1307, USA.
|
||||
|
||||
As a special exception, if other files instantiate templates or
|
||||
use macros or inline functions from this file, or you compile
|
||||
this file and link it with other works to produce a work based
|
||||
on this file, this file does not by itself cause the resulting
|
||||
work to be covered by the GNU General Public License. However
|
||||
the source code for this file must still be made available in
|
||||
accordance with section (3) of the GNU General Public License.
|
||||
|
||||
This exception does not invalidate any other reasons why a work
|
||||
based on this file might be covered by the GNU General Public
|
||||
License.
|
||||
-------------------------------------------
|
||||
####COPYRIGHTEND####*/
|
||||
#ifndef ARCNET_H
|
||||
#define ARCNET_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "bacdef.h"
|
||||
#include "npdu.h"
|
||||
|
||||
/* specific defines for ARCNET */
|
||||
#define MAX_HEADER (1+1+2+2+1+1+1+1)
|
||||
#define MAX_MPDU (MAX_HEADER+MAX_PDU)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
bool arcnet_valid(void);
|
||||
void arcnet_cleanup(void);
|
||||
bool arcnet_init(char *interface_name);
|
||||
|
||||
/* function to send a packet out the 802.2 socket */
|
||||
/* returns zero on success, non-zero on failure */
|
||||
int arcnet_send_pdu(BACNET_ADDRESS * dest, /* destination address */
|
||||
BACNET_NPDU_DATA * npdu_data, /* network information */
|
||||
uint8_t * pdu, /* any data to be sent - may be null */
|
||||
unsigned pdu_len); /* number of bytes of data */
|
||||
|
||||
/* receives an framed packet */
|
||||
/* returns the number of octets in the PDU, or zero on failure */
|
||||
uint16_t arcnet_receive(BACNET_ADDRESS * src, /* source address */
|
||||
uint8_t * pdu, /* PDU data */
|
||||
uint16_t max_pdu, /* amount of space available in the PDU */
|
||||
unsigned timeout); /* milliseconds to wait for a packet */
|
||||
|
||||
void arcnet_get_my_address(BACNET_ADDRESS * my_address);
|
||||
void arcnet_get_broadcast_address(BACNET_ADDRESS * dest); /* destination address */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
@@ -1,473 +0,0 @@
|
||||
/*####COPYRIGHTBEGIN####
|
||||
-------------------------------------------
|
||||
Copyright (C) 2005 Steve Karg
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to:
|
||||
The Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330
|
||||
Boston, MA 02111-1307, USA.
|
||||
|
||||
As a special exception, if other files instantiate templates or
|
||||
use macros or inline functions from this file, or you compile
|
||||
this file and link it with other works to produce a work based
|
||||
on this file, this file does not by itself cause the resulting
|
||||
work to be covered by the GNU General Public License. However
|
||||
the source code for this file must still be made available in
|
||||
accordance with section (3) of the GNU General Public License.
|
||||
|
||||
This exception does not invalidate any other reasons why a work
|
||||
based on this file might be covered by the GNU General Public
|
||||
License.
|
||||
-------------------------------------------
|
||||
####COPYRIGHTEND####*/
|
||||
#include <stdint.h>
|
||||
#include "bacenum.h"
|
||||
#include "bacdcode.h"
|
||||
#include "bacdef.h"
|
||||
#include "device.h"
|
||||
#include "arf.h"
|
||||
|
||||
/* Atomic Read File */
|
||||
|
||||
/* encode service */
|
||||
int arf_encode_apdu(uint8_t * apdu,
|
||||
uint8_t invoke_id, BACNET_ATOMIC_READ_FILE_DATA * data)
|
||||
{
|
||||
int apdu_len = 0; /* total length of the apdu, return value */
|
||||
|
||||
if (apdu) {
|
||||
apdu[0] = PDU_TYPE_CONFIRMED_SERVICE_REQUEST;
|
||||
apdu[1] =
|
||||
encode_max_segs_max_apdu(0, Device_Max_APDU_Length_Accepted());
|
||||
apdu[2] = invoke_id;
|
||||
apdu[3] = SERVICE_CONFIRMED_ATOMIC_READ_FILE; /* service choice */
|
||||
apdu_len = 4;
|
||||
apdu_len += encode_tagged_object_id(&apdu[apdu_len],
|
||||
data->object_type, data->object_instance);
|
||||
switch (data->access) {
|
||||
case FILE_STREAM_ACCESS:
|
||||
apdu_len += encode_opening_tag(&apdu[apdu_len], 0);
|
||||
apdu_len += encode_tagged_signed(&apdu[apdu_len],
|
||||
data->type.stream.fileStartPosition);
|
||||
apdu_len += encode_tagged_unsigned(&apdu[apdu_len],
|
||||
data->type.stream.requestedOctetCount);
|
||||
apdu_len += encode_closing_tag(&apdu[apdu_len], 0);
|
||||
break;
|
||||
case FILE_RECORD_ACCESS:
|
||||
apdu_len += encode_opening_tag(&apdu[apdu_len], 1);
|
||||
apdu_len += encode_tagged_signed(&apdu[apdu_len],
|
||||
data->type.record.fileStartRecord);
|
||||
apdu_len += encode_tagged_unsigned(&apdu[apdu_len],
|
||||
data->type.record.RecordCount);
|
||||
apdu_len += encode_closing_tag(&apdu[apdu_len], 1);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
/* decode the service request only */
|
||||
int arf_decode_service_request(uint8_t * apdu,
|
||||
unsigned apdu_len, BACNET_ATOMIC_READ_FILE_DATA * data)
|
||||
{
|
||||
int len = 0;
|
||||
int tag_len = 0;
|
||||
uint8_t tag_number = 0;
|
||||
uint32_t len_value_type = 0;
|
||||
int type = 0; /* for decoding */
|
||||
|
||||
/* check for value pointers */
|
||||
if (apdu_len && data) {
|
||||
len =
|
||||
decode_tag_number_and_value(&apdu[0], &tag_number,
|
||||
&len_value_type);
|
||||
if (tag_number != BACNET_APPLICATION_TAG_OBJECT_ID)
|
||||
return -1;
|
||||
len += decode_object_id(&apdu[len], &type, &data->object_instance);
|
||||
data->object_type = type;
|
||||
if (decode_is_opening_tag_number(&apdu[len], 0)) {
|
||||
data->access = FILE_STREAM_ACCESS;
|
||||
/* a tag number is not extended so only one octet */
|
||||
len++;
|
||||
/* fileStartPosition */
|
||||
tag_len = decode_tag_number_and_value(&apdu[len],
|
||||
&tag_number, &len_value_type);
|
||||
len += tag_len;
|
||||
if (tag_number != BACNET_APPLICATION_TAG_SIGNED_INT)
|
||||
return -1;
|
||||
len += decode_signed(&apdu[len],
|
||||
len_value_type, &data->type.stream.fileStartPosition);
|
||||
/* requestedOctetCount */
|
||||
tag_len = decode_tag_number_and_value(&apdu[len],
|
||||
&tag_number, &len_value_type);
|
||||
len += tag_len;
|
||||
if (tag_number != BACNET_APPLICATION_TAG_UNSIGNED_INT)
|
||||
return -1;
|
||||
len += decode_unsigned(&apdu[len],
|
||||
len_value_type, &data->type.stream.requestedOctetCount);
|
||||
if (!decode_is_closing_tag_number(&apdu[len], 0))
|
||||
return -1;
|
||||
/* a tag number is not extended so only one octet */
|
||||
len++;
|
||||
} else if (decode_is_opening_tag_number(&apdu[len], 1)) {
|
||||
data->access = FILE_RECORD_ACCESS;
|
||||
/* a tag number is not extended so only one octet */
|
||||
len++;
|
||||
/* fileStartRecord */
|
||||
tag_len = decode_tag_number_and_value(&apdu[len],
|
||||
&tag_number, &len_value_type);
|
||||
len += tag_len;
|
||||
if (tag_number != BACNET_APPLICATION_TAG_SIGNED_INT)
|
||||
return -1;
|
||||
len += decode_signed(&apdu[len],
|
||||
len_value_type, &data->type.record.fileStartRecord);
|
||||
/* RecordCount */
|
||||
tag_len = decode_tag_number_and_value(&apdu[len],
|
||||
&tag_number, &len_value_type);
|
||||
len += tag_len;
|
||||
if (tag_number != BACNET_APPLICATION_TAG_UNSIGNED_INT)
|
||||
return -1;
|
||||
len += decode_unsigned(&apdu[len],
|
||||
len_value_type, &data->type.record.RecordCount);
|
||||
if (!decode_is_closing_tag_number(&apdu[len], 1))
|
||||
return -1;
|
||||
/* a tag number is not extended so only one octet */
|
||||
len++;
|
||||
} else
|
||||
return -1;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
int arf_decode_apdu(uint8_t * apdu,
|
||||
unsigned apdu_len,
|
||||
uint8_t * invoke_id, BACNET_ATOMIC_READ_FILE_DATA * data)
|
||||
{
|
||||
int len = 0;
|
||||
unsigned offset = 0;
|
||||
|
||||
if (!apdu)
|
||||
return -1;
|
||||
/* optional checking - most likely was already done prior to this call */
|
||||
if (apdu[0] != PDU_TYPE_CONFIRMED_SERVICE_REQUEST)
|
||||
return -1;
|
||||
/* apdu[1] = encode_max_segs_max_apdu(0, Device_Max_APDU_Length_Accepted()); */
|
||||
*invoke_id = apdu[2]; /* invoke id - filled in by net layer */
|
||||
if (apdu[3] != SERVICE_CONFIRMED_ATOMIC_READ_FILE)
|
||||
return -1;
|
||||
offset = 4;
|
||||
|
||||
if (apdu_len > offset) {
|
||||
len = arf_decode_service_request(&apdu[offset],
|
||||
apdu_len - offset, data);
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/* encode service */
|
||||
int arf_ack_encode_apdu(uint8_t * apdu,
|
||||
uint8_t invoke_id, BACNET_ATOMIC_READ_FILE_DATA * data)
|
||||
{
|
||||
int apdu_len = 0; /* total length of the apdu, return value */
|
||||
|
||||
if (apdu) {
|
||||
apdu[0] = PDU_TYPE_COMPLEX_ACK;
|
||||
apdu[1] = invoke_id;
|
||||
apdu[2] = SERVICE_CONFIRMED_ATOMIC_READ_FILE; /* service choice */
|
||||
apdu_len = 3;
|
||||
/* endOfFile */
|
||||
apdu_len +=
|
||||
encode_tagged_boolean(&apdu[apdu_len], data->endOfFile);
|
||||
switch (data->access) {
|
||||
case FILE_STREAM_ACCESS:
|
||||
apdu_len += encode_opening_tag(&apdu[apdu_len], 0);
|
||||
apdu_len += encode_tagged_signed(&apdu[apdu_len],
|
||||
data->type.stream.fileStartPosition);
|
||||
apdu_len += encode_tagged_octet_string(&apdu[apdu_len],
|
||||
&data->fileData);
|
||||
apdu_len += encode_closing_tag(&apdu[apdu_len], 0);
|
||||
break;
|
||||
case FILE_RECORD_ACCESS:
|
||||
apdu_len += encode_opening_tag(&apdu[apdu_len], 1);
|
||||
apdu_len += encode_tagged_signed(&apdu[apdu_len],
|
||||
data->type.record.fileStartRecord);
|
||||
apdu_len += encode_tagged_unsigned(&apdu[apdu_len],
|
||||
data->type.record.RecordCount);
|
||||
apdu_len += encode_tagged_octet_string(&apdu[apdu_len],
|
||||
&data->fileData);
|
||||
apdu_len += encode_closing_tag(&apdu[apdu_len], 1);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
/* decode the service request only */
|
||||
int arf_ack_decode_service_request(uint8_t * apdu,
|
||||
unsigned apdu_len, BACNET_ATOMIC_READ_FILE_DATA * data)
|
||||
{
|
||||
int len = 0;
|
||||
int tag_len = 0;
|
||||
uint8_t tag_number = 0;
|
||||
uint32_t len_value_type = 0;
|
||||
|
||||
/* check for value pointers */
|
||||
if (apdu_len && data) {
|
||||
len =
|
||||
decode_tag_number_and_value(&apdu[0], &tag_number,
|
||||
&len_value_type);
|
||||
if (tag_number != BACNET_APPLICATION_TAG_BOOLEAN)
|
||||
return -1;
|
||||
data->endOfFile = decode_boolean(len_value_type);
|
||||
if (decode_is_opening_tag_number(&apdu[len], 0)) {
|
||||
data->access = FILE_STREAM_ACCESS;
|
||||
/* a tag number is not extended so only one octet */
|
||||
len++;
|
||||
/* fileStartPosition */
|
||||
tag_len = decode_tag_number_and_value(&apdu[len],
|
||||
&tag_number, &len_value_type);
|
||||
len += tag_len;
|
||||
if (tag_number != BACNET_APPLICATION_TAG_SIGNED_INT)
|
||||
return -1;
|
||||
len += decode_signed(&apdu[len],
|
||||
len_value_type, &data->type.stream.fileStartPosition);
|
||||
/* fileData */
|
||||
tag_len = decode_tag_number_and_value(&apdu[len],
|
||||
&tag_number, &len_value_type);
|
||||
len += tag_len;
|
||||
if (tag_number != BACNET_APPLICATION_TAG_OCTET_STRING)
|
||||
return -1;
|
||||
len += decode_octet_string(&apdu[len],
|
||||
len_value_type, &data->fileData);
|
||||
if (!decode_is_closing_tag_number(&apdu[len], 0))
|
||||
return -1;
|
||||
/* a tag number is not extended so only one octet */
|
||||
len++;
|
||||
} else if (decode_is_opening_tag_number(&apdu[len], 1)) {
|
||||
data->access = FILE_RECORD_ACCESS;
|
||||
/* a tag number is not extended so only one octet */
|
||||
len++;
|
||||
/* fileStartRecord */
|
||||
tag_len = decode_tag_number_and_value(&apdu[len],
|
||||
&tag_number, &len_value_type);
|
||||
len += tag_len;
|
||||
if (tag_number != BACNET_APPLICATION_TAG_SIGNED_INT)
|
||||
return -1;
|
||||
len += decode_signed(&apdu[len],
|
||||
len_value_type, &data->type.record.fileStartRecord);
|
||||
/* returnedRecordCount */
|
||||
tag_len = decode_tag_number_and_value(&apdu[len],
|
||||
&tag_number, &len_value_type);
|
||||
len += tag_len;
|
||||
if (tag_number != BACNET_APPLICATION_TAG_UNSIGNED_INT)
|
||||
return -1;
|
||||
len += decode_unsigned(&apdu[len],
|
||||
len_value_type, &data->type.record.RecordCount);
|
||||
/* fileData */
|
||||
tag_len = decode_tag_number_and_value(&apdu[len],
|
||||
&tag_number, &len_value_type);
|
||||
len += tag_len;
|
||||
if (tag_number != BACNET_APPLICATION_TAG_OCTET_STRING)
|
||||
return -1;
|
||||
len += decode_octet_string(&apdu[len],
|
||||
len_value_type, &data->fileData);
|
||||
if (!decode_is_closing_tag_number(&apdu[len], 1))
|
||||
return -1;
|
||||
/* a tag number is not extended so only one octet */
|
||||
len++;
|
||||
} else
|
||||
return -1;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
int arf_ack_decode_apdu(uint8_t * apdu,
|
||||
unsigned apdu_len,
|
||||
uint8_t * invoke_id, BACNET_ATOMIC_READ_FILE_DATA * data)
|
||||
{
|
||||
int len = 0;
|
||||
unsigned offset = 0;
|
||||
|
||||
if (!apdu)
|
||||
return -1;
|
||||
/* optional checking - most likely was already done prior to this call */
|
||||
if (apdu[0] != PDU_TYPE_COMPLEX_ACK)
|
||||
return -1;
|
||||
*invoke_id = apdu[1]; /* invoke id - filled in by net layer */
|
||||
if (apdu[2] != SERVICE_CONFIRMED_ATOMIC_READ_FILE)
|
||||
return -1;
|
||||
offset = 3;
|
||||
|
||||
if (apdu_len > offset) {
|
||||
len = arf_ack_decode_service_request(&apdu[offset],
|
||||
apdu_len - offset, data);
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
#ifdef TEST
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include "ctest.h"
|
||||
|
||||
void testAtomicReadFileAckAccess(Test * pTest,
|
||||
BACNET_ATOMIC_READ_FILE_DATA * data)
|
||||
{
|
||||
BACNET_ATOMIC_READ_FILE_DATA test_data = { 0 };
|
||||
uint8_t apdu[480] = { 0 };
|
||||
int len = 0;
|
||||
int apdu_len = 0;
|
||||
uint8_t invoke_id = 128;
|
||||
uint8_t test_invoke_id = 0;
|
||||
|
||||
len = arf_ack_encode_apdu(&apdu[0], invoke_id, data);
|
||||
ct_test(pTest, len != 0);
|
||||
apdu_len = len;
|
||||
|
||||
len = arf_ack_decode_apdu(&apdu[0],
|
||||
apdu_len, &test_invoke_id, &test_data);
|
||||
ct_test(pTest, len != -1);
|
||||
ct_test(pTest, test_data.endOfFile == data->endOfFile);
|
||||
ct_test(pTest, test_data.access == data->access);
|
||||
if (test_data.access == FILE_STREAM_ACCESS) {
|
||||
ct_test(pTest, test_data.type.stream.fileStartPosition ==
|
||||
data->type.stream.fileStartPosition);
|
||||
} else if (test_data.access == FILE_RECORD_ACCESS) {
|
||||
ct_test(pTest, test_data.type.record.fileStartRecord ==
|
||||
data->type.record.fileStartRecord);
|
||||
ct_test(pTest, test_data.type.record.RecordCount ==
|
||||
data->type.record.RecordCount);
|
||||
}
|
||||
ct_test(pTest, octetstring_length(&test_data.fileData) ==
|
||||
octetstring_length(&data->fileData));
|
||||
ct_test(pTest, memcmp(octetstring_value(&test_data.fileData),
|
||||
octetstring_value(&data->fileData),
|
||||
octetstring_length(&test_data.fileData)) == 0);
|
||||
}
|
||||
|
||||
void testAtomicReadFileAck(Test * pTest)
|
||||
{
|
||||
BACNET_ATOMIC_READ_FILE_DATA data = { 0 };
|
||||
uint8_t test_octet_string[32] = "Joshua-Mary-Anna-Christopher";
|
||||
|
||||
|
||||
data.endOfFile = true;
|
||||
data.access = FILE_STREAM_ACCESS;
|
||||
data.type.stream.fileStartPosition = 0;
|
||||
octetstring_init(&data.fileData,
|
||||
test_octet_string, sizeof(test_octet_string));
|
||||
testAtomicReadFileAckAccess(pTest, &data);
|
||||
|
||||
data.endOfFile = false;
|
||||
data.access = FILE_RECORD_ACCESS;
|
||||
data.type.record.fileStartRecord = 1;
|
||||
data.type.record.RecordCount = 2;
|
||||
octetstring_init(&data.fileData,
|
||||
test_octet_string, sizeof(test_octet_string));
|
||||
testAtomicReadFileAckAccess(pTest, &data);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void testAtomicReadFileAccess(Test * pTest,
|
||||
BACNET_ATOMIC_READ_FILE_DATA * data)
|
||||
{
|
||||
BACNET_ATOMIC_READ_FILE_DATA test_data = { 0 };
|
||||
uint8_t apdu[480] = { 0 };
|
||||
int len = 0;
|
||||
int apdu_len = 0;
|
||||
uint8_t invoke_id = 128;
|
||||
uint8_t test_invoke_id = 0;
|
||||
|
||||
len = arf_encode_apdu(&apdu[0], invoke_id, data);
|
||||
ct_test(pTest, len != 0);
|
||||
apdu_len = len;
|
||||
|
||||
len = arf_decode_apdu(&apdu[0], apdu_len, &test_invoke_id, &test_data);
|
||||
ct_test(pTest, len != -1);
|
||||
ct_test(pTest, test_data.object_type == data->object_type);
|
||||
ct_test(pTest, test_data.object_instance == data->object_instance);
|
||||
ct_test(pTest, test_data.access == data->access);
|
||||
if (test_data.access == FILE_STREAM_ACCESS) {
|
||||
ct_test(pTest, test_data.type.stream.fileStartPosition ==
|
||||
data->type.stream.fileStartPosition);
|
||||
ct_test(pTest, test_data.type.stream.requestedOctetCount ==
|
||||
data->type.stream.requestedOctetCount);
|
||||
} else if (test_data.access == FILE_RECORD_ACCESS) {
|
||||
ct_test(pTest, test_data.type.record.fileStartRecord ==
|
||||
data->type.record.fileStartRecord);
|
||||
ct_test(pTest, test_data.type.record.RecordCount ==
|
||||
data->type.record.RecordCount);
|
||||
}
|
||||
}
|
||||
|
||||
void testAtomicReadFile(Test * pTest)
|
||||
{
|
||||
BACNET_ATOMIC_READ_FILE_DATA data = { 0 };
|
||||
|
||||
data.object_type = OBJECT_FILE;
|
||||
data.object_instance = 1;
|
||||
data.access = FILE_STREAM_ACCESS;
|
||||
data.type.stream.fileStartPosition = 0;
|
||||
data.type.stream.requestedOctetCount = 128;
|
||||
testAtomicReadFileAccess(pTest, &data);
|
||||
|
||||
data.object_type = OBJECT_FILE;
|
||||
data.object_instance = 2;
|
||||
data.access = FILE_RECORD_ACCESS;
|
||||
data.type.record.fileStartRecord = 1;
|
||||
data.type.record.RecordCount = 2;
|
||||
testAtomicReadFileAccess(pTest, &data);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef TEST_ATOMIC_READ_FILE
|
||||
uint16_t Device_Max_APDU_Length_Accepted(void)
|
||||
{
|
||||
return MAX_APDU;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
Test *pTest;
|
||||
bool rc;
|
||||
|
||||
pTest = ct_create("BACnet AtomicReadFile", NULL);
|
||||
/* individual tests */
|
||||
rc = ct_addTestFunction(pTest, testAtomicReadFile);
|
||||
assert(rc);
|
||||
rc = ct_addTestFunction(pTest, testAtomicReadFileAck);
|
||||
assert(rc);
|
||||
|
||||
ct_setStream(pTest, stdout);
|
||||
ct_run(pTest);
|
||||
(void) ct_report(pTest);
|
||||
ct_destroy(pTest);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* TEST_xxx */
|
||||
#endif /* TEST */
|
||||
@@ -1,102 +0,0 @@
|
||||
/*####COPYRIGHTBEGIN####
|
||||
-------------------------------------------
|
||||
Copyright (C) 2005 Steve Karg
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to:
|
||||
The Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330
|
||||
Boston, MA 02111-1307, USA.
|
||||
|
||||
As a special exception, if other files instantiate templates or
|
||||
use macros or inline functions from this file, or you compile
|
||||
this file and link it with other works to produce a work based
|
||||
on this file, this file does not by itself cause the resulting
|
||||
work to be covered by the GNU General Public License. However
|
||||
the source code for this file must still be made available in
|
||||
accordance with section (3) of the GNU General Public License.
|
||||
|
||||
This exception does not invalidate any other reasons why a work
|
||||
based on this file might be covered by the GNU General Public
|
||||
License.
|
||||
-------------------------------------------
|
||||
####COPYRIGHTEND####*/
|
||||
#ifndef ATOMIC_READ_FILE_H
|
||||
#define ATOMIC_READ_FILE_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "bacdcode.h"
|
||||
#include "bacstr.h"
|
||||
|
||||
typedef struct BACnet_Atomic_Read_File_Data {
|
||||
BACNET_OBJECT_TYPE object_type;
|
||||
uint32_t object_instance;
|
||||
BACNET_FILE_ACCESS_METHOD access;
|
||||
union {
|
||||
struct {
|
||||
int32_t fileStartPosition;
|
||||
uint32_t requestedOctetCount;
|
||||
} stream;
|
||||
struct {
|
||||
int32_t fileStartRecord;
|
||||
/* requested or returned record count */
|
||||
uint32_t RecordCount;
|
||||
} record;
|
||||
} type;
|
||||
BACNET_OCTET_STRING fileData;
|
||||
bool endOfFile;
|
||||
} BACNET_ATOMIC_READ_FILE_DATA;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/* Atomic Read File */
|
||||
/* encode service */
|
||||
int arf_encode_apdu(uint8_t * apdu,
|
||||
uint8_t invoke_id, BACNET_ATOMIC_READ_FILE_DATA * data);
|
||||
|
||||
/* decode the service request only */
|
||||
int arf_decode_service_request(uint8_t * apdu,
|
||||
unsigned apdu_len, BACNET_ATOMIC_READ_FILE_DATA * data);
|
||||
|
||||
int arf_decode_apdu(uint8_t * apdu,
|
||||
unsigned apdu_len,
|
||||
uint8_t * invoke_id, BACNET_ATOMIC_READ_FILE_DATA * data);
|
||||
|
||||
/* Atomic Read File Ack */
|
||||
|
||||
/* encode service */
|
||||
int arf_ack_encode_apdu(uint8_t * apdu,
|
||||
uint8_t invoke_id, BACNET_ATOMIC_READ_FILE_DATA * data);
|
||||
|
||||
/* decode the service request only */
|
||||
int arf_ack_decode_service_request(uint8_t * apdu,
|
||||
unsigned apdu_len, BACNET_ATOMIC_READ_FILE_DATA * data);
|
||||
|
||||
int arf_ack_decode_apdu(uint8_t * apdu,
|
||||
unsigned apdu_len,
|
||||
uint8_t * invoke_id, BACNET_ATOMIC_READ_FILE_DATA * data);
|
||||
|
||||
#ifdef TEST
|
||||
#include "ctest.h"
|
||||
|
||||
void test_AtomicReadFile(Test * pTest);
|
||||
void test_AtomicReadFileAck(Test * pTest);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
@@ -1,34 +0,0 @@
|
||||
#Makefile to build test case
|
||||
CC = gcc
|
||||
BASEDIR = .
|
||||
# -g for debugging with gdb
|
||||
DEFINES = -DBACFILE=1 -DBACDL_BIP=1 -DTEST -DTEST_ATOMIC_READ_FILE
|
||||
INCLUDES = -I. -Idemo/object -Itest
|
||||
CFLAGS = -Wall $(INCLUDES) $(DEFINES) -g
|
||||
|
||||
SRCS = bacdcode.c \
|
||||
bacstr.c \
|
||||
bigend.c \
|
||||
arf.c \
|
||||
test/ctest.c
|
||||
|
||||
OBJS = ${SRCS:.c=.o}
|
||||
|
||||
TARGET = atomicreadfile
|
||||
|
||||
all: ${TARGET}
|
||||
|
||||
${TARGET}: ${OBJS}
|
||||
${CC} -o $@ ${OBJS}
|
||||
|
||||
.c.o:
|
||||
${CC} -c ${CFLAGS} $*.c -o $@
|
||||
|
||||
depend:
|
||||
rm -f .depend
|
||||
${CC} -MM ${CFLAGS} *.c >> .depend
|
||||
|
||||
clean:
|
||||
rm -rf core ${TARGET} $(OBJS) *.bak *.1 *.ini
|
||||
|
||||
include: .depend
|
||||
@@ -1,405 +0,0 @@
|
||||
/*####COPYRIGHTBEGIN####
|
||||
-------------------------------------------
|
||||
Copyright (C) 2005 Steve Karg
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to:
|
||||
The Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330
|
||||
Boston, MA 02111-1307, USA.
|
||||
|
||||
As a special exception, if other files instantiate templates or
|
||||
use macros or inline functions from this file, or you compile
|
||||
this file and link it with other works to produce a work based
|
||||
on this file, this file does not by itself cause the resulting
|
||||
work to be covered by the GNU General Public License. However
|
||||
the source code for this file must still be made available in
|
||||
accordance with section (3) of the GNU General Public License.
|
||||
|
||||
This exception does not invalidate any other reasons why a work
|
||||
based on this file might be covered by the GNU General Public
|
||||
License.
|
||||
-------------------------------------------
|
||||
####COPYRIGHTEND####*/
|
||||
#include <stdint.h>
|
||||
#include "bacenum.h"
|
||||
#include "bacdcode.h"
|
||||
#include "bacdef.h"
|
||||
#include "device.h"
|
||||
#include "awf.h"
|
||||
|
||||
/* Atomic Write File */
|
||||
|
||||
/* encode service */
|
||||
int awf_encode_apdu(uint8_t * apdu,
|
||||
uint8_t invoke_id, BACNET_ATOMIC_WRITE_FILE_DATA * data)
|
||||
{
|
||||
int apdu_len = 0; /* total length of the apdu, return value */
|
||||
|
||||
if (apdu) {
|
||||
apdu[0] = PDU_TYPE_CONFIRMED_SERVICE_REQUEST;
|
||||
apdu[1] =
|
||||
encode_max_segs_max_apdu(0, Device_Max_APDU_Length_Accepted());
|
||||
apdu[2] = invoke_id;
|
||||
apdu[3] = SERVICE_CONFIRMED_ATOMIC_WRITE_FILE; /* service choice */
|
||||
apdu_len = 4;
|
||||
apdu_len += encode_tagged_object_id(&apdu[apdu_len],
|
||||
data->object_type, data->object_instance);
|
||||
switch (data->access) {
|
||||
case FILE_STREAM_ACCESS:
|
||||
apdu_len += encode_opening_tag(&apdu[apdu_len], 0);
|
||||
apdu_len += encode_tagged_signed(&apdu[apdu_len],
|
||||
data->type.stream.fileStartPosition);
|
||||
apdu_len += encode_tagged_octet_string(&apdu[apdu_len],
|
||||
&data->fileData);
|
||||
apdu_len += encode_closing_tag(&apdu[apdu_len], 0);
|
||||
break;
|
||||
case FILE_RECORD_ACCESS:
|
||||
apdu_len += encode_opening_tag(&apdu[apdu_len], 1);
|
||||
apdu_len += encode_tagged_signed(&apdu[apdu_len],
|
||||
data->type.record.fileStartRecord);
|
||||
apdu_len += encode_tagged_unsigned(&apdu[apdu_len],
|
||||
data->type.record.returnedRecordCount);
|
||||
apdu_len += encode_tagged_octet_string(&apdu[apdu_len],
|
||||
&data->fileData);
|
||||
apdu_len += encode_closing_tag(&apdu[apdu_len], 1);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
/* decode the service request only */
|
||||
int awf_decode_service_request(uint8_t * apdu,
|
||||
unsigned apdu_len, BACNET_ATOMIC_WRITE_FILE_DATA * data)
|
||||
{
|
||||
int len = 0;
|
||||
int tag_len = 0;
|
||||
uint8_t tag_number = 0;
|
||||
uint32_t len_value_type = 0;
|
||||
int type = 0; /* for decoding */
|
||||
|
||||
/* check for value pointers */
|
||||
if (apdu_len && data) {
|
||||
len =
|
||||
decode_tag_number_and_value(&apdu[0], &tag_number,
|
||||
&len_value_type);
|
||||
if (tag_number != BACNET_APPLICATION_TAG_OBJECT_ID)
|
||||
return -1;
|
||||
len += decode_object_id(&apdu[len], &type, &data->object_instance);
|
||||
data->object_type = type;
|
||||
if (decode_is_opening_tag_number(&apdu[len], 0)) {
|
||||
data->access = FILE_STREAM_ACCESS;
|
||||
/* a tag number of 2 is not extended so only one octet */
|
||||
len++;
|
||||
/* fileStartPosition */
|
||||
tag_len = decode_tag_number_and_value(&apdu[len],
|
||||
&tag_number, &len_value_type);
|
||||
len += tag_len;
|
||||
if (tag_number != BACNET_APPLICATION_TAG_SIGNED_INT)
|
||||
return -1;
|
||||
len += decode_signed(&apdu[len],
|
||||
len_value_type, &data->type.stream.fileStartPosition);
|
||||
/* fileData */
|
||||
tag_len = decode_tag_number_and_value(&apdu[len],
|
||||
&tag_number, &len_value_type);
|
||||
len += tag_len;
|
||||
if (tag_number != BACNET_APPLICATION_TAG_OCTET_STRING)
|
||||
return -1;
|
||||
len += decode_octet_string(&apdu[len],
|
||||
len_value_type, &data->fileData);
|
||||
if (!decode_is_closing_tag_number(&apdu[len], 0))
|
||||
return -1;
|
||||
/* a tag number is not extended so only one octet */
|
||||
len++;
|
||||
} else if (decode_is_opening_tag_number(&apdu[len], 1)) {
|
||||
data->access = FILE_RECORD_ACCESS;
|
||||
/* a tag number is not extended so only one octet */
|
||||
len++;
|
||||
/* fileStartRecord */
|
||||
tag_len = decode_tag_number_and_value(&apdu[len],
|
||||
&tag_number, &len_value_type);
|
||||
len += tag_len;
|
||||
if (tag_number != BACNET_APPLICATION_TAG_SIGNED_INT)
|
||||
return -1;
|
||||
len += decode_signed(&apdu[len],
|
||||
len_value_type, &data->type.record.fileStartRecord);
|
||||
/* returnedRecordCount */
|
||||
tag_len = decode_tag_number_and_value(&apdu[len],
|
||||
&tag_number, &len_value_type);
|
||||
len += tag_len;
|
||||
if (tag_number != BACNET_APPLICATION_TAG_UNSIGNED_INT)
|
||||
return -1;
|
||||
len += decode_unsigned(&apdu[len],
|
||||
len_value_type, &data->type.record.returnedRecordCount);
|
||||
/* fileData */
|
||||
tag_len = decode_tag_number_and_value(&apdu[len],
|
||||
&tag_number, &len_value_type);
|
||||
len += tag_len;
|
||||
if (tag_number != BACNET_APPLICATION_TAG_OCTET_STRING)
|
||||
return -1;
|
||||
len += decode_octet_string(&apdu[len],
|
||||
len_value_type, &data->fileData);
|
||||
if (!decode_is_closing_tag_number(&apdu[len], 1))
|
||||
return -1;
|
||||
/* a tag number is not extended so only one octet */
|
||||
len++;
|
||||
} else
|
||||
return -1;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
int awf_decode_apdu(uint8_t * apdu,
|
||||
unsigned apdu_len,
|
||||
uint8_t * invoke_id, BACNET_ATOMIC_WRITE_FILE_DATA * data)
|
||||
{
|
||||
int len = 0;
|
||||
unsigned offset = 0;
|
||||
|
||||
if (!apdu)
|
||||
return -1;
|
||||
/* optional checking - most likely was already done prior to this call */
|
||||
if (apdu[0] != PDU_TYPE_CONFIRMED_SERVICE_REQUEST)
|
||||
return -1;
|
||||
/* apdu[1] = encode_max_segs_max_apdu(0, Device_Max_APDU_Length_Accepted()); */
|
||||
*invoke_id = apdu[2]; /* invoke id - filled in by net layer */
|
||||
if (apdu[3] != SERVICE_CONFIRMED_ATOMIC_WRITE_FILE)
|
||||
return -1;
|
||||
offset = 4;
|
||||
|
||||
if (apdu_len > offset) {
|
||||
len = awf_decode_service_request(&apdu[offset],
|
||||
apdu_len - offset, data);
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
int awf_ack_encode_apdu(uint8_t * apdu,
|
||||
uint8_t invoke_id, BACNET_ATOMIC_WRITE_FILE_DATA * data)
|
||||
{
|
||||
int apdu_len = 0; /* total length of the apdu, return value */
|
||||
|
||||
if (apdu) {
|
||||
apdu[0] = PDU_TYPE_COMPLEX_ACK;
|
||||
apdu[1] = invoke_id;
|
||||
apdu[2] = SERVICE_CONFIRMED_ATOMIC_WRITE_FILE; /* service choice */
|
||||
apdu_len = 3;
|
||||
switch (data->access) {
|
||||
case FILE_STREAM_ACCESS:
|
||||
apdu_len += encode_context_signed(&apdu[apdu_len], 0,
|
||||
data->type.stream.fileStartPosition);
|
||||
break;
|
||||
case FILE_RECORD_ACCESS:
|
||||
apdu_len += encode_context_signed(&apdu[apdu_len], 1,
|
||||
data->type.record.fileStartRecord);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
/* decode the service request only */
|
||||
int awf_ack_decode_service_request(uint8_t * apdu,
|
||||
unsigned apdu_len, BACNET_ATOMIC_WRITE_FILE_DATA * data)
|
||||
{
|
||||
int len = 0;
|
||||
uint8_t tag_number = 0;
|
||||
uint32_t len_value_type = 0;
|
||||
|
||||
/* check for value pointers */
|
||||
if (apdu_len && data) {
|
||||
len =
|
||||
decode_tag_number_and_value(&apdu[0], &tag_number,
|
||||
&len_value_type);
|
||||
if (tag_number == 0) {
|
||||
data->access = FILE_STREAM_ACCESS;
|
||||
len += decode_signed(&apdu[len],
|
||||
len_value_type, &data->type.stream.fileStartPosition);
|
||||
} else if (tag_number == 1) {
|
||||
data->access = FILE_RECORD_ACCESS;
|
||||
len += decode_signed(&apdu[len],
|
||||
len_value_type, &data->type.record.fileStartRecord);
|
||||
} else
|
||||
return -1;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
int awf_ack_decode_apdu(uint8_t * apdu,
|
||||
unsigned apdu_len,
|
||||
uint8_t * invoke_id, BACNET_ATOMIC_WRITE_FILE_DATA * data)
|
||||
{
|
||||
int len = 0;
|
||||
unsigned offset = 0;
|
||||
|
||||
if (!apdu)
|
||||
return -1;
|
||||
/* optional checking - most likely was already done prior to this call */
|
||||
if (apdu[0] != PDU_TYPE_COMPLEX_ACK)
|
||||
return -1;
|
||||
*invoke_id = apdu[1]; /* invoke id - filled in by net layer */
|
||||
if (apdu[2] != SERVICE_CONFIRMED_ATOMIC_WRITE_FILE)
|
||||
return -1;
|
||||
offset = 3;
|
||||
|
||||
if (apdu_len > offset) {
|
||||
len = awf_decode_service_request(&apdu[offset],
|
||||
apdu_len - offset, data);
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include "ctest.h"
|
||||
|
||||
void testAtomicWriteFileAccess(Test * pTest,
|
||||
BACNET_ATOMIC_WRITE_FILE_DATA * data)
|
||||
{
|
||||
BACNET_ATOMIC_WRITE_FILE_DATA test_data = { 0 };
|
||||
uint8_t apdu[480] = { 0 };
|
||||
int len = 0;
|
||||
int apdu_len = 0;
|
||||
uint8_t invoke_id = 128;
|
||||
uint8_t test_invoke_id = 0;
|
||||
|
||||
len = awf_encode_apdu(&apdu[0], invoke_id, data);
|
||||
ct_test(pTest, len != 0);
|
||||
apdu_len = len;
|
||||
|
||||
len = awf_decode_apdu(&apdu[0], apdu_len, &test_invoke_id, &test_data);
|
||||
ct_test(pTest, len != -1);
|
||||
ct_test(pTest, test_data.object_type == data->object_type);
|
||||
ct_test(pTest, test_data.object_instance == data->object_instance);
|
||||
ct_test(pTest, test_data.access == data->access);
|
||||
if (test_data.access == FILE_STREAM_ACCESS) {
|
||||
ct_test(pTest, test_data.type.stream.fileStartPosition ==
|
||||
data->type.stream.fileStartPosition);
|
||||
} else if (test_data.access == FILE_RECORD_ACCESS) {
|
||||
ct_test(pTest, test_data.type.record.fileStartRecord ==
|
||||
data->type.record.fileStartRecord);
|
||||
ct_test(pTest, test_data.type.record.returnedRecordCount ==
|
||||
data->type.record.returnedRecordCount);
|
||||
}
|
||||
ct_test(pTest, octetstring_length(&test_data.fileData) ==
|
||||
octetstring_length(&data->fileData));
|
||||
ct_test(pTest, memcmp(octetstring_value(&test_data.fileData),
|
||||
octetstring_value(&data->fileData),
|
||||
octetstring_length(&test_data.fileData)) == 0);
|
||||
}
|
||||
|
||||
void testAtomicWriteFile(Test * pTest)
|
||||
{
|
||||
BACNET_ATOMIC_WRITE_FILE_DATA data = { 0 };
|
||||
uint8_t test_octet_string[32] = "Joshua-Mary-Anna-Christopher";
|
||||
|
||||
data.object_type = OBJECT_FILE;
|
||||
data.object_instance = 1;
|
||||
data.access = FILE_STREAM_ACCESS;
|
||||
data.type.stream.fileStartPosition = 0;
|
||||
octetstring_init(&data.fileData,
|
||||
test_octet_string, sizeof(test_octet_string));
|
||||
testAtomicWriteFileAccess(pTest, &data);
|
||||
|
||||
data.object_type = OBJECT_FILE;
|
||||
data.object_instance = 1;
|
||||
data.access = FILE_RECORD_ACCESS;
|
||||
data.type.record.fileStartRecord = 1;
|
||||
data.type.record.returnedRecordCount = 2;
|
||||
octetstring_init(&data.fileData,
|
||||
test_octet_string, sizeof(test_octet_string));
|
||||
testAtomicWriteFileAccess(pTest, &data);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void testAtomicWriteFileAckAccess(Test * pTest,
|
||||
BACNET_ATOMIC_WRITE_FILE_DATA * data)
|
||||
{
|
||||
BACNET_ATOMIC_WRITE_FILE_DATA test_data = { 0 };
|
||||
uint8_t apdu[480] = { 0 };
|
||||
int len = 0;
|
||||
int apdu_len = 0;
|
||||
uint8_t invoke_id = 128;
|
||||
uint8_t test_invoke_id = 0;
|
||||
|
||||
len = awf_encode_apdu(&apdu[0], invoke_id, data);
|
||||
ct_test(pTest, len != 0);
|
||||
apdu_len = len;
|
||||
|
||||
len = awf_decode_apdu(&apdu[0], apdu_len, &test_invoke_id, &test_data);
|
||||
ct_test(pTest, len != -1);
|
||||
ct_test(pTest, test_data.access == data->access);
|
||||
if (test_data.access == FILE_STREAM_ACCESS) {
|
||||
ct_test(pTest, test_data.type.stream.fileStartPosition ==
|
||||
data->type.stream.fileStartPosition);
|
||||
} else if (test_data.access == FILE_RECORD_ACCESS) {
|
||||
ct_test(pTest, test_data.type.record.fileStartRecord ==
|
||||
data->type.record.fileStartRecord);
|
||||
}
|
||||
}
|
||||
|
||||
void testAtomicWriteFileAck(Test * pTest)
|
||||
{
|
||||
BACNET_ATOMIC_WRITE_FILE_DATA data = { 0 };
|
||||
|
||||
data.access = FILE_STREAM_ACCESS;
|
||||
data.type.stream.fileStartPosition = 42;
|
||||
testAtomicWriteFileAckAccess(pTest, &data);
|
||||
|
||||
data.access = FILE_RECORD_ACCESS;
|
||||
data.type.record.fileStartRecord = 54;
|
||||
testAtomicWriteFileAckAccess(pTest, &data);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef TEST_ATOMIC_WRITE_FILE
|
||||
uint16_t Device_Max_APDU_Length_Accepted(void)
|
||||
{
|
||||
return MAX_APDU;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
Test *pTest;
|
||||
bool rc;
|
||||
|
||||
pTest = ct_create("BACnet AtomicWriteFile", NULL);
|
||||
/* individual tests */
|
||||
rc = ct_addTestFunction(pTest, testAtomicWriteFile);
|
||||
assert(rc);
|
||||
rc = ct_addTestFunction(pTest, testAtomicWriteFileAck);
|
||||
assert(rc);
|
||||
|
||||
ct_setStream(pTest, stdout);
|
||||
ct_run(pTest);
|
||||
(void) ct_report(pTest);
|
||||
ct_destroy(pTest);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* TEST_WRITE_PROPERTY */
|
||||
#endif /* TEST */
|
||||
@@ -1,97 +0,0 @@
|
||||
/*####COPYRIGHTBEGIN####
|
||||
-------------------------------------------
|
||||
Copyright (C) 2005 Steve Karg
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to:
|
||||
The Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330
|
||||
Boston, MA 02111-1307, USA.
|
||||
|
||||
As a special exception, if other files instantiate templates or
|
||||
use macros or inline functions from this file, or you compile
|
||||
this file and link it with other works to produce a work based
|
||||
on this file, this file does not by itself cause the resulting
|
||||
work to be covered by the GNU General Public License. However
|
||||
the source code for this file must still be made available in
|
||||
accordance with section (3) of the GNU General Public License.
|
||||
|
||||
This exception does not invalidate any other reasons why a work
|
||||
based on this file might be covered by the GNU General Public
|
||||
License.
|
||||
-------------------------------------------
|
||||
####COPYRIGHTEND####*/
|
||||
#ifndef ATOMIC_WRITE_FILE_H
|
||||
#define ATOMIC_WRITE_FILE_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "bacdcode.h"
|
||||
|
||||
typedef struct BACnet_Atomic_Write_File_Data {
|
||||
BACNET_OBJECT_TYPE object_type;
|
||||
uint32_t object_instance;
|
||||
BACNET_FILE_ACCESS_METHOD access;
|
||||
union {
|
||||
struct {
|
||||
int32_t fileStartPosition;
|
||||
} stream;
|
||||
struct {
|
||||
int32_t fileStartRecord;
|
||||
uint32_t returnedRecordCount;
|
||||
} record;
|
||||
} type;
|
||||
BACNET_OCTET_STRING fileData;
|
||||
} BACNET_ATOMIC_WRITE_FILE_DATA;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/* Atomic Write File */
|
||||
/* encode service */
|
||||
int awf_encode_apdu(uint8_t * apdu,
|
||||
uint8_t invoke_id, BACNET_ATOMIC_WRITE_FILE_DATA * data);
|
||||
|
||||
/* decode the service request only */
|
||||
int awf_decode_service_request(uint8_t * apdu,
|
||||
unsigned apdu_len, BACNET_ATOMIC_WRITE_FILE_DATA * data);
|
||||
|
||||
int awf_decode_apdu(uint8_t * apdu,
|
||||
unsigned apdu_len,
|
||||
uint8_t * invoke_id, BACNET_ATOMIC_WRITE_FILE_DATA * data);
|
||||
|
||||
/* Atomic Write File Ack */
|
||||
/* encode service */
|
||||
int awf_ack_encode_apdu(uint8_t * apdu,
|
||||
uint8_t invoke_id, BACNET_ATOMIC_WRITE_FILE_DATA * data);
|
||||
|
||||
/* decode the service request only */
|
||||
int awf_ack_decode_service_request(uint8_t * apdu,
|
||||
unsigned apdu_len, BACNET_ATOMIC_WRITE_FILE_DATA * data);
|
||||
|
||||
int awf_ack_decode_apdu(uint8_t * apdu,
|
||||
unsigned apdu_len,
|
||||
uint8_t * invoke_id, BACNET_ATOMIC_WRITE_FILE_DATA * data);
|
||||
|
||||
#ifdef TEST
|
||||
#include "ctest.h"
|
||||
|
||||
void test_AtomicWriteFile(Test * pTest);
|
||||
void test_AtomicWriteFileAck(Test * pTest);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
@@ -1,34 +0,0 @@
|
||||
#Makefile to build test case
|
||||
CC = gcc
|
||||
BASEDIR = .
|
||||
|
||||
DEFINES = -DBACFILE=1 -DBACDL_BIP=1 -DTEST -DTEST_ATOMIC_WRITE_FILE
|
||||
INCLUDES = -I. -Idemo/object -Itest
|
||||
CFLAGS = -Wall $(INCLUDES) $(DEFINES) -g
|
||||
|
||||
SRCS = bacdcode.c \
|
||||
bacstr.c \
|
||||
bigend.c \
|
||||
awf.c \
|
||||
test/ctest.c
|
||||
|
||||
OBJS = ${SRCS:.c=.o}
|
||||
|
||||
TARGET = atomicwritefile
|
||||
|
||||
all: ${TARGET}
|
||||
|
||||
${TARGET}: ${OBJS}
|
||||
${CC} -o $@ ${OBJS}
|
||||
|
||||
.c.o:
|
||||
${CC} -c ${CFLAGS} $*.c -o $@
|
||||
|
||||
depend:
|
||||
rm -f .depend
|
||||
${CC} -MM ${CFLAGS} *.c >> .depend
|
||||
|
||||
clean:
|
||||
rm -rf core ${TARGET} $(OBJS) *.bak *.1 *.ini
|
||||
|
||||
include: .depend
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,136 +0,0 @@
|
||||
/*####COPYRIGHTBEGIN####
|
||||
-------------------------------------------
|
||||
Copyright (C) 2005 Steve Karg
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to:
|
||||
The Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330
|
||||
Boston, MA 02111-1307, USA.
|
||||
|
||||
As a special exception, if other files instantiate templates or
|
||||
use macros or inline functions from this file, or you compile
|
||||
this file and link it with other works to produce a work based
|
||||
on this file, this file does not by itself cause the resulting
|
||||
work to be covered by the GNU General Public License. However
|
||||
the source code for this file must still be made available in
|
||||
accordance with section (3) of the GNU General Public License.
|
||||
|
||||
This exception does not invalidate any other reasons why a work
|
||||
based on this file might be covered by the GNU General Public
|
||||
License.
|
||||
-------------------------------------------
|
||||
####COPYRIGHTEND####*/
|
||||
#ifndef BACAPP_H
|
||||
#define BACAPP_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacstr.h"
|
||||
#include "datetime.h"
|
||||
|
||||
struct BACnet_Application_Data_Value;
|
||||
typedef struct BACnet_Application_Data_Value {
|
||||
bool context_specific; /* true if context specific data */
|
||||
uint8_t context_tag; /* only used for context specific data */
|
||||
uint8_t tag; /* application tag data type */
|
||||
union {
|
||||
/* NULL - not needed as it is encoded in the tag alone */
|
||||
bool Boolean;
|
||||
uint32_t Unsigned_Int;
|
||||
int32_t Signed_Int;
|
||||
float Real;
|
||||
double Double;
|
||||
BACNET_OCTET_STRING Octet_String;
|
||||
BACNET_CHARACTER_STRING Character_String;
|
||||
BACNET_BIT_STRING Bit_String;
|
||||
int Enumerated;
|
||||
BACNET_DATE Date;
|
||||
BACNET_TIME Time;
|
||||
BACNET_OBJECT_ID Object_Id;
|
||||
} type;
|
||||
/* simple linked list if needed */
|
||||
struct BACnet_Application_Data_Value *next;
|
||||
} BACNET_APPLICATION_DATA_VALUE;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
int bacapp_encode_data(uint8_t * apdu,
|
||||
BACNET_APPLICATION_DATA_VALUE * value);
|
||||
|
||||
int bacapp_decode_application_data(uint8_t * apdu,
|
||||
int max_apdu_len, BACNET_APPLICATION_DATA_VALUE * value);
|
||||
|
||||
int bacapp_encode_application_data(uint8_t * apdu,
|
||||
BACNET_APPLICATION_DATA_VALUE * value);
|
||||
|
||||
int bacapp_decode_context_data(uint8_t * apdu,
|
||||
int max_apdu_len, BACNET_APPLICATION_DATA_VALUE * value,
|
||||
BACNET_PROPERTY_ID property);
|
||||
|
||||
int bacapp_encode_context_data(uint8_t * apdu,
|
||||
BACNET_APPLICATION_DATA_VALUE * value,
|
||||
BACNET_PROPERTY_ID property);
|
||||
|
||||
int bacapp_encode_context_data_value(uint8_t * apdu,
|
||||
uint8_t context_tag_number, BACNET_APPLICATION_DATA_VALUE * value);
|
||||
|
||||
BACNET_APPLICATION_TAG bacapp_context_tag_type(BACNET_PROPERTY_ID
|
||||
property, uint8_t tag_number);
|
||||
|
||||
bool bacapp_copy(BACNET_APPLICATION_DATA_VALUE * dest_value,
|
||||
BACNET_APPLICATION_DATA_VALUE * src_value);
|
||||
|
||||
/* returns the length of data between an opening tag and a closing tag.
|
||||
Expects that the first octet contain the opening tag.
|
||||
Include a value property identifier for context specific data
|
||||
such as the value received in a WriteProperty request */
|
||||
int bacapp_data_len(uint8_t * apdu, int max_apdu_len,
|
||||
BACNET_PROPERTY_ID property);
|
||||
|
||||
#if PRINT_ENABLED
|
||||
#define BACAPP_PRINT_ENABLED
|
||||
#else
|
||||
#ifdef TEST
|
||||
#define BACAPP_PRINT_ENABLED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef BACAPP_PRINT_ENABLED
|
||||
bool bacapp_parse_application_data(BACNET_APPLICATION_TAG tag_number,
|
||||
const char *argv, BACNET_APPLICATION_DATA_VALUE * value);
|
||||
bool bacapp_print_value(FILE * stream,
|
||||
BACNET_APPLICATION_DATA_VALUE * value,
|
||||
BACNET_PROPERTY_ID property);
|
||||
#else
|
||||
#define bacapp_parse_application_data(x,y,z) {(void)x;(void)y;(void)z;}
|
||||
#define bacapp_print_value(x,y,z) {(void)x;(void)y;(void)z;}
|
||||
#endif
|
||||
|
||||
#ifdef TEST
|
||||
#include "ctest.h"
|
||||
#include "datetime.h"
|
||||
bool bacapp_same_value(BACNET_APPLICATION_DATA_VALUE * value,
|
||||
BACNET_APPLICATION_DATA_VALUE * test_value);
|
||||
|
||||
void testBACnetApplicationDataLength(Test * pTest);
|
||||
void testBACnetApplicationData(Test * pTest);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
Binary file not shown.
@@ -1,36 +0,0 @@
|
||||
#Makefile to build test case
|
||||
CC = gcc
|
||||
BASEDIR = .
|
||||
#CFLAGS = -Wall -I.
|
||||
# -g for debugging with gdb
|
||||
#CFLAGS = -Wall -I. -g
|
||||
CFLAGS = -Wall -I. -Itest -DTEST -DTEST_BACNET_APPLICATION_DATA -g
|
||||
|
||||
SRCS = bacdcode.c \
|
||||
bacstr.c \
|
||||
bacapp.c \
|
||||
datetime.c \
|
||||
bactext.c \
|
||||
indtext.c \
|
||||
test/ctest.c
|
||||
|
||||
OBJS = ${SRCS:.c=.o}
|
||||
|
||||
TARGET = bacapp
|
||||
|
||||
all: ${TARGET}
|
||||
|
||||
${TARGET}: ${OBJS}
|
||||
${CC} -o $@ ${OBJS}
|
||||
|
||||
.c.o:
|
||||
${CC} -c ${CFLAGS} $*.c -o $@
|
||||
|
||||
depend:
|
||||
rm -f .depend
|
||||
${CC} -MM ${CFLAGS} *.c >> .depend
|
||||
|
||||
clean:
|
||||
rm -rf core ${TARGET} $(OBJS) *.bak *.1 *.ini
|
||||
|
||||
include: .depend
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,213 +0,0 @@
|
||||
/*####COPYRIGHTBEGIN####
|
||||
-------------------------------------------
|
||||
Copyright (C) 2004 Steve Karg
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to:
|
||||
The Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330
|
||||
Boston, MA 02111-1307, USA.
|
||||
|
||||
As a special exception, if other files instantiate templates or
|
||||
use macros or inline functions from this file, or you compile
|
||||
this file and link it with other works to produce a work based
|
||||
on this file, this file does not by itself cause the resulting
|
||||
work to be covered by the GNU General Public License. However
|
||||
the source code for this file must still be made available in
|
||||
accordance with section (3) of the GNU General Public License.
|
||||
|
||||
This exception does not invalidate any other reasons why a work
|
||||
based on this file might be covered by the GNU General Public
|
||||
License.
|
||||
-------------------------------------------
|
||||
####COPYRIGHTEND####*/
|
||||
#ifndef BACDCODE_H
|
||||
#define BACDCODE_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include "bacdef.h"
|
||||
#include "datetime.h"
|
||||
#include "bacstr.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/* from clause 20.2.1 General Rules for Encoding BACnet Tags */
|
||||
/* returns the number of apdu bytes consumed */
|
||||
int encode_tag(uint8_t * apdu, uint8_t tag_number,
|
||||
bool context_specific, uint32_t len_value_type);
|
||||
|
||||
/* from clause 20.2.1.3.2 Constructed Data */
|
||||
/* returns the number of apdu bytes consumed */
|
||||
int encode_opening_tag(uint8_t * apdu, uint8_t tag_number);
|
||||
int encode_closing_tag(uint8_t * apdu, uint8_t tag_number);
|
||||
int decode_tag_number(uint8_t * apdu, uint8_t * tag_number);
|
||||
int decode_tag_number_and_value(uint8_t * apdu, uint8_t * tag_number,
|
||||
uint32_t * value);
|
||||
/* returns true if the tag is context specific */
|
||||
bool decode_is_context_specific(uint8_t * apdu);
|
||||
/* returns true if the tag is an opening tag and matches */
|
||||
bool decode_is_opening_tag_number(uint8_t * apdu, uint8_t tag_number);
|
||||
/* returns true if the tag is a closing tag and matches */
|
||||
bool decode_is_closing_tag_number(uint8_t * apdu, uint8_t tag_number);
|
||||
/* returns true if the tag is context specific and matches */
|
||||
bool decode_is_context_tag(uint8_t * apdu, uint8_t tag_number);
|
||||
/* returns true if the tag is an opening tag */
|
||||
bool decode_is_opening_tag(uint8_t * apdu);
|
||||
/* returns true if the tag is a closing tag */
|
||||
bool decode_is_closing_tag(uint8_t * apdu);
|
||||
|
||||
/* from clause 20.2.2 Encoding of a Null Value */
|
||||
int encode_tagged_null(uint8_t * apdu);
|
||||
int encode_context_null(uint8_t * apdu, int tag_number);
|
||||
|
||||
/* from clause 20.2.3 Encoding of a Boolean Value */
|
||||
int encode_tagged_boolean(uint8_t * apdu, bool boolean_value);
|
||||
bool decode_boolean(uint32_t len_value);
|
||||
int encode_context_boolean(uint8_t * apdu, int tag_number,
|
||||
bool boolean_value);
|
||||
bool decode_context_boolean(uint8_t * apdu);
|
||||
|
||||
/* from clause 20.2.10 Encoding of a Bit String Value */
|
||||
/* returns the number of apdu bytes consumed */
|
||||
int decode_bitstring(uint8_t * apdu, uint32_t len_value,
|
||||
BACNET_BIT_STRING * bit_string);
|
||||
/* returns the number of apdu bytes consumed */
|
||||
int encode_bitstring(uint8_t * apdu, BACNET_BIT_STRING * bit_string);
|
||||
int encode_tagged_bitstring(uint8_t * apdu,
|
||||
BACNET_BIT_STRING * bit_string);
|
||||
int encode_context_bitstring(uint8_t * apdu, int tag_number,
|
||||
BACNET_BIT_STRING * bit_string);
|
||||
|
||||
/* from clause 20.2.6 Encoding of a Real Number Value */
|
||||
/* and 20.2.1 General Rules for Encoding BACnet Tags */
|
||||
/* returns the number of apdu bytes consumed */
|
||||
int decode_real(uint8_t * apdu, float *real_value);
|
||||
int encode_bacnet_real(float value, uint8_t * apdu);
|
||||
int encode_tagged_real(uint8_t * apdu, float value);
|
||||
int encode_context_real(uint8_t * apdu, int tag_number, float value);
|
||||
|
||||
/* from clause 20.2.14 Encoding of an Object Identifier Value */
|
||||
/* and 20.2.1 General Rules for Encoding BACnet Tags */
|
||||
/* returns the number of apdu bytes consumed */
|
||||
int decode_object_id(uint8_t * apdu, int *object_type,
|
||||
uint32_t * instance);
|
||||
int encode_bacnet_object_id(uint8_t * apdu, int object_type,
|
||||
uint32_t instance);
|
||||
int encode_context_object_id(uint8_t * apdu, int tag_number,
|
||||
int object_type, uint32_t instance);
|
||||
int encode_tagged_object_id(uint8_t * apdu, int object_type,
|
||||
uint32_t instance);
|
||||
|
||||
/* from clause 20.2.8 Encoding of an Octet String Value */
|
||||
/* and 20.2.1 General Rules for Encoding BACnet Tags */
|
||||
/* returns the number of apdu bytes consumed */
|
||||
int encode_octet_string(uint8_t * apdu,
|
||||
BACNET_OCTET_STRING * octet_string);
|
||||
int encode_tagged_octet_string(uint8_t * apdu,
|
||||
BACNET_OCTET_STRING * octet_string);
|
||||
int encode_context_octet_string(uint8_t * apdu,
|
||||
int tag_number, BACNET_OCTET_STRING * octet_string);
|
||||
int decode_octet_string(uint8_t * apdu, uint32_t len_value,
|
||||
BACNET_OCTET_STRING * octet_string);
|
||||
|
||||
|
||||
/* from clause 20.2.9 Encoding of a Character String Value */
|
||||
/* and 20.2.1 General Rules for Encoding BACnet Tags */
|
||||
/* returns the number of apdu bytes consumed */
|
||||
int encode_bacnet_character_string(uint8_t * apdu,
|
||||
BACNET_CHARACTER_STRING * char_string);
|
||||
int encode_tagged_character_string(uint8_t * apdu,
|
||||
BACNET_CHARACTER_STRING * char_string);
|
||||
int encode_context_character_string(uint8_t * apdu, int tag_number,
|
||||
BACNET_CHARACTER_STRING * char_string);
|
||||
int decode_character_string(uint8_t * apdu, uint32_t len_value,
|
||||
BACNET_CHARACTER_STRING * char_string);
|
||||
|
||||
/* from clause 20.2.4 Encoding of an Unsigned Integer Value */
|
||||
/* and 20.2.1 General Rules for Encoding BACnet Tags */
|
||||
/* returns the number of apdu bytes consumed */
|
||||
int encode_bacnet_unsigned(uint8_t * apdu, uint32_t value);
|
||||
int encode_context_unsigned(uint8_t * apdu, int tag_number,
|
||||
uint32_t value);
|
||||
int encode_tagged_unsigned(uint8_t * apdu, uint32_t value);
|
||||
int decode_unsigned(uint8_t * apdu, uint32_t len_value,
|
||||
uint32_t * value);
|
||||
|
||||
/* from clause 20.2.5 Encoding of a Signed Integer Value */
|
||||
/* and 20.2.1 General Rules for Encoding BACnet Tags */
|
||||
/* returns the number of apdu bytes consumed */
|
||||
int encode_bacnet_signed(uint8_t * apdu, int32_t value);
|
||||
int encode_tagged_signed(uint8_t * apdu, int32_t value);
|
||||
int encode_context_signed(uint8_t * apdu, int tag_number,
|
||||
int32_t value);
|
||||
int decode_signed(uint8_t * apdu, uint32_t len_value, int32_t * value);
|
||||
|
||||
/* from clause 20.2.11 Encoding of an Enumerated Value */
|
||||
/* and 20.2.1 General Rules for Encoding BACnet Tags */
|
||||
/* returns the number of apdu bytes consumed */
|
||||
int decode_enumerated(uint8_t * apdu, uint32_t len_value, int *value);
|
||||
int encode_bacnet_enumerated(uint8_t * apdu, int value);
|
||||
int encode_tagged_enumerated(uint8_t * apdu, int value);
|
||||
int encode_context_enumerated(uint8_t * apdu, int tag_number,
|
||||
int value);
|
||||
|
||||
/* from clause 20.2.13 Encoding of a Time Value */
|
||||
/* and 20.2.1 General Rules for Encoding BACnet Tags */
|
||||
/* returns the number of apdu bytes consumed */
|
||||
int encode_bacnet_time(uint8_t * apdu, BACNET_TIME * btime);
|
||||
int encode_tagged_time(uint8_t * apdu, BACNET_TIME * btime);
|
||||
int decode_bacnet_time(uint8_t * apdu, BACNET_TIME * btime);
|
||||
int encode_context_time(uint8_t * apdu, int tag_number,
|
||||
BACNET_TIME * btime);
|
||||
|
||||
/* BACnet Date */
|
||||
/* year = years since 1900 */
|
||||
/* month 1=Jan */
|
||||
/* day = day of month */
|
||||
/* wday 1=Monday...7=Sunday */
|
||||
|
||||
/* from clause 20.2.12 Encoding of a Date Value */
|
||||
/* and 20.2.1 General Rules for Encoding BACnet Tags */
|
||||
/* returns the number of apdu bytes consumed */
|
||||
int encode_bacnet_date(uint8_t * apdu, BACNET_DATE * bdate);
|
||||
int encode_tagged_date(uint8_t * apdu, BACNET_DATE * bdate);
|
||||
int encode_context_date(uint8_t * apdu, int tag_number,
|
||||
BACNET_DATE * bdate);
|
||||
int decode_date(uint8_t * apdu, BACNET_DATE * bdate);
|
||||
|
||||
/* two octet unsigned16 */
|
||||
int encode_unsigned16(uint8_t * apdu, uint16_t value);
|
||||
int decode_unsigned16(uint8_t * apdu, uint16_t * value);
|
||||
/* four octet unsigned32 */
|
||||
int encode_unsigned32(uint8_t * apdu, uint32_t value);
|
||||
int decode_unsigned32(uint8_t * apdu, uint32_t * value);
|
||||
|
||||
/* from clause 20.1.2.4 max-segments-accepted */
|
||||
/* and clause 20.1.2.5 max-APDU-length-accepted */
|
||||
/* returns the encoded octet */
|
||||
uint8_t encode_max_segs_max_apdu(int max_segs, int max_apdu);
|
||||
int decode_max_segs(uint8_t octet);
|
||||
int decode_max_apdu(uint8_t octet);
|
||||
|
||||
/* returns the number of apdu bytes consumed */
|
||||
int encode_simple_ack(uint8_t * apdu, uint8_t invoke_id,
|
||||
uint8_t service_choice);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
Binary file not shown.
@@ -1,30 +0,0 @@
|
||||
#Makefile to build unit tests
|
||||
CC = gcc
|
||||
BASEDIR = .
|
||||
CFLAGS = -Wall -I. -Itest -g -DTEST -DTEST_DECODE
|
||||
|
||||
TARGET = bacdcode
|
||||
|
||||
SRCS = bacdcode.c \
|
||||
bacstr.c \
|
||||
bigend.c \
|
||||
test/ctest.c
|
||||
|
||||
OBJS = ${SRCS:.c=.o}
|
||||
|
||||
all: ${TARGET}
|
||||
|
||||
${TARGET}: ${OBJS}
|
||||
${CC} -o $@ ${OBJS}
|
||||
|
||||
.c.o:
|
||||
${CC} -c ${CFLAGS} $*.c -o $@
|
||||
|
||||
depend:
|
||||
rm -f .depend
|
||||
${CC} -MM ${CFLAGS} *.c >> .depend
|
||||
|
||||
clean:
|
||||
rm -rf core ${OBJS} ${TARGET} *.bak
|
||||
|
||||
include: .depend
|
||||
@@ -1,99 +0,0 @@
|
||||
/*####COPYRIGHTBEGIN####
|
||||
-------------------------------------------
|
||||
Copyright (C) 2005 Steve Karg
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to:
|
||||
The Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330
|
||||
Boston, MA 02111-1307, USA.
|
||||
|
||||
As a special exception, if other files instantiate templates or
|
||||
use macros or inline functions from this file, or you compile
|
||||
this file and link it with other works to produce a work based
|
||||
on this file, this file does not by itself cause the resulting
|
||||
work to be covered by the GNU General Public License. However
|
||||
the source code for this file must still be made available in
|
||||
accordance with section (3) of the GNU General Public License.
|
||||
|
||||
This exception does not invalidate any other reasons why a work
|
||||
based on this file might be covered by the GNU General Public
|
||||
License.
|
||||
-------------------------------------------
|
||||
####COPYRIGHTEND####*/
|
||||
#ifndef BACDEF_H
|
||||
#define BACDEF_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include "bacenum.h"
|
||||
#include "config.h"
|
||||
|
||||
/* This stack implements this version of BACnet */
|
||||
#define BACNET_PROTOCOL_VERSION 1
|
||||
#define BACNET_PROTOCOL_REVISION 5
|
||||
|
||||
/* largest BACnet Instance Number */
|
||||
/* Also used as a device instance number wildcard address */
|
||||
#define BACNET_MAX_INSTANCE (0x3FFFFF)
|
||||
#define BACNET_INSTANCE_BITS 22
|
||||
/* large BACnet Object Type */
|
||||
#define BACNET_MAX_OBJECT (0x3FF)
|
||||
/* Array index 0=size of array, n=array element n, MAX=all array elements */
|
||||
#define BACNET_ARRAY_ALL (~0)
|
||||
/* Priority Array for commandable objects */
|
||||
#define BACNET_NO_PRIORITY 0
|
||||
#define BACNET_MIN_PRIORITY 1
|
||||
#define BACNET_MAX_PRIORITY 16
|
||||
|
||||
/* embedded systems need fixed name sizes */
|
||||
#define MAX_OBJECT_NAME 10
|
||||
/* common object properties */
|
||||
typedef struct BACnet_Object_Data {
|
||||
uint32_t Object_Identifier;
|
||||
char Object_Name[MAX_OBJECT_NAME];
|
||||
BACNET_OBJECT_TYPE Object_Type;
|
||||
} BACNET_OBJECT_DATA;
|
||||
|
||||
#define BACNET_BROADCAST_NETWORK 0xFFFF
|
||||
/* IPv6 (16 octets) coupled with port number (2 octets) */
|
||||
#define MAX_MAC_LEN 18
|
||||
struct BACnet_Device_Address {
|
||||
/* mac_len = 0 if global address */
|
||||
int mac_len;
|
||||
/* note: MAC for IP addresses uses 4 bytes for addr, 2 bytes for port */
|
||||
/* use de/encode_unsigned32/16 for re/storing the IP address */
|
||||
uint8_t mac[MAX_MAC_LEN];
|
||||
/* DNET,DLEN,DADR or SNET,SLEN,SADR */
|
||||
/* the following are used if the device is behind a router */
|
||||
/* net = 0 indicates local */
|
||||
uint16_t net; /* BACnet network number */
|
||||
/* LEN = 0 denotes broadcast MAC ADR and ADR field is absent */
|
||||
/* LEN > 0 specifies length of ADR field */
|
||||
int len; /* length of MAC address */
|
||||
uint8_t adr[MAX_MAC_LEN]; /* hwaddr (MAC) address */
|
||||
};
|
||||
typedef struct BACnet_Device_Address BACNET_ADDRESS;
|
||||
|
||||
/* note: with microprocessors having lots more code space than memory,
|
||||
it might be better to have a packed encoding with a library to
|
||||
easily access the data. */
|
||||
typedef struct BACnet_Object_Id {
|
||||
uint16_t type;
|
||||
uint32_t instance;
|
||||
} BACNET_OBJECT_ID;
|
||||
|
||||
#define MAX_NPDU (1+1+2+1+MAX_MAC_LEN+2+1+MAX_MAC_LEN+1+1+2)
|
||||
#define MAX_PDU (MAX_APDU + MAX_NPDU)
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,259 +0,0 @@
|
||||
/*####COPYRIGHTBEGIN####
|
||||
-------------------------------------------
|
||||
Copyright (C) 2005 Steve Karg
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to:
|
||||
The Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330
|
||||
Boston, MA 02111-1307, USA.
|
||||
|
||||
As a special exception, if other files instantiate templates or
|
||||
use macros or inline functions from this file, or you compile
|
||||
this file and link it with other works to produce a work based
|
||||
on this file, this file does not by itself cause the resulting
|
||||
work to be covered by the GNU General Public License. However
|
||||
the source code for this file must still be made available in
|
||||
accordance with section (3) of the GNU General Public License.
|
||||
|
||||
This exception does not invalidate any other reasons why a work
|
||||
based on this file might be covered by the GNU General Public
|
||||
License.
|
||||
-------------------------------------------
|
||||
####COPYRIGHTEND####*/
|
||||
#include <stdint.h>
|
||||
#include "bacenum.h"
|
||||
#include "bacdcode.h"
|
||||
#include "bacdef.h"
|
||||
|
||||
/* encode service */
|
||||
int bacerror_encode_apdu(uint8_t * apdu,
|
||||
uint8_t invoke_id,
|
||||
BACNET_CONFIRMED_SERVICE service,
|
||||
BACNET_ERROR_CLASS error_class, BACNET_ERROR_CODE error_code)
|
||||
{
|
||||
int apdu_len = 0; /* total length of the apdu, return value */
|
||||
|
||||
if (apdu) {
|
||||
apdu[0] = PDU_TYPE_ERROR;
|
||||
apdu[1] = invoke_id;
|
||||
apdu[2] = service;
|
||||
apdu_len = 3;
|
||||
/* service parameters */
|
||||
apdu_len += encode_tagged_enumerated(&apdu[apdu_len], error_class);
|
||||
apdu_len += encode_tagged_enumerated(&apdu[apdu_len], error_code);
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
/* decode the application class and code */
|
||||
int bacerror_decode_error_class_and_code(uint8_t * apdu,
|
||||
unsigned apdu_len,
|
||||
BACNET_ERROR_CLASS * error_class, BACNET_ERROR_CODE * error_code)
|
||||
{
|
||||
int len = 0;
|
||||
uint8_t tag_number = 0;
|
||||
uint32_t len_value_type = 0;
|
||||
int decoded_value = 0;
|
||||
|
||||
if (apdu_len) {
|
||||
/* error class */
|
||||
len += decode_tag_number_and_value(&apdu[len],
|
||||
&tag_number, &len_value_type);
|
||||
if (tag_number != BACNET_APPLICATION_TAG_ENUMERATED)
|
||||
return 0;
|
||||
len +=
|
||||
decode_enumerated(&apdu[len], len_value_type, &decoded_value);
|
||||
if (error_class)
|
||||
*error_class = decoded_value;
|
||||
/* error code */
|
||||
len += decode_tag_number_and_value(&apdu[len],
|
||||
&tag_number, &len_value_type);
|
||||
if (tag_number != BACNET_APPLICATION_TAG_ENUMERATED)
|
||||
return 0;
|
||||
len +=
|
||||
decode_enumerated(&apdu[len], len_value_type, &decoded_value);
|
||||
if (error_code)
|
||||
*error_code = decoded_value;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/* decode the service request only */
|
||||
int bacerror_decode_service_request(uint8_t * apdu,
|
||||
unsigned apdu_len,
|
||||
uint8_t * invoke_id,
|
||||
BACNET_CONFIRMED_SERVICE * service,
|
||||
BACNET_ERROR_CLASS * error_class, BACNET_ERROR_CODE * error_code)
|
||||
{
|
||||
int len = 0;
|
||||
|
||||
if (apdu_len > 2) {
|
||||
if (invoke_id)
|
||||
*invoke_id = apdu[0];
|
||||
if (service)
|
||||
*service = apdu[1];
|
||||
/* decode the application class and code */
|
||||
len = bacerror_decode_error_class_and_code(&apdu[2],
|
||||
apdu_len - 2, error_class, error_code);
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include "ctest.h"
|
||||
|
||||
/* decode the whole APDU - mainly used for unit testing */
|
||||
int bacerror_decode_apdu(uint8_t * apdu,
|
||||
unsigned apdu_len,
|
||||
uint8_t * invoke_id,
|
||||
BACNET_CONFIRMED_SERVICE * service,
|
||||
BACNET_ERROR_CLASS * error_class, BACNET_ERROR_CODE * error_code)
|
||||
{
|
||||
int len = 0;
|
||||
|
||||
if (!apdu)
|
||||
return -1;
|
||||
/* optional checking - most likely was already done prior to this call */
|
||||
if (apdu_len) {
|
||||
if (apdu[0] != PDU_TYPE_ERROR)
|
||||
return -1;
|
||||
if (apdu_len > 1) {
|
||||
len = bacerror_decode_service_request(&apdu[1],
|
||||
apdu_len - 1, invoke_id, service, error_class, error_code);
|
||||
}
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
void testBACError(Test * pTest)
|
||||
{
|
||||
uint8_t apdu[480] = { 0 };
|
||||
int len = 0;
|
||||
int apdu_len = 0;
|
||||
uint8_t invoke_id = 0;
|
||||
BACNET_CONFIRMED_SERVICE service = 0;
|
||||
BACNET_ERROR_CLASS error_class = 0;
|
||||
BACNET_ERROR_CODE error_code = 0;
|
||||
uint8_t test_invoke_id = 0;
|
||||
BACNET_CONFIRMED_SERVICE test_service = 0;
|
||||
BACNET_ERROR_CLASS test_error_class = 0;
|
||||
BACNET_ERROR_CODE test_error_code = 0;
|
||||
|
||||
len = bacerror_encode_apdu(&apdu[0],
|
||||
invoke_id, service, error_class, error_code);
|
||||
ct_test(pTest, len != 0);
|
||||
apdu_len = len;
|
||||
|
||||
len = bacerror_decode_apdu(&apdu[0],
|
||||
apdu_len,
|
||||
&test_invoke_id,
|
||||
&test_service, &test_error_class, &test_error_code);
|
||||
ct_test(pTest, len != -1);
|
||||
ct_test(pTest, test_invoke_id == invoke_id);
|
||||
ct_test(pTest, test_service == service);
|
||||
ct_test(pTest, test_error_class == error_class);
|
||||
ct_test(pTest, test_error_code == error_code);
|
||||
|
||||
/* change type to get negative response */
|
||||
apdu[0] = PDU_TYPE_ABORT;
|
||||
len = bacerror_decode_apdu(&apdu[0],
|
||||
apdu_len,
|
||||
&test_invoke_id,
|
||||
&test_service, &test_error_class, &test_error_code);
|
||||
ct_test(pTest, len == -1);
|
||||
|
||||
/* test NULL APDU */
|
||||
len = bacerror_decode_apdu(NULL,
|
||||
apdu_len,
|
||||
&test_invoke_id,
|
||||
&test_service, &test_error_class, &test_error_code);
|
||||
ct_test(pTest, len == -1);
|
||||
|
||||
/* force a zero length */
|
||||
len = bacerror_decode_apdu(&apdu[0],
|
||||
0,
|
||||
&test_invoke_id,
|
||||
&test_service, &test_error_class, &test_error_code);
|
||||
ct_test(pTest, len == 0);
|
||||
|
||||
|
||||
/* check them all... */
|
||||
for (service = 0; service < MAX_BACNET_CONFIRMED_SERVICE; service++) {
|
||||
for (error_class = 0;
|
||||
error_class < MAX_BACNET_ERROR_CLASS; error_class++) {
|
||||
for (error_code = 0;
|
||||
error_code < MAX_BACNET_ERROR_CODE; error_code++) {
|
||||
len = bacerror_encode_apdu(&apdu[0],
|
||||
invoke_id, service, error_class, error_code);
|
||||
apdu_len = len;
|
||||
ct_test(pTest, len != 0);
|
||||
len = bacerror_decode_apdu(&apdu[0],
|
||||
apdu_len,
|
||||
&test_invoke_id,
|
||||
&test_service, &test_error_class, &test_error_code);
|
||||
ct_test(pTest, len != -1);
|
||||
ct_test(pTest, test_invoke_id == invoke_id);
|
||||
ct_test(pTest, test_service == service);
|
||||
ct_test(pTest, test_error_class == error_class);
|
||||
ct_test(pTest, test_error_code == error_code);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* max boundaries */
|
||||
service = 255;
|
||||
error_class = LAST_PROPRIETARY_ERROR_CLASS;
|
||||
error_code = LAST_PROPRIETARY_ERROR_CODE;
|
||||
len = bacerror_encode_apdu(&apdu[0],
|
||||
invoke_id, service, error_class, error_code);
|
||||
apdu_len = len;
|
||||
ct_test(pTest, len != 0);
|
||||
len = bacerror_decode_apdu(&apdu[0],
|
||||
apdu_len,
|
||||
&test_invoke_id,
|
||||
&test_service, &test_error_class, &test_error_code);
|
||||
ct_test(pTest, len != -1);
|
||||
ct_test(pTest, test_invoke_id == invoke_id);
|
||||
ct_test(pTest, test_service == service);
|
||||
ct_test(pTest, test_error_class == error_class);
|
||||
ct_test(pTest, test_error_code == error_code);
|
||||
|
||||
}
|
||||
|
||||
#ifdef TEST_BACERROR
|
||||
int main(void)
|
||||
{
|
||||
Test *pTest;
|
||||
bool rc;
|
||||
|
||||
pTest = ct_create("BACnet Error", NULL);
|
||||
/* individual tests */
|
||||
rc = ct_addTestFunction(pTest, testBACError);
|
||||
assert(rc);
|
||||
|
||||
ct_setStream(pTest, stdout);
|
||||
ct_run(pTest);
|
||||
(void) ct_report(pTest);
|
||||
ct_destroy(pTest);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* TEST_ERROR */
|
||||
#endif /* TEST */
|
||||
@@ -1,74 +0,0 @@
|
||||
/*####COPYRIGHTBEGIN####
|
||||
-------------------------------------------
|
||||
Copyright (C) 2005 Steve Karg
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to:
|
||||
The Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330
|
||||
Boston, MA 02111-1307, USA.
|
||||
|
||||
As a special exception, if other files instantiate templates or
|
||||
use macros or inline functions from this file, or you compile
|
||||
this file and link it with other works to produce a work based
|
||||
on this file, this file does not by itself cause the resulting
|
||||
work to be covered by the GNU General Public License. However
|
||||
the source code for this file must still be made available in
|
||||
accordance with section (3) of the GNU General Public License.
|
||||
|
||||
This exception does not invalidate any other reasons why a work
|
||||
based on this file might be covered by the GNU General Public
|
||||
License.
|
||||
-------------------------------------------
|
||||
####COPYRIGHTEND####*/
|
||||
#ifndef BACERROR_H
|
||||
#define BACERROR_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "bacenum.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
int bacerror_encode_apdu(uint8_t * apdu,
|
||||
uint8_t invoke_id,
|
||||
BACNET_CONFIRMED_SERVICE service,
|
||||
BACNET_ERROR_CLASS error_class, BACNET_ERROR_CODE error_code);
|
||||
|
||||
int bacerror_decode_service_request(uint8_t * apdu,
|
||||
unsigned apdu_len,
|
||||
uint8_t * invoke_id,
|
||||
BACNET_CONFIRMED_SERVICE * service,
|
||||
BACNET_ERROR_CLASS * error_class, BACNET_ERROR_CODE * error_code);
|
||||
|
||||
int bacerror_decode_error_class_and_code(uint8_t * apdu,
|
||||
unsigned apdu_len,
|
||||
BACNET_ERROR_CLASS * error_class, BACNET_ERROR_CODE * error_code);
|
||||
|
||||
#ifdef TEST
|
||||
#include "ctest.h"
|
||||
int bacerror_decode_apdu(uint8_t * apdu,
|
||||
unsigned apdu_len,
|
||||
uint8_t * invoke_id,
|
||||
BACNET_CONFIRMED_SERVICE * service,
|
||||
BACNET_ERROR_CLASS * error_class, BACNET_ERROR_CODE * error_code);
|
||||
|
||||
void testBACError(Test * pTest);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
@@ -1,34 +0,0 @@
|
||||
#Makefile to build test case
|
||||
CC = gcc
|
||||
BASEDIR = .
|
||||
#CFLAGS = -Wall -I.
|
||||
# -g for debugging with gdb
|
||||
#CFLAGS = -Wall -I. -g
|
||||
CFLAGS = -Wall -I. -Itest -DTEST -DTEST_BACERROR -g
|
||||
|
||||
SRCS = bacdcode.c \
|
||||
bacstr.c \
|
||||
bigend.c \
|
||||
bacerror.c \
|
||||
test/ctest.c
|
||||
|
||||
OBJS = ${SRCS:.c=.o}
|
||||
|
||||
TARGET = bacerror
|
||||
|
||||
all: ${TARGET}
|
||||
|
||||
${TARGET}: ${OBJS}
|
||||
${CC} -o $@ ${OBJS}
|
||||
|
||||
.c.o:
|
||||
${CC} -c ${CFLAGS} $*.c -o $@
|
||||
|
||||
depend:
|
||||
rm -f .depend
|
||||
${CC} -MM ${CFLAGS} *.c >> .depend
|
||||
|
||||
clean:
|
||||
rm -rf core ${TARGET} $(OBJS) *.bak *.1 *.ini
|
||||
|
||||
include: .depend
|
||||
@@ -1,111 +0,0 @@
|
||||
/*####COPYRIGHTBEGIN####
|
||||
-------------------------------------------
|
||||
Copyright (C) 2005 John Goulah
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to
|
||||
The Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330
|
||||
Boston, MA 02111-1307, USA.
|
||||
|
||||
As a special exception, if other files instantiate templates or
|
||||
use macros or inline functions from this file, or you compile
|
||||
this file and link it with other works to produce a work based
|
||||
on this file, this file does not by itself cause the resulting
|
||||
work to be covered by the GNU General Public License. However
|
||||
the source code for this file must still be made available in
|
||||
accordance with section (3) of the GNU General Public License.
|
||||
|
||||
This exception does not invalidate any other reasons why a work
|
||||
based on this file might be covered by the GNU General Public
|
||||
License.
|
||||
-------------------------------------------
|
||||
####COPYRIGHTEND####*/
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "bacprop.h"
|
||||
|
||||
PROP_TAG_DATA bacnet_object_device_property_tag_map[] = {
|
||||
{PROP_OBJECT_IDENTIFIER, BACNET_APPLICATION_TAG_OBJECT_ID}
|
||||
,
|
||||
{PROP_OBJECT_NAME, BACNET_APPLICATION_TAG_CHARACTER_STRING}
|
||||
,
|
||||
{PROP_OBJECT_TYPE, BACNET_APPLICATION_TAG_ENUMERATED}
|
||||
,
|
||||
{PROP_SYSTEM_STATUS, BACNET_APPLICATION_TAG_ENUMERATED}
|
||||
,
|
||||
{PROP_VENDOR_NAME, BACNET_APPLICATION_TAG_CHARACTER_STRING}
|
||||
,
|
||||
{PROP_VENDOR_IDENTIFIER, BACNET_APPLICATION_TAG_UNSIGNED_INT}
|
||||
,
|
||||
{PROP_MODEL_NAME, BACNET_APPLICATION_TAG_CHARACTER_STRING}
|
||||
,
|
||||
{PROP_FIRMWARE_REVISION, BACNET_APPLICATION_TAG_CHARACTER_STRING}
|
||||
,
|
||||
{PROP_APPLICATION_SOFTWARE_VERSION,
|
||||
BACNET_APPLICATION_TAG_CHARACTER_STRING}
|
||||
,
|
||||
{PROP_PROTOCOL_VERSION, BACNET_APPLICATION_TAG_UNSIGNED_INT}
|
||||
,
|
||||
{PROP_PROTOCOL_CONFORMANCE_CLASS, BACNET_APPLICATION_TAG_UNSIGNED_INT}
|
||||
,
|
||||
{PROP_PROTOCOL_SERVICES_SUPPORTED, BACNET_APPLICATION_TAG_BIT_STRING}
|
||||
,
|
||||
{PROP_PROTOCOL_OBJECT_TYPES_SUPPORTED,
|
||||
BACNET_APPLICATION_TAG_BIT_STRING}
|
||||
,
|
||||
{PROP_MAX_APDU_LENGTH_ACCEPTED, BACNET_APPLICATION_TAG_UNSIGNED_INT}
|
||||
,
|
||||
{PROP_SEGMENTATION_SUPPORTED, BACNET_APPLICATION_TAG_ENUMERATED}
|
||||
,
|
||||
{PROP_APDU_TIMEOUT, BACNET_APPLICATION_TAG_UNSIGNED_INT}
|
||||
,
|
||||
{PROP_NUMBER_OF_APDU_RETRIES, BACNET_APPLICATION_TAG_UNSIGNED_INT}
|
||||
,
|
||||
{-1, -1}
|
||||
};
|
||||
|
||||
signed bacprop_tag_by_index_default(PROP_TAG_DATA * data_list,
|
||||
signed index, signed default_ret)
|
||||
{
|
||||
signed pUnsigned = 0;
|
||||
|
||||
if (data_list) {
|
||||
while (data_list->prop_id != -1) {
|
||||
if (data_list->prop_id == index) {
|
||||
pUnsigned = data_list->tag_id;
|
||||
break;
|
||||
}
|
||||
data_list++;
|
||||
}
|
||||
}
|
||||
|
||||
return pUnsigned ? pUnsigned : default_ret;
|
||||
}
|
||||
|
||||
|
||||
signed bacprop_property_tag(BACNET_OBJECT_TYPE type, signed prop)
|
||||
{
|
||||
switch (type) {
|
||||
case OBJECT_DEVICE:
|
||||
return
|
||||
bacprop_tag_by_index_default
|
||||
(bacnet_object_device_property_tag_map, prop, -1);
|
||||
default:
|
||||
fprintf(stderr, "Unsupported object type");
|
||||
break;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
/*####COPYRIGHTBEGIN####
|
||||
-------------------------------------------
|
||||
Copyright (C) 2005 John Goulah
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to
|
||||
The Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330
|
||||
Boston, MA 02111-1307, USA.
|
||||
|
||||
As a special exception, if other files instantiate templates or
|
||||
use macros or inline functions from this file, or you compile
|
||||
this file and link it with other works to produce a work based
|
||||
on this file, this file does not by itself cause the resulting
|
||||
work to be covered by the GNU General Public License. However
|
||||
the source code for this file must still be made available in
|
||||
accordance with section (3) of the GNU General Public License.
|
||||
|
||||
This exception does not invalidate any other reasons why a work
|
||||
based on this file might be covered by the GNU General Public
|
||||
License.
|
||||
-------------------------------------------
|
||||
####COPYRIGHTEND####*/
|
||||
#ifndef BACPROP_H
|
||||
#define BACPROP_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "bacenum.h"
|
||||
|
||||
typedef struct {
|
||||
signed prop_id; /* index number that matches the text */
|
||||
signed tag_id; /* text pair - use NULL to end the list */
|
||||
} PROP_TAG_DATA;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
signed bacprop_tag_by_index_default(PROP_TAG_DATA * data_list,
|
||||
signed index, signed default_ret);
|
||||
|
||||
signed bacprop_property_tag(BACNET_OBJECT_TYPE type, signed prop);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
@@ -1,637 +0,0 @@
|
||||
/*####COPYRIGHTBEGIN####
|
||||
-------------------------------------------
|
||||
Copyright (C) 2004 Steve Karg
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to:
|
||||
The Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330
|
||||
Boston, MA 02111-1307, USA.
|
||||
|
||||
As a special exception, if other files instantiate templates or
|
||||
use macros or inline functions from this file, or you compile
|
||||
this file and link it with other works to produce a work based
|
||||
on this file, this file does not by itself cause the resulting
|
||||
work to be covered by the GNU General Public License. However
|
||||
the source code for this file must still be made available in
|
||||
accordance with section (3) of the GNU General Public License.
|
||||
|
||||
This exception does not invalidate any other reasons why a work
|
||||
based on this file might be covered by the GNU General Public
|
||||
License.
|
||||
-------------------------------------------
|
||||
####COPYRIGHTEND####*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h> /* for strlen */
|
||||
#include "bacstr.h"
|
||||
#include "bits.h"
|
||||
|
||||
void bitstring_init(BACNET_BIT_STRING * bit_string)
|
||||
{
|
||||
int i;
|
||||
|
||||
bit_string->bits_used = 0;
|
||||
for (i = 0; i < MAX_BITSTRING_BYTES; i++) {
|
||||
bit_string->value[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void bitstring_set_bit(BACNET_BIT_STRING * bit_string, uint8_t bit,
|
||||
bool value)
|
||||
{
|
||||
uint8_t byte_number = bit / 8;
|
||||
uint8_t bit_mask = 1;
|
||||
|
||||
if (byte_number < MAX_BITSTRING_BYTES) {
|
||||
/* set max bits used */
|
||||
if (bit_string->bits_used < (bit + 1))
|
||||
bit_string->bits_used = bit + 1;
|
||||
bit_mask = bit_mask << (bit - (byte_number * 8));
|
||||
if (value)
|
||||
bit_string->value[byte_number] |= bit_mask;
|
||||
else
|
||||
bit_string->value[byte_number] &= (~(bit_mask));
|
||||
}
|
||||
}
|
||||
|
||||
bool bitstring_bit(BACNET_BIT_STRING * bit_string, uint8_t bit)
|
||||
{
|
||||
bool value = false;
|
||||
uint8_t byte_number = bit / 8;
|
||||
uint8_t bit_mask = 1;
|
||||
|
||||
if (bit < (MAX_BITSTRING_BYTES * 8)) {
|
||||
bit_mask = bit_mask << (bit - (byte_number * 8));
|
||||
if (bit_string->value[byte_number] & bit_mask)
|
||||
value = true;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
uint8_t bitstring_bits_used(BACNET_BIT_STRING * bit_string)
|
||||
{
|
||||
return bit_string->bits_used;
|
||||
}
|
||||
|
||||
/* returns the number of bytes that a bit string is using */
|
||||
int bitstring_bytes_used(BACNET_BIT_STRING * bit_string)
|
||||
{
|
||||
int len = 0; /* return value */
|
||||
uint8_t used_bytes = 0;
|
||||
uint8_t last_bit = 0;
|
||||
|
||||
if (bit_string->bits_used) {
|
||||
last_bit = bit_string->bits_used - 1;
|
||||
used_bytes = last_bit / 8;
|
||||
/* add one for the first byte */
|
||||
used_bytes++;
|
||||
len = used_bytes;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
uint8_t bitstring_octet(BACNET_BIT_STRING * bit_string, uint8_t index)
|
||||
{
|
||||
uint8_t octet = 0;
|
||||
|
||||
if (bit_string) {
|
||||
if (index < MAX_BITSTRING_BYTES) {
|
||||
octet = bit_string->value[index];
|
||||
}
|
||||
}
|
||||
|
||||
return octet;
|
||||
}
|
||||
|
||||
bool bitstring_set_octet(BACNET_BIT_STRING * bit_string,
|
||||
uint8_t index, uint8_t octet)
|
||||
{
|
||||
bool status = false;
|
||||
|
||||
if (bit_string) {
|
||||
if (index < MAX_BITSTRING_BYTES) {
|
||||
bit_string->value[index] = octet;
|
||||
status = true;
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
bool bitstring_set_bits_used(BACNET_BIT_STRING * bit_string,
|
||||
uint8_t bytes_used, uint8_t unused_bits)
|
||||
{
|
||||
bool status = false;
|
||||
|
||||
if (bit_string) {
|
||||
/* FIXME: check that bytes_used is at least one? */
|
||||
bit_string->bits_used = bytes_used * 8;
|
||||
bit_string->bits_used -= unused_bits;
|
||||
status = true;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
uint8_t bitstring_bits_capacity(BACNET_BIT_STRING * bit_string)
|
||||
{
|
||||
if (bit_string)
|
||||
return (sizeof(bit_string->value) * 8);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define CHARACTER_STRING_CAPACITY (MAX_CHARACTER_STRING_BYTES - 1)
|
||||
/* returns false if the string exceeds capacity
|
||||
initialize by using length=0 */
|
||||
bool characterstring_init(BACNET_CHARACTER_STRING * char_string,
|
||||
uint8_t encoding, char *value, size_t length)
|
||||
{
|
||||
bool status = false; /* return value */
|
||||
size_t i; /* counter */
|
||||
|
||||
if (char_string) {
|
||||
char_string->length = 0;
|
||||
char_string->encoding = encoding;
|
||||
/* save a byte at the end for NULL -
|
||||
note: assumes printable characters */
|
||||
if (length <= CHARACTER_STRING_CAPACITY) {
|
||||
if (value) {
|
||||
for (i = 0; i < MAX_CHARACTER_STRING_BYTES; i++) {
|
||||
if (i < length) {
|
||||
char_string->value[char_string->length] = value[i];
|
||||
char_string->length++;
|
||||
} else
|
||||
char_string->value[i] = 0;
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < MAX_CHARACTER_STRING_BYTES; i++) {
|
||||
char_string->value[i] = 0;
|
||||
}
|
||||
}
|
||||
status = true;
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
bool characterstring_init_ansi(BACNET_CHARACTER_STRING * char_string,
|
||||
char *value)
|
||||
{
|
||||
return characterstring_init(char_string,
|
||||
CHARACTER_ANSI_X34, value, value ? strlen(value) : 0);
|
||||
}
|
||||
|
||||
bool characterstring_copy(BACNET_CHARACTER_STRING * dest,
|
||||
BACNET_CHARACTER_STRING * src)
|
||||
{
|
||||
return characterstring_init(dest,
|
||||
characterstring_encoding(src),
|
||||
characterstring_value(src), characterstring_length(src));
|
||||
}
|
||||
|
||||
bool characterstring_same(BACNET_CHARACTER_STRING * dest,
|
||||
BACNET_CHARACTER_STRING * src)
|
||||
{
|
||||
size_t i; /* counter */
|
||||
bool same_status = false;
|
||||
|
||||
if (src && dest) {
|
||||
if ((src->length == dest->length) &&
|
||||
(src->encoding == dest->encoding)) {
|
||||
same_status = true;
|
||||
for (i = 0; i < src->length; i++) {
|
||||
if (src->value[i] != dest->value[i]) {
|
||||
same_status = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (src) {
|
||||
if (src->length == 0)
|
||||
same_status = true;
|
||||
} else if (dest) {
|
||||
if (dest->length == 0)
|
||||
same_status = true;
|
||||
}
|
||||
|
||||
return same_status;
|
||||
}
|
||||
|
||||
bool characterstring_ansi_same(BACNET_CHARACTER_STRING * dest,
|
||||
const char *src)
|
||||
{
|
||||
size_t i; /* counter */
|
||||
bool same_status = false;
|
||||
|
||||
if (src && dest) {
|
||||
if ((dest->length == strlen(src)) &&
|
||||
(dest->encoding == CHARACTER_ANSI_X34)) {
|
||||
same_status = true;
|
||||
for (i = 0; i < dest->length; i++) {
|
||||
if (src[i] != dest->value[i]) {
|
||||
same_status = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* NULL matches an empty string in our world */
|
||||
else if (src) {
|
||||
if (strlen(src) == 0)
|
||||
same_status = true;
|
||||
} else if (dest) {
|
||||
if (dest->length == 0)
|
||||
same_status = true;
|
||||
}
|
||||
|
||||
return same_status;
|
||||
}
|
||||
|
||||
/* returns false if the string exceeds capacity */
|
||||
bool characterstring_append(BACNET_CHARACTER_STRING * char_string,
|
||||
char *value, size_t length)
|
||||
{
|
||||
size_t i; /* counter */
|
||||
bool status = false; /* return value */
|
||||
|
||||
if (char_string) {
|
||||
if ((length + char_string->length) <= CHARACTER_STRING_CAPACITY) {
|
||||
for (i = 0; i < length; i++) {
|
||||
char_string->value[char_string->length] = value[i];
|
||||
char_string->length++;
|
||||
}
|
||||
status = true;
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* This function sets a new length without changing the value.
|
||||
If length exceeds capacity, no modification happens and
|
||||
function returns false. */
|
||||
bool characterstring_truncate(BACNET_CHARACTER_STRING * char_string,
|
||||
size_t length)
|
||||
{
|
||||
bool status = false; /* return value */
|
||||
|
||||
if (char_string) {
|
||||
if (length <= CHARACTER_STRING_CAPACITY) {
|
||||
char_string->length = length;
|
||||
status = true;
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Returns the value. */
|
||||
char *characterstring_value(BACNET_CHARACTER_STRING * char_string)
|
||||
{
|
||||
char *value = NULL;
|
||||
|
||||
if (char_string) {
|
||||
value = char_string->value;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/* returns the length. */
|
||||
size_t characterstring_length(BACNET_CHARACTER_STRING * char_string)
|
||||
{
|
||||
size_t length = 0;
|
||||
|
||||
if (char_string) {
|
||||
/* FIXME: validate length is within bounds? */
|
||||
length = char_string->length;
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
size_t characterstring_capacity(BACNET_CHARACTER_STRING * char_string)
|
||||
{
|
||||
size_t length = 0;
|
||||
|
||||
if (char_string) {
|
||||
length = CHARACTER_STRING_CAPACITY;
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
/* returns the encoding. */
|
||||
uint8_t characterstring_encoding(BACNET_CHARACTER_STRING * char_string)
|
||||
{
|
||||
uint8_t encoding = 0;
|
||||
|
||||
if (char_string) {
|
||||
encoding = char_string->encoding;
|
||||
}
|
||||
|
||||
return encoding;
|
||||
}
|
||||
|
||||
/* returns false if the string exceeds capacity
|
||||
initialize by using length=0 */
|
||||
bool octetstring_init(BACNET_OCTET_STRING * octet_string,
|
||||
uint8_t * value, size_t length)
|
||||
{
|
||||
bool status = false; /* return value */
|
||||
size_t i; /* counter */
|
||||
|
||||
if (octet_string) {
|
||||
octet_string->length = 0;
|
||||
if (length <= sizeof(octet_string->value)) {
|
||||
if (value) {
|
||||
for (i = 0; i < length; i++) {
|
||||
octet_string->value[octet_string->length] = value[i];
|
||||
octet_string->length++;
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < sizeof(octet_string->value); i++) {
|
||||
octet_string->value[i] = 0;
|
||||
}
|
||||
}
|
||||
status = true;
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
bool octetstring_copy(BACNET_OCTET_STRING * dest,
|
||||
BACNET_OCTET_STRING * src)
|
||||
{
|
||||
return octetstring_init(dest,
|
||||
octetstring_value(src), octetstring_length(src));
|
||||
}
|
||||
|
||||
/* returns false if the string exceeds capacity */
|
||||
bool octetstring_append(BACNET_OCTET_STRING * octet_string,
|
||||
uint8_t * value, size_t length)
|
||||
{
|
||||
size_t i; /* counter */
|
||||
bool status = false; /* return value */
|
||||
|
||||
if (octet_string) {
|
||||
if ((length + octet_string->length) <= sizeof(octet_string->value)) {
|
||||
for (i = 0; i < length; i++) {
|
||||
octet_string->value[octet_string->length] = value[i];
|
||||
octet_string->length++;
|
||||
}
|
||||
status = true;
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* This function sets a new length without changing the value.
|
||||
If length exceeds capacity, no modification happens and
|
||||
function returns false. */
|
||||
bool octetstring_truncate(BACNET_OCTET_STRING * octet_string,
|
||||
size_t length)
|
||||
{
|
||||
bool status = false; /* return value */
|
||||
|
||||
if (octet_string) {
|
||||
if (length <= sizeof(octet_string->value)) {
|
||||
octet_string->length = length;
|
||||
status = true;
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* returns the length. Returns the value in parameter. */
|
||||
uint8_t *octetstring_value(BACNET_OCTET_STRING * octet_string)
|
||||
{
|
||||
uint8_t *value = NULL;
|
||||
|
||||
if (octet_string) {
|
||||
value = octet_string->value;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/* returns the length. */
|
||||
size_t octetstring_length(BACNET_OCTET_STRING * octet_string)
|
||||
{
|
||||
size_t length = 0;
|
||||
|
||||
if (octet_string) {
|
||||
/* FIXME: validate length is within bounds? */
|
||||
length = octet_string->length;
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
/* returns the length. */
|
||||
size_t octetstring_capacity(BACNET_OCTET_STRING * octet_string)
|
||||
{
|
||||
size_t length = 0;
|
||||
|
||||
if (octet_string) {
|
||||
/* FIXME: validate length is within bounds? */
|
||||
length = sizeof(octet_string->value);
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include "ctest.h"
|
||||
|
||||
void testBitString(Test * pTest)
|
||||
{
|
||||
uint8_t bit = 0;
|
||||
BACNET_BIT_STRING bit_string;
|
||||
|
||||
bitstring_init(&bit_string);
|
||||
/* verify initialization */
|
||||
ct_test(pTest, bitstring_bits_used(&bit_string) == 0);
|
||||
for (bit = 0; bit < (MAX_BITSTRING_BYTES * 8); bit++) {
|
||||
ct_test(pTest, bitstring_bit(&bit_string, bit) == false);
|
||||
}
|
||||
|
||||
/* test for true */
|
||||
for (bit = 0; bit < (MAX_BITSTRING_BYTES * 8); bit++) {
|
||||
bitstring_set_bit(&bit_string, bit, true);
|
||||
ct_test(pTest, bitstring_bits_used(&bit_string) == (bit + 1));
|
||||
ct_test(pTest, bitstring_bit(&bit_string, bit) == true);
|
||||
}
|
||||
/* test for false */
|
||||
bitstring_init(&bit_string);
|
||||
for (bit = 0; bit < (MAX_BITSTRING_BYTES * 8); bit++) {
|
||||
bitstring_set_bit(&bit_string, bit, false);
|
||||
ct_test(pTest, bitstring_bits_used(&bit_string) == (bit + 1));
|
||||
ct_test(pTest, bitstring_bit(&bit_string, bit) == false);
|
||||
}
|
||||
}
|
||||
|
||||
void testCharacterString(Test * pTest)
|
||||
{
|
||||
BACNET_CHARACTER_STRING bacnet_string;
|
||||
char *value = "Joshua,Mary,Anna,Christopher";
|
||||
char test_value[MAX_APDU] = "Patricia";
|
||||
char test_append_value[MAX_APDU] = " and the Kids";
|
||||
char test_append_string[MAX_APDU] = "";
|
||||
bool status = false;
|
||||
size_t length = 0;
|
||||
size_t test_length = 0;
|
||||
size_t i = 0;
|
||||
|
||||
/* verify initialization */
|
||||
status =
|
||||
characterstring_init(&bacnet_string, CHARACTER_ANSI_X34, NULL, 0);
|
||||
ct_test(pTest, status == true);
|
||||
ct_test(pTest, characterstring_length(&bacnet_string) == 0);
|
||||
ct_test(pTest,
|
||||
characterstring_encoding(&bacnet_string) == CHARACTER_ANSI_X34);
|
||||
/* bounds check */
|
||||
status = characterstring_init(&bacnet_string,
|
||||
CHARACTER_ANSI_X34,
|
||||
NULL, characterstring_capacity(&bacnet_string) + 1);
|
||||
ct_test(pTest, status == false);
|
||||
status =
|
||||
characterstring_truncate(&bacnet_string,
|
||||
characterstring_capacity(&bacnet_string) + 1);
|
||||
ct_test(pTest, status == false);
|
||||
status =
|
||||
characterstring_truncate(&bacnet_string,
|
||||
characterstring_capacity(&bacnet_string));
|
||||
ct_test(pTest, status == true);
|
||||
|
||||
test_length = strlen(test_value);
|
||||
status = characterstring_init(&bacnet_string,
|
||||
CHARACTER_ANSI_X34, &test_value[0], test_length);
|
||||
ct_test(pTest, status == true);
|
||||
value = characterstring_value(&bacnet_string);
|
||||
length = characterstring_length(&bacnet_string);
|
||||
ct_test(pTest, length == test_length);
|
||||
for (i = 0; i < test_length; i++) {
|
||||
ct_test(pTest, value[i] == test_value[i]);
|
||||
}
|
||||
test_length = strlen(test_append_value);
|
||||
status = characterstring_append(&bacnet_string,
|
||||
&test_append_value[0], test_length);
|
||||
strcat(test_append_string, test_value);
|
||||
strcat(test_append_string, test_append_value);
|
||||
test_length = strlen(test_append_string);
|
||||
ct_test(pTest, status == true);
|
||||
length = characterstring_length(&bacnet_string);
|
||||
value = characterstring_value(&bacnet_string);
|
||||
ct_test(pTest, length == test_length);
|
||||
for (i = 0; i < test_length; i++) {
|
||||
ct_test(pTest, value[i] == test_append_string[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void testOctetString(Test * pTest)
|
||||
{
|
||||
BACNET_OCTET_STRING bacnet_string;
|
||||
uint8_t *value = NULL;
|
||||
uint8_t test_value[MAX_APDU] = "Patricia";
|
||||
uint8_t test_append_value[MAX_APDU] = " and the Kids";
|
||||
uint8_t test_append_string[MAX_APDU] = "";
|
||||
bool status = false;
|
||||
size_t length = 0;
|
||||
size_t test_length = 0;
|
||||
size_t i = 0;
|
||||
|
||||
/* verify initialization */
|
||||
status = octetstring_init(&bacnet_string, NULL, 0);
|
||||
ct_test(pTest, status == true);
|
||||
ct_test(pTest, octetstring_length(&bacnet_string) == 0);
|
||||
value = octetstring_value(&bacnet_string);
|
||||
for (i = 0; i < octetstring_capacity(&bacnet_string); i++) {
|
||||
ct_test(pTest, value[i] == 0);
|
||||
}
|
||||
/* bounds check */
|
||||
status = octetstring_init(&bacnet_string, NULL,
|
||||
octetstring_capacity(&bacnet_string) + 1);
|
||||
ct_test(pTest, status == false);
|
||||
status = octetstring_init(&bacnet_string, NULL,
|
||||
octetstring_capacity(&bacnet_string));
|
||||
ct_test(pTest, status == true);
|
||||
status =
|
||||
octetstring_truncate(&bacnet_string,
|
||||
octetstring_capacity(&bacnet_string) + 1);
|
||||
ct_test(pTest, status == false);
|
||||
status =
|
||||
octetstring_truncate(&bacnet_string,
|
||||
octetstring_capacity(&bacnet_string));
|
||||
ct_test(pTest, status == true);
|
||||
|
||||
test_length = strlen((char *) test_value);
|
||||
status = octetstring_init(&bacnet_string, &test_value[0], test_length);
|
||||
ct_test(pTest, status == true);
|
||||
length = octetstring_length(&bacnet_string);
|
||||
value = octetstring_value(&bacnet_string);
|
||||
ct_test(pTest, length == test_length);
|
||||
for (i = 0; i < test_length; i++) {
|
||||
ct_test(pTest, value[i] == test_value[i]);
|
||||
}
|
||||
|
||||
test_length = strlen((char *) test_append_value);
|
||||
status = octetstring_append(&bacnet_string,
|
||||
&test_append_value[0], test_length);
|
||||
strcat((char *) test_append_string, (char *) test_value);
|
||||
strcat((char *) test_append_string, (char *) test_append_value);
|
||||
test_length = strlen((char *) test_append_string);
|
||||
ct_test(pTest, status == true);
|
||||
length = octetstring_length(&bacnet_string);
|
||||
value = octetstring_value(&bacnet_string);
|
||||
ct_test(pTest, length == test_length);
|
||||
for (i = 0; i < test_length; i++) {
|
||||
ct_test(pTest, value[i] == test_append_string[i]);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef TEST_BACSTR
|
||||
int main(void)
|
||||
{
|
||||
Test *pTest;
|
||||
bool rc;
|
||||
|
||||
pTest = ct_create("BACnet Strings", NULL);
|
||||
/* individual tests */
|
||||
rc = ct_addTestFunction(pTest, testBitString);
|
||||
assert(rc);
|
||||
rc = ct_addTestFunction(pTest, testCharacterString);
|
||||
assert(rc);
|
||||
rc = ct_addTestFunction(pTest, testOctetString);
|
||||
assert(rc);
|
||||
/* configure output */
|
||||
ct_setStream(pTest, stdout);
|
||||
ct_run(pTest);
|
||||
(void) ct_report(pTest);
|
||||
ct_destroy(pTest);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* TEST_BACSTR */
|
||||
#endif /* TEST */
|
||||
@@ -1,141 +0,0 @@
|
||||
/*####COPYRIGHTBEGIN####
|
||||
-------------------------------------------
|
||||
Copyright (C) 2005 Steve Karg
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to:
|
||||
The Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330
|
||||
Boston, MA 02111-1307, USA.
|
||||
|
||||
As a special exception, if other files instantiate templates or
|
||||
use macros or inline functions from this file, or you compile
|
||||
this file and link it with other works to produce a work based
|
||||
on this file, this file does not by itself cause the resulting
|
||||
work to be covered by the GNU General Public License. However
|
||||
the source code for this file must still be made available in
|
||||
accordance with section (3) of the GNU General Public License.
|
||||
|
||||
This exception does not invalidate any other reasons why a work
|
||||
based on this file might be covered by the GNU General Public
|
||||
License.
|
||||
-------------------------------------------
|
||||
####COPYRIGHTEND####*/
|
||||
#ifndef BACSTR_H
|
||||
#define BACSTR_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include "bacdef.h"
|
||||
|
||||
/* bit strings
|
||||
They could be as large as 256/8=32 octets */
|
||||
#define MAX_BITSTRING_BYTES 15
|
||||
typedef struct BACnet_Bit_String {
|
||||
uint8_t bits_used;
|
||||
uint8_t value[MAX_BITSTRING_BYTES];
|
||||
} BACNET_BIT_STRING;
|
||||
|
||||
#define MAX_CHARACTER_STRING_BYTES (MAX_APDU-6)
|
||||
typedef struct BACnet_Character_String {
|
||||
size_t length;
|
||||
uint8_t encoding;
|
||||
/* limit - 6 octets is the most our tag and type could be */
|
||||
char value[MAX_CHARACTER_STRING_BYTES];
|
||||
} BACNET_CHARACTER_STRING;
|
||||
|
||||
/* FIXME: convert the bacdcode library to use BACNET_OCTET_STRING
|
||||
for APDU buffer to prevent buffer overflows */
|
||||
typedef struct BACnet_Octet_String {
|
||||
size_t length;
|
||||
/* limit - 6 octets is the most our tag and type could be */
|
||||
uint8_t value[MAX_APDU - 6];
|
||||
} BACNET_OCTET_STRING;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
void bitstring_init(BACNET_BIT_STRING * bit_string);
|
||||
void bitstring_set_bit(BACNET_BIT_STRING * bit_string, uint8_t bit,
|
||||
bool value);
|
||||
bool bitstring_bit(BACNET_BIT_STRING * bit_string, uint8_t bit);
|
||||
uint8_t bitstring_bits_used(BACNET_BIT_STRING * bit_string);
|
||||
/* returns the number of bytes that a bit string is using */
|
||||
int bitstring_bytes_used(BACNET_BIT_STRING * bit_string);
|
||||
uint8_t bitstring_bits_capacity(BACNET_BIT_STRING * bit_string);
|
||||
/* used for encoding and decoding from the APDU */
|
||||
uint8_t bitstring_octet(BACNET_BIT_STRING * bit_string,
|
||||
uint8_t octet_index);
|
||||
bool bitstring_set_octet(BACNET_BIT_STRING * bit_string, uint8_t index,
|
||||
uint8_t octet);
|
||||
bool bitstring_set_bits_used(BACNET_BIT_STRING * bit_string,
|
||||
uint8_t bytes_used, uint8_t unused_bits);
|
||||
|
||||
/* returns false if the string exceeds capacity
|
||||
initialize by using length=0 */
|
||||
bool characterstring_init(BACNET_CHARACTER_STRING * char_string,
|
||||
uint8_t encoding, char *value, size_t length);
|
||||
/* used for ANSI C-Strings */
|
||||
bool characterstring_init_ansi(BACNET_CHARACTER_STRING * char_string,
|
||||
char *value);
|
||||
bool characterstring_copy(BACNET_CHARACTER_STRING * dest,
|
||||
BACNET_CHARACTER_STRING * src);
|
||||
/* returns true if the strings are the same length, encoding, value */
|
||||
bool characterstring_same(BACNET_CHARACTER_STRING * dest,
|
||||
BACNET_CHARACTER_STRING * src);
|
||||
bool characterstring_ansi_same(BACNET_CHARACTER_STRING * dest,
|
||||
const char *src);
|
||||
/* returns false if the string exceeds capacity */
|
||||
bool characterstring_append(BACNET_CHARACTER_STRING * char_string,
|
||||
char *value, size_t length);
|
||||
/* This function sets a new length without changing the value.
|
||||
If length exceeds capacity, no modification happens and
|
||||
function returns false. */
|
||||
bool characterstring_truncate(BACNET_CHARACTER_STRING * char_string,
|
||||
size_t length);
|
||||
bool characterstring_set_encoding(BACNET_CHARACTER_STRING *
|
||||
char_string, uint8_t encoding);
|
||||
/* Returns the value */
|
||||
char *characterstring_value(BACNET_CHARACTER_STRING * char_string);
|
||||
/* returns the length */
|
||||
size_t characterstring_length(BACNET_CHARACTER_STRING * char_string);
|
||||
uint8_t characterstring_encoding(BACNET_CHARACTER_STRING *
|
||||
char_string);
|
||||
size_t characterstring_capacity(BACNET_CHARACTER_STRING * char_string);
|
||||
|
||||
/* returns false if the string exceeds capacity
|
||||
initialize by using length=0 */
|
||||
bool octetstring_init(BACNET_OCTET_STRING * octet_string,
|
||||
uint8_t * value, size_t length);
|
||||
bool octetstring_copy(BACNET_OCTET_STRING * dest,
|
||||
BACNET_OCTET_STRING * src);
|
||||
/* returns false if the string exceeds capacity */
|
||||
bool octetstring_append(BACNET_OCTET_STRING * octet_string,
|
||||
uint8_t * value, size_t length);
|
||||
/* This function sets a new length without changing the value.
|
||||
If length exceeds capacity, no modification happens and
|
||||
function returns false. */
|
||||
bool octetstring_truncate(BACNET_OCTET_STRING * octet_string,
|
||||
size_t length);
|
||||
/* Returns the value */
|
||||
uint8_t *octetstring_value(BACNET_OCTET_STRING * octet_string);
|
||||
/* Returns the length.*/
|
||||
size_t octetstring_length(BACNET_OCTET_STRING * octet_string);
|
||||
size_t octetstring_capacity(BACNET_OCTET_STRING * octet_string);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
@@ -1,28 +0,0 @@
|
||||
#Makefile to build unit tests
|
||||
CC = gcc
|
||||
BASEDIR = .
|
||||
CFLAGS = -Wall -I. -Itest -g -DTEST -DTEST_BACSTR
|
||||
|
||||
TARGET = bacstr
|
||||
|
||||
SRCS = bacstr.c \
|
||||
test/ctest.c
|
||||
|
||||
OBJS = ${SRCS:.c=.o}
|
||||
|
||||
all: ${TARGET}
|
||||
|
||||
${TARGET}: ${OBJS}
|
||||
${CC} -o $@ ${OBJS}
|
||||
|
||||
.c.o:
|
||||
${CC} -c ${CFLAGS} $*.c -o $@
|
||||
|
||||
depend:
|
||||
rm -f .depend
|
||||
${CC} -MM ${CFLAGS} *.c >> .depend
|
||||
|
||||
clean:
|
||||
rm -rf core ${OBJS} ${TARGET} *.bak
|
||||
|
||||
include: .depend
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,81 +0,0 @@
|
||||
/*####COPYRIGHTBEGIN####
|
||||
-------------------------------------------
|
||||
Copyright (C) 2005 Steve Karg
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to
|
||||
The Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330
|
||||
Boston, MA 02111-1307, USA.
|
||||
|
||||
As a special exception, if other files instantiate templates or
|
||||
use macros or inline functions from this file, or you compile
|
||||
this file and link it with other works to produce a work based
|
||||
on this file, this file does not by itself cause the resulting
|
||||
work to be covered by the GNU General Public License. However
|
||||
the source code for this file must still be made available in
|
||||
accordance with section (3) of the GNU General Public License.
|
||||
|
||||
This exception does not invalidate any other reasons why a work
|
||||
based on this file might be covered by the GNU General Public
|
||||
License.
|
||||
-------------------------------------------
|
||||
####COPYRIGHTEND####*/
|
||||
#ifndef BACTEXT_H
|
||||
#define BACTEXT_H
|
||||
|
||||
/* tiny implementations have no need to print */
|
||||
#if PRINT_ENABLED
|
||||
#define BACTEXT_PRINT_ENABLED
|
||||
#else
|
||||
#ifdef TEST
|
||||
#define BACTEXT_PRINT_ENABLED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef BACTEXT_PRINT_ENABLED
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "indtext.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
const char *bactext_confirmed_service_name(int index);
|
||||
const char *bactext_unconfirmed_service_name(int index);
|
||||
const char *bactext_application_tag_name(int index);
|
||||
const char *bactext_object_type_name(int index);
|
||||
const char *bactext_property_name(int index);
|
||||
const char *bactext_engineering_unit_name(int index);
|
||||
const char *bactext_reject_reason_name(int index);
|
||||
const char *bactext_abort_reason_name(int index);
|
||||
const char *bactext_error_class_name(int index);
|
||||
const char *bactext_error_code_name(int index);
|
||||
unsigned bactext_property_id(const char *name);
|
||||
const char *bactext_month_name(int index);
|
||||
const char *bactext_week_of_month_name(int index);
|
||||
const char *bactext_day_of_week_name(int index);
|
||||
const char *bactext_event_state_name(int index);
|
||||
const char *bactext_binary_present_value_name(int index);
|
||||
const char *bactext_reliability_name(int index);
|
||||
const char *bactext_device_status_name(int index);
|
||||
const char *bactext_segmentation_name(int index);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif /* BACTEXT_PRINT_ENABLED */
|
||||
#endif
|
||||
@@ -1,28 +0,0 @@
|
||||
/* Big-Endian systems save the most significant byte first. */
|
||||
/* Sun and Motorola processors, IBM-370s and PDP-10s are big-endian. */
|
||||
/* "Network Byte Order" is also know as "Big-Endian Byte Order" */
|
||||
/* for example, a 4 byte integer 67305985 is 0x04030201 in hexidecimal. */
|
||||
/* x[0] = 0x04 */
|
||||
/* x[1] = 0x03 */
|
||||
/* x[2] = 0x02 */
|
||||
/* x[3] = 0x01 */
|
||||
|
||||
/* Little-Endian systems save the least significant byte first. */
|
||||
/* The entire Intel x86 family, Vaxes, Alphas and PDP-11s are little-endian. */
|
||||
/* for example, a 4 byte integer 67305985 is 0x04030201 in hexidecimal. */
|
||||
/* x[0] = 0x01 */
|
||||
/* x[1] = 0x02 */
|
||||
/* x[2] = 0x03 */
|
||||
/* x[3] = 0x04 */
|
||||
|
||||
int big_endian(void)
|
||||
{
|
||||
union {
|
||||
long l;
|
||||
char c[sizeof(long)];
|
||||
} u;
|
||||
|
||||
u.l = 1;
|
||||
|
||||
return (u.c[sizeof(long) - 1] == 1);
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
#ifndef BIGEND_H
|
||||
#define BIGEND_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/* Big-Endian systems save the most significant byte first. */
|
||||
/* Sun and Motorola processors, IBM-370s and PDP-10s are big-endian. */
|
||||
/* for example, a 4 byte integer 67305985 is 0x04030201 in hexidecimal. */
|
||||
/* x[0] = 0x04 */
|
||||
/* x[1] = 0x03 */
|
||||
/* x[2] = 0x02 */
|
||||
/* x[3] = 0x01 */
|
||||
|
||||
/* Little-Endian systems save the least significant byte first. */
|
||||
/* The entire Intel x86 family, Vaxes, Alphas and PDP-11s are little-endian. */
|
||||
/* for example, a 4 byte integer 67305985 is 0x04030201 in hexidecimal. */
|
||||
/* x[0] = 0x01 */
|
||||
/* x[1] = 0x02 */
|
||||
/* x[2] = 0x03 */
|
||||
/* x[3] = 0x04 */
|
||||
|
||||
int big_endian(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
@@ -1,282 +0,0 @@
|
||||
/*####COPYRIGHTBEGIN####
|
||||
-------------------------------------------
|
||||
Copyright (C) 2005 Steve Karg
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to:
|
||||
The Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330
|
||||
Boston, MA 02111-1307, USA.
|
||||
|
||||
As a special exception, if other files instantiate templates or
|
||||
use macros or inline functions from this file, or you compile
|
||||
this file and link it with other works to produce a work based
|
||||
on this file, this file does not by itself cause the resulting
|
||||
work to be covered by the GNU General Public License. However
|
||||
the source code for this file must still be made available in
|
||||
accordance with section (3) of the GNU General Public License.
|
||||
|
||||
This exception does not invalidate any other reasons why a work
|
||||
based on this file might be covered by the GNU General Public
|
||||
License.
|
||||
-------------------------------------------
|
||||
####COPYRIGHTEND####*/
|
||||
|
||||
#include <stdint.h> /* for standard integer types uint8_t etc. */
|
||||
#include <stdbool.h> /* for the standard bool type. */
|
||||
#include "bacdcode.h"
|
||||
#include "bip.h"
|
||||
#include "net.h" /* custom per port */
|
||||
|
||||
static int BIP_Socket = -1;
|
||||
/* port to use - stored in host byte order */
|
||||
static uint16_t BIP_Port = 0xBAC0;
|
||||
/* IP Address - stored in host byte order */
|
||||
static struct in_addr BIP_Address;
|
||||
/* Broadcast Address - stored in host byte order */
|
||||
static struct in_addr BIP_Broadcast_Address;
|
||||
|
||||
void bip_set_socket(int sock_fd)
|
||||
{
|
||||
BIP_Socket = sock_fd;
|
||||
}
|
||||
|
||||
int bip_socket(void)
|
||||
{
|
||||
return BIP_Socket;
|
||||
}
|
||||
|
||||
bool bip_valid(void)
|
||||
{
|
||||
return (BIP_Socket != -1);
|
||||
}
|
||||
|
||||
void bip_cleanup(void)
|
||||
{
|
||||
if (bip_valid())
|
||||
close(BIP_Socket);
|
||||
BIP_Socket = -1;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* set using network byte order */
|
||||
void bip_set_addr(uint32_t net_address)
|
||||
{
|
||||
BIP_Address.s_addr = ntohl(net_address);
|
||||
}
|
||||
|
||||
/* returns host byte order */
|
||||
uint32_t bip_get_addr(void)
|
||||
{
|
||||
return BIP_Address.s_addr;
|
||||
}
|
||||
|
||||
/* set using network byte order */
|
||||
void bip_set_broadcast_addr(uint32_t net_address)
|
||||
{
|
||||
BIP_Broadcast_Address.s_addr = ntohl(net_address);
|
||||
}
|
||||
|
||||
/* returns host byte order */
|
||||
uint32_t bip_get_broadcast_addr(void)
|
||||
{
|
||||
return BIP_Broadcast_Address.s_addr;
|
||||
}
|
||||
|
||||
/* set using host byte order */
|
||||
void bip_set_port(uint16_t port)
|
||||
{
|
||||
BIP_Port = port;
|
||||
}
|
||||
|
||||
/* returns host byte order */
|
||||
uint16_t bip_get_port(void)
|
||||
{
|
||||
return BIP_Port;
|
||||
}
|
||||
|
||||
/* function to send a packet out the BACnet/IP socket (Annex J) */
|
||||
/* returns number of bytes sent on success, negative number on failure */
|
||||
int bip_send_pdu(BACNET_ADDRESS * dest, /* destination address */
|
||||
BACNET_NPDU_DATA * npdu_data, /* network information */
|
||||
uint8_t * pdu, /* any data to be sent - may be null */
|
||||
unsigned pdu_len)
|
||||
{ /* number of bytes of data */
|
||||
struct sockaddr_in bip_dest;
|
||||
uint8_t mtu[MAX_MPDU] = { 0 };
|
||||
int mtu_len = 0;
|
||||
int bytes_sent = 0;
|
||||
|
||||
(void) npdu_data;
|
||||
/* assumes that the driver has already been initialized */
|
||||
if (BIP_Socket < 0)
|
||||
return BIP_Socket;
|
||||
|
||||
mtu[0] = BVLL_TYPE_BACNET_IP;
|
||||
bip_dest.sin_family = AF_INET;
|
||||
if (dest->mac_len == 6) {
|
||||
(void) decode_unsigned32(&dest->mac[0],
|
||||
&(bip_dest.sin_addr.s_addr));
|
||||
(void) decode_unsigned16(&dest->mac[4], &(bip_dest.sin_port));
|
||||
memset(&(bip_dest.sin_zero), '\0', 8);
|
||||
mtu[1] = BVLC_ORIGINAL_UNICAST_NPDU;
|
||||
}
|
||||
/* broadcast */
|
||||
else if (dest->mac_len == 0) {
|
||||
bip_dest.sin_addr.s_addr = htonl(BIP_Broadcast_Address.s_addr);
|
||||
bip_dest.sin_port = htons(BIP_Port);
|
||||
memset(&(bip_dest.sin_zero), '\0', 8);
|
||||
mtu[1] = BVLC_ORIGINAL_BROADCAST_NPDU;
|
||||
} else
|
||||
return -1;
|
||||
|
||||
mtu_len = 2;
|
||||
mtu_len +=
|
||||
encode_unsigned16(&mtu[mtu_len],
|
||||
(uint16_t) (pdu_len + 4 /*inclusive */ ));
|
||||
memcpy(&mtu[mtu_len], pdu, pdu_len);
|
||||
mtu_len += pdu_len;
|
||||
|
||||
/* Send the packet */
|
||||
bytes_sent = sendto(BIP_Socket, (char *) mtu, mtu_len, 0,
|
||||
(struct sockaddr *) &bip_dest, sizeof(struct sockaddr));
|
||||
|
||||
return bytes_sent;
|
||||
}
|
||||
|
||||
/* receives a BACnet/IP packet */
|
||||
/* returns the number of octets in the PDU, or zero on failure */
|
||||
uint16_t bip_receive(BACNET_ADDRESS * src, /* source address */
|
||||
uint8_t * pdu, /* PDU data */
|
||||
uint16_t max_pdu, /* amount of space available in the PDU */
|
||||
unsigned timeout)
|
||||
{ /* number of milliseconds to wait for a packet */
|
||||
int received_bytes;
|
||||
uint8_t buf[MAX_MPDU] = { 0 }; /* data */
|
||||
uint16_t pdu_len = 0; /* return value */
|
||||
fd_set read_fds;
|
||||
int max;
|
||||
struct timeval select_timeout;
|
||||
struct sockaddr_in sin = { -1 };
|
||||
socklen_t sin_len = sizeof(sin);
|
||||
|
||||
/* Make sure the socket is open */
|
||||
if (BIP_Socket < 0)
|
||||
return 0;
|
||||
|
||||
/* we could just use a non-blocking socket, but that consumes all
|
||||
the CPU time. We can use a timeout; it is only supported as
|
||||
a select. */
|
||||
if (timeout >= 1000) {
|
||||
select_timeout.tv_sec = timeout / 1000;
|
||||
select_timeout.tv_usec =
|
||||
1000 * (timeout - select_timeout.tv_sec * 1000);
|
||||
} else {
|
||||
select_timeout.tv_sec = 0;
|
||||
select_timeout.tv_usec = 1000 * timeout;
|
||||
}
|
||||
FD_ZERO(&read_fds);
|
||||
FD_SET((unsigned int) BIP_Socket, &read_fds);
|
||||
max = BIP_Socket;
|
||||
/* see if there is a packet for us */
|
||||
if (select(max + 1, &read_fds, NULL, NULL, &select_timeout) > 0)
|
||||
received_bytes = recvfrom(BIP_Socket,
|
||||
(char *) &buf[0], MAX_MPDU, 0,
|
||||
(struct sockaddr *) &sin, &sin_len);
|
||||
else
|
||||
return 0;
|
||||
|
||||
/* See if there is a problem */
|
||||
if (received_bytes < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* no problem, just no bytes */
|
||||
if (received_bytes == 0)
|
||||
return 0;
|
||||
|
||||
/* the signature of a BACnet/IP packet */
|
||||
if (buf[0] != BVLL_TYPE_BACNET_IP)
|
||||
return 0;
|
||||
if ((buf[1] == BVLC_ORIGINAL_UNICAST_NPDU) ||
|
||||
(buf[1] == BVLC_ORIGINAL_BROADCAST_NPDU)) {
|
||||
/* ignore messages from me */
|
||||
if (sin.sin_addr.s_addr == BIP_Address.s_addr)
|
||||
pdu_len = 0;
|
||||
else {
|
||||
/* copy the source address
|
||||
FIXME: IPv6? */
|
||||
src->mac_len = 6;
|
||||
(void) encode_unsigned32(&src->mac[0], sin.sin_addr.s_addr);
|
||||
(void) encode_unsigned16(&src->mac[4], sin.sin_port);
|
||||
/* FIXME: check destination address */
|
||||
/* see if it is broadcast or for us */
|
||||
/* decode the length of the PDU - length is inclusive of BVLC */
|
||||
(void) decode_unsigned16(&buf[2], &pdu_len);
|
||||
/* copy the buffer into the PDU */
|
||||
pdu_len -= 4; /* BVLC header */
|
||||
if (pdu_len < max_pdu)
|
||||
memmove(&pdu[0], &buf[4], pdu_len);
|
||||
/* ignore packets that are too large */
|
||||
/* clients should check my max-apdu first */
|
||||
else
|
||||
pdu_len = 0;
|
||||
}
|
||||
}
|
||||
#ifdef BBMD_ENABLED
|
||||
if (buf[1] < MAX_BVLC_FUNCTION) {
|
||||
bbmd_handler(&buf[0], received_bytes, &sin);
|
||||
}
|
||||
#endif
|
||||
|
||||
return pdu_len;
|
||||
}
|
||||
|
||||
void bip_get_my_address(BACNET_ADDRESS * my_address)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
my_address->mac_len = 6;
|
||||
(void) encode_unsigned32(&my_address->mac[0],
|
||||
htonl(BIP_Address.s_addr));
|
||||
(void) encode_unsigned16(&my_address->mac[4], htons(BIP_Port));
|
||||
my_address->net = 0; /* local only, no routing */
|
||||
my_address->len = 0; /* no SLEN */
|
||||
for (i = 0; i < MAX_MAC_LEN; i++) {
|
||||
/* no SADR */
|
||||
my_address->adr[i] = 0;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void bip_get_broadcast_address(BACNET_ADDRESS * dest)
|
||||
{ /* destination address */
|
||||
int i = 0; /* counter */
|
||||
|
||||
if (dest) {
|
||||
dest->mac_len = 6;
|
||||
(void) encode_unsigned32(&dest->mac[0],
|
||||
htonl(BIP_Broadcast_Address.s_addr));
|
||||
(void) encode_unsigned16(&dest->mac[4], htons(BIP_Port));
|
||||
dest->net = BACNET_BROADCAST_NETWORK;
|
||||
dest->len = 0; /* no SLEN */
|
||||
for (i = 0; i < MAX_MAC_LEN; i++) {
|
||||
/* no SADR */
|
||||
dest->adr[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -1,99 +0,0 @@
|
||||
/*####COPYRIGHTBEGIN####
|
||||
-------------------------------------------
|
||||
Copyright (C) 2005 Steve Karg
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to:
|
||||
The Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330
|
||||
Boston, MA 02111-1307, USA.
|
||||
|
||||
As a special exception, if other files instantiate templates or
|
||||
use macros or inline functions from this file, or you compile
|
||||
this file and link it with other works to produce a work based
|
||||
on this file, this file does not by itself cause the resulting
|
||||
work to be covered by the GNU General Public License. However
|
||||
the source code for this file must still be made available in
|
||||
accordance with section (3) of the GNU General Public License.
|
||||
|
||||
This exception does not invalidate any other reasons why a work
|
||||
based on this file might be covered by the GNU General Public
|
||||
License.
|
||||
-------------------------------------------
|
||||
####COPYRIGHTEND####*/
|
||||
#ifndef BIP_H
|
||||
#define BIP_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "bacdef.h"
|
||||
#include "npdu.h"
|
||||
#include "net.h"
|
||||
|
||||
/* specific defines for BACnet/IP over Ethernet */
|
||||
#define MAX_HEADER (1 + 1 + 2)
|
||||
#define MAX_MPDU (MAX_HEADER+MAX_PDU)
|
||||
|
||||
#define BVLL_TYPE_BACNET_IP (0x81)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/* note: define init and cleanup in your ports section */
|
||||
bool bip_init(void);
|
||||
|
||||
/* normal functions... */
|
||||
void bip_cleanup(void);
|
||||
void bip_set_socket(int sock_fd);
|
||||
int bip_socket(void);
|
||||
bool bip_valid(void);
|
||||
void bip_get_broadcast_address(BACNET_ADDRESS * dest); /* destination address */
|
||||
void bip_get_my_address(BACNET_ADDRESS * my_address);
|
||||
|
||||
/* function to send a packet out the BACnet/IP socket */
|
||||
/* returns zero on success, non-zero on failure */
|
||||
int bip_send_pdu(BACNET_ADDRESS * dest, /* destination address */
|
||||
BACNET_NPDU_DATA * npdu_data, /* network information */
|
||||
uint8_t * pdu, /* any data to be sent - may be null */
|
||||
unsigned pdu_len); /* number of bytes of data */
|
||||
|
||||
/* receives a BACnet/IP packet */
|
||||
/* returns the number of octets in the PDU, or zero on failure */
|
||||
uint16_t bip_receive(BACNET_ADDRESS * src, /* source address */
|
||||
uint8_t * pdu, /* PDU data */
|
||||
uint16_t max_pdu, /* amount of space available in the PDU */
|
||||
unsigned timeout); /* milliseconds to wait for a packet */
|
||||
|
||||
/* use host byte order for setting */
|
||||
void bip_set_port(uint16_t port);
|
||||
/* returns host byte order */
|
||||
uint16_t bip_get_port(void);
|
||||
|
||||
/* use network byte order for setting */
|
||||
void bip_set_addr(uint32_t net_address);
|
||||
/* returns host byte order */
|
||||
uint32_t bip_get_addr(void);
|
||||
|
||||
/* use network byte order for setting */
|
||||
void bip_set_broadcast_addr(uint32_t net_address);
|
||||
/* returns host byte order */
|
||||
uint32_t bip_get_broadcast_addr(void);
|
||||
|
||||
void bip_set_interface(char *ifname);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
@@ -1,73 +0,0 @@
|
||||
/*####COPYRIGHTBEGIN####
|
||||
-------------------------------------------
|
||||
Copyright (C) 2004 Steve Karg
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to
|
||||
The Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330
|
||||
Boston, MA 02111-1307, USA.
|
||||
|
||||
As a special exception, if other files instantiate templates or
|
||||
use macros or inline functions from this file, or you compile
|
||||
this file and link it with other works to produce a work based
|
||||
on this file, this file does not by itself cause the resulting
|
||||
work to be covered by the GNU General Public License. However
|
||||
the source code for this file must still be made available in
|
||||
accordance with section (3) of the GNU General Public License.
|
||||
|
||||
This exception does not invalidate any other reasons why a work
|
||||
based on this file might be covered by the GNU General Public
|
||||
License.
|
||||
-------------------------------------------
|
||||
####COPYRIGHTEND####*/
|
||||
#ifndef BITS_H
|
||||
#define BITS_H
|
||||
|
||||
/********************************************************************
|
||||
* Bit Masks
|
||||
*********************************************************************/
|
||||
#define BIT0 (0x01)
|
||||
#define BIT1 (0x02)
|
||||
#define BIT2 (0x04)
|
||||
#define BIT3 (0x08)
|
||||
#define BIT4 (0x10)
|
||||
#define BIT5 (0x20)
|
||||
#define BIT6 (0x40)
|
||||
#define BIT7 (0x80)
|
||||
#define BIT8 (0x0100)
|
||||
#define BIT9 (0x0200)
|
||||
#define BIT10 (0x0400)
|
||||
#define BIT11 (0x0800)
|
||||
#define BIT12 (0x1000)
|
||||
#define BIT13 (0x2000)
|
||||
#define BIT14 (0x4000)
|
||||
#define BIT15 (0x8000)
|
||||
#define BIT16 (0x010000UL)
|
||||
#define BIT17 (0x020000UL)
|
||||
#define BIT18 (0x040000UL)
|
||||
#define BIT19 (0x080000UL)
|
||||
#define BIT20 (0x100000UL)
|
||||
#define BIT21 (0x200000UL)
|
||||
#define BIT22 (0x400000UL)
|
||||
#define BIT23 (0x800000UL)
|
||||
#define BIT24 (0x01000000UL)
|
||||
#define BIT25 (0x02000000UL)
|
||||
#define BIT26 (0x04000000UL)
|
||||
#define BIT27 (0x08000000UL)
|
||||
#define BIT28 (0x10000000UL)
|
||||
#define BIT29 (0x20000000UL)
|
||||
#define BIT30 (0x40000000UL)
|
||||
#define BIT31 (0x80000000UL)
|
||||
|
||||
#endif
|
||||
@@ -1,624 +0,0 @@
|
||||
/*####COPYRIGHTBEGIN####
|
||||
-------------------------------------------
|
||||
Copyright (C) 2006 Steve Karg
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to:
|
||||
The Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330
|
||||
Boston, MA 02111-1307, USA.
|
||||
|
||||
As a special exception, if other files instantiate templates or
|
||||
use macros or inline functions from this file, or you compile
|
||||
this file and link it with other works to produce a work based
|
||||
on this file, this file does not by itself cause the resulting
|
||||
work to be covered by the GNU General Public License. However
|
||||
the source code for this file must still be made available in
|
||||
accordance with section (3) of the GNU General Public License.
|
||||
|
||||
This exception does not invalidate any other reasons why a work
|
||||
based on this file might be covered by the GNU General Public
|
||||
License.
|
||||
-------------------------------------------
|
||||
####COPYRIGHTEND####*/
|
||||
|
||||
#include <stdint.h> /* for standard integer types uint8_t etc. */
|
||||
#include <stdbool.h> /* for the standard bool type. */
|
||||
#include <time.h> /* for the standard bool type. */
|
||||
#include "bacdcode.h"
|
||||
#include "bip.h"
|
||||
#include "net.h" /* custom per port */
|
||||
|
||||
/* Handle the BACnet Virtual Link Control (BVLC), which includes:
|
||||
BACnet Broadcast Management Device,
|
||||
Broadcast Distribution Table, and
|
||||
Foreign Device Registration */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
|
||||
/* true if valid entry - false if not */
|
||||
bool valid;
|
||||
|
||||
/* BACnet/IP address */
|
||||
struct in_addr dest_address;
|
||||
|
||||
uint16_t dest_port;
|
||||
|
||||
/* Broadcast Distribution Mask - stored in host byte order */
|
||||
struct in_addr broadcast_mask;
|
||||
|
||||
} BBMD_TABLE_ENTRY;
|
||||
|
||||
#define MAX_BBMD_ENTRIES 128
|
||||
static BBMD_TABLE_ENTRY BBMD_Table[MAX_BBMD_ENTRIES];
|
||||
|
||||
/*Each device that registers as a foreign device shall be placed
|
||||
in an entry in the BBMD's Foreign Device Table (FDT). Each
|
||||
entry shall consist of the 6-octet B/IP address of the registrant;
|
||||
the 2-octet Time-to-Live value supplied at the time of
|
||||
registration; and a 2-octet value representing the number of
|
||||
seconds remaining before the BBMD will purge the registrant's FDT
|
||||
entry if no re-registration occurs. This value will be initialized
|
||||
to the 2-octet Time-to-Live value supplied at the time of
|
||||
registration.*/
|
||||
typedef struct
|
||||
{
|
||||
|
||||
bool valid;
|
||||
|
||||
/* BACnet/IP address */
|
||||
struct in_addr dest_address;
|
||||
|
||||
uint16_t dest_port;
|
||||
|
||||
/* seconds for valid entry lifetime */
|
||||
uint16_t time_to_live;
|
||||
|
||||
time_t seconds_remaining; /* includes 30 second grace period */
|
||||
|
||||
} FD_TABLE_ENTRY;
|
||||
|
||||
#define MAX_FD_ENTRIES 128
|
||||
static FD_TABLE_ENTRY FD_Table[MAX_FD_ENTRIES];
|
||||
|
||||
|
||||
void bvlc_maintenance_timer(unsigned seconds)
|
||||
{
|
||||
|
||||
unsigned i = 0;
|
||||
|
||||
|
||||
for (i = 0; i < MAX_FD_ENTRIES; i++) {
|
||||
|
||||
if (FD_Table[i].valid)
|
||||
|
||||
{
|
||||
|
||||
if (FD_Table[i].seconds_remaining)
|
||||
|
||||
{
|
||||
|
||||
if (FD_Table[i].seconds_remaining < seconds)
|
||||
|
||||
FD_Table[i].seconds_remaining = 0;
|
||||
|
||||
else
|
||||
|
||||
FD_Table[i].seconds_remaining -= seconds;
|
||||
|
||||
if (FD_Table[i].seconds_remaining == 0)
|
||||
|
||||
{
|
||||
|
||||
FD_Table[i].valid = false;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
int bvlc_encode_bip_address(
|
||||
uint8_t * pdu,
|
||||
struct in_addr *address, /* in host format */
|
||||
uint16_t port)
|
||||
{
|
||||
|
||||
int len = 0;
|
||||
|
||||
|
||||
if (pdu) {
|
||||
|
||||
len = encode_unsigned32(&pdu[0], address->s_addr);
|
||||
|
||||
len += encode_unsigned16(&pdu[len], port);
|
||||
|
||||
}
|
||||
|
||||
|
||||
return len;
|
||||
|
||||
}
|
||||
|
||||
|
||||
int bvlc_decode_bip_address(
|
||||
uint8_t * pdu,
|
||||
struct in_addr *address, /* in host format */
|
||||
uint16_t * port)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
/* used for both read and write entries */
|
||||
int bvlc_encode_address_entry(uint8_t * pdu,
|
||||
struct in_addr *address,
|
||||
uint16_t port,
|
||||
struct in_addr *mask)
|
||||
{
|
||||
|
||||
int len = 0;
|
||||
|
||||
|
||||
if (pdu) {
|
||||
|
||||
len = bvlc_encode_bip_address(pdu, address, port);
|
||||
|
||||
len += encode_unsigned32(&pdu[len], mask->s_addr);
|
||||
|
||||
}
|
||||
|
||||
|
||||
return len;
|
||||
|
||||
}
|
||||
|
||||
|
||||
int bvlc_encode_bvlc_result(uint8_t * pdu,
|
||||
|
||||
BACNET_BVLC_RESULT result_code)
|
||||
{
|
||||
|
||||
if (pdu) {
|
||||
|
||||
pdu[0] = BVLL_TYPE_BACNET_IP;
|
||||
|
||||
pdu[1] = BVLC_RESULT;
|
||||
|
||||
/* The 2-octet BVLC Length field is the length, in octets,
|
||||
of the entire BVLL message, including the two octets of the
|
||||
length field itself, most significant octet first. */
|
||||
encode_unsigned16(&pdu[2], 6);
|
||||
|
||||
encode_unsigned16(&pdu[4], result_code);
|
||||
|
||||
}
|
||||
|
||||
|
||||
return 6;
|
||||
|
||||
}
|
||||
|
||||
|
||||
int bvlc_encode_write_bdt_init(
|
||||
uint8_t * pdu,
|
||||
unsigned entries)
|
||||
{
|
||||
|
||||
int len = 0;
|
||||
|
||||
|
||||
if (pdu) {
|
||||
|
||||
pdu[0] = BVLL_TYPE_BACNET_IP;
|
||||
|
||||
pdu[1] = BVLC_WRITE_BROADCAST_DISTRIBUTION_TABLE;
|
||||
|
||||
/* The 2-octet BVLC Length field is the length, in octets,
|
||||
of the entire BVLL message, including the two octets of the
|
||||
length field itself, most significant octet first. */
|
||||
encode_unsigned16(&pdu[2], 4 + entries * 10);
|
||||
|
||||
len = 4;
|
||||
|
||||
}
|
||||
|
||||
|
||||
return len;
|
||||
|
||||
}
|
||||
|
||||
|
||||
int bvlc_encode_read_bdt(
|
||||
uint8_t * pdu)
|
||||
{
|
||||
|
||||
int len = 0;
|
||||
|
||||
|
||||
if (pdu) {
|
||||
|
||||
pdu[0] = BVLL_TYPE_BACNET_IP;
|
||||
|
||||
pdu[1] = BVLC_READ_BROADCAST_DISTRIBUTION_TABLE;
|
||||
|
||||
/* The 2-octet BVLC Length field is the length, in octets,
|
||||
of the entire BVLL message, including the two octets of the
|
||||
length field itself, most significant octet first. */
|
||||
encode_unsigned16(&pdu[2], 4);
|
||||
|
||||
len = 4;
|
||||
|
||||
}
|
||||
|
||||
|
||||
return len;
|
||||
|
||||
}
|
||||
|
||||
|
||||
int bvlc_encode_read_bdt_ack_init(
|
||||
uint8_t * pdu,
|
||||
unsigned entries)
|
||||
{
|
||||
|
||||
int len = 0;
|
||||
|
||||
|
||||
if (pdu) {
|
||||
|
||||
pdu[0] = BVLL_TYPE_BACNET_IP;
|
||||
|
||||
pdu[1] = BVLC_READ_BROADCAST_DISTRIBUTION_TABLE_ACK;
|
||||
|
||||
/* The 2-octet BVLC Length field is the length, in octets,
|
||||
of the entire BVLL message, including the two octets of the
|
||||
length field itself, most significant octet first. */
|
||||
encode_unsigned16(&pdu[2], 4 + entries * 10);
|
||||
|
||||
len = 4;
|
||||
|
||||
}
|
||||
|
||||
|
||||
return len;
|
||||
|
||||
}
|
||||
|
||||
|
||||
int bvlc_encode_forwarded_npdu(uint8_t * pdu,
|
||||
BACNET_ADDRESS * src,
|
||||
uint8_t * npdu,
|
||||
unsigned npdu_length)
|
||||
{
|
||||
|
||||
int len = 0;
|
||||
|
||||
unsigned i; /* for loop counter */
|
||||
|
||||
|
||||
if (pdu) {
|
||||
|
||||
pdu[0] = BVLL_TYPE_BACNET_IP;
|
||||
|
||||
pdu[1] = BVLC_FORWARDED_NPDU;
|
||||
|
||||
/* The 2-octet BVLC Length field is the length, in octets,
|
||||
of the entire BVLL message, including the two octets of the
|
||||
length field itself, most significant octet first. */
|
||||
encode_unsigned16(&pdu[2], 4 + 6 + npdu_length);
|
||||
|
||||
len = 4;
|
||||
|
||||
for (i = 0; i < 6; i++) {
|
||||
|
||||
pdu[len] = src->adr[i];
|
||||
|
||||
len++;
|
||||
|
||||
}
|
||||
|
||||
for (i = 0; i < npdu_length; i++) {
|
||||
|
||||
pdu[len] = npdu[i];
|
||||
|
||||
len++;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
return len;
|
||||
|
||||
}
|
||||
|
||||
|
||||
int bvlc_encode_register_foreign_device(uint8_t * pdu,
|
||||
|
||||
uint16_t time_to_live_seconds)
|
||||
{
|
||||
|
||||
int len = 0;
|
||||
|
||||
|
||||
if (pdu) {
|
||||
|
||||
pdu[0] = BVLL_TYPE_BACNET_IP;
|
||||
|
||||
pdu[1] = BVLC_REGISTER_FOREIGN_DEVICE;
|
||||
|
||||
/* The 2-octet BVLC Length field is the length, in octets,
|
||||
of the entire BVLL message, including the two octets of the
|
||||
length field itself, most significant octet first. */
|
||||
encode_unsigned16(&pdu[2], 6);
|
||||
|
||||
encode_unsigned16(&pdu[2], time_to_live_seconds);
|
||||
|
||||
len = 6;
|
||||
|
||||
}
|
||||
|
||||
|
||||
return len;
|
||||
|
||||
}
|
||||
|
||||
|
||||
int bvlc_encode_read_fdt(
|
||||
uint8_t * pdu)
|
||||
{
|
||||
|
||||
int len = 0;
|
||||
|
||||
|
||||
if (pdu) {
|
||||
|
||||
pdu[0] = BVLL_TYPE_BACNET_IP;
|
||||
|
||||
pdu[1] = BVLC_READ_FOREIGN_DEVICE_TABLE;
|
||||
|
||||
/* The 2-octet BVLC Length field is the length, in octets,
|
||||
of the entire BVLL message, including the two octets of the
|
||||
length field itself, most significant octet first. */
|
||||
encode_unsigned16(&pdu[2], 4);
|
||||
|
||||
len = 4;
|
||||
|
||||
}
|
||||
|
||||
|
||||
return len;
|
||||
|
||||
}
|
||||
|
||||
|
||||
int bvlc_encode_read_fdt_ack_init(
|
||||
uint8_t * pdu,
|
||||
unsigned entries)
|
||||
{
|
||||
|
||||
int len = 0;
|
||||
|
||||
|
||||
if (pdu) {
|
||||
|
||||
pdu[0] = BVLL_TYPE_BACNET_IP;
|
||||
|
||||
pdu[1] = BVLC_READ_FOREIGN_DEVICE_TABLE_ACK;
|
||||
|
||||
/* The 2-octet BVLC Length field is the length, in octets,
|
||||
of the entire BVLL message, including the two octets of the
|
||||
length field itself, most significant octet first. */
|
||||
encode_unsigned16(&pdu[2], 4 + entries * 10);
|
||||
|
||||
len = 4;
|
||||
|
||||
}
|
||||
|
||||
|
||||
return len;
|
||||
|
||||
}
|
||||
|
||||
|
||||
int bvlc_encode_delete_fdt_entry(uint8_t * pdu,
|
||||
struct in_addr *address,
|
||||
|
||||
uint16_t port)
|
||||
{
|
||||
|
||||
int len = 0;
|
||||
|
||||
|
||||
if (pdu) {
|
||||
|
||||
pdu[0] = BVLL_TYPE_BACNET_IP;
|
||||
|
||||
pdu[1] = BVLC_READ_FOREIGN_DEVICE_TABLE;
|
||||
|
||||
/* The 2-octet BVLC Length field is the length, in octets,
|
||||
of the entire BVLL message, including the two octets of the
|
||||
length field itself, most significant octet first. */
|
||||
encode_unsigned16(&pdu[2], 10);
|
||||
|
||||
/* FDT Entry */
|
||||
encode_unsigned32(&pdu[0], address->s_addr);
|
||||
|
||||
encode_unsigned16(&pdu[4], port);
|
||||
|
||||
len = 10;
|
||||
|
||||
}
|
||||
|
||||
|
||||
return len;
|
||||
|
||||
}
|
||||
|
||||
|
||||
int bvlc_encode_distribute_broadcast_to_network(uint8_t * pdu,
|
||||
|
||||
uint8_t * npdu,
|
||||
unsigned npdu_length)
|
||||
{
|
||||
|
||||
int len = 0; /* return value */
|
||||
|
||||
unsigned i; /* for loop counter */
|
||||
|
||||
|
||||
if (pdu) {
|
||||
|
||||
pdu[0] = BVLL_TYPE_BACNET_IP;
|
||||
|
||||
pdu[1] = BVLC_DISTRIBUTE_BROADCAST_TO_NETWORK;
|
||||
|
||||
/* The 2-octet BVLC Length field is the length, in octets,
|
||||
of the entire BVLL message, including the two octets of the
|
||||
length field itself, most significant octet first. */
|
||||
len = encode_unsigned16(&pdu[2], 4 + npdu_length) + 2;
|
||||
|
||||
for (i = 0; i < npdu_length; i++) {
|
||||
|
||||
pdu[len] = npdu[i];
|
||||
|
||||
len++;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
return len;
|
||||
|
||||
}
|
||||
|
||||
|
||||
int bvlc_encode_original_unicast_npdu(uint8_t * pdu,
|
||||
uint8_t * npdu,
|
||||
|
||||
unsigned npdu_length)
|
||||
{
|
||||
|
||||
int len = 0; /* return value */
|
||||
|
||||
unsigned i = 0; /* loop counter */
|
||||
|
||||
|
||||
if (pdu) {
|
||||
|
||||
pdu[0] = BVLL_TYPE_BACNET_IP;
|
||||
|
||||
pdu[1] = BVLC_ORIGINAL_UNICAST_NPDU;
|
||||
|
||||
/* The 2-octet BVLC Length field is the length, in octets,
|
||||
of the entire BVLL message, including the two octets of the
|
||||
length field itself, most significant octet first. */
|
||||
len = encode_unsigned16(&pdu[2], 4 + npdu_length) + 2;
|
||||
|
||||
for (i = 0; i < npdu_length; i++) {
|
||||
|
||||
pdu[len] = npdu[i];
|
||||
|
||||
len++;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
return len;
|
||||
|
||||
}
|
||||
|
||||
|
||||
int bvlc_encode_original_broadcast_npdu(uint8_t * pdu,
|
||||
uint8_t * npdu,
|
||||
|
||||
unsigned npdu_length)
|
||||
{
|
||||
|
||||
int len = 0; /* return value */
|
||||
|
||||
unsigned i = 0; /* loop counter */
|
||||
|
||||
|
||||
if (pdu) {
|
||||
|
||||
pdu[0] = BVLL_TYPE_BACNET_IP;
|
||||
|
||||
pdu[1] = BVLC_ORIGINAL_BROADCAST_NPDU;
|
||||
|
||||
/* The 2-octet BVLC Length field is the length, in octets,
|
||||
of the entire BVLL message, including the two octets of the
|
||||
length field itself, most significant octet first. */
|
||||
len = encode_unsigned16(&pdu[2], 4 + npdu_length) + 2;
|
||||
|
||||
for (i = 0; i < npdu_length; i++) {
|
||||
|
||||
pdu[len] = npdu[i];
|
||||
|
||||
len++;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
return len;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* copy the source internet address to the BACnet address */
|
||||
/* FIXME: IPv6? */
|
||||
/* FIXME: is sockaddr_in host or network order? */
|
||||
void bvlc_internet_to_bacnet_address(
|
||||
BACNET_ADDRESS * src, /* returns the BACnet source address */
|
||||
struct sockaddr_in *sin)
|
||||
{ /* source internet address */
|
||||
|
||||
int len = 0;
|
||||
|
||||
|
||||
if (src && sin)
|
||||
|
||||
{
|
||||
|
||||
len = encode_unsigned32(&src->mac[0], sin->sin_addr.s_addr);
|
||||
|
||||
len += encode_unsigned16(&src->mac[4], sin->sin_port);
|
||||
|
||||
src->mac_len = len;
|
||||
|
||||
src->net = 0;
|
||||
|
||||
src->len = 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* copy the source internet address to the BACnet address */
|
||||
/* FIXME: IPv6? */
|
||||
@@ -1,98 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE CodeBlocks_project_file>
|
||||
<CodeBlocks_project_file>
|
||||
<FileVersion major="1" minor="1"/>
|
||||
<Project>
|
||||
<Option title="BVLC Unit Test"/>
|
||||
<Option makefile="Makefile"/>
|
||||
<Option makefile_is_custom="0"/>
|
||||
<Option compiler="2"/>
|
||||
<Build>
|
||||
<Target title="default">
|
||||
<Option output="C:\code\bacnet-stack\bbmd.exe"/>
|
||||
<Option working_dir="."/>
|
||||
<Option object_output=".objs"/>
|
||||
<Option deps_output=".deps"/>
|
||||
<Option type="1"/>
|
||||
<Option compiler="2"/>
|
||||
<Option projectResourceIncludeDirsRelation="1"/>
|
||||
</Target>
|
||||
</Build>
|
||||
<Compiler>
|
||||
<Add option="-w-aus"/>
|
||||
<Add option="-w-sig"/>
|
||||
<Add option="-DTEST;TEST_BBMD;BACDL_BIP=1;TSM_ENABLED=1"/>
|
||||
<Add directory="."/>
|
||||
<Add directory="demo\handler"/>
|
||||
<Add directory="demo\object"/>
|
||||
<Add directory="ports\win32"/>
|
||||
<Add directory="test"/>
|
||||
</Compiler>
|
||||
<Linker>
|
||||
<Add library="..\..\BCC55\Lib\import32.lib"/>
|
||||
<Add library="..\..\BCC55\Lib\cw32mt.lib"/>
|
||||
</Linker>
|
||||
<Unit filename="bacdcode.c">
|
||||
<Option compilerVar="CC"/>
|
||||
<Option target="default"/>
|
||||
</Unit>
|
||||
<Unit filename="bacdcode.h">
|
||||
<Option compilerVar=""/>
|
||||
<Option compile="0"/>
|
||||
<Option link="0"/>
|
||||
<Option target="default"/>
|
||||
</Unit>
|
||||
<Unit filename="bacdef.h">
|
||||
<Option compilerVar=""/>
|
||||
<Option compile="0"/>
|
||||
<Option link="0"/>
|
||||
<Option target="default"/>
|
||||
</Unit>
|
||||
<Unit filename="bacenum.h">
|
||||
<Option compilerVar=""/>
|
||||
<Option compile="0"/>
|
||||
<Option link="0"/>
|
||||
<Option target="default"/>
|
||||
</Unit>
|
||||
<Unit filename="bacstr.c">
|
||||
<Option compilerVar="CC"/>
|
||||
<Option target="default"/>
|
||||
</Unit>
|
||||
<Unit filename="bacstr.h">
|
||||
<Option compilerVar=""/>
|
||||
<Option compile="0"/>
|
||||
<Option link="0"/>
|
||||
<Option target="default"/>
|
||||
</Unit>
|
||||
<Unit filename="bigend.c">
|
||||
<Option compilerVar="CC"/>
|
||||
<Option target="default"/>
|
||||
</Unit>
|
||||
<Unit filename="bigend.h">
|
||||
<Option compilerVar=""/>
|
||||
<Option compile="0"/>
|
||||
<Option link="0"/>
|
||||
<Option target="default"/>
|
||||
</Unit>
|
||||
<Unit filename="bvlc.c">
|
||||
<Option compilerVar="CC"/>
|
||||
<Option target="default"/>
|
||||
</Unit>
|
||||
<Unit filename="bvlc.h">
|
||||
<Option compilerVar=""/>
|
||||
<Option compile="0"/>
|
||||
<Option link="0"/>
|
||||
<Option target="default"/>
|
||||
</Unit>
|
||||
<Unit filename="test\ctest.c">
|
||||
<Option compilerVar="CC"/>
|
||||
<Option target="default"/>
|
||||
</Unit>
|
||||
<Unit filename="test\ctest.h">
|
||||
<Option compilerVar=""/>
|
||||
<Option compile="0"/>
|
||||
<Option link="0"/>
|
||||
<Option target="default"/>
|
||||
</Unit>
|
||||
</Project>
|
||||
</CodeBlocks_project_file>
|
||||
@@ -1,52 +0,0 @@
|
||||
/*####COPYRIGHTBEGIN####
|
||||
-------------------------------------------
|
||||
Copyright (C) 2006 Steve Karg
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to:
|
||||
The Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330
|
||||
Boston, MA 02111-1307, USA.
|
||||
|
||||
As a special exception, if other files instantiate templates or
|
||||
use macros or inline functions from this file, or you compile
|
||||
this file and link it with other works to produce a work based
|
||||
on this file, this file does not by itself cause the resulting
|
||||
work to be covered by the GNU General Public License. However
|
||||
the source code for this file must still be made available in
|
||||
accordance with section (3) of the GNU General Public License.
|
||||
|
||||
This exception does not invalidate any other reasons why a work
|
||||
based on this file might be covered by the GNU General Public
|
||||
License.
|
||||
-------------------------------------------
|
||||
####COPYRIGHTEND####*/
|
||||
#ifndef BVLC_H
|
||||
#define BVLC_H
|
||||
|
||||
#include <stdint.h> /* for standard integer types uint8_t etc. */
|
||||
#include <stdbool.h> /* for the standard bool type. */
|
||||
#include "bip.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/* called from BACnet/IP handler */
|
||||
void bvlc_handler(uint8_t * buf, int len, struct sockaddr_in *sin);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif /*
|
||||
@@ -1,70 +0,0 @@
|
||||
/* Defines the bit/byte/word/long conversions that are used in code */
|
||||
|
||||
|
||||
#ifndef BYTES_H
|
||||
#define BYTES_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifndef LO_NIB
|
||||
#define LO_NIB(b) ((b) & 0xF)
|
||||
#endif
|
||||
|
||||
#ifndef HI_NIB
|
||||
#define HI_NIB(b) ((b) >> 4)
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#ifndef LO_BYTE
|
||||
|
||||
#define LO_BYTE(w) ((uint8_t)(w))
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#ifndef HI_BYTE
|
||||
|
||||
#define HI_BYTE(w) ((uint8_t)((uint16_t)(w) >> 8))
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#ifndef LO_WORD
|
||||
|
||||
#define LO_WORD(x) ((uint16_t)(x))
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#ifndef HI_WORD
|
||||
|
||||
#define HI_WORD(x) ((uint16_t)((uint32_t)(x) >> 16))
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#ifndef MAKE_WORD
|
||||
|
||||
#define MAKE_WORD(lo,hi) \
|
||||
((uint16_t)(((uint8_t)(lo))|(((uint16_t)((uint8_t)(hi)))<<8)))
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#ifndef MAKE_LONG
|
||||
|
||||
#define MAKE_LONG(lo,hi) \
|
||||
((uint32_t)(((uint16_t)(lo))|(((uint32_t)((uint16_t)(hi)))<<16)))
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#endif /* end of header file */
|
||||
@@ -1,16 +0,0 @@
|
||||
#!/bin/sh
|
||||
directory=${1-`pwd`}
|
||||
for filename in $( find $directory -name '*.c' )
|
||||
do
|
||||
echo Converting $filename
|
||||
ccmtcnvt $filename > /tmp/ccmtcnvt.karg
|
||||
mv /tmp/ccmtcnvt.karg $filename
|
||||
done
|
||||
|
||||
for filename in $( find $directory -name '*.h' )
|
||||
do
|
||||
echo Converting $filename
|
||||
ccmtcnvt $filename > /tmp/ccmtcnvt.karg
|
||||
mv /tmp/ccmtcnvt.karg $filename
|
||||
done
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
#ifndef CONFIG_H
|
||||
#define CONFIG_H
|
||||
|
||||
/* declare a single physical layer */
|
||||
/*#include "bip.h" */
|
||||
/*#include "ethernet.h" */
|
||||
/*#include "arcnet.h" */
|
||||
/*#include "mstp.h" */
|
||||
|
||||
/* Max number of bytes in an APDU. */
|
||||
/* Typical sizes are 50, 128, 206, 480, 1024, and 1476 octets */
|
||||
/* This is used in constructing messages and to tell others our limits */
|
||||
/* 50 is the minimum; adjust to your memory and physical layer constraints */
|
||||
/* Lon=206, MS/TP=480, ARCNET=480, Ethernet=1476 */
|
||||
#define MAX_APDU 50
|
||||
/* #define MAX_APDU 480 */
|
||||
/* #define MAX_APDU 1476 */
|
||||
|
||||
/* for confirmed messages, this is the number of transactions */
|
||||
/* that we hold in a queue waiting for timeout. */
|
||||
/* Configure to zero if you don't want any confirmed messages */
|
||||
/* Configure from 1..255 for number of outstanding confirmed */
|
||||
/* requests available. */
|
||||
#define MAX_TSM_TRANSACTIONS 255
|
||||
|
||||
/* The address cache is used for binding to BACnet devices */
|
||||
/* The number of entries corresponds to the number of */
|
||||
/* devices that might respond to an I-Am on the network. */
|
||||
/* If your device is a simple server and does not need to bind, */
|
||||
/* then you don't need to use this. */
|
||||
#define MAX_ADDRESS_CACHE 255
|
||||
|
||||
#endif
|
||||
@@ -1,970 +0,0 @@
|
||||
/*####COPYRIGHTBEGIN####
|
||||
-------------------------------------------
|
||||
Copyright (C) 2006 Steve Karg
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to:
|
||||
The Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330
|
||||
Boston, MA 02111-1307, USA.
|
||||
|
||||
As a special exception, if other files instantiate templates or
|
||||
use macros or inline functions from this file, or you compile
|
||||
this file and link it with other works to produce a work based
|
||||
on this file, this file does not by itself cause the resulting
|
||||
work to be covered by the GNU General Public License. However
|
||||
the source code for this file must still be made available in
|
||||
accordance with section (3) of the GNU General Public License.
|
||||
|
||||
This exception does not invalidate any other reasons why a work
|
||||
based on this file might be covered by the GNU General Public
|
||||
License.
|
||||
-------------------------------------------
|
||||
####COPYRIGHTEND####*/
|
||||
#include <stdint.h>
|
||||
#include "bacenum.h"
|
||||
#include "bacdcode.h"
|
||||
#include "bacdef.h"
|
||||
#include "bacapp.h"
|
||||
#include "cov.h"
|
||||
#include "device.h"
|
||||
#include "datalink.h"
|
||||
#include "npdu.h"
|
||||
|
||||
/* encode service */
|
||||
|
||||
/* Change-Of-Value Services
|
||||
COV Subscribe
|
||||
COV Subscribe Property
|
||||
COV Notification
|
||||
Unconfirmed COV Notification
|
||||
*/
|
||||
static int notify_encode_adpu(uint8_t * apdu, BACNET_COV_DATA * data)
|
||||
{
|
||||
int len = 0; /* length of each encoding */
|
||||
int apdu_len = 0; /* total length of the apdu, return value */
|
||||
BACNET_PROPERTY_VALUE *value = NULL; /* value in list */
|
||||
|
||||
if (apdu) {
|
||||
/* tag 0 - subscriberProcessIdentifier */
|
||||
len = encode_context_unsigned(&apdu[apdu_len],
|
||||
0, data->subscriberProcessIdentifier);
|
||||
apdu_len += len;
|
||||
/* tag 1 - initiatingDeviceIdentifier */
|
||||
len = encode_context_object_id(&apdu[apdu_len],
|
||||
1, OBJECT_DEVICE, data->initiatingDeviceIdentifier);
|
||||
apdu_len += len;
|
||||
/* tag 2 - monitoredObjectIdentifier */
|
||||
len = encode_context_object_id(&apdu[apdu_len],
|
||||
2,
|
||||
data->monitoredObjectIdentifier.type,
|
||||
data->monitoredObjectIdentifier.instance);
|
||||
apdu_len += len;
|
||||
/* tag 3 - timeRemaining */
|
||||
len = encode_context_unsigned(&apdu[apdu_len],
|
||||
3, data->timeRemaining);
|
||||
apdu_len += len;
|
||||
/* tag 4 - listOfValues */
|
||||
len = encode_opening_tag(&apdu[apdu_len], 4);
|
||||
apdu_len += len;
|
||||
/* the first value includes a pointer to the next value, etc */
|
||||
/* FIXME: for small implementations, we might try a partial
|
||||
approach like the rpm.c where the values are encoded with
|
||||
a separate function */
|
||||
value = &data->listOfValues;
|
||||
while (value != NULL) {
|
||||
/* tag 0 - propertyIdentifier */
|
||||
len = encode_context_enumerated(&apdu[apdu_len],
|
||||
0, value->propertyIdentifier);
|
||||
apdu_len += len;
|
||||
/* tag 1 - propertyArrayIndex OPTIONAL */
|
||||
if (value->propertyArrayIndex != BACNET_ARRAY_ALL) {
|
||||
len = encode_context_unsigned(&apdu[apdu_len],
|
||||
1, value->propertyArrayIndex);
|
||||
apdu_len += len;
|
||||
}
|
||||
/* tag 2 - value */
|
||||
/* abstract syntax gets enclosed in a context tag */
|
||||
len = encode_opening_tag(&apdu[apdu_len], 2);
|
||||
apdu_len += len;
|
||||
len = bacapp_encode_application_data(&apdu[apdu_len],
|
||||
&value->value);
|
||||
apdu_len += len;
|
||||
len = encode_closing_tag(&apdu[apdu_len], 2);
|
||||
apdu_len += len;
|
||||
/* tag 3 - priority OPTIONAL */
|
||||
if (value->priority != BACNET_NO_PRIORITY) {
|
||||
len = encode_context_unsigned(&apdu[apdu_len], 3,
|
||||
value->priority);
|
||||
apdu_len += len;
|
||||
}
|
||||
/* is there another one to encode? */
|
||||
/* FIXME: check to see if there is room in the APDU */
|
||||
value = value->next;
|
||||
}
|
||||
len = encode_closing_tag(&apdu[apdu_len], 4);
|
||||
apdu_len += len;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
int ccov_notify_encode_apdu(uint8_t * apdu,
|
||||
uint8_t invoke_id, BACNET_COV_DATA * data)
|
||||
{
|
||||
int len = 0; /* length of each encoding */
|
||||
int apdu_len = 0; /* total length of the apdu, return value */
|
||||
uint16_t max_apdu = Device_Max_APDU_Length_Accepted();
|
||||
|
||||
if (apdu) {
|
||||
apdu[0] = PDU_TYPE_CONFIRMED_SERVICE_REQUEST;
|
||||
apdu[1] = encode_max_segs_max_apdu(0, max_apdu);
|
||||
apdu[2] = invoke_id;
|
||||
apdu[3] = SERVICE_CONFIRMED_COV_NOTIFICATION;
|
||||
apdu_len = 4;
|
||||
len = notify_encode_adpu(&apdu[apdu_len], data);
|
||||
apdu_len += len;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
int ucov_notify_encode_apdu(uint8_t * apdu, BACNET_COV_DATA * data)
|
||||
{
|
||||
int len = 0; /* length of each encoding */
|
||||
int apdu_len = 0; /* total length of the apdu, return value */
|
||||
|
||||
if (apdu && data) {
|
||||
apdu[0] = PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST;
|
||||
apdu[1] = SERVICE_UNCONFIRMED_COV_NOTIFICATION; /* service choice */
|
||||
apdu_len = 2;
|
||||
len = notify_encode_adpu(&apdu[apdu_len], data);
|
||||
apdu_len += len;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
/* decode the service request only */
|
||||
/* COV and Unconfirmed COV are the same */
|
||||
int cov_notify_decode_service_request(uint8_t * apdu,
|
||||
unsigned apdu_len, BACNET_COV_DATA * data)
|
||||
{
|
||||
int len = 0; /* return value */
|
||||
uint8_t tag_number = 0;
|
||||
uint32_t len_value = 0;
|
||||
uint32_t decoded_value = 0; /* for decoding */
|
||||
int decoded_type = 0; /* for decoding */
|
||||
int property = 0; /* for decoding */
|
||||
BACNET_PROPERTY_VALUE *value = NULL; /* value in list */
|
||||
|
||||
if (apdu_len && data) {
|
||||
/* tag 0 - subscriberProcessIdentifier */
|
||||
if (decode_is_context_tag(&apdu[len], 0)) {
|
||||
len +=
|
||||
decode_tag_number_and_value(&apdu[len], &tag_number,
|
||||
&len_value);
|
||||
len += decode_unsigned(&apdu[len], len_value, &decoded_value);
|
||||
data->subscriberProcessIdentifier = decoded_value;
|
||||
} else
|
||||
return -1;
|
||||
/* tag 1 - initiatingDeviceIdentifier */
|
||||
if (decode_is_context_tag(&apdu[len], 1)) {
|
||||
len +=
|
||||
decode_tag_number_and_value(&apdu[len], &tag_number,
|
||||
&len_value);
|
||||
len +=
|
||||
decode_object_id(&apdu[len], &decoded_type,
|
||||
&data->initiatingDeviceIdentifier);
|
||||
if (decoded_type != OBJECT_DEVICE)
|
||||
return -1;
|
||||
} else
|
||||
return -1;
|
||||
/* tag 2 - monitoredObjectIdentifier */
|
||||
if (decode_is_context_tag(&apdu[len], 2)) {
|
||||
len +=
|
||||
decode_tag_number_and_value(&apdu[len], &tag_number,
|
||||
&len_value);
|
||||
len +=
|
||||
decode_object_id(&apdu[len], &decoded_type,
|
||||
&data->monitoredObjectIdentifier.instance);
|
||||
data->monitoredObjectIdentifier.type = decoded_type;
|
||||
} else
|
||||
return -1;
|
||||
/* tag 3 - timeRemaining */
|
||||
if (decode_is_context_tag(&apdu[len], 3)) {
|
||||
len +=
|
||||
decode_tag_number_and_value(&apdu[len], &tag_number,
|
||||
&len_value);
|
||||
len += decode_unsigned(&apdu[len], len_value, &decoded_value);
|
||||
data->timeRemaining = decoded_value;
|
||||
} else
|
||||
return -1;
|
||||
/* tag 4: opening context tag - listOfValues */
|
||||
if (!decode_is_opening_tag_number(&apdu[len], 4))
|
||||
return -1;
|
||||
/* a tag number of 4 is not extended so only one octet */
|
||||
len++;
|
||||
/* the first value includes a pointer to the next value, etc */
|
||||
value = &data->listOfValues;
|
||||
while (value != NULL) {
|
||||
/* tag 0 - propertyIdentifier */
|
||||
if (decode_is_context_tag(&apdu[len], 0)) {
|
||||
len +=
|
||||
decode_tag_number_and_value(&apdu[len], &tag_number,
|
||||
&len_value);
|
||||
len += decode_enumerated(&apdu[len], len_value, &property);
|
||||
value->propertyIdentifier = property;
|
||||
} else
|
||||
return -1;
|
||||
/* tag 1 - propertyArrayIndex OPTIONAL */
|
||||
if (decode_is_context_tag(&apdu[len], 1)) {
|
||||
len +=
|
||||
decode_tag_number_and_value(&apdu[len], &tag_number,
|
||||
&len_value);
|
||||
len +=
|
||||
decode_unsigned(&apdu[len], len_value, &decoded_value);
|
||||
value->propertyArrayIndex = decoded_value;
|
||||
} else
|
||||
value->propertyArrayIndex = BACNET_ARRAY_ALL;
|
||||
/* tag 2: opening context tag - value */
|
||||
if (!decode_is_opening_tag_number(&apdu[len], 2))
|
||||
return -1;
|
||||
/* a tag number of 2 is not extended so only one octet */
|
||||
len++;
|
||||
len += bacapp_decode_application_data(&apdu[len],
|
||||
apdu_len - len, &value->value);
|
||||
/* FIXME: check the return value; abort if no valid data? */
|
||||
/* FIXME: there might be more than one data element in here! */
|
||||
if (!decode_is_closing_tag_number(&apdu[len], 2))
|
||||
return -1;
|
||||
/* a tag number of 2 is not extended so only one octet */
|
||||
len++;
|
||||
/* tag 3 - priority OPTIONAL */
|
||||
if (decode_is_context_tag(&apdu[len], 3)) {
|
||||
len +=
|
||||
decode_tag_number_and_value(&apdu[len], &tag_number,
|
||||
&len_value);
|
||||
len +=
|
||||
decode_unsigned(&apdu[len], len_value, &decoded_value);
|
||||
value->priority = decoded_value;
|
||||
} else
|
||||
value->priority = BACNET_NO_PRIORITY;
|
||||
/* end of list? */
|
||||
if (decode_is_closing_tag_number(&apdu[len], 4))
|
||||
break;
|
||||
/* is there another one to decode? */
|
||||
value = value->next;
|
||||
/* out of room to store more values */
|
||||
if (value == NULL)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/*
|
||||
12.11.38Active_COV_Subscriptions
|
||||
The Active_COV_Subscriptions property is a List of BACnetCOVSubscription, each of which consists of a Recipient, a
|
||||
Monitored Property Reference, an Issue Confirmed Notifications flag, a Time Remaining value and an optional COV
|
||||
Increment. This property provides a network-visible indication of those COV subscriptions that are active at any given time.
|
||||
Whenever a COV Subscription is created with the SubscribeCOV or SubscribeCOVProperty service, a new entry is added to
|
||||
the Active_COV_Subscriptions list. Similarly, whenever a COV Subscription is terminated, the corresponding entry shall be
|
||||
removed from the Active_COV_Subscriptions list.
|
||||
*/
|
||||
/*
|
||||
SubscribeCOV-Request ::= SEQUENCE {
|
||||
subscriberProcessIdentifier [0] Unsigned32,
|
||||
monitoredObjectIdentifier [1] BACnetObjectIdentifier,
|
||||
issueConfirmedNotifications [2] BOOLEAN OPTIONAL,
|
||||
lifetime [3] Unsigned OPTIONAL
|
||||
}
|
||||
*/
|
||||
|
||||
int cov_subscribe_encode_adpu(uint8_t * apdu,
|
||||
uint8_t invoke_id, BACNET_SUBSCRIBE_COV_DATA * data)
|
||||
{
|
||||
int len = 0; /* length of each encoding */
|
||||
int apdu_len = 0; /* total length of the apdu, return value */
|
||||
uint16_t max_apdu = Device_Max_APDU_Length_Accepted();
|
||||
|
||||
if (apdu && data) {
|
||||
apdu[0] = PDU_TYPE_CONFIRMED_SERVICE_REQUEST;
|
||||
apdu[1] = encode_max_segs_max_apdu(0, max_apdu);
|
||||
apdu[2] = invoke_id;
|
||||
apdu[3] = SERVICE_CONFIRMED_SUBSCRIBE_COV;
|
||||
apdu_len = 4;
|
||||
/* tag 0 - subscriberProcessIdentifier */
|
||||
len = encode_context_unsigned(&apdu[apdu_len],
|
||||
0, data->subscriberProcessIdentifier);
|
||||
apdu_len += len;
|
||||
/* tag 1 - monitoredObjectIdentifier */
|
||||
len = encode_context_object_id(&apdu[apdu_len],
|
||||
1,
|
||||
data->monitoredObjectIdentifier.type,
|
||||
data->monitoredObjectIdentifier.instance);
|
||||
apdu_len += len;
|
||||
/*
|
||||
If both the 'Issue Confirmed Notifications' and
|
||||
'Lifetime' parameters are absent, then this shall
|
||||
indicate a cancellation request.
|
||||
*/
|
||||
if (!data->cancellationRequest) {
|
||||
/* tag 2 - issueConfirmedNotifications */
|
||||
len = encode_context_boolean(&apdu[apdu_len],
|
||||
2, data->issueConfirmedNotifications);
|
||||
apdu_len += len;
|
||||
/* tag 3 - lifetime */
|
||||
len = encode_context_unsigned(&apdu[apdu_len],
|
||||
3, data->lifetime);
|
||||
apdu_len += len;
|
||||
}
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
/* decode the service request only */
|
||||
int cov_subscribe_decode_service_request(uint8_t * apdu,
|
||||
unsigned apdu_len, BACNET_SUBSCRIBE_COV_DATA * data)
|
||||
{
|
||||
int len = 0; /* return value */
|
||||
uint8_t tag_number = 0;
|
||||
uint32_t len_value = 0;
|
||||
uint32_t decoded_value = 0; /* for decoding */
|
||||
int decoded_type = 0; /* for decoding */
|
||||
|
||||
if (apdu_len && data) {
|
||||
/* tag 0 - subscriberProcessIdentifier */
|
||||
if (decode_is_context_tag(&apdu[len], 0)) {
|
||||
len +=
|
||||
decode_tag_number_and_value(&apdu[len], &tag_number,
|
||||
&len_value);
|
||||
len += decode_unsigned(&apdu[len], len_value, &decoded_value);
|
||||
data->subscriberProcessIdentifier = decoded_value;
|
||||
} else
|
||||
return -1;
|
||||
/* tag 1 - monitoredObjectIdentifier */
|
||||
if (decode_is_context_tag(&apdu[len], 1)) {
|
||||
len +=
|
||||
decode_tag_number_and_value(&apdu[len], &tag_number,
|
||||
&len_value);
|
||||
len +=
|
||||
decode_object_id(&apdu[len], &decoded_type,
|
||||
&data->monitoredObjectIdentifier.instance);
|
||||
data->monitoredObjectIdentifier.type = decoded_type;
|
||||
} else
|
||||
return -1;
|
||||
/* tag 2 - issueConfirmedNotifications - optional */
|
||||
if (decode_is_context_tag(&apdu[len], 2)) {
|
||||
data->cancellationRequest = false;
|
||||
len +=
|
||||
decode_tag_number_and_value(&apdu[len], &tag_number,
|
||||
&len_value);
|
||||
data->issueConfirmedNotifications =
|
||||
decode_context_boolean(&apdu[len]);
|
||||
len += len_value;
|
||||
} else
|
||||
data->cancellationRequest = true;
|
||||
/* tag 3 - lifetime - optional */
|
||||
if (decode_is_context_tag(&apdu[len], 3)) {
|
||||
len +=
|
||||
decode_tag_number_and_value(&apdu[len], &tag_number,
|
||||
&len_value);
|
||||
len += decode_unsigned(&apdu[len], len_value, &decoded_value);
|
||||
data->lifetime = decoded_value;
|
||||
} else
|
||||
data->lifetime = 0;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
SubscribeCOVProperty-Request ::= SEQUENCE {
|
||||
subscriberProcessIdentifier [0] Unsigned32,
|
||||
monitoredObjectIdentifier [1] BACnetObjectIdentifier,
|
||||
issueConfirmedNotifications [2] BOOLEAN OPTIONAL,
|
||||
lifetime [3] Unsigned OPTIONAL,
|
||||
monitoredPropertyIdentifier [4] BACnetPropertyReference,
|
||||
covIncrement [5] REAL OPTIONAL
|
||||
}
|
||||
|
||||
BACnetPropertyReference ::= SEQUENCE {
|
||||
propertyIdentifier [0] BACnetPropertyIdentifier,
|
||||
propertyArrayIndex [1] Unsigned OPTIONAL
|
||||
-- used only with array datatype
|
||||
-- if omitted with an array the entire array is referenced
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
int cov_subscribe_property_encode_adpu(uint8_t * apdu,
|
||||
uint8_t invoke_id, BACNET_SUBSCRIBE_COV_DATA * data)
|
||||
{
|
||||
int len = 0; /* length of each encoding */
|
||||
int apdu_len = 0; /* total length of the apdu, return value */
|
||||
uint16_t max_apdu = Device_Max_APDU_Length_Accepted();
|
||||
|
||||
if (apdu && data) {
|
||||
apdu[0] = PDU_TYPE_CONFIRMED_SERVICE_REQUEST;
|
||||
apdu[1] = encode_max_segs_max_apdu(0, max_apdu);
|
||||
apdu[2] = invoke_id;
|
||||
apdu[3] = SERVICE_CONFIRMED_SUBSCRIBE_COV_PROPERTY;
|
||||
apdu_len = 4;
|
||||
/* tag 0 - subscriberProcessIdentifier */
|
||||
len = encode_context_unsigned(&apdu[apdu_len],
|
||||
0, data->subscriberProcessIdentifier);
|
||||
apdu_len += len;
|
||||
/* tag 1 - monitoredObjectIdentifier */
|
||||
len = encode_context_object_id(&apdu[apdu_len],
|
||||
1,
|
||||
data->monitoredObjectIdentifier.type,
|
||||
data->monitoredObjectIdentifier.instance);
|
||||
apdu_len += len;
|
||||
if (!data->cancellationRequest) {
|
||||
/* tag 2 - issueConfirmedNotifications */
|
||||
len = encode_context_boolean(&apdu[apdu_len],
|
||||
2, data->issueConfirmedNotifications);
|
||||
apdu_len += len;
|
||||
/* tag 3 - lifetime */
|
||||
len = encode_context_unsigned(&apdu[apdu_len],
|
||||
3, data->lifetime);
|
||||
apdu_len += len;
|
||||
}
|
||||
/* tag 4 - monitoredPropertyIdentifier */
|
||||
len = encode_opening_tag(&apdu[apdu_len], 4);
|
||||
apdu_len += len;
|
||||
len = encode_context_enumerated(&apdu[apdu_len],
|
||||
0, data->monitoredProperty.propertyIdentifier);
|
||||
apdu_len += len;
|
||||
if (data->monitoredProperty.propertyArrayIndex != BACNET_ARRAY_ALL) {
|
||||
len = encode_context_unsigned(&apdu[apdu_len],
|
||||
1, data->monitoredProperty.propertyArrayIndex);
|
||||
apdu_len += len;
|
||||
|
||||
}
|
||||
len = encode_closing_tag(&apdu[apdu_len], 4);
|
||||
apdu_len += len;
|
||||
|
||||
/* tag 5 - covIncrement */
|
||||
if (data->covIncrementPresent) {
|
||||
len = encode_context_real(&apdu[apdu_len],
|
||||
5, data->covIncrement);
|
||||
apdu_len += len;
|
||||
}
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
/* decode the service request only */
|
||||
int cov_subscribe_property_decode_service_request(uint8_t * apdu,
|
||||
unsigned apdu_len, BACNET_SUBSCRIBE_COV_DATA * data)
|
||||
{
|
||||
int len = 0; /* return value */
|
||||
uint8_t tag_number = 0;
|
||||
uint32_t len_value = 0;
|
||||
uint32_t decoded_value = 0; /* for decoding */
|
||||
int decoded_type = 0; /* for decoding */
|
||||
int property = 0; /* for decoding */
|
||||
|
||||
if (apdu_len && data) {
|
||||
/* tag 0 - subscriberProcessIdentifier */
|
||||
if (decode_is_context_tag(&apdu[len], 0)) {
|
||||
len +=
|
||||
decode_tag_number_and_value(&apdu[len], &tag_number,
|
||||
&len_value);
|
||||
len += decode_unsigned(&apdu[len], len_value, &decoded_value);
|
||||
data->subscriberProcessIdentifier = decoded_value;
|
||||
} else
|
||||
return -1;
|
||||
/* tag 1 - monitoredObjectIdentifier */
|
||||
if (decode_is_context_tag(&apdu[len], 1)) {
|
||||
len +=
|
||||
decode_tag_number_and_value(&apdu[len], &tag_number,
|
||||
&len_value);
|
||||
len +=
|
||||
decode_object_id(&apdu[len], &decoded_type,
|
||||
&data->monitoredObjectIdentifier.instance);
|
||||
data->monitoredObjectIdentifier.type = decoded_type;
|
||||
} else
|
||||
return -2;
|
||||
/* tag 2 - issueConfirmedNotifications - optional */
|
||||
if (decode_is_context_tag(&apdu[len], 2)) {
|
||||
data->cancellationRequest = false;
|
||||
len +=
|
||||
decode_tag_number_and_value(&apdu[len], &tag_number,
|
||||
&len_value);
|
||||
data->issueConfirmedNotifications =
|
||||
decode_context_boolean(&apdu[len]);
|
||||
len++;
|
||||
} else
|
||||
data->cancellationRequest = true;
|
||||
/* tag 3 - lifetime - optional */
|
||||
if (decode_is_context_tag(&apdu[len], 3)) {
|
||||
len +=
|
||||
decode_tag_number_and_value(&apdu[len], &tag_number,
|
||||
&len_value);
|
||||
len += decode_unsigned(&apdu[len], len_value, &decoded_value);
|
||||
data->lifetime = decoded_value;
|
||||
} else
|
||||
data->lifetime = 0;
|
||||
/* tag 4 - monitoredPropertyIdentifier */
|
||||
if (!decode_is_opening_tag_number(&apdu[len], 4))
|
||||
return -3;
|
||||
/* a tag number of 4 is not extended so only one octet */
|
||||
len++;
|
||||
/* the propertyIdentifier is tag 0 */
|
||||
if (decode_is_context_tag(&apdu[len], 0)) {
|
||||
len +=
|
||||
decode_tag_number_and_value(&apdu[len], &tag_number,
|
||||
&len_value);
|
||||
len += decode_enumerated(&apdu[len], len_value, &property);
|
||||
data->monitoredProperty.propertyIdentifier = property;
|
||||
} else
|
||||
return -4;
|
||||
/* the optional array index is tag 1 */
|
||||
if (decode_is_context_tag(&apdu[len], 1)) {
|
||||
len +=
|
||||
decode_tag_number_and_value(&apdu[len], &tag_number,
|
||||
&len_value);
|
||||
len += decode_unsigned(&apdu[len], len_value, &decoded_value);
|
||||
data->monitoredProperty.propertyArrayIndex = decoded_value;
|
||||
} else {
|
||||
data->monitoredProperty.propertyArrayIndex = BACNET_ARRAY_ALL;
|
||||
}
|
||||
|
||||
if (!decode_is_closing_tag_number(&apdu[len], 4))
|
||||
return -5;
|
||||
/* a tag number of 4 is not extended so only one octet */
|
||||
len++;
|
||||
/* tag 5 - covIncrement - optional */
|
||||
if (decode_is_context_tag(&apdu[len], 5)) {
|
||||
data->covIncrementPresent = true;
|
||||
len +=
|
||||
decode_tag_number_and_value(&apdu[len], &tag_number,
|
||||
&len_value);
|
||||
len += decode_real(&apdu[len], &data->covIncrement);
|
||||
} else
|
||||
data->covIncrementPresent = false;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
int ucov_notify_send(uint8_t * buffer, BACNET_COV_DATA * data)
|
||||
{
|
||||
int len = 0;
|
||||
int pdu_len = 0;
|
||||
BACNET_ADDRESS dest;
|
||||
int bytes_sent = 0;
|
||||
BACNET_NPDU_DATA npdu_data;
|
||||
|
||||
/* unconfirmed is a broadcast */
|
||||
datalink_get_broadcast_address(&dest);
|
||||
/* encode the NPDU portion of the packet */
|
||||
npdu_encode_npdu_data(&npdu_data, false, MESSAGE_PRIORITY_NORMAL);
|
||||
pdu_len = npdu_encode_pdu(&buffer[0], &dest, NULL, &npdu_data);
|
||||
/* encode the APDU portion of the packet */
|
||||
len = ucov_notify_encode_apdu(&buffer[pdu_len], data);
|
||||
pdu_len += len;
|
||||
/* send the data */
|
||||
bytes_sent = datalink_send_pdu(&dest, &npdu_data, &buffer[0], pdu_len);
|
||||
|
||||
return bytes_sent;
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include "ctest.h"
|
||||
#include "bacapp.h"
|
||||
|
||||
int ccov_notify_decode_apdu(uint8_t * apdu,
|
||||
unsigned apdu_len, uint8_t * invoke_id, BACNET_COV_DATA * data)
|
||||
{
|
||||
int len = 0;
|
||||
unsigned offset = 0;
|
||||
|
||||
if (!apdu)
|
||||
return -1;
|
||||
/* optional checking - most likely was already done prior to this call */
|
||||
if (apdu[0] != PDU_TYPE_CONFIRMED_SERVICE_REQUEST)
|
||||
return -2;
|
||||
/* apdu[1] = encode_max_segs_max_apdu(0, Device_Max_APDU_Length_Accepted()); */
|
||||
*invoke_id = apdu[2]; /* invoke id - filled in by net layer */
|
||||
if (apdu[3] != SERVICE_CONFIRMED_COV_NOTIFICATION)
|
||||
return -3;
|
||||
offset = 4;
|
||||
|
||||
/* optional limits - must be used as a pair */
|
||||
if (apdu_len > offset) {
|
||||
len =
|
||||
cov_notify_decode_service_request(&apdu[offset],
|
||||
apdu_len - offset, data);
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
int ucov_notify_decode_apdu(uint8_t * apdu,
|
||||
unsigned apdu_len, BACNET_COV_DATA * data)
|
||||
{
|
||||
int len = 0;
|
||||
unsigned offset = 0;
|
||||
|
||||
if (!apdu)
|
||||
return -1;
|
||||
/* optional checking - most likely was already done prior to this call */
|
||||
if (apdu[0] != PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST)
|
||||
return -2;
|
||||
if (apdu[1] != SERVICE_UNCONFIRMED_COV_NOTIFICATION)
|
||||
return -3;
|
||||
/* optional limits - must be used as a pair */
|
||||
offset = 2;
|
||||
if (apdu_len > offset) {
|
||||
len =
|
||||
cov_notify_decode_service_request(&apdu[offset],
|
||||
apdu_len - offset, data);
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
int cov_subscribe_decode_apdu(uint8_t * apdu,
|
||||
unsigned apdu_len, uint8_t * invoke_id,
|
||||
BACNET_SUBSCRIBE_COV_DATA * data)
|
||||
{
|
||||
int len = 0;
|
||||
unsigned offset = 0;
|
||||
|
||||
if (!apdu)
|
||||
return -1;
|
||||
/* optional checking - most likely was already done prior to this call */
|
||||
if (apdu[0] != PDU_TYPE_CONFIRMED_SERVICE_REQUEST)
|
||||
return -2;
|
||||
/* apdu[1] = encode_max_segs_max_apdu(0, Device_Max_APDU_Length_Accepted()); */
|
||||
*invoke_id = apdu[2]; /* invoke id - filled in by net layer */
|
||||
if (apdu[3] != SERVICE_CONFIRMED_SUBSCRIBE_COV)
|
||||
return -3;
|
||||
offset = 4;
|
||||
|
||||
/* optional limits - must be used as a pair */
|
||||
if (apdu_len > offset) {
|
||||
len =
|
||||
cov_subscribe_decode_service_request(&apdu[offset],
|
||||
apdu_len - offset, data);
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
int cov_subscribe_property_decode_apdu(uint8_t * apdu,
|
||||
unsigned apdu_len, uint8_t * invoke_id,
|
||||
BACNET_SUBSCRIBE_COV_DATA * data)
|
||||
{
|
||||
int len = 0;
|
||||
unsigned offset = 0;
|
||||
|
||||
if (!apdu)
|
||||
return -1;
|
||||
/* optional checking - most likely was already done prior to this call */
|
||||
if (apdu[0] != PDU_TYPE_CONFIRMED_SERVICE_REQUEST)
|
||||
return -2;
|
||||
/* apdu[1] = encode_max_segs_max_apdu(0, Device_Max_APDU_Length_Accepted()); */
|
||||
*invoke_id = apdu[2]; /* invoke id - filled in by net layer */
|
||||
if (apdu[3] != SERVICE_CONFIRMED_SUBSCRIBE_COV_PROPERTY)
|
||||
return -3;
|
||||
offset = 4;
|
||||
|
||||
/* optional limits - must be used as a pair */
|
||||
if (apdu_len > offset) {
|
||||
len =
|
||||
cov_subscribe_property_decode_service_request(&apdu[offset],
|
||||
apdu_len - offset, data);
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/* dummy function stubs */
|
||||
int npdu_encode_pdu(uint8_t * npdu,
|
||||
BACNET_ADDRESS * dest,
|
||||
BACNET_ADDRESS * src, BACNET_NPDU_DATA * npdu_data)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void npdu_encode_npdu_data(BACNET_NPDU_DATA * npdu,
|
||||
bool data_expecting_reply, BACNET_MESSAGE_PRIORITY priority)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/* dummy function stubs */
|
||||
int datalink_send_pdu(BACNET_ADDRESS * dest,
|
||||
BACNET_NPDU_DATA * npdu_data, uint8_t * pdu, unsigned pdu_len)
|
||||
{
|
||||
(void) dest;
|
||||
(void) npdu_data;
|
||||
(void) pdu;
|
||||
(void) pdu_len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* dummy function stubs */
|
||||
void datalink_get_broadcast_address(BACNET_ADDRESS * dest)
|
||||
{
|
||||
(void) dest;
|
||||
}
|
||||
|
||||
/* dummy function stubs */
|
||||
uint16_t Device_Max_APDU_Length_Accepted(void)
|
||||
{
|
||||
return MAX_APDU;
|
||||
}
|
||||
|
||||
void testCOVNotifyData(Test * pTest,
|
||||
BACNET_COV_DATA * data, BACNET_COV_DATA * test_data)
|
||||
{
|
||||
ct_test(pTest,
|
||||
test_data->subscriberProcessIdentifier ==
|
||||
data->subscriberProcessIdentifier);
|
||||
ct_test(pTest,
|
||||
test_data->initiatingDeviceIdentifier ==
|
||||
data->initiatingDeviceIdentifier);
|
||||
ct_test(pTest,
|
||||
test_data->monitoredObjectIdentifier.type ==
|
||||
data->monitoredObjectIdentifier.type);
|
||||
ct_test(pTest,
|
||||
test_data->monitoredObjectIdentifier.instance ==
|
||||
data->monitoredObjectIdentifier.instance);
|
||||
ct_test(pTest, test_data->timeRemaining == data->timeRemaining);
|
||||
/* FIXME: test the listOfValues in some clever manner */
|
||||
}
|
||||
|
||||
void testUCOVNotifyData(Test * pTest, BACNET_COV_DATA * data)
|
||||
{
|
||||
uint8_t apdu[480] = { 0 };
|
||||
int len = 0;
|
||||
int apdu_len = 0;
|
||||
BACNET_COV_DATA test_data;
|
||||
|
||||
len = ucov_notify_encode_apdu(&apdu[0], data);
|
||||
ct_test(pTest, len > 0);
|
||||
apdu_len = len;
|
||||
|
||||
test_data.listOfValues.next = NULL;
|
||||
len = ucov_notify_decode_apdu(&apdu[0], apdu_len, &test_data);
|
||||
ct_test(pTest, len != -1);
|
||||
testCOVNotifyData(pTest, data, &test_data);
|
||||
}
|
||||
|
||||
void testCCOVNotifyData(Test * pTest, uint8_t invoke_id,
|
||||
BACNET_COV_DATA * data)
|
||||
{
|
||||
uint8_t apdu[480] = { 0 };
|
||||
int len = 0;
|
||||
int apdu_len = 0;
|
||||
BACNET_COV_DATA test_data;
|
||||
uint8_t test_invoke_id = 0;
|
||||
|
||||
len = ccov_notify_encode_apdu(&apdu[0], invoke_id, data);
|
||||
ct_test(pTest, len != 0);
|
||||
apdu_len = len;
|
||||
|
||||
test_data.listOfValues.next = NULL;
|
||||
len = ccov_notify_decode_apdu(&apdu[0], apdu_len,
|
||||
&test_invoke_id, &test_data);
|
||||
ct_test(pTest, len > 0);
|
||||
ct_test(pTest, test_invoke_id == invoke_id);
|
||||
testCOVNotifyData(pTest, data, &test_data);
|
||||
}
|
||||
|
||||
void testCOVNotify(Test * pTest)
|
||||
{
|
||||
uint8_t invoke_id = 12;
|
||||
BACNET_COV_DATA data;
|
||||
/* BACNET_PROPERTY_VALUE value2; */
|
||||
|
||||
data.subscriberProcessIdentifier = 1;
|
||||
data.initiatingDeviceIdentifier = 123;
|
||||
data.monitoredObjectIdentifier.type = OBJECT_ANALOG_INPUT;
|
||||
data.monitoredObjectIdentifier.instance = 321;
|
||||
data.timeRemaining = 456;
|
||||
|
||||
data.listOfValues.propertyIdentifier = PROP_PRESENT_VALUE;
|
||||
data.listOfValues.propertyArrayIndex = BACNET_ARRAY_ALL;
|
||||
bacapp_parse_application_data(BACNET_APPLICATION_TAG_REAL,
|
||||
"21.0", &data.listOfValues.value);
|
||||
data.listOfValues.priority = 0;
|
||||
data.listOfValues.next = NULL;
|
||||
|
||||
testUCOVNotifyData(pTest, &data);
|
||||
testCCOVNotifyData(pTest, invoke_id, &data);
|
||||
|
||||
/* FIXME: add more values to the list of values */
|
||||
}
|
||||
|
||||
void testCOVSubscribeData(Test * pTest,
|
||||
BACNET_SUBSCRIBE_COV_DATA * data,
|
||||
BACNET_SUBSCRIBE_COV_DATA * test_data)
|
||||
{
|
||||
ct_test(pTest,
|
||||
test_data->subscriberProcessIdentifier ==
|
||||
data->subscriberProcessIdentifier);
|
||||
ct_test(pTest,
|
||||
test_data->monitoredObjectIdentifier.type ==
|
||||
data->monitoredObjectIdentifier.type);
|
||||
ct_test(pTest,
|
||||
test_data->monitoredObjectIdentifier.instance ==
|
||||
data->monitoredObjectIdentifier.instance);
|
||||
ct_test(pTest,
|
||||
test_data->cancellationRequest == data->cancellationRequest);
|
||||
if (!test_data->cancellationRequest) {
|
||||
ct_test(pTest,
|
||||
test_data->issueConfirmedNotifications ==
|
||||
data->issueConfirmedNotifications);
|
||||
ct_test(pTest, test_data->lifetime == data->lifetime);
|
||||
}
|
||||
}
|
||||
|
||||
void testCOVSubscribePropertyData(Test * pTest,
|
||||
BACNET_SUBSCRIBE_COV_DATA * data,
|
||||
BACNET_SUBSCRIBE_COV_DATA * test_data)
|
||||
{
|
||||
testCOVSubscribeData(pTest, data, test_data);
|
||||
ct_test(pTest,
|
||||
test_data->monitoredProperty.propertyIdentifier ==
|
||||
data->monitoredProperty.propertyIdentifier);
|
||||
ct_test(pTest,
|
||||
test_data->monitoredProperty.propertyArrayIndex ==
|
||||
data->monitoredProperty.propertyArrayIndex);
|
||||
ct_test(pTest,
|
||||
test_data->covIncrementPresent == data->covIncrementPresent);
|
||||
if (test_data->covIncrementPresent) {
|
||||
ct_test(pTest, test_data->covIncrement == data->covIncrement);
|
||||
}
|
||||
}
|
||||
|
||||
void testCOVSubscribeEncoding(Test * pTest, uint8_t invoke_id,
|
||||
BACNET_SUBSCRIBE_COV_DATA * data)
|
||||
{
|
||||
uint8_t apdu[480] = { 0 };
|
||||
int len = 0;
|
||||
int apdu_len = 0;
|
||||
BACNET_SUBSCRIBE_COV_DATA test_data;
|
||||
uint8_t test_invoke_id = 0;
|
||||
|
||||
len = cov_subscribe_encode_adpu(&apdu[0], invoke_id, data);
|
||||
ct_test(pTest, len != 0);
|
||||
apdu_len = len;
|
||||
|
||||
len = cov_subscribe_decode_apdu(&apdu[0], apdu_len,
|
||||
&test_invoke_id, &test_data);
|
||||
ct_test(pTest, len > 0);
|
||||
ct_test(pTest, test_invoke_id == invoke_id);
|
||||
testCOVSubscribeData(pTest, data, &test_data);
|
||||
}
|
||||
|
||||
void testCOVSubscribePropertyEncoding(Test * pTest, uint8_t invoke_id,
|
||||
BACNET_SUBSCRIBE_COV_DATA * data)
|
||||
{
|
||||
uint8_t apdu[480] = { 0 };
|
||||
int len = 0;
|
||||
int apdu_len = 0;
|
||||
BACNET_SUBSCRIBE_COV_DATA test_data;
|
||||
uint8_t test_invoke_id = 0;
|
||||
|
||||
len = cov_subscribe_property_encode_adpu(&apdu[0], invoke_id, data);
|
||||
ct_test(pTest, len != 0);
|
||||
apdu_len = len;
|
||||
|
||||
len = cov_subscribe_property_decode_apdu(&apdu[0], apdu_len,
|
||||
&test_invoke_id, &test_data);
|
||||
ct_test(pTest, len > 0);
|
||||
ct_test(pTest, test_invoke_id == invoke_id);
|
||||
testCOVSubscribePropertyData(pTest, data, &test_data);
|
||||
}
|
||||
|
||||
void testCOVSubscribe(Test * pTest)
|
||||
{
|
||||
uint8_t invoke_id = 12;
|
||||
BACNET_SUBSCRIBE_COV_DATA data;
|
||||
|
||||
data.subscriberProcessIdentifier = 1;
|
||||
data.monitoredObjectIdentifier.type = OBJECT_ANALOG_INPUT;
|
||||
data.monitoredObjectIdentifier.instance = 321;
|
||||
data.cancellationRequest = false;
|
||||
data.issueConfirmedNotifications = true;
|
||||
data.lifetime = 456;
|
||||
|
||||
testCOVSubscribeEncoding(pTest, invoke_id, &data);
|
||||
data.cancellationRequest = true;
|
||||
testCOVSubscribeEncoding(pTest, invoke_id, &data);
|
||||
}
|
||||
|
||||
void testCOVSubscribeProperty(Test * pTest)
|
||||
{
|
||||
uint8_t invoke_id = 12;
|
||||
BACNET_SUBSCRIBE_COV_DATA data;
|
||||
|
||||
data.subscriberProcessIdentifier = 1;
|
||||
data.monitoredObjectIdentifier.type = OBJECT_ANALOG_INPUT;
|
||||
data.monitoredObjectIdentifier.instance = 321;
|
||||
data.cancellationRequest = false;
|
||||
data.issueConfirmedNotifications = true;
|
||||
data.lifetime = 456;
|
||||
data.monitoredProperty.propertyIdentifier = PROP_FILE_SIZE;
|
||||
data.monitoredProperty.propertyArrayIndex = BACNET_ARRAY_ALL;
|
||||
data.covIncrementPresent = true;
|
||||
data.covIncrement = 1.0;
|
||||
|
||||
testCOVSubscribePropertyEncoding(pTest, invoke_id, &data);
|
||||
|
||||
data.cancellationRequest = true;
|
||||
testCOVSubscribePropertyEncoding(pTest, invoke_id, &data);
|
||||
|
||||
data.cancellationRequest = false;
|
||||
data.covIncrementPresent = false;
|
||||
testCOVSubscribePropertyEncoding(pTest, invoke_id, &data);
|
||||
}
|
||||
|
||||
#ifdef TEST_COV
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
Test *pTest;
|
||||
bool rc;
|
||||
|
||||
pTest = ct_create("BACnet COV", NULL);
|
||||
/* individual tests */
|
||||
rc = ct_addTestFunction(pTest, testCOVNotify);
|
||||
assert(rc);
|
||||
rc = ct_addTestFunction(pTest, testCOVSubscribe);
|
||||
assert(rc);
|
||||
rc = ct_addTestFunction(pTest, testCOVSubscribeProperty);
|
||||
assert(rc);
|
||||
|
||||
ct_setStream(pTest, stdout);
|
||||
ct_run(pTest);
|
||||
(void) ct_report(pTest);
|
||||
ct_destroy(pTest);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* TEST_COV */
|
||||
#endif /* TEST */
|
||||
@@ -1,80 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE CodeBlocks_project_file>
|
||||
<CodeBlocks_project_file>
|
||||
<FileVersion major="1" minor="1"/>
|
||||
<Project>
|
||||
<Option title="COV Unit Test"/>
|
||||
<Option makefile="Makefile"/>
|
||||
<Option makefile_is_custom="0"/>
|
||||
<Option compiler="0"/>
|
||||
<Build>
|
||||
<Target title="default">
|
||||
<Option output="C:\code\bacnet-stack\cov.exe"/>
|
||||
<Option working_dir="."/>
|
||||
<Option object_output=".objs"/>
|
||||
<Option deps_output=".deps"/>
|
||||
<Option type="1"/>
|
||||
<Option compiler="0"/>
|
||||
<Option projectResourceIncludeDirsRelation="1"/>
|
||||
</Target>
|
||||
</Build>
|
||||
<Compiler>
|
||||
<Add option="-DTEST"/>
|
||||
<Add option="-DTEST_WHOIS"/>
|
||||
</Compiler>
|
||||
<Unit filename="bacapp.c">
|
||||
<Option compilerVar="CC"/>
|
||||
<Option target="default"/>
|
||||
</Unit>
|
||||
<Unit filename="bacapp.h">
|
||||
<Option compilerVar=""/>
|
||||
<Option compile="0"/>
|
||||
<Option link="0"/>
|
||||
<Option target="default"/>
|
||||
</Unit>
|
||||
<Unit filename="bacdcode.c">
|
||||
<Option compilerVar="CC"/>
|
||||
<Option target="default"/>
|
||||
</Unit>
|
||||
<Unit filename="bacdcode.h">
|
||||
<Option compilerVar=""/>
|
||||
<Option compile="0"/>
|
||||
<Option link="0"/>
|
||||
<Option target="default"/>
|
||||
</Unit>
|
||||
<Unit filename="bacdef.h">
|
||||
<Option compilerVar=""/>
|
||||
<Option compile="0"/>
|
||||
<Option link="0"/>
|
||||
<Option target="default"/>
|
||||
</Unit>
|
||||
<Unit filename="bacenum.h">
|
||||
<Option compilerVar=""/>
|
||||
<Option compile="0"/>
|
||||
<Option link="0"/>
|
||||
<Option target="default"/>
|
||||
</Unit>
|
||||
<Unit filename="bacstr.c">
|
||||
<Option compilerVar="CC"/>
|
||||
<Option target="default"/>
|
||||
</Unit>
|
||||
<Unit filename="bigend.c">
|
||||
<Option compilerVar="CC"/>
|
||||
<Option target="default"/>
|
||||
</Unit>
|
||||
<Unit filename="cov.c">
|
||||
<Option compilerVar="CC"/>
|
||||
<Option target="default"/>
|
||||
</Unit>
|
||||
<Unit filename="cov.h">
|
||||
<Option compilerVar=""/>
|
||||
<Option compile="0"/>
|
||||
<Option link="0"/>
|
||||
<Option target="default"/>
|
||||
</Unit>
|
||||
<Unit filename="test\ctest.c">
|
||||
<Option compilerVar="CC"/>
|
||||
<Option target="default"/>
|
||||
</Unit>
|
||||
</Project>
|
||||
</CodeBlocks_project_file>
|
||||
@@ -1,120 +0,0 @@
|
||||
/*####COPYRIGHTBEGIN####
|
||||
-------------------------------------------
|
||||
Copyright (C) 2006 Steve Karg
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to:
|
||||
The Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330
|
||||
Boston, MA 02111-1307, USA.
|
||||
|
||||
As a special exception, if other files instantiate templates or
|
||||
use macros or inline functions from this file, or you compile
|
||||
this file and link it with other works to produce a work based
|
||||
on this file, this file does not by itself cause the resulting
|
||||
work to be covered by the GNU General Public License. However
|
||||
the source code for this file must still be made available in
|
||||
accordance with section (3) of the GNU General Public License.
|
||||
|
||||
This exception does not invalidate any other reasons why a work
|
||||
based on this file might be covered by the GNU General Public
|
||||
License.
|
||||
-------------------------------------------
|
||||
####COPYRIGHTEND####*/
|
||||
#ifndef COV_H
|
||||
#define COV_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "bacapp.h"
|
||||
|
||||
struct BACnet_Property_Value;
|
||||
typedef struct BACnet_Property_Value {
|
||||
BACNET_PROPERTY_ID propertyIdentifier;
|
||||
unsigned propertyArrayIndex;
|
||||
BACNET_APPLICATION_DATA_VALUE value;
|
||||
uint8_t priority;
|
||||
/* simple linked list */
|
||||
struct BACnet_Property_Value *next;
|
||||
} BACNET_PROPERTY_VALUE;
|
||||
|
||||
typedef struct BACnet_COV_Data {
|
||||
uint32_t subscriberProcessIdentifier;
|
||||
uint32_t initiatingDeviceIdentifier;
|
||||
BACNET_OBJECT_ID monitoredObjectIdentifier;
|
||||
unsigned timeRemaining;
|
||||
/* simple linked list of values */
|
||||
BACNET_PROPERTY_VALUE listOfValues;
|
||||
} BACNET_COV_DATA;
|
||||
|
||||
typedef struct BACnet_Property_Reference {
|
||||
BACNET_PROPERTY_ID propertyIdentifier;
|
||||
unsigned propertyArrayIndex; /* optional */
|
||||
} BACNET_PROPERTY_REFERENCE;
|
||||
|
||||
typedef struct BACnet_Subscribe_COV_Data {
|
||||
uint32_t subscriberProcessIdentifier;
|
||||
BACNET_OBJECT_ID monitoredObjectIdentifier;
|
||||
bool cancellationRequest; /* true if this is a cancellation request */
|
||||
bool issueConfirmedNotifications; /* optional */
|
||||
unsigned lifetime; /* optional */
|
||||
BACNET_PROPERTY_REFERENCE monitoredProperty;
|
||||
bool covIncrementPresent; /* true if present */
|
||||
float covIncrement; /* optional */
|
||||
} BACNET_SUBSCRIBE_COV_DATA;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
int ucov_notify_encode_apdu(uint8_t * apdu, BACNET_COV_DATA * data);
|
||||
|
||||
int ucov_notify_decode_apdu(uint8_t * apdu,
|
||||
unsigned apdu_len, BACNET_COV_DATA * data);
|
||||
|
||||
int ucov_notify_send(uint8_t * buffer, BACNET_COV_DATA * data);
|
||||
|
||||
int ccov_notify_encode_apdu(uint8_t * apdu,
|
||||
uint8_t invoke_id, BACNET_COV_DATA * data);
|
||||
|
||||
int ccov_notify_decode_apdu(uint8_t * apdu,
|
||||
unsigned apdu_len, uint8_t * invoke_id, BACNET_COV_DATA * data);
|
||||
|
||||
/* common for both confirmed and unconfirmed */
|
||||
int cov_notify_decode_service_request(uint8_t * apdu,
|
||||
unsigned apdu_len, BACNET_COV_DATA * data);
|
||||
|
||||
int cov_subscribe_property_decode_service_request(uint8_t * apdu,
|
||||
unsigned apdu_len, BACNET_SUBSCRIBE_COV_DATA * data);
|
||||
|
||||
int cov_subscribe_property_encode_adpu(uint8_t * apdu,
|
||||
uint8_t invoke_id, BACNET_SUBSCRIBE_COV_DATA * data);
|
||||
|
||||
int cov_subscribe_decode_service_request(uint8_t * apdu,
|
||||
unsigned apdu_len, BACNET_SUBSCRIBE_COV_DATA * data);
|
||||
|
||||
int cov_subscribe_encode_adpu(uint8_t * apdu,
|
||||
uint8_t invoke_id, BACNET_SUBSCRIBE_COV_DATA * data);
|
||||
|
||||
|
||||
#ifdef TEST
|
||||
#include "ctest.h"
|
||||
void testCOVNotify(Test * pTest);
|
||||
void testCOVSubscribeProperty(Test * pTest);
|
||||
void testCOVSubscribe(Test * pTest);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
@@ -1,37 +0,0 @@
|
||||
#Makefile to build test case
|
||||
CC = gcc
|
||||
BASEDIR = .
|
||||
#CFLAGS = -Wall -I.
|
||||
# -g for debugging with gdb
|
||||
#CFLAGS = -Wall -I. -g
|
||||
CFLAGS = -Wall -I. -Itest -Idemo/object -DTEST -DTEST_COV -DBACDL_TEST=1 -DBIG_ENDIAN=0 -g
|
||||
|
||||
SRCS = bacdcode.c \
|
||||
bacstr.c \
|
||||
datetime.c \
|
||||
bacapp.c \
|
||||
indtext.c \
|
||||
bactext.c \
|
||||
cov.c \
|
||||
test/ctest.c
|
||||
|
||||
OBJS = ${SRCS:.c=.o}
|
||||
|
||||
TARGET = cov
|
||||
|
||||
all: ${TARGET}
|
||||
|
||||
${TARGET}: ${OBJS}
|
||||
${CC} -o $@ ${OBJS}
|
||||
|
||||
.c.o:
|
||||
${CC} -c ${CFLAGS} $*.c -o $@
|
||||
|
||||
depend:
|
||||
rm -f .depend
|
||||
${CC} -MM ${CFLAGS} *.c >> .depend
|
||||
|
||||
clean:
|
||||
rm -rf core ${TARGET} $(OBJS) *.bak *.1 *.ini
|
||||
|
||||
include: .depend
|
||||
@@ -1,153 +0,0 @@
|
||||
/*####COPYRIGHTBEGIN####
|
||||
-------------------------------------------
|
||||
Copyright (C) 2004 Steve Karg
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to:
|
||||
The Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330
|
||||
Boston, MA 02111-1307
|
||||
USA.
|
||||
|
||||
As a special exception, if other files instantiate templates or
|
||||
use macros or inline functions from this file, or you compile
|
||||
this file and link it with other works to produce a work based
|
||||
on this file, this file does not by itself cause the resulting
|
||||
work to be covered by the GNU General Public License. However
|
||||
the source code for this file must still be made available in
|
||||
accordance with section (3) of the GNU General Public License.
|
||||
|
||||
This exception does not invalidate any other reasons why a work
|
||||
based on this file might be covered by the GNU General Public
|
||||
License.
|
||||
-------------------------------------------
|
||||
####COPYRIGHTEND####*/
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/* Accumulate "dataValue" into the CRC in crcValue. */
|
||||
/* Return value is updated CRC */
|
||||
/* */
|
||||
/* The ^ operator means exclusive OR. */
|
||||
/* Note: This function is copied directly from the BACnet standard. */
|
||||
uint8_t CRC_Calc_Header(uint8_t dataValue, uint8_t crcValue)
|
||||
{
|
||||
uint16_t crc;
|
||||
|
||||
crc = crcValue ^ dataValue; /* XOR C7..C0 with D7..D0 */
|
||||
|
||||
/* Exclusive OR the terms in the table (top down) */
|
||||
crc = crc ^ (crc << 1) ^ (crc << 2) ^ (crc << 3)
|
||||
^ (crc << 4) ^ (crc << 5) ^ (crc << 6)
|
||||
^ (crc << 7);
|
||||
|
||||
/* Combine bits shifted out left hand end */
|
||||
return (crc & 0xfe) ^ ((crc >> 8) & 1);
|
||||
}
|
||||
|
||||
/* Accumulate "dataValue" into the CRC in crcValue. */
|
||||
/* Return value is updated CRC */
|
||||
/* */
|
||||
/* The ^ operator means exclusive OR. */
|
||||
/* Note: This function is copied directly from the BACnet standard. */
|
||||
uint16_t CRC_Calc_Data(uint8_t dataValue, uint16_t crcValue)
|
||||
{
|
||||
uint16_t crcLow;
|
||||
|
||||
crcLow = (crcValue & 0xff) ^ dataValue; /* XOR C7..C0 with D7..D0 */
|
||||
|
||||
/* Exclusive OR the terms in the table (top down) */
|
||||
return (crcValue >> 8) ^ (crcLow << 8) ^ (crcLow << 3)
|
||||
^ (crcLow << 12) ^ (crcLow >> 4)
|
||||
^ (crcLow & 0x0f) ^ ((crcLow & 0x0f) << 7);
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include "ctest.h"
|
||||
#include "bytes.h"
|
||||
|
||||
/* test from Annex G 1.0 of BACnet Standard */
|
||||
void testCRC8(Test * pTest)
|
||||
{
|
||||
uint8_t crc = 0xff; /* accumulates the crc value */
|
||||
uint8_t frame_crc; /* appended to the end of the frame */
|
||||
|
||||
crc = CRC_Calc_Header(0x00, crc);
|
||||
ct_test(pTest, crc == 0x55);
|
||||
crc = CRC_Calc_Header(0x10, crc);
|
||||
ct_test(pTest, crc == 0xC2);
|
||||
crc = CRC_Calc_Header(0x05, crc);
|
||||
ct_test(pTest, crc == 0xBC);
|
||||
crc = CRC_Calc_Header(0x00, crc);
|
||||
ct_test(pTest, crc == 0x95);
|
||||
crc = CRC_Calc_Header(0x00, crc);
|
||||
ct_test(pTest, crc == 0x73);
|
||||
/* send the ones complement of the CRC in place of */
|
||||
/* the CRC, and the resulting CRC will always equal 0x55. */
|
||||
frame_crc = ~crc;
|
||||
ct_test(pTest, frame_crc == 0x8C);
|
||||
/* use the ones complement value and the next to last CRC value */
|
||||
crc = CRC_Calc_Header(frame_crc, crc);
|
||||
ct_test(pTest, crc == 0x55);
|
||||
}
|
||||
|
||||
/* test from Annex G 2.0 of BACnet Standard */
|
||||
void testCRC16(Test * pTest)
|
||||
{
|
||||
uint16_t crc = 0xffff;
|
||||
uint16_t data_crc;
|
||||
|
||||
crc = CRC_Calc_Data(0x01, crc);
|
||||
ct_test(pTest, crc == 0x1E0E);
|
||||
crc = CRC_Calc_Data(0x22, crc);
|
||||
ct_test(pTest, crc == 0xEB70);
|
||||
crc = CRC_Calc_Data(0x30, crc);
|
||||
ct_test(pTest, crc == 0x42EF);
|
||||
/* send the ones complement of the CRC in place of */
|
||||
/* the CRC, and the resulting CRC will always equal 0xF0B8. */
|
||||
data_crc = ~crc;
|
||||
ct_test(pTest, data_crc == 0xBD10);
|
||||
crc = CRC_Calc_Data(LO_BYTE(data_crc), crc);
|
||||
ct_test(pTest, crc == 0x0F3A);
|
||||
crc = CRC_Calc_Data(HI_BYTE(data_crc), crc);
|
||||
ct_test(pTest, crc == 0xF0B8);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef TEST_CRC
|
||||
int main(void)
|
||||
{
|
||||
Test *pTest;
|
||||
bool rc;
|
||||
|
||||
pTest = ct_create("crc", NULL);
|
||||
|
||||
/* individual tests */
|
||||
rc = ct_addTestFunction(pTest, testCRC8);
|
||||
assert(rc);
|
||||
rc = ct_addTestFunction(pTest, testCRC16);
|
||||
assert(rc);
|
||||
|
||||
ct_setStream(pTest, stdout);
|
||||
ct_run(pTest);
|
||||
(void) ct_report(pTest);
|
||||
|
||||
ct_destroy(pTest);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
@@ -1,51 +0,0 @@
|
||||
/*####COPYRIGHTBEGIN####
|
||||
-------------------------------------------
|
||||
Copyright (C) 2004 Steve Karg
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to:
|
||||
The Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330
|
||||
Boston, MA 02111-1307
|
||||
USA.
|
||||
|
||||
As a special exception, if other files instantiate templates or
|
||||
use macros or inline functions from this file, or you compile
|
||||
this file and link it with other works to produce a work based
|
||||
on this file, this file does not by itself cause the resulting
|
||||
work to be covered by the GNU General Public License. However
|
||||
the source code for this file must still be made available in
|
||||
accordance with section (3) of the GNU General Public License.
|
||||
|
||||
This exception does not invalidate any other reasons why a work
|
||||
based on this file might be covered by the GNU General Public
|
||||
License.
|
||||
-------------------------------------------
|
||||
####COPYRIGHTEND####*/
|
||||
#ifndef CRC_H
|
||||
#define CRC_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
uint8_t CRC_Calc_Header(uint8_t dataValue, uint8_t crcValue);
|
||||
uint16_t CRC_Calc_Data(uint8_t dataValue, uint16_t crcValue);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
Binary file not shown.
@@ -1,29 +0,0 @@
|
||||
#Makefile to build CRC tests
|
||||
CC = gcc
|
||||
BASEDIR = .
|
||||
#CFLAGS = -Wall -I.
|
||||
# -g for debugging with gdb
|
||||
#CFLAGS = -Wall -I. -g
|
||||
CFLAGS = -Wall -I. -Itest -DTEST -DTEST_CRC -g
|
||||
|
||||
OBJS = crc.o test/ctest.o
|
||||
|
||||
TARGET = crc
|
||||
|
||||
all: ${TARGET}
|
||||
|
||||
${TARGET}: ${OBJS}
|
||||
${CC} -o $@ ${OBJS}
|
||||
|
||||
.c.o:
|
||||
${CC} -c ${CFLAGS} $*.c -o $@
|
||||
|
||||
depend:
|
||||
rm -f .depend
|
||||
${CC} -MM ${CFLAGS} *.c >> .depend
|
||||
|
||||
clean:
|
||||
rm -rf core ${TARGET} $(OBJS) *.bak *.1 *.ini
|
||||
|
||||
include: .depend
|
||||
|
||||
@@ -1,86 +0,0 @@
|
||||
/*####COPYRIGHTBEGIN####
|
||||
-------------------------------------------
|
||||
Copyright (C) 2005 Steve Karg
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to:
|
||||
The Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330
|
||||
Boston, MA 02111-1307, USA.
|
||||
|
||||
As a special exception, if other files instantiate templates or
|
||||
use macros or inline functions from this file, or you compile
|
||||
this file and link it with other works to produce a work based
|
||||
on this file, this file does not by itself cause the resulting
|
||||
work to be covered by the GNU General Public License. However
|
||||
the source code for this file must still be made available in
|
||||
accordance with section (3) of the GNU General Public License.
|
||||
|
||||
This exception does not invalidate any other reasons why a work
|
||||
based on this file might be covered by the GNU General Public
|
||||
License.
|
||||
-------------------------------------------
|
||||
####COPYRIGHTEND####*/
|
||||
#ifndef DATALINK_H
|
||||
#define DATALINK_H
|
||||
|
||||
#if defined(BACDL_ETHERNET)
|
||||
#include "ethernet.h"
|
||||
|
||||
#define datalink_send_pdu ethernet_send_pdu
|
||||
#define datalink_receive ethernet_receive
|
||||
#define datalink_cleanup ethernet_cleanup
|
||||
#define datalink_get_broadcast_address ethernet_get_broadcast_address
|
||||
#define datalink_get_my_address ethernet_get_my_address
|
||||
|
||||
#elif defined(BACDL_ARCNET)
|
||||
#include "arcnet.h"
|
||||
|
||||
#define datalink_send_pdu arcnet_send_pdu
|
||||
#define datalink_receive arcnet_receive
|
||||
#define datalink_cleanup arcnet_cleanup
|
||||
#define datalink_get_broadcast_address arcnet_get_broadcast_address
|
||||
#define datalink_get_my_address arcnet_get_my_address
|
||||
|
||||
#elif defined(BACDL_MSTP)
|
||||
#include "dlmstp.h"
|
||||
|
||||
#define datalink_send_pdu dlmstp_send_pdu
|
||||
#define datalink_receive dlmstp_receive
|
||||
#define datalink_cleanup dlmstp_cleanup
|
||||
#define datalink_get_broadcast_address dlmstp_get_broadcast_address
|
||||
#define datalink_get_my_address dlmstp_get_my_address
|
||||
|
||||
#elif defined(BACDL_BIP)
|
||||
#include "bip.h"
|
||||
|
||||
#define datalink_send_pdu bip_send_pdu
|
||||
#define datalink_receive bip_receive
|
||||
#define datalink_cleanup bip_cleanup
|
||||
#define datalink_get_broadcast_address bip_get_broadcast_address
|
||||
#define datalink_get_my_address bip_get_my_address
|
||||
|
||||
#elif defined(BACDL_TEST)
|
||||
#include "npdu.h"
|
||||
|
||||
extern int datalink_send_pdu(BACNET_ADDRESS * dest,
|
||||
BACNET_NPDU_DATA * npdu_data, uint8_t * pdu, unsigned pdu_len);
|
||||
extern uint16_t datalink_receive(BACNET_ADDRESS * src,
|
||||
uint8_t * pdu, uint16_t max_pdu, unsigned timeout);
|
||||
extern void datalink_cleanup(void);
|
||||
extern void datalink_get_broadcast_address(BACNET_ADDRESS * dest);
|
||||
extern void bip_get_my_address(BACNET_ADDRESS * my_address);
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,713 +0,0 @@
|
||||
/*####COPYRIGHTBEGIN####
|
||||
-------------------------------------------
|
||||
Copyright (C) 2007 Steve Karg <skarg@users.sourceforge.net>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to:
|
||||
The Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330
|
||||
Boston, MA 02111-1307, USA.
|
||||
|
||||
As a special exception, if other files instantiate templates or
|
||||
use macros or inline functions from this file, or you compile
|
||||
this file and link it with other works to produce a work based
|
||||
on this file, this file does not by itself cause the resulting
|
||||
work to be covered by the GNU General Public License. However
|
||||
the source code for this file must still be made available in
|
||||
accordance with section (3) of the GNU General Public License.
|
||||
|
||||
This exception does not invalidate any other reasons why a work
|
||||
based on this file might be covered by the GNU General Public
|
||||
License.
|
||||
-------------------------------------------
|
||||
####COPYRIGHTEND####*/
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include "datetime.h"
|
||||
|
||||
/* BACnet Date */
|
||||
/* year = years since 1900 */
|
||||
/* month 1=Jan */
|
||||
/* day = day of month 1..31 */
|
||||
/* wday 1=Monday...7=Sunday */
|
||||
|
||||
/* Wildcards:
|
||||
A value of X'FF' in any of the four octets
|
||||
shall indicate that the value is unspecified.
|
||||
If all four octets = X'FF', the corresponding
|
||||
time or date may be interpreted as "any" or "don't care"
|
||||
*/
|
||||
|
||||
static bool is_leap_year(uint16_t year)
|
||||
{
|
||||
if ((year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0))
|
||||
return (true);
|
||||
else
|
||||
return (false);
|
||||
}
|
||||
|
||||
static uint8_t month_days(uint16_t year, uint8_t month)
|
||||
{
|
||||
/* note: start with a zero in the first element to save us from a
|
||||
month - 1 calculation in the lookup */
|
||||
int month_days[13] =
|
||||
{ 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
|
||||
|
||||
/* February */
|
||||
if ((month == 2) && is_leap_year(year))
|
||||
return 29;
|
||||
else if (month >= 1 && month <= 12)
|
||||
return month_days[month];
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint32_t days_since_epoch(uint16_t year, uint8_t month, uint8_t day)
|
||||
{
|
||||
uint32_t days = 0; /* return value */
|
||||
uint8_t monthdays; /* days in a month */
|
||||
uint16_t years = 0; /* loop counter for years */
|
||||
uint8_t months = 0; /* loop counter for months */
|
||||
|
||||
monthdays = month_days(year, month);
|
||||
if ((year >= 1900) && (monthdays) && (day >= 1) && (day <= monthdays)) {
|
||||
for (years = 1900; years < year; years++) {
|
||||
days += 365;
|
||||
if (is_leap_year(years))
|
||||
days++;
|
||||
}
|
||||
for (months = 1; months < month; months++) {
|
||||
days += month_days(years, months);
|
||||
}
|
||||
days += (day - 1);
|
||||
}
|
||||
|
||||
return (days);
|
||||
}
|
||||
|
||||
static void days_since_epoch_into_ymd(uint32_t days,
|
||||
uint16_t * pYear, uint8_t * pMonth, uint8_t * pDay)
|
||||
{
|
||||
uint16_t year = 1900;
|
||||
uint8_t month = 1;
|
||||
uint8_t day = 1;
|
||||
|
||||
while (days >= 365) {
|
||||
if ((is_leap_year(year)) && (days == 365))
|
||||
break;
|
||||
days -= 365;
|
||||
if (is_leap_year(year))
|
||||
--days;
|
||||
year++;
|
||||
}
|
||||
|
||||
while (days >= (uint32_t) month_days(year, month)) {
|
||||
days -= month_days(year, month);
|
||||
month++;
|
||||
}
|
||||
|
||||
day += ((uint8_t) days);
|
||||
|
||||
if (pYear)
|
||||
*pYear = year;
|
||||
if (pMonth)
|
||||
*pMonth = month;
|
||||
if (pDay)
|
||||
*pDay = day;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* Jan 1, 1900 is a Monday */
|
||||
/* wday 1=Monday...7=Sunday */
|
||||
static uint8_t day_of_week(uint16_t year, uint8_t month, uint8_t day)
|
||||
{
|
||||
return ((uint8_t) (days_since_epoch(year, month, day) % 7) + 1);
|
||||
}
|
||||
|
||||
/* if the date1 is the same as date2, return is 0
|
||||
if date1 is after date2, returns positive
|
||||
if date1 is before date2, returns negative */
|
||||
int datetime_compare_date(BACNET_DATE * date1, BACNET_DATE * date2)
|
||||
{
|
||||
int diff = 0;
|
||||
|
||||
if (date1 && date2) {
|
||||
diff = (int) date1->year - (int) date2->year;
|
||||
if (diff == 0) {
|
||||
diff = (int) date1->month - (int) date2->month;
|
||||
if (diff == 0) {
|
||||
diff = (int) date1->day - (int) date2->day;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return diff;
|
||||
}
|
||||
|
||||
/* if the time1 is the same as time2, return is 0
|
||||
if time1 is after time2, returns positive
|
||||
if time1 is before time2, returns negative */
|
||||
int datetime_compare_time(BACNET_TIME * time1, BACNET_TIME * time2)
|
||||
{
|
||||
int diff = 0;
|
||||
|
||||
if (time1 && time2) {
|
||||
diff = (int) time1->hour - (int) time2->hour;
|
||||
if (diff == 0) {
|
||||
diff = (int) time1->min - (int) time2->min;
|
||||
if (diff == 0) {
|
||||
diff = (int) time1->sec - (int) time2->sec;
|
||||
if (diff == 0) {
|
||||
diff =
|
||||
(int) time1->hundredths - (int) time2->hundredths;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return diff;
|
||||
}
|
||||
|
||||
/* if the datetime1 is the same as datetime2, return is 0
|
||||
if datetime1 is before datetime2, returns negative
|
||||
if datetime1 is after datetime2, returns positive */
|
||||
int datetime_compare(BACNET_DATE_TIME * datetime1,
|
||||
BACNET_DATE_TIME * datetime2)
|
||||
{
|
||||
int diff = 0;
|
||||
|
||||
diff = datetime_compare_date(&datetime1->date, &datetime2->date);
|
||||
if (diff == 0) {
|
||||
diff = datetime_compare_time(&datetime1->time, &datetime2->time);
|
||||
}
|
||||
|
||||
return diff;
|
||||
}
|
||||
|
||||
void datetime_copy_date(BACNET_DATE * dest_date, BACNET_DATE * src_date)
|
||||
{
|
||||
if (dest_date && src_date) {
|
||||
dest_date->year = src_date->year;
|
||||
dest_date->month = src_date->month;
|
||||
dest_date->day = src_date->day;
|
||||
dest_date->wday = src_date->wday;
|
||||
}
|
||||
}
|
||||
|
||||
void datetime_copy_time(BACNET_TIME * dest_time, BACNET_TIME * src_time)
|
||||
{
|
||||
if (dest_time && src_time) {
|
||||
dest_time->hour = src_time->hour;
|
||||
dest_time->min = src_time->min;
|
||||
dest_time->sec = src_time->sec;
|
||||
dest_time->hundredths = src_time->hundredths;
|
||||
}
|
||||
}
|
||||
|
||||
void datetime_copy(BACNET_DATE_TIME * dest_datetime,
|
||||
BACNET_DATE_TIME * src_datetime)
|
||||
{
|
||||
datetime_copy_time(&dest_datetime->time, &src_datetime->time);
|
||||
datetime_copy_date(&dest_datetime->date, &src_datetime->date);
|
||||
}
|
||||
|
||||
void datetime_set_date(BACNET_DATE * bdate,
|
||||
uint16_t year, uint8_t month, uint8_t day)
|
||||
{
|
||||
if (bdate) {
|
||||
bdate->year = year;
|
||||
bdate->month = month;
|
||||
bdate->day = day;
|
||||
bdate->wday = day_of_week(year, month, day);
|
||||
}
|
||||
}
|
||||
|
||||
void datetime_set_time(BACNET_TIME * btime,
|
||||
uint8_t hour, uint8_t minute, uint8_t seconds, uint8_t hundredths)
|
||||
{
|
||||
if (btime) {
|
||||
btime->hour = hour;
|
||||
btime->min = minute;
|
||||
btime->sec = seconds;
|
||||
btime->hundredths = hundredths;
|
||||
}
|
||||
}
|
||||
|
||||
void datetime_set(BACNET_DATE_TIME * bdatetime,
|
||||
BACNET_DATE * bdate, BACNET_TIME * btime)
|
||||
{
|
||||
if (bdate && btime && bdatetime) {
|
||||
bdatetime->time.hour = btime->hour;
|
||||
bdatetime->time.min = btime->min;
|
||||
bdatetime->time.sec = btime->sec;
|
||||
bdatetime->time.hundredths = btime->hundredths;
|
||||
bdatetime->date.year = bdate->year;
|
||||
bdatetime->date.month = bdate->month;
|
||||
bdatetime->date.day = bdate->day;
|
||||
bdatetime->date.wday = bdate->wday;
|
||||
}
|
||||
}
|
||||
|
||||
void datetime_set_values(BACNET_DATE_TIME * bdatetime,
|
||||
uint16_t year, uint8_t month, uint8_t day,
|
||||
uint8_t hour, uint8_t minute, uint8_t seconds, uint8_t hundredths)
|
||||
{
|
||||
if (bdatetime) {
|
||||
bdatetime->date.year = year;
|
||||
bdatetime->date.month = month;
|
||||
bdatetime->date.day = day;
|
||||
bdatetime->date.wday = day_of_week(year, month, day);
|
||||
bdatetime->time.hour = hour;
|
||||
bdatetime->time.min = minute;
|
||||
bdatetime->time.sec = seconds;
|
||||
bdatetime->time.hundredths = hundredths;
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t seconds_since_midnight(uint8_t hours, uint8_t minutes,
|
||||
uint8_t seconds)
|
||||
{
|
||||
return ((hours * 60 * 60) + (minutes * 60) + seconds);
|
||||
}
|
||||
|
||||
static void seconds_since_midnight_into_hms(uint32_t seconds,
|
||||
uint8_t * pHours, uint8_t * pMinutes, uint8_t * pSeconds)
|
||||
{
|
||||
uint8_t hour = 0;
|
||||
uint8_t minute = 0;
|
||||
|
||||
hour = (uint8_t) (seconds / (60 * 60));
|
||||
seconds -= (hour * 60 * 60);
|
||||
minute = (uint8_t) (seconds / 60);
|
||||
seconds -= (minute * 60);
|
||||
|
||||
if (pHours)
|
||||
*pHours = hour;
|
||||
if (pMinutes)
|
||||
*pMinutes = minute;
|
||||
if (pSeconds)
|
||||
*pSeconds = (uint8_t) seconds;
|
||||
}
|
||||
|
||||
void datetime_add_minutes(BACNET_DATE_TIME * bdatetime, uint32_t minutes)
|
||||
{
|
||||
uint32_t bdatetime_minutes = 0;
|
||||
uint32_t bdatetime_days = 0;
|
||||
uint32_t days = 0;
|
||||
|
||||
/* convert bdatetime to seconds and days */
|
||||
bdatetime_minutes = seconds_since_midnight(bdatetime->time.hour,
|
||||
bdatetime->time.min, bdatetime->time.sec) / 60;
|
||||
bdatetime_days = days_since_epoch(bdatetime->date.year,
|
||||
bdatetime->date.month, bdatetime->date.day);
|
||||
|
||||
/* add */
|
||||
days = minutes / (24 * 60);
|
||||
bdatetime_days += days;
|
||||
minutes -= (days * 24 * 60);
|
||||
bdatetime_minutes += minutes;
|
||||
days = bdatetime_minutes / (24 * 60);
|
||||
bdatetime_days += days;
|
||||
|
||||
/* convert bdatetime from seconds and days */
|
||||
seconds_since_midnight_into_hms(bdatetime_minutes * 60,
|
||||
&bdatetime->time.hour, &bdatetime->time.min, &bdatetime->time.sec);
|
||||
days_since_epoch_into_ymd(bdatetime_days,
|
||||
&bdatetime->date.year,
|
||||
&bdatetime->date.month, &bdatetime->date.day);
|
||||
bdatetime->date.wday = day_of_week(bdatetime->date.year,
|
||||
bdatetime->date.month, bdatetime->date.day);
|
||||
}
|
||||
|
||||
bool datetime_wildcard(BACNET_DATE_TIME * bdatetime)
|
||||
{
|
||||
bool wildcard_present = false;
|
||||
|
||||
if (bdatetime) {
|
||||
if ((bdatetime->date.year == (1900 + 0xFF)) &&
|
||||
(bdatetime->date.month == 0xFF) &&
|
||||
(bdatetime->date.day == 0xFF) &&
|
||||
(bdatetime->date.wday == 0xFF) &&
|
||||
(bdatetime->time.hour == 0xFF) &&
|
||||
(bdatetime->time.min == 0xFF) &&
|
||||
(bdatetime->time.sec == 0xFF) &&
|
||||
(bdatetime->time.hundredths == 0xFF)) {
|
||||
wildcard_present = true;
|
||||
}
|
||||
}
|
||||
|
||||
return wildcard_present;
|
||||
}
|
||||
|
||||
void datetime_wildcard_set(BACNET_DATE_TIME * bdatetime)
|
||||
{
|
||||
if (bdatetime) {
|
||||
bdatetime->date.year = 1900 + 0xFF;
|
||||
bdatetime->date.month = 0xFF;
|
||||
bdatetime->date.day = 0xFF;
|
||||
bdatetime->date.wday = 0xFF;
|
||||
bdatetime->time.hour = 0xFF;
|
||||
bdatetime->time.min = 0xFF;
|
||||
bdatetime->time.sec = 0xFF;
|
||||
bdatetime->time.hundredths = 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef TEST
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include "ctest.h"
|
||||
|
||||
void testBACnetDateTimeWildcard(Test * pTest)
|
||||
{
|
||||
BACNET_DATE_TIME bdatetime;
|
||||
bool status = false;
|
||||
|
||||
datetime_set_values(&bdatetime, 1900, 1, 1, 0, 0, 0, 0);
|
||||
status = datetime_wildcard(&bdatetime);
|
||||
ct_test(pTest, status == false);
|
||||
|
||||
datetime_wildcard_set(&bdatetime);
|
||||
status = datetime_wildcard(&bdatetime);
|
||||
ct_test(pTest, status == true);
|
||||
}
|
||||
|
||||
void testBACnetDateTimeAdd(Test * pTest)
|
||||
{
|
||||
BACNET_DATE_TIME bdatetime, test_bdatetime;
|
||||
uint32_t minutes = 0;
|
||||
int diff = 0;
|
||||
|
||||
datetime_set_values(&bdatetime, 1900, 1, 1, 0, 0, 0, 0);
|
||||
datetime_copy(&test_bdatetime, &bdatetime);
|
||||
datetime_add_minutes(&bdatetime, minutes);
|
||||
diff = datetime_compare(&test_bdatetime, &bdatetime);
|
||||
ct_test(pTest, diff == 0);
|
||||
|
||||
datetime_set_values(&bdatetime, 1900, 1, 1, 0, 0, 0, 0);
|
||||
datetime_add_minutes(&bdatetime, 60);
|
||||
datetime_set_values(&test_bdatetime, 1900, 1, 1, 1, 0, 0, 0);
|
||||
diff = datetime_compare(&test_bdatetime, &bdatetime);
|
||||
ct_test(pTest, diff == 0);
|
||||
|
||||
datetime_set_values(&bdatetime, 1900, 1, 1, 0, 0, 0, 0);
|
||||
datetime_add_minutes(&bdatetime, (24 * 60));
|
||||
datetime_set_values(&test_bdatetime, 1900, 1, 2, 0, 0, 0, 0);
|
||||
diff = datetime_compare(&test_bdatetime, &bdatetime);
|
||||
ct_test(pTest, diff == 0);
|
||||
|
||||
datetime_set_values(&bdatetime, 1900, 1, 1, 0, 0, 0, 0);
|
||||
datetime_add_minutes(&bdatetime, (31 * 24 * 60));
|
||||
datetime_set_values(&test_bdatetime, 1900, 2, 1, 0, 0, 0, 0);
|
||||
diff = datetime_compare(&test_bdatetime, &bdatetime);
|
||||
ct_test(pTest, diff == 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void testBACnetDateTimeSeconds(Test * pTest)
|
||||
{
|
||||
uint8_t hour = 0, minute = 0, second = 0;
|
||||
uint8_t test_hour = 0, test_minute = 0, test_second = 0;
|
||||
uint32_t seconds = 0, test_seconds;
|
||||
|
||||
for (hour = 0; hour < 24; hour++) {
|
||||
for (minute = 0; minute < 60; minute += 3) {
|
||||
for (second = 0; second < 60; second += 17) {
|
||||
seconds = seconds_since_midnight(hour, minute, second);
|
||||
seconds_since_midnight_into_hms(seconds,
|
||||
&test_hour, &test_minute, &test_second);
|
||||
test_seconds =
|
||||
seconds_since_midnight(test_hour, test_minute,
|
||||
test_second);
|
||||
ct_test(pTest, seconds == test_seconds);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void testBACnetDate(Test * pTest)
|
||||
{
|
||||
BACNET_DATE bdate1, bdate2;
|
||||
int diff = 0;
|
||||
|
||||
datetime_set_date(&bdate1, 1900, 1, 1);
|
||||
datetime_copy_date(&bdate2, &bdate1);
|
||||
diff = datetime_compare_date(&bdate1, &bdate2);
|
||||
ct_test(pTest, diff == 0);
|
||||
datetime_set_date(&bdate2, 1900, 1, 2);
|
||||
diff = datetime_compare_date(&bdate1, &bdate2);
|
||||
ct_test(pTest, diff < 0);
|
||||
datetime_set_date(&bdate2, 1900, 2, 1);
|
||||
diff = datetime_compare_date(&bdate1, &bdate2);
|
||||
ct_test(pTest, diff < 0);
|
||||
datetime_set_date(&bdate2, 1901, 1, 1);
|
||||
diff = datetime_compare_date(&bdate1, &bdate2);
|
||||
ct_test(pTest, diff < 0);
|
||||
|
||||
/* midpoint */
|
||||
datetime_set_date(&bdate1, 2007, 7, 15);
|
||||
datetime_copy_date(&bdate2, &bdate1);
|
||||
diff = datetime_compare_date(&bdate1, &bdate2);
|
||||
ct_test(pTest, diff == 0);
|
||||
datetime_set_date(&bdate2, 2007, 7, 14);
|
||||
diff = datetime_compare_date(&bdate1, &bdate2);
|
||||
ct_test(pTest, diff > 0);
|
||||
datetime_set_date(&bdate2, 2007, 7, 1);
|
||||
diff = datetime_compare_date(&bdate1, &bdate2);
|
||||
ct_test(pTest, diff > 0);
|
||||
datetime_set_date(&bdate2, 2007, 7, 31);
|
||||
diff = datetime_compare_date(&bdate1, &bdate2);
|
||||
ct_test(pTest, diff < 0);
|
||||
datetime_set_date(&bdate2, 2007, 8, 15);
|
||||
diff = datetime_compare_date(&bdate1, &bdate2);
|
||||
ct_test(pTest, diff < 0);
|
||||
datetime_set_date(&bdate2, 2007, 12, 15);
|
||||
diff = datetime_compare_date(&bdate1, &bdate2);
|
||||
ct_test(pTest, diff < 0);
|
||||
datetime_set_date(&bdate2, 2007, 6, 15);
|
||||
diff = datetime_compare_date(&bdate1, &bdate2);
|
||||
ct_test(pTest, diff > 0);
|
||||
datetime_set_date(&bdate2, 2007, 1, 15);
|
||||
diff = datetime_compare_date(&bdate1, &bdate2);
|
||||
ct_test(pTest, diff > 0);
|
||||
datetime_set_date(&bdate2, 2006, 7, 15);
|
||||
diff = datetime_compare_date(&bdate1, &bdate2);
|
||||
ct_test(pTest, diff > 0);
|
||||
datetime_set_date(&bdate2, 1900, 7, 15);
|
||||
diff = datetime_compare_date(&bdate1, &bdate2);
|
||||
ct_test(pTest, diff > 0);
|
||||
datetime_set_date(&bdate2, 2008, 7, 15);
|
||||
diff = datetime_compare_date(&bdate1, &bdate2);
|
||||
ct_test(pTest, diff < 0);
|
||||
datetime_set_date(&bdate2, 2154, 7, 15);
|
||||
diff = datetime_compare_date(&bdate1, &bdate2);
|
||||
ct_test(pTest, diff < 0);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void testBACnetTime(Test * pTest)
|
||||
{
|
||||
BACNET_TIME btime1, btime2;
|
||||
int diff = 0;
|
||||
|
||||
datetime_set_time(&btime1, 0, 0, 0, 0);
|
||||
datetime_copy_time(&btime2, &btime1);
|
||||
diff = datetime_compare_time(&btime1, &btime2);
|
||||
ct_test(pTest, diff == 0);
|
||||
|
||||
datetime_set_time(&btime1, 23, 59, 59, 99);
|
||||
datetime_copy_time(&btime2, &btime1);
|
||||
diff = datetime_compare_time(&btime1, &btime2);
|
||||
ct_test(pTest, diff == 0);
|
||||
|
||||
/* midpoint */
|
||||
datetime_set_time(&btime1, 12, 30, 30, 50);
|
||||
datetime_copy_time(&btime2, &btime1);
|
||||
diff = datetime_compare_time(&btime1, &btime2);
|
||||
ct_test(pTest, diff == 0);
|
||||
datetime_set_time(&btime2, 12, 30, 30, 51);
|
||||
diff = datetime_compare_time(&btime1, &btime2);
|
||||
ct_test(pTest, diff < 0);
|
||||
datetime_set_time(&btime2, 12, 30, 31, 50);
|
||||
diff = datetime_compare_time(&btime1, &btime2);
|
||||
ct_test(pTest, diff < 0);
|
||||
datetime_set_time(&btime2, 12, 31, 30, 50);
|
||||
diff = datetime_compare_time(&btime1, &btime2);
|
||||
ct_test(pTest, diff < 0);
|
||||
datetime_set_time(&btime2, 13, 30, 30, 50);
|
||||
diff = datetime_compare_time(&btime1, &btime2);
|
||||
ct_test(pTest, diff < 0);
|
||||
|
||||
datetime_set_time(&btime2, 12, 30, 30, 49);
|
||||
diff = datetime_compare_time(&btime1, &btime2);
|
||||
ct_test(pTest, diff > 0);
|
||||
datetime_set_time(&btime2, 12, 30, 29, 50);
|
||||
diff = datetime_compare_time(&btime1, &btime2);
|
||||
ct_test(pTest, diff > 0);
|
||||
datetime_set_time(&btime2, 12, 29, 30, 50);
|
||||
diff = datetime_compare_time(&btime1, &btime2);
|
||||
ct_test(pTest, diff > 0);
|
||||
datetime_set_time(&btime2, 11, 30, 30, 50);
|
||||
diff = datetime_compare_time(&btime1, &btime2);
|
||||
ct_test(pTest, diff > 0);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void testBACnetDateTime(Test * pTest)
|
||||
{
|
||||
BACNET_DATE_TIME bdatetime1, bdatetime2;
|
||||
BACNET_DATE bdate;
|
||||
BACNET_TIME btime;
|
||||
int diff = 0;
|
||||
|
||||
datetime_set_values(&bdatetime1, 1900, 1, 1, 0, 0, 0, 0);
|
||||
datetime_copy(&bdatetime2, &bdatetime1);
|
||||
diff = datetime_compare(&bdatetime1, &bdatetime2);
|
||||
ct_test(pTest, diff == 0);
|
||||
datetime_set_time(&btime, 0, 0, 0, 0);
|
||||
datetime_set_date(&bdate, 1900, 1, 1);
|
||||
datetime_set(&bdatetime1, &bdate, &btime);
|
||||
diff = datetime_compare(&bdatetime1, &bdatetime2);
|
||||
ct_test(pTest, diff == 0);
|
||||
|
||||
/* midpoint */
|
||||
/* if datetime1 is before datetime2, returns negative */
|
||||
datetime_set_values(&bdatetime1, 2000, 7, 15, 12, 30, 30, 50);
|
||||
datetime_set_values(&bdatetime2, 2000, 7, 15, 12, 30, 30, 51);
|
||||
diff = datetime_compare(&bdatetime1, &bdatetime2);
|
||||
ct_test(pTest, diff < 0);
|
||||
datetime_set_values(&bdatetime2, 2000, 7, 15, 12, 30, 31, 50);
|
||||
diff = datetime_compare(&bdatetime1, &bdatetime2);
|
||||
ct_test(pTest, diff < 0);
|
||||
datetime_set_values(&bdatetime2, 2000, 7, 15, 12, 31, 30, 50);
|
||||
diff = datetime_compare(&bdatetime1, &bdatetime2);
|
||||
ct_test(pTest, diff < 0);
|
||||
datetime_set_values(&bdatetime2, 2000, 7, 15, 13, 30, 30, 50);
|
||||
diff = datetime_compare(&bdatetime1, &bdatetime2);
|
||||
ct_test(pTest, diff < 0);
|
||||
datetime_set_values(&bdatetime2, 2000, 7, 16, 12, 30, 30, 50);
|
||||
diff = datetime_compare(&bdatetime1, &bdatetime2);
|
||||
ct_test(pTest, diff < 0);
|
||||
datetime_set_values(&bdatetime2, 2000, 8, 15, 12, 30, 30, 50);
|
||||
diff = datetime_compare(&bdatetime1, &bdatetime2);
|
||||
ct_test(pTest, diff < 0);
|
||||
datetime_set_values(&bdatetime2, 2001, 7, 15, 12, 30, 30, 50);
|
||||
diff = datetime_compare(&bdatetime1, &bdatetime2);
|
||||
ct_test(pTest, diff < 0);
|
||||
datetime_set_values(&bdatetime2, 2000, 7, 15, 12, 30, 30, 49);
|
||||
diff = datetime_compare(&bdatetime1, &bdatetime2);
|
||||
ct_test(pTest, diff > 0);
|
||||
datetime_set_values(&bdatetime2, 2000, 7, 15, 12, 30, 29, 50);
|
||||
diff = datetime_compare(&bdatetime1, &bdatetime2);
|
||||
ct_test(pTest, diff > 0);
|
||||
datetime_set_values(&bdatetime2, 2000, 7, 15, 12, 29, 30, 50);
|
||||
diff = datetime_compare(&bdatetime1, &bdatetime2);
|
||||
ct_test(pTest, diff > 0);
|
||||
datetime_set_values(&bdatetime2, 2000, 7, 15, 11, 30, 30, 50);
|
||||
diff = datetime_compare(&bdatetime1, &bdatetime2);
|
||||
ct_test(pTest, diff > 0);
|
||||
datetime_set_values(&bdatetime2, 2000, 7, 14, 12, 30, 30, 50);
|
||||
diff = datetime_compare(&bdatetime1, &bdatetime2);
|
||||
ct_test(pTest, diff > 0);
|
||||
datetime_set_values(&bdatetime2, 2000, 6, 15, 12, 30, 30, 50);
|
||||
diff = datetime_compare(&bdatetime1, &bdatetime2);
|
||||
ct_test(pTest, diff > 0);
|
||||
datetime_set_values(&bdatetime2, 1999, 7, 15, 12, 30, 30, 50);
|
||||
diff = datetime_compare(&bdatetime1, &bdatetime2);
|
||||
ct_test(pTest, diff > 0);
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void testDateEpoch(Test * pTest)
|
||||
{
|
||||
uint32_t days = 0;
|
||||
uint16_t year = 0, test_year = 0;
|
||||
uint8_t month = 0, test_month = 0;
|
||||
uint8_t day = 0, test_day = 0;
|
||||
|
||||
days = days_since_epoch(1900, 1, 1);
|
||||
ct_test(pTest, days == 0);
|
||||
days_since_epoch_into_ymd(days, &year, &month, &day);
|
||||
ct_test(pTest, year == 1900);
|
||||
ct_test(pTest, month == 1);
|
||||
ct_test(pTest, day == 1);
|
||||
|
||||
|
||||
for (year = 1900; year <= 2154; year++) {
|
||||
for (month = 1; month <= 12; month++) {
|
||||
for (day = 1; day <= month_days(year, month); day++) {
|
||||
days = days_since_epoch(year, month, day);
|
||||
days_since_epoch_into_ymd(days,
|
||||
&test_year, &test_month, &test_day);
|
||||
ct_test(pTest, year == test_year);
|
||||
ct_test(pTest, month == test_month);
|
||||
ct_test(pTest, day == test_day);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void testBACnetDayOfWeek(Test * pTest)
|
||||
{
|
||||
uint8_t dow = 0;
|
||||
|
||||
/* 1/1/1900 is a Monday */
|
||||
dow = day_of_week(1900, 1, 1);
|
||||
ct_test(pTest, dow == 1);
|
||||
|
||||
/* 1/1/2007 is a Monday */
|
||||
dow = day_of_week(2007, 1, 1);
|
||||
ct_test(pTest, dow == 1);
|
||||
dow = day_of_week(2007, 1, 2);
|
||||
ct_test(pTest, dow == 2);
|
||||
dow = day_of_week(2007, 1, 3);
|
||||
ct_test(pTest, dow == 3);
|
||||
dow = day_of_week(2007, 1, 4);
|
||||
ct_test(pTest, dow == 4);
|
||||
dow = day_of_week(2007, 1, 5);
|
||||
ct_test(pTest, dow == 5);
|
||||
dow = day_of_week(2007, 1, 6);
|
||||
ct_test(pTest, dow == 6);
|
||||
dow = day_of_week(2007, 1, 7);
|
||||
ct_test(pTest, dow == 7);
|
||||
|
||||
dow = day_of_week(2007, 1, 31);
|
||||
ct_test(pTest, dow == 3);
|
||||
}
|
||||
|
||||
#ifdef TEST_DATE_TIME
|
||||
int main(void)
|
||||
{
|
||||
Test *pTest;
|
||||
bool rc;
|
||||
|
||||
pTest = ct_create("BACnet Date Time", NULL);
|
||||
/* individual tests */
|
||||
rc = ct_addTestFunction(pTest, testBACnetDate);
|
||||
assert(rc);
|
||||
rc = ct_addTestFunction(pTest, testBACnetTime);
|
||||
assert(rc);
|
||||
rc = ct_addTestFunction(pTest, testBACnetDateTime);
|
||||
assert(rc);
|
||||
rc = ct_addTestFunction(pTest, testBACnetDayOfWeek);
|
||||
assert(rc);
|
||||
rc = ct_addTestFunction(pTest, testDateEpoch);
|
||||
assert(rc);
|
||||
rc = ct_addTestFunction(pTest, testBACnetDateTimeSeconds);
|
||||
assert(rc);
|
||||
rc = ct_addTestFunction(pTest, testBACnetDateTimeAdd);
|
||||
assert(rc);
|
||||
rc = ct_addTestFunction(pTest, testBACnetDateTimeWildcard);
|
||||
assert(rc);
|
||||
|
||||
ct_setStream(pTest, stdout);
|
||||
ct_run(pTest);
|
||||
(void) ct_report(pTest);
|
||||
ct_destroy(pTest);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* TEST_DATE_TIME */
|
||||
#endif /* TEST */
|
||||
@@ -1,112 +0,0 @@
|
||||
/*####COPYRIGHTBEGIN####
|
||||
-------------------------------------------
|
||||
Copyright (C) 2007 Steve Karg <skarg@users.sourceforge.net>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to:
|
||||
The Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330
|
||||
Boston, MA 02111-1307, USA.
|
||||
|
||||
As a special exception, if other files instantiate templates or
|
||||
use macros or inline functions from this file, or you compile
|
||||
this file and link it with other works to produce a work based
|
||||
on this file, this file does not by itself cause the resulting
|
||||
work to be covered by the GNU General Public License. However
|
||||
the source code for this file must still be made available in
|
||||
accordance with section (3) of the GNU General Public License.
|
||||
|
||||
This exception does not invalidate any other reasons why a work
|
||||
based on this file might be covered by the GNU General Public
|
||||
License.
|
||||
-------------------------------------------
|
||||
####COPYRIGHTEND####*/
|
||||
#ifndef DATE_TIME_H
|
||||
#define DATE_TIME_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef enum {
|
||||
BACNET_WEEKDAY_MONDAY = 1,
|
||||
BACNET_WEEKDAY_TUESDAY = 2,
|
||||
BACNET_WEEKDAY_WEDNESDAY = 3,
|
||||
BACNET_WEEKDAY_THURSDAY = 4,
|
||||
BACNET_WEEKDAY_FRIDAY = 5,
|
||||
BACNET_WEEKDAY_SATURDAY = 6,
|
||||
BACNET_WEEKDAY_SUNDAY = 7
|
||||
} BACNET_WEEKDAY;
|
||||
|
||||
/* date */
|
||||
typedef struct BACnet_Date {
|
||||
uint16_t year; /* AD */
|
||||
uint8_t month; /* 1=Jan */
|
||||
uint8_t day; /* 1..31 */
|
||||
uint8_t wday; /* 1=Monday-7=Sunday */
|
||||
} BACNET_DATE;
|
||||
|
||||
/* time */
|
||||
typedef struct BACnet_Time {
|
||||
uint8_t hour;
|
||||
uint8_t min;
|
||||
uint8_t sec;
|
||||
uint8_t hundredths;
|
||||
} BACNET_TIME;
|
||||
|
||||
typedef struct BACnet_DateTime {
|
||||
BACNET_DATE date;
|
||||
BACNET_TIME time;
|
||||
} BACNET_DATE_TIME;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/* utility initialization functions */
|
||||
void datetime_set_date(BACNET_DATE * bdate,
|
||||
uint16_t year, uint8_t month, uint8_t day);
|
||||
void datetime_set_time(BACNET_TIME * btime,
|
||||
uint8_t hour, uint8_t minute, uint8_t seconds, uint8_t hundredths);
|
||||
void datetime_set(BACNET_DATE_TIME * bdatetime,
|
||||
BACNET_DATE * bdate, BACNET_TIME * btime);
|
||||
void datetime_set_values(BACNET_DATE_TIME * bdatetime,
|
||||
uint16_t year, uint8_t month, uint8_t day,
|
||||
uint8_t hour, uint8_t minute, uint8_t seconds, uint8_t hundredths);
|
||||
|
||||
/* utility comparison functions:
|
||||
if the date/times are the same, return is 0
|
||||
if date1 is before date2, returns negative
|
||||
if date1 is after date2, returns positive */
|
||||
int datetime_compare_date(BACNET_DATE * date1, BACNET_DATE * date2);
|
||||
int datetime_compare_time(BACNET_TIME * time1, BACNET_TIME * time2);
|
||||
int datetime_compare(BACNET_DATE_TIME * datetime1,
|
||||
BACNET_DATE_TIME * datetime2);
|
||||
|
||||
/* utility copy functions */
|
||||
void datetime_copy_date(BACNET_DATE * date1, BACNET_DATE * date2);
|
||||
void datetime_copy_time(BACNET_TIME * time1, BACNET_TIME * time2);
|
||||
void datetime_copy(BACNET_DATE_TIME * datetime1,
|
||||
BACNET_DATE_TIME * datetime2);
|
||||
|
||||
/* utility add function */
|
||||
void datetime_add_minutes(BACNET_DATE_TIME * bdatetime,
|
||||
uint32_t minutes);
|
||||
|
||||
/* date and time wildcards */
|
||||
bool datetime_wildcard(BACNET_DATE_TIME * bdatetime);
|
||||
void datetime_wildcard_set(BACNET_DATE_TIME * bdatetime);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif /* DATE_TIME_H */
|
||||
Binary file not shown.
@@ -1,31 +0,0 @@
|
||||
#Makefile to build test case
|
||||
CC = gcc
|
||||
BASEDIR = .
|
||||
#CFLAGS = -Wall -I.
|
||||
# -g for debugging with gdb
|
||||
#CFLAGS = -Wall -I. -g
|
||||
CFLAGS = -Wall -I. -Itest -DTEST -DTEST_DATE_TIME -g
|
||||
|
||||
SRCS = datetime.c \
|
||||
test/ctest.c
|
||||
|
||||
OBJS = ${SRCS:.c=.o}
|
||||
|
||||
TARGET = datetime
|
||||
|
||||
all: ${TARGET}
|
||||
|
||||
${TARGET}: ${OBJS}
|
||||
${CC} -o $@ ${OBJS}
|
||||
|
||||
.c.o:
|
||||
${CC} -c ${CFLAGS} $*.c -o $@
|
||||
|
||||
depend:
|
||||
rm -f .depend
|
||||
${CC} -MM ${CFLAGS} *.c >> .depend
|
||||
|
||||
clean:
|
||||
rm -rf core ${TARGET} $(OBJS) *.bak *.1 *.ini
|
||||
|
||||
include: .depend
|
||||
@@ -1,308 +0,0 @@
|
||||
/*####COPYRIGHTBEGIN####
|
||||
-------------------------------------------
|
||||
Copyright (C) 2006 Steve Karg
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to:
|
||||
The Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330
|
||||
Boston, MA 02111-1307, USA.
|
||||
|
||||
As a special exception, if other files instantiate templates or
|
||||
use macros or inline functions from this file, or you compile
|
||||
this file and link it with other works to produce a work based
|
||||
on this file, this file does not by itself cause the resulting
|
||||
work to be covered by the GNU General Public License. However
|
||||
the source code for this file must still be made available in
|
||||
accordance with section (3) of the GNU General Public License.
|
||||
|
||||
This exception does not invalidate any other reasons why a work
|
||||
based on this file might be covered by the GNU General Public
|
||||
License.
|
||||
-------------------------------------------
|
||||
####COPYRIGHTEND####*/
|
||||
#include <stdint.h>
|
||||
#include "bacenum.h"
|
||||
#include "bacdcode.h"
|
||||
#include "bacdef.h"
|
||||
#include "dcc.h"
|
||||
|
||||
/* note: the disable and time are not expected to survive
|
||||
over a power cycle or reinitialization. */
|
||||
/* note: time duration is given in Minutes, but in order to be accurate,
|
||||
we need to count down in seconds. */
|
||||
static uint32_t DCC_Time_Duration_Seconds = 0;
|
||||
static BACNET_COMMUNICATION_ENABLE_DISABLE DCC_Enable_Disable =
|
||||
COMMUNICATION_ENABLE;
|
||||
/* password is optionally supported */
|
||||
|
||||
BACNET_COMMUNICATION_ENABLE_DISABLE dcc_enable_status(void)
|
||||
{
|
||||
return DCC_Enable_Disable;
|
||||
}
|
||||
|
||||
bool dcc_communication_enabled(void)
|
||||
{
|
||||
return (DCC_Enable_Disable == COMMUNICATION_ENABLE);
|
||||
}
|
||||
|
||||
/* When network communications are completely disabled,
|
||||
only DeviceCommunicationControl and ReinitializeDevice APDUs
|
||||
shall be processed and no messages shall be initiated.*/
|
||||
bool dcc_communication_disabled(void)
|
||||
{
|
||||
return (DCC_Enable_Disable == COMMUNICATION_DISABLE);
|
||||
}
|
||||
|
||||
/* When the initiation of communications is disabled,
|
||||
all APDUs shall be processed and responses returned as
|
||||
required and no messages shall be initiated with the
|
||||
exception of I-Am requests, which shall be initiated only in
|
||||
response to Who-Is messages. In this state, a device that
|
||||
supports I-Am request initiation shall send one I-Am request
|
||||
for any Who-Is request that is received if and only if
|
||||
the Who-Is request does not contain an address range or
|
||||
the device is included in the address range. */
|
||||
bool dcc_communication_initiation_disabled(void)
|
||||
{
|
||||
return (DCC_Enable_Disable == COMMUNICATION_DISABLE_INITIATION);
|
||||
}
|
||||
|
||||
uint32_t dcc_duration_seconds(void)
|
||||
{
|
||||
return DCC_Time_Duration_Seconds;
|
||||
}
|
||||
|
||||
/* called every second or so. If more than one second,
|
||||
then seconds should be the number of seconds to tick away */
|
||||
void dcc_timer_seconds(uint32_t seconds)
|
||||
{
|
||||
if (DCC_Time_Duration_Seconds) {
|
||||
if (DCC_Time_Duration_Seconds > seconds)
|
||||
DCC_Time_Duration_Seconds -= seconds;
|
||||
else
|
||||
DCC_Time_Duration_Seconds = 0;
|
||||
/* just expired - do something */
|
||||
if (DCC_Time_Duration_Seconds == 0)
|
||||
DCC_Enable_Disable = COMMUNICATION_ENABLE;
|
||||
}
|
||||
}
|
||||
|
||||
bool dcc_set_status_duration(BACNET_COMMUNICATION_ENABLE_DISABLE status,
|
||||
uint16_t minutes)
|
||||
{
|
||||
bool valid = false;
|
||||
|
||||
/* valid? */
|
||||
if (status < MAX_BACNET_COMMUNICATION_ENABLE_DISABLE) {
|
||||
DCC_Enable_Disable = status;
|
||||
if (status == COMMUNICATION_ENABLE)
|
||||
DCC_Time_Duration_Seconds = 0;
|
||||
else
|
||||
DCC_Time_Duration_Seconds = minutes * 60;
|
||||
valid = true;
|
||||
}
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
||||
/* encode service */
|
||||
int dcc_encode_apdu(uint8_t * apdu, uint8_t invoke_id, uint16_t timeDuration, /* 0=optional */
|
||||
BACNET_COMMUNICATION_ENABLE_DISABLE enable_disable,
|
||||
BACNET_CHARACTER_STRING * password)
|
||||
{ /* NULL=optional */
|
||||
int len = 0; /* length of each encoding */
|
||||
int apdu_len = 0; /* total length of the apdu, return value */
|
||||
|
||||
if (apdu) {
|
||||
apdu[0] = PDU_TYPE_CONFIRMED_SERVICE_REQUEST;
|
||||
apdu[1] = encode_max_segs_max_apdu(0, MAX_APDU);
|
||||
apdu[2] = invoke_id;
|
||||
apdu[3] = SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL;
|
||||
apdu_len = 4;
|
||||
/* optional timeDuration */
|
||||
if (timeDuration) {
|
||||
len =
|
||||
encode_context_unsigned(&apdu[apdu_len], 0, timeDuration);
|
||||
apdu_len += len;
|
||||
}
|
||||
/* enable disable */
|
||||
len =
|
||||
encode_context_enumerated(&apdu[apdu_len], 1, enable_disable);
|
||||
apdu_len += len;
|
||||
/* optional password */
|
||||
if (password) {
|
||||
/* FIXME: must be at least 1 character, limited to 20 characters */
|
||||
len =
|
||||
encode_context_character_string(&apdu[apdu_len], 2,
|
||||
password);
|
||||
apdu_len += len;
|
||||
}
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
/* decode the service request only */
|
||||
int dcc_decode_service_request(uint8_t * apdu,
|
||||
unsigned apdu_len,
|
||||
uint16_t * timeDuration,
|
||||
BACNET_COMMUNICATION_ENABLE_DISABLE * enable_disable,
|
||||
BACNET_CHARACTER_STRING * password)
|
||||
{
|
||||
unsigned len = 0;
|
||||
uint8_t tag_number = 0;
|
||||
uint32_t len_value_type = 0;
|
||||
int value = 0;
|
||||
uint32_t value32 = 0;
|
||||
|
||||
/* check for value pointers */
|
||||
if (apdu_len) {
|
||||
/* Tag 0: timeDuration --optional-- */
|
||||
if (decode_is_context_tag(&apdu[len], 0)) {
|
||||
len += decode_tag_number_and_value(&apdu[len], &tag_number,
|
||||
&len_value_type);
|
||||
len += decode_unsigned(&apdu[len], len_value_type, &value32);
|
||||
if (timeDuration)
|
||||
*timeDuration = (uint16_t) value32;
|
||||
} else if (timeDuration)
|
||||
*timeDuration = 0;
|
||||
/* Tag 1: enable_disable */
|
||||
if (!decode_is_context_tag(&apdu[len], 1))
|
||||
return -1;
|
||||
len += decode_tag_number_and_value(&apdu[len],
|
||||
&tag_number, &len_value_type);
|
||||
len += decode_enumerated(&apdu[len], len_value_type, &value);
|
||||
if (enable_disable)
|
||||
*enable_disable = value;
|
||||
/* Tag 2: password --optional-- */
|
||||
if (len < apdu_len) {
|
||||
if (!decode_is_context_tag(&apdu[len], 2))
|
||||
return -1;
|
||||
len += decode_tag_number_and_value(&apdu[len],
|
||||
&tag_number, &len_value_type);
|
||||
len +=
|
||||
decode_character_string(&apdu[len], len_value_type,
|
||||
password);
|
||||
} else if (password)
|
||||
characterstring_init_ansi(password, NULL);
|
||||
}
|
||||
|
||||
return (int) len;
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include "ctest.h"
|
||||
|
||||
int dcc_decode_apdu(uint8_t * apdu,
|
||||
unsigned apdu_len,
|
||||
uint8_t * invoke_id,
|
||||
uint16_t * timeDuration,
|
||||
BACNET_COMMUNICATION_ENABLE_DISABLE * enable_disable,
|
||||
BACNET_CHARACTER_STRING * password)
|
||||
{
|
||||
int len = 0;
|
||||
unsigned offset = 0;
|
||||
|
||||
if (!apdu)
|
||||
return -1;
|
||||
/* optional checking - most likely was already done prior to this call */
|
||||
if (apdu[0] != PDU_TYPE_CONFIRMED_SERVICE_REQUEST)
|
||||
return -1;
|
||||
/* apdu[1] = encode_max_segs_max_apdu(0, Device_Max_APDU_Length_Accepted()); */
|
||||
*invoke_id = apdu[2]; /* invoke id - filled in by net layer */
|
||||
if (apdu[3] != SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL)
|
||||
return -1;
|
||||
offset = 4;
|
||||
|
||||
if (apdu_len > offset) {
|
||||
len = dcc_decode_service_request(&apdu[offset],
|
||||
apdu_len - offset, timeDuration, enable_disable, password);
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
void test_DeviceCommunicationControlData(Test * pTest,
|
||||
uint8_t invoke_id,
|
||||
uint16_t timeDuration,
|
||||
BACNET_COMMUNICATION_ENABLE_DISABLE enable_disable,
|
||||
BACNET_CHARACTER_STRING * password)
|
||||
{
|
||||
uint8_t apdu[480] = { 0 };
|
||||
int len = 0;
|
||||
int apdu_len = 0;
|
||||
uint8_t test_invoke_id = 0;
|
||||
uint16_t test_timeDuration = 0;
|
||||
BACNET_COMMUNICATION_ENABLE_DISABLE test_enable_disable;
|
||||
BACNET_CHARACTER_STRING test_password;
|
||||
|
||||
len = dcc_encode_apdu(&apdu[0],
|
||||
invoke_id, timeDuration, enable_disable, password);
|
||||
ct_test(pTest, len != 0);
|
||||
apdu_len = len;
|
||||
|
||||
len = dcc_decode_apdu(&apdu[0],
|
||||
apdu_len,
|
||||
&test_invoke_id,
|
||||
&test_timeDuration, &test_enable_disable, &test_password);
|
||||
ct_test(pTest, len != -1);
|
||||
ct_test(pTest, test_invoke_id == invoke_id);
|
||||
ct_test(pTest, test_timeDuration == timeDuration);
|
||||
ct_test(pTest, test_enable_disable == enable_disable);
|
||||
ct_test(pTest, characterstring_same(&test_password, password));
|
||||
}
|
||||
|
||||
void test_DeviceCommunicationControl(Test * pTest)
|
||||
{
|
||||
uint8_t invoke_id = 128;
|
||||
uint16_t timeDuration = 0;
|
||||
BACNET_COMMUNICATION_ENABLE_DISABLE enable_disable;
|
||||
BACNET_CHARACTER_STRING password;
|
||||
|
||||
timeDuration = 0;
|
||||
enable_disable = COMMUNICATION_DISABLE_INITIATION;
|
||||
characterstring_init_ansi(&password, "John 3:16");
|
||||
test_DeviceCommunicationControlData(pTest,
|
||||
invoke_id, timeDuration, enable_disable, &password);
|
||||
|
||||
timeDuration = 12345;
|
||||
enable_disable = COMMUNICATION_DISABLE;
|
||||
test_DeviceCommunicationControlData(pTest,
|
||||
invoke_id, timeDuration, enable_disable, NULL);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef TEST_DEVICE_COMMUNICATION_CONTROL
|
||||
int main(void)
|
||||
{
|
||||
Test *pTest;
|
||||
bool rc;
|
||||
|
||||
pTest = ct_create("BACnet DeviceCommunicationControl", NULL);
|
||||
/* individual tests */
|
||||
rc = ct_addTestFunction(pTest, test_DeviceCommunicationControl);
|
||||
assert(rc);
|
||||
|
||||
ct_setStream(pTest, stdout);
|
||||
ct_run(pTest);
|
||||
(void) ct_report(pTest);
|
||||
ct_destroy(pTest);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* TEST_DEVICE_COMMUNICATION_CONTROL */
|
||||
#endif /* TEST */
|
||||
@@ -1,86 +0,0 @@
|
||||
/*####COPYRIGHTBEGIN####
|
||||
-------------------------------------------
|
||||
Copyright (C) 2006 Steve Karg
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to:
|
||||
The Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330
|
||||
Boston, MA 02111-1307, USA.
|
||||
|
||||
As a special exception, if other files instantiate templates or
|
||||
use macros or inline functions from this file, or you compile
|
||||
this file and link it with other works to produce a work based
|
||||
on this file, this file does not by itself cause the resulting
|
||||
work to be covered by the GNU General Public License. However
|
||||
the source code for this file must still be made available in
|
||||
accordance with section (3) of the GNU General Public License.
|
||||
|
||||
This exception does not invalidate any other reasons why a work
|
||||
based on this file might be covered by the GNU General Public
|
||||
License.
|
||||
-------------------------------------------
|
||||
####COPYRIGHTEND####*/
|
||||
#ifndef DCC_H
|
||||
#define DCC_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "bacenum.h"
|
||||
#include "bacstr.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/* return the status */
|
||||
BACNET_COMMUNICATION_ENABLE_DISABLE dcc_enable_status(void);
|
||||
bool dcc_communication_enabled(void);
|
||||
bool dcc_communication_disabled(void);
|
||||
bool dcc_communication_initiation_disabled(void);
|
||||
/* return the time */
|
||||
uint32_t dcc_duration_seconds(void);
|
||||
/* called every second or so. If more than one second,
|
||||
then seconds should be the number of seconds to tick away */
|
||||
void dcc_timer_seconds(uint32_t seconds);
|
||||
/* setup the communication values */
|
||||
bool dcc_set_status_duration(BACNET_COMMUNICATION_ENABLE_DISABLE
|
||||
status, uint16_t minutes);
|
||||
|
||||
/* encode service */
|
||||
int dcc_encode_apdu(uint8_t * apdu, uint8_t invoke_id, uint16_t timeDuration, /* 0=optional */
|
||||
BACNET_COMMUNICATION_ENABLE_DISABLE enable_disable, BACNET_CHARACTER_STRING * password); /* NULL=optional */
|
||||
|
||||
/* decode the service request only */
|
||||
int dcc_decode_service_request(uint8_t * apdu,
|
||||
unsigned apdu_len,
|
||||
uint16_t * timeDuration,
|
||||
BACNET_COMMUNICATION_ENABLE_DISABLE * enable_disable,
|
||||
BACNET_CHARACTER_STRING * password);
|
||||
|
||||
#ifdef TEST
|
||||
#include "ctest.h"
|
||||
int dcc_decode_apdu(uint8_t * apdu,
|
||||
unsigned apdu_len,
|
||||
uint8_t * invoke_id,
|
||||
uint16_t * timeDuration,
|
||||
BACNET_COMMUNICATION_ENABLE_DISABLE * enable_disable,
|
||||
BACNET_CHARACTER_STRING * password);
|
||||
|
||||
void test_DeviceCommunicationControl(Test * pTest);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
@@ -1,34 +0,0 @@
|
||||
#Makefile to build test case
|
||||
CC = gcc
|
||||
BASEDIR = .
|
||||
#CFLAGS = -Wall -I.
|
||||
# -g for debugging with gdb
|
||||
#CFLAGS = -Wall -I. -g
|
||||
CFLAGS = -Wall -I. -Itest -DTEST -DTEST_DEVICE_COMMUNICATION_CONTROL -g
|
||||
|
||||
SRCS = bacdcode.c \
|
||||
bacstr.c \
|
||||
bigend.c \
|
||||
dcc.c \
|
||||
test/ctest.c
|
||||
|
||||
OBJS = ${SRCS:.c=.o}
|
||||
|
||||
TARGET = dcc
|
||||
|
||||
all: ${TARGET}
|
||||
|
||||
${TARGET}: ${OBJS}
|
||||
${CC} -o $@ ${OBJS}
|
||||
|
||||
.c.o:
|
||||
${CC} -c ${CFLAGS} $*.c -o $@
|
||||
|
||||
depend:
|
||||
rm -f .depend
|
||||
${CC} -MM ${CFLAGS} *.c >> .depend
|
||||
|
||||
clean:
|
||||
rm -rf core ${TARGET} $(OBJS) *.bak *.1 *.ini
|
||||
|
||||
include: .depend
|
||||
@@ -1,86 +0,0 @@
|
||||
#Makefile to build BACnet Application for the Linux Port
|
||||
CC = gcc
|
||||
BASEDIR = .
|
||||
#CFLAGS = -Wall -I.
|
||||
# -g for debugging with gdb
|
||||
#CFLAGS = -Wall -I. -O2 -g
|
||||
# Note: you can strip out symbols using the strip command
|
||||
# to get an idea of how big the compile really is.
|
||||
#DEFINES = -DBACFILE=1 -DBACDL_ETHERNET=1
|
||||
#DEFINES = -DBACFILE=1 -DBACDL_ARCNET=1
|
||||
#DEFINES = -DBACFILE=1 -DBACDL_MSTP=1
|
||||
DEFINES = -DBACFILE=1 -DTSM_ENABLED=1 -DBACDL_BIP=1 -DBIG_ENDIAN=0 -DPRINT_ENABLED=1
|
||||
BACNET_PORT = ../../ports/linux
|
||||
BACNET_OBJECT = ../object
|
||||
BACNET_HANDLER = ../handler
|
||||
BACNET_ROOT = ../..
|
||||
INCLUDES = -I$(BACNET_ROOT) -I$(BACNET_PORT) -I$(BACNET_OBJECT) -I$(BACNET_HANDLER)
|
||||
|
||||
CFLAGS = -Wall -g $(INCLUDES) $(DEFINES)
|
||||
|
||||
TARGET = bacdcc
|
||||
|
||||
SRCS = main.c \
|
||||
$(BACNET_ROOT)/dcc.c \
|
||||
$(BACNET_PORT)/bip-init.c \
|
||||
$(BACNET_ROOT)/bip.c \
|
||||
$(BACNET_HANDLER)/txbuf.c \
|
||||
$(BACNET_HANDLER)/noserv.c \
|
||||
$(BACNET_HANDLER)/h_whois.c \
|
||||
$(BACNET_HANDLER)/h_rp.c \
|
||||
$(BACNET_HANDLER)/h_iam.c \
|
||||
$(BACNET_HANDLER)/h_dcc.c \
|
||||
$(BACNET_HANDLER)/s_whois.c \
|
||||
$(BACNET_HANDLER)/s_dcc.c \
|
||||
$(BACNET_OBJECT)/device.c \
|
||||
$(BACNET_OBJECT)/ai.c \
|
||||
$(BACNET_OBJECT)/ao.c \
|
||||
$(BACNET_OBJECT)/av.c \
|
||||
$(BACNET_OBJECT)/bi.c \
|
||||
$(BACNET_OBJECT)/bo.c \
|
||||
$(BACNET_OBJECT)/bv.c \
|
||||
$(BACNET_OBJECT)/lc.c \
|
||||
$(BACNET_OBJECT)/lsp.c \
|
||||
$(BACNET_OBJECT)/mso.c \
|
||||
$(BACNET_OBJECT)/bacfile.c \
|
||||
$(BACNET_ROOT)/filename.c \
|
||||
$(BACNET_ROOT)/rp.c \
|
||||
$(BACNET_ROOT)/wp.c \
|
||||
$(BACNET_ROOT)/bacdcode.c \
|
||||
$(BACNET_ROOT)/bacapp.c \
|
||||
$(BACNET_ROOT)/bacprop.c \
|
||||
$(BACNET_ROOT)/bacstr.c \
|
||||
$(BACNET_ROOT)/bactext.c \
|
||||
$(BACNET_ROOT)/datetime.c \
|
||||
$(BACNET_ROOT)/indtext.c \
|
||||
$(BACNET_ROOT)/bigend.c \
|
||||
$(BACNET_ROOT)/whois.c \
|
||||
$(BACNET_ROOT)/iam.c \
|
||||
$(BACNET_ROOT)/tsm.c \
|
||||
$(BACNET_ROOT)/address.c \
|
||||
$(BACNET_ROOT)/arf.c \
|
||||
$(BACNET_ROOT)/abort.c \
|
||||
$(BACNET_ROOT)/reject.c \
|
||||
$(BACNET_ROOT)/bacerror.c \
|
||||
$(BACNET_ROOT)/apdu.c \
|
||||
$(BACNET_ROOT)/npdu.c
|
||||
|
||||
OBJS = ${SRCS:.c=.o}
|
||||
|
||||
all: ${TARGET}
|
||||
|
||||
${TARGET}: ${OBJS}
|
||||
${CC} -o $@ ${OBJS}
|
||||
|
||||
.c.o:
|
||||
${CC} -c ${CFLAGS} $*.c -o $@
|
||||
|
||||
depend:
|
||||
rm -f .depend
|
||||
${CC} -MM ${CFLAGS} *.c >> .depend
|
||||
|
||||
clean:
|
||||
rm -rf core ${TARGET} $(OBJS) *.bak ports/linux/*.bak *.1 *.ini
|
||||
|
||||
include: .depend
|
||||
|
||||
@@ -1,282 +0,0 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2006 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
/* command line tool demo for BACnet stack */
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h> /* for time */
|
||||
#include <errno.h>
|
||||
#include "bactext.h"
|
||||
#include "iam.h"
|
||||
#include "arf.h"
|
||||
#include "tsm.h"
|
||||
#include "address.h"
|
||||
#include "config.h"
|
||||
#include "bacdef.h"
|
||||
#include "npdu.h"
|
||||
#include "apdu.h"
|
||||
#include "device.h"
|
||||
#include "net.h"
|
||||
#include "datalink.h"
|
||||
#include "whois.h"
|
||||
#include "dcc.h"
|
||||
/* some demo stuff needed */
|
||||
#include "filename.h"
|
||||
#include "handlers.h"
|
||||
#include "client.h"
|
||||
#include "txbuf.h"
|
||||
|
||||
/* buffer used for receive */
|
||||
static uint8_t Rx_Buf[MAX_MPDU] = { 0 };
|
||||
|
||||
/* global variables used in this file */
|
||||
static uint32_t Target_Device_Object_Instance = BACNET_MAX_INSTANCE;
|
||||
static BACNET_ADDRESS Target_Address;
|
||||
static uint16_t Communication_Timeout_Minutes = 0;
|
||||
static BACNET_COMMUNICATION_ENABLE_DISABLE Communication_State =
|
||||
COMMUNICATION_ENABLE;
|
||||
static char *Communication_Password = NULL;
|
||||
|
||||
static bool Error_Detected = false;
|
||||
|
||||
static void MyErrorHandler(BACNET_ADDRESS * src,
|
||||
uint8_t invoke_id,
|
||||
BACNET_ERROR_CLASS error_class, BACNET_ERROR_CODE error_code)
|
||||
{
|
||||
/* FIXME: verify src and invoke id */
|
||||
(void) src;
|
||||
(void) invoke_id;
|
||||
printf("BACnet Error: %s: %s\r\n",
|
||||
bactext_error_class_name(error_class),
|
||||
bactext_error_code_name(error_code));
|
||||
Error_Detected = true;
|
||||
}
|
||||
|
||||
void MyAbortHandler(BACNET_ADDRESS * src,
|
||||
uint8_t invoke_id, uint8_t abort_reason, bool server)
|
||||
{
|
||||
/* FIXME: verify src and invoke id */
|
||||
(void) src;
|
||||
(void) invoke_id;
|
||||
(void) server;
|
||||
printf("BACnet Abort: %s\r\n",
|
||||
bactext_abort_reason_name(abort_reason));
|
||||
Error_Detected = true;
|
||||
}
|
||||
|
||||
void MyRejectHandler(BACNET_ADDRESS * src,
|
||||
uint8_t invoke_id, uint8_t reject_reason)
|
||||
{
|
||||
/* FIXME: verify src and invoke id */
|
||||
(void) src;
|
||||
(void) invoke_id;
|
||||
printf("BACnet Reject: %s\r\n",
|
||||
bactext_reject_reason_name(reject_reason));
|
||||
Error_Detected = true;
|
||||
}
|
||||
|
||||
void MyDeviceCommunicationControlSimpleAckHandler(BACNET_ADDRESS * src,
|
||||
uint8_t invoke_id)
|
||||
{
|
||||
(void) src;
|
||||
(void) invoke_id;
|
||||
printf("DeviceCommunicationControl Acknowledged!\r\n");
|
||||
}
|
||||
|
||||
static void Init_Service_Handlers(void)
|
||||
{
|
||||
/* we need to handle who-is
|
||||
to support dynamic device binding to us */
|
||||
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS,
|
||||
handler_who_is);
|
||||
/* handle i-am to support binding to other devices */
|
||||
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_I_AM,
|
||||
handler_i_am_bind);
|
||||
/* 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);
|
||||
/* we must implement read property - it's required! */
|
||||
apdu_set_confirmed_handler(SERVICE_CONFIRMED_READ_PROPERTY,
|
||||
handler_read_property);
|
||||
/* handle communication so we can shutup when asked */
|
||||
apdu_set_confirmed_handler
|
||||
(SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL,
|
||||
handler_device_communication_control);
|
||||
/* handle the ack coming back */
|
||||
apdu_set_confirmed_simple_ack_handler
|
||||
(SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL,
|
||||
MyDeviceCommunicationControlSimpleAckHandler);
|
||||
/* handle any errors coming back */
|
||||
apdu_set_error_handler(SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL,
|
||||
MyErrorHandler);
|
||||
apdu_set_abort_handler(MyAbortHandler);
|
||||
apdu_set_reject_handler(MyRejectHandler);
|
||||
}
|
||||
|
||||
#ifdef BIP_DEBUG
|
||||
static void print_address(char *name, BACNET_ADDRESS * dest)
|
||||
{ /* destination address */
|
||||
int i = 0; /* counter */
|
||||
|
||||
if (dest) {
|
||||
printf("%s: ", name);
|
||||
for (i = 0; i < dest->mac_len; i++) {
|
||||
printf("%02X", dest->mac[i]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
BACNET_ADDRESS src = { 0 }; /* address where message came from */
|
||||
uint16_t pdu_len = 0;
|
||||
unsigned timeout = 100; /* milliseconds */
|
||||
unsigned max_apdu = 0;
|
||||
time_t elapsed_seconds = 0;
|
||||
time_t last_seconds = 0;
|
||||
time_t current_seconds = 0;
|
||||
time_t timeout_seconds = 0;
|
||||
uint8_t invoke_id = 0;
|
||||
bool found = false;
|
||||
#ifdef BIP_DEBUG
|
||||
BACNET_ADDRESS my_address, broadcast_address;
|
||||
#endif
|
||||
|
||||
if (argc < 3) {
|
||||
/* note: priority 16 and 0 should produce the same end results... */
|
||||
printf("Usage: %s device-instance state timeout [password]\r\n"
|
||||
"Send BACnet DeviceCommunicationControl service to device.\r\n"
|
||||
"\r\n"
|
||||
"The device-instance can be 0 to %d.\r\n"
|
||||
"Possible state values:\r\n"
|
||||
" 0=enable\r\n"
|
||||
" 1=disable\r\n"
|
||||
" 2=disable-initiation\r\n"
|
||||
"The timeout can be 0 for infinite, or a value in minutes for disable.\r\n"
|
||||
"The optional password is a character string of 1 to 20 characters.\r\n",
|
||||
filename_remove_path(argv[0]), BACNET_MAX_INSTANCE - 1);
|
||||
return 0;
|
||||
}
|
||||
/* decode the command line parameters */
|
||||
Target_Device_Object_Instance = strtol(argv[1], NULL, 0);
|
||||
Communication_State = strtol(argv[2], NULL, 0);
|
||||
Communication_Timeout_Minutes = strtol(argv[3], NULL, 0);
|
||||
/* optional password */
|
||||
if (argc > 4)
|
||||
Communication_Password = argv[4];
|
||||
|
||||
if (Target_Device_Object_Instance >= BACNET_MAX_INSTANCE) {
|
||||
fprintf(stderr, "device-instance=%u - it must be less than %u\r\n",
|
||||
Target_Device_Object_Instance, BACNET_MAX_INSTANCE);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* setup my info */
|
||||
Device_Set_Object_Instance_Number(BACNET_MAX_INSTANCE);
|
||||
address_init();
|
||||
Init_Service_Handlers();
|
||||
#ifdef BACDL_ETHERNET
|
||||
/* init the physical layer */
|
||||
if (!ethernet_init("eth0"))
|
||||
return 1;
|
||||
#endif
|
||||
#ifdef BACDL_BIP
|
||||
bip_set_interface("eth0");
|
||||
if (!bip_init())
|
||||
return 1;
|
||||
printf("bip: using port %hu\r\n", bip_get_port());
|
||||
#ifdef BIP_DEBUG
|
||||
datalink_get_broadcast_address(&broadcast_address);
|
||||
print_address("Broadcast", &broadcast_address);
|
||||
datalink_get_my_address(&my_address);
|
||||
print_address("Address", &my_address);
|
||||
#endif
|
||||
#endif
|
||||
#ifdef BACDL_ARCNET
|
||||
if (!arcnet_init("arc0"))
|
||||
return 1;
|
||||
#endif
|
||||
/* configure the timeout values */
|
||||
last_seconds = time(NULL);
|
||||
timeout_seconds = (Device_APDU_Timeout() / 1000) *
|
||||
Device_Number_Of_APDU_Retries();
|
||||
/* try to bind with the device */
|
||||
Send_WhoIs(Target_Device_Object_Instance,
|
||||
Target_Device_Object_Instance);
|
||||
/* loop forever */
|
||||
for (;;) {
|
||||
/* increment timer - exit if timed out */
|
||||
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 */
|
||||
if (current_seconds != last_seconds)
|
||||
tsm_timer_milliseconds(((current_seconds -
|
||||
last_seconds) * 1000));
|
||||
if (Error_Detected)
|
||||
break;
|
||||
/* wait until the device is bound, or timeout and quit */
|
||||
found = address_bind_request(Target_Device_Object_Instance,
|
||||
&max_apdu, &Target_Address);
|
||||
if (found) {
|
||||
if (invoke_id == 0) {
|
||||
invoke_id =
|
||||
Send_Device_Communication_Control_Request
|
||||
(Target_Device_Object_Instance,
|
||||
Communication_Timeout_Minutes, Communication_State,
|
||||
Communication_Password);
|
||||
} else if (tsm_invoke_id_free(invoke_id))
|
||||
break;
|
||||
else if (tsm_invoke_id_failed(invoke_id)) {
|
||||
fprintf(stderr, "\rError: TSM Timeout!\r\n");
|
||||
tsm_free_invoke_id(invoke_id);
|
||||
/* try again or abort? */
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* increment timer - exit if timed out */
|
||||
elapsed_seconds += (current_seconds - last_seconds);
|
||||
if (elapsed_seconds > timeout_seconds) {
|
||||
printf("\rError: APDU Timeout!\r\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* keep track of time for next check */
|
||||
last_seconds = current_seconds;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,157 +0,0 @@
|
||||
#
|
||||
# Simple makefile to build an executable for Win32
|
||||
#
|
||||
# This makefile assumes Borland bcc32 development environment
|
||||
# on Windows NT/9x/2000/XP
|
||||
#
|
||||
|
||||
!ifndef BORLAND_DIR
|
||||
BORLAND_DIR_Not_Defined:
|
||||
@echo .
|
||||
@echo You must define environment variable BORLAND_DIR to compile.
|
||||
!endif
|
||||
|
||||
PRODUCT = bacdcc
|
||||
PRODUCT_EXE = $(PRODUCT).exe
|
||||
|
||||
# Choose the Data Link Layer to Enable
|
||||
DEFINES = -DBACDL_BIP=1;TSM_ENABLED=1;USE_INADDR=1;BIP_DEBUG;BIG_ENDIAN=0;PRINT_ENABLED=1
|
||||
|
||||
SRCS = main.c \
|
||||
..\..\ports\win32\bip-init.c \
|
||||
..\..\filename.c \
|
||||
..\..\bip.c \
|
||||
..\..\demo\handler\txbuf.c \
|
||||
..\..\demo\handler\noserv.c \
|
||||
..\..\demo\handler\h_whois.c \
|
||||
..\..\demo\handler\h_iam.c \
|
||||
..\..\demo\handler\h_rp.c \
|
||||
..\..\demo\handler\h_dcc.c \
|
||||
..\..\demo\handler\s_whois.c \
|
||||
..\..\demo\handler\s_dcc.c \
|
||||
..\..\bacdcode.c \
|
||||
..\..\bacapp.c \
|
||||
..\..\bacstr.c \
|
||||
..\..\bactext.c \
|
||||
..\..\datetime.c \
|
||||
..\..\indtext.c \
|
||||
..\..\bigend.c \
|
||||
..\..\whois.c \
|
||||
..\..\iam.c \
|
||||
..\..\rp.c \
|
||||
..\..\wp.c \
|
||||
..\..\arf.c \
|
||||
..\..\awf.c \
|
||||
..\..\dcc.c \
|
||||
..\..\demo\object\bacfile.c \
|
||||
..\..\demo\object\device.c \
|
||||
..\..\demo\object\ai.c \
|
||||
..\..\demo\object\ao.c \
|
||||
..\..\demo\object\av.c \
|
||||
..\..\demo\object\bi.c \
|
||||
..\..\demo\object\bo.c \
|
||||
..\..\demo\object\bv.c \
|
||||
..\..\demo\object\lc.c \
|
||||
..\..\demo\object\lsp.c \
|
||||
..\..\demo\object\mso.c \
|
||||
..\..\tsm.c \
|
||||
..\..\address.c \
|
||||
..\..\abort.c \
|
||||
..\..\reject.c \
|
||||
..\..\bacerror.c \
|
||||
..\..\apdu.c \
|
||||
..\..\npdu.c
|
||||
|
||||
OBJS = $(SRCS:.c=.obj)
|
||||
|
||||
# Compiler definitions
|
||||
#
|
||||
CC = $(BORLAND_DIR)\bin\bcc32 +bcc32.cfg
|
||||
#LINK = $(BORLAND_DIR)\bin\tlink32
|
||||
LINK = $(BORLAND_DIR)\bin\ilink32
|
||||
TLIB = $(BORLAND_DIR)\bin\tlib
|
||||
|
||||
#
|
||||
# Include directories
|
||||
#
|
||||
CC_DIR = $(BORLAND_DIR)\BIN
|
||||
INCL_DIRS = -I$(BORLAND_DIR)\include;..\..\;..\..\demo\object\;..\..\demo\handler\;..\..\ports\win32\;.
|
||||
|
||||
CFLAGS = $(INCL_DIRS) $(CS_FLAGS) $(DEFINES)
|
||||
|
||||
# Libraries
|
||||
#
|
||||
C_LIB_DIR = $(BORLAND_DIR)\lib
|
||||
|
||||
LIBS = $(C_LIB_DIR)\IMPORT32.lib \
|
||||
$(C_LIB_DIR)\CW32MT.lib
|
||||
|
||||
#
|
||||
# Main target
|
||||
#
|
||||
# This should be the first one in the makefile
|
||||
|
||||
all : bcc32.cfg $(PRODUCT_EXE)
|
||||
|
||||
install: $(PRODUCT_EXE)
|
||||
copy $(PRODUCT_EXE) ..\..\utils\$(PRODUCT_EXE)
|
||||
|
||||
# Linker specific: the link below is for BCC linker/compiler. If you link
|
||||
# with a different linker - please change accordingly.
|
||||
#
|
||||
|
||||
# need a temp response file (@&&) because command line is too long
|
||||
$(PRODUCT_EXE) : $(OBJS)
|
||||
@echo Running Linker for $(PRODUCT_EXE)
|
||||
$(LINK) -L$(C_LIB_DIR) -m -c -s -v @&&| # temp response file, starts with |
|
||||
$(BORLAND_DIR)\lib\c0x32.obj $** # $** lists each dependency
|
||||
$<
|
||||
$*.map
|
||||
$(LIBS)
|
||||
| # end of temp response file
|
||||
|
||||
#
|
||||
# Utilities
|
||||
|
||||
clean :
|
||||
@echo Deleting obj files, $(PRODUCT_EXE) and map files.
|
||||
# del $(OBJS) # command too long, bummer!
|
||||
del *.obj
|
||||
del ..\..\*.obj
|
||||
del ..\..\demo\handler\*.obj
|
||||
del ..\..\demo\object\*.obj
|
||||
del ..\..\ports\win32\*.obj
|
||||
del $(PRODUCT_EXE)
|
||||
del *.map
|
||||
del bcc32.cfg
|
||||
|
||||
#
|
||||
# Generic rules
|
||||
#
|
||||
.SUFFIXES: .cpp .c .sbr .obj
|
||||
|
||||
#
|
||||
# cc generic rule
|
||||
#
|
||||
.c.obj:
|
||||
$(CC) -o$@ $<
|
||||
|
||||
# Compiler configuration file
|
||||
bcc32.cfg :
|
||||
Copy &&|
|
||||
$(CFLAGS)
|
||||
-c
|
||||
-y #include line numbers in OBJ's
|
||||
-v #include debug info
|
||||
-w+ #turn on all warnings
|
||||
-Od #disable all optimizations
|
||||
#-a4 #32 bit data alignment
|
||||
#-M # generate link map
|
||||
#-ls # linker options
|
||||
#-WM- #not multithread
|
||||
-WM #multithread
|
||||
-w-aus # ignore warning assigned a value that is never used
|
||||
-w-sig # ignore warning conversion may lose sig digits
|
||||
| $@
|
||||
|
||||
# EOF: makefile
|
||||
@@ -1,506 +0,0 @@
|
||||
#############################################################################
|
||||
|
||||
# Makefile for building bacdcc
|
||||
# Generated by tmake at 11:27, 2006/05/10
|
||||
# Project: tmake
|
||||
# Template: app
|
||||
#############################################################################
|
||||
|
||||
####### Compiler, tools and options
|
||||
|
||||
QTDIR = /usr
|
||||
CC = gcc
|
||||
CXX = g++
|
||||
CFLAGS = -pipe -Wall -W -g -DBACDL_BIP=1 -DTSM_ENABLED=1 -DUSE_INADDR=1 -DBIP_DEBUG
|
||||
CXXFLAGS= -pipe -Wall -W -g -DBACDL_BIP=1 -DTSM_ENABLED=1 -DUSE_INADDR=1 -DBIP_DEBUG
|
||||
INCPATH = -I. -I../.. -I../../demo/object -I../../demo/handler -I../../ports/linux
|
||||
LINK = g++
|
||||
LFLAGS =
|
||||
LIBS = $(SUBLIBS)
|
||||
MOC = $(QTDIR)/bin/moc
|
||||
UIC = $(QTDIR)/bin/uic
|
||||
|
||||
TAR = tar -cf
|
||||
GZIP = gzip -9f
|
||||
|
||||
####### Files
|
||||
|
||||
HEADERS =
|
||||
SOURCES = main.c \
|
||||
../../filename.c \
|
||||
../../bip.c \
|
||||
../../demo/handler/txbuf.c \
|
||||
../../demo/handler/noserv.c \
|
||||
../../demo/handler/h_whois.c \
|
||||
../../demo/handler/h_iam.c \
|
||||
../../demo/handler/h_rp.c \
|
||||
../../demo/handler/h_dcc.c \
|
||||
../../demo/handler/s_whois.c \
|
||||
../../demo/handler/s_dcc.c \
|
||||
../../bacdcode.c \
|
||||
../../bacapp.c \
|
||||
../../bacstr.c \
|
||||
../../bactext.c \
|
||||
../../indtext.c \
|
||||
../../bigend.c \
|
||||
../../whois.c \
|
||||
../../iam.c \
|
||||
../../rp.c \
|
||||
../../wp.c \
|
||||
../../arf.c \
|
||||
../../awf.c \
|
||||
../../dcc.c \
|
||||
../../demo/object/bacfile.c \
|
||||
../../demo/object/device.c \
|
||||
../../demo/object/ai.c \
|
||||
../../demo/object/ao.c \
|
||||
../../demo/object/bi.c \
|
||||
../../demo/object/bo.c \
|
||||
../../demo/object/lsp.c \
|
||||
../../datalink.c \
|
||||
../../tsm.c \
|
||||
../../address.c \
|
||||
../../abort.c \
|
||||
../../reject.c \
|
||||
../../bacerror.c \
|
||||
../../apdu.c \
|
||||
../../npdu.c \
|
||||
../../ports/linux/bip-init.c
|
||||
OBJECTS = main.o \
|
||||
../../filename.o \
|
||||
../../bip.o \
|
||||
../../demo/handler/txbuf.o \
|
||||
../../demo/handler/noserv.o \
|
||||
../../demo/handler/h_whois.o \
|
||||
../../demo/handler/h_iam.o \
|
||||
../../demo/handler/h_rp.o \
|
||||
../../demo/handler/h_dcc.o \
|
||||
../../demo/handler/s_whois.o \
|
||||
../../demo/handler/s_dcc.o \
|
||||
../../bacdcode.o \
|
||||
../../bacapp.o \
|
||||
../../bacstr.o \
|
||||
../../bactext.o \
|
||||
../../indtext.o \
|
||||
../../bigend.o \
|
||||
../../whois.o \
|
||||
../../iam.o \
|
||||
../../rp.o \
|
||||
../../wp.o \
|
||||
../../arf.o \
|
||||
../../awf.o \
|
||||
../../dcc.o \
|
||||
../../demo/object/bacfile.o \
|
||||
../../demo/object/device.o \
|
||||
../../demo/object/ai.o \
|
||||
../../demo/object/ao.o \
|
||||
../../demo/object/bi.o \
|
||||
../../demo/object/bo.o \
|
||||
../../demo/object/lsp.o \
|
||||
../../datalink.o \
|
||||
../../tsm.o \
|
||||
../../address.o \
|
||||
../../abort.o \
|
||||
../../reject.o \
|
||||
../../bacerror.o \
|
||||
../../apdu.o \
|
||||
../../npdu.o \
|
||||
../../ports/linux/bip-init.o
|
||||
INTERFACES =
|
||||
UICDECLS =
|
||||
UICIMPLS =
|
||||
SRCMOC =
|
||||
OBJMOC =
|
||||
DIST =
|
||||
TARGET = bacdcc
|
||||
INTERFACE_DECL_PATH = .
|
||||
|
||||
####### Implicit rules
|
||||
|
||||
.SUFFIXES: .cpp .cxx .cc .C .c
|
||||
|
||||
.cpp.o:
|
||||
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $<
|
||||
|
||||
.cxx.o:
|
||||
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $<
|
||||
|
||||
.cc.o:
|
||||
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $<
|
||||
|
||||
.C.o:
|
||||
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $<
|
||||
|
||||
.c.o:
|
||||
$(CC) -c $(CFLAGS) $(INCPATH) -o $@ $<
|
||||
|
||||
####### Build rules
|
||||
|
||||
|
||||
all: $(TARGET)
|
||||
|
||||
$(TARGET): $(UICDECLS) $(OBJECTS) $(OBJMOC)
|
||||
$(LINK) $(LFLAGS) -o $(TARGET) $(OBJECTS) $(OBJMOC) $(LIBS)
|
||||
|
||||
moc: $(SRCMOC)
|
||||
|
||||
tmake: makefile.g++
|
||||
|
||||
makefile.g++: tmake.pro
|
||||
tmake tmake.pro -o makefile.g++
|
||||
|
||||
dist:
|
||||
$(TAR) tmake.tar tmake.pro $(SOURCES) $(HEADERS) $(INTERFACES) $(DIST)
|
||||
$(GZIP) tmake.tar
|
||||
|
||||
clean:
|
||||
-rm -f $(OBJECTS) $(OBJMOC) $(SRCMOC) $(UICIMPLS) $(UICDECLS) $(TARGET)
|
||||
-rm -f *~ core
|
||||
-rm -f core *~
|
||||
|
||||
####### Sub-libraries
|
||||
|
||||
|
||||
###### Combined headers
|
||||
|
||||
|
||||
####### Compile
|
||||
|
||||
main.o: main.c
|
||||
|
||||
../../filename.o: ../../filename.c
|
||||
|
||||
../../bip.o: ../../bip.c \
|
||||
../../bacdcode.h \
|
||||
../../bacdef.h \
|
||||
../../bacenum.h \
|
||||
../../config.h \
|
||||
../../bacstr.h \
|
||||
../../bip.h
|
||||
|
||||
../../demo/handler/txbuf.o: ../../demo/handler/txbuf.c \
|
||||
../../config.h
|
||||
|
||||
../../demo/handler/noserv.o: ../../demo/handler/noserv.c \
|
||||
../../demo/handler/txbuf.h \
|
||||
../../config.h \
|
||||
../../bacdef.h \
|
||||
../../bacenum.h \
|
||||
../../bacdcode.h \
|
||||
../../bacstr.h
|
||||
|
||||
../../demo/handler/h_whois.o: ../../demo/handler/h_whois.c \
|
||||
../../config.h \
|
||||
../../demo/handler/txbuf.h \
|
||||
../../bacdef.h \
|
||||
../../bacenum.h \
|
||||
../../bacdcode.h \
|
||||
../../bacstr.h \
|
||||
../../demo/handler/client.h
|
||||
|
||||
../../demo/handler/h_iam.o: ../../demo/handler/h_iam.c \
|
||||
../../config.h \
|
||||
../../demo/handler/txbuf.h \
|
||||
../../bacdef.h \
|
||||
../../bacenum.h \
|
||||
../../bacdcode.h \
|
||||
../../bacstr.h
|
||||
|
||||
../../demo/handler/h_rp.o: ../../demo/handler/h_rp.c \
|
||||
../../config.h \
|
||||
../../demo/handler/txbuf.h \
|
||||
../../bacdef.h \
|
||||
../../bacenum.h \
|
||||
../../bacdcode.h \
|
||||
../../bacstr.h
|
||||
|
||||
../../demo/handler/h_dcc.o: ../../demo/handler/h_dcc.c \
|
||||
../../config.h \
|
||||
../../demo/handler/txbuf.h \
|
||||
../../bacdef.h \
|
||||
../../bacenum.h \
|
||||
../../bacdcode.h \
|
||||
../../bacstr.h
|
||||
|
||||
../../demo/handler/s_whois.o: ../../demo/handler/s_whois.c \
|
||||
../../config.h \
|
||||
../../demo/handler/txbuf.h \
|
||||
../../bacdef.h \
|
||||
../../bacenum.h \
|
||||
../../bacdcode.h \
|
||||
../../bacstr.h \
|
||||
../../demo/handler/handlers.h
|
||||
|
||||
../../demo/handler/s_dcc.o: ../../demo/handler/s_dcc.c \
|
||||
../../config.h \
|
||||
../../demo/handler/txbuf.h \
|
||||
../../bacdef.h \
|
||||
../../bacenum.h \
|
||||
../../bacdcode.h \
|
||||
../../bacstr.h \
|
||||
../../demo/handler/handlers.h
|
||||
|
||||
../../bacdcode.o: ../../bacdcode.c \
|
||||
../../bacdef.h \
|
||||
../../bacenum.h \
|
||||
../../config.h \
|
||||
../../bacdcode.h \
|
||||
../../bacstr.h \
|
||||
../../bits.h \
|
||||
../../bigend.h
|
||||
|
||||
../../bacapp.o: ../../bacapp.c \
|
||||
../../bacenum.h \
|
||||
../../bacdcode.h \
|
||||
../../bacdef.h \
|
||||
../../config.h \
|
||||
../../bacstr.h \
|
||||
../../bacapp.h \
|
||||
../../bactext.h \
|
||||
../../indtext.h
|
||||
|
||||
../../bacstr.o: ../../bacstr.c \
|
||||
../../bacstr.h \
|
||||
../../bacdef.h \
|
||||
../../bacenum.h \
|
||||
../../config.h \
|
||||
../../bits.h
|
||||
|
||||
../../bactext.o: ../../bactext.c \
|
||||
../../indtext.h \
|
||||
../../bacenum.h
|
||||
|
||||
../../indtext.o: ../../indtext.c \
|
||||
../../indtext.h
|
||||
|
||||
../../bigend.o: ../../bigend.c
|
||||
|
||||
../../whois.o: ../../whois.c \
|
||||
../../bacenum.h \
|
||||
../../bacdcode.h \
|
||||
../../bacdef.h \
|
||||
../../config.h \
|
||||
../../bacstr.h
|
||||
|
||||
../../iam.o: ../../iam.c \
|
||||
../../bacenum.h \
|
||||
../../bacdef.h \
|
||||
../../config.h \
|
||||
../../npdu.h \
|
||||
../../datalink.h \
|
||||
../../ethernet.h \
|
||||
../../arcnet.h \
|
||||
../../dlmstp.h \
|
||||
../../bip.h \
|
||||
../../bacdcode.h \
|
||||
../../bacstr.h \
|
||||
../../address.h
|
||||
|
||||
../../rp.o: ../../rp.c \
|
||||
../../bacenum.h \
|
||||
../../bacdcode.h \
|
||||
../../bacdef.h \
|
||||
../../config.h \
|
||||
../../bacstr.h \
|
||||
../../rp.h
|
||||
|
||||
../../wp.o: ../../wp.c \
|
||||
../../bacenum.h \
|
||||
../../bacdcode.h \
|
||||
../../bacdef.h \
|
||||
../../config.h \
|
||||
../../bacstr.h \
|
||||
../../wp.h \
|
||||
../../bacapp.h
|
||||
|
||||
../../arf.o: ../../arf.c \
|
||||
../../bacenum.h \
|
||||
../../bacdcode.h \
|
||||
../../bacdef.h \
|
||||
../../config.h \
|
||||
../../bacstr.h \
|
||||
../../arf.h
|
||||
|
||||
../../awf.o: ../../awf.c \
|
||||
../../bacenum.h \
|
||||
../../bacdcode.h \
|
||||
../../bacdef.h \
|
||||
../../config.h \
|
||||
../../bacstr.h \
|
||||
../../awf.h
|
||||
|
||||
../../dcc.o: ../../dcc.c \
|
||||
../../bacenum.h \
|
||||
../../bacdcode.h \
|
||||
../../bacdef.h \
|
||||
../../config.h \
|
||||
../../bacstr.h \
|
||||
../../dcc.h
|
||||
|
||||
../../demo/object/bacfile.o: ../../demo/object/bacfile.c \
|
||||
../../config.h \
|
||||
../../address.h \
|
||||
../../bacdef.h \
|
||||
../../bacenum.h \
|
||||
../../datalink.h \
|
||||
../../ethernet.h \
|
||||
../../arcnet.h \
|
||||
../../dlmstp.h \
|
||||
../../bip.h \
|
||||
../../bacdcode.h \
|
||||
../../bacstr.h \
|
||||
../../npdu.h \
|
||||
../../demo/object/device.h \
|
||||
../../wp.h \
|
||||
../../bacapp.h \
|
||||
../../arf.h \
|
||||
../../awf.h
|
||||
|
||||
../../demo/object/device.o: ../../demo/object/device.c \
|
||||
../../bacdef.h \
|
||||
../../bacenum.h \
|
||||
../../config.h \
|
||||
../../bacdcode.h \
|
||||
../../bacstr.h \
|
||||
../../demo/object/ai.h \
|
||||
../../demo/object/bi.h \
|
||||
../../demo/object/bo.h \
|
||||
../../wp.h \
|
||||
../../bacapp.h \
|
||||
../../demo/object/ao.h \
|
||||
../../demo/object/lsp.h \
|
||||
../../demo/object/device.h \
|
||||
../../demo/object/bacfile.h \
|
||||
../../arf.h
|
||||
|
||||
../../demo/object/ai.o: ../../demo/object/ai.c \
|
||||
../../bacdef.h \
|
||||
../../bacenum.h \
|
||||
../../config.h \
|
||||
../../bacdcode.h \
|
||||
../../bacstr.h
|
||||
|
||||
../../demo/object/ao.o: ../../demo/object/ao.c \
|
||||
../../bacdef.h \
|
||||
../../bacenum.h \
|
||||
../../config.h \
|
||||
../../bacdcode.h \
|
||||
../../bacstr.h \
|
||||
../../wp.h \
|
||||
../../bacapp.h
|
||||
|
||||
../../demo/object/bi.o: ../../demo/object/bi.c \
|
||||
../../bacdef.h \
|
||||
../../bacenum.h \
|
||||
../../config.h \
|
||||
../../bacdcode.h \
|
||||
../../bacstr.h
|
||||
|
||||
../../demo/object/bo.o: ../../demo/object/bo.c \
|
||||
../../bacdef.h \
|
||||
../../bacenum.h \
|
||||
../../config.h \
|
||||
../../bacdcode.h \
|
||||
../../bacstr.h \
|
||||
../../wp.h \
|
||||
../../bacapp.h
|
||||
|
||||
../../demo/object/lsp.o: ../../demo/object/lsp.c \
|
||||
../../bacdef.h \
|
||||
../../bacenum.h \
|
||||
../../config.h \
|
||||
../../bacdcode.h \
|
||||
../../bacstr.h \
|
||||
../../wp.h \
|
||||
../../bacapp.h
|
||||
|
||||
../../datalink.o: ../../datalink.c \
|
||||
../../datalink.h \
|
||||
../../bacdef.h \
|
||||
../../bacenum.h \
|
||||
../../config.h \
|
||||
../../ethernet.h \
|
||||
../../arcnet.h \
|
||||
../../dlmstp.h \
|
||||
../../bip.h
|
||||
|
||||
../../tsm.o: ../../tsm.c \
|
||||
../../bits.h \
|
||||
../../apdu.h \
|
||||
../../bacdef.h \
|
||||
../../bacenum.h \
|
||||
../../config.h \
|
||||
../../bacdcode.h \
|
||||
../../bacstr.h \
|
||||
../../tsm.h \
|
||||
../../demo/object/device.h \
|
||||
../../wp.h \
|
||||
../../bacapp.h \
|
||||
../../datalink.h \
|
||||
../../ethernet.h \
|
||||
../../arcnet.h \
|
||||
../../dlmstp.h \
|
||||
../../bip.h \
|
||||
../../demo/handler/handlers.h \
|
||||
../../address.h
|
||||
|
||||
../../address.o: ../../address.c \
|
||||
../../config.h \
|
||||
../../address.h \
|
||||
../../bacdef.h \
|
||||
../../bacenum.h \
|
||||
../../bacdcode.h \
|
||||
../../bacstr.h
|
||||
|
||||
../../abort.o: ../../abort.c \
|
||||
../../bacenum.h \
|
||||
../../bacdcode.h \
|
||||
../../bacdef.h \
|
||||
../../config.h \
|
||||
../../bacstr.h
|
||||
|
||||
../../reject.o: ../../reject.c \
|
||||
../../bacenum.h \
|
||||
../../bacdcode.h \
|
||||
../../bacdef.h \
|
||||
../../config.h \
|
||||
../../bacstr.h
|
||||
|
||||
../../bacerror.o: ../../bacerror.c \
|
||||
../../bacenum.h \
|
||||
../../bacdcode.h \
|
||||
../../bacdef.h \
|
||||
../../config.h \
|
||||
../../bacstr.h
|
||||
|
||||
../../apdu.o: ../../apdu.c \
|
||||
../../bits.h \
|
||||
../../apdu.h \
|
||||
../../bacdef.h \
|
||||
../../bacenum.h \
|
||||
../../config.h \
|
||||
../../bacdcode.h \
|
||||
../../bacstr.h \
|
||||
../../tsm.h \
|
||||
../../dcc.h \
|
||||
../../iam.h
|
||||
|
||||
../../npdu.o: ../../npdu.c \
|
||||
../../bacdef.h \
|
||||
../../bacenum.h \
|
||||
../../config.h \
|
||||
../../bacdcode.h \
|
||||
../../bacstr.h \
|
||||
../../bits.h \
|
||||
../../npdu.h \
|
||||
../../apdu.h
|
||||
|
||||
../../ports/linux/bip-init.o: ../../ports/linux/bip-init.c \
|
||||
../../bacdcode.h \
|
||||
../../bacdef.h \
|
||||
../../bacenum.h \
|
||||
../../config.h \
|
||||
../../bacstr.h \
|
||||
../../bip.h \
|
||||
../../ports/linux/net.h
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
TEMPLATE = app
|
||||
CONFIG = warn_on debug console
|
||||
CLEAN_FILES = core *~
|
||||
TARGET = bacdcc
|
||||
DEFINES = BACDL_BIP=1 TSM_ENABLED=1 USE_INADDR=1 BIP_DEBUG
|
||||
SOURCES = main.c \
|
||||
../../filename.c \
|
||||
../../bip.c \
|
||||
../../demo/handler/txbuf.c \
|
||||
../../demo/handler/noserv.c \
|
||||
../../demo/handler/h_whois.c \
|
||||
../../demo/handler/h_iam.c \
|
||||
../../demo/handler/h_rp.c \
|
||||
../../demo/handler/h_dcc.c \
|
||||
../../demo/handler/s_whois.c \
|
||||
../../demo/handler/s_dcc.c \
|
||||
../../bacdcode.c \
|
||||
../../bacapp.c \
|
||||
../../bacstr.c \
|
||||
../../bactext.c \
|
||||
../../indtext.c \
|
||||
../../bigend.c \
|
||||
../../whois.c \
|
||||
../../iam.c \
|
||||
../../rp.c \
|
||||
../../wp.c \
|
||||
../../arf.c \
|
||||
../../awf.c \
|
||||
../../dcc.c \
|
||||
../../demo/object/bacfile.c \
|
||||
../../demo/object/device.c \
|
||||
../../demo/object/ai.c \
|
||||
../../demo/object/ao.c \
|
||||
../../demo/object/bi.c \
|
||||
../../demo/object/bo.c \
|
||||
../../demo/object/lsp.c \
|
||||
../../datalink.c \
|
||||
../../tsm.c \
|
||||
../../address.c \
|
||||
../../abort.c \
|
||||
../../reject.c \
|
||||
../../bacerror.c \
|
||||
../../apdu.c \
|
||||
../../npdu.c
|
||||
unix:SOURCES += ../../ports/linux/bip-init.c
|
||||
win32:SOURCES += ../../ports/win32/bip-init.c
|
||||
|
||||
INCLUDEPATH = . \
|
||||
../../ \
|
||||
../../demo/object \
|
||||
../../demo/handler
|
||||
|
||||
unix:INCLUDEPATH += ../../ports/linux
|
||||
win32:INCLUDEPATH += ../../ports/win32
|
||||
|
||||
#unix:HEADERS += ../../ports/linux/net.h
|
||||
#win32:HEADERS += ../../ports/win32/stdint.h
|
||||
#win32:HEADERS += ../../ports/win32/net.h
|
||||
#win32:HEADERS += ../../ports/win32/stdbool.h
|
||||
@@ -1,90 +0,0 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2006 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 CLIENT_H
|
||||
#define CLIENT_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include "bacdef.h"
|
||||
#include "apdu.h"
|
||||
#include "bacapp.h"
|
||||
#include "bacenum.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/* unconfirmed requests */
|
||||
void Send_WhoIs(int32_t low_limit, int32_t high_limit);
|
||||
|
||||
void Send_WhoHas_Object(int32_t low_limit,
|
||||
int32_t high_limit,
|
||||
BACNET_OBJECT_TYPE object_type, uint32_t object_instance);
|
||||
|
||||
void Send_WhoHas_Name(int32_t low_limit,
|
||||
int32_t high_limit, char *object_name);
|
||||
|
||||
void Send_I_Have(uint32_t device_id,
|
||||
BACNET_OBJECT_TYPE object_type,
|
||||
uint32_t object_instance, char *object_name);
|
||||
|
||||
/* returns the invoke ID for confirmed request, or 0 if failed */
|
||||
uint8_t Send_Read_Property_Request(uint32_t device_id, /* destination device */
|
||||
BACNET_OBJECT_TYPE object_type,
|
||||
uint32_t object_instance,
|
||||
BACNET_PROPERTY_ID object_property, int32_t array_index);
|
||||
|
||||
/* returns the invoke ID for confirmed request, or 0 if failed */
|
||||
uint8_t Send_Write_Property_Request(uint32_t device_id, /* destination device */
|
||||
BACNET_OBJECT_TYPE object_type,
|
||||
uint32_t object_instance,
|
||||
BACNET_PROPERTY_ID object_property,
|
||||
BACNET_APPLICATION_DATA_VALUE * object_value,
|
||||
uint8_t priority, int32_t array_index);
|
||||
|
||||
/* returns the invoke ID for confirmed request, or 0 if failed */
|
||||
uint8_t Send_Reinitialize_Device_Request(uint32_t device_id,
|
||||
BACNET_REINITIALIZED_STATE state, char *password);
|
||||
|
||||
/* returns the invoke ID for confirmed request, or 0 if failed */
|
||||
uint8_t Send_Device_Communication_Control_Request(uint32_t device_id, uint16_t timeDuration, /* 0=optional */
|
||||
BACNET_COMMUNICATION_ENABLE_DISABLE state, char *password); /* NULL=optional */
|
||||
|
||||
void Send_TimeSync(BACNET_DATE * bdate, BACNET_TIME * btime);
|
||||
void Send_TimeSyncUTC(BACNET_DATE * bdate, BACNET_TIME * btime);
|
||||
|
||||
uint8_t Send_Atomic_Read_File_Stream(uint32_t device_id,
|
||||
uint32_t file_instance, int fileStartPosition,
|
||||
unsigned requestedOctetCount);
|
||||
uint8_t Send_Atomic_Write_File_Stream(uint32_t device_id,
|
||||
uint32_t file_instance,
|
||||
int fileStartPosition, BACNET_OCTET_STRING * fileData);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
@@ -1,185 +0,0 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include "config.h"
|
||||
#include "txbuf.h"
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "apdu.h"
|
||||
#include "npdu.h"
|
||||
#include "abort.h"
|
||||
#include "arf.h"
|
||||
/* demo objects */
|
||||
#include "device.h"
|
||||
#include "ai.h"
|
||||
#include "ao.h"
|
||||
#include "bacfile.h"
|
||||
|
||||
/*
|
||||
from BACnet SSPC-135-2004
|
||||
|
||||
14. FILE ACCESS SERVICES
|
||||
|
||||
This clause defines the set of services used to access and
|
||||
manipulate files contained in BACnet devices. The concept of files
|
||||
is used here as a network-visible representation for a collection
|
||||
of octets of arbitrary length and meaning. This is an abstract
|
||||
concept only and does not imply the use of disk, tape or other
|
||||
mass storage devices in the server devices. These services may
|
||||
be used to access vendor-defined files as well as specific
|
||||
files defined in the BACnet protocol standard.
|
||||
Every file that is accessible by File Access Services shall
|
||||
have a corresponding File object in the BACnet device. This File
|
||||
object is used to identify the particular file by name. In addition,
|
||||
the File object provides access to "header information," such
|
||||
as the file's total size, creation date, and type. File Access
|
||||
Services may model files in two ways: as a continuous stream of
|
||||
octets or as a contiguous sequence of numbered records.
|
||||
The File Access Services provide atomic read and write operations.
|
||||
In this context "atomic" means that during the execution
|
||||
of a read or write operation, no other AtomicReadFile or
|
||||
AtomicWriteFile operations are allowed for the same file.
|
||||
Synchronization of these services with internal operations
|
||||
of the BACnet device is a local matter and is not defined by this
|
||||
standard.
|
||||
|
||||
14.1 AtomicReadFile Service
|
||||
|
||||
14.1.5 Service Procedure
|
||||
|
||||
The responding BACnet-user shall first verify the validity
|
||||
of the 'File Identifier' parameter and return a 'Result(-)' response
|
||||
with the appropriate error class and code if the File object
|
||||
is unknown, if there is currently another AtomicReadFile or
|
||||
AtomicWriteFile service in progress, or if the File object is
|
||||
currently inaccessible for another reason. If the 'File Start
|
||||
Position' parameter or the 'File Start Record' parameter is
|
||||
either less than 0 or exceeds the actual file size, then the appropriate
|
||||
error is returned in a 'Result(-)' response. If not, then the
|
||||
responding BACnet-user shall read the number of octets specified by
|
||||
'Requested Octet Count' or the number of records specified by
|
||||
'Requested Record Count'. If the number of remaining octets or
|
||||
records is less than the requested amount, then the length of
|
||||
the 'File Data' returned or 'Returned Record Count' shall indicate
|
||||
the actual number read. If the returned response contains the
|
||||
last octet or record of the file, then the 'End Of File' parameter
|
||||
shall be TRUE, otherwise FALSE.
|
||||
*/
|
||||
|
||||
void handler_atomic_read_file(uint8_t * service_request,
|
||||
uint16_t service_len,
|
||||
BACNET_ADDRESS * src, BACNET_CONFIRMED_SERVICE_DATA * service_data)
|
||||
{
|
||||
BACNET_ATOMIC_READ_FILE_DATA data;
|
||||
int len = 0;
|
||||
int pdu_len = 0;
|
||||
bool error = false;
|
||||
int bytes_sent = 0;
|
||||
BACNET_NPDU_DATA npdu_data;
|
||||
BACNET_ADDRESS my_address;
|
||||
BACNET_ERROR_CLASS error_class = ERROR_CLASS_OBJECT;
|
||||
BACNET_ERROR_CODE error_code = ERROR_CODE_UNKNOWN_OBJECT;
|
||||
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Received Atomic-Read-File Request!\n");
|
||||
#endif
|
||||
len = arf_decode_service_request(service_request, service_len, &data);
|
||||
/* encode the NPDU portion of the packet */
|
||||
datalink_get_my_address(&my_address);
|
||||
npdu_encode_npdu_data(&npdu_data, false, MESSAGE_PRIORITY_NORMAL);
|
||||
pdu_len = npdu_encode_pdu(&Handler_Transmit_Buffer[0], src,
|
||||
&my_address, &npdu_data);
|
||||
/* bad decoding - send an abort */
|
||||
if (len < 0) {
|
||||
len = abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id, ABORT_REASON_OTHER, true);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Bad Encoding. Sending Abort!\n");
|
||||
#endif
|
||||
} else if (service_data->segmented_message) {
|
||||
len = abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
ABORT_REASON_SEGMENTATION_NOT_SUPPORTED, true);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Segmented Message. Sending Abort!\n");
|
||||
#endif
|
||||
} else if (data.object_type == OBJECT_FILE) {
|
||||
if (!bacfile_valid_instance(data.object_instance)) {
|
||||
error = true;
|
||||
} else if (data.access == FILE_STREAM_ACCESS) {
|
||||
if (data.type.stream.requestedOctetCount <
|
||||
octetstring_capacity(&data.fileData)) {
|
||||
if (bacfile_read_data(&data)) {
|
||||
len =
|
||||
arf_ack_encode_apdu(&Handler_Transmit_Buffer
|
||||
[pdu_len], service_data->invoke_id, &data);
|
||||
} else {
|
||||
error = true;
|
||||
error_class = ERROR_CLASS_OBJECT;
|
||||
error_code = ERROR_CODE_FILE_ACCESS_DENIED;
|
||||
}
|
||||
} else {
|
||||
len =
|
||||
abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
ABORT_REASON_SEGMENTATION_NOT_SUPPORTED, true);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Too Big To Send. Sending Abort!\n");
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
error = true;
|
||||
error_class = ERROR_CLASS_SERVICES;
|
||||
error_code = ERROR_CODE_INVALID_FILE_ACCESS_METHOD;
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Record Access Requested. Sending Error!\n");
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
error = true;
|
||||
error_class = ERROR_CLASS_SERVICES;
|
||||
error_code = ERROR_CODE_FILE_ACCESS_DENIED;
|
||||
}
|
||||
if (error) {
|
||||
len =
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_ATOMIC_READ_FILE, error_class, error_code);
|
||||
}
|
||||
pdu_len += len;
|
||||
bytes_sent = datalink_send_pdu(src, &npdu_data,
|
||||
&Handler_Transmit_Buffer[0], pdu_len);
|
||||
#if PRINT_ENABLED
|
||||
if (bytes_sent <= 0) {
|
||||
fprintf(stderr, "Failed to send PDU (%s)!\n", strerror(errno));
|
||||
}
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -1,93 +0,0 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include "config.h"
|
||||
#include "config.h"
|
||||
#include "txbuf.h"
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "address.h"
|
||||
#include "tsm.h"
|
||||
#include "npdu.h"
|
||||
#include "apdu.h"
|
||||
#include "device.h"
|
||||
#include "datalink.h"
|
||||
#include "arf.h"
|
||||
#include "bacfile.h"
|
||||
/* some demo stuff needed */
|
||||
#include "handlers.h"
|
||||
#include "txbuf.h"
|
||||
|
||||
/* We performed an AtomicReadFile Request, */
|
||||
/* and here is the data from the server */
|
||||
/* Note: it does not have to be the same file=instance */
|
||||
/* that someone can read from us. It is common to */
|
||||
/* use the description as the file name. */
|
||||
#if BACFILE
|
||||
void handler_atomic_read_file_ack(uint8_t * service_request,
|
||||
uint16_t service_len,
|
||||
BACNET_ADDRESS * src, BACNET_CONFIRMED_SERVICE_ACK_DATA * service_data)
|
||||
{
|
||||
int len = 0;
|
||||
BACNET_ATOMIC_READ_FILE_DATA data;
|
||||
FILE *pFile = NULL;
|
||||
char *pFilename = NULL;
|
||||
uint32_t instance = 0;
|
||||
|
||||
(void) src;
|
||||
/* get the file instance from the tsm data before freeing it */
|
||||
instance = bacfile_instance_from_tsm(service_data->invoke_id);
|
||||
len = arf_ack_decode_service_request(service_request,
|
||||
service_len, &data);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Received Read-File Ack!\n");
|
||||
#endif
|
||||
if ((len > 0) && (instance <= BACNET_MAX_INSTANCE)) {
|
||||
/* write the data received to the file specified */
|
||||
if (data.access == FILE_STREAM_ACCESS) {
|
||||
pFilename = bacfile_name(instance);
|
||||
if (pFilename) {
|
||||
pFile = fopen(pFilename, "rb");
|
||||
if (pFile) {
|
||||
(void) fseek(pFile,
|
||||
data.type.stream.fileStartPosition, SEEK_SET);
|
||||
if (fwrite(octetstring_value(&data.fileData),
|
||||
octetstring_length(&data.fileData), 1,
|
||||
pFile) != 1) {
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Failed to write to %s (%u)!\n",
|
||||
pFilename, instance);
|
||||
#endif
|
||||
}
|
||||
fclose(pFile);
|
||||
}
|
||||
}
|
||||
} else if (data.access == FILE_RECORD_ACCESS) {
|
||||
/* FIXME: add handling for Record Access */
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1,128 +0,0 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2006 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include "config.h"
|
||||
#include "txbuf.h"
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "bacerror.h"
|
||||
#include "apdu.h"
|
||||
#include "npdu.h"
|
||||
#include "abort.h"
|
||||
#include "reject.h"
|
||||
#include "dcc.h"
|
||||
|
||||
static char *My_Password = "filister";
|
||||
|
||||
void handler_device_communication_control(uint8_t * service_request,
|
||||
uint16_t service_len,
|
||||
BACNET_ADDRESS * src, BACNET_CONFIRMED_SERVICE_DATA * service_data)
|
||||
{
|
||||
uint16_t timeDuration = 0;
|
||||
BACNET_COMMUNICATION_ENABLE_DISABLE state = COMMUNICATION_ENABLE;
|
||||
BACNET_CHARACTER_STRING password;
|
||||
int len = 0;
|
||||
int pdu_len = 0;
|
||||
int bytes_sent = 0;
|
||||
BACNET_NPDU_DATA npdu_data;
|
||||
BACNET_ADDRESS my_address;
|
||||
|
||||
/* decode the service request only */
|
||||
len = dcc_decode_service_request(service_request,
|
||||
service_len, &timeDuration, &state, &password);
|
||||
/* encode the NPDU portion of the packet */
|
||||
datalink_get_my_address(&my_address);
|
||||
npdu_encode_npdu_data(&npdu_data, false, MESSAGE_PRIORITY_NORMAL);
|
||||
pdu_len = npdu_encode_pdu(&Handler_Transmit_Buffer[0], src,
|
||||
&my_address, &npdu_data);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "DeviceCommunicationControl!\n");
|
||||
if (len > 0)
|
||||
fprintf(stderr, "DeviceCommunicationControl: "
|
||||
"timeout=%u state=%u password=%s\n",
|
||||
(unsigned) timeDuration,
|
||||
(unsigned) state, characterstring_value(&password));
|
||||
#endif
|
||||
/* bad decoding or something we didn't understand - send an abort */
|
||||
if (len < 0) {
|
||||
len = abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id, ABORT_REASON_OTHER, true);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "DeviceCommunicationControl: "
|
||||
"Sending Abort - could not decode.\n");
|
||||
#endif
|
||||
} else if (service_data->segmented_message) {
|
||||
len = abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
ABORT_REASON_SEGMENTATION_NOT_SUPPORTED, true);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "DeviceCommunicationControl: "
|
||||
"Sending Abort - segmented message.\n");
|
||||
#endif
|
||||
} else if (state >= MAX_BACNET_COMMUNICATION_ENABLE_DISABLE) {
|
||||
len = reject_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id, REJECT_REASON_UNDEFINED_ENUMERATION);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "DeviceCommunicationControl: "
|
||||
"Sending Reject - undefined enumeration\n");
|
||||
#endif
|
||||
} else {
|
||||
if (characterstring_ansi_same(&password, My_Password)) {
|
||||
len = encode_simple_ack(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "DeviceCommunicationControl: "
|
||||
"Sending Simple Ack!\n");
|
||||
#endif
|
||||
dcc_set_status_duration(state, timeDuration);
|
||||
} else {
|
||||
len =
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL,
|
||||
ERROR_CLASS_SERVICES, ERROR_CODE_PASSWORD_FAILURE);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr,
|
||||
"DeviceCommunicationControl: "
|
||||
"Sending Error - password failure.\n");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
pdu_len += len;
|
||||
bytes_sent = datalink_send_pdu(src, &npdu_data,
|
||||
&Handler_Transmit_Buffer[0], pdu_len);
|
||||
#if PRINT_ENABLED
|
||||
if (bytes_sent <= 0)
|
||||
fprintf(stderr, "DeviceCommunicationControl: "
|
||||
"Failed to send PDU (%s)!\n", strerror(errno));
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include "config.h"
|
||||
#include "txbuf.h"
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "iam.h"
|
||||
#include "address.h"
|
||||
|
||||
void handler_i_am_add(uint8_t * service_request,
|
||||
uint16_t service_len, BACNET_ADDRESS * src)
|
||||
{
|
||||
int len = 0;
|
||||
uint32_t device_id = 0;
|
||||
unsigned max_apdu = 0;
|
||||
int segmentation = 0;
|
||||
uint16_t vendor_id = 0;
|
||||
|
||||
(void) service_len;
|
||||
len = iam_decode_service_request(service_request,
|
||||
&device_id, &max_apdu, &segmentation, &vendor_id);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Received I-Am Request");
|
||||
#endif
|
||||
if (len != -1) {
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, " from %u!\n", device_id);
|
||||
#endif
|
||||
address_add(device_id, max_apdu, src);
|
||||
} else {
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "!\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void handler_i_am_bind(uint8_t * service_request,
|
||||
uint16_t service_len, BACNET_ADDRESS * src)
|
||||
{
|
||||
int len = 0;
|
||||
uint32_t device_id = 0;
|
||||
unsigned max_apdu = 0;
|
||||
int segmentation = 0;
|
||||
uint16_t vendor_id = 0;
|
||||
|
||||
(void) service_len;
|
||||
len = iam_decode_service_request(service_request,
|
||||
&device_id, &max_apdu, &segmentation, &vendor_id);
|
||||
/* only add address if requested to bind */
|
||||
address_add_binding(device_id, max_apdu, src);
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2006 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include "config.h"
|
||||
#include "txbuf.h"
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "bactext.h"
|
||||
#include "ihave.h"
|
||||
|
||||
void handler_i_have(uint8_t * service_request,
|
||||
uint16_t service_len, BACNET_ADDRESS * src)
|
||||
{
|
||||
int len = 0;
|
||||
BACNET_I_HAVE_DATA data;
|
||||
|
||||
(void) service_len;
|
||||
(void) src;
|
||||
len = ihave_decode_service_request(service_request,
|
||||
service_len, &data);
|
||||
if (len != -1) {
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "I-Have: %s %d from %s %u!\r\n",
|
||||
bactext_object_type_name(data.object_id.type),
|
||||
data.object_id.instance,
|
||||
bactext_object_type_name(data.device_id.type),
|
||||
data.device_id.instance);
|
||||
#endif
|
||||
} else {
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "I-Have: received, but unable to decode!\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -1,130 +0,0 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2006 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include "config.h"
|
||||
#include "txbuf.h"
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "bacerror.h"
|
||||
#include "apdu.h"
|
||||
#include "npdu.h"
|
||||
#include "abort.h"
|
||||
#include "reject.h"
|
||||
#include "rd.h"
|
||||
|
||||
static char *Password = "Jesus";
|
||||
static BACNET_CHARACTER_STRING My_Password;
|
||||
|
||||
void handler_reinitialize_device(uint8_t * service_request,
|
||||
uint16_t service_len,
|
||||
BACNET_ADDRESS * src, BACNET_CONFIRMED_SERVICE_DATA * service_data)
|
||||
{
|
||||
BACNET_REINITIALIZED_STATE state;
|
||||
BACNET_CHARACTER_STRING their_password;
|
||||
int len = 0;
|
||||
int pdu_len = 0;
|
||||
BACNET_NPDU_DATA npdu_data;
|
||||
int bytes_sent = 0;
|
||||
BACNET_ADDRESS my_address;
|
||||
|
||||
/* decode the service request only */
|
||||
len = rd_decode_service_request(service_request,
|
||||
service_len, &state, &their_password);
|
||||
/* encode the NPDU portion of the packet */
|
||||
datalink_get_my_address(&my_address);
|
||||
npdu_encode_npdu_data(&npdu_data, false, MESSAGE_PRIORITY_NORMAL);
|
||||
pdu_len = npdu_encode_pdu(&Handler_Transmit_Buffer[0], src,
|
||||
&my_address, &npdu_data);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "ReinitializeDevice!\n");
|
||||
if (len > 0)
|
||||
fprintf(stderr, "ReinitializeDevice: state=%u password=%s\n",
|
||||
(unsigned) state, characterstring_value(&their_password));
|
||||
else
|
||||
fprintf(stderr, "ReinitializeDevice: Unable to decode request!\n");
|
||||
#endif
|
||||
/* bad decoding or something we didn't understand - send an abort */
|
||||
if (len < 0) {
|
||||
len = abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id, ABORT_REASON_OTHER, true);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr,
|
||||
"ReinitializeDevice: Sending Abort - could not decode.\n");
|
||||
#endif
|
||||
} else if (service_data->segmented_message) {
|
||||
len = abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
ABORT_REASON_SEGMENTATION_NOT_SUPPORTED, true);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr,
|
||||
"ReinitializeDevice: Sending Abort - segmented message.\n");
|
||||
#endif
|
||||
} else if (state >= MAX_BACNET_REINITIALIZED_STATE) {
|
||||
len = reject_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id, REJECT_REASON_UNDEFINED_ENUMERATION);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr,
|
||||
"ReinitializeDevice: Sending Reject - undefined enumeration\n");
|
||||
#endif
|
||||
} else {
|
||||
characterstring_init_ansi(&My_Password, Password);
|
||||
if (characterstring_same(&their_password, &My_Password)) {
|
||||
len = encode_simple_ack(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_REINITIALIZE_DEVICE);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "ReinitializeDevice: Sending Simple Ack!\n");
|
||||
#endif
|
||||
/* FIXME: now you can reboot, restart, quit, or something clever */
|
||||
/* Note: you can use a mix of state and password to do specific stuff */
|
||||
/* Note: if you don't do something clever like actually restart,
|
||||
you probably should clear any DCC status and timeouts */
|
||||
} else {
|
||||
len =
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_REINITIALIZE_DEVICE,
|
||||
ERROR_CLASS_SERVICES, ERROR_CODE_PASSWORD_FAILURE);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr,
|
||||
"ReinitializeDevice: Sending Error - password failure.\n");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
pdu_len += len;
|
||||
bytes_sent = datalink_send_pdu(src, &npdu_data,
|
||||
&Handler_Transmit_Buffer[0], pdu_len);
|
||||
#if PRINT_ENABLED
|
||||
if (bytes_sent <= 0)
|
||||
fprintf(stderr, "ReinitializeDevice: Failed to send PDU (%s)!\n",
|
||||
strerror(errno));
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -1,368 +0,0 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include "config.h"
|
||||
#include "txbuf.h"
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "apdu.h"
|
||||
#include "npdu.h"
|
||||
#include "abort.h"
|
||||
#include "rp.h"
|
||||
/* demo objects */
|
||||
#include "device.h"
|
||||
#include "ai.h"
|
||||
#include "ao.h"
|
||||
#include "av.h"
|
||||
#include "bi.h"
|
||||
#include "bo.h"
|
||||
#include "bv.h"
|
||||
#include "lc.h"
|
||||
#include "lsp.h"
|
||||
#include "mso.h"
|
||||
#if BACFILE
|
||||
#include "bacfile.h"
|
||||
#endif
|
||||
|
||||
static uint8_t Temp_Buf[MAX_APDU] = { 0 };
|
||||
|
||||
void handler_read_property(uint8_t * service_request,
|
||||
uint16_t service_len,
|
||||
BACNET_ADDRESS * src, BACNET_CONFIRMED_SERVICE_DATA * service_data)
|
||||
{
|
||||
BACNET_READ_PROPERTY_DATA data;
|
||||
int len = 0;
|
||||
int pdu_len = 0;
|
||||
BACNET_NPDU_DATA npdu_data;
|
||||
bool error = false;
|
||||
int bytes_sent = 0;
|
||||
BACNET_ERROR_CLASS error_class = ERROR_CLASS_OBJECT;
|
||||
BACNET_ERROR_CODE error_code = ERROR_CODE_UNKNOWN_OBJECT;
|
||||
BACNET_ADDRESS my_address;
|
||||
|
||||
len = rp_decode_service_request(service_request, service_len, &data);
|
||||
/* encode the NPDU portion of the packet */
|
||||
datalink_get_my_address(&my_address);
|
||||
npdu_encode_npdu_data(&npdu_data, false, MESSAGE_PRIORITY_NORMAL);
|
||||
pdu_len = npdu_encode_pdu(&Handler_Transmit_Buffer[0], src,
|
||||
&my_address, &npdu_data);
|
||||
#if PRINT_ENABLED
|
||||
if (len <= 0)
|
||||
fprintf(stderr, "Unable to decode Read-Property Request!\n");
|
||||
#endif
|
||||
if (len < 0) {
|
||||
/* bad decoding - send an abort */
|
||||
len = abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id, ABORT_REASON_OTHER, true);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Sending Abort!\n");
|
||||
#endif
|
||||
} else if (service_data->segmented_message) {
|
||||
/* we don't support segmentation - send an abort */
|
||||
len = abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
ABORT_REASON_SEGMENTATION_NOT_SUPPORTED, true);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Sending Abort!\n");
|
||||
#endif
|
||||
} else {
|
||||
/* most cases will be error */
|
||||
error = true;
|
||||
switch (data.object_type) {
|
||||
case OBJECT_DEVICE:
|
||||
/* FIXME: probably need a length limitation sent with encode */
|
||||
if (data.object_instance == Device_Object_Instance_Number()) {
|
||||
len = Device_Encode_Property_APDU(&Temp_Buf[0],
|
||||
data.object_property,
|
||||
data.array_index, &error_class, &error_code);
|
||||
if (len >= 0) {
|
||||
/* encode the APDU portion of the packet */
|
||||
data.application_data = &Temp_Buf[0];
|
||||
data.application_data_len = len;
|
||||
/* FIXME: probably need a length limitation sent with encode */
|
||||
len =
|
||||
rp_ack_encode_apdu(&Handler_Transmit_Buffer
|
||||
[pdu_len], service_data->invoke_id, &data);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr,
|
||||
"Sending Read Property Ack for Device!\n");
|
||||
#endif
|
||||
error = false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case OBJECT_ANALOG_INPUT:
|
||||
if (Analog_Input_Valid_Instance(data.object_instance)) {
|
||||
len = Analog_Input_Encode_Property_APDU(&Temp_Buf[0],
|
||||
data.object_instance,
|
||||
data.object_property,
|
||||
data.array_index, &error_class, &error_code);
|
||||
if (len >= 0) {
|
||||
/* encode the APDU portion of the packet */
|
||||
data.application_data = &Temp_Buf[0];
|
||||
data.application_data_len = len;
|
||||
/* FIXME: probably need a length limitation sent with encode */
|
||||
len =
|
||||
rp_ack_encode_apdu(&Handler_Transmit_Buffer
|
||||
[pdu_len], service_data->invoke_id, &data);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Sending Read Property Ack for AI!\n");
|
||||
#endif
|
||||
error = false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case OBJECT_BINARY_INPUT:
|
||||
if (Binary_Input_Valid_Instance(data.object_instance)) {
|
||||
len = Binary_Input_Encode_Property_APDU(&Temp_Buf[0],
|
||||
data.object_instance,
|
||||
data.object_property,
|
||||
data.array_index, &error_class, &error_code);
|
||||
if (len >= 0) {
|
||||
/* encode the APDU portion of the packet */
|
||||
data.application_data = &Temp_Buf[0];
|
||||
data.application_data_len = len;
|
||||
/* FIXME: probably need a length limitation sent with encode */
|
||||
len =
|
||||
rp_ack_encode_apdu(&Handler_Transmit_Buffer
|
||||
[pdu_len], service_data->invoke_id, &data);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Sending Read Property Ack for BI!\n");
|
||||
#endif
|
||||
error = false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case OBJECT_BINARY_OUTPUT:
|
||||
if (Binary_Output_Valid_Instance(data.object_instance)) {
|
||||
len = Binary_Output_Encode_Property_APDU(&Temp_Buf[0],
|
||||
data.object_instance,
|
||||
data.object_property,
|
||||
data.array_index, &error_class, &error_code);
|
||||
if (len >= 0) {
|
||||
/* encode the APDU portion of the packet */
|
||||
data.application_data = &Temp_Buf[0];
|
||||
data.application_data_len = len;
|
||||
/* FIXME: probably need a length limitation sent with encode */
|
||||
len =
|
||||
rp_ack_encode_apdu(&Handler_Transmit_Buffer
|
||||
[pdu_len], service_data->invoke_id, &data);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Sending Read Property Ack for BO!\n");
|
||||
#endif
|
||||
error = false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case OBJECT_BINARY_VALUE:
|
||||
if (Binary_Value_Valid_Instance(data.object_instance)) {
|
||||
len = Binary_Value_Encode_Property_APDU(&Temp_Buf[0],
|
||||
data.object_instance,
|
||||
data.object_property,
|
||||
data.array_index, &error_class, &error_code);
|
||||
if (len >= 0) {
|
||||
/* encode the APDU portion of the packet */
|
||||
data.application_data = &Temp_Buf[0];
|
||||
data.application_data_len = len;
|
||||
/* FIXME: probably need a length limitation sent with encode */
|
||||
len =
|
||||
rp_ack_encode_apdu(&Handler_Transmit_Buffer
|
||||
[pdu_len], service_data->invoke_id, &data);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Sending Read Property Ack for BV!\n");
|
||||
#endif
|
||||
error = false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case OBJECT_ANALOG_OUTPUT:
|
||||
if (Analog_Output_Valid_Instance(data.object_instance)) {
|
||||
len = Analog_Output_Encode_Property_APDU(&Temp_Buf[0],
|
||||
data.object_instance,
|
||||
data.object_property,
|
||||
data.array_index, &error_class, &error_code);
|
||||
if (len >= 0) {
|
||||
/* encode the APDU portion of the packet */
|
||||
data.application_data = &Temp_Buf[0];
|
||||
data.application_data_len = len;
|
||||
/* FIXME: probably need a length limitation sent with encode */
|
||||
len =
|
||||
rp_ack_encode_apdu(&Handler_Transmit_Buffer
|
||||
[pdu_len], service_data->invoke_id, &data);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Sending Read Property Ack for AO!\n");
|
||||
#endif
|
||||
error = false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case OBJECT_ANALOG_VALUE:
|
||||
if (Analog_Value_Valid_Instance(data.object_instance)) {
|
||||
len = Analog_Value_Encode_Property_APDU(&Temp_Buf[0],
|
||||
data.object_instance,
|
||||
data.object_property,
|
||||
data.array_index, &error_class, &error_code);
|
||||
if (len >= 0) {
|
||||
/* encode the APDU portion of the packet */
|
||||
data.application_data = &Temp_Buf[0];
|
||||
data.application_data_len = len;
|
||||
/* FIXME: probably need a length limitation sent with encode */
|
||||
len =
|
||||
rp_ack_encode_apdu(&Handler_Transmit_Buffer
|
||||
[pdu_len], service_data->invoke_id, &data);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Sending Read Property Ack for AV!\n");
|
||||
#endif
|
||||
error = false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case OBJECT_LIFE_SAFETY_POINT:
|
||||
if (Life_Safety_Point_Valid_Instance(data.object_instance)) {
|
||||
len = Life_Safety_Point_Encode_Property_APDU(&Temp_Buf[0],
|
||||
data.object_instance,
|
||||
data.object_property,
|
||||
data.array_index, &error_class, &error_code);
|
||||
if (len >= 0) {
|
||||
/* encode the APDU portion of the packet */
|
||||
data.application_data = &Temp_Buf[0];
|
||||
data.application_data_len = len;
|
||||
/* FIXME: probably need a length limitation sent with encode */
|
||||
len =
|
||||
rp_ack_encode_apdu(&Handler_Transmit_Buffer
|
||||
[pdu_len], service_data->invoke_id, &data);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr,
|
||||
"Sending Read Property Ack for LSP!\n");
|
||||
#endif
|
||||
error = false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case OBJECT_LOAD_CONTROL:
|
||||
if (Load_Control_Valid_Instance(data.object_instance)) {
|
||||
len = Load_Control_Encode_Property_APDU(&Temp_Buf[0],
|
||||
data.object_instance,
|
||||
data.object_property,
|
||||
data.array_index, &error_class, &error_code);
|
||||
if (len >= 0) {
|
||||
/* encode the APDU portion of the packet */
|
||||
data.application_data = &Temp_Buf[0];
|
||||
data.application_data_len = len;
|
||||
/* FIXME: probably need a length limitation sent with encode */
|
||||
len =
|
||||
rp_ack_encode_apdu(&Handler_Transmit_Buffer
|
||||
[pdu_len], service_data->invoke_id, &data);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr,
|
||||
"Sending Read Property Ack for Load Control!\n");
|
||||
#endif
|
||||
error = false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case OBJECT_MULTI_STATE_OUTPUT:
|
||||
if (Multistate_Output_Valid_Instance(data.object_instance)) {
|
||||
len = Multistate_Output_Encode_Property_APDU(&Temp_Buf[0],
|
||||
data.object_instance,
|
||||
data.object_property,
|
||||
data.array_index, &error_class, &error_code);
|
||||
if (len >= 0) {
|
||||
/* encode the APDU portion of the packet */
|
||||
data.application_data = &Temp_Buf[0];
|
||||
data.application_data_len = len;
|
||||
/* FIXME: probably need a length limitation sent with encode */
|
||||
len =
|
||||
rp_ack_encode_apdu(&Handler_Transmit_Buffer
|
||||
[pdu_len], service_data->invoke_id, &data);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr,
|
||||
"Sending Read Property Ack for MSO!\n");
|
||||
#endif
|
||||
error = false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
#if BACFILE
|
||||
case OBJECT_FILE:
|
||||
if (bacfile_valid_instance(data.object_instance)) {
|
||||
len = bacfile_encode_property_apdu(&Temp_Buf[0],
|
||||
data.object_instance,
|
||||
data.object_property,
|
||||
data.array_index, &error_class, &error_code);
|
||||
if (len >= 0) {
|
||||
/* encode the APDU portion of the packet */
|
||||
data.application_data = &Temp_Buf[0];
|
||||
data.application_data_len = len;
|
||||
/* FIXME: probably need a length limitation sent with encode */
|
||||
len =
|
||||
rp_ack_encode_apdu(&Handler_Transmit_Buffer
|
||||
[pdu_len], service_data->invoke_id, &data);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr,
|
||||
"Sending Read Property Ack for File!\n");
|
||||
#endif
|
||||
error = false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif /* BACFILE */
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (error) {
|
||||
switch (len) {
|
||||
/* BACnet APDU too small to fit data, so proper response is Abort */
|
||||
case -2:
|
||||
len = abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
ABORT_REASON_SEGMENTATION_NOT_SUPPORTED, true);
|
||||
break;
|
||||
case -1:
|
||||
default:
|
||||
len = bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_READ_PROPERTY, error_class, error_code);
|
||||
break;
|
||||
}
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Sending Read Property Error!\n");
|
||||
#endif
|
||||
}
|
||||
pdu_len += len;
|
||||
bytes_sent = datalink_send_pdu(src, &npdu_data,
|
||||
&Handler_Transmit_Buffer[0], pdu_len);
|
||||
#if PRINT_ENABLED
|
||||
if (bytes_sent <= 0)
|
||||
fprintf(stderr, "Failed to send PDU (%s)!\n", strerror(errno));
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -1,114 +0,0 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include "config.h"
|
||||
#include "config.h"
|
||||
#include "txbuf.h"
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "address.h"
|
||||
#include "tsm.h"
|
||||
#include "npdu.h"
|
||||
#include "apdu.h"
|
||||
#include "device.h"
|
||||
#include "datalink.h"
|
||||
#include "bactext.h"
|
||||
#include "rp.h"
|
||||
/* some demo stuff needed */
|
||||
#include "handlers.h"
|
||||
#include "txbuf.h"
|
||||
|
||||
/* for debugging... */
|
||||
static void PrintReadPropertyData(BACNET_READ_PROPERTY_DATA * data)
|
||||
{
|
||||
BACNET_APPLICATION_DATA_VALUE value; /* for decode value data */
|
||||
int len = 0;
|
||||
uint8_t *application_data;
|
||||
int application_data_len;
|
||||
bool first_value = true;
|
||||
bool print_brace = false;
|
||||
|
||||
if (data) {
|
||||
#if 0
|
||||
if (data->array_index == BACNET_ARRAY_ALL)
|
||||
fprintf(stderr, "%s #%u %s\n",
|
||||
bactext_object_type_name(data->object_type),
|
||||
data->object_instance,
|
||||
bactext_property_name(data->object_property));
|
||||
else
|
||||
fprintf(stderr, "%s #%u %s[%d]\n",
|
||||
bactext_object_type_name(data->object_type),
|
||||
data->object_instance,
|
||||
bactext_property_name(data->object_property),
|
||||
data->array_index);
|
||||
#endif
|
||||
application_data = data->application_data;
|
||||
application_data_len = data->application_data_len;
|
||||
/* FIXME: what if application_data_len is bigger than 255? */
|
||||
/* value? need to loop until all of the len is gone... */
|
||||
for (;;) {
|
||||
len = bacapp_decode_application_data(application_data,
|
||||
(uint8_t) application_data_len, &value);
|
||||
if (first_value && (len < application_data_len)) {
|
||||
first_value = false;
|
||||
fprintf(stdout, "{");
|
||||
print_brace = true;
|
||||
}
|
||||
bacapp_print_value(stdout, &value, data->object_property);
|
||||
if (len) {
|
||||
if (len < application_data_len) {
|
||||
application_data += len;
|
||||
application_data_len -= len;
|
||||
/* there's more! */
|
||||
fprintf(stdout, ",");
|
||||
} else
|
||||
break;
|
||||
} else
|
||||
break;
|
||||
}
|
||||
if (print_brace)
|
||||
fprintf(stdout, "}");
|
||||
fprintf(stdout, "\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
void handler_read_property_ack(uint8_t * service_request,
|
||||
uint16_t service_len,
|
||||
BACNET_ADDRESS * src, BACNET_CONFIRMED_SERVICE_ACK_DATA * service_data)
|
||||
{
|
||||
int len = 0;
|
||||
BACNET_READ_PROPERTY_DATA data;
|
||||
|
||||
(void) src;
|
||||
(void) service_data; /* we could use these... */
|
||||
len = rp_ack_decode_service_request(service_request,
|
||||
service_len, &data);
|
||||
#if 0
|
||||
fprintf(stderr, "Received Read-Property Ack!\n");
|
||||
#endif
|
||||
if (len > 0)
|
||||
PrintReadPropertyData(&data);
|
||||
}
|
||||
@@ -1,122 +0,0 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2006 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include "config.h"
|
||||
#include "txbuf.h"
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "bacerror.h"
|
||||
#include "apdu.h"
|
||||
#include "npdu.h"
|
||||
#include "abort.h"
|
||||
#include "rp.h"
|
||||
/* demo objects */
|
||||
#include "device.h"
|
||||
|
||||
/* note: this is a minimal handler. See h_rp.c for another */
|
||||
|
||||
static uint8_t Temp_Buf[MAX_APDU] = { 0 };
|
||||
|
||||
void handler_read_property(uint8_t * service_request,
|
||||
uint16_t service_len,
|
||||
BACNET_ADDRESS * src, BACNET_CONFIRMED_SERVICE_DATA * service_data)
|
||||
{
|
||||
BACNET_READ_PROPERTY_DATA data;
|
||||
int len = 0;
|
||||
int pdu_len = 0;
|
||||
BACNET_NPDU_DATA npdu_data;
|
||||
bool send = false;
|
||||
bool error = false;
|
||||
int bytes_sent = 0;
|
||||
BACNET_ERROR_CLASS error_class = ERROR_CLASS_OBJECT;
|
||||
BACNET_ERROR_CODE error_code = ERROR_CODE_UNKNOWN_OBJECT;
|
||||
BACNET_ADDRESS my_address;
|
||||
|
||||
len = rp_decode_service_request(service_request, service_len, &data);
|
||||
/* encode the NPDU portion of the packet */
|
||||
datalink_get_my_address(&my_address);
|
||||
npdu_encode_npdu_data(&npdu_data, false, MESSAGE_PRIORITY_NORMAL);
|
||||
pdu_len = npdu_encode_pdu(&Handler_Transmit_Buffer[0], src,
|
||||
&my_address, &npdu_data);
|
||||
if (len < 0) {
|
||||
/* bad decoding - send an abort */
|
||||
len = abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id, ABORT_REASON_OTHER, true);
|
||||
} else if (service_data->segmented_message) {
|
||||
/* we don't support segmentation - send an abort */
|
||||
len = abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
ABORT_REASON_SEGMENTATION_NOT_SUPPORTED, true);
|
||||
} else {
|
||||
/* most cases will be error */
|
||||
error = true;
|
||||
switch (data.object_type) {
|
||||
case OBJECT_DEVICE:
|
||||
/* FIXME: probably need a length limitation sent with encode */
|
||||
if (data.object_instance == Device_Object_Instance_Number()) {
|
||||
len = Device_Encode_Property_APDU(&Temp_Buf[0],
|
||||
data.object_property,
|
||||
data.array_index, &error_class, &error_code);
|
||||
if (len >= 0) {
|
||||
/* encode the APDU portion of the packet */
|
||||
data.application_data = &Temp_Buf[0];
|
||||
data.application_data_len = len;
|
||||
/* FIXME: probably need a length limitation sent with encode */
|
||||
len =
|
||||
rp_ack_encode_apdu(&Handler_Transmit_Buffer
|
||||
[pdu_len], service_data->invoke_id, &data);
|
||||
error = false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (error) {
|
||||
switch (len) {
|
||||
/* BACnet APDU too small to fit data, so proper response is Abort */
|
||||
case -2:
|
||||
len = abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
ABORT_REASON_SEGMENTATION_NOT_SUPPORTED, true);
|
||||
break;
|
||||
case -1:
|
||||
default:
|
||||
len = bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_READ_PROPERTY, error_class, error_code);
|
||||
break;
|
||||
}
|
||||
}
|
||||
pdu_len += len;
|
||||
bytes_sent = datalink_send_pdu(src, &npdu_data,
|
||||
&Handler_Transmit_Buffer[0], pdu_len);
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2006 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include "config.h"
|
||||
#include "txbuf.h"
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "timesync.h"
|
||||
|
||||
static void show_bacnet_date_time(BACNET_DATE * bdate, BACNET_TIME * btime)
|
||||
{
|
||||
/* show the date received */
|
||||
fprintf(stderr, "%u", (unsigned) bdate->year);
|
||||
fprintf(stderr, "/%u", (unsigned) bdate->month);
|
||||
fprintf(stderr, "/%u", (unsigned) bdate->day);
|
||||
/* show the time received */
|
||||
fprintf(stderr, " %02u", (unsigned) btime->hour);
|
||||
fprintf(stderr, ":%02u", (unsigned) btime->min);
|
||||
fprintf(stderr, ":%02u", (unsigned) btime->sec);
|
||||
fprintf(stderr, ".%02u", (unsigned) btime->hundredths);
|
||||
fprintf(stderr, "\r\n");
|
||||
}
|
||||
|
||||
void handler_timesync(uint8_t * service_request,
|
||||
uint16_t service_len, BACNET_ADDRESS * src)
|
||||
{
|
||||
int len = 0;
|
||||
BACNET_DATE bdate;
|
||||
BACNET_TIME btime;
|
||||
|
||||
(void) src;
|
||||
(void) service_len;
|
||||
len = timesync_decode_service_request(service_request,
|
||||
service_len, &bdate, &btime);
|
||||
fprintf(stderr, "Received TimeSyncronization Request\r\n");
|
||||
show_bacnet_date_time(&bdate, &btime);
|
||||
/* FIXME: set the time? */
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void handler_timesync_utc(uint8_t * service_request,
|
||||
uint16_t service_len, BACNET_ADDRESS * src)
|
||||
{
|
||||
int len = 0;
|
||||
BACNET_DATE bdate;
|
||||
BACNET_TIME btime;
|
||||
|
||||
(void) src;
|
||||
(void) service_len;
|
||||
len = timesync_decode_service_request(service_request,
|
||||
service_len, &bdate, &btime);
|
||||
fprintf(stderr, "Received TimeSyncronization Request\r\n");
|
||||
show_bacnet_date_time(&bdate, &btime);
|
||||
/* FIXME: set the time? */
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2006 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include "config.h"
|
||||
#include "txbuf.h"
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "whohas.h"
|
||||
#include "device.h"
|
||||
#include "client.h"
|
||||
|
||||
void handler_who_has(uint8_t * service_request,
|
||||
uint16_t service_len, BACNET_ADDRESS * src)
|
||||
{
|
||||
int len = 0;
|
||||
BACNET_WHO_HAS_DATA data;
|
||||
bool directed_to_me = false;
|
||||
int object_type = 0;
|
||||
uint32_t object_instance = 0;
|
||||
char *object_name = NULL;
|
||||
bool found = false;
|
||||
|
||||
(void) src;
|
||||
len = whohas_decode_service_request(service_request,
|
||||
service_len, &data);
|
||||
if (len > 0) {
|
||||
if ((data.low_limit == -1) || (data.high_limit == -1))
|
||||
directed_to_me = true;
|
||||
else if ((Device_Object_Instance_Number() >=
|
||||
(uint32_t) data.low_limit)
|
||||
&& (Device_Object_Instance_Number() <=
|
||||
(uint32_t) data.high_limit))
|
||||
directed_to_me = true;
|
||||
if (directed_to_me) {
|
||||
/* do we have such an object? If so, send an I-Have.
|
||||
note: we should have only 1 of such an object */
|
||||
if (data.object_name) {
|
||||
/* valid name in my device? */
|
||||
object_name = characterstring_value(&data.object.name);
|
||||
found = Device_Valid_Object_Name(object_name,
|
||||
&object_type, &object_instance);
|
||||
if (found)
|
||||
Send_I_Have(Device_Object_Instance_Number(),
|
||||
object_type, object_instance, object_name);
|
||||
} else {
|
||||
/* valid object in my device? */
|
||||
object_name =
|
||||
Device_Valid_Object_Id(data.object.identifier.type,
|
||||
data.object.identifier.instance);
|
||||
if (object_name)
|
||||
Send_I_Have(Device_Object_Instance_Number(),
|
||||
data.object.identifier.type,
|
||||
data.object.identifier.instance, object_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include "config.h"
|
||||
#include "txbuf.h"
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "whois.h"
|
||||
#include "iam.h"
|
||||
#include "device.h"
|
||||
#include "client.h"
|
||||
#include "txbuf.h"
|
||||
|
||||
void handler_who_is(uint8_t * service_request,
|
||||
uint16_t service_len, BACNET_ADDRESS * src)
|
||||
{
|
||||
int len = 0;
|
||||
int32_t low_limit = 0;
|
||||
int32_t high_limit = 0;
|
||||
|
||||
(void) src;
|
||||
len = whois_decode_service_request(service_request,
|
||||
service_len, &low_limit, &high_limit);
|
||||
/* in our simple system, we just set a flag and let the main loop
|
||||
send the I-Am request. */
|
||||
if (len == 0)
|
||||
iam_send(&Handler_Transmit_Buffer[0]);
|
||||
else if (len != -1) {
|
||||
/* is my device id within the limits? */
|
||||
if (((Device_Object_Instance_Number() >= (uint32_t) low_limit) &&
|
||||
(Device_Object_Instance_Number() <= (uint32_t) high_limit))
|
||||
||
|
||||
/* BACnet wildcard is the max instance number - everyone responds */
|
||||
((BACNET_MAX_INSTANCE >= (uint32_t) low_limit) &&
|
||||
(BACNET_MAX_INSTANCE <= (uint32_t) high_limit)))
|
||||
iam_send(&Handler_Transmit_Buffer[0]);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -1,333 +0,0 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include "config.h"
|
||||
#include "txbuf.h"
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "apdu.h"
|
||||
#include "npdu.h"
|
||||
#include "abort.h"
|
||||
#include "wp.h"
|
||||
/* demo objects */
|
||||
#include "device.h"
|
||||
#include "ai.h"
|
||||
#include "ao.h"
|
||||
#include "av.h"
|
||||
#include "bi.h"
|
||||
#include "bo.h"
|
||||
#include "bv.h"
|
||||
#include "lc.h"
|
||||
#include "lsp.h"
|
||||
#include "mso.h"
|
||||
#if BACFILE
|
||||
#include "bacfile.h"
|
||||
#endif
|
||||
|
||||
void handler_write_property(uint8_t * service_request,
|
||||
uint16_t service_len,
|
||||
BACNET_ADDRESS * src, BACNET_CONFIRMED_SERVICE_DATA * service_data)
|
||||
{
|
||||
BACNET_WRITE_PROPERTY_DATA wp_data;
|
||||
int len = 0;
|
||||
int pdu_len = 0;
|
||||
BACNET_NPDU_DATA npdu_data;
|
||||
BACNET_ERROR_CLASS error_class = ERROR_CLASS_OBJECT;
|
||||
BACNET_ERROR_CODE error_code = ERROR_CODE_UNKNOWN_OBJECT;
|
||||
int bytes_sent = 0;
|
||||
BACNET_ADDRESS my_address;
|
||||
|
||||
/* decode the service request only */
|
||||
len = wp_decode_service_request(service_request,
|
||||
service_len, &wp_data);
|
||||
/* encode the NPDU portion of the packet */
|
||||
datalink_get_my_address(&my_address);
|
||||
npdu_encode_npdu_data(&npdu_data, false, MESSAGE_PRIORITY_NORMAL);
|
||||
pdu_len = npdu_encode_pdu(&Handler_Transmit_Buffer[0], src,
|
||||
&my_address, &npdu_data);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Received Write-Property Request!\n");
|
||||
if (len > 0)
|
||||
fprintf(stderr, "type=%u instance=%u property=%u index=%d\n",
|
||||
wp_data.object_type,
|
||||
wp_data.object_instance,
|
||||
wp_data.object_property, wp_data.array_index);
|
||||
else
|
||||
fprintf(stderr, "Unable to decode Write-Property Request!\n");
|
||||
#endif
|
||||
/* bad decoding or something we didn't understand - send an abort */
|
||||
if (len <= 0) {
|
||||
len = abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id, ABORT_REASON_OTHER, true);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Sending Abort!\n");
|
||||
#endif
|
||||
} else if (service_data->segmented_message) {
|
||||
len = abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
ABORT_REASON_SEGMENTATION_NOT_SUPPORTED, true);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Sending Abort!\n");
|
||||
#endif
|
||||
} else {
|
||||
switch (wp_data.object_type) {
|
||||
case OBJECT_DEVICE:
|
||||
if (Device_Write_Property(&wp_data, &error_class, &error_code)) {
|
||||
len =
|
||||
encode_simple_ack(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr,
|
||||
"Sending Write Property Simple Ack for Device!\n");
|
||||
#endif
|
||||
} else {
|
||||
len =
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY, error_class,
|
||||
error_code);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr,
|
||||
"Sending Write Property Error for Device!\n");
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case OBJECT_ANALOG_INPUT:
|
||||
case OBJECT_BINARY_INPUT:
|
||||
error_class = ERROR_CLASS_PROPERTY;
|
||||
error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
len =
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id, SERVICE_CONFIRMED_WRITE_PROPERTY,
|
||||
error_class, error_code);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Sending Write Access Error!\n");
|
||||
#endif
|
||||
break;
|
||||
case OBJECT_BINARY_OUTPUT:
|
||||
if (Binary_Output_Write_Property(&wp_data, &error_class,
|
||||
&error_code)) {
|
||||
len =
|
||||
encode_simple_ack(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr,
|
||||
"Sending Write Property Simple Ack for BO!\n");
|
||||
#endif
|
||||
} else {
|
||||
len =
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY, error_class,
|
||||
error_code);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Sending Write Access Error for BO!\n");
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case OBJECT_BINARY_VALUE:
|
||||
if (Binary_Value_Write_Property(&wp_data, &error_class,
|
||||
&error_code)) {
|
||||
len =
|
||||
encode_simple_ack(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr,
|
||||
"Sending Write Property Simple Ack for BV!\n");
|
||||
#endif
|
||||
} else {
|
||||
len =
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY, error_class,
|
||||
error_code);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Sending Write Access Error for BV!\n");
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case OBJECT_ANALOG_OUTPUT:
|
||||
if (Analog_Output_Write_Property(&wp_data, &error_class,
|
||||
&error_code)) {
|
||||
len =
|
||||
encode_simple_ack(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr,
|
||||
"Sending Write Property Simple Ack for AO!\n");
|
||||
#endif
|
||||
} else {
|
||||
len =
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY, error_class,
|
||||
error_code);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Sending Write Access Error for AO!\n");
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case OBJECT_ANALOG_VALUE:
|
||||
if (Analog_Value_Write_Property(&wp_data, &error_class,
|
||||
&error_code)) {
|
||||
len =
|
||||
encode_simple_ack(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr,
|
||||
"Sending Write Property Simple Ack for AV!\n");
|
||||
#endif
|
||||
} else {
|
||||
len =
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY, error_class,
|
||||
error_code);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Sending Write Access Error for AV!\n");
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case OBJECT_LIFE_SAFETY_POINT:
|
||||
if (Life_Safety_Point_Write_Property(&wp_data, &error_class,
|
||||
&error_code)) {
|
||||
len =
|
||||
encode_simple_ack(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr,
|
||||
"Sending Write Property Simple Ack for LSP!\n");
|
||||
#endif
|
||||
} else {
|
||||
len =
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY, error_class,
|
||||
error_code);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Sending Write Access Error for LSP!\n");
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case OBJECT_LOAD_CONTROL:
|
||||
if (Load_Control_Write_Property(&wp_data, &error_class,
|
||||
&error_code)) {
|
||||
len =
|
||||
encode_simple_ack(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr,
|
||||
"Sending Write Property Simple Ack for Load Control!\n");
|
||||
#endif
|
||||
} else {
|
||||
len =
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY, error_class,
|
||||
error_code);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr,
|
||||
"Sending Write Access Error for Load Control!\n");
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case OBJECT_MULTI_STATE_OUTPUT:
|
||||
if (Multistate_Output_Write_Property(&wp_data, &error_class,
|
||||
&error_code)) {
|
||||
len =
|
||||
encode_simple_ack(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr,
|
||||
"Sending Write Property Simple Ack for MSO!\n");
|
||||
#endif
|
||||
} else {
|
||||
len =
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY, error_class,
|
||||
error_code);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Sending Write Access Error for MSO!\n");
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
#if BACFILE
|
||||
case OBJECT_FILE:
|
||||
if (bacfile_write_property(&wp_data, &error_class,
|
||||
&error_code)) {
|
||||
len =
|
||||
encode_simple_ack(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr,
|
||||
"Sending Write Property Simple Ack for File!\n");
|
||||
#endif
|
||||
} else {
|
||||
len =
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY, error_class,
|
||||
error_code);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Sending Write Access Error for File!\n");
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
#endif /* BACFILE */
|
||||
default:
|
||||
len =
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id, SERVICE_CONFIRMED_WRITE_PROPERTY,
|
||||
error_class, error_code);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Sending Unknown Object Error!\n");
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
pdu_len += len;
|
||||
bytes_sent = datalink_send_pdu(src, &npdu_data,
|
||||
&Handler_Transmit_Buffer[0], pdu_len);
|
||||
#if PRINT_ENABLED
|
||||
if (bytes_sent <= 0)
|
||||
fprintf(stderr, "Failed to send PDU (%s)!\n", strerror(errno));
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -1,103 +0,0 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2005-2006 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 HANDLERS_H
|
||||
#define HANDLERS_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include "bacdef.h"
|
||||
#include "apdu.h"
|
||||
#include "bacapp.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
void handler_unrecognized_service(uint8_t * service_request,
|
||||
uint16_t service_len,
|
||||
BACNET_ADDRESS * dest,
|
||||
BACNET_CONFIRMED_SERVICE_DATA * service_data);
|
||||
|
||||
void handler_who_is(uint8_t * service_request,
|
||||
uint16_t service_len, BACNET_ADDRESS * src);
|
||||
|
||||
void handler_who_has(uint8_t * service_request,
|
||||
uint16_t service_len, BACNET_ADDRESS * src);
|
||||
|
||||
void handler_i_am_add(uint8_t * service_request,
|
||||
uint16_t service_len, BACNET_ADDRESS * src);
|
||||
|
||||
void handler_i_am_bind(uint8_t * service_request,
|
||||
uint16_t service_len, BACNET_ADDRESS * src);
|
||||
|
||||
void handler_read_property(uint8_t * service_request,
|
||||
uint16_t service_len,
|
||||
BACNET_ADDRESS * src,
|
||||
BACNET_CONFIRMED_SERVICE_DATA * service_data);
|
||||
|
||||
void handler_read_property_ack(uint8_t * service_request,
|
||||
uint16_t service_len,
|
||||
BACNET_ADDRESS * src,
|
||||
BACNET_CONFIRMED_SERVICE_ACK_DATA * service_data);
|
||||
|
||||
void handler_write_property(uint8_t * service_request,
|
||||
uint16_t service_len,
|
||||
BACNET_ADDRESS * src,
|
||||
BACNET_CONFIRMED_SERVICE_DATA * service_data);
|
||||
|
||||
void handler_atomic_read_file(uint8_t * service_request,
|
||||
uint16_t service_len,
|
||||
BACNET_ADDRESS * src,
|
||||
BACNET_CONFIRMED_SERVICE_DATA * service_data);
|
||||
|
||||
void handler_atomic_read_file_ack(uint8_t * service_request,
|
||||
uint16_t service_len,
|
||||
BACNET_ADDRESS * src,
|
||||
BACNET_CONFIRMED_SERVICE_ACK_DATA * service_data);
|
||||
|
||||
void handler_reinitialize_device(uint8_t * service_request,
|
||||
uint16_t service_len,
|
||||
BACNET_ADDRESS * src,
|
||||
BACNET_CONFIRMED_SERVICE_DATA * service_data);
|
||||
|
||||
void handler_device_communication_control(uint8_t * service_request,
|
||||
uint16_t service_len,
|
||||
BACNET_ADDRESS * src,
|
||||
BACNET_CONFIRMED_SERVICE_DATA * service_data);
|
||||
|
||||
void handler_i_have(uint8_t * service_request,
|
||||
uint16_t service_len, BACNET_ADDRESS * src);
|
||||
|
||||
void handler_timesync(uint8_t * service_request,
|
||||
uint16_t service_len, BACNET_ADDRESS * src);
|
||||
|
||||
void handler_timesync_utc(uint8_t * service_request,
|
||||
uint16_t service_len, BACNET_ADDRESS * src);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
@@ -1,68 +0,0 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include "txbuf.h"
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "apdu.h"
|
||||
#include "npdu.h"
|
||||
#include "reject.h"
|
||||
|
||||
void handler_unrecognized_service(uint8_t * service_request,
|
||||
uint16_t service_len,
|
||||
BACNET_ADDRESS * src, BACNET_CONFIRMED_SERVICE_DATA * service_data)
|
||||
{
|
||||
int len = 0;
|
||||
int pdu_len = 0;
|
||||
int bytes_sent = 0;
|
||||
BACNET_NPDU_DATA npdu_data;
|
||||
BACNET_ADDRESS my_address;
|
||||
|
||||
(void) service_request;
|
||||
(void) service_len;
|
||||
|
||||
/* encode the NPDU portion of the packet */
|
||||
datalink_get_my_address(&my_address);
|
||||
npdu_encode_npdu_data(&npdu_data, false, MESSAGE_PRIORITY_NORMAL);
|
||||
pdu_len = npdu_encode_pdu(&Handler_Transmit_Buffer[0], src,
|
||||
&my_address, &npdu_data);
|
||||
/* encode the APDU portion of the packet */
|
||||
len = reject_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id, REJECT_REASON_UNRECOGNIZED_SERVICE);
|
||||
pdu_len += len;
|
||||
/* send the data */
|
||||
bytes_sent = datalink_send_pdu(src, &npdu_data,
|
||||
&Handler_Transmit_Buffer[0], pdu_len);
|
||||
#if PRINT_ENABLED
|
||||
if (bytes_sent > 0)
|
||||
fprintf(stderr, "Sent Reject!\n");
|
||||
else
|
||||
fprintf(stderr, "Failed to Send Reject (%s)!\n", strerror(errno));
|
||||
#endif
|
||||
}
|
||||
@@ -1,112 +0,0 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2006 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
#include "config.h"
|
||||
#include "config.h"
|
||||
#include "txbuf.h"
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "address.h"
|
||||
#include "dcc.h"
|
||||
#include "tsm.h"
|
||||
#include "npdu.h"
|
||||
#include "apdu.h"
|
||||
#include "device.h"
|
||||
#include "datalink.h"
|
||||
#include "arf.h"
|
||||
/* some demo stuff needed */
|
||||
#include "handlers.h"
|
||||
#include "txbuf.h"
|
||||
|
||||
uint8_t Send_Atomic_Read_File_Stream(uint32_t device_id,
|
||||
uint32_t file_instance,
|
||||
int fileStartPosition, unsigned requestedOctetCount)
|
||||
{
|
||||
BACNET_ADDRESS dest;
|
||||
BACNET_ADDRESS my_address;
|
||||
BACNET_NPDU_DATA npdu_data;
|
||||
unsigned max_apdu = 0;
|
||||
uint8_t invoke_id = 0;
|
||||
bool status = false;
|
||||
int len = 0;
|
||||
int pdu_len = 0;
|
||||
int bytes_sent = 0;
|
||||
BACNET_ATOMIC_READ_FILE_DATA data;
|
||||
|
||||
/* if we are forbidden to send, don't send! */
|
||||
if (!dcc_communication_enabled())
|
||||
return 0;
|
||||
|
||||
/* is the device bound? */
|
||||
status = address_get_by_device(device_id, &max_apdu, &dest);
|
||||
/* is there a tsm available? */
|
||||
if (status)
|
||||
invoke_id = tsm_next_free_invokeID();
|
||||
if (invoke_id) {
|
||||
/* load the data for the encoding */
|
||||
data.object_type = OBJECT_FILE;
|
||||
data.object_instance = file_instance;
|
||||
data.access = FILE_STREAM_ACCESS;
|
||||
data.type.stream.fileStartPosition = fileStartPosition;
|
||||
data.type.stream.requestedOctetCount = requestedOctetCount;
|
||||
/* encode the NPDU portion of the packet */
|
||||
datalink_get_my_address(&my_address);
|
||||
npdu_encode_npdu_data(&npdu_data, true, MESSAGE_PRIORITY_NORMAL);
|
||||
pdu_len = npdu_encode_pdu(&Handler_Transmit_Buffer[0], &dest,
|
||||
&my_address, &npdu_data);
|
||||
len = arf_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
invoke_id, &data);
|
||||
pdu_len += len;
|
||||
/* will the APDU fit the target device?
|
||||
note: if there is a bottleneck router in between
|
||||
us and the destination, we won't know unless
|
||||
we have a way to check for that and update the
|
||||
max_apdu in the address binding table. */
|
||||
if ((unsigned) pdu_len < max_apdu) {
|
||||
tsm_set_confirmed_unsegmented_transaction(invoke_id, &dest,
|
||||
&npdu_data, &Handler_Transmit_Buffer[0], pdu_len);
|
||||
bytes_sent =
|
||||
datalink_send_pdu(&dest, &npdu_data,
|
||||
&Handler_Transmit_Buffer[0], pdu_len);
|
||||
#if PRINT_ENABLED
|
||||
if (bytes_sent <= 0)
|
||||
fprintf(stderr,
|
||||
"Failed to Send AtomicReadFile Request (%s)!\n",
|
||||
strerror(errno));
|
||||
#endif
|
||||
} else {
|
||||
tsm_free_invoke_id(invoke_id);
|
||||
invoke_id = 0;
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Failed to Send AtomicReadFile Request "
|
||||
"(payload exceeds destination maximum APDU)!\n");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
return invoke_id;
|
||||
}
|
||||
@@ -1,126 +0,0 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2006 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
#include "config.h"
|
||||
#include "config.h"
|
||||
#include "txbuf.h"
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "address.h"
|
||||
#include "tsm.h"
|
||||
#include "dcc.h"
|
||||
#include "npdu.h"
|
||||
#include "apdu.h"
|
||||
#include "device.h"
|
||||
#include "datalink.h"
|
||||
#include "awf.h"
|
||||
/* some demo stuff needed */
|
||||
#include "handlers.h"
|
||||
#include "txbuf.h"
|
||||
|
||||
uint8_t Send_Atomic_Write_File_Stream(uint32_t device_id,
|
||||
uint32_t file_instance,
|
||||
int fileStartPosition, BACNET_OCTET_STRING * fileData)
|
||||
{
|
||||
BACNET_ADDRESS dest;
|
||||
BACNET_ADDRESS my_address;
|
||||
BACNET_NPDU_DATA npdu_data;
|
||||
unsigned max_apdu = 0;
|
||||
uint8_t invoke_id = 0;
|
||||
bool status = false;
|
||||
int len = 0;
|
||||
int pdu_len = 0;
|
||||
int bytes_sent = 0;
|
||||
BACNET_ATOMIC_WRITE_FILE_DATA data;
|
||||
|
||||
/* if we are forbidden to send, don't send! */
|
||||
if (!dcc_communication_enabled())
|
||||
return 0;
|
||||
|
||||
/* is the device bound? */
|
||||
status = address_get_by_device(device_id, &max_apdu, &dest);
|
||||
/* is there a tsm available? */
|
||||
if (status)
|
||||
invoke_id = tsm_next_free_invokeID();
|
||||
if (invoke_id) {
|
||||
/* load the data for the encoding */
|
||||
data.object_type = OBJECT_FILE;
|
||||
data.object_instance = file_instance;
|
||||
data.access = FILE_STREAM_ACCESS;
|
||||
data.type.stream.fileStartPosition = fileStartPosition;
|
||||
status = octetstring_copy(&data.fileData, fileData);
|
||||
if (status) {
|
||||
/* encode the NPDU portion of the packet */
|
||||
datalink_get_my_address(&my_address);
|
||||
npdu_encode_npdu_data(&npdu_data, true,
|
||||
MESSAGE_PRIORITY_NORMAL);
|
||||
pdu_len =
|
||||
npdu_encode_pdu(&Handler_Transmit_Buffer[0], &dest,
|
||||
&my_address, &npdu_data);
|
||||
/* encode the APDU portion of the packet */
|
||||
len = awf_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
invoke_id, &data);
|
||||
pdu_len += len;
|
||||
/* will the APDU fit the target device?
|
||||
note: if there is a bottleneck router in between
|
||||
us and the destination, we won't know unless
|
||||
we have a way to check for that and update the
|
||||
max_apdu in the address binding table. */
|
||||
if ((unsigned) pdu_len <= max_apdu) {
|
||||
tsm_set_confirmed_unsegmented_transaction(invoke_id, &dest,
|
||||
&npdu_data, &Handler_Transmit_Buffer[0], pdu_len);
|
||||
bytes_sent =
|
||||
datalink_send_pdu(&dest, &npdu_data,
|
||||
&Handler_Transmit_Buffer[0], pdu_len);
|
||||
#if PRINT_ENABLED
|
||||
if (bytes_sent <= 0)
|
||||
fprintf(stderr,
|
||||
"Failed to Send AtomicWriteFile Request (%s)!\n",
|
||||
strerror(errno));
|
||||
#endif
|
||||
} else {
|
||||
tsm_free_invoke_id(invoke_id);
|
||||
invoke_id = 0;
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Failed to Send AtomicWriteFile Request "
|
||||
"(payload [%d] exceeds destination maximum APDU [%u])!\n",
|
||||
pdu_len, max_apdu);
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
tsm_free_invoke_id(invoke_id);
|
||||
invoke_id = 0;
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Failed to Send AtomicWriteFile Request "
|
||||
"(payload [%d] exceeds octet string capacity)!\n",
|
||||
pdu_len);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
return invoke_id;
|
||||
}
|
||||
@@ -1,109 +0,0 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2006 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include "config.h"
|
||||
#include "config.h"
|
||||
#include "txbuf.h"
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "address.h"
|
||||
#include "tsm.h"
|
||||
#include "npdu.h"
|
||||
#include "apdu.h"
|
||||
#include "device.h"
|
||||
#include "datalink.h"
|
||||
#include "dcc.h"
|
||||
/* some demo stuff needed */
|
||||
#include "handlers.h"
|
||||
#include "txbuf.h"
|
||||
|
||||
uint8_t Send_Device_Communication_Control_Request(uint32_t device_id, uint16_t timeDuration, /* 0=optional */
|
||||
BACNET_COMMUNICATION_ENABLE_DISABLE state, char *password)
|
||||
{ /* NULL=optional */
|
||||
BACNET_ADDRESS dest;
|
||||
BACNET_ADDRESS my_address;
|
||||
unsigned max_apdu = 0;
|
||||
uint8_t invoke_id = 0;
|
||||
bool status = false;
|
||||
int len = 0;
|
||||
int pdu_len = 0;
|
||||
int bytes_sent = 0;
|
||||
BACNET_CHARACTER_STRING password_string;
|
||||
BACNET_NPDU_DATA npdu_data;
|
||||
|
||||
/* if we are forbidden to send, don't send! */
|
||||
if (!dcc_communication_enabled())
|
||||
return 0;
|
||||
|
||||
/* is the device bound? */
|
||||
status = address_get_by_device(device_id, &max_apdu, &dest);
|
||||
/* is there a tsm available? */
|
||||
if (status)
|
||||
invoke_id = tsm_next_free_invokeID();
|
||||
if (invoke_id) {
|
||||
/* encode the NPDU portion of the packet */
|
||||
datalink_get_my_address(&my_address);
|
||||
npdu_encode_npdu_data(&npdu_data, true, MESSAGE_PRIORITY_NORMAL);
|
||||
pdu_len = npdu_encode_pdu(&Handler_Transmit_Buffer[0], &dest,
|
||||
&my_address, &npdu_data);
|
||||
/* encode the APDU portion of the packet */
|
||||
characterstring_init_ansi(&password_string, password);
|
||||
len = dcc_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
invoke_id,
|
||||
timeDuration, state, password ? &password_string : NULL);
|
||||
pdu_len += len;
|
||||
/* will it fit in the sender?
|
||||
note: if there is a bottleneck router in between
|
||||
us and the destination, we won't know unless
|
||||
we have a way to check for that and update the
|
||||
max_apdu in the address binding table. */
|
||||
if ((unsigned) pdu_len < max_apdu) {
|
||||
tsm_set_confirmed_unsegmented_transaction(invoke_id, &dest,
|
||||
&npdu_data, &Handler_Transmit_Buffer[0], pdu_len);
|
||||
bytes_sent =
|
||||
datalink_send_pdu(&dest, &npdu_data,
|
||||
&Handler_Transmit_Buffer[0], pdu_len);
|
||||
#if PRINT_ENABLED
|
||||
if (bytes_sent <= 0)
|
||||
fprintf(stderr,
|
||||
"Failed to Send DeviceCommunicationControl Request (%s)!\n",
|
||||
strerror(errno));
|
||||
#endif
|
||||
} else {
|
||||
tsm_free_invoke_id(invoke_id);
|
||||
invoke_id = 0;
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr,
|
||||
"Failed to Send DeviceCommunicationControl Request "
|
||||
"(exceeds destination maximum APDU)!\n");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
return invoke_id;
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2006 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include "config.h"
|
||||
#include "config.h"
|
||||
#include "txbuf.h"
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "address.h"
|
||||
#include "tsm.h"
|
||||
#include "npdu.h"
|
||||
#include "apdu.h"
|
||||
#include "device.h"
|
||||
#include "datalink.h"
|
||||
#include "dcc.h"
|
||||
#include "ihave.h"
|
||||
/* some demo stuff needed */
|
||||
#include "handlers.h"
|
||||
#include "txbuf.h"
|
||||
|
||||
/* find a specific device, or use -1 for limit if you want unlimited */
|
||||
void Send_I_Have(uint32_t device_id,
|
||||
BACNET_OBJECT_TYPE object_type,
|
||||
uint32_t object_instance, char *object_name)
|
||||
{
|
||||
int len = 0;
|
||||
int pdu_len = 0;
|
||||
BACNET_ADDRESS dest;
|
||||
int bytes_sent = 0;
|
||||
BACNET_I_HAVE_DATA data;
|
||||
BACNET_NPDU_DATA npdu_data;
|
||||
|
||||
/* if we are forbidden to send, don't send! */
|
||||
if (!dcc_communication_enabled())
|
||||
return;
|
||||
/* Who-Has is a global broadcast */
|
||||
datalink_get_broadcast_address(&dest);
|
||||
/* encode the NPDU portion of the packet */
|
||||
npdu_encode_npdu_data(&npdu_data, false, MESSAGE_PRIORITY_NORMAL);
|
||||
pdu_len = npdu_encode_pdu(&Handler_Transmit_Buffer[0], &dest,
|
||||
NULL, &npdu_data);
|
||||
/* encode the APDU portion of the packet */
|
||||
data.device_id.type = OBJECT_DEVICE;
|
||||
data.device_id.instance = device_id;
|
||||
data.object_id.type = object_type;
|
||||
data.object_id.instance = object_instance;
|
||||
characterstring_init_ansi(&data.object_name, object_name);
|
||||
len = ihave_encode_apdu(&Handler_Transmit_Buffer[pdu_len], &data);
|
||||
pdu_len += len;
|
||||
/* send the data */
|
||||
bytes_sent = datalink_send_pdu(&dest, &npdu_data,
|
||||
&Handler_Transmit_Buffer[0], pdu_len);
|
||||
#if PRINT_ENABLED
|
||||
if (bytes_sent <= 0)
|
||||
fprintf(stderr, "Failed to Send I-Have Reply (%s)!\n",
|
||||
strerror(errno));
|
||||
#endif
|
||||
}
|
||||
@@ -1,107 +0,0 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
#include "config.h"
|
||||
#include "config.h"
|
||||
#include "txbuf.h"
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "address.h"
|
||||
#include "tsm.h"
|
||||
#include "npdu.h"
|
||||
#include "apdu.h"
|
||||
#include "device.h"
|
||||
#include "datalink.h"
|
||||
#include "dcc.h"
|
||||
#include "rd.h"
|
||||
/* some demo stuff needed */
|
||||
#include "handlers.h"
|
||||
#include "txbuf.h"
|
||||
|
||||
uint8_t Send_Reinitialize_Device_Request(uint32_t device_id,
|
||||
BACNET_REINITIALIZED_STATE state, char *password)
|
||||
{
|
||||
BACNET_ADDRESS dest;
|
||||
BACNET_ADDRESS my_address;
|
||||
unsigned max_apdu = 0;
|
||||
uint8_t invoke_id = 0;
|
||||
bool status = false;
|
||||
int len = 0;
|
||||
int pdu_len = 0;
|
||||
int bytes_sent = 0;
|
||||
BACNET_CHARACTER_STRING password_string;
|
||||
BACNET_NPDU_DATA npdu_data;
|
||||
|
||||
/* if we are forbidden to send, don't send! */
|
||||
if (!dcc_communication_enabled())
|
||||
return 0;
|
||||
|
||||
/* is the device bound? */
|
||||
status = address_get_by_device(device_id, &max_apdu, &dest);
|
||||
/* is there a tsm available? */
|
||||
if (status)
|
||||
invoke_id = tsm_next_free_invokeID();
|
||||
if (invoke_id) {
|
||||
/* encode the NPDU portion of the packet */
|
||||
datalink_get_my_address(&my_address);
|
||||
npdu_encode_npdu_data(&npdu_data, true, MESSAGE_PRIORITY_NORMAL);
|
||||
pdu_len = npdu_encode_pdu(&Handler_Transmit_Buffer[0], &dest,
|
||||
&my_address, &npdu_data);
|
||||
/* encode the APDU portion of the packet */
|
||||
characterstring_init_ansi(&password_string, password);
|
||||
len = rd_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
invoke_id, state, password ? &password_string : NULL);
|
||||
pdu_len += len;
|
||||
/* will it fit in the sender?
|
||||
note: if there is a bottleneck router in between
|
||||
us and the destination, we won't know unless
|
||||
we have a way to check for that and update the
|
||||
max_apdu in the address binding table. */
|
||||
if ((unsigned) pdu_len < max_apdu) {
|
||||
tsm_set_confirmed_unsegmented_transaction(invoke_id, &dest,
|
||||
&npdu_data, &Handler_Transmit_Buffer[0], pdu_len);
|
||||
bytes_sent =
|
||||
datalink_send_pdu(&dest, &npdu_data,
|
||||
&Handler_Transmit_Buffer[0], pdu_len);
|
||||
#if PRINT_ENABLED
|
||||
if (bytes_sent <= 0)
|
||||
fprintf(stderr,
|
||||
"Failed to Send ReinitializeDevice Request (%s)!\n",
|
||||
strerror(errno));
|
||||
#endif
|
||||
} else {
|
||||
tsm_free_invoke_id(invoke_id);
|
||||
invoke_id = 0;
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Failed to Send ReinitializeDevice Request "
|
||||
"(exceeds destination maximum APDU)!\n");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
return invoke_id;
|
||||
}
|
||||
@@ -1,114 +0,0 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include "config.h"
|
||||
#include "config.h"
|
||||
#include "txbuf.h"
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "address.h"
|
||||
#include "tsm.h"
|
||||
#include "npdu.h"
|
||||
#include "apdu.h"
|
||||
#include "device.h"
|
||||
#include "datalink.h"
|
||||
#include "dcc.h"
|
||||
#include "rp.h"
|
||||
/* some demo stuff needed */
|
||||
#include "handlers.h"
|
||||
#include "txbuf.h"
|
||||
|
||||
/* returns invoke id of 0 if device is not bound or no tsm available */
|
||||
uint8_t Send_Read_Property_Request(uint32_t device_id, /* destination device */
|
||||
BACNET_OBJECT_TYPE object_type,
|
||||
uint32_t object_instance,
|
||||
BACNET_PROPERTY_ID object_property, int32_t array_index)
|
||||
{
|
||||
BACNET_ADDRESS dest;
|
||||
BACNET_ADDRESS my_address;
|
||||
unsigned max_apdu = 0;
|
||||
uint8_t invoke_id = 0;
|
||||
bool status = false;
|
||||
int len = 0;
|
||||
int pdu_len = 0;
|
||||
int bytes_sent = 0;
|
||||
BACNET_READ_PROPERTY_DATA data;
|
||||
BACNET_NPDU_DATA npdu_data;
|
||||
|
||||
if (!dcc_communication_enabled())
|
||||
return 0;
|
||||
|
||||
/* is the device bound? */
|
||||
status = address_get_by_device(device_id, &max_apdu, &dest);
|
||||
/* is there a tsm available? */
|
||||
if (status)
|
||||
invoke_id = tsm_next_free_invokeID();
|
||||
if (invoke_id) {
|
||||
/* encode the NPDU portion of the packet */
|
||||
datalink_get_my_address(&my_address);
|
||||
npdu_encode_npdu_data(&npdu_data, true, MESSAGE_PRIORITY_NORMAL);
|
||||
pdu_len = npdu_encode_pdu(&Handler_Transmit_Buffer[0], &dest,
|
||||
&my_address, &npdu_data);
|
||||
/* encode the APDU portion of the packet */
|
||||
data.object_type = object_type;
|
||||
data.object_instance = object_instance;
|
||||
data.object_property = object_property;
|
||||
data.array_index = array_index;
|
||||
len = rp_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
invoke_id, &data);
|
||||
pdu_len += len;
|
||||
/* will it fit in the sender?
|
||||
note: if there is a bottleneck router in between
|
||||
us and the destination, we won't know unless
|
||||
we have a way to check for that and update the
|
||||
max_apdu in the address binding table. */
|
||||
if ((unsigned) pdu_len < max_apdu) {
|
||||
tsm_set_confirmed_unsegmented_transaction(invoke_id, &dest,
|
||||
&npdu_data, &Handler_Transmit_Buffer[0],
|
||||
(uint16_t) pdu_len);
|
||||
bytes_sent =
|
||||
datalink_send_pdu(&dest, &npdu_data,
|
||||
&Handler_Transmit_Buffer[0], pdu_len);
|
||||
#if PRINT_ENABLED
|
||||
if (bytes_sent <= 0)
|
||||
fprintf(stderr,
|
||||
"Failed to Send ReadProperty Request (%s)!\n",
|
||||
strerror(errno));
|
||||
#endif
|
||||
} else {
|
||||
tsm_free_invoke_id(invoke_id);
|
||||
invoke_id = 0;
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Failed to Send ReadProperty Request "
|
||||
"(exceeds destination maximum APDU)!\n");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
return invoke_id;
|
||||
}
|
||||
@@ -1,100 +0,0 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
#include "config.h"
|
||||
#include "config.h"
|
||||
#include "txbuf.h"
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "address.h"
|
||||
#include "tsm.h"
|
||||
#include "npdu.h"
|
||||
#include "apdu.h"
|
||||
#include "device.h"
|
||||
#include "datalink.h"
|
||||
#include "dcc.h"
|
||||
#include "timesync.h"
|
||||
/* some demo stuff needed */
|
||||
#include "handlers.h"
|
||||
#include "txbuf.h"
|
||||
|
||||
void Send_TimeSync(BACNET_DATE * bdate, BACNET_TIME * btime)
|
||||
{
|
||||
int len = 0;
|
||||
int pdu_len = 0;
|
||||
BACNET_ADDRESS dest;
|
||||
int bytes_sent = 0;
|
||||
BACNET_NPDU_DATA npdu_data;
|
||||
|
||||
if (!dcc_communication_enabled())
|
||||
return;
|
||||
|
||||
/* we could use unicast or broadcast */
|
||||
datalink_get_broadcast_address(&dest);
|
||||
/* encode the NPDU portion of the packet */
|
||||
npdu_encode_npdu_data(&npdu_data, false, MESSAGE_PRIORITY_NORMAL);
|
||||
pdu_len = npdu_encode_pdu(&Handler_Transmit_Buffer[0], &dest,
|
||||
NULL, &npdu_data);
|
||||
/* encode the APDU portion of the packet */
|
||||
len = timesync_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
bdate, btime);
|
||||
pdu_len += len;
|
||||
/* send it out the datalink */
|
||||
bytes_sent = datalink_send_pdu(&dest, &npdu_data,
|
||||
&Handler_Transmit_Buffer[0], pdu_len);
|
||||
#if PRINT_ENABLED
|
||||
if (bytes_sent <= 0)
|
||||
fprintf(stderr,
|
||||
"Failed to Send Time-Synchronization Request (%s)!\n",
|
||||
strerror(errno));
|
||||
#endif
|
||||
}
|
||||
|
||||
void Send_TimeSyncUTC(BACNET_DATE * bdate, BACNET_TIME * btime)
|
||||
{
|
||||
int pdu_len = 0;
|
||||
BACNET_ADDRESS dest;
|
||||
int bytes_sent = 0;
|
||||
BACNET_NPDU_DATA npdu_data;
|
||||
|
||||
if (!dcc_communication_enabled())
|
||||
return;
|
||||
|
||||
/* we could use unicast or broadcast */
|
||||
datalink_get_broadcast_address(&dest);
|
||||
/* encode the APDU portion of the packet */
|
||||
pdu_len = timesync_utc_encode_apdu(&Handler_Transmit_Buffer[0],
|
||||
bdate, btime);
|
||||
bytes_sent = datalink_send_pdu(&dest, &npdu_data,
|
||||
&Handler_Transmit_Buffer[0], pdu_len);
|
||||
#if PRINT_ENABLED
|
||||
if (bytes_sent <= 0)
|
||||
fprintf(stderr,
|
||||
"Failed to Send UTC-Time-Synchronization Request (%s)!\n",
|
||||
strerror(errno));
|
||||
#endif
|
||||
}
|
||||
@@ -1,118 +0,0 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2006 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
#include "config.h"
|
||||
#include "config.h"
|
||||
#include "txbuf.h"
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "address.h"
|
||||
#include "tsm.h"
|
||||
#include "npdu.h"
|
||||
#include "apdu.h"
|
||||
#include "device.h"
|
||||
#include "datalink.h"
|
||||
#include "dcc.h"
|
||||
#include "whohas.h"
|
||||
/* some demo stuff needed */
|
||||
#include "handlers.h"
|
||||
#include "txbuf.h"
|
||||
|
||||
/* find a specific device, or use -1 for limit if you want unlimited */
|
||||
void Send_WhoHas_Name(int32_t low_limit,
|
||||
int32_t high_limit, char *object_name)
|
||||
{
|
||||
int len = 0;
|
||||
int pdu_len = 0;
|
||||
BACNET_ADDRESS dest;
|
||||
int bytes_sent = 0;
|
||||
BACNET_WHO_HAS_DATA data;
|
||||
BACNET_NPDU_DATA npdu_data;
|
||||
|
||||
/* if we are forbidden to send, don't send! */
|
||||
if (!dcc_communication_enabled())
|
||||
return;
|
||||
/* Who-Has is a global broadcast */
|
||||
datalink_get_broadcast_address(&dest);
|
||||
/* encode the NPDU portion of the packet */
|
||||
npdu_encode_npdu_data(&npdu_data, false, MESSAGE_PRIORITY_NORMAL);
|
||||
pdu_len = npdu_encode_pdu(&Handler_Transmit_Buffer[0], &dest,
|
||||
NULL, &npdu_data);
|
||||
/* encode the APDU portion of the packet */
|
||||
data.low_limit = low_limit;
|
||||
data.high_limit = high_limit;
|
||||
data.object_name = true;
|
||||
characterstring_init_ansi(&data.object.name, object_name);
|
||||
len = whohas_encode_apdu(&Handler_Transmit_Buffer[pdu_len], &data);
|
||||
pdu_len += len;
|
||||
/* send the data */
|
||||
bytes_sent = datalink_send_pdu(&dest, &npdu_data,
|
||||
&Handler_Transmit_Buffer[0], pdu_len);
|
||||
#if PRINT_ENABLED
|
||||
if (bytes_sent <= 0)
|
||||
fprintf(stderr, "Failed to Send Who-Has Request (%s)!\n",
|
||||
strerror(errno));
|
||||
#endif
|
||||
}
|
||||
|
||||
/* find a specific device, or use -1 for limit if you want unlimited */
|
||||
void Send_WhoHas_Object(int32_t low_limit,
|
||||
int32_t high_limit,
|
||||
BACNET_OBJECT_TYPE object_type, uint32_t object_instance)
|
||||
{
|
||||
int len = 0;
|
||||
int pdu_len = 0;
|
||||
BACNET_ADDRESS dest;
|
||||
int bytes_sent = 0;
|
||||
BACNET_WHO_HAS_DATA data;
|
||||
BACNET_NPDU_DATA npdu_data;
|
||||
|
||||
/* if we are forbidden to send, don't send! */
|
||||
if (!dcc_communication_enabled())
|
||||
return;
|
||||
/* Who-Has is a global broadcast */
|
||||
datalink_get_broadcast_address(&dest);
|
||||
/* encode the NPDU portion of the packet */
|
||||
npdu_encode_npdu_data(&npdu_data, false, MESSAGE_PRIORITY_NORMAL);
|
||||
pdu_len = npdu_encode_pdu(&Handler_Transmit_Buffer[0], &dest,
|
||||
NULL, &npdu_data);
|
||||
/* encode the APDU portion of the packet */
|
||||
data.low_limit = low_limit;
|
||||
data.high_limit = high_limit;
|
||||
data.object_name = false;
|
||||
data.object.identifier.type = object_type;
|
||||
data.object.identifier.instance = object_instance;
|
||||
len = whohas_encode_apdu(&Handler_Transmit_Buffer[pdu_len], &data);
|
||||
pdu_len += len;
|
||||
bytes_sent = datalink_send_pdu(&dest, &npdu_data,
|
||||
&Handler_Transmit_Buffer[0], pdu_len);
|
||||
#if PRINT_ENABLED
|
||||
if (bytes_sent <= 0)
|
||||
fprintf(stderr, "Failed to Send Who-Has Request (%s)!\n",
|
||||
strerror(errno));
|
||||
#endif
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include "config.h"
|
||||
#include "config.h"
|
||||
#include "txbuf.h"
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "address.h"
|
||||
#include "tsm.h"
|
||||
#include "npdu.h"
|
||||
#include "apdu.h"
|
||||
#include "device.h"
|
||||
#include "datalink.h"
|
||||
#include "dcc.h"
|
||||
#include "whois.h"
|
||||
/* some demo stuff needed */
|
||||
#include "handlers.h"
|
||||
#include "txbuf.h"
|
||||
|
||||
/* find a specific device, or use -1 for limit if you want unlimited */
|
||||
void Send_WhoIs(int32_t low_limit, int32_t high_limit)
|
||||
{
|
||||
int len = 0;
|
||||
int pdu_len = 0;
|
||||
BACNET_ADDRESS dest;
|
||||
int bytes_sent = 0;
|
||||
BACNET_NPDU_DATA npdu_data;
|
||||
|
||||
if (!dcc_communication_enabled())
|
||||
return;
|
||||
|
||||
/* Who-Is is a global broadcast */
|
||||
datalink_get_broadcast_address(&dest);
|
||||
/* encode the NPDU portion of the packet */
|
||||
npdu_encode_npdu_data(&npdu_data, false, MESSAGE_PRIORITY_NORMAL);
|
||||
pdu_len = npdu_encode_pdu(&Handler_Transmit_Buffer[0], &dest,
|
||||
NULL, &npdu_data);
|
||||
/* encode the APDU portion of the packet */
|
||||
len = whois_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
low_limit, high_limit);
|
||||
pdu_len += len;
|
||||
bytes_sent = datalink_send_pdu(&dest, &npdu_data,
|
||||
&Handler_Transmit_Buffer[0], pdu_len);
|
||||
#if PRINT_ENABLED
|
||||
if (bytes_sent <= 0)
|
||||
fprintf(stderr, "Failed to Send Who-Is Request (%s)!\n",
|
||||
strerror(errno));
|
||||
#endif
|
||||
}
|
||||
@@ -1,148 +0,0 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include "config.h"
|
||||
#include "config.h"
|
||||
#include "txbuf.h"
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "address.h"
|
||||
#include "tsm.h"
|
||||
#include "npdu.h"
|
||||
#include "apdu.h"
|
||||
#include "device.h"
|
||||
#include "datalink.h"
|
||||
#include "dcc.h"
|
||||
#include "whois.h"
|
||||
/* some demo stuff needed */
|
||||
#include "handlers.h"
|
||||
#include "txbuf.h"
|
||||
|
||||
/* returns the invoke ID for confirmed request, or zero on failure */
|
||||
uint8_t Send_Write_Property_Request_Data(uint32_t device_id,
|
||||
BACNET_OBJECT_TYPE object_type,
|
||||
uint32_t object_instance,
|
||||
BACNET_PROPERTY_ID object_property,
|
||||
uint8_t * application_data,
|
||||
int application_data_len, uint8_t priority, int32_t array_index)
|
||||
{
|
||||
BACNET_ADDRESS dest;
|
||||
BACNET_ADDRESS my_address;
|
||||
unsigned max_apdu = 0;
|
||||
uint8_t invoke_id = 0;
|
||||
bool status = false;
|
||||
int len = 0;
|
||||
int pdu_len = 0;
|
||||
int bytes_sent = 0;
|
||||
BACNET_WRITE_PROPERTY_DATA data;
|
||||
BACNET_NPDU_DATA npdu_data;
|
||||
|
||||
if (!dcc_communication_enabled())
|
||||
return 0;
|
||||
|
||||
/* is the device bound? */
|
||||
status = address_get_by_device(device_id, &max_apdu, &dest);
|
||||
/* is there a tsm available? */
|
||||
if (status)
|
||||
invoke_id = tsm_next_free_invokeID();
|
||||
if (invoke_id) {
|
||||
/* encode the NPDU portion of the packet */
|
||||
datalink_get_my_address(&my_address);
|
||||
npdu_encode_npdu_data(&npdu_data, true, MESSAGE_PRIORITY_NORMAL);
|
||||
pdu_len = npdu_encode_pdu(&Handler_Transmit_Buffer[0], &dest,
|
||||
&my_address, &npdu_data);
|
||||
/* encode the APDU portion of the packet */
|
||||
data.object_type = object_type;
|
||||
data.object_instance = object_instance;
|
||||
data.object_property = object_property;
|
||||
data.array_index = array_index;
|
||||
data.application_data_len = application_data_len;
|
||||
memcpy(&data.application_data[0], &application_data[0],
|
||||
application_data_len);
|
||||
data.priority = priority;
|
||||
len = wp_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
invoke_id, &data);
|
||||
pdu_len += len;
|
||||
/* will it fit in the sender?
|
||||
note: if there is a bottleneck router in between
|
||||
us and the destination, we won't know unless
|
||||
we have a way to check for that and update the
|
||||
max_apdu in the address binding table. */
|
||||
if ((unsigned) pdu_len < max_apdu) {
|
||||
tsm_set_confirmed_unsegmented_transaction(invoke_id, &dest,
|
||||
&npdu_data, &Handler_Transmit_Buffer[0],
|
||||
(uint16_t) pdu_len);
|
||||
bytes_sent =
|
||||
datalink_send_pdu(&dest, &npdu_data,
|
||||
&Handler_Transmit_Buffer[0], pdu_len);
|
||||
#if PRINT_ENABLED
|
||||
if (bytes_sent <= 0)
|
||||
fprintf(stderr,
|
||||
"Failed to Send WriteProperty Request (%s)!\n",
|
||||
strerror(errno));
|
||||
#endif
|
||||
} else {
|
||||
tsm_free_invoke_id(invoke_id);
|
||||
invoke_id = 0;
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Failed to Send WriteProperty Request "
|
||||
"(exceeds destination maximum APDU)!\n");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
return invoke_id;
|
||||
}
|
||||
|
||||
uint8_t Send_Write_Property_Request(uint32_t device_id,
|
||||
BACNET_OBJECT_TYPE object_type,
|
||||
uint32_t object_instance,
|
||||
BACNET_PROPERTY_ID object_property,
|
||||
BACNET_APPLICATION_DATA_VALUE * object_value,
|
||||
uint8_t priority, int32_t array_index)
|
||||
{
|
||||
uint8_t application_data[MAX_APDU] = { 0 };
|
||||
int apdu_len = 0, len = 0;
|
||||
|
||||
while (object_value) {
|
||||
len = bacapp_encode_data(&application_data[apdu_len],
|
||||
object_value);
|
||||
if ((len + apdu_len) < MAX_APDU) {
|
||||
apdu_len += len;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
object_value = object_value->next;
|
||||
}
|
||||
|
||||
return Send_Write_Property_Request_Data(device_id,
|
||||
object_type,
|
||||
object_instance,
|
||||
object_property,
|
||||
&application_data[0], apdu_len, priority, array_index);
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include "config.h"
|
||||
#include "datalink.h"
|
||||
|
||||
uint8_t Handler_Transmit_Buffer[MAX_MPDU] = { 0 };
|
||||
@@ -1,35 +0,0 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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 TXBUF_H
|
||||
#define TXBUF_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include "config.h"
|
||||
#include "datalink.h"
|
||||
|
||||
extern uint8_t Handler_Transmit_Buffer[MAX_MPDU];
|
||||
|
||||
#endif
|
||||
@@ -1,197 +0,0 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
/* Analog Input Objects customize for your use */
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "bacenum.h"
|
||||
#include "config.h" /* the custom stuff */
|
||||
|
||||
#define MAX_ANALOG_INPUTS 7
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need validate that the */
|
||||
/* given instance exists */
|
||||
bool Analog_Input_Valid_Instance(uint32_t object_instance)
|
||||
{
|
||||
if (object_instance < MAX_ANALOG_INPUTS)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then count how many you have */
|
||||
unsigned Analog_Input_Count(void)
|
||||
{
|
||||
return MAX_ANALOG_INPUTS;
|
||||
}
|
||||
|
||||
/* 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 Analog_Input_Index_To_Instance(unsigned index)
|
||||
{
|
||||
return index;
|
||||
}
|
||||
|
||||
char *Analog_Input_Name(uint32_t object_instance)
|
||||
{
|
||||
static char text_string[32] = ""; /* okay for single thread */
|
||||
|
||||
if (object_instance < MAX_ANALOG_INPUTS) {
|
||||
sprintf(text_string, "ANALOG INPUT %u", object_instance);
|
||||
return text_string;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* return apdu length, or -1 on error */
|
||||
/* assumption - object has already exists */
|
||||
int Analog_Input_Encode_Property_APDU(uint8_t * apdu,
|
||||
uint32_t object_instance,
|
||||
BACNET_PROPERTY_ID property,
|
||||
int32_t array_index,
|
||||
BACNET_ERROR_CLASS * error_class, BACNET_ERROR_CODE * error_code)
|
||||
{
|
||||
int apdu_len = 0; /* return value */
|
||||
BACNET_BIT_STRING bit_string;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
float value = (float) 3.14;
|
||||
|
||||
(void) array_index;
|
||||
switch (property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len = encode_tagged_object_id(&apdu[0], OBJECT_ANALOG_INPUT,
|
||||
object_instance);
|
||||
break;
|
||||
case PROP_OBJECT_NAME:
|
||||
case PROP_DESCRIPTION:
|
||||
characterstring_init_ansi(&char_string,
|
||||
Analog_Input_Name(object_instance));
|
||||
apdu_len = encode_tagged_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_OBJECT_TYPE:
|
||||
apdu_len = encode_tagged_enumerated(&apdu[0], OBJECT_ANALOG_INPUT);
|
||||
break;
|
||||
case PROP_PRESENT_VALUE:
|
||||
apdu_len = encode_tagged_real(&apdu[0], value);
|
||||
break;
|
||||
case PROP_STATUS_FLAGS:
|
||||
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_tagged_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
case PROP_EVENT_STATE:
|
||||
apdu_len = encode_tagged_enumerated(&apdu[0], EVENT_STATE_NORMAL);
|
||||
break;
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
apdu_len = encode_tagged_boolean(&apdu[0], false);
|
||||
break;
|
||||
case PROP_UNITS:
|
||||
apdu_len = encode_tagged_enumerated(&apdu[0], UNITS_PERCENT);
|
||||
break;
|
||||
case 9997:
|
||||
apdu_len = encode_tagged_real(&apdu[0], (float) 90.510);
|
||||
break;
|
||||
case 9998:
|
||||
apdu_len = encode_tagged_unsigned(&apdu[0], 90);
|
||||
break;
|
||||
/* test case for signed encoding-decoding negative value correctly */
|
||||
case 9999:
|
||||
apdu_len = encode_tagged_signed(&apdu[0], -200);
|
||||
break;
|
||||
default:
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
apdu_len = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include "ctest.h"
|
||||
|
||||
void testAnalogInput(Test * pTest)
|
||||
{
|
||||
uint8_t apdu[MAX_APDU] = { 0 };
|
||||
int len = 0;
|
||||
uint32_t len_value = 0;
|
||||
uint8_t tag_number = 0;
|
||||
BACNET_OBJECT_TYPE decoded_type = OBJECT_ANALOG_OUTPUT;
|
||||
uint32_t decoded_instance = 0;
|
||||
uint32_t instance = 123;
|
||||
BACNET_ERROR_CLASS error_class;
|
||||
BACNET_ERROR_CODE error_code;
|
||||
|
||||
|
||||
/* FIXME: we should do a lot more testing here... */
|
||||
len = Analog_Input_Encode_Property_APDU(&apdu[0],
|
||||
instance,
|
||||
PROP_OBJECT_IDENTIFIER,
|
||||
BACNET_ARRAY_ALL, &error_class, &error_code);
|
||||
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],
|
||||
(int *) &decoded_type, &decoded_instance);
|
||||
ct_test(pTest, decoded_type == OBJECT_ANALOG_INPUT);
|
||||
ct_test(pTest, decoded_instance == instance);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef TEST_ANALOG_INPUT
|
||||
int main(void)
|
||||
{
|
||||
Test *pTest;
|
||||
bool rc;
|
||||
|
||||
pTest = ct_create("BACnet Analog Input", NULL);
|
||||
/* individual tests */
|
||||
rc = ct_addTestFunction(pTest, testAnalogInput);
|
||||
assert(rc);
|
||||
|
||||
ct_setStream(pTest, stdout);
|
||||
ct_run(pTest);
|
||||
(void) ct_report(pTest);
|
||||
ct_destroy(pTest);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* TEST_ANALOG_INPUT */
|
||||
#endif /* TEST */
|
||||
@@ -1,55 +0,0 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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 AI_H
|
||||
#define AI_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "bacdef.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
bool Analog_Input_Valid_Instance(uint32_t object_instance);
|
||||
unsigned Analog_Input_Count(void);
|
||||
uint32_t Analog_Input_Index_To_Instance(unsigned index);
|
||||
char *Analog_Input_Name(uint32_t object_instance);
|
||||
|
||||
int Analog_Input_Encode_Property_APDU(uint8_t * apdu,
|
||||
uint32_t object_instance,
|
||||
BACNET_PROPERTY_ID property,
|
||||
int32_t array_index,
|
||||
BACNET_ERROR_CLASS * error_class, BACNET_ERROR_CODE * error_code);
|
||||
|
||||
#ifdef TEST
|
||||
#include "ctest.h"
|
||||
void testAnalogInput(Test * pTest);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user