Ver código fonte

建立十态单轴状态机

deepseek
ywh 1 mês atrás
pai
commit
ffd715ae75
10 arquivos alterados com 1894 adições e 28 exclusões
  1. +17
    -0
      Core/Src/main.c
  2. +15
    -0
      EWARM/Modbus.ewp
  3. +2
    -0
      Middlewares/Third_Party/Micrium/Config/app_cfg.h
  4. +28
    -0
      PLSR/Inc/plsr_core.h
  5. +46
    -0
      PLSR/Inc/plsr_resource.h
  6. +168
    -0
      PLSR/Inc/plsr_types.h
  7. +1006
    -0
      PLSR/Src/plsr_core.c
  8. +209
    -0
      PLSR/Src/plsr_resource.c
  9. +47
    -28
      PLSR/Test/run_host_tests.ps1
  10. +356
    -0
      PLSR/Test/test_plsr_core.c

+ 17
- 0
Core/Src/main.c Ver arquivo

@@ -25,6 +25,7 @@
#include "ucos_ii.h"
#include "modbus_rtu_slave.h"
#include "plc_device.h"
#include "plsr_core.h"
#include "stdio.h"
/* USER CODE END Includes */

@@ -51,6 +52,7 @@ static volatile uint8_t ConnectFlag;
/* USER CODE BEGIN PV */

static OS_STK AppTaskStartStk[APP_TASK_START_STK_SIZE];
static OS_STK PlsrTaskStk[APP_TASK_PLSR_STK_SIZE];
/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
@@ -165,12 +167,27 @@ int main(void)
{
Error_Handler();
}
if (PlsrInit() != PLSR_RESULT_OK)
{
Error_Handler();
}
/* USER CODE BEGIN 2 */
INT8U osError;

OSInit();

osError = OSTaskCreateExt(PlsrTask, 0,
&PlsrTaskStk[APP_TASK_PLSR_STK_SIZE - 1u],
APP_TASK_PLSR_PRIO, APP_TASK_PLSR_PRIO,
&PlsrTaskStk[0], APP_TASK_PLSR_STK_SIZE, 0,
(OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR));

if (osError != OS_ERR_NONE)
{
Error_Handler();
}

