0

How can I determine the size of a PIM (Per Instance Memory) in c from inside a Runnable (without looking it up in the generated RTE and adding a fix value)?

Situation: Runnable Foo has access to two PIMs Pim1 and Pim2. In the example the data from Pim1 shall be copied to Pim2.

Not only because of security and safety I need to check the size of both PIMs in order NOT to overwrite illegal data areas. I know that the size of the PIM is configured in the SW-C description (SWCD). But as the SWCD may be changed after code implementation and in order to keep the code of the Runnable more generic, the size checking should not be based on fix values.

I also considered the problem of the sizeof for an array: How to find the 'sizeof'(a pointer pointing to an array)?

For the PIMs the following code is generated by the RTE-Generator:

In Rte_Type.h

typedef uint8 Rte_DT_DtImplRec1_0;
typedef uint16 Rte_DT_DtImplRec1_1;

typedef struct
{
  Rte_DT_DtImplRec1_0 var1;
  Rte_DT_DtImplRec1_1 var2;
  Rte_DT_DtImplRec1_2 var3;
} DtImplRec1;

typedef uint8 Rte_DT_DtImplAry1_0;
typedef Rte_DT_DtImplAry1_0 DtImplAry1[5];

In Rte.c

VAR(DtImplRec1, RTE_VAR_DEFAULT_RTE_PIM_GROUP) Rte_FOO_Pim1;
VAR(DtImplAry1, RTE_VAR_DEFAULT_RTE_PIM_GROUP) Rte_FOO_Pim2;

In Rte_FOO.h

#define Rte_Pim_Pim1() (&Rte_FOO_Pim1)

#ifdef RTE_PTR2ARRAYBASETYPE_PASSING
# define Rte_Pim_Pim2() (&((*RtePim_Pim2())[0]))
#else
# define Rte_Pim_Pim2() RtePim_Pim2()
#endif

#define RtePim_Pim2() (&Rte_FOO_Pim2)

Note that the define for array PIMs might also be changing, depending on the RTE_PTR2ARRAYBASETYPE_PASSING “switch”.

The following “access” is generated for the FOO template:

DtImplRec1 *Rte_Pim_Pim1(void);
Rte_DT_DtImplAry1_0 *Rte_Pim_Pim2(void)

The code for the Foo-Runnable may look like this:

FUNC(void, FOO_CODE) Foo(void)
{
  DtImplRec1 *pim1 = Rte_Pim_Pim1();
  Rte_DT_DtImplAry1_0 *pim2 = Rte_Pim_Pim2();

  uint8 sizeOfPim1a = sizeof(Rte_Pim_Pim1());    /* always returns 4 as the size of the pointer */
  uint8 sizeOfPim1b = sizeof(*Rte_Pim_Pim1());   /* evaluates to 6 */
  uint8 sizeOfPim1c = sizeof(DtImplRec1);        /* evaluates to 6 */
  uint8 sizeOfPim1d = sizeof(Rte_FOO_Pim1);      /* evaluates to 6 */

  uint8 sizeOfPim2a = sizeof(Rte_Pim_Pim2());       /* always returns 4 as the size of the pointer */
  uint8 sizeOfPim2b = sizeof(*Rte_Pim_Pim2());      /* evaluates to 1 */
  uint8 sizeOfPim2c = sizeof(Rte_DT_DtImplAry1_0);  /* evaluates to 1: sizeof(uint8) */

  uint8 finalSize = MIN(sizeOfPim1b, sizeOfPim2b);

  memcpy( pim2, pim1, finalSize ); /* (use of) memcpy is not the topic here */
}

To make my problem more "visible", here is a Callback-Runnable example for writing a DID via diagnostics:

FUNC(Std_ReturnType, FOO_CODE)
  DataServices_Data_FFFF_WriteData(P2CONST(uint8, AUTOMATIC, RTE_APPL_DATA) Data, Dcm_OpStatusType OpStatus, P2VAR(Dcm_NegativeResponseCodeType, AUTOMATIC, RTE_APPL_DATA) ErrorCode)
{
  Std_ReturnType ret = E_NOT_OK;

  #define sizeOfPim1     (5)   /* how to determine the PIM size here if we do not know anything about it here? (PIM structure can change without modifying the code here) */
  #define sizeOfDidFFFF  (5)   /* This is even another problem: How to determine the size of a DID. I will create another discussion thread for this question. */

  /* Instead of this if-condition, an assert during compile-time would also be appropriate */
  if( sizeOfPim1 == sizeOfDidFFFF )
  {
    /* We have to make sure that we do not copy more bytes as of the size of Pim1 */
    memcpy( Rte_Pim_Pim1(), Data, sizeOfPim1 ); /* (use of) memcpy is not the topic here */
    ret = E_OK;
  }

  return ret;
}
Oliver Scheid
  • 182
  • 2
  • 15

2 Answers2

0

I don't have here any AUTOSAR environment to test this, so, please, if you try any of this, just let me know if it works. Besides, I am not an expert and it is quite a long time I don't write AUTOSAR code, so I will probably be missing something. I also don't want to publicize any RTE generator from any vendor, so I will cite only the standard.

