Quellcode durchsuchen

PLSR S0 S1 S2 D 现在可以解析、校验、生成不可变任务快照,并异步提交给 PLSR 核心

deepseek
ywh vor 1 Monat
Ursprung
Commit
9296f55657
8 geänderte Dateien mit 2074 neuen und 7 gelöschten Zeilen
  1. +6
    -0
      EWARM/Modbus.ewp
  2. +4
    -0
      PLSR/Inc/plsr_core.h
  3. +198
    -0
      PLSR/Inc/plsr_job.h
  4. +21
    -1
      PLSR/Inc/plsr_types.h
  5. +161
    -6
      PLSR/Src/plsr_core.c
  6. +1262
    -0
      PLSR/Src/plsr_job.c
  7. +12
    -0
      PLSR/Test/run_host_tests.ps1
  8. +410
    -0
      PLSR/Test/test_plsr_job.c

+ 6
- 0
EWARM/Modbus.ewp Datei anzeigen

@@ -1281,6 +1281,9 @@
<file>
<name>$PROJ_DIR$\..\PLSR\Inc\plsr_core.h</name>
</file>
<file>
<name>$PROJ_DIR$\..\PLSR\Inc\plsr_job.h</name>
</file>
<file>
<name>$PROJ_DIR$\..\PLSR\Src\plsr_persistence.c</name>
</file>
@@ -1290,6 +1293,9 @@
<file>
<name>$PROJ_DIR$\..\PLSR\Src\plsr_resource.c</name>
</file>
<file>
<name>$PROJ_DIR$\..\PLSR\Src\plsr_job.c</name>
</file>
<file>
<name>$PROJ_DIR$\..\PLSR\Src\plsr_core.c</name>
</file>


+ 4
- 0
PLSR/Inc/plsr_core.h Datei anzeigen

@@ -1,6 +1,7 @@
#ifndef PLSR_CORE_H
#define PLSR_CORE_H

#include "plsr_job.h"
#include "plsr_types.h"
#include <stdint.h>

@@ -13,9 +14,12 @@ void PlsrTask(void *argument);
void PlsrProcess(void);

PLSR_RESULT PlsrPostStart(const PLSR_START_REQUEST *request);
PLSR_RESULT PlsrPostCall(const PLSR_CALL *call);
PLSR_RESULT PlsrPostCommand(const PLSR_COMMAND *command);
PLSR_RESULT PlsrPostEvent(uint8_t axis, uint32_t eventMask);
PLSR_RESULT PlsrGetStatus(uint8_t axis, PLSR_STATUS *status);
PLSR_RESULT PlsrGetLastParseDetail(uint8_t axis,
PLSR_PARSE_DETAIL *detail);