osError = OSTaskCreateExt(AppTaskStart, 0,
&AppTaskStartStk[APP_TASK_START_STK_SIZE - 1u],
APP_TASK_START_PRIO, APP_TASK_START_PRIO,


+ 15
- 0
EWARM/Modbus.ewp Ver arquivo

@@ -1272,12 +1272,27 @@
<file>
<name>$PROJ_DIR$\..\PLSR\Inc\plc_device.h</name>
</file>
<file>
<name>$PROJ_DIR$\..\PLSR\Inc\plsr_types.h</name>
</file>
<file>
<name>$PROJ_DIR$\..\PLSR\Inc\plsr_resource.h</name>
</file>
<file>
<name>$PROJ_DIR$\..\PLSR\Inc\plsr_core.h</name>
</file>
<file>
<name>$PROJ_DIR$\..\PLSR\Src\plsr_persistence.c</name>
</file>
<file>
<name>$PROJ_DIR$\..\PLSR\Src\plc_device.c</name>
</file>
<file>
<name>$PROJ_DIR$\..\PLSR\Src\plsr_resource.c</name>
</file>
<file>
<name>$PROJ_DIR$\..\PLSR\Src\plsr_core.c</name>
</file>
</group>
<group>
<name>Modbus</name>


+ 2
- 0
Middlewares/Third_Party/Micrium/Config/app_cfg.h Ver arquivo

@@ -7,6 +7,7 @@
*/
#define APP_TASK_START_PRIO 5u
#define APP_TASK_TEST_PRIO 6u
#define APP_TASK_PLSR_PRIO 4u

/*
* 任务栈大小的单位是OS_STK元素。当前OS_STK为32位,
@@ -14,5 +15,6 @@
*/
#define APP_TASK_START_STK_SIZE 256u
#define APP_TASK_TEST_STK_SIZE 256u
#define APP_TASK_PLSR_STK_SIZE 256u

#endif

+ 28
- 0
PLSR/Inc/plsr_core.h Ver arquivo

@@ -0,0 +1,28 @@
#ifndef PLSR_CORE_H
#define PLSR_CORE_H

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

#ifdef __cplusplus
extern "C" {
#endif

PLSR_RESULT PlsrInit(void);
void PlsrTask(void *argument);
void PlsrProcess(void);

PLSR_RESULT PlsrPostStart(const PLSR_START_REQUEST *request);
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 PlsrStateTransition(uint8_t axis,
PLSR_STATE target,
PLSR_TRANSITION_REASON reason);

#ifdef __cplusplus
}
#endif

#endif /* PLSR_CORE_H */

+ 46
- 0
PLSR/Inc/plsr_resource.h Ver arquivo

@@ -0,0 +1,46 @@
#ifndef PLSR_RESOURCE_H
#define PLSR_RESOURCE_H

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

#ifdef __cplusplus
extern "C" {
#endif

typedef struct
{
uint8_t ownerAxis;
PLSR_OUTPUT_MODE outputMode;
uint8_t dAxis;
uint8_t directionPoint;
} PLSR_RESOURCE_REQUEST;

typedef struct
{
uint32_t outputMask;
uint8_t highMask;
uint8_t ownerAxis;
uint8_t directionPoint;
PLSR_OUTPUT_MODE outputMode;
uint8_t valid;
} PLSR_RESOURCE_LEASE;

typedef struct
{
uint32_t outputMask;
uint8_t highMask;
} PLSR_RESOURCE_STATUS;

void PlsrResourceInit(void);
PLSR_RESULT PlsrResourceReserve(const PLSR_RESOURCE_REQUEST *request,
PLSR_RESOURCE_LEASE *lease);
void PlsrResourceRelease(PLSR_RESOURCE_LEASE *lease);
void PlsrResourceGetStatus(PLSR_RESOURCE_STATUS *status);
uint8_t PlsrResourceCheckInvariant(void);

#ifdef __cplusplus
}
#endif

#endif /* PLSR_RESOURCE_H */

+ 168
- 0
PLSR/Inc/plsr_types.h Ver arquivo

@@ -0,0 +1,168 @@
#ifndef PLSR_TYPES_H
#define PLSR_TYPES_H

#include <stdint.h>

#ifdef __cplusplus
extern "C" {
#endif

#define PLSR_COMMAND_QUEUE_DEPTH (16U)
#define PLSR_DIRECTION_POINT_NONE (0xFFU)

typedef enum
{
PLSR_STATE_UNINITIALIZED = 0,
PLSR_STATE_IDLE,
PLSR_STATE_ACCEL,
PLSR_STATE_RUN,
PLSR_STATE_DECEL,
PLSR_STATE_WAIT,
PLSR_STATE_PAUSED,
PLSR_STATE_COMPLETED,
PLSR_STATE_STOPPED,
PLSR_STATE_ERROR
} PLSR_STATE;

typedef enum
{
PLSR_OUTPUT_PULSE_DIR = 0,
PLSR_OUTPUT_AB,
PLSR_OUTPUT_CW_CCW
} PLSR_OUTPUT_MODE;

typedef enum
{
PLSR_CMD_START = 0,
PLSR_CMD_STOP_DECEL,
PLSR_CMD_STOP_IMMEDIATE,
PLSR_CMD_PAUSE,
PLSR_CMD_RESUME,
PLSR_CMD_SET_POSITION,
PLSR_CMD_CLEAR_POSITION,
PLSR_CMD_CLEAR_TOTAL,
PLSR_CMD_SAVE_CONFIG,
PLSR_CMD_LOAD_CONFIG,
PLSR_CMD_RESET_ERROR,
PLSR_CMD_SELF_TEST
} PLSR_COMMAND_OPCODE;

typedef enum
{
PLSR_RESULT_OK = 0,
PLSR_RESULT_QUEUED,
PLSR_RESULT_INVALID_ARGUMENT,
PLSR_RESULT_INVALID_AXIS,
PLSR_RESULT_INVALID_STATE,
PLSR_RESULT_QUEUE_FULL,
PLSR_RESULT_RESOURCE_CONFLICT,
PLSR_RESULT_INVALID_RESOURCE,
PLSR_RESULT_BUSY,
PLSR_RESULT_PERSISTENCE_ERROR,
PLSR_RESULT_NOT_SUPPORTED,
PLSR_RESULT_INTERNAL_ERROR
} PLSR_RESULT;

typedef enum
{
PLSR_ERROR_NONE = 0,
PLSR_ERROR_ILLEGAL_TRANSITION,
PLSR_ERROR_RESOURCE_CONFLICT,
PLSR_ERROR_INVALID_RESOURCE,
PLSR_ERROR_TIMER_FAULT,
PLSR_ERROR_COUNTER_FAULT,
PLSR_ERROR_LIMIT_POSITIVE,
PLSR_ERROR_LIMIT_NEGATIVE,
PLSR_ERROR_INTERNAL
} PLSR_ERROR;

typedef enum
{
PLSR_STOP_REASON_NONE = 0,
PLSR_STOP_REASON_NORMAL_COMPLETE,
PLSR_STOP_REASON_PAUSE,
PLSR_STOP_REASON_STOP_DECEL,
PLSR_STOP_REASON_STOP_IMMEDIATE,
PLSR_STOP_REASON_LIMIT_POSITIVE,
PLSR_STOP_REASON_LIMIT_NEGATIVE,
PLSR_STOP_REASON_SOFTWARE_EMERGENCY,
PLSR_STOP_REASON_FAULT
} PLSR_STOP_REASON;

typedef enum
{
PLSR_TRANSITION_INITIALIZED = 0,
PLSR_TRANSITION_START,
PLSR_TRANSITION_ACCEL_COMPLETE,
PLSR_TRANSITION_DECEL_REQUEST,
PLSR_TRANSITION_DECEL_COMPLETE,
PLSR_TRANSITION_WAIT_BEGIN,
PLSR_TRANSITION_WAIT_COMPLETE,
PLSR_TRANSITION_JOB_COMPLETE,
PLSR_TRANSITION_STOP,
PLSR_TRANSITION_FAULT,
PLSR_TRANSITION_RESET_ERROR
} PLSR_TRANSITION_REASON;

#define PLSR_EVENT_SOFTWARE_EMERGENCY (1UL << 0U)
#define PLSR_EVENT_LIMIT_POSITIVE (1UL << 1U)
#define PLSR_EVENT_LIMIT_NEGATIVE (1UL << 2U)
#define PLSR_EVENT_TIMER_FAULT (1UL << 3U)
#define PLSR_EVENT_COUNTER_FAULT (1UL << 4U)
#define PLSR_EVENT_STOP_IMMEDIATE_DONE (1UL << 5U)
#define PLSR_EVENT_ACCEL_COMPLETE (1UL << 8U)
#define PLSR_EVENT_DECEL_COMPLETE (1UL << 9U)
#define PLSR_EVENT_WAIT_BEGIN (1UL << 10U)
#define PLSR_EVENT_WAIT_COMPLETE (1UL << 11U)
#define PLSR_EVENT_JOB_COMPLETE (1UL << 12U)

#define PLSR_EVENT_ALL_MASK (0x00001F3FUL)
#define PLSR_EVENT_CRITICAL_MASK (PLSR_EVENT_SOFTWARE_EMERGENCY \
| PLSR_EVENT_LIMIT_POSITIVE \
| PLSR_EVENT_LIMIT_NEGATIVE \
| PLSR_EVENT_TIMER_FAULT \
| PLSR_EVENT_COUNTER_FAULT)

typedef struct
{
uint32_t sequence;
uint8_t axis;
PLSR_COMMAND_OPCODE opcode;
int64_t argument;
} PLSR_COMMAND;

typedef struct
{
uint32_t sequence;
uint8_t axis;
PLSR_OUTPUT_MODE outputMode;
uint8_t directionPoint;
uint8_t directionPositive;
} PLSR_START_REQUEST;

typedef struct
{
PLSR_STATE state;
PLSR_OUTPUT_MODE outputMode;
PLSR_ERROR error;
PLSR_STOP_REASON stopReason;
PLSR_RESULT lastCommandResult;
uint32_t lastCommandSequence;
uint32_t illegalTransitionCount;
uint32_t pendingEvents;
int64_t logicalPosition;
int64_t totalPulses;
uint8_t busy;
uint8_t pulseActive;
uint8_t done;
uint8_t wait;
uint8_t directionPositive;
uint8_t highResourceMask;
uint8_t directionPoint;
} PLSR_STATUS;

#ifdef __cplusplus
}
#endif