Use sizeof(DtImplAry1)

You define that type and give it as input to the RTE generator, so you know the name. If your SWC doesn't make explicit use of that type the RTE generator could not include it in your .h, but you could add it manually to you SWC arxml. I think all tools out there allow to do this without having to edit the arxml by hand, just look for the option to include additional SWC types in your tool.

Use Instance API to access SWC data

The standard specifies a variable of type Rte_CDS_FOO to hold all pointers to PIMs of the SWC (among other things) if you enable the API (look for it in your tool). Besides, a variable Rte_Inst_FOO should be available to you, declared as extern in your header. You could do sizeof(*Rte_Inst_FOO->Pim_Pim2).

EDIT: reply to some of your comments

I guess the reason you don't find the CDS is because of this (from Specification of RTE, 4.2.2, 5.4 RTE Data Structures):

The [CDS and Instance handler] definitions only apply to RTE generators operating in compatibility mode – in this mode the instance handle and the component data structure have to be defined even for those (object-code) software components for which multiple instantiation is forbidden to ensure compatibility.

Also,

[SWS_Rte_03793] If a software component does not support multiple instantiation,the name of the component data instance shall be Rte_Inst_cts, where cts is the component type symbol of the AtomicSwComponentType. (SRS_Rte_00011)

So, when the RTE-generator adheres to this compatibility mode, those variables must be there. If you are using a vendor specific solution, well, try to tag the question with that vendor name also, hopefully somebody can answer.

Assert at compile time

I am not going to ask why you are doing this, but IMHO I think it does not sound right, does it makes sense for the receiving buffer to be smaller that the data to copy?. Maybe it is better to assert at compile time if the buffer is smaller than your struct. Or you could define your array instead to be a struct and cast it if needed (if your are following MISRA rules, maybe you will have problems with it, just check). Just for reference, compile time assertions can use sizeof.

Fusho
  • 1,469
  • 1
  • 10
  • 22
  • Thank you. Unfortunately it does not solve my problem: First of all, this Component Data Structure (CDS) is only available for SW-Cs that "support multiple instantiation". Apart from that, the CDS struct which is generated by "my" RTE-generator only contains pointers to the PIM-access-functions. I assume that this structure is highly vendor specific anyhow. Using an assert at build time is a good proposal. However, I still need the information about the PIM size. To make my problem more "visible", I have added a Callback-Runnable example for writing a DID via diagnostics above. – Oliver Scheid Jun 05 '17 at 11:13
  • I understand what you say, please, check the edit. Also, have you tried the first suggestion? Is the type of the Pim available in your runnable?. And the other suggestion: to define it as the original struct instead of an array and cast? – Fusho Jun 05 '17 at 15:07
  • I actually did not follow your first proposal, as I am looking for a more generic solution. Also the other suggestion for defining the PIM as struct etc. is not what I'm looking for. As in the example with DataServices_Data_FFFF_WriteData() I don't want to care much about the PIM details but simply copy the data of (already existing) PIMs, considering the PIM size. I checked the setting of the RTE generator and it was already running in COMPATIBILITY_MODE. Note that I'm running AR4.0 but I think it should make no difference there. – Oliver Scheid Jun 05 '17 at 19:18
  • I think there is no such easy and generic solution available here. What makes me wonder is why nobody else ever raised this probolem. The C-code that I see from other programmers is simply not safe enough. – Oliver Scheid Jun 05 '17 at 19:19
  • As you already said, the definition of the PIM is in the SWCD. And this SWCD describes your SW-C. If it is not in sync with your implementation would be problematic, but it should be testable by Integration Tests. PIMs are either types by AUTOSAR appl/impl types, or as C-types in the SWCD. Also the DiagServices are typed by DiagService specific datatypes, which means, also your WriteData should be typed by this specific DataService_XXX type. This could also be added to a DiagServiceNeeds, afaik. – kesselhaus May 13 '18 at 08:36
0

You have several problems here: a) your sizeof(*pim1) returns 6 because of padding, because you start with an uint8, the second is uint16, and I guess the 3rd ist also uint16.

That's, why you should rather sort them by type size/alignment .. biggest to smallest

uint32
uint16
uint8

Even though, the elements might not be ordered anymore, but it also decreases finally the gaps in memory created by the linker.

b) the pim2 is an array, you can not get the array len/size from the pointer. But, you should have the Rte definition of DtImplAry1.

typedef uint8 Rte_DT_DtImplAry1_0;
typedef Rte_DT_DtImplAry1_0 DtImplAry1[5];  // <-- taken in through Rte_Foo_Type.h (includes Rte_Type.h

uint32 ary_len = sizeof(DtImplAry1) / sizeof(DtImplAry1[0]);
kesselhaus
  • 1,241
  • 8
  • 9
  • Thank you for your hints, which are both supportive. But actually I'm looking for some generic solution that works with all kind of PIMs. Use case is the mentioned DataServices_Data_FFFF_WriteData() or _Read(). The idea is to make the code realiable (safe) by checking the size before copying data and to have code that is easy to maintain (=> independent of the PIM structure and size) – Oliver Scheid Jul 19 '17 at 07:06