PLSR_RESULT PlsrStateTransition(uint8_t axis,
PLSR_STATE target,


+ 198
- 0
PLSR/Inc/plsr_job.h Datei anzeigen

@@ -0,0 +1,198 @@
#ifndef PLSR_JOB_H
#define PLSR_JOB_H

#include "plsr_types.h"
#include <stdint.h>

#ifdef __cplusplus
extern "C" {
#endif

#define PLSR_MAX_SEGMENTS (100U)
#define PLSR_OUTPUT_MODE_FROM_SFD (0xFFU)
#define PLSR_FREQUENCY_MIN_HZ (1UL)
#define PLSR_FREQUENCY_MAX_HZ (100000UL)

typedef enum
{
PLSR_DEVICE_D = 0,
PLSR_DEVICE_HD,
PLSR_DEVICE_FD,
PLSR_DEVICE_X,
PLSR_DEVICE_M,
PLSR_DEVICE_HM
} PLSR_DEVICE_TYPE;

typedef uint8_t (*PLSR_VALIDATE_WORDS_FN)(void *context,
PLSR_DEVICE_TYPE device,
uint32_t firstAddress,
uint32_t wordCount);
typedef uint8_t (*PLSR_READ_WORD_FN)(void *context,
PLSR_DEVICE_TYPE device,
uint32_t address,
uint16_t *value);
typedef uint8_t (*PLSR_READ_BIT_FN)(void *context,
PLSR_DEVICE_TYPE device,
uint32_t address,
uint8_t *value);

typedef struct
{
void *context;
PLSR_VALIDATE_WORDS_FN validateWords;
PLSR_READ_WORD_FN readWord;
PLSR_READ_BIT_FN readBit;
} PLSR_DATA_SOURCE;

typedef struct
{
PLSR_DEVICE_TYPE device;
uint32_t address;
} PLSR_DATA_REF;

typedef enum
{
PLSR_OPERAND_CONSTANT = 0,
PLSR_OPERAND_DATA
} PLSR_OPERAND_TYPE;

typedef struct
{
PLSR_OPERAND_TYPE type;
PLSR_DATA_REF data;
int32_t constant;
} PLSR_VALUE_OPERAND;

typedef struct
{
uint32_t sequence;
/* The source context must remain valid while the queued/running job exists. */
PLSR_DATA_SOURCE source;
PLSR_DATA_REF s0;
PLSR_DATA_REF s1;
PLSR_VALUE_OPERAND s2;
uint8_t dAxis;
uint8_t outputModeOverride;
} PLSR_CALL;

typedef enum
{
PLSR_WAIT_PULSE_COMPLETE = 0,
PLSR_WAIT_TIME,
PLSR_WAIT_SIGNAL,
PLSR_WAIT_ACT_TIME,
PLSR_WAIT_EXT,
PLSR_WAIT_EXT_OR_COMPLETE
} PLSR_WAIT_CONDITION;

typedef enum
{
PLSR_VALUE_CONSTANT = 0,
PLSR_VALUE_D,
PLSR_VALUE_HD,
PLSR_VALUE_FD,
PLSR_VALUE_X,
PLSR_VALUE_M,
PLSR_VALUE_HM
} PLSR_VALUE_SOURCE;

#define PLSR_SEGMENT_FLAG_ZERO_PULSE (1U << 0U)
#define PLSR_SEGMENT_FLAG_DEFAULT_SPEED (1U << 1U)
#define PLSR_SEGMENT_FLAG_SPEED_CLAMPED (1U << 2U)
#define PLSR_SEGMENT_FLAG_SELF_LOOP (1U << 3U)

typedef struct
{
uint32_t targetFrequency;
int32_t pulseOrTarget;
int32_t waitValueOrAddress;
int32_t jumpValueOrAddress;
uint8_t waitCondition;
uint8_t waitSource;
uint8_t jumpSource;
uint8_t flags;
} PLSR_SEGMENT_SNAPSHOT;

typedef struct
{
uint32_t defaultSpeed;
uint32_t maximumSpeed;
uint32_t startSpeed;
uint32_t stopSpeed;
uint32_t zrnHighSpeed;
uint32_t zrnCrawlSpeed;
uint16_t accelerationMs;
uint16_t decelerationMs;
uint16_t gapAccelerationMs;
uint16_t directionDelayUs;
uint8_t curveMode;
uint8_t follow;
uint8_t feedforwardPercent;
uint8_t refreshCode;
} PLSR_S2_SNAPSHOT;

typedef struct
{
PLSR_DATA_SOURCE source;
PLSR_DATA_REF s0;
PLSR_DATA_REF s1;
PLSR_S2_SNAPSHOT s2;
PLSR_SEGMENT_SNAPSHOT segments[PLSR_MAX_SEGMENTS];
uint32_t timerClockHz;
uint32_t pairedTimerClockHz;
uint16_t segmentCount;
uint16_t startSegment;
uint8_t dAxis;
uint8_t s2Set;
uint8_t positioningMode;
uint8_t outputMode;
uint8_t directionPoint;
uint8_t directionActiveHigh;
uint8_t initialDirectionPositive;
uint8_t speedClamped;
uint8_t hasSelfLoop;
} PLSR_JOB_SNAPSHOT;

typedef enum
{
PLSR_PARSE_BLOCK_NONE = 0,
PLSR_PARSE_BLOCK_S0,
PLSR_PARSE_BLOCK_S1,
PLSR_PARSE_BLOCK_S2,
PLSR_PARSE_BLOCK_OUTPUT,
PLSR_PARSE_BLOCK_POSITION
} PLSR_PARSE_BLOCK;

typedef struct
{
PLSR_RESULT result;
PLSR_PARSE_BLOCK block;
uint32_t address;
int32_t value;
uint16_t segment;
} PLSR_PARSE_DETAIL;

typedef struct
{
int64_t logicalPosition;
uint8_t positionValid;
} PLSR_PARSE_CONTEXT;

PLSR_RESULT PlsrBuildJobSnapshot(const PLSR_CALL *call,
const PLSR_PARSE_CONTEXT *context,
PLSR_JOB_SNAPSHOT *snapshot,
PLSR_PARSE_DETAIL *detail);
PLSR_RESULT PlsrResolveLiveFrequency(const PLSR_JOB_SNAPSHOT *snapshot,
uint16_t segment,
uint32_t *frequency,
uint8_t *clamped);
PLSR_RESULT PlsrCalculateTimerDivider(uint32_t timerClockHz,
uint32_t frequencyHz,
uint16_t *psc,
uint16_t *arr);

#ifdef __cplusplus
}
#endif

#endif /* PLSR_JOB_H */

+ 21
- 1
PLSR/Inc/plsr_types.h Datei anzeigen

@@ -60,7 +60,21 @@ typedef enum
PLSR_RESULT_BUSY,
PLSR_RESULT_PERSISTENCE_ERROR,
PLSR_RESULT_NOT_SUPPORTED,
PLSR_RESULT_INTERNAL_ERROR
PLSR_RESULT_INTERNAL_ERROR,
PLSR_RESULT_DATA_ACCESS,
PLSR_RESULT_ADDRESS_OVERFLOW,
PLSR_RESULT_BLOCK_OVERLAP,
PLSR_RESULT_SEGMENT_OVERFLOW,
PLSR_RESULT_RESERVED_NOT_ZERO,
PLSR_RESULT_INVALID_POSITION_MODE,
PLSR_RESULT_INVALID_S2,
PLSR_RESULT_INVALID_FREQUENCY,
PLSR_RESULT_INVALID_WAIT,
PLSR_RESULT_INVALID_JUMP,
PLSR_RESULT_PATH_CYCLE,
PLSR_RESULT_POSITION_INVALID,
PLSR_RESULT_POSITION_OVERFLOW,
PLSR_RESULT_DIVIDER_UNREPRESENTABLE
} PLSR_RESULT;