#endif /* PLSR_TYPES_H */

+ 1006
- 0
PLSR/Src/plsr_core.c
Diferenças do arquivo suprimidas por serem muito extensas
Ver arquivo


+ 209
- 0
PLSR/Src/plsr_resource.c Ver arquivo

@@ -0,0 +1,209 @@
#include "plsr_resource.h"
#include "plsr_address_map.h"
#include <string.h>

#ifndef PLSR_HOST_TEST
#include "stm32f4xx.h"
#endif

#define PLSR_HIGH_OUTPUT_MASK (0x0000000FUL)
#define PLSR_VALID_OUTPUT_MASK (0x0013FCFFUL)
#define PLSR_OUTPUT_POINT_COUNT (21U)
#define PLSR_RESOURCE_OWNER_NONE (0xFFU)

static uint32_t PlsrUsedOutputMask;
static uint8_t PlsrUsedHighMask;
static uint8_t PlsrOutputOwners[PLSR_OUTPUT_POINT_COUNT];

static uint32_t PlsrResourceEnterCritical(void)
{
#ifdef PLSR_HOST_TEST
return 0UL;
#else
uint32_t interruptState = __get_PRIMASK();
__disable_irq();
__DMB();
return interruptState;
#endif
}

static void PlsrResourceExitCritical(uint32_t interruptState)
{
#ifdef PLSR_HOST_TEST
(void)interruptState;
#else
__DMB();
if (interruptState == 0UL)
{
__enable_irq();
}
#endif
}

static uint8_t PlsrResourceOutputPointIsValid(uint8_t point)
{
if (point >= PLSR_OUTPUT_POINT_COUNT)
{
return 0U;
}
return ((PLSR_VALID_OUTPUT_MASK & (1UL << point)) != 0UL) ? 1U : 0U;
}

