299 lines
12 KiB
C
299 lines
12 KiB
C
/**
|
||
* @file batch_endurance_testbench.c
|
||
*
|
||
* @brief Batch mode test bench:
|
||
* 1. Write to all nodes (at 100ms intervals)
|
||
* 2. Read all nodes
|
||
* 3. Verify positions (retry mismatch up to 2 times)
|
||
* 4. Cycle complete – reset for next iteration
|
||
*
|
||
* @copyright
|
||
*/
|
||
|
||
#include "enduranceTestBench.h"
|
||
#include "stdlib.h"
|
||
|
||
/* CANopen includes */
|
||
#include <gen_define.h>
|
||
#include <co_canopen.h>
|
||
#include "../nms_hal/hal_system.h"
|
||
|
||
/******************************************************************************
|
||
* Macro constant declarations
|
||
******************************************************************************/
|
||
#define ENDURANCE_TEST_BENCH_MAX_RETRY_CNT 3u
|
||
#define ENDURANCE_TEST_BENCH_TIMEOUT 1000u
|
||
#define ENDURANCE_TEST_BENCH_LSS_NODE_COUNT 20u
|
||
#define ENDURANCE_TEST_BENCH_POSITION_SETPOINT_INDEX 0x6002
|
||
#define ENDURANCE_TEST_BENCH_POSITION_SETPOINT_SUB_INDEX 0x0
|
||
#define ENDURANCE_TEST_BENCH_POSITION_FEEDBACK_INDEX 0x6004
|
||
#define ENDURANCE_TEST_BENCH_POSITION_FEEDBACK_SUB_INDEX 0x0
|
||
|
||
/* Batch delay between node operations (in ms) */
|
||
#define NODE_OP_DELAY_MS 100u
|
||
|
||
/******************************************************************************
|
||
* Type Declarations
|
||
******************************************************************************/
|
||
typedef enum
|
||
{
|
||
TEST_BENCH_BATCH_WRITE, /* Write to nodes in batch */
|
||
TEST_BENCH_BATCH_WRITE_WAIT, /* Wait between writes */
|
||
TEST_BENCH_BATCH_READ, /* Read all nodes */
|
||
TEST_BENCH_BATCH_READ_WAIT, /* Wait between reads */
|
||
TEST_BENCH_BATCH_VERIFY, /* Verify all nodes */
|
||
TEST_BENCH_CYCLE_COMPLETE, /* End of cycle, reset for next iteration */
|
||
TEST_BENCH_IDLE /* Idle state (optional) */
|
||
} SdlTestBenchState_en;
|
||
|
||
typedef enum
|
||
{
|
||
TEST_BENCH_DATA_VERIF_DEFAULT,
|
||
TEST_BENCH_DATA_VERIF_SUCCESS,
|
||
TEST_BENCH_DATA_VERIF_FAILURE,
|
||
TEST_BENCH_DATA_VERIF_SKIPPED,
|
||
} TestBenchStatus_en;
|
||
|
||
typedef struct
|
||
{
|
||
uint8 targetPositions_gau8[ENDURANCE_TEST_BENCH_LSS_NODE_COUNT];
|
||
uint8 readPosition_gau8[ENDURANCE_TEST_BENCH_LSS_NODE_COUNT];
|
||
TestBenchStatus_en status_en[ENDURANCE_TEST_BENCH_LSS_NODE_COUNT];
|
||
} TestBenchData_en;
|
||
|
||
/******************************************************************************
|
||
* Global variable declarations
|
||
******************************************************************************/
|
||
static TestBenchData_en testBenchData_en;
|
||
static uint8 currentNode_gu8 = 0u;
|
||
static SdlTestBenchState_en testBenchState_en = TEST_BENCH_IDLE;
|
||
static uint32 readPosition_gu32;
|
||
static uint8 storedTargetPos = 0u; /* Flag: target written to current node */
|
||
static uint8 readMismatchRetries_u8 = 0u; /* Retry count for verify mismatches */
|
||
|
||
static uint64 writeTime_u64 = 0uLL;
|
||
static uint64 readExecutedTime_u64 = 0uLL;
|
||
static uint64 cycleStartTime_u64 = 0uLL;
|
||
static uint8 retries_u8 = 0u; /* General retry counter for SDO communication */
|
||
|
||
/******************************************************************************
|
||
* Public Function Definitions
|
||
******************************************************************************/
|
||
void TestRun(void)
|
||
{
|
||
uint64 currentTime_u64;
|
||
HalSystemGetRunTimeMs(¤tTime_u64);
|
||
|
||
/* Initialization: start new cycle if in idle or cycle complete state */
|
||
if (testBenchState_en == TEST_BENCH_IDLE || testBenchState_en == TEST_BENCH_CYCLE_COMPLETE)
|
||
{
|
||
/* Prepare new cycle: reset all node statuses and choose new target positions */
|
||
for (uint8 i = 0u; i < ENDURANCE_TEST_BENCH_LSS_NODE_COUNT; i++)
|
||
{
|
||
testBenchData_en.targetPositions_gau8[i] = (uint8)(rand() % 256);
|
||
testBenchData_en.readPosition_gau8[i] = 0u;
|
||
testBenchData_en.status_en[i] = TEST_BENCH_DATA_VERIF_DEFAULT;
|
||
}
|
||
currentNode_gu8 = 0u;
|
||
storedTargetPos = 0u;
|
||
retries_u8 = 0u;
|
||
readMismatchRetries_u8 = 0u;
|
||
cycleStartTime_u64 = currentTime_u64;
|
||
testBenchState_en = TEST_BENCH_BATCH_WRITE;
|
||
}
|
||
|
||
switch (testBenchState_en)
|
||
{
|
||
/* -------------------- Batch Write -------------------- */
|
||
case TEST_BENCH_BATCH_WRITE:
|
||
{
|
||
if (currentNode_gu8 < ENDURANCE_TEST_BENCH_LSS_NODE_COUNT)
|
||
{
|
||
if (storedTargetPos == 0)
|
||
{
|
||
/* Use the pre-assigned target value for this node */
|
||
uint8 value_u8 = testBenchData_en.targetPositions_gau8[currentNode_gu8];
|
||
|
||
RET_T retVal_en = coSdoWrite(
|
||
(currentNode_gu8 + 1),
|
||
ENDURANCE_TEST_BENCH_POSITION_SETPOINT_INDEX,
|
||
ENDURANCE_TEST_BENCH_POSITION_SETPOINT_SUB_INDEX,
|
||
&value_u8,
|
||
sizeof(uint8),
|
||
CO_FALSE,
|
||
ENDURANCE_TEST_BENCH_TIMEOUT
|
||
);
|
||
|
||
if (retVal_en == RET_OK)
|
||
{
|
||
storedTargetPos = 1; /* Mark that target is written for this node */
|
||
HalSystemGetRunTimeMs(&writeTime_u64);
|
||
retries_u8 = 0u;
|
||
testBenchState_en = TEST_BENCH_BATCH_WRITE_WAIT;
|
||
}
|
||
else
|
||
{
|
||
retries_u8++;
|
||
if (retries_u8 >= ENDURANCE_TEST_BENCH_MAX_RETRY_CNT)
|
||
{
|
||
testBenchData_en.status_en[currentNode_gu8] = TEST_BENCH_DATA_VERIF_SKIPPED;
|
||
/* Mark node as skipped and move on */
|
||
currentNode_gu8++;
|
||
retries_u8 = 0u;
|
||
storedTargetPos = 0u;
|
||
testBenchState_en = TEST_BENCH_BATCH_WRITE;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
/* Finished writing to all nodes */
|
||
currentNode_gu8 = 0u; /* Reset index for read phase */
|
||
testBenchState_en = TEST_BENCH_BATCH_READ;
|
||
}
|
||
break;
|
||
}
|
||
|
||
case TEST_BENCH_BATCH_WRITE_WAIT:
|
||
{
|
||
/* Wait 100ms between writes */
|
||
if ((currentTime_u64 - writeTime_u64) >= 500)
|
||
{
|
||
/* Move to next node write */
|
||
currentNode_gu8++;
|
||
storedTargetPos = 0u; /* Reset for next node */
|
||
testBenchState_en = TEST_BENCH_BATCH_WRITE;
|
||
}
|
||
break;
|
||
}
|
||
|
||
/* -------------------- Batch Read -------------------- */
|
||
case TEST_BENCH_BATCH_READ:
|
||
{
|
||
if (currentNode_gu8 < ENDURANCE_TEST_BENCH_LSS_NODE_COUNT)
|
||
{
|
||
RET_T retVal_en = coSdoRead(
|
||
(currentNode_gu8 + 1),
|
||
ENDURANCE_TEST_BENCH_POSITION_FEEDBACK_INDEX,
|
||
ENDURANCE_TEST_BENCH_POSITION_FEEDBACK_SUB_INDEX,
|
||
(uint8*)&readPosition_gu32,
|
||
sizeof(uint32),
|
||
CO_FALSE,
|
||
ENDURANCE_TEST_BENCH_TIMEOUT
|
||
);
|
||
|
||
if (retVal_en == RET_OK)
|
||
{
|
||
retries_u8 = 0u;
|
||
/* The read indication callback is assumed to update
|
||
* testBenchData_en.readPosition_gau8[currentNode_gu8] and
|
||
* then we simply continue to next node after a small delay.
|
||
*/
|
||
HalSystemGetRunTimeMs(&readExecutedTime_u64);
|
||
testBenchData_en.readPosition_gau8[currentNode_gu8] = (uint8)readPosition_gu32;
|
||
testBenchState_en = TEST_BENCH_BATCH_READ_WAIT;
|
||
}
|
||
else if (retVal_en == RET_SERVICE_BUSY && retries_u8 < ENDURANCE_TEST_BENCH_MAX_RETRY_CNT)
|
||
{
|
||
retries_u8++;
|
||
}
|
||
else
|
||
{
|
||
/* If read fails, mark as skipped and move on */
|
||
testBenchData_en.status_en[currentNode_gu8] = TEST_BENCH_DATA_VERIF_SKIPPED;
|
||
currentNode_gu8++;
|
||
retries_u8 = 0u;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
/* Finished reading all nodes */
|
||
currentNode_gu8 = 0u; /* Reset for verification phase */
|
||
testBenchState_en = TEST_BENCH_BATCH_VERIFY;
|
||
}
|
||
break;
|
||
}
|
||
|
||
case TEST_BENCH_BATCH_READ_WAIT:
|
||
{
|
||
/* Wait 100ms between node reads */
|
||
if ((currentTime_u64 - readExecutedTime_u64) >= 10)
|
||
{
|
||
currentNode_gu8++;
|
||
testBenchState_en = TEST_BENCH_BATCH_READ;
|
||
}
|
||
break;
|
||
}
|
||
|
||
/* -------------------- Batch Verify -------------------- */
|
||
case TEST_BENCH_BATCH_VERIFY:
|
||
{
|
||
if (currentNode_gu8 < ENDURANCE_TEST_BENCH_LSS_NODE_COUNT)
|
||
{
|
||
/* Process only if the node was not already skipped */
|
||
if (testBenchData_en.status_en[currentNode_gu8] != TEST_BENCH_DATA_VERIF_SKIPPED)
|
||
{
|
||
uint8 diff = abs(testBenchData_en.targetPositions_gau8[currentNode_gu8] -
|
||
testBenchData_en.readPosition_gau8[currentNode_gu8]);
|
||
|
||
if (diff <= 1)
|
||
{
|
||
testBenchData_en.status_en[currentNode_gu8] = TEST_BENCH_DATA_VERIF_SUCCESS;
|
||
}
|
||
else
|
||
{
|
||
testBenchData_en.status_en[currentNode_gu8] = TEST_BENCH_DATA_VERIF_FAILURE;
|
||
}
|
||
}
|
||
/* Move to the next node in any case */
|
||
currentNode_gu8++;
|
||
testBenchState_en = TEST_BENCH_BATCH_VERIFY;
|
||
}
|
||
else
|
||
{
|
||
/* All nodes verified; complete cycle */
|
||
testBenchState_en = TEST_BENCH_CYCLE_COMPLETE;
|
||
}
|
||
break;
|
||
}
|
||
|
||
/* -------------------- Cycle Complete -------------------- */
|
||
case TEST_BENCH_CYCLE_COMPLETE:
|
||
{
|
||
/* Optionally, you can log or process the batch results here */
|
||
/* Reset all node data for the next cycle */
|
||
for (uint8 i = 0u; i < ENDURANCE_TEST_BENCH_LSS_NODE_COUNT; i++)
|
||
{
|
||
testBenchData_en.targetPositions_gau8[i] = 0u;
|
||
testBenchData_en.readPosition_gau8[i] = 0u;
|
||
testBenchData_en.status_en[i] = TEST_BENCH_DATA_VERIF_DEFAULT;
|
||
}
|
||
currentNode_gu8 = 0u;
|
||
storedTargetPos = 0u;
|
||
retries_u8 = 0u;
|
||
readMismatchRetries_u8 = 0u;
|
||
/* Start next cycle */
|
||
testBenchState_en = TEST_BENCH_IDLE;
|
||
break;
|
||
}
|
||
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
|
||
/******************************************************************************
|
||
* Callback Functions
|
||
******************************************************************************/
|
||
void TestReadInd(uint8 sdoNr_u8, uint16 index_u16, uint8 subIndex_u8, uint32 errorVal_u32)
|
||
{
|
||
HalSystemGetRunTimeMs(&writeTime_u64);
|
||
}
|
||
|
||
void TestWriteInd(uint8 sdoNr_u8, uint16 index_u16, uint8 subIndex_u8, uint32 size, uint32 errorVal_u32)
|
||
{
|
||
HalSystemGetRunTimeMs(&readExecutedTime_u64);
|
||
//testBenchData_en.readPosition_gau8[currentNode_gu8] = (uint8)readPosition_gu32;
|
||
}
|