typedef enum
@@ -159,6 +173,12 @@ typedef struct
uint8_t directionPositive;
uint8_t highResourceMask;
uint8_t directionPoint;
uint8_t positionValid;
uint8_t jobValid;
uint8_t s2Set;
uint8_t speedClamped;
uint16_t segmentCount;
uint16_t startSegment;
} PLSR_STATUS;

#ifdef __cplusplus


+ 161
- 6
PLSR/Src/plsr_core.c Datei anzeigen

@@ -17,6 +17,8 @@ typedef struct
PLSR_STOP_REASON stopReason;
PLSR_STATE pendingTerminal;
PLSR_RESOURCE_LEASE lease;
PLSR_JOB_SNAPSHOT job;
PLSR_PARSE_DETAIL parseDetail;
volatile uint32_t pendingEvents;
uint32_t lastCommandSequence;
PLSR_RESULT lastCommandResult;
@@ -27,14 +29,18 @@ typedef struct
uint8_t done;
uint8_t directionPositive;
uint8_t immediateStopPending;
uint8_t positionValid;
uint8_t jobValid;
} PLSR_AXIS;

typedef struct
{
PLSR_COMMAND command;
PLSR_START_REQUEST start;
PLSR_CALL call;
uint32_t ticket;
uint8_t hasStart;
uint8_t hasCall;
uint8_t occupied;
} PLSR_COMMAND_SLOT;

@@ -42,6 +48,7 @@ static PLSR_AXIS PlsrAxes[PLSR_AXIS_COUNT];
static PLSR_COMMAND_SLOT PlsrCommandQueue[PLSR_COMMAND_QUEUE_DEPTH];
static uint32_t PlsrNextTicket;
static uint8_t PlsrInitialized;
static PLSR_JOB_SNAPSHOT PlsrJobScratch;

static uint32_t PlsrCoreEnterCritical(void)
{
@@ -240,7 +247,8 @@ static uint8_t PlsrCommandPriority(PLSR_COMMAND_OPCODE opcode)
}

static PLSR_RESULT PlsrQueueCommand(const PLSR_COMMAND *command,
const PLSR_START_REQUEST *start)
const PLSR_START_REQUEST *start,
const PLSR_CALL *call)
{
uint32_t interruptState;
uint8_t freeSlot = PLSR_COMMAND_QUEUE_DEPTH;
@@ -292,6 +300,18 @@ static PLSR_RESULT PlsrQueueCommand(const PLSR_COMMAND *command,
sizeof(PlsrCommandQueue[freeSlot].start));
PlsrCommandQueue[freeSlot].hasStart = 0U;
}
if (call != NULL)
{
PlsrCommandQueue[freeSlot].call = *call;
PlsrCommandQueue[freeSlot].hasCall = 1U;
}
else
{
(void)memset(&PlsrCommandQueue[freeSlot].call,
0,
sizeof(PlsrCommandQueue[freeSlot].call));
PlsrCommandQueue[freeSlot].hasCall = 0U;
}
PlsrCommandQueue[freeSlot].ticket = PlsrNextTicket++;
PlsrCommandQueue[freeSlot].occupied = 1U;
PlsrCoreExitCritical(interruptState);
@@ -361,7 +381,30 @@ PLSR_RESULT PlsrPostStart(const PLSR_START_REQUEST *request)
command.axis = request->axis;
command.opcode = PLSR_CMD_START;
command.argument = 0;
return PlsrQueueCommand(&command, request);
return PlsrQueueCommand(&command, request, NULL);
}

PLSR_RESULT PlsrPostCall(const PLSR_CALL *call)
{
PLSR_COMMAND command;

if (call == NULL)
{
return PLSR_RESULT_INVALID_ARGUMENT;
}
if (call->dAxis >= PLSR_AXIS_COUNT)
{
return PLSR_RESULT_INVALID_AXIS;
}
if (PlsrInitialized == 0U)
{
return PLSR_RESULT_INVALID_STATE;
}
command.sequence = call->sequence;
command.axis = call->dAxis;
command.opcode = PLSR_CMD_START;
command.argument = 0;
return PlsrQueueCommand(&command, NULL, call);
}

PLSR_RESULT PlsrPostCommand(const PLSR_COMMAND *command)
@@ -383,7 +426,7 @@ PLSR_RESULT PlsrPostCommand(const PLSR_COMMAND *command)
{
return PLSR_RESULT_INVALID_STATE;
}
return PlsrQueueCommand(command, NULL);
return PlsrQueueCommand(command, NULL, NULL);
}