void PlsrResourceInit(void)
{
uint32_t interruptState = PlsrResourceEnterCritical();

PlsrUsedOutputMask = 0UL;
PlsrUsedHighMask = 0U;
(void)memset(PlsrOutputOwners,
PLSR_RESOURCE_OWNER_NONE,
sizeof(PlsrOutputOwners));
PlsrResourceExitCritical(interruptState);
}

PLSR_RESULT PlsrResourceReserve(const PLSR_RESOURCE_REQUEST *request,
PLSR_RESOURCE_LEASE *lease)
{
uint32_t requestedOutputMask;
uint32_t interruptState;
uint8_t requestedHighMask;
uint8_t point;

if ((request == NULL) || (lease == NULL))
{
return PLSR_RESULT_INVALID_ARGUMENT;
}
if ((request->ownerAxis >= PLSR_AXIS_COUNT)
|| (request->dAxis >= PLSR_AXIS_COUNT)
|| (request->ownerAxis != request->dAxis))
{
return PLSR_RESULT_INVALID_AXIS;
}
if (lease->valid != 0U)
{
return PLSR_RESULT_BUSY;
}

if (request->outputMode == PLSR_OUTPUT_PULSE_DIR)
{
if ((PlsrResourceOutputPointIsValid(request->directionPoint) == 0U)
|| (request->directionPoint == request->dAxis))
{
return PLSR_RESULT_INVALID_RESOURCE;
}
requestedHighMask = (uint8_t)(1U << request->dAxis);
requestedOutputMask = (uint32_t)requestedHighMask
| (1UL << request->directionPoint);
}
else if ((request->outputMode == PLSR_OUTPUT_AB)
|| (request->outputMode == PLSR_OUTPUT_CW_CCW))
{
if ((request->dAxis != 0U) && (request->dAxis != 2U))
{
return PLSR_RESULT_INVALID_RESOURCE;
}
requestedHighMask = (uint8_t)(0x03U << request->dAxis);
requestedOutputMask = (uint32_t)requestedHighMask;
}
else
{
return PLSR_RESULT_INVALID_RESOURCE;
}

interruptState = PlsrResourceEnterCritical();
if ((PlsrUsedOutputMask & requestedOutputMask) != 0UL)
{
PlsrResourceExitCritical(interruptState);
return PLSR_RESULT_RESOURCE_CONFLICT;
}

PlsrUsedOutputMask |= requestedOutputMask;
PlsrUsedHighMask |= requestedHighMask;
for (point = 0U; point < PLSR_OUTPUT_POINT_COUNT; point++)
{
if ((requestedOutputMask & (1UL << point)) != 0UL)
{
PlsrOutputOwners[point] = request->ownerAxis;
}
}
PlsrResourceExitCritical(interruptState);

lease->outputMask = requestedOutputMask;
lease->highMask = requestedHighMask;
lease->ownerAxis = request->ownerAxis;
lease->directionPoint = (request->outputMode == PLSR_OUTPUT_PULSE_DIR)
? request->directionPoint
: PLSR_DIRECTION_POINT_NONE;
lease->outputMode = request->outputMode;
lease->valid = 1U;
return PLSR_RESULT_OK;
}

void PlsrResourceRelease(PLSR_RESOURCE_LEASE *lease)
{
uint32_t releaseMask = 0UL;
uint32_t interruptState;
uint8_t point;

if ((lease == NULL) || (lease->valid == 0U))
{
return;
}

interruptState = PlsrResourceEnterCritical();
for (point = 0U; point < PLSR_OUTPUT_POINT_COUNT; point++)
{
if (((lease->outputMask & (1UL << point)) != 0UL)
&& (PlsrOutputOwners[point] == lease->ownerAxis))
{
releaseMask |= (1UL << point);
PlsrOutputOwners[point] = PLSR_RESOURCE_OWNER_NONE;
}
}
PlsrUsedOutputMask &= ~releaseMask;
PlsrUsedHighMask = (uint8_t)(PlsrUsedOutputMask & PLSR_HIGH_OUTPUT_MASK);
PlsrResourceExitCritical(interruptState);

(void)memset(lease, 0, sizeof(*lease));
lease->directionPoint = PLSR_DIRECTION_POINT_NONE;
}

void PlsrResourceGetStatus(PLSR_RESOURCE_STATUS *status)
{
uint32_t interruptState;

if (status == NULL)
{
return;
}

interruptState = PlsrResourceEnterCritical();
status->outputMask = PlsrUsedOutputMask;
status->highMask = PlsrUsedHighMask;
PlsrResourceExitCritical(interruptState);
}

