Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "open-plc-editor",
"description": "OpenPLC Editor - IDE capable of creating programs for the OpenPLC Runtime",
"version": "4.2.10",
"version": "4.2.9",
"license": "GPL-3.0",
"author": {
"name": "Autonomy Logic"
Expand Down
2 changes: 1 addition & 1 deletion src/frontend/data/constants/app-version.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
/**
* Single source of truth for the OpenPLC application version, SHARED
* byte-for-byte between openplc-web and openplc-editor.
Expand All @@ -18,4 +18,4 @@
* compares a per-deploy `BUILD_ID` (git commit SHA), not this version, so a
* stale tab is detected on every deploy even without a version bump.
*/
export const APP_VERSION = '4.2.10'
export const APP_VERSION = '4.2.9'
22 changes: 22 additions & 0 deletions src/frontend/store/__tests__/project-validation-variables.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -516,6 +516,28 @@ describe('updateVariableValidation', () => {
},
)

it.each([
['BYTE', '%IB0'],
['BYTE', '%QB1'],
['BYTE', '%MB2'],
['SINT', '%IB3'],
['USINT', '%MB4'],
])('accepts byte locations (I/Q/M) for %s type (%s)', (type, location) => {
const v = makeVariable('Test', type, '')
const result = updateVariableValidation([], { location }, v)
expect(result.ok).toBe(true)
})

it.each([
['BYTE', '%IX0.0'], // bit location, wrong width for a byte type
['SINT', '%IW0'], // word location, wrong width
['BOOL', '%IB0'], // byte location, wrong width for a bit type
])('rejects a cross-width location for %s (%s)', (type, location) => {
const v = makeVariable('Test', type, '')
const result = updateVariableValidation([], { location }, v)
expect(result.ok).toBe(false)
})

it('returns ok: true when location is valid for WORD type', () => {
const wordVar = makeVariable('Test', 'WORD', '')
const result = updateVariableValidation([], { location: '%QW0' }, wordVar)
Expand Down
9 changes: 9 additions & 0 deletions src/frontend/store/slices/project/validation/variables.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import type { PLCVariable } from '../../../../../middleware/shared/ports/types'
import { DISALLOWED_LOCATION_CLASSES } from '../../../../utils/generate-iec-string-to-variables'
import {
BOOL_LOCATION_REGEX,
BYTE_LOCATION_REGEX,
DWORD_LOCATION_REGEX,
LWORD_LOCATION_REGEX,
PLC_ADDRESS_PREFIX,
Expand Down Expand Up @@ -131,6 +132,10 @@
const boolMatch = BOOL_LOCATION_REGEX.test(variableLocation) && variableLocation.split('.')[1] <= '7'
return boolMatch
}
case 'BYTE':
case 'SINT':
case 'USINT':
return BYTE_LOCATION_REGEX.test(variableLocation)
case 'INT':
case 'UINT':
case 'WORD':
Expand All @@ -154,6 +159,10 @@
switch (variableType.toUpperCase()) {
case 'BOOL':
return 'Valid locations: %QX0.0..7, %IX0.0..7, %MX0.0..7 (change the number to the desired location)'
case 'BYTE':
case 'SINT':
case 'USINT':
return 'Valid locations: %QB0, %IB0, %MB0 (change the number to the desired location)'
case 'INT':
case 'UINT':
case 'WORD':
Expand Down
13 changes: 10 additions & 3 deletions src/frontend/utils/PLC/address-constants/types.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
export const PLC_ADDRESS_PREFIX = {
BOOL_OUTPUT: '%QX',
BOOL_INPUT: '%IX',
BOOL_MEMORY: '%MX',
BYTE_OUTPUT: '%QB',
BYTE_INPUT: '%IB',
BYTE_MEMORY: '%MB',
WORD_OUTPUT: '%QW',
WORD_INPUT: '%IW',
WORD_MEMORY: '%MW',
Expand All @@ -13,10 +16,14 @@
LWORD_MEMORY: '%ML',
} as const

// Accept every valid IEC area prefix — input (I), output (Q) and memory (M).
// `%MX` memory bits are legitimate (e.g. Modbus coils) and were previously
// rejected here, unlike the word-width regexes below which already allow M.
// Each IEC size class accepts all three area prefixes — input (I), output (Q)
// and memory (M) — matching what strucpp and the runtime image tables support:
// X = bit (BOOL), B = byte (BYTE/SINT/USINT), W = word (INT/UINT/WORD),
// D = dword (DINT/UDINT/REAL/DWORD), L = lword (LINT/ULINT/LREAL/LWORD).
// NOTE: %MB (memory byte) is accepted here even though the runtime does not
// yet back it (no byte_memory buffer) — a runtime fix is planned separately.
Comment on lines +19 to +24

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Correct the runtime-support claim in the documentation.

Lines 20 and 23-24 contradict each other: the first says all three areas match runtime support, while the latter says %MB has no runtime byte_memory buffer. Clarify that %MB is intentionally validator-supported but not runtime-backed yet.

Proposed wording
-// and memory (M) — matching what strucpp and the runtime image tables support:
+// and memory (M); strucpp supports all three, but the runtime does not yet
+// provide a byte_memory buffer for %MB:
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Each IEC size class accepts all three area prefixes — input (I), output (Q)
// and memory (M) — matching what strucpp and the runtime image tables support:
// X = bit (BOOL), B = byte (BYTE/SINT/USINT), W = word (INT/UINT/WORD),
// D = dword (DINT/UDINT/REAL/DWORD), L = lword (LINT/ULINT/LREAL/LWORD).
// NOTE: %MB (memory byte) is accepted here even though the runtime does not
// yet back it (no byte_memory buffer) — a runtime fix is planned separately.
// Each IEC size class accepts all three area prefixes — input (I), output (Q)
// and memory (M); strucpp supports all three, but the runtime does not yet
// provide a byte_memory buffer for %MB:
// X = bit (BOOL), B = byte (BYTE/SINT/USINT), W = word (INT/UINT/WORD),
// D = dword (DINT/UDINT/REAL/DWORD), L = lword (LINT/ULINT/LREAL/LWORD).
// NOTE: %MB (memory byte) is accepted here even though the runtime does not
// yet back it (no byte_memory buffer) — a runtime fix is planned separately.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/frontend/utils/PLC/address-constants/types.ts` around lines 19 - 24,
Update the comments above the IEC size-class definitions to distinguish
validator support from runtime backing: state that the prefixes are accepted by
validation, while clarifying that %MB is intentionally accepted but not
currently supported by the runtime because byte_memory is absent. Remove the
contradictory claim that all three areas match runtime support.

export const BOOL_LOCATION_REGEX = /^%[QIM]X\d+\.\d$/
export const BYTE_LOCATION_REGEX = /^%[QIM]B\d+$/
export const WORD_LOCATION_REGEX = /^%[QIM]W\d+$/
export const DWORD_LOCATION_REGEX = /^%[QIM]D\d+$/
export const LWORD_LOCATION_REGEX = /^%[QIM]L\d+$/
Loading