Fixed 2 problems that Steve found:

1) Did not properly handle when RPM was not supported.
2) Did not handle small MAX_APDU values well.
This commit is contained in:
tbrennan3
2010-05-14 14:44:27 +00:00
parent 04e99f3671
commit c69686c99b
+109 -48
View File
@@ -68,8 +68,13 @@ static uint8_t Rx_Buf[MAX_MPDU] = { 0 };
/* target information converted from command line */ /* target information converted from command line */
static uint32_t Target_Device_Object_Instance = BACNET_MAX_INSTANCE; static uint32_t Target_Device_Object_Instance = BACNET_MAX_INSTANCE;
static BACNET_ADDRESS Target_Address; static BACNET_ADDRESS Target_Address;
/* = { 6, { 127, 0, 0, 1, 0xBA, 0xC0, 0 }, 0 }; loopback address to talk to myself */
/* any errors are picked up in main loop */ /* any errors are picked up in main loop */
static bool Error_Detected = false; static bool Error_Detected = false;
static uint16_t Last_Error_Class = 0;
static uint16_t Last_Error_Code = 0;
static bool Has_RPM = true; /* Assume device can do RPM, to start */
static EPICS_STATES myState = INITIAL_BINDING; static EPICS_STATES myState = INITIAL_BINDING;
/* any valid RP or RPM data returned is put here */ /* any valid RP or RPM data returned is put here */
@@ -104,6 +109,14 @@ static uint32_t Property_List_Index = 0;
static int32_t Property_List[MAX_PROPS + 2]; static int32_t Property_List[MAX_PROPS + 2];
/* This normally points to Property_List. */ /* This normally points to Property_List. */
static const int *pPropList = NULL; static const int *pPropList = NULL;
#define MINIMAL_PROPLIST_SIZE 4
static int32_t MinimalPropList[MINIMAL_PROPLIST_SIZE] =
{
PROP_OBJECT_IDENTIFIER,
PROP_OBJECT_NAME,
PROP_OBJECT_TYPE,
-1
};
/* When we have to walk through an array of things, like ObjectIDs or /* When we have to walk through an array of things, like ObjectIDs or
* Subordinate_Annotations, one RP call at a time, use these for indexing. * Subordinate_Annotations, one RP call at a time, use these for indexing.
@@ -132,14 +145,14 @@ static void MyErrorHandler(
(void) src; (void) src;
(void) invoke_id; (void) invoke_id;
#if PRINT_ERRORS #if PRINT_ERRORS
printf("-- BACnet Error: %s: %s\r\n", if ( ShowValues )
bactext_error_class_name(error_class), fprintf(stderr, "-- BACnet Error: %s: %s\r\n",
bactext_error_code_name(error_code)); bactext_error_class_name(error_class),
#else bactext_error_code_name(error_code));
(void) error_class;
(void) error_code;
#endif #endif
Error_Detected = true; Error_Detected = true;
Last_Error_Class = error_class;
Last_Error_Code = error_code;
} }
void MyAbortHandler( void MyAbortHandler(
@@ -154,13 +167,16 @@ void MyAbortHandler(
(void) server; (void) server;
#if PRINT_ERRORS #if PRINT_ERRORS
/* It is normal for this to fail, so don't print. */ /* It is normal for this to fail, so don't print. */
if ((myState != GET_ALL_RESPONSE) && !IsLongArray) if ((myState != GET_ALL_RESPONSE) && !IsLongArray && ShowValues )
printf("-- BACnet Abort: %s ", fprintf(stderr, "-- BACnet Abort: %s \r\n",
bactext_abort_reason_name(abort_reason)); bactext_abort_reason_name(abort_reason));
#else
(void) abort_reason;
#endif #endif
Error_Detected = true; Error_Detected = true;
Last_Error_Class = ERROR_CLASS_SERVICES;
if ( abort_reason < MAX_BACNET_ABORT_REASON )
Last_Error_Code = (ERROR_CODE_ABORT_BUFFER_OVERFLOW -1) + abort_reason;
else
Last_Error_Code = ERROR_CODE_ABORT_OTHER;
} }
void MyRejectHandler( void MyRejectHandler(
@@ -172,11 +188,15 @@ void MyRejectHandler(
(void) src; (void) src;
(void) invoke_id; (void) invoke_id;
#if PRINT_ERRORS #if PRINT_ERRORS
printf("BACnet Reject: %s\r\n", bactext_reject_reason_name(reject_reason)); if ( ShowValues )
#else fprintf(stderr, "BACnet Reject: %s\r\n", bactext_reject_reason_name(reject_reason));
(void) reject_reason;
#endif #endif
Error_Detected = true; Error_Detected = true;
Last_Error_Class = ERROR_CLASS_SERVICES;
if ( reject_reason < MAX_BACNET_REJECT_REASON )
Last_Error_Code = (ERROR_CODE_REJECT_BUFFER_OVERFLOW -1) + reject_reason;
else
Last_Error_Code = ERROR_CODE_REJECT_OTHER;
} }
void MyReadPropertyAckHandler( void MyReadPropertyAckHandler(
@@ -365,7 +385,7 @@ void PrintReadPropertyData(
value = rpm_property->value; value = rpm_property->value;
if (value == NULL) { if (value == NULL) {
/* Then we print the error information */ /* Then we print the error information */
fprintf(stdout, "? -- BACnet Error: %s: %s\r\n", fprintf(stderr, "? -- BACnet Error: %s: %s\r\n",
bactext_error_class_name((int) rpm_property->error.error_class), bactext_error_class_name((int) rpm_property->error.error_class),
bactext_error_code_name((int) rpm_property->error.error_code)); bactext_error_code_name((int) rpm_property->error.error_code));
return; return;
@@ -546,8 +566,11 @@ static uint8_t Read_Properties(
{ {
uint8_t invoke_id = 0; uint8_t invoke_id = 0;
struct special_property_list_t PropertyListStruct; struct special_property_list_t PropertyListStruct;
int i;
if (Property_List_Length == 0) { if ( ( !Has_RPM && ( Property_List_Index == 0 ) ) ||
( Property_List_Length == 0) )
{
/* If we failed to get the Properties with RPM, just settle for what we /* If we failed to get the Properties with RPM, just settle for what we
* know is the fixed list of Required (only) properties. * know is the fixed list of Required (only) properties.
* In practice, this should only happen for simple devices that don't * In practice, this should only happen for simple devices that don't
@@ -558,9 +581,14 @@ static uint8_t Read_Properties(
if (pPropList != NULL) { if (pPropList != NULL) {
Property_List_Length = PropertyListStruct.Required.count; Property_List_Length = PropertyListStruct.Required.count;
} else { } else {
fprintf(stdout, " -- No Properties available for %s \r\n", fprintf(stdout, " -- Just Minimal Properties: \r\n" );
bactext_object_type_name(pMyObject->type)); pPropList = MinimalPropList;
Property_List_Length = MINIMAL_PROPLIST_SIZE -1;
} }
/* Copy this list for later one-by-one processing */
for ( i = 0; i < Property_List_Length; i++ )
Property_List[i] = pPropList[i];
Property_List[i] = -1; /* Just to be sure we terminate */
} else } else
pPropList = Property_List; pPropList = Property_List;
@@ -576,7 +604,7 @@ static uint8_t Read_Properties(
array_index = Walked_List_Index; array_index = Walked_List_Index;
} }
} else { } else {
printf(" %s: ", bactext_property_name(prop)); fprintf(stdout, " %s: ", bactext_property_name(prop));
array_index = BACNET_ARRAY_ALL; array_index = BACNET_ARRAY_ALL;
switch (prop) { switch (prop) {
@@ -651,7 +679,7 @@ EPICS_STATES ProcessRPMData(
free(old_value); free(old_value);
} }
} else { } else {
printf(" %s: ", fprintf(stdout, " %s: ",
bactext_property_name(rpm_property->propertyIdentifier)); bactext_property_name(rpm_property->propertyIdentifier));
PrintReadPropertyData(rpm_property); PrintReadPropertyData(rpm_property);
} }
@@ -741,6 +769,22 @@ int CheckCommandLineArgs(
return 0; /* All OK if we reach here */ return 0; /* All OK if we reach here */
} }
/* Initialize fields for a new Object */
void StartNextObject( BACNET_READ_ACCESS_DATA *rpm_object, BACNET_OBJECT_ID *pNewObject )
{
BACNET_PROPERTY_REFERENCE *rpm_property;
Error_Detected = false;
Property_List_Index = Property_List_Length = 0;
rpm_object->object_type = pNewObject->type;
rpm_object->object_instance = pNewObject->instance;
rpm_property = calloc(1, sizeof(BACNET_PROPERTY_REFERENCE));
rpm_object->listOfProperties = rpm_property;
assert(rpm_property);
rpm_property->propertyIdentifier = PROP_ALL;
/* Start with a count of the array size */
rpm_property->propertyArrayIndex = 0;
}
/** Main function of the bacepics program. /** Main function of the bacepics program.
* *
* @see Device_Set_Object_Instance_Number, Keylist_Create, address_init, * @see Device_Set_Object_Instance_Number, Keylist_Create, address_init,
@@ -773,7 +817,6 @@ int main(
BACNET_OBJECT_ID myObject; BACNET_OBJECT_ID myObject;
uint8_t buffer[MAX_PDU] = { 0 }; uint8_t buffer[MAX_PDU] = { 0 };
BACNET_READ_ACCESS_DATA *rpm_object; BACNET_READ_ACCESS_DATA *rpm_object;
BACNET_PROPERTY_REFERENCE *rpm_property;
KEY nextKey; KEY nextKey;
CheckCommandLineArgs(argc, argv); /* Won't return if there is an issue. */ CheckCommandLineArgs(argc, argv); /* Won't return if there is an issue. */
@@ -784,6 +827,7 @@ int main(
address_init(); address_init();
Init_Service_Handlers(); Init_Service_Handlers();
dlenv_init(); dlenv_init();
/* bip_set_port( 0xBAC0 ); Set back to std BIP port */
/* configure the timeout values */ /* configure the timeout values */
current_seconds = time(NULL); current_seconds = time(NULL);
timeout_seconds = (apdu_timeout() / 1000) * apdu_retries(); timeout_seconds = (apdu_timeout() / 1000) * apdu_retries();
@@ -794,6 +838,10 @@ int main(
if (!found) { if (!found) {
Send_WhoIs(Target_Device_Object_Instance, Send_WhoIs(Target_Device_Object_Instance,
Target_Device_Object_Instance); Target_Device_Object_Instance);
/* In an Alternate universe, where we talk to ourselves:
* address_add_binding( Target_Device_Object_Instance, max_apdu,
* &Target_Address);
*/
} }
printf("List of Objects in test device:\r\n"); printf("List of Objects in test device:\r\n");
/* Print Opening brace, then kick off the Device Object */ /* Print Opening brace, then kick off the Device Object */
@@ -830,36 +878,30 @@ int main(
/* increment timer - exit if timed out */ /* increment timer - exit if timed out */
elapsed_seconds += (current_seconds - last_seconds); elapsed_seconds += (current_seconds - last_seconds);
if (elapsed_seconds > timeout_seconds) { if (elapsed_seconds > timeout_seconds) {
printf("\rError: APDU Timeout!\r\n"); fprintf(stderr, "\rError: APDU Timeout!\r\n");
break; break;
} }
/* else, loop back and try again */ /* else, loop back and try again */
continue; continue;
} else } else
{
myState = GET_ALL_REQUEST; myState = GET_ALL_REQUEST;
rpm_object = calloc(1, sizeof(BACNET_READ_ACCESS_DATA));
assert(rpm_object);
}
break; break;
case GET_ALL_REQUEST: case GET_ALL_REQUEST:
case GET_LIST_OF_ALL_REQUEST: /* differs in ArrayIndex only */ case GET_LIST_OF_ALL_REQUEST: /* differs in ArrayIndex only */
Error_Detected = false;
Property_List_Index = Property_List_Length = 0;
/* Update times; aids single-step debugging */ /* Update times; aids single-step debugging */
last_seconds = current_seconds; last_seconds = current_seconds;
rpm_object = calloc(1, sizeof(BACNET_READ_ACCESS_DATA)); StartNextObject( rpm_object, &myObject );
assert(rpm_object); /* Override the default and set the optional array index to "None" */
rpm_object->object_type = myObject.type; if (myState == GET_ALL_REQUEST)
rpm_object->object_instance = myObject.instance; rpm_object->listOfProperties->propertyArrayIndex = -1;
rpm_property = calloc(1, sizeof(BACNET_PROPERTY_REFERENCE));
rpm_object->listOfProperties = rpm_property;
assert(rpm_property);
rpm_property->propertyIdentifier = PROP_ALL;
if (myState == GET_LIST_OF_ALL_REQUEST)
rpm_property->propertyArrayIndex = 0; /* Get count of arrays */
else
rpm_property->propertyArrayIndex = -1; /* optional: None */
invoke_id = invoke_id =
Send_Read_Property_Multiple_Request(buffer, MAX_PDU, Send_Read_Property_Multiple_Request(buffer, MAX_PDU,
Target_Device_Object_Instance, rpm_object); Target_Device_Object_Instance, rpm_object);
if (invoke_id > 0) { if (invoke_id > 0) {
if (myState == GET_LIST_OF_ALL_REQUEST) if (myState == GET_LIST_OF_ALL_REQUEST)
myState = GET_LIST_OF_ALL_RESPONSE; myState = GET_LIST_OF_ALL_RESPONSE;
@@ -895,19 +937,31 @@ int main(
} else if (tsm_invoke_id_free(invoke_id)) { } else if (tsm_invoke_id_free(invoke_id)) {
invoke_id = 0; invoke_id = 0;
if (Error_Detected) { /* The normal case for Device Object */ if (Error_Detected) { /* The normal case for Device Object */
/* Try again, just to get a list of properties. */ /* Was it because the Device can't do RPM? */
if (myState == GET_ALL_RESPONSE) if ( Last_Error_Code == ERROR_CODE_REJECT_UNRECOGNIZED_SERVICE )
myState = GET_LIST_OF_ALL_REQUEST; {
/* Else it may be that RPM is not implemented. */ Has_RPM = false;
else
myState = GET_PROPERTY_REQUEST; myState = GET_PROPERTY_REQUEST;
} else }
/* Try again, just to get a list of properties. */
else if (myState == GET_ALL_RESPONSE)
myState = GET_LIST_OF_ALL_REQUEST;
/* Else drop back to RP. */
else
{
myState = GET_PROPERTY_REQUEST;
StartNextObject( rpm_object, &myObject );
}
}
else if ( Has_RPM )
myState = GET_ALL_REQUEST; /* Let's try again */ myState = GET_ALL_REQUEST; /* Let's try again */
else
myState = GET_PROPERTY_REQUEST;
} else if (tsm_invoke_id_failed(invoke_id)) { } else if (tsm_invoke_id_failed(invoke_id)) {
fprintf(stderr, "\rError: TSM Timeout!\r\n"); fprintf(stderr, "\rError: TSM Timeout!\r\n");
tsm_free_invoke_id(invoke_id); tsm_free_invoke_id(invoke_id);
invoke_id = 0; invoke_id = 0;
myState = GET_ALL_REQUEST; /* Let's try again */ myState = GET_ALL_REQUEST; /* Let's try again */
} else if (Error_Detected) { } else if (Error_Detected) {
/* Don't think we'll ever actually reach this point. */ /* Don't think we'll ever actually reach this point. */
invoke_id = 0; invoke_id = 0;
@@ -965,7 +1019,7 @@ int main(
} }
/* if ( pPropList[Property_List_Index] == PROP_OBJECT_LIST ) */ /* if ( pPropList[Property_List_Index] == PROP_OBJECT_LIST ) */
/* { */ /* { */
/* if ( !Using_Walked_List ) /* if ( !Using_Walked_List ) */
/* { */ /* { */
/* Just switched */ /* Just switched */
/* Using_Walked_List = true; */ /* Using_Walked_List = true; */
@@ -975,6 +1029,7 @@ int main(
myState = GET_PROPERTY_REQUEST; /* Go fetch next Property */ myState = GET_PROPERTY_REQUEST; /* Go fetch next Property */
} else if (tsm_invoke_id_free(invoke_id)) { } else if (tsm_invoke_id_free(invoke_id)) {
invoke_id = 0; invoke_id = 0;
myState = GET_PROPERTY_REQUEST;
if (Error_Detected) { if (Error_Detected) {
if (IsLongArray) { if (IsLongArray) {
/* Change to using a Walked List and retry this property */ /* Change to using a Walked List and retry this property */
@@ -985,10 +1040,10 @@ int main(
fprintf(stdout, " -- Failed to get %s \r\n", fprintf(stdout, " -- Failed to get %s \r\n",
bactext_property_name(pPropList bactext_property_name(pPropList
[Property_List_Index])); [Property_List_Index]));
Property_List_Index++; if ( ++Property_List_Index >= Property_List_Length )
myState = NEXT_OBJECT; /* Give up and move on to the next. */
} }
} }
myState = GET_PROPERTY_REQUEST;
} else if (tsm_invoke_id_failed(invoke_id)) { } else if (tsm_invoke_id_failed(invoke_id)) {
fprintf(stderr, "\rError: TSM Timeout!\r\n"); fprintf(stderr, "\rError: TSM Timeout!\r\n");
tsm_free_invoke_id(invoke_id); tsm_free_invoke_id(invoke_id);
@@ -1029,7 +1084,13 @@ int main(
printf( " -- Structured View %d \n", myObject.instance ); printf( " -- Structured View %d \n", myObject.instance );
*/ */
} }
myState = GET_ALL_REQUEST; if ( Has_RPM )
myState = GET_ALL_REQUEST;
else
{
myState = GET_PROPERTY_REQUEST;
StartNextObject( rpm_object, &myObject );
}
} while (myObject.type == OBJECT_DEVICE); } while (myObject.type == OBJECT_DEVICE);
/* Else, don't re-do the Device Object; move to the next object. */ /* Else, don't re-do the Device Object; move to the next object. */
@@ -1045,7 +1106,7 @@ int main(
/* increment timer - exit if timed out */ /* increment timer - exit if timed out */
elapsed_seconds += (current_seconds - last_seconds); elapsed_seconds += (current_seconds - last_seconds);
if (elapsed_seconds > timeout_seconds) { if (elapsed_seconds > timeout_seconds) {
printf("\rError: APDU Timeout!\r\n"); fprintf(stderr, "\rError: APDU Timeout!\r\n");
break; break;
} }
} }