uint8_t PlsrResourceCheckInvariant(void)
{
uint32_t interruptState;
uint8_t valid = 1U;
uint8_t point;

interruptState = PlsrResourceEnterCritical();
if (PlsrUsedHighMask
!= (uint8_t)(PlsrUsedOutputMask & PLSR_HIGH_OUTPUT_MASK))
{
valid = 0U;
}

for (point = 0U; point < PLSR_OUTPUT_POINT_COUNT; point++)
{
if (((PlsrUsedOutputMask & (1UL << point)) == 0UL)
!= (PlsrOutputOwners[point] == PLSR_RESOURCE_OWNER_NONE))
{
valid = 0U;
}
}
PlsrResourceExitCritical(interruptState);
return valid;
}

+ 47
- 28
PLSR/Test/run_host_tests.ps1 Ver arquivo

@@ -7,45 +7,64 @@ if ($null -eq $compiler)
throw 'gcc.exe was not found; PLSR host tests cannot run.'
}

$outputPath = Join-Path $workspacePath 'tmp\test_plc_device.exe'
$outputDirectory = Split-Path -Parent $outputPath
$outputDirectory = Join-Path $workspacePath 'tmp'
if (-not (Test-Path -LiteralPath $outputDirectory))
{
New-Item -ItemType Directory -Path $outputDirectory | Out-Null
}

