/** * @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 #include #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; }