Final fixes (I believe, for now) for EPICS generation.
Now has proper support for State Text and Subordinate Annotations text arrays, even very large ones. Now has 3 ways, of descending throughput, for all Objects and all their properties: a) Get all object properties with RPM for ALL b) Get individual properties with RP for Array_Index = ALL c) Walk through a too-large array one index step at a time.
This commit is contained in:
@@ -106,10 +106,15 @@ static int32_t Property_List[MAX_PROPS + 2];
|
|||||||
static const int *pPropList = NULL;
|
static const int *pPropList = NULL;
|
||||||
|
|
||||||
/* 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.
|
||||||
|
*/
|
||||||
static uint32_t Walked_List_Length = 0;
|
static uint32_t Walked_List_Length = 0;
|
||||||
static uint32_t Walked_List_Index = 0;
|
static uint32_t Walked_List_Index = 0;
|
||||||
|
/* TODO: Probably should have done this as additional EPICS_STATES */
|
||||||
static bool Using_Walked_List = false;
|
static bool Using_Walked_List = false;
|
||||||
|
/* When requesting RP for BACNET_ARRAY_ALL of what we know can be a long
|
||||||
|
* array, then set this true in case it aborts and we need Using_Walked_List */
|
||||||
|
static bool IsLongArray = false;
|
||||||
|
|
||||||
static bool ShowValues = false; /* Show value instead of '?' */
|
static bool ShowValues = false; /* Show value instead of '?' */
|
||||||
|
|
||||||
@@ -127,7 +132,7 @@ 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", bactext_error_class_name(error_class),
|
printf("-- BACnet Error: %s: %s\r\n", bactext_error_class_name(error_class),
|
||||||
bactext_error_code_name(error_code));
|
bactext_error_code_name(error_code));
|
||||||
#else
|
#else
|
||||||
(void) error_class;
|
(void) error_class;
|
||||||
@@ -148,8 +153,8 @@ 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 )
|
if ( ( myState != GET_ALL_RESPONSE ) && !IsLongArray )
|
||||||
printf("BACnet Abort: %s\r\n", bactext_abort_reason_name(abort_reason));
|
printf("-- BACnet Abort: %s ", bactext_abort_reason_name(abort_reason));
|
||||||
#else
|
#else
|
||||||
(void) abort_reason;
|
(void) abort_reason;
|
||||||
#endif
|
#endif
|
||||||
@@ -362,6 +367,7 @@ void PrintReadPropertyData(
|
|||||||
BACNET_APPLICATION_DATA_VALUE *value, *old_value;
|
BACNET_APPLICATION_DATA_VALUE *value, *old_value;
|
||||||
bool print_brace = false;
|
bool print_brace = false;
|
||||||
KEY object_list_element;
|
KEY object_list_element;
|
||||||
|
bool isSequence = false; /* Ie, will need bracketing braces {} */
|
||||||
|
|
||||||
if (rpm_property == NULL )
|
if (rpm_property == NULL )
|
||||||
{
|
{
|
||||||
@@ -405,8 +411,11 @@ void PrintReadPropertyData(
|
|||||||
{
|
{
|
||||||
switch( rpm_property->propertyIdentifier )
|
switch( rpm_property->propertyIdentifier )
|
||||||
{
|
{
|
||||||
|
/* These are all arrays, so they open and close with braces */
|
||||||
case PROP_OBJECT_LIST:
|
case PROP_OBJECT_LIST:
|
||||||
|
case PROP_STATE_TEXT:
|
||||||
case PROP_STRUCTURED_OBJECT_LIST:
|
case PROP_STRUCTURED_OBJECT_LIST:
|
||||||
|
case PROP_SUBORDINATE_ANNOTATIONS:
|
||||||
case PROP_SUBORDINATE_LIST:
|
case PROP_SUBORDINATE_LIST:
|
||||||
if ( Using_Walked_List )
|
if ( Using_Walked_List )
|
||||||
{
|
{
|
||||||
@@ -423,21 +432,30 @@ void PrintReadPropertyData(
|
|||||||
assert( Walked_List_Index == rpm_property->propertyArrayIndex);
|
assert( Walked_List_Index == rpm_property->propertyArrayIndex);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
Walked_List_Index++;
|
Walked_List_Index++;
|
||||||
|
/* If we got the whole Object List array in one RP call, keep
|
||||||
|
* the Index and List_Length in sync as we cycle through. */
|
||||||
|
if ( rpm_property->propertyIdentifier == PROP_OBJECT_LIST)
|
||||||
|
Object_List_Length = ++Object_List_Index;
|
||||||
|
}
|
||||||
if ( Walked_List_Index == 1 )
|
if ( Walked_List_Index == 1 )
|
||||||
{
|
{
|
||||||
/* Open the list of Objects (opening brace may be already printed) */
|
/* Open this Array of Objects for the first entry (unless
|
||||||
|
* opening brace has already printed, since this is an array
|
||||||
|
* of values[] ) */
|
||||||
if( value->next == NULL )
|
if( value->next == NULL )
|
||||||
fprintf(stdout, "{ \r\n ");
|
fprintf(stdout, "{ \r\n ");
|
||||||
else
|
else
|
||||||
fprintf(stdout, "\r\n ");
|
fprintf(stdout, "\r\n ");
|
||||||
}
|
}
|
||||||
if ( value->tag != BACNET_APPLICATION_TAG_OBJECT_ID ) {
|
|
||||||
assert( false ); /* Something not right here */
|
if ( rpm_property->propertyIdentifier == PROP_OBJECT_LIST)
|
||||||
break;
|
|
||||||
}
|
|
||||||
else if ( rpm_property->propertyIdentifier == PROP_OBJECT_LIST)
|
|
||||||
{
|
{
|
||||||
|
if ( value->tag != BACNET_APPLICATION_TAG_OBJECT_ID ) {
|
||||||
|
assert( false ); /* Something not right here */
|
||||||
|
break;
|
||||||
|
}
|
||||||
/* Store the object list so we can interrogate
|
/* Store the object list so we can interrogate
|
||||||
each object. */
|
each object. */
|
||||||
object_list_element =
|
object_list_element =
|
||||||
@@ -447,16 +465,42 @@ void PrintReadPropertyData(
|
|||||||
* yet, so just leave it null. The key is Key here. */
|
* yet, so just leave it null. The key is Key here. */
|
||||||
Keylist_Data_Add( Object_List, object_list_element, NULL );
|
Keylist_Data_Add( Object_List, object_list_element, NULL );
|
||||||
}
|
}
|
||||||
|
else if ( rpm_property->propertyIdentifier == PROP_STATE_TEXT )
|
||||||
|
{
|
||||||
|
/* Make sure it fits within 31 chars for original VTS3 limitation.
|
||||||
|
* If longer, take first 15 dash, and last 15 chars. */
|
||||||
|
if ( value->type.Character_String.length > 31 )
|
||||||
|
{
|
||||||
|
int iLast15idx = value->type.Character_String.length - 15;
|
||||||
|
value->type.Character_String.value[15] = '-';
|
||||||
|
memcpy( &value->type.Character_String.value[16],
|
||||||
|
&value->type.Character_String.value[iLast15idx], 15 );
|
||||||
|
value->type.Character_String.value[31] = 0;
|
||||||
|
value->type.Character_String.length = 31;
|
||||||
|
}
|
||||||
|
}
|
||||||
else if ( rpm_property->propertyIdentifier == PROP_SUBORDINATE_LIST)
|
else if ( rpm_property->propertyIdentifier == PROP_SUBORDINATE_LIST)
|
||||||
{
|
{
|
||||||
|
if ( value->tag != BACNET_APPLICATION_TAG_OBJECT_ID ) {
|
||||||
|
assert( false ); /* Something not right here */
|
||||||
|
break;
|
||||||
|
}
|
||||||
/* TODO: handle Sequence of { Device ObjID, Object ID }, */
|
/* TODO: handle Sequence of { Device ObjID, Object ID }, */
|
||||||
|
isSequence = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If the object is a Sequence, it needs its own bracketing braces */
|
||||||
|
if ( isSequence )
|
||||||
|
fprintf(stdout, "{");
|
||||||
bacapp_print_value(stdout, value, rpm_property->propertyIdentifier );
|
bacapp_print_value(stdout, value, rpm_property->propertyIdentifier );
|
||||||
|
if ( isSequence )
|
||||||
|
fprintf(stdout, "}");
|
||||||
|
|
||||||
if ( ( Walked_List_Index < Walked_List_Length ) ||
|
if ( ( Walked_List_Index < Walked_List_Length ) ||
|
||||||
( value->next != NULL ) )
|
( value->next != NULL ) )
|
||||||
{
|
{
|
||||||
/* There are more. */
|
/* There are more. */
|
||||||
fprintf(stdout, ",");
|
fprintf(stdout, ", ");
|
||||||
if (!(Walked_List_Index % 4))
|
if (!(Walked_List_Index % 4))
|
||||||
fprintf(stdout, "\r\n ");
|
fprintf(stdout, "\r\n ");
|
||||||
} else {
|
} else {
|
||||||
@@ -557,27 +601,37 @@ static uint8_t Read_Properties(
|
|||||||
if ( (pPropList != NULL ) && ( pPropList[Property_List_Index] != -1) )
|
if ( (pPropList != NULL ) && ( pPropList[Property_List_Index] != -1) )
|
||||||
{
|
{
|
||||||
int prop = pPropList[Property_List_Index];
|
int prop = pPropList[Property_List_Index];
|
||||||
|
int32_t array_index;
|
||||||
|
IsLongArray = false;
|
||||||
if ( Using_Walked_List )
|
if ( Using_Walked_List )
|
||||||
{
|
{
|
||||||
if (Walked_List_Length == 0) {
|
if (Walked_List_Length == 0) {
|
||||||
printf(" %s: ", bactext_property_name( prop ) );
|
// printf(" %s: ", bactext_property_name( prop ) );
|
||||||
invoke_id =
|
array_index = 0;
|
||||||
Send_Read_Property_Request(device_instance,
|
|
||||||
pMyObject->type, pMyObject->instance,
|
|
||||||
prop, 0);
|
|
||||||
} else {
|
} else {
|
||||||
invoke_id =
|
array_index = Walked_List_Index;
|
||||||
Send_Read_Property_Request(device_instance,
|
|
||||||
pMyObject->type, pMyObject->instance,
|
|
||||||
prop, Walked_List_Index);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
printf(" %s: ", bactext_property_name( prop ) );
|
printf(" %s: ", bactext_property_name( prop ) );
|
||||||
invoke_id =
|
array_index = BACNET_ARRAY_ALL;
|
||||||
Send_Read_Property_Request(device_instance,
|
|
||||||
pMyObject->type, pMyObject->instance,
|
switch( prop )
|
||||||
prop, BACNET_ARRAY_ALL);
|
{
|
||||||
|
/* These are all potentially long arrays, so they may abort */
|
||||||
|
case PROP_OBJECT_LIST:
|
||||||
|
case PROP_STATE_TEXT:
|
||||||
|
case PROP_STRUCTURED_OBJECT_LIST:
|
||||||
|
case PROP_SUBORDINATE_ANNOTATIONS:
|
||||||
|
case PROP_SUBORDINATE_LIST:
|
||||||
|
IsLongArray = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
invoke_id =
|
||||||
|
Send_Read_Property_Request(device_instance,
|
||||||
|
pMyObject->type, pMyObject->instance,
|
||||||
|
prop, array_index );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return invoke_id;
|
return invoke_id;
|
||||||
@@ -956,24 +1010,31 @@ int main(
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
Property_List_Index++;
|
Property_List_Index++;
|
||||||
if ( pPropList[Property_List_Index] == PROP_OBJECT_LIST )
|
// if ( pPropList[Property_List_Index] == PROP_OBJECT_LIST )
|
||||||
{
|
// {
|
||||||
if ( !Using_Walked_List ) /* Just switched */
|
// if ( !Using_Walked_List ) /* Just switched */
|
||||||
{
|
// {
|
||||||
Using_Walked_List = true;
|
// Using_Walked_List = true;
|
||||||
Walked_List_Index = Walked_List_Length = 0;
|
// Walked_List_Index = Walked_List_Length = 0;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
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;
|
||||||
if (Error_Detected)
|
if (Error_Detected)
|
||||||
{
|
{
|
||||||
/* OK, skip this one and try the next property. */
|
if ( IsLongArray ) {
|
||||||
fprintf( stdout, " -- Failed to get %s \r\n",
|
/* Change to using a Walked List and retry this property */
|
||||||
bactext_property_name(pPropList[Property_List_Index]) );
|
Using_Walked_List = true;
|
||||||
Property_List_Index++;
|
Walked_List_Index = Walked_List_Length = 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* OK, skip this one and try the next property. */
|
||||||
|
fprintf( stdout, " -- Failed to get %s \r\n",
|
||||||
|
bactext_property_name(pPropList[Property_List_Index]) );
|
||||||
|
Property_List_Index++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
myState = GET_PROPERTY_REQUEST;
|
myState = GET_PROPERTY_REQUEST;
|
||||||
} else if (tsm_invoke_id_failed(invoke_id)) {
|
} else if (tsm_invoke_id_failed(invoke_id)) {
|
||||||
|
|||||||
Reference in New Issue
Block a user