$arguments = @(
'-std=c11',
'-Wall',
'-Wextra',
'-Werror',
'-DPLSR_HOST_TEST',
"-I$workspacePath\PLSR\Inc",
"$workspacePath\PLSR\Src\plc_device.c",
"$workspacePath\PLSR\Src\plsr_persistence.c",
"$workspacePath\PLSR\Test\test_plc_device.c",
'-o',
$outputPath
$tests = @(
@{
Name = 'test_plc_device'
Sources = @(
"$workspacePath\PLSR\Src\plc_device.c"
"$workspacePath\PLSR\Src\plsr_persistence.c"
"$workspacePath\PLSR\Test\test_plc_device.c"
)
},
@{
Name = 'test_plsr_core'
Sources = @(
"$workspacePath\PLSR\Src\plc_device.c"
"$workspacePath\PLSR\Src\plsr_persistence.c"
"$workspacePath\PLSR\Src\plsr_resource.c"
"$workspacePath\PLSR\Src\plsr_core.c"
"$workspacePath\PLSR\Test\test_plsr_core.c"
)
}
)

try
foreach ($test in $tests)
{
& $compiler.Source @arguments
if ($LASTEXITCODE -ne 0)
{
throw "PLSR host-test compilation failed with exit code $LASTEXITCODE."
}
$outputPath = Join-Path $outputDirectory "$($test.Name).exe"
$arguments = @(
'-std=c11'
'-Wall'
'-Wextra'
'-Werror'
'-DPLSR_HOST_TEST'
"-I$workspacePath\PLSR\Inc"
) + $test.Sources + @('-o', $outputPath)

& $outputPath
if ($LASTEXITCODE -ne 0)
try
{
throw "PLSR host tests failed with exit code $LASTEXITCODE."
& $compiler.Source @arguments
if ($LASTEXITCODE -ne 0)
{
throw "$($test.Name) compilation failed with exit code $LASTEXITCODE."
}

& $outputPath
if ($LASTEXITCODE -ne 0)
{
throw "$($test.Name) failed with exit code $LASTEXITCODE."
}
}
}
finally
{
if (Test-Path -LiteralPath $outputPath)
finally
{
Remove-Item -LiteralPath $outputPath -Force
if (Test-Path -LiteralPath $outputPath)
{
Remove-Item -LiteralPath $outputPath -Force
}
}
}

+ 356
- 0
PLSR/Test/test_plsr_core.c Ver arquivo

@@ -0,0 +1,356 @@
#include "plc_device.h"
#include "plsr_core.h"
#include "plsr_persistence.h"
#include "plsr_resource.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

static unsigned int TestCount;

#define TEST_CHECK(condition) \
do \
{ \
TestCount++; \
if (!(condition)) \
{ \
(void)fprintf(stderr, "FAIL line %d: %s\n", __LINE__, #condition); \
exit(EXIT_FAILURE); \
} \
} while (0)

static void TestReset(void)
{
PlsrPersistenceTestResetStorage();
TEST_CHECK(PlcDeviceInit() == PLC_DEVICE_OK);
TEST_CHECK(PlsrInit() == PLSR_RESULT_OK);
}

static PLSR_RESULT TestPostCommand(uint32_t sequence,
uint8_t axis,
PLSR_COMMAND_OPCODE opcode,
int64_t argument)
{
PLSR_COMMAND command;

command.sequence = sequence;
command.axis = axis;
command.opcode = opcode;
command.argument = argument;
return PlsrPostCommand(&command);
}

static PLSR_RESULT TestPostStart(uint32_t sequence,
uint8_t axis,
PLSR_OUTPUT_MODE mode,
uint8_t directionPoint,
uint8_t directionPositive)
{
PLSR_START_REQUEST request;

request.sequence = sequence;
request.axis = axis;
request.outputMode = mode;
request.directionPoint = directionPoint;
request.directionPositive = directionPositive;
return PlsrPostStart(&request);
}

static PLSR_STATUS TestGetStatus(uint8_t axis)
{
PLSR_STATUS status;

(void)memset(&status, 0, sizeof(status));
TEST_CHECK(PlsrGetStatus(axis, &status) == PLSR_RESULT_OK);
return status;
}

static void TestResourceManager(void)
{
PLSR_RESOURCE_REQUEST request;
PLSR_RESOURCE_LEASE first;
PLSR_RESOURCE_LEASE second;
PLSR_RESOURCE_STATUS status;

(void)memset(&first, 0, sizeof(first));
(void)memset(&second, 0, sizeof(second));
PlsrResourceInit();

request.ownerAxis = 0U;
request.outputMode = PLSR_OUTPUT_PULSE_DIR;
request.dAxis = 0U;
request.directionPoint = 4U;
TEST_CHECK(PlsrResourceReserve(&request, &first) == PLSR_RESULT_OK);
TEST_CHECK(first.highMask == 0x01U);
TEST_CHECK(first.outputMask == ((1UL << 0U) | (1UL << 4U)));

request.ownerAxis = 1U;
request.dAxis = 1U;
request.directionPoint = 4U;
TEST_CHECK(PlsrResourceReserve(&request, &second)
== PLSR_RESULT_RESOURCE_CONFLICT);
TEST_CHECK(second.valid == 0U);

request.directionPoint = 8U;
TEST_CHECK(PlsrResourceReserve(&request, &second)
== PLSR_RESULT_INVALID_RESOURCE);
request.directionPoint = 1U;
TEST_CHECK(PlsrResourceReserve(&request, &second)
== PLSR_RESULT_INVALID_RESOURCE);

PlsrResourceRelease(&first);
PlsrResourceRelease(&first);
request.ownerAxis = 0U;
request.outputMode = PLSR_OUTPUT_AB;
request.dAxis = 0U;
request.directionPoint = PLSR_DIRECTION_POINT_NONE;
TEST_CHECK(PlsrResourceReserve(&request, &first) == PLSR_RESULT_OK);
TEST_CHECK(first.highMask == 0x03U);

request.ownerAxis = 2U;
request.outputMode = PLSR_OUTPUT_PULSE_DIR;
request.dAxis = 2U;
request.directionPoint = 4U;
TEST_CHECK(PlsrResourceReserve(&request, &second) == PLSR_RESULT_OK);
TEST_CHECK(second.highMask == 0x04U);

request.ownerAxis = 1U;
request.outputMode = PLSR_OUTPUT_CW_CCW;
request.dAxis = 1U;
request.directionPoint = PLSR_DIRECTION_POINT_NONE;
PlsrResourceRelease(&second);
TEST_CHECK(PlsrResourceReserve(&request, &second)
== PLSR_RESULT_INVALID_RESOURCE);

PlsrResourceGetStatus(&status);
TEST_CHECK(status.highMask == 0x03U);
TEST_CHECK(PlsrResourceCheckInvariant() != 0U);
PlsrResourceRelease(&first);
PlsrResourceGetStatus(&status);
TEST_CHECK(status.outputMask == 0UL);
}

static void TestStateMachineAndCommands(void)
{
PLSR_RESOURCE_STATUS resources;
PLSR_STATUS status;

TestReset();
status = TestGetStatus(0U);
TEST_CHECK(status.state == PLSR_STATE_IDLE);
TEST_CHECK(status.directionPoint == PLSR_DIRECTION_POINT_NONE);

TEST_CHECK(TestPostStart(1U, 0U, PLSR_OUTPUT_PULSE_DIR, 4U, 1U)
== PLSR_RESULT_QUEUED);
PlsrProcess();
status = TestGetStatus(0U);
TEST_CHECK(status.state == PLSR_STATE_ACCEL);
TEST_CHECK(status.busy != 0U);
TEST_CHECK(status.pulseActive != 0U);
TEST_CHECK(status.done == 0U);
TEST_CHECK(status.highResourceMask == 0x01U);
TEST_CHECK(status.directionPoint == 4U);
TEST_CHECK(status.lastCommandSequence == 1U);
TEST_CHECK(status.lastCommandResult == PLSR_RESULT_OK);
TEST_CHECK(TestPostStart(1U, 0U, PLSR_OUTPUT_PULSE_DIR, 4U, 1U)
== PLSR_RESULT_OK);

TEST_CHECK(TestPostStart(1U, 1U, PLSR_OUTPUT_PULSE_DIR, 4U, 1U)
== PLSR_RESULT_QUEUED);
PlsrProcess();
status = TestGetStatus(1U);
TEST_CHECK(status.state == PLSR_STATE_IDLE);
TEST_CHECK(status.lastCommandResult == PLSR_RESULT_RESOURCE_CONFLICT);
TEST_CHECK(status.error == PLSR_ERROR_RESOURCE_CONFLICT);

TEST_CHECK(PlsrPostEvent(0U, PLSR_EVENT_ACCEL_COMPLETE)
== PLSR_RESULT_OK);
PlsrProcess();
TEST_CHECK(TestGetStatus(0U).state == PLSR_STATE_RUN);

TEST_CHECK(TestPostCommand(2U, 0U, PLSR_CMD_SET_POSITION, 500)
== PLSR_RESULT_QUEUED);
PlsrProcess();
TEST_CHECK(TestGetStatus(0U).lastCommandResult == PLSR_RESULT_BUSY);

TEST_CHECK(TestPostCommand(3U, 0U, PLSR_CMD_PAUSE, 0)
== PLSR_RESULT_QUEUED);
PlsrProcess();
TEST_CHECK(TestGetStatus(0U).state == PLSR_STATE_DECEL);
TEST_CHECK(PlsrPostEvent(0U, PLSR_EVENT_DECEL_COMPLETE)
== PLSR_RESULT_OK);
PlsrProcess();
status = TestGetStatus(0U);
TEST_CHECK(status.state == PLSR_STATE_PAUSED);
TEST_CHECK(status.busy != 0U);
TEST_CHECK(status.pulseActive == 0U);
TEST_CHECK(status.highResourceMask == 0x01U);

TEST_CHECK(TestPostCommand(4U, 0U, PLSR_CMD_RESUME, 0)
== PLSR_RESULT_QUEUED);
PlsrProcess();
TEST_CHECK(TestGetStatus(0U).state == PLSR_STATE_ACCEL);

TEST_CHECK(TestPostCommand(5U, 0U, PLSR_CMD_STOP_IMMEDIATE, 0)
== PLSR_RESULT_QUEUED);
PlsrProcess();
status = TestGetStatus(0U);
TEST_CHECK(status.state == PLSR_STATE_ACCEL);
TEST_CHECK(status.stopReason == PLSR_STOP_REASON_STOP_IMMEDIATE);
TEST_CHECK(status.highResourceMask == 0x01U);
TEST_CHECK(TestPostCommand(5U, 0U, PLSR_CMD_STOP_IMMEDIATE, 0)
== PLSR_RESULT_OK);

TEST_CHECK(PlsrPostEvent(0U, PLSR_EVENT_STOP_IMMEDIATE_DONE)
== PLSR_RESULT_OK);
PlsrProcess();
status = TestGetStatus(0U);
TEST_CHECK(status.state == PLSR_STATE_STOPPED);
TEST_CHECK(status.busy == 0U);
TEST_CHECK(status.done == 0U);
TEST_CHECK(status.highResourceMask == 0U);
PlsrResourceGetStatus(&resources);
TEST_CHECK(resources.outputMask == 0UL);

TEST_CHECK(TestPostStart(6U, 0U, PLSR_OUTPUT_PULSE_DIR, 4U, 0U)
== PLSR_RESULT_QUEUED);
PlsrProcess();
TEST_CHECK(PlsrPostEvent(0U, PLSR_EVENT_JOB_COMPLETE)
== PLSR_RESULT_OK);
PlsrProcess();
status = TestGetStatus(0U);
TEST_CHECK(status.state == PLSR_STATE_COMPLETED);
TEST_CHECK(status.done != 0U);
TEST_CHECK(status.stopReason == PLSR_STOP_REASON_NORMAL_COMPLETE);

TEST_CHECK(TestPostStart(7U, 0U, PLSR_OUTPUT_PULSE_DIR, 4U, 1U)
== PLSR_RESULT_QUEUED);
PlsrProcess();
TEST_CHECK(TestGetStatus(0U).done == 0U);
TEST_CHECK(PlsrPostEvent(0U,
PLSR_EVENT_JOB_COMPLETE
| PLSR_EVENT_SOFTWARE_EMERGENCY)
== PLSR_RESULT_OK);
PlsrProcess();
status = TestGetStatus(0U);
TEST_CHECK(status.state == PLSR_STATE_STOPPED);
TEST_CHECK(status.done == 0U);
TEST_CHECK(status.stopReason == PLSR_STOP_REASON_SOFTWARE_EMERGENCY);

TEST_CHECK(PlsrStateTransition(0U,
PLSR_STATE_RUN,
PLSR_TRANSITION_ACCEL_COMPLETE)
== PLSR_RESULT_INVALID_STATE);
status = TestGetStatus(0U);
TEST_CHECK(status.state == PLSR_STATE_ERROR);
TEST_CHECK(status.error == PLSR_ERROR_ILLEGAL_TRANSITION);
TEST_CHECK(status.illegalTransitionCount == 1UL);
TEST_CHECK(TestPostCommand(8U, 0U, PLSR_CMD_RESET_ERROR, 0)
== PLSR_RESULT_QUEUED);
PlsrProcess();
TEST_CHECK(TestGetStatus(0U).state == PLSR_STATE_IDLE);
}

static void TestLimitWaitAndPairs(void)
{
PLSR_STATUS status;

TestReset();
TEST_CHECK(TestPostStart(10U, 0U, PLSR_OUTPUT_PULSE_DIR, 4U, 1U)
== PLSR_RESULT_QUEUED);
PlsrProcess();
TEST_CHECK(PlsrPostEvent(0U,
PLSR_EVENT_LIMIT_POSITIVE
| PLSR_EVENT_DECEL_COMPLETE)
== PLSR_RESULT_OK);
PlsrProcess();
status = TestGetStatus(0U);
TEST_CHECK(status.state == PLSR_STATE_STOPPED);
TEST_CHECK(status.stopReason == PLSR_STOP_REASON_LIMIT_POSITIVE);
TEST_CHECK(status.error == PLSR_ERROR_LIMIT_POSITIVE);

TEST_CHECK(TestPostStart(11U,
2U,
PLSR_OUTPUT_AB,
PLSR_DIRECTION_POINT_NONE,
0U)
== PLSR_RESULT_QUEUED);
PlsrProcess();
status = TestGetStatus(2U);
TEST_CHECK(status.highResourceMask == 0x0CU);
TEST_CHECK(status.outputMode == PLSR_OUTPUT_AB);
TEST_CHECK(PlsrPostEvent(2U, PLSR_EVENT_WAIT_BEGIN) == PLSR_RESULT_OK);
PlsrProcess();
status = TestGetStatus(2U);
TEST_CHECK(status.state == PLSR_STATE_WAIT);
TEST_CHECK(status.busy != 0U);
TEST_CHECK(status.pulseActive == 0U);
TEST_CHECK(status.highResourceMask == 0x0CU);

TEST_CHECK(TestPostCommand(12U, 2U, PLSR_CMD_PAUSE, 0)
== PLSR_RESULT_QUEUED);
PlsrProcess();
TEST_CHECK(TestGetStatus(2U).state == PLSR_STATE_PAUSED);
TEST_CHECK(TestPostCommand(13U, 2U, PLSR_CMD_STOP_DECEL, 0)
== PLSR_RESULT_QUEUED);
PlsrProcess();
status = TestGetStatus(2U);
TEST_CHECK(status.state == PLSR_STATE_STOPPED);
TEST_CHECK(status.highResourceMask == 0U);

TEST_CHECK(TestPostStart(14U,
1U,
PLSR_OUTPUT_CW_CCW,
PLSR_DIRECTION_POINT_NONE,
1U)
== PLSR_RESULT_QUEUED);
PlsrProcess();
status = TestGetStatus(1U);
TEST_CHECK(status.state == PLSR_STATE_IDLE);
TEST_CHECK(status.lastCommandResult == PLSR_RESULT_INVALID_RESOURCE);
}

static void TestQueueAndInputValidation(void)
{
PLSR_COMMAND command;
uint32_t sequence;

TestReset();
TEST_CHECK(PlsrPostEvent(4U, PLSR_EVENT_JOB_COMPLETE)
== PLSR_RESULT_INVALID_AXIS);
TEST_CHECK(PlsrPostEvent(0U, 0UL) == PLSR_RESULT_INVALID_ARGUMENT);
TEST_CHECK(PlsrPostEvent(0U, 0x80000000UL)
== PLSR_RESULT_INVALID_ARGUMENT);
TEST_CHECK(PlsrGetStatus(0U, NULL) == PLSR_RESULT_INVALID_ARGUMENT);
TEST_CHECK(PlsrGetStatus(4U, NULL) == PLSR_RESULT_INVALID_AXIS);

command.axis = 1U;
command.opcode = PLSR_CMD_CLEAR_POSITION;
command.argument = 0;
for (sequence = 100U;
sequence < 100U + PLSR_COMMAND_QUEUE_DEPTH;
sequence++)
{
command.sequence = sequence;
TEST_CHECK(PlsrPostCommand(&command) == PLSR_RESULT_QUEUED);
}
command.sequence = 1000U;
TEST_CHECK(PlsrPostCommand(&command) == PLSR_RESULT_QUEUE_FULL);
PlsrProcess();
TEST_CHECK(TestGetStatus(1U).lastCommandResult == PLSR_RESULT_OK);
TEST_CHECK(TestPostCommand(2000U, 0U, PLSR_CMD_SELF_TEST, 0)
== PLSR_RESULT_QUEUED);
PlsrProcess();
TEST_CHECK(TestGetStatus(0U).lastCommandResult == PLSR_RESULT_OK);
}

int main(void)
{
TestResourceManager();
TestStateMachineAndCommands();
TestLimitWaitAndPairs();
TestQueueAndInputValidation();

(void)printf("PASS: %u PLSR core checks\n", TestCount);
return EXIT_SUCCESS;
}

Carregando…
Cancelar
Salvar