modified for AtomicReadFile handling.

This commit is contained in:
skarg
2005-06-12 01:01:30 +00:00
parent cfeffab82f
commit 2624538022
14 changed files with 402 additions and 60 deletions
+3
View File
@@ -25,6 +25,9 @@ SRCS = ports/linux/main.c \
device.c \
ai.c \
ao.c \
bacfile.c \
arf.c \
awf.c \
abort.c \
reject.c \
bacerror.c \
+1 -1
View File
@@ -33,7 +33,7 @@
#include "bacenum.h"
#include "config.h" // the custom stuff
#define MAX_ANALOG_INPUTS 32
#define MAX_ANALOG_INPUTS 7
// we simply have 0-n object instances. Yours might be
// more complex, and then you need validate that the
+1 -1
View File
@@ -34,7 +34,7 @@
#include "config.h" // the custom stuff
#include "wp.h"
#define MAX_ANALOG_OUTPUTS 20
#define MAX_ANALOG_OUTPUTS 4
// we choose to have a NULL level in our system represented by
// a particular value. When the priorities are not in use, they
+55 -15
View File
@@ -42,6 +42,25 @@
#include "tsm.h"
#include "iam.h"
#ifdef TEST
void tsm_free_invoke_id(uint8_t invokeID)
{
// dummy stub for testing
(void)invokeID;
}
void iam_handler(
uint8_t *service_request,
uint16_t service_len,
BACNET_ADDRESS *src)
{
// dummy stub for testing
(void)service_request;
(void)service_len;
(void)src;
}
#endif
// Confirmed Function Handlers
// If they are not set, they are handled by a reject message
static confirmed_function
@@ -149,6 +168,35 @@ void apdu_set_confirmed_ack_handler(
}
}
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, // source address
bool data_expecting_reply,
@@ -170,21 +218,13 @@ void apdu_handler(
switch (apdu[0] & 0xF0)
{
case PDU_TYPE_CONFIRMED_SERVICE_REQUEST:
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;
len = apdu_decode_confirmed_service_request(
&apdu[0], // APDU data
apdu_len,
&service_data,
&service_choice,
&service_request,
&service_request_len);
if (service_choice < MAX_BACNET_CONFIRMED_SERVICE)
{
if (Confirmed_Function[service_choice])
+8
View File
@@ -125,6 +125,14 @@ void apdu_set_unconfirmed_handler(
BACNET_UNCONFIRMED_SERVICE service_choice,
unconfirmed_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
bool data_expecting_reply,
+2 -2
View File
@@ -1270,7 +1270,7 @@ int decode_bacnet_time(uint8_t * apdu, int *hour, int *min, int *sec,
int encode_bacnet_date(uint8_t * apdu, int year, int month, int day,
int wday)
{
apdu[0] = year;
apdu[0] = year - 1900;
apdu[1] = month;
apdu[2] = day;
apdu[3] = wday;
@@ -1299,7 +1299,7 @@ int encode_tagged_date(uint8_t * apdu, int year, int month, int day,
// returns the number of apdu bytes consumed
int decode_date(uint8_t * apdu, int *year, int *month, int *day, int *wday)
{
*year = apdu[0];
*year = apdu[0] + 1900;
*month = apdu[1];
*day = apdu[2];
*wday = apdu[3];
+14 -1
View File
@@ -31,6 +31,7 @@
#include "config.h" // the custom stuff
#include "ai.h" // object list dependency
#include "ao.h" // object list dependency
#include "bacfile.h" // object list dependency
#include "wp.h" // write property handling
static uint32_t Object_Instance_Number = 0;
@@ -228,6 +229,7 @@ unsigned Device_Object_List_Count(void)
count += Analog_Input_Count();
count += Analog_Output_Count();
count += bacfile_count();
return count;
}
@@ -267,7 +269,18 @@ bool Device_Object_List_Identifier(unsigned array_index,
status = true;
}
}
if (!status)
{
object_index -= Analog_Output_Count();
if (object_index < bacfile_count())
{
*object_type = OBJECT_FILE;
*instance = bacfile_index_to_instance(object_index);
status = true;
}
}
return status;
}
+207
View File
@@ -37,6 +37,8 @@
#include "ao.h"
#include "rp.h"
#include "wp.h"
#include "arf.h"
#include "bacfile.h"
#include "whois.h"
#include "iam.h"
#include "reject.h"
@@ -411,6 +413,39 @@ void ReadPropertyHandler(
else
error = true;
break;
case OBJECT_FILE:
if (bacfile_valid_instance(object_instance))
{
len = bacfile_encode_property_apdu(
&Temp_Buf[0],
object_instance,
object_property,
array_index,
&error_class,
&error_code);
if (len > 0)
{
// encode the APDU portion of the packet
rp_data.object_type = object_type;
rp_data.object_instance = object_instance;
rp_data.object_property = object_property;
rp_data.array_index = array_index;
rp_data.application_data = &Temp_Buf[0];
rp_data.application_data_len = len;
// FIXME: probably need a length limitation sent with encode
pdu_len += rp_ack_encode_apdu(
&Tx_Buf[pdu_len],
service_data->invoke_id,
&rp_data);
fprintf(stderr,"Sending Read Property Ack!\n");
send = true;
}
else
error = true;
}
else
error = true;
break;
default:
error = true;
break;
@@ -570,3 +605,175 @@ void WritePropertyHandler(
return;
}
void AtomicReadFileHandler(
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;
BACNET_ADDRESS my_address;
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;
char buffer[MAX_APDU - 16] = ""; // for reply data, less apdu overhead
fprintf(stderr,"Received Atomic-Read-File Request!\n");
len = arf_decode_service_request(
service_request,
service_len,
&data);
if (len < 0)
fprintf(stderr,"Unable to decode Atomic-Read-File Request!\n");
// prepare a reply
datalink_get_my_address(&my_address);
// encode the NPDU portion of the packet
pdu_len = npdu_encode_apdu(
&Tx_Buf[0],
src,
&my_address,
false, // true for confirmed messages
MESSAGE_PRIORITY_NORMAL);
// bad decoding - send an abort
if (len < 0)
{
pdu_len += abort_encode_apdu(
&Tx_Buf[pdu_len],
service_data->invoke_id,
ABORT_REASON_OTHER);
fprintf(stderr,"Sending Abort!\n");
send = true;
}
else if (service_data->segmented_message)
{
pdu_len += abort_encode_apdu(
&Tx_Buf[pdu_len],
service_data->invoke_id,
ABORT_REASON_SEGMENTATION_NOT_SUPPORTED);
fprintf(stderr,"Sending Abort!\n");
send = true;
}
else
{
if (data.access == FILE_STREAM_ACCESS)
{
data.fileData = &buffer[0];
data.fileDataLength = sizeof(buffer);
if (data.type.stream.requestedOctetCount < data.fileDataLength)
{
if (bacfile_read_data(&data))
{
pdu_len += arf_ack_encode_apdu(
&Tx_Buf[pdu_len],
service_data->invoke_id,
&data);
send = true;
}
else
{
send = true;
error = true;
}
}
else
{
pdu_len += abort_encode_apdu(
&Tx_Buf[pdu_len],
service_data->invoke_id,
ABORT_REASON_SEGMENTATION_NOT_SUPPORTED);
fprintf(stderr,"Sending Abort!\n");
send = true;
}
}
else
{
error_class = ERROR_CLASS_SERVICES;
error_code = ERROR_CODE_INVALID_FILE_ACCESS_METHOD;
send = true;
error = true;
}
}
if (error)
{
pdu_len += bacerror_encode_apdu(
&Tx_Buf[pdu_len],
service_data->invoke_id,
SERVICE_CONFIRMED_ATOMIC_READ_FILE,
error_class,
error_code);
fprintf(stderr,"Sending Error!\n");
send = true;
}
if (send)
{
bytes_sent = datalink_send_pdu(
src, // destination address
&Tx_Buf[0],
pdu_len); // number of bytes of data
if (bytes_sent <= 0)
fprintf(stderr,"Failed to send PDU (%s)!\n", strerror(errno));
}
return;
}
// 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.
void AtomicReadFileAckHandler(
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);
tsm_free_invoke_id(service_data->invoke_id);
len = arf_ack_decode_service_request(
service_request,
service_len,
&data);
fprintf(stderr,"Received Read-File Ack!\n");
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(data.fileData,data.fileDataLength,1,pFile) != 1)
fprintf(stderr,"Failed to write to %s (%u)!\n",
pFilename, instance);
fclose(pFile);
}
}
}
else if (data.access == FILE_RECORD_ACCESS)
{
// FIXME: add handling for Record Access
}
}
}
+11
View File
@@ -76,4 +76,15 @@ bool Send_Read_Property_Request(
BACNET_PROPERTY_ID object_property,
int32_t array_index);
void AtomicReadFileHandler(
uint8_t *service_request,
uint16_t service_len,
BACNET_ADDRESS *src,
BACNET_CONFIRMED_SERVICE_DATA *service_data);
void AtomicReadFileAckHandler(
uint8_t *service_request,
uint16_t service_len,
BACNET_ADDRESS *src,
BACNET_CONFIRMED_SERVICE_ACK_DATA *service_data);
#endif
+1
View File
@@ -66,6 +66,7 @@ void iam_handler(
int iam_send(uint8_t *buffer);
#ifdef TEST
#include "ctest.h"
void testIAm(Test * pTest);
#endif
+51 -38
View File
@@ -175,7 +175,11 @@ int npdu_decode(
BACNET_NPDU_DATA *npdu_data)
{
int len = 0; // return value - number of octets loaded in this function
int i = 0; // counter
int i = 0; // counter
uint16_t src_net = 0;
uint16_t dest_net = 0;
uint8_t address_len = 0;
uint8_t mac_octet = 0;
if (npdu && npdu_data)
{
@@ -211,30 +215,35 @@ int npdu_decode(
// 1 = DNET, DLEN, and Hop Count present
// DLEN = 0 denotes broadcast MAC DADR and DADR field is absent
// DLEN > 0 specifies length of DADR field
if (dest)
if (npdu[1] & BIT5)
{
if (npdu[1] & BIT5)
len += decode_unsigned16(&npdu[len], &dest_net);
// DLEN = 0 denotes broadcast MAC DADR and DADR field is absent
// DLEN > 0 specifies length of DADR field
address_len = npdu[len++];
if (dest)
{
len += decode_unsigned16(&npdu[len], &dest->net);
// DLEN = 0 denotes broadcast MAC DADR and DADR field is absent
// DLEN > 0 specifies length of DADR field
dest->len = npdu[len++];
if (dest->len)
dest->net = dest_net;
dest->len = address_len;
}
if (address_len)
{
for (i = 0; i < address_len; i++)
{
for (i = 0; i < dest->len; i++)
{
dest->adr[i] = npdu[len++];
}
mac_octet = npdu[len++];
if (dest)
dest->adr[i] = mac_octet;
}
}
else
}
// zero out the destination address
else if (dest)
{
dest->net = 0;
dest->len = 0;
for (i = 0; i < MAX_MAC_LEN; i++)
{
dest->net = 0;
dest->len = 0;
for (i = 0; i < MAX_MAC_LEN; i++)
{
dest->adr[i] = 0;
}
dest->adr[i] = 0;
}
}
// Bit 3: Source specifier where:
@@ -242,36 +251,40 @@ int npdu_decode(
// 1 = SNET, SLEN, and SADR present
// SLEN = 0 Invalid
// SLEN > 0 specifies length of SADR field
if (src)
if (npdu[1] & BIT3)
{
if (npdu[1] & BIT3)
len += decode_unsigned16(&npdu[len], &src_net);
// SLEN = 0 denotes broadcast MAC SADR and SADR field is absent
// SLEN > 0 specifies length of SADR field
address_len = npdu[len++];
if (src)
{
len += decode_unsigned16(&npdu[len], &src->net);
// SLEN = 0 denotes broadcast MAC SADR and SADR field is absent
// SLEN > 0 specifies length of SADR field
src->len = npdu[len++];
if (src->len)
src->net = src_net;
src->len = address_len;
}
if (address_len)
{
for (i = 0; i < address_len; i++)
{
for (i = 0; i < src->len; i++)
{
src->adr[i] = npdu[len++];
}
mac_octet = npdu[len++];
if (src)
src->adr[i] = mac_octet;
}
}
else
}
else if (src)
{
src->net = 0;
src->len = 0;
for (i = 0; i < MAX_MAC_LEN; i++)
{
src->net = 0;
src->len = 0;
for (i = 0; i < MAX_MAC_LEN; i++)
{
src->adr[i] = 0;
}
src->adr[i] = 0;
}
}
// The Hop Count field shall be present only if the message is
// destined for a remote network, i.e., if DNET is present.
// This is a one-octet field that is initialized to a value of 0xff.
if (dest && dest->net)
if (dest_net)
npdu_data->hop_count = npdu[len++];
else
npdu_data->hop_count = 0;
+8
View File
@@ -38,6 +38,7 @@
#include "iam.h"
#include "tsm.h"
#include "device.h"
#include "bacfile.h"
#ifdef BACDL_ETHERNET
#include "ethernet.h"
#endif
@@ -236,6 +237,7 @@ static void Init_Service_Handlers(void)
// It is required to send the proper reject message...
apdu_set_unrecognized_service_handler_handler(
UnrecognizedServiceHandler);
// Set the handlers for any confirmed services that we support
// we must implement read property - it's required!
apdu_set_confirmed_handler(
SERVICE_CONFIRMED_READ_PROPERTY,
@@ -243,10 +245,16 @@ static void Init_Service_Handlers(void)
apdu_set_confirmed_handler(
SERVICE_CONFIRMED_WRITE_PROPERTY,
WritePropertyHandler);
apdu_set_confirmed_handler(
SERVICE_CONFIRMED_ATOMIC_READ_FILE,
AtomicReadFileHandler);
// handle the data coming back from confirmed requests
apdu_set_confirmed_ack_handler(
SERVICE_CONFIRMED_READ_PROPERTY,
ReadPropertyAckHandler);
apdu_set_confirmed_ack_handler(
SERVICE_CONFIRMED_ATOMIC_READ_FILE,
AtomicReadFileAckHandler);
}
static void print_address_cache(void)
+34 -2
View File
@@ -137,7 +137,6 @@ uint8_t tsm_next_free_invokeID(void)
return invokeID;
}
// returns 0 if there are no free transactions
void tsm_set_confirmed_unsegmented_transaction(
uint8_t invokeID,
BACNET_ADDRESS *dest,
@@ -146,7 +145,6 @@ void tsm_set_confirmed_unsegmented_transaction(
{
uint16_t j = 0;
uint8_t index;
if (invokeID)
{
@@ -171,6 +169,40 @@ void tsm_set_confirmed_unsegmented_transaction(
return;
}
// used to retrieve the transaction payload
// if we wanted to find out what we sent (i.e. when we get an ack)
bool tsm_get_transaction_pdu(
uint8_t invokeID,
BACNET_ADDRESS *dest,
uint8_t *pdu,
uint16_t *pdu_len)
{
uint16_t j = 0;
uint8_t index;
bool found = false;
if (invokeID)
{
index = tsm_find_invokeID_index(invokeID);
// how much checking is needed? state? dest match? just invokeID?
if (index < MAX_TSM_TRANSACTIONS)
{
// FIXME: we may want to free the transaction so it doesn't timeout
// retrieve the transaction
// FIXME: bounds check the pdu_len?
*pdu_len = TSM_List[index].pdu_len;
for (j = 0; j < *pdu_len; j++)
{
pdu[j] = TSM_List[index].pdu[j];
}
address_copy(dest,&TSM_List[index].dest);
found = true;
}
}
return found;
}
// called once a millisecond
void tsm_timer_milliseconds(uint16_t milliseconds)
{
+6
View File
@@ -97,6 +97,12 @@ void tsm_set_confirmed_unsegmented_transaction(
BACNET_ADDRESS *dest,
uint8_t *pdu,
uint16_t pdu_len);
// returns true if transaction is found
bool tsm_get_transaction_pdu(
uint8_t invokeID,
BACNET_ADDRESS *dest,
uint8_t *pdu,
uint16_t *pdu_len);
#endif