PLSR_RESULT PlsrPostEvent(uint8_t axis, uint32_t eventMask)
@@ -464,6 +507,7 @@ static PLSR_RESULT PlsrStartAxis(PLSR_AXIS *axisObject,
axisObject->pendingTerminal = PLSR_STATE_UNINITIALIZED;
axisObject->immediateStopPending = 0U;
axisObject->done = 0U;
axisObject->jobValid = 0U;
result = PlsrStateTransition(start->axis,
PLSR_STATE_ACCEL,
PLSR_TRANSITION_START);
@@ -474,6 +518,67 @@ static PLSR_RESULT PlsrStartAxis(PLSR_AXIS *axisObject,
return result;
}

static PLSR_RESULT PlsrStartCall(PLSR_AXIS *axisObject,
const PLSR_CALL *call)
{
PLSR_RESOURCE_REQUEST resourceRequest;
PLSR_PARSE_CONTEXT parseContext;
PLSR_RESULT result;

if ((axisObject->state != PLSR_STATE_IDLE)
&& (axisObject->state != PLSR_STATE_COMPLETED)
&& (axisObject->state != PLSR_STATE_STOPPED))
{
return PLSR_RESULT_INVALID_STATE;
}

parseContext.logicalPosition = axisObject->logicalPosition;
parseContext.positionValid = axisObject->positionValid;
result = PlsrBuildJobSnapshot(call,
&parseContext,
&PlsrJobScratch,
&axisObject->parseDetail);
if (result != PLSR_RESULT_OK)
{
return result;
}

resourceRequest.ownerAxis = call->dAxis;
resourceRequest.outputMode =
(PLSR_OUTPUT_MODE)PlsrJobScratch.outputMode;
resourceRequest.dAxis = call->dAxis;
resourceRequest.directionPoint = PlsrJobScratch.directionPoint;
result = PlsrResourceReserve(&resourceRequest, &axisObject->lease);
if (result != PLSR_RESULT_OK)
{
axisObject->error = (result == PLSR_RESULT_RESOURCE_CONFLICT)
? PLSR_ERROR_RESOURCE_CONFLICT
: PLSR_ERROR_INVALID_RESOURCE;
axisObject->parseDetail.result = result;
axisObject->parseDetail.block = PLSR_PARSE_BLOCK_OUTPUT;
return result;
}

axisObject->job = PlsrJobScratch;
axisObject->jobValid = 1U;
axisObject->outputMode = (PLSR_OUTPUT_MODE)axisObject->job.outputMode;
axisObject->directionPositive = axisObject->job.initialDirectionPositive;
axisObject->error = PLSR_ERROR_NONE;
axisObject->stopReason = PLSR_STOP_REASON_NONE;
axisObject->pendingTerminal = PLSR_STATE_UNINITIALIZED;
axisObject->immediateStopPending = 0U;
axisObject->done = 0U;
result = PlsrStateTransition(call->dAxis,
PLSR_STATE_ACCEL,
PLSR_TRANSITION_START);
if (result != PLSR_RESULT_OK)
{
axisObject->jobValid = 0U;
PlsrResourceRelease(&axisObject->lease);
}
return result;
}

static PLSR_RESULT PlsrStopImmediate(uint8_t axis)
{
PLSR_AXIS *axisObject = &PlsrAxes[axis];
@@ -590,9 +695,16 @@ static PLSR_RESULT PlsrExecuteCommand(const PLSR_COMMAND_SLOT *slot)
switch (slot->command.opcode)
{
case PLSR_CMD_START:
result = (slot->hasStart != 0U)
? PlsrStartAxis(axisObject, &slot->start)
: PLSR_RESULT_INVALID_ARGUMENT;
if (slot->hasCall != 0U)
{
result = PlsrStartCall(axisObject, &slot->call);
}
else
{
result = (slot->hasStart != 0U)
? PlsrStartAxis(axisObject, &slot->start)
: PLSR_RESULT_INVALID_ARGUMENT;
}
break;

case PLSR_CMD_STOP_DECEL:
@@ -630,6 +742,7 @@ static PLSR_RESULT PlsrExecuteCommand(const PLSR_COMMAND_SLOT *slot)
else
{
axisObject->logicalPosition = slot->command.argument;
axisObject->positionValid = 1U;
(void)PlcDevicePublishHsdPair(
(uint16_t)(slot->command.axis
* PLSR_HSD_RUNTIME_AXIS_COUNT),
@@ -646,6 +759,7 @@ static PLSR_RESULT PlsrExecuteCommand(const PLSR_COMMAND_SLOT *slot)
else
{
axisObject->logicalPosition = 0;
axisObject->positionValid = 1U;
(void)PlcDevicePublishHsdPair(
(uint16_t)(slot->command.axis
* PLSR_HSD_RUNTIME_AXIS_COUNT),
@@ -888,6 +1002,7 @@ static void PlsrProcessNormalEvents(uint8_t axis, uint32_t events)

PLSR_RESULT PlsrInit(void)
{
int64_t restoredPosition;
uint8_t axis;

(void)memset(PlsrAxes, 0, sizeof(PlsrAxes));
@@ -901,6 +1016,15 @@ PLSR_RESULT PlsrInit(void)
PlsrAxes[axis].state = PLSR_STATE_UNINITIALIZED;
PlsrAxes[axis].pendingTerminal = PLSR_STATE_UNINITIALIZED;
PlsrAxes[axis].lease.directionPoint = PLSR_DIRECTION_POINT_NONE;
if ((PlcDeviceGetLastHsdLoadResult() == PLSR_PERSISTENCE_OK)
&& (PlcDeviceReadHsdPair(
(uint16_t)(axis * PLSR_HSD_RUNTIME_AXIS_COUNT),
&restoredPosition)
== PLC_DEVICE_OK))
{
PlsrAxes[axis].logicalPosition = restoredPosition;
PlsrAxes[axis].positionValid = 1U;
}
if (PlsrStateTransition(axis,
PLSR_STATE_IDLE,
PLSR_TRANSITION_INITIALIZED)
@@ -1001,6 +1125,37 @@ PLSR_RESULT PlsrGetStatus(uint8_t axis, PLSR_STATUS *status)
status->directionPoint = (axisObject->lease.valid != 0U)
? axisObject->lease.directionPoint
: PLSR_DIRECTION_POINT_NONE;
status->positionValid = axisObject->positionValid;
status->jobValid = axisObject->jobValid;
status->s2Set = (axisObject->jobValid != 0U) ? axisObject->job.s2Set : 0U;
status->speedClamped = (axisObject->jobValid != 0U)
? axisObject->job.speedClamped
: 0U;
status->segmentCount = (axisObject->jobValid != 0U)
? axisObject->job.segmentCount
: 0U;
status->startSegment = (axisObject->jobValid != 0U)
? axisObject->job.startSegment
: 0U;
PlsrCoreExitCritical(interruptState);
return PLSR_RESULT_OK;
}

PLSR_RESULT PlsrGetLastParseDetail(uint8_t axis,
PLSR_PARSE_DETAIL *detail)
{
uint32_t interruptState;

if (axis >= PLSR_AXIS_COUNT)
{
return PLSR_RESULT_INVALID_AXIS;
}
if (detail == NULL)
{
return PLSR_RESULT_INVALID_ARGUMENT;
}
interruptState = PlsrCoreEnterCritical();
*detail = PlsrAxes[axis].parseDetail;
PlsrCoreExitCritical(interruptState);
return PLSR_RESULT_OK;
}

+ 1262
- 0
PLSR/Src/plsr_job.c
Datei-Diff unterdrückt, da er zu groß ist
Datei anzeigen


+ 12
- 0
PLSR/Test/run_host_tests.ps1 Datei anzeigen

@@ -28,9 +28,21 @@ $tests = @(
"$workspacePath\PLSR\Src\plc_device.c"
"$workspacePath\PLSR\Src\plsr_persistence.c"
"$workspacePath\PLSR\Src\plsr_resource.c"
"$workspacePath\PLSR\Src\plsr_job.c"
"$workspacePath\PLSR\Src\plsr_core.c"
"$workspacePath\PLSR\Test\test_plsr_core.c"
)
},
@{
Name = 'test_plsr_job'
Sources = @(
"$workspacePath\PLSR\Src\plc_device.c"
"$workspacePath\PLSR\Src\plsr_persistence.c"
"$workspacePath\PLSR\Src\plsr_resource.c"
"$workspacePath\PLSR\Src\plsr_job.c"
"$workspacePath\PLSR\Src\plsr_core.c"
"$workspacePath\PLSR\Test\test_plsr_job.c"
)
}
)



+ 410
- 0
PLSR/Test/test_plsr_job.c Datei anzeigen

@@ -0,0 +1,410 @@
#include "plc_device.h"
#include "plsr_core.h"
#include "plsr_job.h"
#include "plsr_persistence.h"
#include <stdio.h>
#include <string.h>

#define TEST_WORD_CAPACITY (3000U)
#define TEST_BIT_CAPACITY (128U)

typedef struct
{
uint16_t words[3][TEST_WORD_CAPACITY];
uint8_t bits[3][TEST_BIT_CAPACITY];
} TEST_MEMORY;

static int TestFailures;
static int TestChecks;

#define CHECK(condition) \
do \
{ \
TestChecks++; \
if (!(condition)) \
{ \
TestFailures++; \
(void)printf("FAIL line %d: %s\n", __LINE__, #condition); \
} \
} while (0)

static uint8_t TestValidateWords(void *context,
PLSR_DEVICE_TYPE device,
uint32_t firstAddress,
uint32_t wordCount)
{
(void)context;
if ((device > PLSR_DEVICE_FD) || (wordCount == 0UL))
{
return 0U;
}
return (((uint64_t)firstAddress + wordCount) <= TEST_WORD_CAPACITY)
? 1U
: 0U;
}

static uint8_t TestReadWord(void *context,
PLSR_DEVICE_TYPE device,
uint32_t address,
uint16_t *value)
{
TEST_MEMORY *memory = (TEST_MEMORY *)context;

if ((memory == NULL) || (value == NULL) || (device > PLSR_DEVICE_FD)
|| (address >= TEST_WORD_CAPACITY))
{
return 0U;
}
*value = memory->words[device][address];
return 1U;
}

static uint8_t TestReadBit(void *context,
PLSR_DEVICE_TYPE device,
uint32_t address,
uint8_t *value)
{
TEST_MEMORY *memory = (TEST_MEMORY *)context;
uint8_t index;

if ((memory == NULL) || (value == NULL) || (device < PLSR_DEVICE_X)
|| (device > PLSR_DEVICE_HM) || (address >= TEST_BIT_CAPACITY))
{
return 0U;
}
index = (uint8_t)(device - PLSR_DEVICE_X);
*value = memory->bits[index][address];
return 1U;
}

static void TestWriteDword(TEST_MEMORY *memory,
PLSR_DEVICE_TYPE device,
uint32_t address,
int32_t value)
{
uint32_t raw = (uint32_t)value;

memory->words[device][address] = (uint16_t)(raw & 0xFFFFUL);
memory->words[device][address + 1UL] = (uint16_t)(raw >> 16U);
}

static void TestWriteSfdDword(uint16_t address, uint32_t value)
{
CHECK(PlcDeviceWriteSfd(address, (int32_t)(value & 0xFFFFUL))
== PLC_DEVICE_OK);
CHECK(PlcDeviceWriteSfd((uint16_t)(address + 1U),
(int32_t)(value >> 16U))
== PLC_DEVICE_OK);
}

static void TestConfigureAxis0K1(void)
{
CHECK(PlcDeviceWriteSfd(900U, 0) == PLC_DEVICE_OK);
CHECK(PlcDeviceWriteSfd(906U, 4) == PLC_DEVICE_OK);
CHECK(PlcDeviceWriteSfd(907U, 10) == PLC_DEVICE_OK);
TestWriteSfdDword(950U, 1000UL);
CHECK(PlcDeviceWriteSfd(952U, 100) == PLC_DEVICE_OK);
CHECK(PlcDeviceWriteSfd(953U, 120) == PLC_DEVICE_OK);
CHECK(PlcDeviceWriteSfd(954U, 10) == PLC_DEVICE_OK);
CHECK(PlcDeviceWriteSfd(955U, 0) == PLC_DEVICE_OK);
TestWriteSfdDword(956U, 100000UL);
TestWriteSfdDword(958U, 120000UL);
TestWriteSfdDword(960U, 500UL);
CHECK(PlcDeviceWriteSfd(962U, 50) == PLC_DEVICE_OK);
CHECK(PlcDeviceWriteSfd(963U, 20) == PLC_DEVICE_OK);
CHECK(PlcDeviceWriteSfd(964U, 0) == PLC_DEVICE_OK);
TestWriteSfdDword(966U, 2000UL);
TestWriteSfdDword(968U, 200UL);
}

static void TestBuildValidBlocks(TEST_MEMORY *memory)
{
(void)memset(memory, 0, sizeof(*memory));
TestWriteDword(memory, PLSR_DEVICE_D, 100U, 2);

TestWriteDword(memory, PLSR_DEVICE_D, 110U, 150000);
TestWriteDword(memory, PLSR_DEVICE_D, 112U, 100);
memory->words[PLSR_DEVICE_D][114U] = 0U;
TestWriteDword(memory, PLSR_DEVICE_D, 115U, 0);
memory->words[PLSR_DEVICE_D][117U] = 0U;
TestWriteDword(memory, PLSR_DEVICE_D, 118U, 0);

TestWriteDword(memory, PLSR_DEVICE_D, 120U, 0);
TestWriteDword(memory, PLSR_DEVICE_D, 122U, -50);
memory->words[PLSR_DEVICE_D][124U] = 0x0100U;
TestWriteDword(memory, PLSR_DEVICE_D, 125U, 0);
memory->words[PLSR_DEVICE_D][127U] = 0U;
TestWriteDword(memory, PLSR_DEVICE_D, 128U, 2);

TestWriteDword(memory, PLSR_DEVICE_D, 200U, 0);
TestWriteDword(memory, PLSR_DEVICE_D, 202U, 0);
TestWriteDword(memory, PLSR_DEVICE_HD, 10U, 1);
}

static PLSR_CALL TestMakeCall(TEST_MEMORY *memory)
{
PLSR_CALL call;

(void)memset(&call, 0, sizeof(call));
call.sequence = 77UL;
call.source.context = memory;
call.source.validateWords = TestValidateWords;
call.source.readWord = TestReadWord;
call.source.readBit = TestReadBit;
call.s0.device = PLSR_DEVICE_D;
call.s0.address = 100UL;
call.s1.device = PLSR_DEVICE_D;
call.s1.address = 200UL;
call.s2.type = PLSR_OPERAND_CONSTANT;
call.s2.constant = 1;
call.dAxis = 0U;
call.outputModeOverride = PLSR_OUTPUT_MODE_FROM_SFD;
return call;
}

static void TestValidSnapshotAndLiveFrequency(void)
{
TEST_MEMORY memory;
PLSR_CALL call;
PLSR_PARSE_CONTEXT context;
PLSR_JOB_SNAPSHOT snapshot;
PLSR_PARSE_DETAIL detail;
uint32_t frequency;
uint8_t clamped;

TestBuildValidBlocks(&memory);
call = TestMakeCall(&memory);
context.logicalPosition = 0;
context.positionValid = 0U;
CHECK(PlsrBuildJobSnapshot(&call, &context, &snapshot, &detail)
== PLSR_RESULT_OK);
CHECK(detail.result == PLSR_RESULT_OK);
CHECK(snapshot.segmentCount == 2U);
CHECK(snapshot.startSegment == 1U);
CHECK(snapshot.s2Set == 1U);
CHECK(snapshot.outputMode == PLSR_OUTPUT_PULSE_DIR);
CHECK(snapshot.directionPoint == 4U);
CHECK(snapshot.s2.defaultSpeed == 1000UL);
CHECK(snapshot.s2.maximumSpeed == 100000UL);
CHECK(snapshot.s2.startSpeed == 100000UL);
CHECK(snapshot.speedClamped == 1U);
CHECK(snapshot.segments[0].targetFrequency == 100000UL);
CHECK((snapshot.segments[0].flags & PLSR_SEGMENT_FLAG_SPEED_CLAMPED)
!= 0U);
CHECK(snapshot.segments[1].targetFrequency == 1000UL);
CHECK((snapshot.segments[1].flags & PLSR_SEGMENT_FLAG_DEFAULT_SPEED)
!= 0U);
CHECK((snapshot.segments[1].flags & PLSR_SEGMENT_FLAG_SELF_LOOP) != 0U);
CHECK(snapshot.hasSelfLoop == 1U);
CHECK(snapshot.initialDirectionPositive == 1U);

TestWriteDword(&memory, PLSR_DEVICE_D, 112U, 9999);
CHECK(snapshot.segments[0].pulseOrTarget == 100);
TestWriteDword(&memory, PLSR_DEVICE_D, 110U, 2500);
CHECK(PlsrResolveLiveFrequency(&snapshot, 1U, &frequency, &clamped)
== PLSR_RESULT_OK);
CHECK(frequency == 2500UL);
CHECK(clamped == 0U);
TestWriteDword(&memory, PLSR_DEVICE_D, 110U, 200000);
CHECK(PlsrResolveLiveFrequency(&snapshot, 1U, &frequency, &clamped)
== PLSR_RESULT_OK);
CHECK(frequency == 100000UL);
CHECK(clamped == 1U);

call.s2.type = PLSR_OPERAND_DATA;
call.s2.data.device = PLSR_DEVICE_HD;
call.s2.data.address = 10UL;
CHECK(PlsrBuildJobSnapshot(&call, &context, &snapshot, &detail)
== PLSR_RESULT_OK);
CHECK(snapshot.s2Set == 1U);
}

static void TestValidationFailures(void)
{
TEST_MEMORY memory;
PLSR_CALL call;
PLSR_PARSE_CONTEXT context = {0, 0U};
PLSR_JOB_SNAPSHOT snapshot;
PLSR_PARSE_DETAIL detail;

TestBuildValidBlocks(&memory);
call = TestMakeCall(&memory);
call.s1.address = 120UL;
CHECK(PlsrBuildJobSnapshot(&call, &context, &snapshot, &detail)
== PLSR_RESULT_BLOCK_OVERLAP);

TestBuildValidBlocks(&memory);
call = TestMakeCall(&memory);
memory.words[PLSR_DEVICE_D][103U] = 1U;
CHECK(PlsrBuildJobSnapshot(&call, &context, &snapshot, &detail)
== PLSR_RESULT_RESERVED_NOT_ZERO);
CHECK(detail.address == 103UL);

TestBuildValidBlocks(&memory);
call = TestMakeCall(&memory);
TestWriteDword(&memory, PLSR_DEVICE_D, 100U, 101);
CHECK(PlsrBuildJobSnapshot(&call, &context, &snapshot, &detail)
== PLSR_RESULT_SEGMENT_OVERFLOW);

TestBuildValidBlocks(&memory);
call = TestMakeCall(&memory);
TestWriteDword(&memory, PLSR_DEVICE_D, 110U, -1);
CHECK(PlsrBuildJobSnapshot(&call, &context, &snapshot, &detail)
== PLSR_RESULT_INVALID_FREQUENCY);
CHECK(detail.segment == 1U);

TestBuildValidBlocks(&memory);
call = TestMakeCall(&memory);
memory.words[PLSR_DEVICE_D][124U] = 0x0405U;
CHECK(PlsrBuildJobSnapshot(&call, &context, &snapshot, &detail)
== PLSR_RESULT_INVALID_WAIT);

TestBuildValidBlocks(&memory);
call = TestMakeCall(&memory);
TestWriteDword(&memory, PLSR_DEVICE_D, 128U, 3);
CHECK(PlsrBuildJobSnapshot(&call, &context, &snapshot, &detail)
== PLSR_RESULT_INVALID_JUMP);

TestBuildValidBlocks(&memory);
call = TestMakeCall(&memory);
TestWriteDword(&memory, PLSR_DEVICE_D, 118U, 2);
TestWriteDword(&memory, PLSR_DEVICE_D, 128U, 1);
CHECK(PlsrBuildJobSnapshot(&call, &context, &snapshot, &detail)
== PLSR_RESULT_PATH_CYCLE);

TestBuildValidBlocks(&memory);
call = TestMakeCall(&memory);
TestWriteDword(&memory, PLSR_DEVICE_D, 200U, 1);
CHECK(PlsrBuildJobSnapshot(&call, &context, &snapshot, &detail)
== PLSR_RESULT_POSITION_INVALID);

TestBuildValidBlocks(&memory);
call = TestMakeCall(&memory);
call.s0.address = UINT32_MAX - 5UL;
CHECK(PlsrBuildJobSnapshot(&call, &context, &snapshot, &detail)
== PLSR_RESULT_ADDRESS_OVERFLOW);

TestBuildValidBlocks(&memory);
call = TestMakeCall(&memory);
call.s2.constant = 5;
CHECK(PlsrBuildJobSnapshot(&call, &context, &snapshot, &detail)
== PLSR_RESULT_INVALID_S2);

TestBuildValidBlocks(&memory);
call = TestMakeCall(&memory);
CHECK(PlcDeviceWriteSfd(962U, 356) == PLC_DEVICE_OK);
CHECK(PlsrBuildJobSnapshot(&call, &context, &snapshot, &detail)
== PLSR_RESULT_INVALID_S2);
CHECK(PlcDeviceWriteSfd(962U, 50) == PLC_DEVICE_OK);
CHECK(PlcDeviceWriteSfd(964U, 1) == PLC_DEVICE_OK);
CHECK(PlsrBuildJobSnapshot(&call, &context, &snapshot, &detail)
== PLSR_RESULT_INVALID_S2);
CHECK(PlcDeviceWriteSfd(964U, 0) == PLC_DEVICE_OK);
}

static void TestDynamicReferences(void)
{
TEST_MEMORY memory;
PLSR_CALL call;
PLSR_PARSE_CONTEXT context = {0, 0U};
PLSR_JOB_SNAPSHOT snapshot;
PLSR_PARSE_DETAIL detail;

TestBuildValidBlocks(&memory);
call = TestMakeCall(&memory);
memory.words[PLSR_DEVICE_D][124U] = 0x0101U;
TestWriteDword(&memory, PLSR_DEVICE_D, 125U, 300);
TestWriteDword(&memory, PLSR_DEVICE_D, 300U, 25);
memory.words[PLSR_DEVICE_D][127U] = 1U;
TestWriteDword(&memory, PLSR_DEVICE_D, 128U, 302);
TestWriteDword(&memory, PLSR_DEVICE_D, 302U, 2);
CHECK(PlsrBuildJobSnapshot(&call, &context, &snapshot, &detail)
== PLSR_RESULT_OK);
CHECK(snapshot.segments[1].waitSource == PLSR_VALUE_D);
CHECK(snapshot.segments[1].waitValueOrAddress == 300);
CHECK(snapshot.segments[1].jumpSource == PLSR_VALUE_D);
CHECK(snapshot.segments[1].jumpValueOrAddress == 302);

memory.words[PLSR_DEVICE_D][124U] = 0x0404U;
TestWriteDword(&memory, PLSR_DEVICE_D, 125U, 7);
memory.bits[0][7U] = 1U;
memory.words[PLSR_DEVICE_D][127U] = 0U;
TestWriteDword(&memory, PLSR_DEVICE_D, 128U, 2);
CHECK(PlsrBuildJobSnapshot(&call, &context, &snapshot, &detail)
== PLSR_RESULT_OK);
}

static void TestOutputAndDivider(void)
{
TEST_MEMORY memory;
PLSR_CALL call;
PLSR_PARSE_CONTEXT context = {0, 0U};
PLSR_JOB_SNAPSHOT snapshot;
PLSR_PARSE_DETAIL detail;
uint16_t psc;
uint16_t arr;

TestBuildValidBlocks(&memory);
call = TestMakeCall(&memory);
CHECK(PlcDeviceWriteSfd(900U, (1U << 13U)) == PLC_DEVICE_OK);
CHECK(PlsrBuildJobSnapshot(&call, &context, &snapshot, &detail)
== PLSR_RESULT_OK);
CHECK(snapshot.outputMode == PLSR_OUTPUT_AB);
CHECK(snapshot.pairedTimerClockHz == 84000000UL);
CHECK(PlsrCalculateTimerDivider(168000000UL, 1UL, &psc, &arr)
== PLSR_RESULT_OK);
CHECK(PlsrCalculateTimerDivider(84000000UL, 100000UL, &psc, &arr)
== PLSR_RESULT_OK);
CHECK(PlsrCalculateTimerDivider(84000000UL, 0UL, &psc, &arr)
== PLSR_RESULT_INVALID_ARGUMENT);
CHECK(PlsrCalculateTimerDivider(1UL, 100000UL, &psc, &arr)
== PLSR_RESULT_DIVIDER_UNREPRESENTABLE);
CHECK(PlcDeviceWriteSfd(900U, 0) == PLC_DEVICE_OK);
}

static void TestCoreSubmission(void)
{
TEST_MEMORY memory;
PLSR_CALL call;
PLSR_STATUS status;
PLSR_PARSE_DETAIL detail;

TestBuildValidBlocks(&memory);
call = TestMakeCall(&memory);
call.sequence = 500UL;
CHECK(PlsrInit() == PLSR_RESULT_OK);
CHECK(PlsrPostCall(&call) == PLSR_RESULT_QUEUED);
PlsrProcess();
CHECK(PlsrGetStatus(0U, &status) == PLSR_RESULT_OK);
CHECK(status.lastCommandResult == PLSR_RESULT_OK);
CHECK(status.state == PLSR_STATE_ACCEL);
CHECK(status.jobValid == 1U);
CHECK(status.segmentCount == 2U);
CHECK(status.startSegment == 1U);
CHECK(status.s2Set == 1U);
CHECK(status.speedClamped == 1U);
CHECK(PlsrGetLastParseDetail(0U, &detail) == PLSR_RESULT_OK);
CHECK(detail.result == PLSR_RESULT_OK);
}

int main(void)
{
PlsrPersistenceTestResetStorage();
CHECK(PlcDeviceInit() == PLC_DEVICE_OK);
TestConfigureAxis0K1();
TestValidSnapshotAndLiveFrequency();
TestValidationFailures();
TestDynamicReferences();
TestOutputAndDivider();
TestCoreSubmission();

if (TestFailures != 0)
{
(void)printf("FAIL: %d of %d PLSR job checks failed\n",
TestFailures,
TestChecks);
return 1;
}
(void)printf("PASS: %d PLSR job checks\n", TestChecks);
return 0;
}

Laden…
Abbrechen
Speichern