|
- #include "plsr_modbus_control.h"
- #include "modbus_data_store.h"
- #include "plsr_address_map.h"
- #include "plsr_core.h"
- #include "plsr_job.h"
- #include "plsr_modbus_data.h"
- #include <stddef.h>
- #include <string.h>
-
- #define PLSR_MODBUS_MAGIC_LOW (0x504CU)
- #define PLSR_MODBUS_MAGIC_HIGH (0x5352U)
- #define PLSR_MODBUS_CAPABILITIES (0x0007U)
- #define PLSR_MODBUS_CALL_REQUEST_WORDS (16UL)
- #define PLSR_MODBUS_CALL_RESPONSE_WORDS (12UL)
- #define PLSR_MODBUS_COMMAND_REQUEST_WORDS (8UL)
- #define PLSR_MODBUS_COMMAND_RESPONSE_WORDS (8UL)
- #define PLSR_MODBUS_S0_HEADER_WORDS (10UL)
- #define PLSR_MODBUS_S0_SEGMENT_WORDS (10UL)
- #define PLSR_MODBUS_S1_WORDS (4UL)
- #define PLSR_MODBUS_HASH_OFFSET (2166136261UL)
- #define PLSR_MODBUS_HASH_PRIME (16777619UL)
-
- typedef struct
- {
- PLSR_CALL call;
- uint32_t fingerprint;
- uint8_t valid;
- } PLSR_MODBUS_COMMITTED_CALL;
-
- static uint16_t PlsrModbusBaseAddress;
- static uint8_t PlsrModbusEnabled;
- static uint32_t PlsrModbusLastCallRequestSequence;
- static uint32_t PlsrModbusLastCommandRequestSequence;
- static uint32_t PlsrModbusStatusGeneration[PLSR_AXIS_COUNT];
- static PLSR_MODBUS_COMMITTED_CALL PlsrModbusCommitted[PLSR_AXIS_COUNT];
- static uint16_t PlsrModbusStatusWords[PLSR_AXIS_COUNT]
- [PLSR_MODBUS_AXIS_STATUS_WORDS];
- static const uint16_t PlsrModbusZeroWindow[PLSR_MODBUS_WINDOW_WORDS] = {0U};
-
- static void PlsrModbusPutU32(uint16_t *words,
- uint32_t offset,
- uint32_t value)
- {
- words[offset] = (uint16_t)(value & 0xFFFFUL);
- words[offset + 1UL] = (uint16_t)(value >> 16U);
- }
-
- static void PlsrModbusPutU64(uint16_t *words,
- uint32_t offset,
- uint64_t value)
- {
- words[offset] = (uint16_t)(value & 0xFFFFULL);
- words[offset + 1UL] = (uint16_t)((value >> 16U) & 0xFFFFULL);
- words[offset + 2UL] = (uint16_t)((value >> 32U) & 0xFFFFULL);
- words[offset + 3UL] = (uint16_t)(value >> 48U);
- }
-
- static uint32_t PlsrModbusGetU32(const uint16_t *words, uint32_t offset)
- {
- return ((uint32_t)words[offset + 1UL] << 16U) | words[offset];
- }
-
- static uint64_t PlsrModbusGetU64(const uint16_t *words, uint32_t offset)
- {
- return ((uint64_t)words[offset + 3UL] << 48U)
- | ((uint64_t)words[offset + 2UL] << 32U)
- | ((uint64_t)words[offset + 1UL] << 16U)
- | words[offset];
- }
-
- static uint8_t PlsrModbusReadWords(uint32_t offset,
- uint16_t *words,
- uint32_t wordCount)
- {
- uint32_t index;
-
- if (words == NULL)
- {
- return 0U;
- }
- for (index = 0UL; index < wordCount; index++)
- {
- if (ModbusDataReadWord(MODBUS_DATA_DEVICE_D,
- (uint32_t)PlsrModbusBaseAddress + offset + index,
- &words[index]) == 0U)
- {
- return 0U;
- }
- }
- return 1U;
- }
-
- static uint8_t PlsrModbusRangesOverlap(uint32_t firstA,
- uint32_t countA,
- uint32_t firstB,
- uint32_t countB)
- {
- return ((firstA < (firstB + countB)) && (firstB < (firstA + countA)))
- ? 1U
- : 0U;
- }
-
- static uint32_t PlsrModbusHashWord(uint32_t hash, uint16_t value)
- {
- hash ^= (uint8_t)(value & 0x00FFU);
- hash *= PLSR_MODBUS_HASH_PRIME;
- hash ^= (uint8_t)(value >> 8U);
- hash *= PLSR_MODBUS_HASH_PRIME;
- return hash;
- }
-
- static uint32_t PlsrModbusHashU32(uint32_t hash, uint32_t value)
- {
- hash = PlsrModbusHashWord(hash, (uint16_t)(value & 0xFFFFUL));
- return PlsrModbusHashWord(hash, (uint16_t)(value >> 16U));
- }
-
- static PLSR_RESULT PlsrModbusFingerprintCall(const PLSR_CALL *call,
- uint32_t *fingerprint)
- {
- uint16_t word;
- int32_t segmentCount;
- uint32_t s0Words;
- uint32_t index;
- uint32_t hash = PLSR_MODBUS_HASH_OFFSET;
-
- if ((call == NULL) || (fingerprint == NULL)
- || (call->source.readDword == NULL)
- || (call->source.readWord == NULL)
- || (call->source.validateWords == NULL))
- {
- return PLSR_RESULT_INVALID_ARGUMENT;
- }
- if (call->source.readDword(call->source.context,
- call->s0.device,
- call->s0.address,
- &segmentCount) == 0U)
- {
- return PLSR_RESULT_DATA_ACCESS;
- }
- if ((segmentCount < 1) || (segmentCount > (int32_t)PLSR_MAX_SEGMENTS))
- {
- return PLSR_RESULT_SEGMENT_OVERFLOW;
- }
- s0Words = PLSR_MODBUS_S0_HEADER_WORDS
- + (uint32_t)segmentCount * PLSR_MODBUS_S0_SEGMENT_WORDS;
- if ((call->source.validateWords(call->source.context,
- call->s0.device,
- call->s0.address,
- s0Words) == 0U)
- || (call->source.validateWords(call->source.context,
- call->s1.device,
- call->s1.address,
- PLSR_MODBUS_S1_WORDS) == 0U))
- {
- return PLSR_RESULT_DATA_ACCESS;
- }
- if (((call->s0.device == PLSR_DEVICE_D)
- && (PlsrModbusRangesOverlap(call->s0.address,
- s0Words,
- PlsrModbusBaseAddress,
- PLSR_MODBUS_WINDOW_WORDS) != 0U))
- || ((call->s1.device == PLSR_DEVICE_D)
- && (PlsrModbusRangesOverlap(call->s1.address,
- PLSR_MODBUS_S1_WORDS,
- PlsrModbusBaseAddress,
- PLSR_MODBUS_WINDOW_WORDS) != 0U)))
- {
- return PLSR_RESULT_BLOCK_OVERLAP;
- }
-
- hash = PlsrModbusHashWord(hash, (uint16_t)call->s0.device);
- hash = PlsrModbusHashU32(hash, call->s0.address);
- for (index = 0UL; index < s0Words; index++)
- {
- if (call->source.readWord(call->source.context,
- call->s0.device,
- call->s0.address + index,
- &word) == 0U)
- {
- return PLSR_RESULT_DATA_ACCESS;
- }
- hash = PlsrModbusHashWord(hash, word);
- }
- hash = PlsrModbusHashWord(hash, (uint16_t)call->s1.device);
- hash = PlsrModbusHashU32(hash, call->s1.address);
- for (index = 0UL; index < PLSR_MODBUS_S1_WORDS; index++)
- {
- if (call->source.readWord(call->source.context,
- call->s1.device,
- call->s1.address + index,
- &word) == 0U)
- {
- return PLSR_RESULT_DATA_ACCESS;
- }
- hash = PlsrModbusHashWord(hash, word);
- }
- hash = PlsrModbusHashWord(hash, (uint16_t)call->s2.type);
- hash = PlsrModbusHashWord(hash, (uint16_t)call->s2.data.device);
- hash = PlsrModbusHashU32(hash, call->s2.data.address);
- hash = PlsrModbusHashU32(hash, (uint32_t)call->s2.constant);
- if (call->s2.type == PLSR_OPERAND_DATA)
- {
- for (index = 0UL; index < 2UL; index++)
- {
- if (call->source.readWord(call->source.context,
- call->s2.data.device,
- call->s2.data.address + index,
- &word) == 0U)
- {
- return PLSR_RESULT_DATA_ACCESS;
- }
- hash = PlsrModbusHashWord(hash, word);
- }
- }
- hash = PlsrModbusHashWord(hash, call->dAxis);
- hash = PlsrModbusHashWord(hash, call->outputModeOverride);
- *fingerprint = hash;
- return PLSR_RESULT_OK;
- }
-
- static PLSR_RESULT PlsrModbusBuildCall(const uint16_t *request,
- PLSR_CALL *call)
- {
- uint16_t s2Type;
- uint16_t outputMode;
-
- if ((request == NULL) || (call == NULL))
- {
- return PLSR_RESULT_INVALID_ARGUMENT;
- }
- s2Type = request[8UL];
- outputMode = request[13UL];
- if ((request[2UL] > (uint16_t)PLSR_DEVICE_FD)
- || (request[5UL] > (uint16_t)PLSR_DEVICE_FD)
- || (s2Type > (uint16_t)PLSR_OPERAND_DATA)
- || ((s2Type == (uint16_t)PLSR_OPERAND_DATA)
- && (request[9UL] > (uint16_t)PLSR_DEVICE_FD))
- || (request[12UL] >= PLSR_AXIS_COUNT)
- || ((outputMode > (uint16_t)PLSR_OUTPUT_CW_CCW)
- && (outputMode != PLSR_OUTPUT_MODE_FROM_SFD)))
- {
- return PLSR_RESULT_INVALID_ARGUMENT;
- }
-
- (void)memset(call, 0, sizeof(*call));
- call->sequence = PlsrModbusGetU32(request, 0UL);
- call->s0.device = (PLSR_DEVICE_TYPE)request[2UL];
- call->s0.address = PlsrModbusGetU32(request, 3UL);
- call->s1.device = (PLSR_DEVICE_TYPE)request[5UL];
- call->s1.address = PlsrModbusGetU32(request, 6UL);
- call->s2.type = (PLSR_OPERAND_TYPE)s2Type;
- call->s2.data.device = (PLSR_DEVICE_TYPE)request[9UL];
- call->s2.data.address = PlsrModbusGetU32(request, 10UL);
- call->s2.constant = (int32_t)PlsrModbusGetU32(request, 10UL);
- call->dAxis = (uint8_t)request[12UL];
- call->outputModeOverride = (uint8_t)outputMode;
- PlsrModbusDataSourceInit(&call->source);
- return PLSR_RESULT_OK;
- }
-
- static void PlsrModbusPublishCallResponse(uint32_t sequence,
- uint16_t operation,
- PLSR_RESULT result,
- const PLSR_PARSE_DETAIL *detail,
- uint8_t committed)
- {
- uint16_t response[PLSR_MODBUS_CALL_RESPONSE_WORDS] = {0U};
-
- PlsrModbusPutU32(response, 0UL, sequence);
- response[2UL] = operation;
- response[3UL] = (uint16_t)result;
- if (detail != NULL)
- {
- response[4UL] = (uint16_t)detail->result;
- response[5UL] = (uint16_t)detail->block;
- PlsrModbusPutU32(response, 6UL, detail->address);
- PlsrModbusPutU32(response, 8UL, (uint32_t)detail->value);
- response[10UL] = detail->segment;
- }
- response[11UL] = committed;
- (void)ModbusDataWriteWords(MODBUS_DATA_DEVICE_D,
- (uint32_t)PlsrModbusBaseAddress
- + PLSR_MODBUS_CALL_RESPONSE_OFFSET,
- response,
- PLSR_MODBUS_CALL_RESPONSE_WORDS);
- }
-
- static void PlsrModbusHandleCallRequest(void)
- {
- uint16_t request[PLSR_MODBUS_CALL_REQUEST_WORDS];
- PLSR_CALL call;
- PLSR_PARSE_DETAIL detail;
- PLSR_RESULT result;
- uint32_t sequence;
- uint32_t fingerprint;
- uint16_t operation;
- uint8_t axis = 0U;
-
- if (PlsrModbusReadWords(PLSR_MODBUS_CALL_REQUEST_OFFSET,
- request,
- PLSR_MODBUS_CALL_REQUEST_WORDS) == 0U)
- {
- return;
- }
- sequence = PlsrModbusGetU32(request, 0UL);
- if ((sequence == 0UL) || (sequence == PlsrModbusLastCallRequestSequence))
- {
- return;
- }
- PlsrModbusLastCallRequestSequence = sequence;
- operation = request[14UL];
- (void)memset(&detail, 0, sizeof(detail));
- result = PlsrModbusBuildCall(request, &call);
- if (result == PLSR_RESULT_OK)
- {
- axis = call.dAxis;
- }
-
- if ((result == PLSR_RESULT_OK) && (operation == PLSR_MODBUS_CALL_COMMIT))
- {
- result = PlsrValidateCall(&call, &detail);
- if (result == PLSR_RESULT_OK)
- {
- result = PlsrModbusFingerprintCall(&call, &fingerprint);
- }
- if (result == PLSR_RESULT_OK)
- {
- PlsrModbusCommitted[axis].call = call;
- PlsrModbusCommitted[axis].fingerprint = fingerprint;
- PlsrModbusCommitted[axis].valid = 1U;
- }
- else
- {
- PlsrModbusCommitted[axis].valid = 0U;
- }
- }
- else if ((result == PLSR_RESULT_OK)
- && (operation == PLSR_MODBUS_CALL_START))
- {
- if (PlsrModbusCommitted[axis].valid == 0U)
- {
- result = PLSR_RESULT_INVALID_STATE;
- }
- else
- {
- result = PlsrModbusFingerprintCall(
- &PlsrModbusCommitted[axis].call,
- &fingerprint);
- if ((result == PLSR_RESULT_OK)
- && (fingerprint != PlsrModbusCommitted[axis].fingerprint))
- {
- result = PLSR_RESULT_BUSY;
- }
- if (result == PLSR_RESULT_OK)
- {
- result = PlsrValidateCall(&PlsrModbusCommitted[axis].call,
- &detail);
- }
- if (result == PLSR_RESULT_OK)
- {
- PlsrModbusCommitted[axis].call.sequence = sequence;
- result = PlsrPostCall(&PlsrModbusCommitted[axis].call);
- }
- }
- }
- else if (result == PLSR_RESULT_OK)
- {
- result = PLSR_RESULT_INVALID_ARGUMENT;
- }
-
- PlsrModbusPublishCallResponse(
- sequence,
- operation,
- result,
- &detail,
- (axis < PLSR_AXIS_COUNT) ? PlsrModbusCommitted[axis].valid : 0U);
- }
-
- static void PlsrModbusPublishCommandResponse(uint32_t sequence,
- uint16_t opcode,
- uint16_t axis,
- PLSR_RESULT result)
- {
- uint16_t response[PLSR_MODBUS_COMMAND_RESPONSE_WORDS] = {0U};
-
- PlsrModbusPutU32(response, 0UL, sequence);
- response[2UL] = opcode;
- response[3UL] = axis;
- response[4UL] = (uint16_t)result;
- (void)ModbusDataWriteWords(MODBUS_DATA_DEVICE_D,
- (uint32_t)PlsrModbusBaseAddress
- + PLSR_MODBUS_COMMAND_RESPONSE_OFFSET,
- response,
- PLSR_MODBUS_COMMAND_RESPONSE_WORDS);
- }
-
- static void PlsrModbusHandleCommandRequest(void)
- {
- uint16_t request[PLSR_MODBUS_COMMAND_REQUEST_WORDS];
- PLSR_COMMAND command;
- PLSR_RESULT result;
- uint32_t sequence;
-
- if (PlsrModbusReadWords(PLSR_MODBUS_COMMAND_REQUEST_OFFSET,
- request,
- PLSR_MODBUS_COMMAND_REQUEST_WORDS) == 0U)
- {
- return;
- }
- sequence = PlsrModbusGetU32(request, 0UL);
- if ((sequence == 0UL)
- || (sequence == PlsrModbusLastCommandRequestSequence))
- {
- return;
- }
- PlsrModbusLastCommandRequestSequence = sequence;
- (void)memset(&command, 0, sizeof(command));
- if ((request[2UL] > (uint16_t)PLSR_CMD_SELF_TEST)
- || (request[2UL] == (uint16_t)PLSR_CMD_START)
- || (request[3UL] >= PLSR_AXIS_COUNT))
- {
- result = PLSR_RESULT_INVALID_ARGUMENT;
- }
- else
- {
- command.sequence = sequence;
- command.opcode = (PLSR_COMMAND_OPCODE)request[2UL];
- command.axis = (uint8_t)request[3UL];
- command.argument = (int64_t)PlsrModbusGetU64(request, 4UL);
- result = PlsrPostCommand(&command);
- }
- PlsrModbusPublishCommandResponse(sequence,
- request[2UL],
- request[3UL],
- result);
- }
-
- static void PlsrModbusPublishAxisStatus(uint8_t axis)
- {
- PLSR_STATUS status;
- uint16_t *words = PlsrModbusStatusWords[axis];
- uint32_t flags = 0UL;
- uint32_t generation;
-
- if (PlsrGetStatus(axis, &status) != PLSR_RESULT_OK)
- {
- return;
- }
- generation = PlsrModbusStatusGeneration[axis] + 2UL;
- if (generation == 0UL)
- {
- generation = 2UL;
- }
- PlsrModbusStatusGeneration[axis] = generation;
- (void)memset(words, 0, sizeof(PlsrModbusStatusWords[axis]));
- if (status.busy != 0U) flags |= (1UL << 0U);
- if (status.pulseActive != 0U) flags |= (1UL << 1U);
- if (status.done != 0U) flags |= (1UL << 2U);
- if (status.wait != 0U) flags |= (1UL << 3U);
- if (status.directionPositive != 0U) flags |= (1UL << 4U);
- if (status.positionValid != 0U) flags |= (1UL << 5U);
- if (status.jobValid != 0U) flags |= (1UL << 6U);
- if (status.speedClamped != 0U) flags |= (1UL << 7U);
- if (status.positionOverflow != 0U) flags |= (1UL << 8U);
- if (status.positiveLimitActive != 0U) flags |= (1UL << 9U);
- if (status.negativeLimitActive != 0U) flags |= (1UL << 10U);
- if (status.emergencyLatched != 0U) flags |= (1UL << 11U);
- if (status.backlashActive != 0U) flags |= (1UL << 12U);
-
- PlsrModbusPutU32(words, 0UL, generation);
- words[2UL] = (uint16_t)status.state;
- PlsrModbusPutU32(words, 3UL, flags);
- words[5UL] = (uint16_t)status.outputMode;
- words[6UL] = (uint16_t)status.error;
- words[7UL] = (uint16_t)status.stopReason;
- words[8UL] = (uint16_t)status.lastCommandResult;
- words[9UL] = status.s2Set;
- PlsrModbusPutU32(words, 10UL, status.lastCommandSequence);
- PlsrModbusPutU32(words, 12UL, status.illegalTransitionCount);
- PlsrModbusPutU32(words, 14UL, status.pendingEvents);
- PlsrModbusPutU64(words, 16UL, (uint64_t)status.logicalPosition);
- PlsrModbusPutU64(words, 20UL, (uint64_t)status.taskPulses);
- PlsrModbusPutU64(words, 24UL, (uint64_t)status.totalPulses);
- PlsrModbusPutU64(words, 28UL, status.physicalPulses);
- words[32UL] = status.segmentCount;
- words[33UL] = status.startSegment;
- words[34UL] = status.currentSegment;
- words[35UL] = status.directionPoint;
- words[36UL] = status.highResourceMask;
- PlsrModbusPutU32(words, 38UL, status.currentFrequencyHz);
- PlsrModbusPutU32(words, 40UL, status.targetFrequencyHz);
- PlsrModbusPutU32(words, 42UL, status.liveFrequencyRejectCount);
- words[44UL] = (uint16_t)status.lastLiveFrequencyResult;
- PlsrModbusPutU32(words, 46UL, generation);
- (void)ModbusDataWriteWords(
- MODBUS_DATA_DEVICE_D,
- (uint32_t)PlsrModbusBaseAddress + PLSR_MODBUS_AXIS_STATUS_OFFSET
- + (uint32_t)axis * PLSR_MODBUS_AXIS_STATUS_WORDS,
- words,
- PLSR_MODBUS_AXIS_STATUS_WORDS);
- }
-
- PLSR_RESULT PlsrModbusControlInit(uint16_t baseAddress)
- {
- uint16_t header[8] = {0U};
-
- if (ModbusDataValidateWords(MODBUS_DATA_DEVICE_D,
- baseAddress,
- PLSR_MODBUS_WINDOW_WORDS) == 0U)
- {
- return PLSR_RESULT_DATA_ACCESS;
- }
- PlsrModbusBaseAddress = baseAddress;
- PlsrModbusEnabled = 0U;
- PlsrModbusLastCallRequestSequence = 0UL;
- PlsrModbusLastCommandRequestSequence = 0UL;
- (void)memset(PlsrModbusCommitted, 0, sizeof(PlsrModbusCommitted));
- (void)memset(PlsrModbusStatusGeneration,
- 0,
- sizeof(PlsrModbusStatusGeneration));
- if (ModbusDataWriteWords(MODBUS_DATA_DEVICE_D,
- baseAddress,
- PlsrModbusZeroWindow,
- PLSR_MODBUS_WINDOW_WORDS) == 0U)
- {
- return PLSR_RESULT_DATA_ACCESS;
- }
- header[0UL] = PLSR_MODBUS_MAGIC_LOW;
- header[1UL] = PLSR_MODBUS_MAGIC_HIGH;
- header[2UL] = PLSR_MODBUS_PROTOCOL_VERSION;
- header[3UL] = (uint16_t)PLSR_MODBUS_WINDOW_WORDS;
- header[4UL] = PLSR_MODBUS_CAPABILITIES;
- if (ModbusDataWriteWords(MODBUS_DATA_DEVICE_D,
- baseAddress,
- header,
- 8UL) == 0U)
- {
- return PLSR_RESULT_DATA_ACCESS;
- }
- PlsrModbusEnabled = 1U;
- PlsrModbusControlPoll();
- return PLSR_RESULT_OK;
- }
-
- void PlsrModbusControlPoll(void)
- {
- uint8_t axis;
-
- if (PlsrModbusEnabled == 0U)
- {
- return;
- }
- PlsrModbusHandleCallRequest();
- PlsrModbusHandleCommandRequest();
- for (axis = 0U; axis < PLSR_AXIS_COUNT; axis++)
- {
- PlsrModbusPublishAxisStatus(axis);
- }
- }
-
- uint8_t PlsrModbusControlIsEnabled(void)
- {
- return PlsrModbusEnabled;
- }
-
- uint16_t PlsrModbusControlGetBaseAddress(void)
- {
- return PlsrModbusBaseAddress;
- }
|