(undefined)
// Sync state from config
useEffect(() => {
@@ -500,17 +501,20 @@ const S7CommServerEditor = () => {
setIsModalOpen(true)
}, [])
- const handleEditDataBlock = useCallback((dataBlock: S7CommDataBlock) => {
+ const handleEditDataBlock = useCallback((dataBlock: S7CommUIDataBlock) => {
setEditingBlock(dataBlock)
setIsModalOpen(true)
}, [])
const handleSaveDataBlock = useCallback(
- (dataBlock: S7CommDataBlock) => {
+ (dataBlock: S7CommUIDataBlock) => {
+ // Cast UI data block to middleware type — the extra UI fields (startBuffer, bitAddressing) are ignored by the store
+ const middlewareBlock =
+ dataBlock as unknown as import('../../../../../../../middleware/shared/ports/types').S7CommDataBlock
if (editingBlock) {
- projectActions.updateS7CommDataBlock(serverName, editingBlock.dbNumber, dataBlock)
+ projectActions.updateS7CommDataBlock(serverName, editingBlock.dbNumber, middlewareBlock)
} else {
- projectActions.addS7CommDataBlock(serverName, dataBlock)
+ projectActions.addS7CommDataBlock(serverName, middlewareBlock)
}
handleFileAndWorkspaceSavedState(serverName)
},
@@ -728,12 +732,14 @@ const S7CommServerEditor = () => {
{db.sizeBytes} bytes
|
- {BUFFER_TYPE_OPTIONS.find((o) => o.value === db.mapping.type)?.label || db.mapping.type}
+ {BUFFER_TYPE_OPTIONS.find((o) => o.value === db.mapping.type)?.label ||
+ db.mapping.type ||
+ 'Unknown'}
|
-
+
Dimensions
diff --git a/src2/frontend/components/_molecules/data-types/array/table/editable-cell.tsx b/src/frontend/components/_molecules/data-types/array/table/editable-cell.tsx
similarity index 100%
rename from src2/frontend/components/_molecules/data-types/array/table/editable-cell.tsx
rename to src/frontend/components/_molecules/data-types/array/table/editable-cell.tsx
index 3fbbf703f..e0e2789ff 100644
--- a/src2/frontend/components/_molecules/data-types/array/table/editable-cell.tsx
+++ b/src/frontend/components/_molecules/data-types/array/table/editable-cell.tsx
@@ -1,8 +1,8 @@
import { CellContext } from '@tanstack/react-table'
import { useEffect, useRef, useState } from 'react'
-import { InputWithRef } from '../../../../_atoms/input'
import { cn } from '../../../../../utils/cn'
+import { InputWithRef } from '../../../../_atoms/input'
type EditableCellProps = CellContext<{ dimension: string }, unknown> & {
id: string
diff --git a/src2/frontend/components/_molecules/data-types/array/table/index.tsx b/src/frontend/components/_molecules/data-types/array/table/index.tsx
similarity index 100%
rename from src2/frontend/components/_molecules/data-types/array/table/index.tsx
rename to src/frontend/components/_molecules/data-types/array/table/index.tsx
index 19f942a92..ed76f2ce4 100644
--- a/src2/frontend/components/_molecules/data-types/array/table/index.tsx
+++ b/src/frontend/components/_molecules/data-types/array/table/index.tsx
@@ -1,13 +1,13 @@
import { createColumnHelper, getCoreRowModel, useReactTable } from '@tanstack/react-table'
import React, { useEffect, useRef } from 'react'
-import { GenericDataTypeTable } from '../../../../_atoms/generic-data-type-table'
-import { toast } from '../../../../_features/[app]/toast/use-toast'
+import type { PLCDataType } from '../../../../../../middleware/shared/ports/types'
import { usePouSnapshot } from '../../../../../hooks/use-pou-snapshot'
import { useOpenPLCStore } from '../../../../../store'
import { arrayValidation } from '../../../../../store/slices/project/validation/variables'
-import type { PLCDataType } from '../../../../../../middleware/shared/ports/types'
import { cn } from '../../../../../utils/cn'
+import { GenericDataTypeTable } from '../../../../_atoms/generic-data-type-table'
+import { toast } from '../../../../_features/[app]/toast/use-toast'
import { DimensionCell } from './editable-cell'
type PLCArrayDatatype = Extract
diff --git a/src2/frontend/components/_molecules/data-types/enumerated/index.tsx b/src/frontend/components/_molecules/data-types/enumerated/index.tsx
similarity index 98%
rename from src2/frontend/components/_molecules/data-types/enumerated/index.tsx
rename to src/frontend/components/_molecules/data-types/enumerated/index.tsx
index 5a825dfb9..a407ea143 100644
--- a/src2/frontend/components/_molecules/data-types/enumerated/index.tsx
+++ b/src/frontend/components/_molecules/data-types/enumerated/index.tsx
@@ -1,13 +1,13 @@
import { ComponentPropsWithoutRef, useEffect, useState } from 'react'
+import type { PLCDataType } from '../../../../../middleware/shared/ports/types'
import { MinusIcon } from '../../../../assets/icons/interface/Minus'
import { PlusIcon } from '../../../../assets/icons/interface/Plus'
import { StickArrowIcon } from '../../../../assets/icons/interface/StickArrow'
-import { Select, SelectContent, SelectItem, SelectTrigger } from '../../../_atoms/select'
-import TableActions from '../../../_atoms/table-actions'
import { usePouSnapshot } from '../../../../hooks/use-pou-snapshot'
import { useOpenPLCStore } from '../../../../store'
-import type { PLCDataType } from '../../../../../middleware/shared/ports/types'
+import { Select, SelectContent, SelectItem, SelectTrigger } from '../../../_atoms/select'
+import TableActions from '../../../_atoms/table-actions'
import { EnumeratedTable } from './table'
type PLCEnumeratedDatatype = Extract
@@ -136,12 +136,12 @@ const EnumeratorDataType = ({ data, ...rest }: EnumDatatypeProps) => {
className='flex h-full w-full flex-1 flex-row gap-4 overflow-hidden bg-transparent'
{...rest}
>
-
+
Description
diff --git a/src2/frontend/components/_molecules/data-types/enumerated/table/editable-cell.tsx b/src/frontend/components/_molecules/data-types/enumerated/table/editable-cell.tsx
similarity index 100%
rename from src2/frontend/components/_molecules/data-types/enumerated/table/editable-cell.tsx
rename to src/frontend/components/_molecules/data-types/enumerated/table/editable-cell.tsx
index c55268d53..584477ac8 100644
--- a/src2/frontend/components/_molecules/data-types/enumerated/table/editable-cell.tsx
+++ b/src/frontend/components/_molecules/data-types/enumerated/table/editable-cell.tsx
@@ -1,8 +1,8 @@
import { CellContext } from '@tanstack/react-table'
import { useEffect, useRef, useState } from 'react'
-import { InputWithRef } from '../../../../_atoms/input'
import { cn } from '../../../../../utils/cn'
+import { InputWithRef } from '../../../../_atoms/input'
type EditableCellProps = CellContext<{ description: string }, unknown> & {
editable?: boolean
diff --git a/src2/frontend/components/_molecules/data-types/enumerated/table/index.tsx b/src/frontend/components/_molecules/data-types/enumerated/table/index.tsx
similarity index 99%
rename from src2/frontend/components/_molecules/data-types/enumerated/table/index.tsx
rename to src/frontend/components/_molecules/data-types/enumerated/table/index.tsx
index c258c84d7..b647c0184 100644
--- a/src2/frontend/components/_molecules/data-types/enumerated/table/index.tsx
+++ b/src/frontend/components/_molecules/data-types/enumerated/table/index.tsx
@@ -1,13 +1,13 @@
import { createColumnHelper, getCoreRowModel, useReactTable } from '@tanstack/react-table'
import React, { useEffect, useRef } from 'react'
-import { GenericDataTypeTable } from '../../../../_atoms/generic-data-type-table'
-import { toast } from '../../../../_features/[app]/toast/use-toast'
+import type { PLCDataType } from '../../../../../../middleware/shared/ports/types'
import { usePouSnapshot } from '../../../../../hooks/use-pou-snapshot'
import { useOpenPLCStore } from '../../../../../store'
import { enumeratedValidation } from '../../../../../store/slices/project/validation/variables'
-import type { PLCDataType } from '../../../../../../middleware/shared/ports/types'
import { cn } from '../../../../../utils/cn'
+import { GenericDataTypeTable } from '../../../../_atoms/generic-data-type-table'
+import { toast } from '../../../../_features/[app]/toast/use-toast'
import { DescriptionCell } from './editable-cell'
type PLCEnumeratedDatatype = Extract
@@ -58,7 +58,6 @@ const EnumeratedTable = ({
),
}),
],
- // eslint-disable-next-line react-hooks/exhaustive-deps
[values, name, selectedRow, initialValue],
)
diff --git a/src2/frontend/components/_molecules/data-types/structure/index.tsx b/src/frontend/components/_molecules/data-types/structure/index.tsx
similarity index 98%
rename from src2/frontend/components/_molecules/data-types/structure/index.tsx
rename to src/frontend/components/_molecules/data-types/structure/index.tsx
index c952260fd..29ff54123 100644
--- a/src2/frontend/components/_molecules/data-types/structure/index.tsx
+++ b/src/frontend/components/_molecules/data-types/structure/index.tsx
@@ -1,14 +1,14 @@
import { useEffect, useState } from 'react'
+import type { PLCDataType, PLCStructureVariable } from '../../../../../middleware/shared/ports/types'
import { MinusIcon } from '../../../../assets/icons/interface/Minus'
import { PlusIcon } from '../../../../assets/icons/interface/Plus'
import { StickArrowIcon } from '../../../../assets/icons/interface/StickArrow'
-import { toast } from '../../../_features/[app]/toast/use-toast'
-import TableActions from '../../../_atoms/table-actions'
import { usePouSnapshot } from '../../../../hooks/use-pou-snapshot'
import { useOpenPLCStore } from '../../../../store'
import type { StructureTableType } from '../../../../store/slices/editor/types'
-import type { PLCDataType, PLCStructureVariable } from '../../../../../middleware/shared/ports/types'
+import TableActions from '../../../_atoms/table-actions'
+import { toast } from '../../../_features/[app]/toast/use-toast'
import { StructureTable } from './table'
const StructureDataType = () => {
@@ -50,7 +50,6 @@ const StructureDataType = () => {
const { description, selectedRow } = editor.structure
setEditorStructure({ description: description, selectedRow: selectedRow })
}
- // eslint-disable-next-line react-hooks/exhaustive-deps
}, [editor])
const handleRowClick = (row: HTMLTableRowElement) => {
@@ -106,7 +105,7 @@ const StructureDataType = () => {
...structureVariables,
{
name: getNextVariableName(baseName),
- type: { definition: 'base-type', value: 'dint' },
+ type: { definition: 'base-type', value: 'DINT' },
initialValue: { simpleValue: { value: '' } },
},
],
diff --git a/src2/frontend/components/_molecules/data-types/structure/table/editable-cell.tsx b/src/frontend/components/_molecules/data-types/structure/table/editable-cell.tsx
similarity index 93%
rename from src2/frontend/components/_molecules/data-types/structure/table/editable-cell.tsx
rename to src/frontend/components/_molecules/data-types/structure/table/editable-cell.tsx
index 05c452135..459bb2482 100644
--- a/src2/frontend/components/_molecules/data-types/structure/table/editable-cell.tsx
+++ b/src/frontend/components/_molecules/data-types/structure/table/editable-cell.tsx
@@ -1,11 +1,11 @@
import type { CellContext, RowData } from '@tanstack/react-table'
import { useEffect, useState } from 'react'
-import { InputWithRef } from '../../../../_atoms/input'
-import { useToast } from '../../../../_features/[app]/toast/use-toast'
-import type { ProjectResponse } from '../../../../../store/slices/project/types'
import type { PLCStructureVariable } from '../../../../../../middleware/shared/ports/types'
+import type { ProjectResponse } from '../../../../../store/slices/project/types'
import { cn } from '../../../../../utils/cn'
+import { InputWithRef } from '../../../../_atoms/input'
+import { useToast } from '../../../../_features/[app]/toast/use-toast'
declare module '@tanstack/react-table' {
// This is a helper interface that adds the `updateData` property to the table meta.
@@ -89,15 +89,8 @@ const EditableInitialValueCell = ({
return (
- setCellValue((prev) => ({
- ...prev,
- simpleValue: {
- value: e.target.value,
- },
- }))
- }
+ value={cellValue ?? ''}
+ onChange={(e) => setCellValue(e.target.value)}
onBlur={onBlur}
className={cn(
`flex w-full flex-1 bg-transparent p-2 text-center outline-none ${!editable ? 'pointer-events-none' : ''}`,
diff --git a/src2/frontend/components/_molecules/data-types/structure/table/elements/array-modal.tsx b/src/frontend/components/_molecules/data-types/structure/table/elements/array-modal.tsx
similarity index 93%
rename from src2/frontend/components/_molecules/data-types/structure/table/elements/array-modal.tsx
rename to src/frontend/components/_molecules/data-types/structure/table/elements/array-modal.tsx
index 40a04779f..20f99cb96 100644
--- a/src2/frontend/components/_molecules/data-types/structure/table/elements/array-modal.tsx
+++ b/src/frontend/components/_molecules/data-types/structure/table/elements/array-modal.tsx
@@ -1,12 +1,12 @@
+import { baseTypeSchema } from '@root/middleware/shared/ports/plc-schemas'
+import type { PLCDataType, PLCStructureVariable } from '@root/middleware/shared/ports/types'
import { useEffect, useState } from 'react'
import type { z } from 'zod'
-import { DimensionsModal } from '../../../../../_atoms/dimensions-modal'
-import { toast } from '../../../../../_features/[app]/toast/use-toast'
import { useOpenPLCStore } from '../../../../../../store'
import { arrayValidation } from '../../../../../../store/slices/project/validation/variables'
-import { baseTypeSchema } from '../../../../../../../middleware/shared/ports/plc-schemas'
-import type { PLCStructureVariable } from '../../../../../../../middleware/shared/ports/types'
+import { DimensionsModal } from '../../../../../_atoms/dimensions-modal'
+import { toast } from '../../../../../_features/[app]/toast/use-toast'
type BaseType = z.infer
@@ -78,7 +78,7 @@ export const ArrayModal = ({
const variable = structure.variable.find((variable) => variable.name === variableName)
if (!variable) return
- if (variable.type.definition === 'array') {
+ if (variable.type.definition === 'array' && variable.type.data) {
setDimensions(variable.type.data.dimensions.map((dimension) => dimension.dimension))
setTypeValue(variable.type.data.baseType.value)
}
@@ -109,7 +109,7 @@ export const ArrayModal = ({
setSelectedInput((index + 1).toString())
}
- const handleUpdateType = (value: BaseType) => {
+ const handleUpdateType = (value: string) => {
setTypeValue(value)
}
@@ -155,7 +155,6 @@ export const ArrayModal = ({
return
}
- // @ts-expect-error - This is a valid operation. This is being fixed.
const updatedVariables: PLCStructureVariable[] = structure.variable.map((variable) => {
if (variable.name === variableName) {
const isBaseType = baseTypes.includes(typeValue as BaseType)
@@ -173,7 +172,7 @@ export const ArrayModal = ({
dimensions: dimensionToSave.map((value) => ({ dimension: value })),
},
},
- initialValue: variable.initialValue?.simpleValue?.value === '' ? undefined : variable.initialValue,
+ initialValue: (variable.initialValue ?? '') === '' ? undefined : variable.initialValue,
}
}
return variable
@@ -182,7 +181,7 @@ export const ArrayModal = ({
updateDatatype(name, {
...structure,
variable: updatedVariables,
- })
+ } as unknown as PLCDataType)
setArrayModalIsOpen(false)
closeContainer()
diff --git a/src2/frontend/components/_molecules/data-types/structure/table/index.tsx b/src/frontend/components/_molecules/data-types/structure/table/index.tsx
similarity index 95%
rename from src2/frontend/components/_molecules/data-types/structure/table/index.tsx
rename to src/frontend/components/_molecules/data-types/structure/table/index.tsx
index 4a38e4207..02d937f46 100644
--- a/src2/frontend/components/_molecules/data-types/structure/table/index.tsx
+++ b/src/frontend/components/_molecules/data-types/structure/table/index.tsx
@@ -1,14 +1,12 @@
import { createColumnHelper } from '@tanstack/react-table'
-import { GenericTable } from '../../../../_atoms/generic-table'
+import type { PLCDataType, PLCStructureVariable } from '../../../../../../middleware/shared/ports/types'
import { usePouSnapshot } from '../../../../../hooks/use-pou-snapshot'
import { useOpenPLCStore } from '../../../../../store'
-import type { PLCDataType, PLCStructureVariable } from '../../../../../../middleware/shared/ports/types'
+import { GenericTable } from '../../../../_atoms/generic-table'
import { EditableInitialValueCell, EditableNameCell } from './editable-cell'
import { SelectableTypeCell } from './selectable-cell'
-type PLCStructureDatatype = Extract
-
const columnHelper = createColumnHelper()
const columns = [
@@ -41,7 +39,7 @@ const columns = [
]
type PLCStructureTableProps = {
- tableData: PLCStructureDatatype['variable']
+ tableData: PLCStructureVariable[]
selectedRow: number
handleRowClick: (row: HTMLTableRowElement) => void
}
diff --git a/src2/frontend/components/_molecules/data-types/structure/table/selectable-cell.tsx b/src/frontend/components/_molecules/data-types/structure/table/selectable-cell.tsx
similarity index 100%
rename from src2/frontend/components/_molecules/data-types/structure/table/selectable-cell.tsx
rename to src/frontend/components/_molecules/data-types/structure/table/selectable-cell.tsx
index 5b4efd6ce..4820548b5 100644
--- a/src2/frontend/components/_molecules/data-types/structure/table/selectable-cell.tsx
+++ b/src/frontend/components/_molecules/data-types/structure/table/selectable-cell.tsx
@@ -3,12 +3,12 @@ import type { CellContext } from '@tanstack/react-table'
import _ from 'lodash'
import { useEffect, useState } from 'react'
-import { ArrowIcon } from '../../../../../assets/icons/interface/Arrow'
-import { InputWithRef } from '../../../../_atoms/input'
-import { useOpenPLCStore } from '../../../../../store'
import { baseTypeSchema } from '../../../../../../middleware/shared/ports/plc-schemas'
import type { PLCStructureVariable } from '../../../../../../middleware/shared/ports/types'
+import { ArrowIcon } from '../../../../../assets/icons/interface/Arrow'
+import { useOpenPLCStore } from '../../../../../store'
import { cn } from '../../../../../utils/cn'
+import { InputWithRef } from '../../../../_atoms/input'
import { ArrayModal } from './elements/array-modal'
type ISelectableCellProps = CellContext & { editable?: boolean }
diff --git a/src2/frontend/components/_molecules/file/file-label.tsx b/src/frontend/components/_molecules/file/file-label.tsx
similarity index 100%
rename from src2/frontend/components/_molecules/file/file-label.tsx
rename to src/frontend/components/_molecules/file/file-label.tsx
diff --git a/src2/frontend/components/_molecules/file/file-root.tsx b/src/frontend/components/_molecules/file/file-root.tsx
similarity index 99%
rename from src2/frontend/components/_molecules/file/file-root.tsx
rename to src/frontend/components/_molecules/file/file-root.tsx
index 949713ce1..04dddb9b4 100644
--- a/src2/frontend/components/_molecules/file/file-root.tsx
+++ b/src/frontend/components/_molecules/file/file-root.tsx
@@ -1,6 +1,7 @@
-import { cn } from '../../../utils/cn'
import { HTMLAttributes } from 'react'
+import { cn } from '../../../utils/cn'
+
type FolderRootProps = HTMLAttributes
export default function Root({ ...props }: FolderRootProps) {
diff --git a/src/renderer/components/_molecules/file/file-shape.tsx b/src/frontend/components/_molecules/file/file-shape.tsx
similarity index 100%
rename from src/renderer/components/_molecules/file/file-shape.tsx
rename to src/frontend/components/_molecules/file/file-shape.tsx
diff --git a/src/renderer/components/_molecules/file/index.ts b/src/frontend/components/_molecules/file/index.ts
similarity index 100%
rename from src/renderer/components/_molecules/file/index.ts
rename to src/frontend/components/_molecules/file/index.ts
diff --git a/src2/frontend/components/_molecules/global-variables-table/editable-cell.tsx b/src/frontend/components/_molecules/global-variables-table/editable-cell.tsx
similarity index 98%
rename from src2/frontend/components/_molecules/global-variables-table/editable-cell.tsx
rename to src/frontend/components/_molecules/global-variables-table/editable-cell.tsx
index 1079183b1..b7034bb7f 100644
--- a/src2/frontend/components/_molecules/global-variables-table/editable-cell.tsx
+++ b/src/frontend/components/_molecules/global-variables-table/editable-cell.tsx
@@ -1,22 +1,22 @@
import * as PrimitivePopover from '@radix-ui/react-popover'
+import type { CellContext, RowData } from '@tanstack/react-table'
+import { useCallback, useEffect, useRef, useState } from 'react'
+
+import type { PLCGlobalVariable } from '../../../../middleware/shared/ports/types'
import { pinSelectors, remoteDeviceSelectors } from '../../../hooks/use-store-selectors'
import { useOpenPLCStore } from '../../../store'
import type { ProjectResponse } from '../../../store/slices/project'
+import { cn } from '../../../utils/cn'
+import { isLegalIdentifier, sanitizeVariableInput } from '../../../utils/keywords'
import { buildRemoteDeviceOptionGroups } from '../../../utils/remote-device-options'
import {
findAllReferencesToVariable,
propagateVariableRename,
type ReferenceImpactAnalysis,
} from '../../../utils/variable-references'
-import type { PLCVariable } from '../../../../middleware/shared/ports/types'
-import { cn } from '../../../utils/cn'
-import { isLegalIdentifier, sanitizeVariableInput } from '../../../utils/keywords'
-import type { CellContext, RowData } from '@tanstack/react-table'
-import { useCallback, useEffect, useRef, useState } from 'react'
-
+import { GenericComboboxCell } from '../../_atoms/generic-table-inputs/generic-combobox-cell'
import { HighlightedText } from '../../_atoms/highlighted-text'
import { InputWithRef } from '../../_atoms/input'
-import { GenericComboboxCell } from '../../_atoms/generic-table-inputs/generic-combobox-cell'
import { useToast } from '../../_features/[app]/toast/use-toast'
import { RenameImpactModal } from '../rename-impact-modal'
@@ -28,7 +28,7 @@ declare module '@tanstack/react-table' {
}
}
-type IEditableCellProps = CellContext & { editable?: boolean }
+type IEditableCellProps = CellContext & { editable?: boolean }
const EditableNameCell = ({ getValue, row: { index }, column: { id }, table, editable = true }: IEditableCellProps) => {
const initialValue = getValue()
const { toast } = useToast()
diff --git a/src2/frontend/components/_molecules/global-variables-table/elements/array-modal.tsx b/src/frontend/components/_molecules/global-variables-table/elements/array-modal.tsx
similarity index 92%
rename from src2/frontend/components/_molecules/global-variables-table/elements/array-modal.tsx
rename to src/frontend/components/_molecules/global-variables-table/elements/array-modal.tsx
index 8d2cf99d9..6f95b2c99 100644
--- a/src2/frontend/components/_molecules/global-variables-table/elements/array-modal.tsx
+++ b/src/frontend/components/_molecules/global-variables-table/elements/array-modal.tsx
@@ -1,11 +1,10 @@
-import { DimensionsModal } from '../../../_atoms/dimensions-modal'
-import { toast } from '../../../_features/[app]/toast/use-toast'
-import { useOpenPLCStore } from '../../../../store'
-import { arrayValidation } from '../../../../store/slices/workspace/utils/variables'
-import { baseTypeSchema } from '../../../../../middleware/shared/ports'
import { useEffect, useState } from 'react'
-type BaseType = (typeof baseTypeSchema.options)[number]
+import { baseTypeSchema } from '../../../../../middleware/shared/ports'
+import { useOpenPLCStore } from '../../../../store'
+import { arrayValidation } from '../../../../store/slices/workspace/utils/variables'
+import { DimensionsModal } from '../../../_atoms/dimensions-modal'
+import { toast } from '../../../_features/[app]/toast/use-toast'
type ArrayModalProps = {
variableName: string
@@ -73,9 +72,9 @@ export const GlobalArrayModal = ({
const variable = globalVariables.find((variable) => variable.name === variableName)
if (!variable) return
- if (variable.type.definition === 'array') {
- setDimensions(variable.type.data?.dimensions.map((dimension) => dimension.dimension) ?? [])
- setTypeValue(variable.type.data?.baseType ?? 'dint')
+ if (variable.type.definition === 'array' && variable.type.data) {
+ setDimensions(variable.type.data.dimensions.map((dimension) => dimension.dimension))
+ setTypeValue(variable.type.data.baseType.value ?? 'dint')
} else {
setDimensions([])
setTypeValue('dint')
@@ -111,7 +110,7 @@ export const GlobalArrayModal = ({
setSelectedInput((index + 1).toString())
}
- const handleUpdateType = (value: BaseType) => {
+ const handleUpdateType = (value: string) => {
setTypeValue(value)
}
@@ -155,7 +154,10 @@ export const GlobalArrayModal = ({
definition: 'array',
value: formatArrayName,
data: {
- baseType: isBaseType ? typeValue : typeValue,
+ baseType: {
+ definition: isBaseType ? ('base-type' as const) : ('user-data-type' as const),
+ value: typeValue,
+ },
dimensions: dimensionToSave.map((dimension) => ({ dimension: dimension })),
},
},
diff --git a/src2/frontend/components/_molecules/global-variables-table/index.tsx b/src/frontend/components/_molecules/global-variables-table/index.tsx
similarity index 94%
rename from src2/frontend/components/_molecules/global-variables-table/index.tsx
rename to src/frontend/components/_molecules/global-variables-table/index.tsx
index fa7969c6c..208ff4062 100644
--- a/src2/frontend/components/_molecules/global-variables-table/index.tsx
+++ b/src/frontend/components/_molecules/global-variables-table/index.tsx
@@ -1,6 +1,6 @@
-import type { PLCGlobalVariable } from '../../../../middleware/shared/ports/types'
import { createColumnHelper } from '@tanstack/react-table'
+import type { PLCGlobalVariable } from '../../../../middleware/shared/ports/types'
import { usePouSnapshot } from '../../../hooks/use-pou-snapshot'
import { useOpenPLCStore } from '../../../store'
import { GenericTable } from '../../_atoms/generic-table'
@@ -78,6 +78,7 @@ const GlobalVariablesTable = ({ tableData, selectedRow, handleRowClick }: PLCVar
meta: { name },
},
projectActions: { updateVariable },
+ sharedWorkspaceActions: { handleFileAndWorkspaceSavedState },
} = useOpenPLCStore()
const { captureAndPush } = usePouSnapshot()
@@ -91,6 +92,9 @@ const GlobalVariablesTable = ({ tableData, selectedRow, handleRowClick }: PLCVar
updateData={(rowIndex, columnId, value) => {
captureAndPush(name)
const result = updateVariable({ scope: 'global', rowId: rowIndex, data: { [columnId]: value } })
+ if (result.ok) {
+ handleFileAndWorkspaceSavedState('Resource')
+ }
return result
}}
tableContext='Variables'
diff --git a/src2/frontend/components/_molecules/global-variables-table/selectable-cell.tsx b/src/frontend/components/_molecules/global-variables-table/selectable-cell.tsx
similarity index 98%
rename from src2/frontend/components/_molecules/global-variables-table/selectable-cell.tsx
rename to src/frontend/components/_molecules/global-variables-table/selectable-cell.tsx
index 6b57b76bd..f4aa9592c 100644
--- a/src2/frontend/components/_molecules/global-variables-table/selectable-cell.tsx
+++ b/src/frontend/components/_molecules/global-variables-table/selectable-cell.tsx
@@ -1,22 +1,22 @@
import * as PrimitiveDropdown from '@radix-ui/react-dropdown-menu'
-import { ArrowIcon } from '../../../assets/icons/interface/Arrow'
-import { DebuggerIcon } from '../../../assets/icons/interface/Debugger'
-import { useOpenPLCStore } from '../../../store'
-import { TypeChangeValidationResult, validateTypeChange, } from '../../../store/slices/project/validation/type-change'
-import { propagateVariableTypeChange } from '../../../utils/variable-references'
-import type { PLCGlobalVariable, PLCVariable } from '../../../../middleware/shared/ports/types'
-import { baseTypeSchema } from '../../../../middleware/shared/ports'
-import { cn } from '../../../utils/cn'
import type { CellContext } from '@tanstack/react-table'
import _ from 'lodash'
import { useEffect, useState } from 'react'
+import { baseTypeSchema } from '../../../../middleware/shared/ports'
+import type { PLCGlobalVariable, PLCVariable } from '../../../../middleware/shared/ports/types'
+import { ArrowIcon } from '../../../assets/icons/interface/Arrow'
+import { DebuggerIcon } from '../../../assets/icons/interface/Debugger'
+import { useOpenPLCStore } from '../../../store'
+import { TypeChangeValidationResult, validateTypeChange } from '../../../store/slices/project/validation/type-change'
+import { cn } from '../../../utils/cn'
+import { propagateVariableTypeChange } from '../../../utils/variable-references'
import { InputWithRef } from '../../_atoms/input'
import { Select, SelectContent, SelectItem, SelectTrigger } from '../../_atoms/select'
import { TypeChangeModal } from '../type-change-modal'
import { GlobalArrayModal } from './elements/array-modal'
-type ISelectableCellProps = CellContext & { editable?: boolean }
+type ISelectableCellProps = CellContext & { editable?: boolean }
const createVariableType = (
definition: PLCVariable['type']['definition'],
diff --git a/src/renderer/components/_molecules/graphical-editor/fbd/fbd-utils/edges.ts b/src/frontend/components/_molecules/graphical-editor/fbd/fbd-utils/edges.ts
similarity index 100%
rename from src/renderer/components/_molecules/graphical-editor/fbd/fbd-utils/edges.ts
rename to src/frontend/components/_molecules/graphical-editor/fbd/fbd-utils/edges.ts
diff --git a/src2/frontend/components/_molecules/graphical-editor/fbd/fbd-utils/nodes.ts b/src/frontend/components/_molecules/graphical-editor/fbd/fbd-utils/nodes.ts
similarity index 100%
rename from src2/frontend/components/_molecules/graphical-editor/fbd/fbd-utils/nodes.ts
rename to src/frontend/components/_molecules/graphical-editor/fbd/fbd-utils/nodes.ts
diff --git a/src2/frontend/components/_molecules/graphical-editor/fbd/fbd-utils/useCopyPaste.ts b/src/frontend/components/_molecules/graphical-editor/fbd/fbd-utils/useCopyPaste.ts
similarity index 99%
rename from src2/frontend/components/_molecules/graphical-editor/fbd/fbd-utils/useCopyPaste.ts
rename to src/frontend/components/_molecules/graphical-editor/fbd/fbd-utils/useCopyPaste.ts
index fd9000870..ec4f09af4 100644
--- a/src2/frontend/components/_molecules/graphical-editor/fbd/fbd-utils/useCopyPaste.ts
+++ b/src/frontend/components/_molecules/graphical-editor/fbd/fbd-utils/useCopyPaste.ts
@@ -1,11 +1,12 @@
-import { toast } from '../../../../_features/[app]/toast/use-toast'
+import { Edge, Node, ReactFlowInstance, XYPosition } from '@xyflow/react'
+import { useCallback, useEffect } from 'react'
+
import { useOpenPLCStore } from '../../../../../store'
+import { ClipboardType } from '../../../../../store/slices/clipboard'
import type { FBDRungState } from '../../../../../store/slices/fbd'
import { pasteNodesAtFBD } from '../../../../../store/slices/fbd/utils'
import { EdgeType, NodeType } from '../../../../../store/slices/react-flow'
-import { ClipboardType } from '../../../../../store/slices/clipboard'
-import { Edge, Node, ReactFlowInstance, XYPosition } from '@xyflow/react'
-import { useCallback, useEffect } from 'react'
+import { toast } from '../../../../_features/[app]/toast/use-toast'
export const useFBDClipboard = ({
mousePosition,
diff --git a/src2/frontend/components/_molecules/graphical-editor/fbd/index.tsx b/src/frontend/components/_molecules/graphical-editor/fbd/index.tsx
similarity index 92%
rename from src2/frontend/components/_molecules/graphical-editor/fbd/index.tsx
rename to src/frontend/components/_molecules/graphical-editor/fbd/index.tsx
index c37754221..cdac66b73 100644
--- a/src2/frontend/components/_molecules/graphical-editor/fbd/index.tsx
+++ b/src/frontend/components/_molecules/graphical-editor/fbd/index.tsx
@@ -1,16 +1,3 @@
-import { CustomFbdNodeTypes, customNodeTypes } from '../../../_atoms/graphical-editor/fbd'
-import { BasicNodeData, BlockNode } from '../../../_atoms/graphical-editor/fbd/utils/types'
-import { getVariableRestrictionType } from '../../../_atoms/graphical-editor/utils'
-import { ReactFlowPanel } from '../../../_atoms/react-flow'
-import { toast } from '../../../_features/[app]/toast/use-toast'
-import BlockElement from '../../../_features/[workspace]/editor/graphical/elements/fbd/block'
-import { useDebugCompositeKey } from '../../../../hooks/use-debug-composite-key'
-import { usePouSnapshot } from '../../../../hooks/use-pou-snapshot'
-import { openPLCStoreBase, useOpenPLCStore } from '../../../../store'
-import type { FBDRungState } from '../../../../store/slices/fbd'
-import { getFunctionBlockVariablesToCleanup } from '../../../../utils/graphical/get-function-block-variables-to-cleanup'
-import { isFbdBlockDrag, getFbdBlockType } from '../../../../utils/graphical/drag-detection'
-import { newGraphicalEditorNodeID } from '../../../../utils/new-graphical-editor-node-id'
import {
addEdge,
applyEdgeChanges,
@@ -28,6 +15,19 @@ import {
import { debounce, isEqual } from 'lodash'
import { DragEventHandler, useCallback, useEffect, useMemo, useRef, useState } from 'react'
+import { useDebugCompositeKey } from '../../../../hooks/use-debug-composite-key'
+import { usePouSnapshot } from '../../../../hooks/use-pou-snapshot'
+import { openPLCStoreBase, useOpenPLCStore } from '../../../../store'
+import type { FBDRungState } from '../../../../store/slices/fbd'
+import { getFbdBlockType, isFbdBlockDrag } from '../../../../utils/graphical/drag-detection'
+import { getFunctionBlockVariablesToCleanup } from '../../../../utils/graphical/get-function-block-variables-to-cleanup'
+import { newGraphicalEditorNodeID } from '../../../../utils/new-graphical-editor-node-id'
+import { CustomFbdNodeTypes, customNodeTypes } from '../../../_atoms/graphical-editor/fbd'
+import { BlockNode } from '../../../_atoms/graphical-editor/fbd/utils/types'
+import { getVariableRestrictionType } from '../../../_atoms/graphical-editor/utils'
+import { ReactFlowPanel } from '../../../_atoms/react-flow'
+import { toast } from '../../../_features/[app]/toast/use-toast'
+import BlockElement from '../../../_features/[workspace]/editor/graphical/elements/fbd/block'
import { buildGenericNode } from './fbd-utils/nodes'
import { useFBDClipboard } from './fbd-utils/useCopyPaste'
@@ -54,7 +54,7 @@ export const FBDBody = ({ rung, nodeDivergences = [], isDebuggerActive = false }
const { captureAndPush } = usePouSnapshot()
const { pous } = project.data
- const pouRef = pous.find((pou) => pou.data.name === editor.meta.name)
+ const pouRef = pous.find((pou) => pou.name === editor.meta.name)
const getCompositeKey = useDebugCompositeKey()
const [rungLocal, setRungLocal] = useState(rung)
const [dragging, setDragging] = useState(false)
@@ -102,7 +102,9 @@ export const FBDBody = ({ rung, nodeDivergences = [], isDebuggerActive = false }
if (!variableName) return undefined
if (!pouRef) return undefined
- const variable = pouRef.data.variables.find((v) => v.name.toLowerCase() === variableName.toLowerCase())
+ const variable = (pouRef.interface?.variables ?? []).find(
+ (v) => v.name.toLowerCase() === variableName.toLowerCase(),
+ )
if (!variable || variable.type.value.toUpperCase() !== 'BOOL') return undefined
const compositeKey = getCompositeKey(variableName)
@@ -125,8 +127,8 @@ export const FBDBody = ({ rung, nodeDivergences = [], isDebuggerActive = false }
}
if (!sourceHandle) return undefined
- if (pouRef?.type !== 'function-block') {
- const instances = project.data.configuration.resource.instances
+ if (pouRef?.pouType !== 'function-block') {
+ const instances = project.data.configurations.resource.instances
const programInstance = instances.find((inst: { program: string }) => inst.program === editor.meta.name)
if (!programInstance) return undefined
}
@@ -228,7 +230,6 @@ export const FBDBody = ({ rung, nodeDivergences = [], isDebuggerActive = false }
return edge
})
- // eslint-disable-next-line react-hooks/exhaustive-deps
}, [
rungLocal.edges,
rungLocal.nodes,
@@ -236,8 +237,8 @@ export const FBDBody = ({ rung, nodeDivergences = [], isDebuggerActive = false }
debugVariableValues,
debugForcedVariables,
editor.meta.name,
- pouRef?.data.variables,
- project.data.configuration.resource.instances,
+ pouRef?.interface?.variables,
+ project.data.configurations.resource.instances,
])
const styledNodes = useMemo(() => {
@@ -265,8 +266,7 @@ export const FBDBody = ({ rung, nodeDivergences = [], isDebuggerActive = false }
const updateRungState = () => {
const stripDivergence = (node: FlowNode) => {
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
- const { hasDivergence: _hd, ...cleanData } = node.data as Record
+ const { hasDivergence: _hd, ...cleanData } = node.data
return { ...node, data: cleanData }
}
@@ -326,7 +326,6 @@ export const FBDBody = ({ rung, nodeDivergences = [], isDebuggerActive = false }
// updating ref when state changes
// now, ref.current will have the latest sendRequest with access to the latest state
debounceUpdateRungRef.current = updateRungState
- // eslint-disable-next-line react-hooks/exhaustive-deps
}, [dragging, rungLocal, rung])
// creating debounced callback only once - on mount
const debouncedUpdateRungStateCallback = useMemo(() => {
@@ -342,13 +341,11 @@ export const FBDBody = ({ rung, nodeDivergences = [], isDebuggerActive = false }
useEffect(() => {
updateRungLocalFromStore()
- // eslint-disable-next-line react-hooks/exhaustive-deps
}, [rung])
useEffect(() => {
debouncedUpdateRungStateCallback()
return () => debouncedUpdateRungStateCallback.cancel()
- // eslint-disable-next-line react-hooks/exhaustive-deps
}, [rungLocal])
/**
@@ -368,7 +365,6 @@ export const FBDBody = ({ rung, nodeDivergences = [], isDebuggerActive = false }
)
return () => unsub()
- // eslint-disable-next-line react-hooks/exhaustive-deps
}, [reactFlowInstance])
useEffect(() => {
@@ -377,7 +373,6 @@ export const FBDBody = ({ rung, nodeDivergences = [], isDebuggerActive = false }
setTimeout(() => {
reactFlowInstance.setViewport(viewport, { duration: 0 })
}, 0)
- // eslint-disable-next-line react-hooks/exhaustive-deps
}, [reactFlowInstance, editor.meta.name])
/**
@@ -401,33 +396,33 @@ export const FBDBody = ({ rung, nodeDivergences = [], isDebuggerActive = false }
if (blockLibraryType === 'user') {
const library = libraries.user.find((library) => library.name === blockLibrary)
- const pou = pous.find((pou) => pou.data.name === library?.name)
+ const pou = pous.find((pou) => pou.name === library?.name)
if (!pou) return
- const variables = pou.data.variables.map((variable) => ({
+ const variables = (pou.interface?.variables ?? []).map((variable) => ({
id: variable.id,
name: variable.name,
class: variable.class,
type: { definition: variable.type.definition, value: variable.type.value.toUpperCase() },
}))
- if (pou.type === 'function') {
- const variable = getVariableRestrictionType(pou.data.returnType)
+ if (pou.pouType === 'function') {
+ const variable = getVariableRestrictionType(pou.interface?.returnType ?? '')
variables.push({
id: 'OUT',
name: 'OUT',
class: 'output',
type: {
definition: (variable.definition as 'array' | 'base-type' | 'user-data-type' | 'derived') ?? 'derived',
- value: pou.data.returnType.toUpperCase(),
+ value: (pou.interface?.returnType ?? '').toUpperCase(),
},
})
}
pouLibrary = {
- name: pou.data.name,
- type: pou.type,
+ name: pou.name,
+ type: pou.pouType,
variables: variables,
- documentation: pou.data.documentation,
+ documentation: pou.documentation,
extensible: false,
}
}
@@ -479,7 +474,7 @@ export const FBDBody = ({ rung, nodeDivergences = [], isDebuggerActive = false }
})
if (pouRef && nodes.length > 0) {
- const allVariables = pouRef.data.variables
+ const allVariables = pouRef.interface?.variables ?? []
const allRungs = [rung]
const variablesToDelete = getFunctionBlockVariablesToCleanup(nodes, allRungs, allVariables)
@@ -584,7 +579,6 @@ export const FBDBody = ({ rung, nodeDivergences = [], isDebuggerActive = false }
}
})
},
- // eslint-disable-next-line react-hooks/exhaustive-deps
[rungLocal, dragging],
)
@@ -595,14 +589,13 @@ export const FBDBody = ({ rung, nodeDivergences = [], isDebuggerActive = false }
edges: applyEdgeChanges(changes, rung.edges),
}))
},
- // eslint-disable-next-line react-hooks/exhaustive-deps
[rungLocal, dragging],
)
const onNodeDragStart = useCallback(() => {
+ captureAndPush(editor.meta.name)
setDragging(true)
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, [rungLocal, dragging])
+ }, [rungLocal, dragging, captureAndPush, editor.meta.name])
/**
* When the node drag stops, update the fbd rung state
@@ -619,7 +612,6 @@ export const FBDBody = ({ rung, nodeDivergences = [], isDebuggerActive = false }
},
})
},
- // eslint-disable-next-line react-hooks/exhaustive-deps
[rungLocal, dragging],
)
@@ -635,7 +627,6 @@ export const FBDBody = ({ rung, nodeDivergences = [], isDebuggerActive = false }
return
}
},
- // eslint-disable-next-line react-hooks/exhaustive-deps
[reactFlowViewportRef],
)
@@ -701,7 +692,6 @@ export const FBDBody = ({ rung, nodeDivergences = [], isDebuggerActive = false }
handleAddElementByDropping(position, blockType as CustomFbdNodeTypes, library)
},
- // eslint-disable-next-line react-hooks/exhaustive-deps
[rung, reactFlowInstance],
)
diff --git a/src2/frontend/components/_molecules/graphical-editor/ladder/rung/body.tsx b/src/frontend/components/_molecules/graphical-editor/ladder/rung/body.tsx
similarity index 94%
rename from src2/frontend/components/_molecules/graphical-editor/ladder/rung/body.tsx
rename to src/frontend/components/_molecules/graphical-editor/ladder/rung/body.tsx
index c9f821d47..662b43c90 100644
--- a/src2/frontend/components/_molecules/graphical-editor/ladder/rung/body.tsx
+++ b/src/frontend/components/_molecules/graphical-editor/ladder/rung/body.tsx
@@ -1,20 +1,20 @@
-import { getVariableRestrictionType } from '../../../../_atoms/graphical-editor/utils'
+import type { CoordinateExtent, Node as FlowNode, OnNodesChange, ReactFlowInstance } from '@xyflow/react'
+import { applyNodeChanges, getNodesBounds } from '@xyflow/react'
+import { differenceWith, isEqual, parseInt } from 'lodash'
+import { DragEventHandler, MouseEvent, useCallback, useEffect, useMemo, useRef, useState } from 'react'
+
+import type { PLCVariable } from '../../../../../../middleware/shared/ports/types'
import { useDebugCompositeKey } from '../../../../../hooks/use-debug-composite-key'
import { usePouSnapshot } from '../../../../../hooks/use-pou-snapshot'
import { useOpenPLCStore } from '../../../../../store'
import type { RungLadderState } from '../../../../../store/slices/ladder'
-import type { PLCVariable } from '../../../../../../middleware/shared/ports/types'
import { cn } from '../../../../../utils/cn'
import { getLadderBlockType, isLadderBlockDrag } from '../../../../../utils/graphical/drag-detection'
-import { syncNodesWithVariables } from '../../../../../utils/graphical/sync-nodes-with-variables'
import { getFunctionBlockVariablesToCleanup } from '../../../../../utils/graphical/get-function-block-variables-to-cleanup'
-import type { CoordinateExtent, Node as FlowNode, OnNodesChange, ReactFlowInstance } from '@xyflow/react'
-import { applyNodeChanges, getNodesBounds } from '@xyflow/react'
-import { differenceWith, isEqual, parseInt } from 'lodash'
-import { DragEventHandler, MouseEvent, useCallback, useEffect, useMemo, useRef, useState } from 'react'
-
+import { syncNodesWithVariables } from '../../../../../utils/graphical/sync-nodes-with-variables'
import { customNodeTypes } from '../../../../_atoms/graphical-editor/ladder'
import type { BasicNodeData } from '../../../../_atoms/graphical-editor/ladder/utils/types'
+import { getVariableRestrictionType } from '../../../../_atoms/graphical-editor/utils'
import { ReactFlowPanel } from '../../../../_atoms/react-flow'
import { toast } from '../../../../_features/[app]/toast/use-toast'
import { addNewElement, removeElements } from './ladder-utils/elements'
@@ -85,7 +85,7 @@ export const RungBody = ({ rung, className, nodeDivergences = [], isDebuggerActi
const { captureAndPush } = usePouSnapshot()
const { pous } = project.data
- const pouRef = pous.find((pou) => pou.data.name === editor.meta.name)
+ const pouRef = pous.find((pou) => pou.name === editor.meta.name)
const getCompositeKey = useDebugCompositeKey()
const nodeTypes = useMemo(() => customNodeTypes, [])
@@ -183,8 +183,8 @@ export const RungBody = ({ rung, className, nodeDivergences = [], isDebuggerActi
}
if (!sourceHandle) return undefined
- if (pouRef?.type !== 'function-block') {
- const instances = project.data.configuration.resource.instances
+ if (pouRef?.pouType !== 'function-block') {
+ const instances = project.data.configurations.resource.instances
const programInstance = instances.find((inst) => inst.program === editor.meta.name)
if (!programInstance) return undefined
}
@@ -270,7 +270,6 @@ export const RungBody = ({ rung, className, nodeDivergences = [], isDebuggerActi
return edge
})
- // eslint-disable-next-line react-hooks/exhaustive-deps
}, [
rungLocal.edges,
rungLocal.nodes,
@@ -350,7 +349,6 @@ export const RungBody = ({ rung, className, nodeDivergences = [], isDebuggerActi
}
return baseNodes
- // eslint-disable-next-line react-hooks/exhaustive-deps
}, [
rungLocal.edges,
rungLocal.nodes,
@@ -374,7 +372,6 @@ export const RungBody = ({ rung, className, nodeDivergences = [], isDebuggerActi
})),
})
updateReactFlowPanelExtent(rung)
- // eslint-disable-next-line react-hooks/exhaustive-deps
}, [rung.nodes])
/**
@@ -395,7 +392,6 @@ export const RungBody = ({ rung, className, nodeDivergences = [], isDebuggerActi
rungId: rung.id,
nodes: rungLocal.selectedNodes,
})
- // eslint-disable-next-line react-hooks/exhaustive-deps
}, [rungLocal.selectedNodes])
useEffect(() => {
@@ -426,7 +422,6 @@ export const RungBody = ({ rung, className, nodeDivergences = [], isDebuggerActi
} else {
setSearchNodePosition({ x: 0, y: 0 })
}
- // eslint-disable-next-line react-hooks/exhaustive-deps
}, [searchQuery, rungLocal, reactFlowInstance])
/**
@@ -471,32 +466,32 @@ export const RungBody = ({ rung, className, nodeDivergences = [], isDebuggerActi
if (blockLibraryType === 'user') {
const library = libraries.user.find((library) => library.name === blockLibrary)
- const pou = pous.find((pou) => pou.data.name === library?.name)
+ const pou = pous.find((pou) => pou.name === library?.name)
if (!pou) return
- const variables = pou.data.variables.map((variable) => ({
+ const variables = (pou.interface?.variables ?? []).map((variable) => ({
id: variable.id,
name: variable.name,
class: variable.class,
type: { definition: variable.type.definition, value: variable.type.value.toUpperCase() },
}))
- if (pou.type === 'function') {
- const variable = getVariableRestrictionType(pou.data.returnType)
+ if (pou.pouType === 'function') {
+ const variable = getVariableRestrictionType(pou.interface?.returnType ?? '')
variables.push({
id: 'OUT',
name: 'OUT',
class: 'output',
type: {
definition: (variable.definition as 'array' | 'base-type' | 'user-data-type' | 'derived') ?? 'derived',
- value: pou.data.returnType.toUpperCase(),
+ value: (pou.interface?.returnType ?? '').toUpperCase(),
},
})
}
pouLibrary = {
- name: pou.data.name,
- type: pou.type,
+ name: pou.name,
+ type: pou.pouType,
variables: variables,
- documentation: pou.data.documentation,
+ documentation: pou.documentation,
extensible: false,
}
}
@@ -531,7 +526,12 @@ export const RungBody = ({ rung, className, nodeDivergences = [], isDebuggerActi
})
if (pouRef) {
- syncNodesWithVariables(pouRef.data.variables, ladderFlows, ladderFlowActions.updateNode, editor.meta.name)
+ syncNodesWithVariables(
+ pouRef.interface?.variables ?? [],
+ ladderFlows,
+ ladderFlowActions.updateNode,
+ editor.meta.name,
+ )
}
}
@@ -566,9 +566,11 @@ export const RungBody = ({ rung, className, nodeDivergences = [], isDebuggerActi
const blockNodes = nodes.filter((node) => node.type === 'block')
if (blockNodes.length > 0) {
let variables: PLCVariable[] = []
- if (pouRef) variables = [...pouRef.data.variables] as PLCVariable[]
+ if (pouRef) variables = [...(pouRef.interface?.variables ?? [])] as PLCVariable[]
- const variablesToCleanup = getFunctionBlockVariablesToCleanup(blockNodes, variables, ladderFlows)
+ const currentFlow = ladderFlows.find((f) => f.name === editor.meta.name)
+ const allRungs = currentFlow?.rungs ?? []
+ const variablesToCleanup = getFunctionBlockVariablesToCleanup(blockNodes, allRungs, variables)
variablesToCleanup.forEach((variableName) => {
deleteVariable({
@@ -601,7 +603,12 @@ export const RungBody = ({ rung, className, nodeDivergences = [], isDebuggerActi
}
if (pouRef) {
- syncNodesWithVariables(pouRef.data.variables, ladderFlows, ladderFlowActions.updateNode, editor.meta.name)
+ syncNodesWithVariables(
+ pouRef.interface?.variables ?? [],
+ ladderFlows,
+ ladderFlowActions.updateNode,
+ editor.meta.name,
+ )
}
}
@@ -652,7 +659,12 @@ export const RungBody = ({ rung, className, nodeDivergences = [], isDebuggerActi
ladderFlowActions.setEdges({ editorName: editor.meta.name, rungId: rungLocal.id, edges: result.edges })
if (pouRef) {
- syncNodesWithVariables(pouRef.data.variables, ladderFlows, ladderFlowActions.updateNode, editor.meta.name)
+ syncNodesWithVariables(
+ pouRef.interface?.variables ?? [],
+ ladderFlows,
+ ladderFlowActions.updateNode,
+ editor.meta.name,
+ )
}
}
@@ -710,7 +722,6 @@ export const RungBody = ({ rung, className, nodeDivergences = [], isDebuggerActi
selectedNodes: selectedNodes,
}))
},
- // eslint-disable-next-line react-hooks/exhaustive-deps
[rungLocal, rung, dragging],
)
@@ -746,7 +757,6 @@ export const RungBody = ({ rung, className, nodeDivergences = [], isDebuggerActi
setRungLocal((rung) => ({ ...rung, nodes }))
}
},
- // eslint-disable-next-line react-hooks/exhaustive-deps
[rung, rungLocal, setReactFlowPanelExtent, reactFlowPanelExtent, dragging, isDebuggerActive],
)
@@ -788,7 +798,6 @@ export const RungBody = ({ rung, className, nodeDivergences = [], isDebuggerActi
const nodes = removePlaceholderElements(rungLocal.nodes)
setRungLocal((rung) => ({ ...rung, nodes }))
},
- // eslint-disable-next-line react-hooks/exhaustive-deps
[rung, rungLocal, setReactFlowPanelExtent, reactFlowPanelExtent, dragging, isDebuggerActive],
)
@@ -826,7 +835,6 @@ export const RungBody = ({ rung, className, nodeDivergences = [], isDebuggerActi
}),
}))
},
- // eslint-disable-next-line react-hooks/exhaustive-deps
[rung, rungLocal, isDebuggerActive],
)
@@ -857,7 +865,6 @@ export const RungBody = ({ rung, className, nodeDivergences = [], isDebuggerActi
// Then add the node to the rung
handleAddNode(blockType, library)
},
- // eslint-disable-next-line react-hooks/exhaustive-deps
[rung, rungLocal, setReactFlowPanelExtent, reactFlowPanelExtent, isDebuggerActive],
)
diff --git a/src2/frontend/components/_molecules/graphical-editor/ladder/rung/create-rung.tsx b/src/frontend/components/_molecules/graphical-editor/ladder/rung/create-rung.tsx
similarity index 100%
rename from src2/frontend/components/_molecules/graphical-editor/ladder/rung/create-rung.tsx
rename to src/frontend/components/_molecules/graphical-editor/ladder/rung/create-rung.tsx
diff --git a/src2/frontend/components/_molecules/graphical-editor/ladder/rung/header.tsx b/src/frontend/components/_molecules/graphical-editor/ladder/rung/header.tsx
similarity index 100%
rename from src2/frontend/components/_molecules/graphical-editor/ladder/rung/header.tsx
rename to src/frontend/components/_molecules/graphical-editor/ladder/rung/header.tsx
index ec804bcbe..5e6f3d53f 100644
--- a/src2/frontend/components/_molecules/graphical-editor/ladder/rung/header.tsx
+++ b/src/frontend/components/_molecules/graphical-editor/ladder/rung/header.tsx
@@ -10,9 +10,9 @@ import { CloseIcon } from '../../../../../assets/icons/interface/Close'
import { DragHandleIcon } from '../../../../../assets/icons/interface/DragHandle'
import { DuplicateIcon } from '../../../../../assets/icons/interface/Duplicate'
import { StickArrowIcon } from '../../../../../assets/icons/interface/StickArrow'
-import { cn } from '../../../../../utils/cn'
import { useOpenPLCStore } from '../../../../../store'
import type { RungLadderState } from '../../../../../store/slices/ladder'
+import { cn } from '../../../../../utils/cn'
import { HighlightedTextArea } from '../../../../_atoms/highlighted-textarea'
type RungHeaderProps = {
diff --git a/src2/frontend/components/_molecules/graphical-editor/ladder/rung/ladder-utils/edges.ts b/src/frontend/components/_molecules/graphical-editor/ladder/rung/ladder-utils/edges.ts
similarity index 100%
rename from src2/frontend/components/_molecules/graphical-editor/ladder/rung/ladder-utils/edges.ts
rename to src/frontend/components/_molecules/graphical-editor/ladder/rung/ladder-utils/edges.ts
index f0741e323..177873a38 100644
--- a/src2/frontend/components/_molecules/graphical-editor/ladder/rung/ladder-utils/edges.ts
+++ b/src/frontend/components/_molecules/graphical-editor/ladder/rung/ladder-utils/edges.ts
@@ -1,7 +1,7 @@
-import type { BasicNodeData, ParallelNode } from '../../../../../_atoms/graphical-editor/ladder/utils/types'
-import type { RungLadderState } from '../../../../../../store/slices/ladder'
import type { Edge, Node } from '@xyflow/react'
+import type { RungLadderState } from '../../../../../../store/slices/ladder'
+import type { BasicNodeData, ParallelNode } from '../../../../../_atoms/graphical-editor/ladder/utils/types'
import { isNodeOfType } from './nodes'
type ConnectionOptions = {
diff --git a/src2/frontend/components/_molecules/graphical-editor/ladder/rung/ladder-utils/elements/diagram/index.ts b/src/frontend/components/_molecules/graphical-editor/ladder/rung/ladder-utils/elements/diagram/index.ts
similarity index 99%
rename from src2/frontend/components/_molecules/graphical-editor/ladder/rung/ladder-utils/elements/diagram/index.ts
rename to src/frontend/components/_molecules/graphical-editor/ladder/rung/ladder-utils/elements/diagram/index.ts
index 2dd1e5ff2..b8f959463 100644
--- a/src2/frontend/components/_molecules/graphical-editor/ladder/rung/ladder-utils/elements/diagram/index.ts
+++ b/src/frontend/components/_molecules/graphical-editor/ladder/rung/ladder-utils/elements/diagram/index.ts
@@ -1,11 +1,11 @@
-import { defaultCustomNodesStyles } from '../../../../../../../_atoms/graphical-editor/ladder'
-import type { CustomHandleProps } from '../../../../../../../_atoms/graphical-editor/ladder/handle'
-import type { BasicNodeData, ParallelNode } from '../../../../../../../_atoms/graphical-editor/ladder/utils/types'
// import type { VariableNode } from '../../../../../../../_atoms/graphical-editor/ladder/variable'
-import type { RungLadderState } from '../../../../../../../../store/slices'
+import type { RungLadderState } from '@root/frontend/store/slices'
import type { Edge, Node } from '@xyflow/react'
import { Position } from '@xyflow/react'
+import type { CustomHandleProps } from '../../../../../../../_atoms/graphical-editor/ladder/handle'
+import { defaultCustomNodesStyles } from '../../../../../../../_atoms/graphical-editor/ladder/node-builders'
+import type { BasicNodeData, ParallelNode } from '../../../../../../../_atoms/graphical-editor/ladder/utils/types'
import { getDefaultNodeStyle, isNodeOfType } from '../../nodes'
import {
findAllParallelsDepthAndNodes,
diff --git a/src2/frontend/components/_molecules/graphical-editor/ladder/rung/ladder-utils/elements/drag-n-drop/index.ts b/src/frontend/components/_molecules/graphical-editor/ladder/rung/ladder-utils/elements/drag-n-drop/index.ts
similarity index 98%
rename from src2/frontend/components/_molecules/graphical-editor/ladder/rung/ladder-utils/elements/drag-n-drop/index.ts
rename to src/frontend/components/_molecules/graphical-editor/ladder/rung/ladder-utils/elements/drag-n-drop/index.ts
index 528128ada..46dbfcba4 100644
--- a/src2/frontend/components/_molecules/graphical-editor/ladder/rung/ladder-utils/elements/drag-n-drop/index.ts
+++ b/src/frontend/components/_molecules/graphical-editor/ladder/rung/ladder-utils/elements/drag-n-drop/index.ts
@@ -1,7 +1,8 @@
-import type { RungLadderState } from '../../../../../../../../store/slices'
+import type { RungLadderState } from '@root/frontend/store/slices'
import type { Edge, Node, ReactFlowInstance } from '@xyflow/react'
import { toInteger } from 'lodash'
+import { PlaceholderNode } from '../../../../../../../_atoms/graphical-editor/ladder/utils/types'
import { isNodeOfType } from '../../nodes'
import { removeElement } from '..'
import { updateDiagramElementsPosition } from '../diagram'
@@ -10,7 +11,6 @@ import { removePlaceholderElements } from '../placeholder'
import { renderPlaceholderElements, searchNearestPlaceholder } from '../placeholder'
import { appendSerialConnection } from '../serial'
import { removeVariableBlock } from '../variable-block'
-import { PlaceholderNode } from '../../../../../../../_atoms/graphical-editor/ladder/utils/types'
export const onElementDragStart = (rung: RungLadderState, draggedNode: Node) => {
/**
diff --git a/src2/frontend/components/_molecules/graphical-editor/ladder/rung/ladder-utils/elements/index.ts b/src/frontend/components/_molecules/graphical-editor/ladder/rung/ladder-utils/elements/index.ts
similarity index 98%
rename from src2/frontend/components/_molecules/graphical-editor/ladder/rung/ladder-utils/elements/index.ts
rename to src/frontend/components/_molecules/graphical-editor/ladder/rung/ladder-utils/elements/index.ts
index 249c1cb60..ce0dece9d 100644
--- a/src2/frontend/components/_molecules/graphical-editor/ladder/rung/ladder-utils/elements/index.ts
+++ b/src/frontend/components/_molecules/graphical-editor/ladder/rung/ladder-utils/elements/index.ts
@@ -1,7 +1,7 @@
-import type { BasicNodeData, PlaceholderNode } from '../../../../../../_atoms/graphical-editor/ladder/utils/types'
-import type { RungLadderState } from '../../../../../../../store/slices'
+import type { RungLadderState } from '@root/frontend/store/slices'
import type { Edge, Node } from '@xyflow/react'
+import type { BasicNodeData, PlaceholderNode } from '../../../../../../_atoms/graphical-editor/ladder/utils/types'
import { disconnectNodes } from '../edges'
import { isNodeOfType, removeNode } from '../nodes'
import { updateDiagramElementsPosition } from './diagram'
diff --git a/src2/frontend/components/_molecules/graphical-editor/ladder/rung/ladder-utils/elements/parallel/index.ts b/src/frontend/components/_molecules/graphical-editor/ladder/rung/ladder-utils/elements/parallel/index.ts
similarity index 98%
rename from src2/frontend/components/_molecules/graphical-editor/ladder/rung/ladder-utils/elements/parallel/index.ts
rename to src/frontend/components/_molecules/graphical-editor/ladder/rung/ladder-utils/elements/parallel/index.ts
index 45a50bdec..f71f337da 100644
--- a/src2/frontend/components/_molecules/graphical-editor/ladder/rung/ladder-utils/elements/parallel/index.ts
+++ b/src/frontend/components/_molecules/graphical-editor/ladder/rung/ladder-utils/elements/parallel/index.ts
@@ -1,14 +1,14 @@
-import { checkIfElementIsNode, nodesBuilder } from '../../../../../../../_atoms/graphical-editor/ladder'
+import type { RungLadderState } from '@root/frontend/store/slices'
+import { newGraphicalEditorNodeID } from '@root/frontend/utils/new-graphical-editor-node-id'
+import type { Edge, Node } from '@xyflow/react'
+
+import { checkIfElementIsNode, nodesBuilder } from '../../../../../../../_atoms/graphical-editor/ladder/node-builders'
import type {
BasicNodeData,
BlockNodeData,
ParallelNode,
PlaceholderNode,
} from '../../../../../../../_atoms/graphical-editor/ladder/utils/types'
-import type { RungLadderState } from '../../../../../../../../store/slices'
-import type { Edge, Node } from '@xyflow/react'
-
-import { newGraphicalEditorNodeID } from '../../../../../../../../utils/new-graphical-editor-node-id'
import { buildEdge, connectNodes, removeEdge } from '../../edges'
import { buildGenericNode, isNodeOfType, removeNode } from '../../nodes'
import { removePlaceholderElements } from '../placeholder'
diff --git a/src2/frontend/components/_molecules/graphical-editor/ladder/rung/ladder-utils/elements/placeholder/index.ts b/src/frontend/components/_molecules/graphical-editor/ladder/rung/ladder-utils/elements/placeholder/index.ts
similarity index 96%
rename from src2/frontend/components/_molecules/graphical-editor/ladder/rung/ladder-utils/elements/placeholder/index.ts
rename to src/frontend/components/_molecules/graphical-editor/ladder/rung/ladder-utils/elements/placeholder/index.ts
index a446e966e..344a2950d 100644
--- a/src2/frontend/components/_molecules/graphical-editor/ladder/rung/ladder-utils/elements/placeholder/index.ts
+++ b/src/frontend/components/_molecules/graphical-editor/ladder/rung/ladder-utils/elements/placeholder/index.ts
@@ -1,8 +1,8 @@
-import { nodesBuilder } from '../../../../../../../_atoms/graphical-editor/ladder'
-import type { RungLadderState } from '../../../../../../../../store/slices'
+import type { RungLadderState } from '@root/frontend/store/slices'
+import { newGraphicalEditorNodeID } from '@root/frontend/utils/new-graphical-editor-node-id'
import type { Node, ReactFlowInstance } from '@xyflow/react'
-import { newGraphicalEditorNodeID } from '../../../../../../../../utils/new-graphical-editor-node-id'
+import { nodesBuilder } from '../../../../../../../_atoms/graphical-editor/ladder/node-builders'
import { getDeepestNodesInsideParallels, getNodesInsideAllParallels, getPlaceholderPositionBasedOnNode } from '../utils'
export const removePlaceholderElements = (nodes: Node[]) => {
diff --git a/src2/frontend/components/_molecules/graphical-editor/ladder/rung/ladder-utils/elements/serial/index.ts b/src/frontend/components/_molecules/graphical-editor/ladder/rung/ladder-utils/elements/serial/index.ts
similarity index 94%
rename from src2/frontend/components/_molecules/graphical-editor/ladder/rung/ladder-utils/elements/serial/index.ts
rename to src/frontend/components/_molecules/graphical-editor/ladder/rung/ladder-utils/elements/serial/index.ts
index 6bc830859..6a0b785df 100644
--- a/src2/frontend/components/_molecules/graphical-editor/ladder/rung/ladder-utils/elements/serial/index.ts
+++ b/src/frontend/components/_molecules/graphical-editor/ladder/rung/ladder-utils/elements/serial/index.ts
@@ -1,13 +1,13 @@
-import { checkIfElementIsNode } from '../../../../../../../_atoms/graphical-editor/ladder'
-import type { RungLadderState } from '../../../../../../../../store/slices'
+import type { RungLadderState } from '@root/frontend/store/slices'
+import { newGraphicalEditorNodeID } from '@root/frontend/utils/new-graphical-editor-node-id'
import type { Edge, Node } from '@xyflow/react'
-import { newGraphicalEditorNodeID } from '../../../../../../../../utils/new-graphical-editor-node-id'
+import { checkIfElementIsNode } from '../../../../../../../_atoms/graphical-editor/ladder/node-builders'
+import { ParallelNode, PlaceholderNode } from '../../../../../../../_atoms/graphical-editor/ladder/utils/types'
import { connectNodes } from '../../edges'
import { buildGenericNode, isNodeOfType } from '../../nodes'
import { removePlaceholderElements } from '../placeholder'
import { getElementPositionBasedOnPlaceholderElement, getPreviousElement, getPreviousElementsByEdge } from '../utils'
-import { ParallelNode, PlaceholderNode } from '../../../../../../../_atoms/graphical-editor/ladder/utils/types'
export const appendSerialConnection = (
rung: RungLadderState,
diff --git a/src2/frontend/components/_molecules/graphical-editor/ladder/rung/ladder-utils/elements/utils/index.ts b/src/frontend/components/_molecules/graphical-editor/ladder/rung/ladder-utils/elements/utils/index.ts
similarity index 99%
rename from src2/frontend/components/_molecules/graphical-editor/ladder/rung/ladder-utils/elements/utils/index.ts
rename to src/frontend/components/_molecules/graphical-editor/ladder/rung/ladder-utils/elements/utils/index.ts
index 70e0d3f90..2ab82738c 100644
--- a/src2/frontend/components/_molecules/graphical-editor/ladder/rung/ladder-utils/elements/utils/index.ts
+++ b/src/frontend/components/_molecules/graphical-editor/ladder/rung/ladder-utils/elements/utils/index.ts
@@ -1,9 +1,9 @@
-import type { CustomHandleProps } from '../../../../../../../_atoms/graphical-editor/ladder/handle'
-import type { RungLadderState } from '../../../../../../../../store/slices'
+import type { RungLadderState } from '@root/frontend/store/slices'
import type { Edge, Node } from '@xyflow/react'
-import { getDefaultNodeStyle, isNodeOfType } from '../../nodes'
+import type { CustomHandleProps } from '../../../../../../../_atoms/graphical-editor/ladder/handle'
import { BasicNodeData, ParallelNode } from '../../../../../../../_atoms/graphical-editor/ladder/utils/types'
+import { getDefaultNodeStyle, isNodeOfType } from '../../nodes'
/**
* Get the previous element by searching with edge in the rung
diff --git a/src2/frontend/components/_molecules/graphical-editor/ladder/rung/ladder-utils/elements/variable-block/index.ts b/src/frontend/components/_molecules/graphical-editor/ladder/rung/ladder-utils/elements/variable-block/index.ts
similarity index 88%
rename from src2/frontend/components/_molecules/graphical-editor/ladder/rung/ladder-utils/elements/variable-block/index.ts
rename to src/frontend/components/_molecules/graphical-editor/ladder/rung/ladder-utils/elements/variable-block/index.ts
index befabcf06..c3626ef08 100644
--- a/src2/frontend/components/_molecules/graphical-editor/ladder/rung/ladder-utils/elements/variable-block/index.ts
+++ b/src/frontend/components/_molecules/graphical-editor/ladder/rung/ladder-utils/elements/variable-block/index.ts
@@ -1,10 +1,13 @@
-import { defaultCustomNodesStyles, nodesBuilder } from '../../../../../../../_atoms/graphical-editor/ladder'
-import { RungLadderState } from '../../../../../../../../store/slices'
+import { RungLadderState } from '@root/frontend/store/slices'
+import { newGraphicalEditorNodeID } from '@root/frontend/utils/new-graphical-editor-node-id'
import { Edge, Node } from '@xyflow/react'
-import { newGraphicalEditorNodeID } from '../../../../../../../../utils/new-graphical-editor-node-id'
-import { buildEdge } from '../../edges'
+import {
+ defaultCustomNodesStyles,
+ nodesBuilder,
+} from '../../../../../../../_atoms/graphical-editor/ladder/node-builders'
import { BlockNode, BlockVariant } from '../../../../../../../_atoms/graphical-editor/ladder/utils/types'
+import { buildEdge } from '../../edges'
export const renderVariableBlock = (rung: RungLadderState, block: Node) => {
const variableElements: Node[] = []
@@ -24,7 +27,9 @@ export const renderVariableBlock = (rung: RungLadderStat
: []
inputHandles.forEach((inputHandle) => {
- const connectedVariable = blockElement.data.connectedVariables.find((variable) => {
+ const connectedVariable = (
+ Array.isArray(blockElement.data.connectedVariables) ? blockElement.data.connectedVariables : []
+ ).find((variable) => {
return variable.type === 'input' && variable.handleId === inputHandle.id
})
@@ -64,7 +69,9 @@ export const renderVariableBlock = (rung: RungLadderStat
})
outputHandles.forEach((outputHandle) => {
- const connectedVariable = blockElement.data.connectedVariables.find((variable) => {
+ const connectedVariable = (
+ Array.isArray(blockElement.data.connectedVariables) ? blockElement.data.connectedVariables : []
+ ).find((variable) => {
return variable.type === 'output' && variable.handleId === outputHandle.id
})
diff --git a/src2/frontend/components/_molecules/graphical-editor/ladder/rung/ladder-utils/nodes.ts b/src/frontend/components/_molecules/graphical-editor/ladder/rung/ladder-utils/nodes.ts
similarity index 97%
rename from src2/frontend/components/_molecules/graphical-editor/ladder/rung/ladder-utils/nodes.ts
rename to src/frontend/components/_molecules/graphical-editor/ladder/rung/ladder-utils/nodes.ts
index a165f466a..a25ed80f2 100644
--- a/src2/frontend/components/_molecules/graphical-editor/ladder/rung/ladder-utils/nodes.ts
+++ b/src/frontend/components/_molecules/graphical-editor/ladder/rung/ladder-utils/nodes.ts
@@ -1,8 +1,9 @@
-import { defaultCustomNodesStyles, nodesBuilder } from '../../../../../_atoms/graphical-editor/ladder'
-import type { BuilderBasicProps } from '../../../../../_atoms/graphical-editor/ladder/utils/types'
-import type { RungLadderState } from '../../../../../../store/slices/ladder'
import type { Node } from '@xyflow/react'
+import type { RungLadderState } from '../../../../../../store/slices/ladder'
+import { defaultCustomNodesStyles, nodesBuilder } from '../../../../../_atoms/graphical-editor/ladder/node-builders'
+import type { BuilderBasicProps } from '../../../../../_atoms/graphical-editor/ladder/utils/types'
+
export const findNode = (
rung: RungLadderState,
nodeId: string,
diff --git a/src2/frontend/components/_molecules/input-field/index.tsx b/src/frontend/components/_molecules/input-field/index.tsx
similarity index 99%
rename from src2/frontend/components/_molecules/input-field/index.tsx
rename to src/frontend/components/_molecules/input-field/index.tsx
index 00887753a..e5dcf0e6e 100644
--- a/src2/frontend/components/_molecules/input-field/index.tsx
+++ b/src/frontend/components/_molecules/input-field/index.tsx
@@ -1,5 +1,4 @@
import { cn } from '../../../utils/cn'
-
import { InputWithRef } from '../../_atoms/input'
type InputFieldProps = {
diff --git a/src2/frontend/components/_molecules/instances-table/editable-cell.tsx b/src/frontend/components/_molecules/instances-table/editable-cell.tsx
similarity index 100%
rename from src2/frontend/components/_molecules/instances-table/editable-cell.tsx
rename to src/frontend/components/_molecules/instances-table/editable-cell.tsx
index d78c1bb49..3270b37f7 100644
--- a/src2/frontend/components/_molecules/instances-table/editable-cell.tsx
+++ b/src/frontend/components/_molecules/instances-table/editable-cell.tsx
@@ -1,10 +1,10 @@
-import type { PLCInstance } from '../../../../middleware/shared/ports/types'
-import type { ProjectResponse } from '../../../store/slices/project'
-import { useOpenPLCStore } from '../../../store'
-import { cn } from '../../../utils/cn'
import type { CellContext, RowData } from '@tanstack/react-table'
import { useEffect, useState } from 'react'
+import type { PLCInstance } from '../../../../middleware/shared/ports/types'
+import { useOpenPLCStore } from '../../../store'
+import type { ProjectResponse } from '../../../store/slices/project'
+import { cn } from '../../../utils/cn'
import { HighlightedText } from '../../_atoms/highlighted-text'
import { InputWithRef } from '../../_atoms/input'
import { useToast } from '../../_features/[app]/toast/use-toast'
diff --git a/src2/frontend/components/_molecules/instances-table/index.tsx b/src/frontend/components/_molecules/instances-table/index.tsx
similarity index 96%
rename from src2/frontend/components/_molecules/instances-table/index.tsx
rename to src/frontend/components/_molecules/instances-table/index.tsx
index 7f7aea42b..e992e1423 100644
--- a/src2/frontend/components/_molecules/instances-table/index.tsx
+++ b/src/frontend/components/_molecules/instances-table/index.tsx
@@ -1,6 +1,6 @@
-import type { PLCInstance } from '../../../../middleware/shared/ports/types'
import { createColumnHelper } from '@tanstack/react-table'
+import type { PLCInstance } from '../../../../middleware/shared/ports/types'
import { usePouSnapshot } from '../../../hooks/use-pou-snapshot'
import { useOpenPLCStore } from '../../../store'
import { GenericTable } from '../../_atoms/generic-table'
@@ -17,7 +17,7 @@ const columns = [
maxSize: 150,
cell: EditableNameCell,
}),
- columnHelper.accessor('pouName', {
+ columnHelper.accessor('program', {
header: 'Program',
size: 768,
minSize: 150,
@@ -25,7 +25,7 @@ const columns = [
enableResizing: true,
cell: SelectableProgramCell,
}),
- columnHelper.accessor('taskName', {
+ columnHelper.accessor('task', {
header: ' Task',
enableResizing: true,
size: 768,
diff --git a/src2/frontend/components/_molecules/instances-table/selectable-cell.tsx b/src/frontend/components/_molecules/instances-table/selectable-cell.tsx
similarity index 100%
rename from src2/frontend/components/_molecules/instances-table/selectable-cell.tsx
rename to src/frontend/components/_molecules/instances-table/selectable-cell.tsx
index 3c3e4c997..b8c9c07cf 100644
--- a/src2/frontend/components/_molecules/instances-table/selectable-cell.tsx
+++ b/src/frontend/components/_molecules/instances-table/selectable-cell.tsx
@@ -1,10 +1,10 @@
-import type { PLCInstance } from '../../../../middleware/shared/ports/types'
-import { useOpenPLCStore } from '../../../store'
-import { cn } from '../../../utils/cn'
import { CellContext } from '@tanstack/react-table'
import _ from 'lodash'
import { useEffect, useState } from 'react'
+import type { PLCInstance } from '../../../../middleware/shared/ports/types'
+import { useOpenPLCStore } from '../../../store'
+import { cn } from '../../../utils/cn'
import { Select, SelectContent, SelectItem, SelectTrigger } from '../../_atoms/select'
type ISelectableCellProps = CellContext & { editable?: boolean }
diff --git a/src2/frontend/components/_molecules/library-tree/index.tsx b/src/frontend/components/_molecules/library-tree/index.tsx
similarity index 99%
rename from src2/frontend/components/_molecules/library-tree/index.tsx
rename to src/frontend/components/_molecules/library-tree/index.tsx
index 8b2ad9444..3ae1af3f9 100644
--- a/src2/frontend/components/_molecules/library-tree/index.tsx
+++ b/src/frontend/components/_molecules/library-tree/index.tsx
@@ -1,9 +1,10 @@
+import { ComponentPropsWithoutRef, ReactNode, useCallback, useEffect, useState } from 'react'
+
import { ArrowIcon } from '../../../assets/icons/interface/Arrow'
import { LibraryCloseFolderIcon } from '../../../assets/icons/library/CloseFolder'
import { LibraryFileIcon } from '../../../assets/icons/library/File'
import { LibraryOpenFolderIcon } from '../../../assets/icons/library/OpenFolder'
import { cn } from '../../../utils/cn'
-import { ComponentPropsWithoutRef, ReactNode, useCallback, useEffect, useState } from 'react'
type ILibraryRootProps = ComponentPropsWithoutRef<'ul'> & {
children: ReactNode
diff --git a/src/renderer/components/_molecules/menu-bar/constants.ts b/src/frontend/components/_molecules/menu-bar/constants.ts
similarity index 100%
rename from src/renderer/components/_molecules/menu-bar/constants.ts
rename to src/frontend/components/_molecules/menu-bar/constants.ts
diff --git a/src2/frontend/components/_molecules/menu-bar/index.tsx b/src/frontend/components/_molecules/menu-bar/index.tsx
similarity index 99%
rename from src2/frontend/components/_molecules/menu-bar/index.tsx
rename to src/frontend/components/_molecules/menu-bar/index.tsx
index c69af9ea4..60a74f914 100644
--- a/src2/frontend/components/_molecules/menu-bar/index.tsx
+++ b/src/frontend/components/_molecules/menu-bar/index.tsx
@@ -1,7 +1,6 @@
import * as MenuPrimitive from '@radix-ui/react-menubar'
import { cn } from '../../../utils/cn'
-
import { MenuClasses } from './constants'
import { DisplayMenu } from './menus/display'
import { EditMenu } from './menus/edit'
diff --git a/src/frontend/components/_molecules/menu-bar/menus/display.tsx b/src/frontend/components/_molecules/menu-bar/menus/display.tsx
new file mode 100644
index 000000000..17492f0ad
--- /dev/null
+++ b/src/frontend/components/_molecules/menu-bar/menus/display.tsx
@@ -0,0 +1,106 @@
+import * as MenuPrimitive from '@radix-ui/react-menubar'
+import { useEffect, useState } from 'react'
+
+import { i18n } from '../../../../locales/i18n'
+import { useOpenPLCStore } from '../../../../store'
+import { MenuClasses } from '../constants'
+
+interface FullscreenElement extends HTMLElement {
+ webkitRequestFullscreen?: () => Promise
+ msRequestFullscreen?: () => Promise
+}
+
+function getThemePreference(): 'light' | 'dark' {
+ const stored = localStorage.getItem('theme')
+ if (stored === 'dark' || stored === 'light') return stored
+ return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'
+}
+
+export const DisplayMenu = () => {
+ const {
+ workspaceActions: { setSystemConfigs, toggleCollapse },
+ } = useOpenPLCStore()
+
+ const { TRIGGER, CONTENT, ITEM, ACCELERATOR, SEPARATOR } = MenuClasses
+
+ const [theme, setTheme] = useState(getThemePreference())
+
+ useEffect(() => {
+ document.documentElement.classList.add(theme)
+ setSystemConfigs({ shouldUseDarkMode: theme === 'dark' })
+ return () => {
+ document.documentElement.classList.remove(theme)
+ }
+ }, [theme, setSystemConfigs])
+
+ const toggleTheme = () => {
+ const newTheme = theme === 'light' ? 'dark' : 'light'
+ setTheme(newTheme)
+ localStorage.setItem('theme', newTheme)
+ }
+
+ const switchPerspective = () => {
+ toggleCollapse()
+ }
+
+ return (
+
+ {i18n.t('menu:display.label')}
+
+
+ window.location.reload()}>
+ {i18n.t('menu:display.submenu.refresh')}
+ {'Ctrl + R'}
+
+
+ {i18n.t('menu:display.submenu.clearErrors')}
+
+
+
+ {i18n.t('menu:display.submenu.zoomIn')}
+ {'Ctrl + +'}
+
+
+ {i18n.t('menu:display.submenu.zoomOut')}
+ {'Ctrl + -'}
+
+
+ {i18n.t('menu:display.submenu.switchPerspective')}
+ {'F12'}
+
+
+
+ {i18n.t('menu:display.submenu.resetPerspective')}
+ {'Shift + F12'}
+
+ {
+ const elem = document.documentElement as FullscreenElement
+ if (elem.requestFullscreen) {
+ elem.requestFullscreen()
+ } else if (elem.webkitRequestFullscreen) {
+ elem.webkitRequestFullscreen()
+ } else if (elem.msRequestFullscreen) {
+ elem.msRequestFullscreen()
+ }
+ }}
+ >
+ {i18n.t('menu:display.submenu.fullScreen')}
+ {'F11'}
+
+
+ {i18n.t('menu:display.submenu.sortAlpha')}
+ {'F10'}
+
+
+
+ {i18n.t('menu:display.submenu.theme')}
+ {theme === 'light' ? 'dark' : 'light'}
+
+
+
+
+
+ )
+}
diff --git a/src/frontend/components/_molecules/menu-bar/menus/edit.tsx b/src/frontend/components/_molecules/menu-bar/menus/edit.tsx
new file mode 100644
index 000000000..7dc0a2614
--- /dev/null
+++ b/src/frontend/components/_molecules/menu-bar/menus/edit.tsx
@@ -0,0 +1,93 @@
+import * as MenuPrimitive from '@radix-ui/react-menubar'
+import { useEffect } from 'react'
+
+import { useHandleRemoveTab } from '../../../../hooks/use-remove-tab'
+import { i18n } from '../../../../locales/i18n'
+import { useOpenPLCStore } from '../../../../store'
+import { MenuClasses } from '../constants'
+
+export const EditMenu = () => {
+ const {
+ editor,
+ workspaceActions: { setModalOpen },
+ modalActions: { openModal },
+ } = useOpenPLCStore()
+ const { setSelectedTab } = useHandleRemoveTab()
+ const { TRIGGER, CONTENT, ITEM, ACCELERATOR, SEPARATOR } = MenuClasses
+
+ useEffect(() => {
+ setSelectedTab(editor.meta.name)
+ return () => {
+ setSelectedTab('')
+ }
+ }, [editor])
+
+ const handleFindInProject = () => {
+ setModalOpen('findInProject', true)
+ }
+
+ const handleConfirmDeleteElement = () => {
+ openModal('confirm-delete-element', null)
+ }
+
+ return (
+
+ {i18n.t('menu:edit.label')}
+
+
+
+ {i18n.t('menu:edit.submenu.undo')}
+ {'Ctrl + Z'}
+
+
+ {i18n.t('menu:edit.submenu.redo')}
+ {'Ctrl + Y'}
+
+
+
+ {i18n.t('menu:edit.submenu.cut')}
+ {'Ctrl + X'}
+
+
+ {i18n.t('menu:edit.submenu.copy')}
+ {'Ctrl + C'}
+
+
+ {i18n.t('menu:edit.submenu.paste')}
+ {'Ctrl + V'}
+
+
+
+ {i18n.t('menu:edit.submenu.find')}
+ {'Ctrl + F'}
+
+
+ {i18n.t('menu:edit.submenu.findNext')}
+ {'Ctrl + K'}
+
+
+ {i18n.t('menu:edit.submenu.findPrevious')}
+ {'Ctrl + Shift + K'}
+
+
+
+ {i18n.t('menu:edit.submenu.findInProject')}
+ {'Ctrl + Shift + F'}
+
+
+
+ {i18n.t('menu:edit.submenu.addElement.label')}
+
+
+ {i18n.t('menu:edit.submenu.selectAll')}
+ {'Ctrl + A'}
+
+
+ {i18n.t('menu:edit.submenu.deletePou')}
+ {'Ctrl + Backspace'}
+
+
+
+
+ )
+}
diff --git a/src/frontend/components/_molecules/menu-bar/menus/file.tsx b/src/frontend/components/_molecules/menu-bar/menus/file.tsx
new file mode 100644
index 000000000..0f4c1e2bf
--- /dev/null
+++ b/src/frontend/components/_molecules/menu-bar/menus/file.tsx
@@ -0,0 +1,155 @@
+import * as MenuPrimitive from '@radix-ui/react-menubar'
+import { useCallback, useEffect } from 'react'
+
+import { useCapabilities, useProject } from '../../../../../middleware/shared/providers'
+import { useHandleRemoveTab } from '../../../../hooks/use-remove-tab'
+import { i18n } from '../../../../locales/i18n'
+import { useOpenPLCStore } from '../../../../store'
+import { prepareSavePayload } from '../../../../utils/save-project'
+import { toast } from '../../../_features/[app]/toast/use-toast'
+import { MenuClasses } from '../constants'
+
+export const FileMenu = () => {
+ const projectPort = useProject()
+ const capabilities = useCapabilities()
+ const {
+ project,
+ editor: activeEditor,
+ editors,
+ deviceDefinitions,
+ workspace: { editingState },
+ workspaceActions: { setEditingState },
+ sharedWorkspaceActions: { closeProject },
+ fileActions: { setAllToSaved },
+ snapshotActions: { markAllSaved },
+ } = useOpenPLCStore()
+
+ const { handleRemoveTab, selectedTab, setSelectedTab } = useHandleRemoveTab()
+
+ useEffect(() => {
+ setSelectedTab(activeEditor.meta.name)
+ }, [activeEditor])
+
+ const { TRIGGER, CONTENT, ITEM, ACCELERATOR, SEPARATOR } = MenuClasses
+
+ const isSaving = editingState === 'save-request'
+
+ const executeSave = useCallback(async () => {
+ setEditingState('save-request')
+ toast({
+ title: 'Save changes',
+ description: 'Trying to save the changes in the project file.',
+ variant: 'warn',
+ })
+
+ try {
+ const params = prepareSavePayload({
+ projectPath: project.meta.path,
+ projectName: project.meta.name,
+ projectData: project.data,
+ deviceConfiguration: deviceDefinitions.configuration,
+ devicePinMapping: deviceDefinitions.pinMapping.pins,
+ editors,
+ activeEditor,
+ })
+
+ const res = await projectPort.saveProject(params)
+ if (res.success) {
+ setEditingState('saved')
+ setAllToSaved()
+ markAllSaved()
+ toast({
+ title: 'Changes saved!',
+ description: 'The project was saved successfully!',
+ variant: 'default',
+ })
+ } else {
+ setEditingState('unsaved')
+ toast({
+ title: 'Error in the save request!',
+ description: res.error ?? 'Save failed',
+ variant: 'fail',
+ })
+ }
+ } catch {
+ setEditingState('unsaved')
+ toast({
+ title: 'Error in the save request!',
+ description: 'An unexpected error occurred while saving.',
+ variant: 'fail',
+ })
+ }
+ }, [project, deviceDefinitions, editors, activeEditor, projectPort, setEditingState, setAllToSaved])
+
+ const handleSave = () => {
+ if (activeEditor.meta.name && !isSaving) {
+ void executeSave()
+ }
+ }
+
+ const handleSaveProject = () => {
+ if (!isSaving) {
+ void executeSave()
+ }
+ }
+
+ const handleCloseTab = () => {
+ handleRemoveTab(selectedTab)
+ }
+
+ const handleCloseProject = () => {
+ closeProject()
+ }
+
+ return (
+
+ {i18n.t('menu:file.label')}
+
+
+
+ {i18n.t('menu:file.submenu.save')}
+ {'Ctrl + S'}
+
+
+ {i18n.t('menu:file.submenu.saveProject')}
+ {'Ctrl + Shift + S'}
+
+
+ {i18n.t('menu:file.submenu.closeTab')}
+ {'Ctrl + W'}
+
+
+ {i18n.t('menu:file.submenu.closeProject')}
+ {'Ctrl + Shift + W'}
+
+ {capabilities.hasProjectExport && (
+ <>
+
+
+ {i18n.t('menu:file.submenu.exportToPLCOpenXml')}
+
+ >
+ )}
+
+
+ {i18n.t('menu:file.submenu.pageSetup')}
+ {'Ctrl + Alt + P'}
+
+
+ {i18n.t('menu:file.submenu.preview')}
+ {'Ctrl + Shift + P'}
+
+
+ {i18n.t('menu:file.submenu.print')}
+ {'Ctrl + P'}
+
+
+
+ {i18n.t('menu:file.submenu.updates')}
+ {'Ctrl + U'}
+
+
+
+
+ )
+}
diff --git a/src/frontend/components/_molecules/menu-bar/menus/help.tsx b/src/frontend/components/_molecules/menu-bar/menus/help.tsx
new file mode 100644
index 000000000..66b55a6bb
--- /dev/null
+++ b/src/frontend/components/_molecules/menu-bar/menus/help.tsx
@@ -0,0 +1,45 @@
+import * as MenuPrimitive from '@radix-ui/react-menubar'
+
+import { useCapabilities } from '../../../../../middleware/shared/providers'
+import { i18n } from '../../../../locales/i18n'
+import { useOpenPLCStore } from '../../../../store'
+import { MenuClasses } from '../constants'
+
+export const HelpMenu = () => {
+ const capabilities = useCapabilities()
+ const {
+ workspaceActions: { setModalOpen },
+ } = useOpenPLCStore()
+ const { TRIGGER, CONTENT, ITEM, ACCELERATOR } = MenuClasses
+
+ const handleOpenCommunitySupport = () => {
+ try {
+ window.open('https://openplc.discussion.community/', '_blank')
+ } catch (error) {
+ console.error('Error opening link:', error)
+ }
+ }
+
+ const handleOpenAboutModal = () => {
+ setModalOpen('aboutOpenPlc', true)
+ }
+
+ return (
+
+ {i18n.t('menu:help.label')}
+
+
+
+ {i18n.t('menu:help.submenu.communitySupport')}
+ {'F1'}
+
+ {capabilities.hasAboutDialog && (
+
+ {i18n.t('menu:help.submenu.about')}
+
+ )}
+
+
+
+ )
+}
diff --git a/src/frontend/components/_molecules/menu-bar/menus/recent.tsx b/src/frontend/components/_molecules/menu-bar/menus/recent.tsx
new file mode 100644
index 000000000..243aabc1e
--- /dev/null
+++ b/src/frontend/components/_molecules/menu-bar/menus/recent.tsx
@@ -0,0 +1,27 @@
+import * as MenuPrimitive from '@radix-ui/react-menubar'
+
+import { cn } from '../../../../utils/cn'
+import { MenuClasses } from '../constants'
+
+export const RecentMenu = () => {
+ const { TRIGGER, CONTENT, ITEM } = MenuClasses
+
+ return (
+
+ Recent
+
+
+
+ No recent projects
+
+
+
+
+ )
+}
diff --git a/src2/frontend/components/_molecules/modal/index.tsx b/src/frontend/components/_molecules/modal/index.tsx
similarity index 99%
rename from src2/frontend/components/_molecules/modal/index.tsx
rename to src/frontend/components/_molecules/modal/index.tsx
index d4f77f33c..7007200d7 100644
--- a/src2/frontend/components/_molecules/modal/index.tsx
+++ b/src/frontend/components/_molecules/modal/index.tsx
@@ -1,8 +1,9 @@
-import { CloseIcon } from '../../../assets/icons/interface/Close'
import * as PrimitiveDialog from '@radix-ui/react-dialog'
-import { cn } from '../../../utils/cn'
import { ComponentPropsWithoutRef, ElementRef, forwardRef } from 'react'
+import { CloseIcon } from '../../../assets/icons/interface/Close'
+import { cn } from '../../../utils/cn'
+
const Modal = PrimitiveDialog.Root
const ModalTrigger = PrimitiveDialog.Trigger
diff --git a/src2/frontend/components/_molecules/pin-mapping-table/combobox-input.tsx b/src/frontend/components/_molecules/pin-mapping-table/combobox-input.tsx
similarity index 100%
rename from src2/frontend/components/_molecules/pin-mapping-table/combobox-input.tsx
rename to src/frontend/components/_molecules/pin-mapping-table/combobox-input.tsx
index 038c5adf8..6fd007945 100644
--- a/src2/frontend/components/_molecules/pin-mapping-table/combobox-input.tsx
+++ b/src/frontend/components/_molecules/pin-mapping-table/combobox-input.tsx
@@ -1,8 +1,8 @@
import { CellContext } from '@tanstack/react-table'
import { useCallback, useEffect, useState } from 'react'
-import { boardSelectors, pinSelectors } from '../../../hooks/use-store-selectors'
import type { DevicePin } from '../../../../middleware/shared/ports/types'
+import { boardSelectors, pinSelectors } from '../../../hooks/use-store-selectors'
import { GenericComboboxCell } from '../../_atoms/generic-table-inputs/generic-combobox-cell'
import { toast } from '../../_features/[app]/toast/use-toast'
diff --git a/src2/frontend/components/_molecules/pin-mapping-table/select-input.tsx b/src/frontend/components/_molecules/pin-mapping-table/select-input.tsx
similarity index 100%
rename from src2/frontend/components/_molecules/pin-mapping-table/select-input.tsx
rename to src/frontend/components/_molecules/pin-mapping-table/select-input.tsx
index 7f30f9ae2..24d8b401f 100644
--- a/src2/frontend/components/_molecules/pin-mapping-table/select-input.tsx
+++ b/src/frontend/components/_molecules/pin-mapping-table/select-input.tsx
@@ -1,8 +1,8 @@
-import type { DevicePin, PinType } from '../../../../middleware/shared/ports/types'
import { CellContext } from '@tanstack/react-table'
import { startCase } from 'lodash'
import { useCallback, useEffect, useState } from 'react'
+import type { DevicePin, PinType } from '../../../../middleware/shared/ports/types'
import { GenericSelectCell } from '../../_atoms/generic-table-inputs/generic-select-cell'
import { toast } from '../../_features/[app]/toast/use-toast'
diff --git a/src2/frontend/components/_molecules/pin-mapping-table/text-input.tsx b/src/frontend/components/_molecules/pin-mapping-table/text-input.tsx
similarity index 100%
rename from src2/frontend/components/_molecules/pin-mapping-table/text-input.tsx
rename to src/frontend/components/_molecules/pin-mapping-table/text-input.tsx
index 28aa97688..9a59954d1 100644
--- a/src2/frontend/components/_molecules/pin-mapping-table/text-input.tsx
+++ b/src/frontend/components/_molecules/pin-mapping-table/text-input.tsx
@@ -1,7 +1,7 @@
-import type { DevicePin } from '../../../../middleware/shared/ports/types'
import { CellContext } from '@tanstack/react-table'
import { useEffect, useState } from 'react'
+import type { DevicePin } from '../../../../middleware/shared/ports/types'
import { GenericTextCell } from '../../_atoms/generic-table-inputs/generic-text-cell'
import { toast } from '../../_features/[app]/toast/use-toast'
diff --git a/src2/frontend/components/_molecules/project-tree/index.tsx b/src/frontend/components/_molecules/project-tree/index.tsx
similarity index 96%
rename from src2/frontend/components/_molecules/project-tree/index.tsx
rename to src/frontend/components/_molecules/project-tree/index.tsx
index 20b476f66..0e6136a57 100644
--- a/src2/frontend/components/_molecules/project-tree/index.tsx
+++ b/src/frontend/components/_molecules/project-tree/index.tsx
@@ -1,8 +1,11 @@
import * as Popover from '@radix-ui/react-popover'
+import { ComponentPropsWithoutRef, ReactNode, useCallback, useEffect, useMemo, useRef, useState } from 'react'
+
import { ArrowIcon } from '../../../assets/icons/interface/Arrow'
import { CloseIcon } from '../../../assets/icons/interface/Close'
import { ConfigIcon } from '../../../assets/icons/interface/Config'
import { DeviceTransferIcon } from '../../../assets/icons/interface/DeviceTransfer'
+import { DuplicateIcon } from '../../../assets/icons/interface/Duplicate'
import { MoreOptionsIcon } from '../../../assets/icons/interface/MoreOptions'
import { PencilIcon } from '../../../assets/icons/interface/Pencil'
import { ArrayIcon } from '../../../assets/icons/project/Array'
@@ -15,22 +18,20 @@ import { FunctionIcon } from '../../../assets/icons/project/Function'
import { FunctionBlockIcon } from '../../../assets/icons/project/FunctionBlock'
import { ILIcon } from '../../../assets/icons/project/IL'
import { LDIcon } from '../../../assets/icons/project/LD'
+import { OrchestratorIcon } from '../../../assets/icons/project/Orchestrator'
import { PLCIcon } from '../../../assets/icons/project/PLC'
import { ProgramIcon } from '../../../assets/icons/project/Program'
import { PythonIcon } from '../../../assets/icons/project/Python'
import { RemoteDeviceIcon } from '../../../assets/icons/project/RemoteDevice'
import { ResourceIcon } from '../../../assets/icons/project/Resource'
+import { ServerIcon } from '../../../assets/icons/project/Server'
import { SFCIcon } from '../../../assets/icons/project/SFC'
import { STIcon } from '../../../assets/icons/project/ST'
-import { ServerIcon } from '../../../assets/icons/project/Server'
import { StructureIcon } from '../../../assets/icons/project/Structure'
-import { DuplicateIcon } from '../../../assets/icons/interface/Duplicate'
import { useOpenPLCStore } from '../../../store'
import { WorkspaceProjectTreeLeafType } from '../../../store/slices/workspace/types'
import { cn } from '../../../utils/cn'
import { isUnsaved, unsavedLabel } from '../../../utils/unsaved-label'
-import { ComponentPropsWithoutRef, ReactNode, useCallback, useEffect, useMemo, useRef, useState } from 'react'
-
import { toast } from '../../_features/[app]/toast/use-toast'
const pousAllLanguages = ['il', 'st', 'python', 'cpp', 'ld', 'sfc', 'fbd'] as const
@@ -114,7 +115,7 @@ const ProjectTreeBranch = ({ branchTarget, children, ...res }: ProjectTreeBranch
const { BranchIcon, label } = BranchSources[branchTarget]
const handleBranchVisibility = useCallback(() => setBranchIsOpen(!branchIsOpen), [branchIsOpen])
const hasAssociatedPou =
- pous.some((pou) => pou.type === branchTarget) ||
+ pous.some((pou) => pou.pouType === branchTarget) ||
branchTarget === 'device' ||
(branchTarget === 'data-type' && dataTypes.length > 0) ||
(branchTarget === 'server' && servers !== undefined && servers.length > 0) ||
@@ -252,6 +253,7 @@ type IProjectTreeLeafProps = ComponentPropsWithoutRef<'li'> & {
| 'res'
| 'devConfig'
| 'devPin'
+ | 'devOrchestrators'
| 'server'
| 'remoteDevice'
leafType: WorkspaceProjectTreeLeafType
@@ -272,6 +274,7 @@ const LeafSources = {
res: { LeafIcon: ResourceIcon },
devConfig: { LeafIcon: ConfigIcon },
devPin: { LeafIcon: DeviceTransferIcon },
+ devOrchestrators: { LeafIcon: OrchestratorIcon },
server: { LeafIcon: ServerIcon },
remoteDevice: { LeafIcon: RemoteDeviceIcon },
}
@@ -320,7 +323,7 @@ const ProjectTreeLeaf = ({ leafLang, leafType, label, onClick: handleLeafClick,
setSelectedProjectTreeLeaf({ label, type: leafType })
}
- const handleRenameFile = async (newLabel: string) => {
+ const handleRenameFile = (newLabel: string) => {
setIsEditing(false)
if (!isAPou && !isDatatype && !isServer && !isRemoteDevice) {
@@ -342,39 +345,39 @@ const ProjectTreeLeaf = ({ leafLang, leafType, label, onClick: handleLeafClick,
}
if (isAPou) {
- const res = await renamePou(label, newLabel)
- if (!res.success) {
+ const res = renamePou(label, newLabel)
+ if (!res.ok) {
setNewLabel(label || '')
}
return
}
if (isDatatype) {
- const res = await renameDatatype(label, newLabel)
- if (!res.success) {
+ const res = renameDatatype(label, newLabel)
+ if (!res.ok) {
setNewLabel(label || '')
}
return
}
if (isServer) {
- const res = await renameServer(label, newLabel)
- if (!res.success) {
+ const res = renameServer(label, newLabel)
+ if (!res.ok) {
setNewLabel(label || '')
}
return
}
if (isRemoteDevice) {
- const res = await renameRemoteDevice(label, newLabel)
- if (!res.success) {
+ const res = renameRemoteDevice(label, newLabel)
+ if (!res.ok) {
setNewLabel(label || '')
}
return
}
}
- const handleDuplicateFile = async () => {
+ const handleDuplicateFile = () => {
if (!isAPou && !isDatatype) {
toast({
title: 'Error',
@@ -394,12 +397,12 @@ const ProjectTreeLeaf = ({ leafLang, leafType, label, onClick: handleLeafClick,
}
if (isAPou) {
- await duplicatePou(label)
+ duplicatePou(label, `${label}_copy`)
return
}
if (isDatatype) {
- await duplicateDatatype(label)
+ duplicateDatatype(label, `${label}_copy`)
return
}
diff --git a/src2/frontend/components/_molecules/rename-impact-modal/index.tsx b/src/frontend/components/_molecules/rename-impact-modal/index.tsx
similarity index 99%
rename from src2/frontend/components/_molecules/rename-impact-modal/index.tsx
rename to src/frontend/components/_molecules/rename-impact-modal/index.tsx
index ece6d93e2..6ccd2d5d7 100644
--- a/src2/frontend/components/_molecules/rename-impact-modal/index.tsx
+++ b/src/frontend/components/_molecules/rename-impact-modal/index.tsx
@@ -1,5 +1,4 @@
import type { ReferenceImpactAnalysis } from '../../../utils/variable-reference-types'
-
import { Modal, ModalContent, ModalFooter, ModalHeader, ModalTitle } from '../modal'
type RenameImpactModalProps = {
diff --git a/src2/frontend/components/_molecules/search/index.tsx b/src/frontend/components/_molecules/search/index.tsx
similarity index 100%
rename from src2/frontend/components/_molecules/search/index.tsx
rename to src/frontend/components/_molecules/search/index.tsx
index d41e3fda1..1f70cb096 100644
--- a/src2/frontend/components/_molecules/search/index.tsx
+++ b/src/frontend/components/_molecules/search/index.tsx
@@ -1,6 +1,6 @@
-import { MagnifierIcon } from '../../../assets/icons/interface/Magnifier'
import { ComponentPropsWithoutRef, createRef } from 'react'
+import { MagnifierIcon } from '../../../assets/icons/interface/Magnifier'
import { InputWithRef } from '../../_atoms/input'
type ISearchProps = ComponentPropsWithoutRef<'form'>
diff --git a/src2/frontend/components/_molecules/select-field/index.tsx b/src/frontend/components/_molecules/select-field/index.tsx
similarity index 99%
rename from src2/frontend/components/_molecules/select-field/index.tsx
rename to src/frontend/components/_molecules/select-field/index.tsx
index 167259401..3167cd75f 100644
--- a/src2/frontend/components/_molecules/select-field/index.tsx
+++ b/src/frontend/components/_molecules/select-field/index.tsx
@@ -1,5 +1,4 @@
import { cn } from '../../../utils/cn'
-
import { Select, SelectContent, SelectItem, SelectTrigger } from '../../_atoms/select'
const SelectField = ({
diff --git a/src/frontend/components/_molecules/tabs/index.tsx b/src/frontend/components/_molecules/tabs/index.tsx
new file mode 100644
index 000000000..890f4516a
--- /dev/null
+++ b/src/frontend/components/_molecules/tabs/index.tsx
@@ -0,0 +1,77 @@
+import { useEffect, useRef } from 'react'
+
+import { useHandleRemoveTab } from '../../../hooks/use-remove-tab'
+import { useOpenPLCStore } from '../../../store'
+import type { TabsProps } from '../../../store/slices/tabs'
+import { CreateEditorObjectFromTab } from '../../../store/slices/tabs/utils'
+import { Tab } from '../../_atoms/tab'
+import { TabList } from '../../_atoms/tab-list'
+
+const Tabs = () => {
+ const {
+ tabs,
+ editor,
+ tabsActions: { sortTabs },
+ editorActions: { setEditor, getEditorFromEditors },
+ } = useOpenPLCStore()
+ const { handleRemoveTab, selectedTab, setSelectedTab } = useHandleRemoveTab()
+ const hasTabs = tabs.length > 0
+ const dndTab = useRef(0)
+ const replaceTab = useRef(0)
+
+ const handleSort = () => {
+ const tabClone = [...tabs]
+ const draggedTab = tabClone[dndTab.current]
+ tabClone.splice(dndTab.current, 1)
+ tabClone.splice(replaceTab.current, 0, draggedTab)
+ sortTabs(tabClone)
+ }
+ /**
+ * Todo: this tab handler should be refactored to fit all possibles cases
+ * @param tab the selected tab
+ */
+ const handleClickedTab = (tab: TabsProps) => {
+ if (tab.name === selectedTab) return
+ setSelectedTab(tab.name)
+ const candidate = getEditorFromEditors(tab.name)
+ if (!candidate) {
+ setEditor(CreateEditorObjectFromTab(tab))
+ return
+ }
+ setEditor(candidate)
+ }
+
+ const handleDragStart = ({ tab, idx }: { tab: TabsProps; idx: number }) => {
+ dndTab.current = idx
+ setSelectedTab(tab.name)
+ setEditor(CreateEditorObjectFromTab(tab))
+ }
+ const handleDragEnter = (idx: number) => {
+ replaceTab.current = idx
+ }
+
+ useEffect(() => {
+ setSelectedTab(editor.meta.name)
+ }, [editor.meta.name, setSelectedTab])
+
+ return (
+
+ {hasTabs &&
+ tabs.map((element, idx) => (
+ handleDragStart({ tab: element, idx })}
+ onDragEnter={() => handleDragEnter(idx)}
+ onDragEnd={() => handleSort()}
+ onDragOver={(e) => e.preventDefault()}
+ handleClickedTab={() => handleClickedTab(element)}
+ handleDeleteTab={() => handleRemoveTab(element.name)}
+ key={element.name}
+ fileName={element.name}
+ fileDerivation={element.elementType}
+ currentTab={selectedTab === element.name}
+ />
+ ))}
+
+ )
+}
+export { Tabs }
diff --git a/src2/frontend/components/_molecules/task-table/editable-cell.tsx b/src/frontend/components/_molecules/task-table/editable-cell.tsx
similarity index 100%
rename from src2/frontend/components/_molecules/task-table/editable-cell.tsx
rename to src/frontend/components/_molecules/task-table/editable-cell.tsx
index 0e2ba7796..59277cdce 100644
--- a/src2/frontend/components/_molecules/task-table/editable-cell.tsx
+++ b/src/frontend/components/_molecules/task-table/editable-cell.tsx
@@ -1,10 +1,10 @@
-import type { PLCTask } from '../../../../middleware/shared/ports/types'
-import type { ProjectResponse } from '../../../store/slices/project'
-import { useOpenPLCStore } from '../../../store'
-import { cn } from '../../../utils/cn'
import type { CellContext, RowData } from '@tanstack/react-table'
import { useEffect, useState } from 'react'
+import type { PLCTask } from '../../../../middleware/shared/ports/types'
+import { useOpenPLCStore } from '../../../store'
+import type { ProjectResponse } from '../../../store/slices/project'
+import { cn } from '../../../utils/cn'
import { HighlightedText } from '../../_atoms/highlighted-text'
import { InputWithRef } from '../../_atoms/input'
import { useToast } from '../../_features/[app]/toast/use-toast'
diff --git a/src2/frontend/components/_molecules/task-table/index.tsx b/src/frontend/components/_molecules/task-table/index.tsx
similarity index 100%
rename from src2/frontend/components/_molecules/task-table/index.tsx
rename to src/frontend/components/_molecules/task-table/index.tsx
index 99cec1f8b..23237074f 100644
--- a/src2/frontend/components/_molecules/task-table/index.tsx
+++ b/src/frontend/components/_molecules/task-table/index.tsx
@@ -1,6 +1,6 @@
-import type { PLCTask } from '../../../../middleware/shared/ports/types'
import { createColumnHelper } from '@tanstack/react-table'
+import type { PLCTask } from '../../../../middleware/shared/ports/types'
import { usePouSnapshot } from '../../../hooks/use-pou-snapshot'
import { useOpenPLCStore } from '../../../store'
import { GenericTable } from '../../_atoms/generic-table'
diff --git a/src2/frontend/components/_molecules/task-table/selectable-cell.tsx b/src/frontend/components/_molecules/task-table/selectable-cell.tsx
similarity index 100%
rename from src2/frontend/components/_molecules/task-table/selectable-cell.tsx
rename to src/frontend/components/_molecules/task-table/selectable-cell.tsx
index 2b4ca0cfd..03c0656c9 100644
--- a/src2/frontend/components/_molecules/task-table/selectable-cell.tsx
+++ b/src/frontend/components/_molecules/task-table/selectable-cell.tsx
@@ -1,12 +1,12 @@
-import type { PLCTask } from '../../../../middleware/shared/ports/types'
-import { cn } from '../../../utils/cn'
import type { CellContext } from '@tanstack/react-table'
import _ from 'lodash'
import { useEffect, useMemo, useState } from 'react'
+import type { PLCTask } from '../../../../middleware/shared/ports/types'
+import { cn } from '../../../utils/cn'
import { Select, SelectContent, SelectItem, SelectTrigger } from '../../_atoms/select'
-import { Modal, ModalContent, ModalTitle, ModalTrigger } from '../modal'
import ArrowButtonGroup from '../../_features/[workspace]/editor/graphical/elements/arrow-button-group'
+import { Modal, ModalContent, ModalTitle, ModalTrigger } from '../modal'
type ISelectableCellProps = CellContext & { editable?: boolean }
diff --git a/src/renderer/components/_molecules/toast/index.tsx b/src/frontend/components/_molecules/toast/index.tsx
similarity index 100%
rename from src/renderer/components/_molecules/toast/index.tsx
rename to src/frontend/components/_molecules/toast/index.tsx
diff --git a/src2/frontend/components/_molecules/type-change-modal/index.tsx b/src/frontend/components/_molecules/type-change-modal/index.tsx
similarity index 99%
rename from src2/frontend/components/_molecules/type-change-modal/index.tsx
rename to src/frontend/components/_molecules/type-change-modal/index.tsx
index 4d84e5156..a918676aa 100644
--- a/src2/frontend/components/_molecules/type-change-modal/index.tsx
+++ b/src/frontend/components/_molecules/type-change-modal/index.tsx
@@ -1,6 +1,5 @@
-import type { TypeChangeValidationResult } from '../../../store/slices/project/validation/type-change'
import type { PLCVariable } from '../../../../middleware/shared/ports/types'
-
+import type { TypeChangeValidationResult } from '../../../store/slices/project/validation/type-change'
import { Modal, ModalContent, ModalFooter, ModalHeader, ModalTitle } from '../modal'
type TypeChangeModalProps = {
diff --git a/src2/frontend/components/_molecules/variables-panel/index.tsx b/src/frontend/components/_molecules/variables-panel/index.tsx
similarity index 100%
rename from src2/frontend/components/_molecules/variables-panel/index.tsx
rename to src/frontend/components/_molecules/variables-panel/index.tsx
index 95877656a..f9f5bccd1 100644
--- a/src2/frontend/components/_molecules/variables-panel/index.tsx
+++ b/src/frontend/components/_molecules/variables-panel/index.tsx
@@ -1,9 +1,9 @@
import { useCallback, useEffect, useRef, useState } from 'react'
import { createPortal } from 'react-dom'
+import type { DebugTreeNode } from '../../../../middleware/shared/ports/types'
import ViewIcon from '../../../assets/icons/interface/View'
import ZapIcon from '../../../assets/icons/interface/Zap'
-import type { DebugTreeNode } from '../../../../middleware/shared/ports/types'
import { cn } from '../../../utils/cn'
import {
floatToBuffer,
diff --git a/src2/frontend/components/_molecules/variables-table/editable-cell.tsx b/src/frontend/components/_molecules/variables-table/editable-cell.tsx
similarity index 98%
rename from src2/frontend/components/_molecules/variables-table/editable-cell.tsx
rename to src/frontend/components/_molecules/variables-table/editable-cell.tsx
index 12ca65c57..dfc6f4d70 100644
--- a/src2/frontend/components/_molecules/variables-table/editable-cell.tsx
+++ b/src/frontend/components/_molecules/variables-table/editable-cell.tsx
@@ -1,22 +1,22 @@
import * as PrimitivePopover from '@radix-ui/react-popover'
+import type { CellContext, RowData } from '@tanstack/react-table'
+import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
+
import type { PLCVariable } from '../../../../middleware/shared/ports/types'
import { pinSelectors, remoteDeviceSelectors } from '../../../hooks/use-store-selectors'
import { useOpenPLCStore } from '../../../store'
import { ProjectResponse } from '../../../store/slices/project'
+import { cn } from '../../../utils/cn'
+import { isLegalIdentifier, sanitizeVariableInput } from '../../../utils/keywords'
import { buildRemoteDeviceOptionGroups } from '../../../utils/remote-device-options'
import {
findAllReferencesToVariable,
propagateVariableRename,
type ReferenceImpactAnalysis,
} from '../../../utils/variable-references'
-import { cn } from '../../../utils/cn'
-import { isLegalIdentifier, sanitizeVariableInput } from '../../../utils/keywords'
-import type { CellContext, RowData } from '@tanstack/react-table'
-import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
-
+import { GenericComboboxCell } from '../../_atoms/generic-table-inputs/generic-combobox-cell'
import { HighlightedText } from '../../_atoms/highlighted-text'
import { InputWithRef } from '../../_atoms/input'
-import { GenericComboboxCell } from '../../_atoms/generic-table-inputs/generic-combobox-cell'
import { useToast } from '../../_features/[app]/toast/use-toast'
import { RenameImpactModal } from '../rename-impact-modal'
@@ -49,7 +49,7 @@ const EditableNameCell = ({
searchQuery,
projectActions: { getVariable, updatePou, updateVariable },
project: {
- data: { pous, configuration },
+ data: { pous, configurations },
},
workspace: { isDebuggerVisible },
} = useOpenPLCStore()
@@ -61,7 +61,7 @@ const EditableNameCell = ({
const [impactAnalysis, setImpactAnalysis] = useState(null)
const confirmResolveRef = useRef<(v: boolean) => void>()
- const globalVariables = configuration.resource.globalVariables
+ const globalVariables = configurations.resource.globalVariables
const isExternalVariable = variable?.class === 'external'
@@ -248,7 +248,7 @@ const EditableNameCell = ({
useEffect(() => {
setVariable(
getVariable({
- variableId: table.options.data[index].id,
+ rowId: index,
scope,
associatedPou: editor.meta.name,
}),
@@ -389,7 +389,7 @@ const EditableInitialValueCell = ({
useEffect(() => {
setVariable(
getVariable({
- variableId: table.options.data[index].id,
+ rowId: index,
scope,
associatedPou: editor.meta.name,
}),
@@ -478,7 +478,7 @@ const EditableLocationCell = ({
useEffect(() => {
setVariable(
getVariable({
- variableId: table.options.data[index].id,
+ rowId: index,
scope,
associatedPou: editor.meta.name,
}),
diff --git a/src2/frontend/components/_molecules/variables-table/elements/array-modal.tsx b/src/frontend/components/_molecules/variables-table/elements/array-modal.tsx
similarity index 95%
rename from src2/frontend/components/_molecules/variables-table/elements/array-modal.tsx
rename to src/frontend/components/_molecules/variables-table/elements/array-modal.tsx
index fdc6727f6..7db33b2ea 100644
--- a/src2/frontend/components/_molecules/variables-table/elements/array-modal.tsx
+++ b/src/frontend/components/_molecules/variables-table/elements/array-modal.tsx
@@ -1,11 +1,11 @@
import { useEffect, useState } from 'react'
import type { z } from 'zod'
-import { DimensionsModal } from '../../../_atoms/dimensions-modal'
-import { toast } from '../../../_features/[app]/toast/use-toast'
+import { baseTypeSchema } from '../../../../../middleware/shared/ports/plc-schemas'
import { useOpenPLCStore } from '../../../../store'
import { arrayValidation } from '../../../../store/slices/project/validation/variables'
-import { baseTypeSchema } from '../../../../../middleware/shared/ports/plc-schemas'
+import { DimensionsModal } from '../../../_atoms/dimensions-modal'
+import { toast } from '../../../_features/[app]/toast/use-toast'
type BaseType = z.infer
@@ -88,11 +88,11 @@ export const ArrayModal = ({
useEffect(() => {
const variable = pous
- .find((pou) => pou.data.name === name)
- ?.data.variables.find((variable) => variable.name === variableName)
+ .find((pou) => pou.name === name)
+ ?.interface?.variables?.find((variable) => variable.name === variableName)
if (!variable) return
- if (variable.type.definition === 'array') {
+ if (variable.type.definition === 'array' && variable.type.data) {
setDimensions(variable.type.data.dimensions.map((dimension) => dimension.dimension))
setTypeValue(variable.type.data.baseType.value)
} else {
@@ -130,7 +130,7 @@ export const ArrayModal = ({
setSelectedInput((index + 1).toString())
}
- const handleUpdateType = (value: BaseType) => {
+ const handleUpdateType = (value: string) => {
setTypeValue(value)
}
@@ -175,7 +175,6 @@ export const ArrayModal = ({
definition: 'array',
value: formatArrayName,
data: {
- // @ts-expect-error - This is a valid operation. This is being fixed.
baseType: {
definition: isBaseType ? 'base-type' : 'user-data-type',
value: typeValue,
diff --git a/src2/frontend/components/_molecules/variables-table/index.tsx b/src/frontend/components/_molecules/variables-table/index.tsx
similarity index 94%
rename from src2/frontend/components/_molecules/variables-table/index.tsx
rename to src/frontend/components/_molecules/variables-table/index.tsx
index 1de9647af..25c9be4d2 100644
--- a/src2/frontend/components/_molecules/variables-table/index.tsx
+++ b/src/frontend/components/_molecules/variables-table/index.tsx
@@ -1,6 +1,6 @@
-import type { PLCVariable } from '../../../../middleware/shared/ports/types'
import { ColumnFiltersState, createColumnHelper, OnChangeFn } from '@tanstack/react-table'
+import type { PLCVariable } from '../../../../middleware/shared/ports/types'
import { usePouSnapshot } from '../../../hooks/use-pou-snapshot'
import { useOpenPLCStore } from '../../../store'
import { GenericTable } from '../../_atoms/generic-table'
@@ -138,6 +138,7 @@ const VariablesTable = ({
data: { pous },
},
projectActions: { updateVariable },
+ sharedWorkspaceActions: { handleFileAndWorkspaceSavedState },
} = useOpenPLCStore()
const { captureAndPush } = usePouSnapshot()
@@ -159,14 +160,18 @@ const VariablesTable = ({
}
}
- return updateVariable({
+ const result = updateVariable({
scope: 'local',
associatedPou: name,
- variableId: tableData[rowIndex].id,
+ rowId: rowIndex,
data: {
[columnId]: value,
},
})
+ if (result.ok) {
+ handleFileAndWorkspaceSavedState(name)
+ }
+ return result
}}
tableContext='Variables'
columnFilters={columnFilters}
diff --git a/src2/frontend/components/_molecules/variables-table/selectable-cell.tsx b/src/frontend/components/_molecules/variables-table/selectable-cell.tsx
similarity index 97%
rename from src2/frontend/components/_molecules/variables-table/selectable-cell.tsx
rename to src/frontend/components/_molecules/variables-table/selectable-cell.tsx
index 45e681db1..7af575a2f 100644
--- a/src2/frontend/components/_molecules/variables-table/selectable-cell.tsx
+++ b/src/frontend/components/_molecules/variables-table/selectable-cell.tsx
@@ -1,16 +1,16 @@
import * as PrimitiveDropdown from '@radix-ui/react-dropdown-menu'
-import { ArrowIcon } from '../../../assets/icons/interface/Arrow'
-import { DebuggerIcon } from '../../../assets/icons/interface/Debugger'
-import { useOpenPLCStore } from '../../../store'
-import { TypeChangeValidationResult, validateTypeChange, } from '../../../store/slices/project/validation/type-change'
-import { syncNodesWithVariables, syncNodesWithVariablesFBD } from '../../../utils/graphical/sync-nodes-with-variables'
-import type { PLCVariable } from '../../../../middleware/shared/ports/types'
-import { baseTypeSchema } from '../../../../middleware/shared/ports/plc-schemas'
-import { cn } from '../../../utils/cn'
import type { CellContext } from '@tanstack/react-table'
import _ from 'lodash'
import { useEffect, useState } from 'react'
+import { baseTypeSchema } from '../../../../middleware/shared/ports/plc-schemas'
+import type { PLCVariable } from '../../../../middleware/shared/ports/types'
+import { ArrowIcon } from '../../../assets/icons/interface/Arrow'
+import { DebuggerIcon } from '../../../assets/icons/interface/Debugger'
+import { useOpenPLCStore } from '../../../store'
+import { TypeChangeValidationResult, validateTypeChange } from '../../../store/slices/project/validation/type-change'
+import { cn } from '../../../utils/cn'
+import { syncNodesWithVariables, syncNodesWithVariablesFBD } from '../../../utils/graphical/sync-nodes-with-variables'
import { InputWithRef } from '../../_atoms/input'
import { Select, SelectContent, SelectItem, SelectTrigger } from '../../_atoms/select'
import { TypeChangeModal } from '../type-change-modal'
@@ -74,7 +74,7 @@ const SelectableTypeCell = ({
{
definition: 'system',
values: sliceLibraries.system.flatMap((library) =>
- library.pous.filter((pou) => pou.pouType === 'function-block').map((pou) => pou.name.toUpperCase()),
+ library.pous.filter((pou) => pou.type === 'function-block').map((pou) => pou.name.toUpperCase()),
),
},
{
@@ -82,11 +82,11 @@ const SelectableTypeCell = ({
values: sliceLibraries.user
.filter((userLibrary) => userLibrary.name !== editor.meta.name)
.flatMap((userLibrary) =>
- 'pous' in userLibrary && Array.isArray((userLibrary as { pous: { pouType: string; name: string }[] }).pous)
- ? (userLibrary as { pous: { pouType: string; name: string }[] }).pous
- .filter((pou) => pou.pouType === 'function-block')
+ 'pous' in userLibrary && Array.isArray((userLibrary as { pous: { type: string; name: string }[] }).pous)
+ ? (userLibrary as { pous: { type: string; name: string }[] }).pous
+ .filter((pou) => pou.type === 'function-block')
.map((pou) => pou.name.toUpperCase())
- : userLibrary.pouType === 'function-block'
+ : userLibrary.type === 'function-block'
? [userLibrary.name.toUpperCase()]
: [],
),
@@ -271,10 +271,7 @@ const SelectableTypeCell = ({
/>
)}
-
+
{
const windowPort = useWindow()
diff --git a/src2/frontend/components/_molecules/workspace-activity-bar/default/chat.tsx b/src/frontend/components/_molecules/workspace-activity-bar/default/chat.tsx
similarity index 99%
rename from src2/frontend/components/_molecules/workspace-activity-bar/default/chat.tsx
rename to src/frontend/components/_molecules/workspace-activity-bar/default/chat.tsx
index c9c3570d5..2e76ff302 100644
--- a/src2/frontend/components/_molecules/workspace-activity-bar/default/chat.tsx
+++ b/src/frontend/components/_molecules/workspace-activity-bar/default/chat.tsx
@@ -1,6 +1,5 @@
import { useOpenPLCStore } from '../../../../store'
import { cn } from '../../../../utils/cn'
-
import { ActivityBarButton } from '../../../_atoms/buttons/activity-bar'
export const ChatButton = () => {
diff --git a/src2/frontend/components/_molecules/workspace-activity-bar/default/debugger.tsx b/src/frontend/components/_molecules/workspace-activity-bar/default/debugger.tsx
similarity index 99%
rename from src2/frontend/components/_molecules/workspace-activity-bar/default/debugger.tsx
rename to src/frontend/components/_molecules/workspace-activity-bar/default/debugger.tsx
index f136097c3..6791c971d 100644
--- a/src2/frontend/components/_molecules/workspace-activity-bar/default/debugger.tsx
+++ b/src/frontend/components/_molecules/workspace-activity-bar/default/debugger.tsx
@@ -1,6 +1,7 @@
+import { ComponentPropsWithoutRef } from 'react'
+
import { DebuggerIcon } from '../../../../assets/icons/interface/Debugger'
import { ActivityBarButton } from '../../../_atoms/buttons/activity-bar'
-import { ComponentPropsWithoutRef } from 'react'
type DebuggerButtonProps = ComponentPropsWithoutRef & {
isActive?: boolean
diff --git a/src/frontend/components/_molecules/workspace-activity-bar/default/download.tsx b/src/frontend/components/_molecules/workspace-activity-bar/default/download.tsx
new file mode 100644
index 000000000..1544144ff
--- /dev/null
+++ b/src/frontend/components/_molecules/workspace-activity-bar/default/download.tsx
@@ -0,0 +1,14 @@
+import { DownloadIcon } from '../../../../assets/icons/interface/Download'
+import { ActivityBarButton } from '../../../_atoms/buttons/activity-bar'
+
+type DownloadButtonProps = { onClick?: () => void; disabled?: boolean; className?: string }
+
+const DownloadButton = ({ onClick, disabled, className }: DownloadButtonProps) => {
+ return (
+
+
+
+ )
+}
+
+export { DownloadButton }
diff --git a/src2/frontend/components/_molecules/workspace-activity-bar/default/exit.tsx b/src/frontend/components/_molecules/workspace-activity-bar/default/exit.tsx
similarity index 99%
rename from src2/frontend/components/_molecules/workspace-activity-bar/default/exit.tsx
rename to src/frontend/components/_molecules/workspace-activity-bar/default/exit.tsx
index a240e76d3..5704e5956 100644
--- a/src2/frontend/components/_molecules/workspace-activity-bar/default/exit.tsx
+++ b/src/frontend/components/_molecules/workspace-activity-bar/default/exit.tsx
@@ -1,7 +1,8 @@
+import { ComponentPropsWithoutRef } from 'react'
+
import { CloseFilledIcon } from '../../../../assets/icons/interface/Close'
import { StickArrowIcon } from '../../../../assets/icons/interface/StickArrow'
import { ActivityBarButton } from '../../../_atoms/buttons/activity-bar'
-import { ComponentPropsWithoutRef } from 'react'
export const ExitButton = ({ onClick }: ComponentPropsWithoutRef<'button'>) => {
return (
diff --git a/src2/frontend/components/_molecules/workspace-activity-bar/default/play.tsx b/src/frontend/components/_molecules/workspace-activity-bar/default/play.tsx
similarity index 99%
rename from src2/frontend/components/_molecules/workspace-activity-bar/default/play.tsx
rename to src/frontend/components/_molecules/workspace-activity-bar/default/play.tsx
index 998200a8a..f39fd155e 100644
--- a/src2/frontend/components/_molecules/workspace-activity-bar/default/play.tsx
+++ b/src/frontend/components/_molecules/workspace-activity-bar/default/play.tsx
@@ -1,6 +1,7 @@
+import { ComponentPropsWithoutRef, ReactNode } from 'react'
+
import { PlayIcon } from '../../../../assets/icons/interface/Play'
import { ActivityBarButton } from '../../../_atoms/buttons/activity-bar'
-import { ComponentPropsWithoutRef, ReactNode } from 'react'
type PlayButtonProps = ComponentPropsWithoutRef & {
children?: ReactNode
diff --git a/src2/frontend/components/_molecules/workspace-activity-bar/default/search.tsx b/src/frontend/components/_molecules/workspace-activity-bar/default/search.tsx
similarity index 99%
rename from src2/frontend/components/_molecules/workspace-activity-bar/default/search.tsx
rename to src/frontend/components/_molecules/workspace-activity-bar/default/search.tsx
index 8605a444e..c44a22379 100644
--- a/src2/frontend/components/_molecules/workspace-activity-bar/default/search.tsx
+++ b/src/frontend/components/_molecules/workspace-activity-bar/default/search.tsx
@@ -1,6 +1,5 @@
import { SearchIcon } from '../../../../assets/icons/interface/Search'
import { useOpenPLCStore } from '../../../../store'
-
import { ActivityBarButton } from '../../../_atoms/buttons/activity-bar'
import SearchInProject from '../../../_features/[workspace]/editor/search-in-project'
import { Modal, ModalContent, ModalTitle, ModalTrigger } from '../../modal'
diff --git a/src2/frontend/components/_molecules/workspace-activity-bar/default/zoom.tsx b/src/frontend/components/_molecules/workspace-activity-bar/default/zoom.tsx
similarity index 100%
rename from src2/frontend/components/_molecules/workspace-activity-bar/default/zoom.tsx
rename to src/frontend/components/_molecules/workspace-activity-bar/default/zoom.tsx
index 685d667fe..8ebde914b 100644
--- a/src2/frontend/components/_molecules/workspace-activity-bar/default/zoom.tsx
+++ b/src/frontend/components/_molecules/workspace-activity-bar/default/zoom.tsx
@@ -1,6 +1,6 @@
-import { ZoomInOut } from '../../../../assets/icons/interface/ZoomInOut'
import { ComponentPropsWithoutRef } from 'react'
+import { ZoomInOut } from '../../../../assets/icons/interface/ZoomInOut'
import { ActivityBarButton } from '../../../_atoms/buttons/activity-bar'
export const ZoomButton = (props: ComponentPropsWithoutRef<'button'>) => {
diff --git a/src2/frontend/components/_molecules/workspace-activity-bar/fbd/block.tsx b/src/frontend/components/_molecules/workspace-activity-bar/fbd/block.tsx
similarity index 99%
rename from src2/frontend/components/_molecules/workspace-activity-bar/fbd/block.tsx
rename to src/frontend/components/_molecules/workspace-activity-bar/fbd/block.tsx
index e900d0a37..dc6370777 100644
--- a/src2/frontend/components/_molecules/workspace-activity-bar/fbd/block.tsx
+++ b/src/frontend/components/_molecules/workspace-activity-bar/fbd/block.tsx
@@ -1,6 +1,7 @@
+import { ComponentPropsWithoutRef } from 'react'
+
import BlockIcon from '../../../../assets/icons/project/fbd/Block'
import { ActivityBarButton } from '../../../_atoms/buttons/activity-bar'
-import { ComponentPropsWithoutRef } from 'react'
export const BlockButton = ({ onDragStart, onDragEnd }: ComponentPropsWithoutRef<'div'>) => {
return (
diff --git a/src2/frontend/components/_molecules/workspace-activity-bar/fbd/comment.tsx b/src/frontend/components/_molecules/workspace-activity-bar/fbd/comment.tsx
similarity index 99%
rename from src2/frontend/components/_molecules/workspace-activity-bar/fbd/comment.tsx
rename to src/frontend/components/_molecules/workspace-activity-bar/fbd/comment.tsx
index 361093ba9..cf9683dba 100644
--- a/src2/frontend/components/_molecules/workspace-activity-bar/fbd/comment.tsx
+++ b/src/frontend/components/_molecules/workspace-activity-bar/fbd/comment.tsx
@@ -1,6 +1,7 @@
+import { ComponentPropsWithoutRef } from 'react'
+
import CommentIcon from '../../../../assets/icons/project/fbd/Comment'
import { ActivityBarButton } from '../../../_atoms/buttons/activity-bar'
-import { ComponentPropsWithoutRef } from 'react'
export const Comment = ({ onDragStart, onDragEnd }: ComponentPropsWithoutRef<'div'>) => {
return (
diff --git a/src2/frontend/components/_molecules/workspace-activity-bar/fbd/connector.tsx b/src/frontend/components/_molecules/workspace-activity-bar/fbd/connector.tsx
similarity index 99%
rename from src2/frontend/components/_molecules/workspace-activity-bar/fbd/connector.tsx
rename to src/frontend/components/_molecules/workspace-activity-bar/fbd/connector.tsx
index 7fa7c063f..5ff55b169 100644
--- a/src2/frontend/components/_molecules/workspace-activity-bar/fbd/connector.tsx
+++ b/src/frontend/components/_molecules/workspace-activity-bar/fbd/connector.tsx
@@ -1,6 +1,7 @@
+import { ComponentPropsWithoutRef } from 'react'
+
import ConnectorIcon from '../../../../assets/icons/project/fbd/Connector'
import { ActivityBarButton } from '../../../_atoms/buttons/activity-bar'
-import { ComponentPropsWithoutRef } from 'react'
export const Connector = ({ onDragStart, onDragEnd }: ComponentPropsWithoutRef<'div'>) => {
return (
diff --git a/src2/frontend/components/_molecules/workspace-activity-bar/fbd/continuation.tsx b/src/frontend/components/_molecules/workspace-activity-bar/fbd/continuation.tsx
similarity index 99%
rename from src2/frontend/components/_molecules/workspace-activity-bar/fbd/continuation.tsx
rename to src/frontend/components/_molecules/workspace-activity-bar/fbd/continuation.tsx
index 4c857a127..c477ebfbd 100644
--- a/src2/frontend/components/_molecules/workspace-activity-bar/fbd/continuation.tsx
+++ b/src/frontend/components/_molecules/workspace-activity-bar/fbd/continuation.tsx
@@ -1,6 +1,7 @@
+import { ComponentPropsWithoutRef } from 'react'
+
import ContinuationIcon from '../../../../assets/icons/project/fbd/Continuation'
import { ActivityBarButton } from '../../../_atoms/buttons/activity-bar'
-import { ComponentPropsWithoutRef } from 'react'
export const Continuation = ({ onDragStart, onDragEnd }: ComponentPropsWithoutRef<'div'>) => {
return (
diff --git a/src2/frontend/components/_molecules/workspace-activity-bar/fbd/inout-variable.tsx b/src/frontend/components/_molecules/workspace-activity-bar/fbd/inout-variable.tsx
similarity index 99%
rename from src2/frontend/components/_molecules/workspace-activity-bar/fbd/inout-variable.tsx
rename to src/frontend/components/_molecules/workspace-activity-bar/fbd/inout-variable.tsx
index 33a0d919b..fe5611738 100644
--- a/src2/frontend/components/_molecules/workspace-activity-bar/fbd/inout-variable.tsx
+++ b/src/frontend/components/_molecules/workspace-activity-bar/fbd/inout-variable.tsx
@@ -1,6 +1,7 @@
+import { ComponentPropsWithoutRef } from 'react'
+
import VariableInOutIcon from '../../../../assets/icons/project/fbd/VariableInOut'
import { ActivityBarButton } from '../../../_atoms/buttons/activity-bar'
-import { ComponentPropsWithoutRef } from 'react'
export const InOutVariable = ({ onDragStart, onDragEnd }: ComponentPropsWithoutRef<'div'>) => {
return (
diff --git a/src2/frontend/components/_molecules/workspace-activity-bar/fbd/input-variable.tsx b/src/frontend/components/_molecules/workspace-activity-bar/fbd/input-variable.tsx
similarity index 99%
rename from src2/frontend/components/_molecules/workspace-activity-bar/fbd/input-variable.tsx
rename to src/frontend/components/_molecules/workspace-activity-bar/fbd/input-variable.tsx
index 3d9227afc..00b9150fc 100644
--- a/src2/frontend/components/_molecules/workspace-activity-bar/fbd/input-variable.tsx
+++ b/src/frontend/components/_molecules/workspace-activity-bar/fbd/input-variable.tsx
@@ -1,6 +1,7 @@
+import { ComponentPropsWithoutRef } from 'react'
+
import VariableInIcon from '../../../../assets/icons/project/fbd/VariableIn'
import { ActivityBarButton } from '../../../_atoms/buttons/activity-bar'
-import { ComponentPropsWithoutRef } from 'react'
export const InputVariable = ({ onDragStart, onDragEnd }: ComponentPropsWithoutRef<'div'>) => {
return (
diff --git a/src2/frontend/components/_molecules/workspace-activity-bar/fbd/out-variable.tsx b/src/frontend/components/_molecules/workspace-activity-bar/fbd/out-variable.tsx
similarity index 99%
rename from src2/frontend/components/_molecules/workspace-activity-bar/fbd/out-variable.tsx
rename to src/frontend/components/_molecules/workspace-activity-bar/fbd/out-variable.tsx
index 5ffe93f14..ff2691eb1 100644
--- a/src2/frontend/components/_molecules/workspace-activity-bar/fbd/out-variable.tsx
+++ b/src/frontend/components/_molecules/workspace-activity-bar/fbd/out-variable.tsx
@@ -1,6 +1,7 @@
+import { ComponentPropsWithoutRef } from 'react'
+
import VariableOutIcon from '../../../../assets/icons/project/fbd/VariableOut'
import { ActivityBarButton } from '../../../_atoms/buttons/activity-bar'
-import { ComponentPropsWithoutRef } from 'react'
export const OutVariable = ({ onDragStart, onDragEnd }: ComponentPropsWithoutRef<'div'>) => {
return (
diff --git a/src2/frontend/components/_molecules/workspace-activity-bar/ladder/block.tsx b/src/frontend/components/_molecules/workspace-activity-bar/ladder/block.tsx
similarity index 99%
rename from src2/frontend/components/_molecules/workspace-activity-bar/ladder/block.tsx
rename to src/frontend/components/_molecules/workspace-activity-bar/ladder/block.tsx
index e4d0aaa0d..0efd224bb 100644
--- a/src2/frontend/components/_molecules/workspace-activity-bar/ladder/block.tsx
+++ b/src/frontend/components/_molecules/workspace-activity-bar/ladder/block.tsx
@@ -1,6 +1,7 @@
+import { ComponentPropsWithoutRef } from 'react'
+
import BlockIcon from '../../../../assets/icons/project/ladder/Block'
import { ActivityBarButton } from '../../../_atoms/buttons/activity-bar'
-import { ComponentPropsWithoutRef } from 'react'
export const BlockButton = ({ onDragStart, onDragEnd }: ComponentPropsWithoutRef<'div'>) => {
return (
diff --git a/src2/frontend/components/_molecules/workspace-activity-bar/ladder/coil.tsx b/src/frontend/components/_molecules/workspace-activity-bar/ladder/coil.tsx
similarity index 99%
rename from src2/frontend/components/_molecules/workspace-activity-bar/ladder/coil.tsx
rename to src/frontend/components/_molecules/workspace-activity-bar/ladder/coil.tsx
index 26eb0dbca..0ba3d519f 100644
--- a/src2/frontend/components/_molecules/workspace-activity-bar/ladder/coil.tsx
+++ b/src/frontend/components/_molecules/workspace-activity-bar/ladder/coil.tsx
@@ -1,6 +1,7 @@
+import { ComponentPropsWithoutRef } from 'react'
+
import CoilIcon from '../../../../assets/icons/project/ladder/Coil'
import { ActivityBarButton } from '../../../_atoms/buttons/activity-bar'
-import { ComponentPropsWithoutRef } from 'react'
export const CoilButton = ({ onDragStart }: ComponentPropsWithoutRef<'div'>) => {
return (
diff --git a/src2/frontend/components/_molecules/workspace-activity-bar/ladder/contact.tsx b/src/frontend/components/_molecules/workspace-activity-bar/ladder/contact.tsx
similarity index 99%
rename from src2/frontend/components/_molecules/workspace-activity-bar/ladder/contact.tsx
rename to src/frontend/components/_molecules/workspace-activity-bar/ladder/contact.tsx
index 58e72af6d..584f690a5 100644
--- a/src2/frontend/components/_molecules/workspace-activity-bar/ladder/contact.tsx
+++ b/src/frontend/components/_molecules/workspace-activity-bar/ladder/contact.tsx
@@ -1,6 +1,7 @@
+import { ComponentPropsWithoutRef } from 'react'
+
import ContactIcon from '../../../../assets/icons/project/ladder/Contact'
import { ActivityBarButton } from '../../../_atoms/buttons/activity-bar'
-import { ComponentPropsWithoutRef } from 'react'
export const ContactButton = ({ onDragStart }: ComponentPropsWithoutRef<'div'>) => {
return (
diff --git a/src2/frontend/components/_molecules/workspace-activity-bar/ladder/parallel.tsx b/src/frontend/components/_molecules/workspace-activity-bar/ladder/parallel.tsx
similarity index 99%
rename from src2/frontend/components/_molecules/workspace-activity-bar/ladder/parallel.tsx
rename to src/frontend/components/_molecules/workspace-activity-bar/ladder/parallel.tsx
index ed0cb218f..a302733da 100644
--- a/src2/frontend/components/_molecules/workspace-activity-bar/ladder/parallel.tsx
+++ b/src/frontend/components/_molecules/workspace-activity-bar/ladder/parallel.tsx
@@ -1,6 +1,7 @@
+import { ComponentPropsWithoutRef } from 'react'
+
import LoopIcon from '../../../../assets/icons/project/Loop'
import { ActivityBarButton } from '../../../_atoms/buttons/activity-bar'
-import { ComponentPropsWithoutRef } from 'react'
export const ParallelButton = ({ onDragStart }: ComponentPropsWithoutRef<'div'>) => {
return (
diff --git a/src/renderer/components/_molecules/workspace-activity-bar/tooltip-button.tsx b/src/frontend/components/_molecules/workspace-activity-bar/tooltip-button.tsx
similarity index 100%
rename from src/renderer/components/_molecules/workspace-activity-bar/tooltip-button.tsx
rename to src/frontend/components/_molecules/workspace-activity-bar/tooltip-button.tsx
diff --git a/src2/frontend/components/_organisms/about-modal/index.tsx b/src/frontend/components/_organisms/about-modal/index.tsx
similarity index 92%
rename from src2/frontend/components/_organisms/about-modal/index.tsx
rename to src/frontend/components/_organisms/about-modal/index.tsx
index 4f7b735f8..755979700 100644
--- a/src2/frontend/components/_organisms/about-modal/index.tsx
+++ b/src/frontend/components/_organisms/about-modal/index.tsx
@@ -1,8 +1,8 @@
-import openPlcLogo from '../../../assets/icons/about/logo.svg'
-import { useOpenPLCStore } from '../../../store'
-import { useAccelerator, useSystem } from '../../../../middleware/shared/providers'
import { useEffect, useState } from 'react'
+import { useAccelerator, useCapabilities, useSystem } from '../../../../middleware/shared/providers'
+import openPlcLogo from '../../../assets/icons/about/logo.svg'
+import { useOpenPLCStore } from '../../../store'
import { Modal, ModalContent } from '../../_molecules/modal'
const AboutModal = () => {
@@ -10,6 +10,7 @@ const AboutModal = () => {
workspaceActions: { setModalOpen },
workspace: { isModalOpen },
} = useOpenPLCStore()
+ const capabilities = useCapabilities()
const system = useSystem()
const accelerator = useAccelerator()
@@ -44,11 +45,12 @@ const AboutModal = () => {
}
useEffect(() => {
+ if (!capabilities.hasAboutDialog) return
const unsubscribe = accelerator.onAbout(() => {
openAboutModal()
})
return unsubscribe
- }, [])
+ }, [capabilities.hasAboutDialog])
return (
diff --git a/src2/frontend/components/_organisms/console/__tests__/log.test.tsx b/src/frontend/components/_organisms/console/__tests__/log.test.tsx
similarity index 98%
rename from src2/frontend/components/_organisms/console/__tests__/log.test.tsx
rename to src/frontend/components/_organisms/console/__tests__/log.test.tsx
index b9a42eb3e..046bf9dc9 100644
--- a/src2/frontend/components/_organisms/console/__tests__/log.test.tsx
+++ b/src/frontend/components/_organisms/console/__tests__/log.test.tsx
@@ -1,6 +1,6 @@
import { render, screen } from '@testing-library/react'
-import { LogComponent, type LogLevel } from '../log'
+import { LogComponent } from '../log'
describe('LogComponent', () => {
it('renders message text', () => {
diff --git a/src2/frontend/components/_organisms/console/filters.tsx b/src/frontend/components/_organisms/console/filters.tsx
similarity index 97%
rename from src2/frontend/components/_organisms/console/filters.tsx
rename to src/frontend/components/_organisms/console/filters.tsx
index 92edec6b2..b9a0d19dc 100644
--- a/src2/frontend/components/_organisms/console/filters.tsx
+++ b/src/frontend/components/_organisms/console/filters.tsx
@@ -1,9 +1,10 @@
+import { ChevronDown, Download, Filter, Search, X } from 'lucide-react'
+import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react'
+
import { useOpenPLCStore } from '../../../store'
import { TimestampFormat } from '../../../store/slices/console/types'
import { cn } from '../../../utils/cn'
import formatTimestamp from '../../../utils/format-timestamp'
-import { ChevronDown, Download, Filter, Search, X } from 'lucide-react'
-import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react'
type LogLevel = 'debug' | 'info' | 'warning' | 'error'
type ExportFormat = 'txt' | 'csv' | 'json'
@@ -123,7 +124,7 @@ const ConsoleFilters = memo(() => {
if (filters.searchTerm) {
const searchLower = filters.searchTerm.toLowerCase()
const messageMatch = log.message.toLowerCase().includes(searchLower)
- const timestampMatch = log.tstamp.toISOString().includes(searchLower)
+ const timestampMatch = log.tstamp?.toISOString().includes(searchLower) ?? false
if (!messageMatch && !timestampMatch) return false
}
return true
@@ -141,7 +142,7 @@ const ConsoleFilters = memo(() => {
case 'json':
content = JSON.stringify(
filteredLogs.map((log) => ({
- timestamp: log.tstamp.toISOString(),
+ timestamp: (log.tstamp ?? new Date()).toISOString(),
level: log.level || 'info',
message: log.message,
})),
@@ -156,7 +157,7 @@ const ConsoleFilters = memo(() => {
content += filteredLogs
.map((log) => {
const escapedMessage = `"${log.message.replace(/"/g, '""')}"`
- return `${log.tstamp.toISOString()},${log.level || 'info'},${escapedMessage}`
+ return `${(log.tstamp ?? new Date()).toISOString()},${log.level || 'info'},${escapedMessage}`
})
.join('\n')
mimeType = 'text/csv'
@@ -166,7 +167,7 @@ const ConsoleFilters = memo(() => {
content = filteredLogs
.map(
(log) =>
- `[${formatTimestamp(log.tstamp, 'full')}] [${(log.level || 'info').toUpperCase()}]: ${log.message}`,
+ `[${formatTimestamp(log.tstamp ?? new Date(), 'full')}] [${(log.level || 'info').toUpperCase()}]: ${log.message}`,
)
.join('\n')
mimeType = 'text/plain'
diff --git a/src2/frontend/components/_organisms/console/index.tsx b/src/frontend/components/_organisms/console/index.tsx
similarity index 93%
rename from src2/frontend/components/_organisms/console/index.tsx
rename to src/frontend/components/_organisms/console/index.tsx
index 627ea7c53..a4a896a7b 100644
--- a/src2/frontend/components/_organisms/console/index.tsx
+++ b/src/frontend/components/_organisms/console/index.tsx
@@ -1,8 +1,8 @@
-import { useOpenPLCStore } from '../../../store'
-import formatTimestamp from '../../../utils/format-timestamp'
import { debounce } from 'lodash'
import { memo, useEffect, useMemo, useRef } from 'react'
+import { useOpenPLCStore } from '../../../store'
+import formatTimestamp from '../../../utils/format-timestamp'
import { LogComponent } from './log'
const Console = memo(() => {
@@ -23,7 +23,7 @@ const Console = memo(() => {
if (filters.searchTerm) {
const searchLower = filters.searchTerm.toLowerCase()
const messageMatch = log.message.toLowerCase().includes(searchLower)
- const timestampMatch = log.tstamp.toISOString().includes(searchLower)
+ const timestampMatch = log.tstamp?.toISOString().includes(searchLower) ?? false
if (!messageMatch && !timestampMatch) return false
}
@@ -82,7 +82,7 @@ const Console = memo(() => {
key={log.id}
level={log.level}
message={log.message}
- tstamp={formatTimestamp(log.tstamp, filters.timestampFormat)}
+ tstamp={formatTimestamp(log.tstamp ?? new Date(), filters.timestampFormat)}
searchTerm={filters.searchTerm}
/>
))}
diff --git a/src2/frontend/components/_organisms/console/log.tsx b/src/frontend/components/_organisms/console/log.tsx
similarity index 99%
rename from src2/frontend/components/_organisms/console/log.tsx
rename to src/frontend/components/_organisms/console/log.tsx
index 280b16893..e780ef492 100644
--- a/src2/frontend/components/_organisms/console/log.tsx
+++ b/src/frontend/components/_organisms/console/log.tsx
@@ -1,7 +1,8 @@
-import { cn } from '../../../utils/cn'
import { Copy } from 'lucide-react'
import { ComponentPropsWithoutRef, useCallback, useEffect, useRef, useState } from 'react'
+import { cn } from '../../../utils/cn'
+
const messageClasses = {
debug: 'text-neutral-500 dark:text-neutral-400',
warning: 'text-yellow-600',
diff --git a/src2/frontend/components/_organisms/debugger/index.tsx b/src/frontend/components/_organisms/debugger/index.tsx
similarity index 99%
rename from src2/frontend/components/_organisms/debugger/index.tsx
rename to src/frontend/components/_organisms/debugger/index.tsx
index ba50d1506..5814e90da 100644
--- a/src2/frontend/components/_organisms/debugger/index.tsx
+++ b/src/frontend/components/_organisms/debugger/index.tsx
@@ -1,10 +1,10 @@
import * as Select from '@radix-ui/react-select'
+import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
+
import { ArrowIcon } from '../../../assets/icons/interface/Arrow'
import { PauseIcon } from '../../../assets/icons/interface/Pause'
import { PlayIcon } from '../../../assets/icons/interface/Play'
import { useOpenPLCStore } from '../../../store'
-import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
-
import { Button } from '../../_atoms/buttons/default'
import { LineChart } from '../../_molecules/charts/line-chart'
@@ -181,7 +181,7 @@ const Debugger = ({ graphList }: DebuggerData) => {
{renderSeries.series.map(({ name, points, isBool }) => (
({ x: p.t, y: p.y }))}
isBool={isBool}
range={range}
now={renderSeries.now}
diff --git a/src2/frontend/components/_organisms/display-recent-projects/index.tsx b/src/frontend/components/_organisms/display-recent-projects/index.tsx
similarity index 83%
rename from src2/frontend/components/_organisms/display-recent-projects/index.tsx
rename to src/frontend/components/_organisms/display-recent-projects/index.tsx
index 5651ba3af..43f7df591 100644
--- a/src2/frontend/components/_organisms/display-recent-projects/index.tsx
+++ b/src/frontend/components/_organisms/display-recent-projects/index.tsx
@@ -1,9 +1,10 @@
-import { File as FileElement } from '../../_atoms/file'
-import { toast } from '../../_features/[app]/toast/use-toast'
-import { useOpenPLCStore } from '../../../store'
-import { useSystem, useProject } from '../../../../middleware/shared/providers'
import { ComponentProps, useEffect, useRef, useState } from 'react'
+import { useProject, useSystem } from '../../../../middleware/shared/providers'
+import { useOpenPLCStore } from '../../../store'
+import { File } from '../../_atoms/file'
+import { toast } from '../../_features/[app]/toast/use-toast'
+
export type IDisplayRecentProjectProps = ComponentProps<'section'> & {
searchNameFilterValue: string
}
@@ -12,6 +13,7 @@ const DisplayRecentProjects = ({ searchNameFilterValue, ...props }: IDisplayRece
const {
workspace: { recent },
workspaceActions: { setRecent },
+ sharedWorkspaceActions: { handleOpenProjectResponse },
} = useOpenPLCStore()
const system = useSystem()
@@ -91,15 +93,17 @@ const DisplayRecentProjects = ({ searchNameFilterValue, ...props }: IDisplayRece
}
const handleOpenProjectByPath = async (projectPath: string) => {
- const result = await project.openProject(projectPath)
- if (!result.ok) {
- void updateUserRecentProjects()
- toast({
- title: 'Cannot open the project.',
- description: result.message ?? `The path ${projectPath} does not exist on this computer.`,
- variant: 'fail',
- })
+ const result = await project.openProjectByPath(projectPath)
+ if (result.success && result.data) {
+ handleOpenProjectResponse(result.data)
+ return
}
+ void updateUserRecentProjects()
+ toast({
+ title: 'Cannot open the project.',
+ description: result.error?.description ?? `The path ${projectPath} does not exist on this computer.`,
+ variant: 'fail',
+ })
}
return (
@@ -112,18 +116,14 @@ const DisplayRecentProjects = ({ searchNameFilterValue, ...props }: IDisplayRece
{recentProjects.map((proj) => (
- void handleOpenProjectByPath(proj.path)}
- className='overflow-hidden '
+ className='overflow-hidden'
key={proj.path}
- >
-
-
-
+ projectName={proj.name}
+ projectPath={proj.path}
+ lastModified={projectTimes[proj.path]}
+ />
))}
diff --git a/src2/frontend/components/_organisms/explorer/__tests__/info.test.tsx b/src/frontend/components/_organisms/explorer/__tests__/info.test.tsx
similarity index 100%
rename from src2/frontend/components/_organisms/explorer/__tests__/info.test.tsx
rename to src/frontend/components/_organisms/explorer/__tests__/info.test.tsx
diff --git a/src2/frontend/components/_organisms/explorer/index.tsx b/src/frontend/components/_organisms/explorer/index.tsx
similarity index 95%
rename from src2/frontend/components/_organisms/explorer/index.tsx
rename to src/frontend/components/_organisms/explorer/index.tsx
index 4ca641a18..5cf03414d 100644
--- a/src2/frontend/components/_organisms/explorer/index.tsx
+++ b/src/frontend/components/_organisms/explorer/index.tsx
@@ -1,7 +1,7 @@
-import { useOpenPLCStore } from '../../../store'
import { LegacyRef, ReactElement, useState } from 'react'
import { ImperativePanelHandle } from 'react-resizable-panels'
+import { useOpenPLCStore } from '../../../store'
import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from '../panel'
import { Info } from './info'
import { Library } from './library'
@@ -47,7 +47,7 @@ const Explorer = ({ collapse }: ExplorerProps): ReactElement => {
// System Libraries filtering with type and text filter
const filteredLibraries = system.filter((library) =>
- pous.find((pou) => pou.data.name === editor.meta.name)?.type === 'function'
+ pous.find((pou) => pou.name === editor.meta.name)?.pouType === 'function'
? library.pous.some((pou) => pou.name.toLowerCase().includes(filterText) && pou.type === 'function')
: library.pous.some((pou) => pou.name.toLowerCase().includes(filterText)),
)
@@ -69,14 +69,14 @@ const Explorer = ({ collapse }: ExplorerProps): ReactElement => {
className="flex h-full w-[200px] max-w-lg flex-col overflow-auto rounded-lg border-2 border-inherit border-neutral-200 bg-white data-[panel-size='0.0']:hidden dark:border-neutral-850 dark:bg-neutral-950"
>
-
+
-
+
{
+ const capabilities = useCapabilities()
const {
project: {
- data: { pous, dataTypes, configuration, servers, remoteDevices },
+ data: { pous, dataTypes, configurations, servers, remoteDevices },
meta: { name },
},
projectActions: { updateMetaName },
@@ -95,19 +99,19 @@ const Project = () => {
{/* Project Functions tree branch */}
{pous
- ?.filter(({ type }) => type === 'function')
- .sort((a, b) => a.data.name.localeCompare(b.data.name))
- .map(({ data }) => (
+ ?.filter((pou) => pou.pouType === 'function')
+ .sort((a, b) => a.name.localeCompare(b.name))
+ .map((pou) => (
handleCreateTab({
- name: data.name,
- path: `/data/pous/function/${data.name}`,
- elementType: { type: 'function', language: data.language },
+ name: pou.name,
+ path: `/data/pous/function/${pou.name}`,
+ elementType: { type: 'function', language: pou.body.language as PouLeafLang },
})
}
/>
@@ -117,19 +121,19 @@ const Project = () => {
{/* Project Function Blocks tree branch */}
{pous
- ?.filter(({ type }) => type === 'function-block')
- .sort((a, b) => a.data.name.localeCompare(b.data.name))
- .map(({ data }) => (
+ ?.filter((pou) => pou.pouType === 'function-block')
+ .sort((a, b) => a.name.localeCompare(b.name))
+ .map((pou) => (
handleCreateTab({
- name: data.name,
- path: `/data/pous/function-block/${data.name}`,
- elementType: { type: 'function-block', language: data.language },
+ name: pou.name,
+ path: `/data/pous/function-block/${pou.name}`,
+ elementType: { type: 'function-block', language: pou.body.language as PouLeafLang },
})
}
/>
@@ -139,19 +143,19 @@ const Project = () => {
{/* Project Programs tree branch */}
{pous
- ?.filter(({ type }) => type === 'program')
- .sort((a, b) => a.data.name.localeCompare(b.data.name))
- .map(({ data }) => (
+ ?.filter((pou) => pou.pouType === 'program')
+ .sort((a, b) => a.name.localeCompare(b.name))
+ .map((pou) => (
handleCreateTab({
- name: data.name,
- path: `/data/pous/program/${data.name}`,
- elementType: { type: 'program', language: data.language },
+ name: pou.name,
+ path: `/data/pous/program/${pou.name}`,
+ elementType: { type: 'program', language: pou.body.language as PouLeafLang },
})
}
/>
@@ -165,7 +169,6 @@ const Project = () => {
.sort((a, b) => a.name.localeCompare(b.name))
.map(({ name }) => (
{
.sort((a, b) => a.name.localeCompare(b.name))
.map(({ name }) => (
{
.sort((a, b) => a.name.localeCompare(b.name))
.map(({ name }) => (
{
branchTarget='resource'
onClick={() => {
handleCreateTab({
- configuration: configuration,
+ configuration: configurations,
name: 'Resource',
path: `/data/configuration/resource`,
elementType: { type: 'resource' },
@@ -240,53 +241,59 @@ const Project = () => {
{/* Project Device tree branch */}
-
- handleCreateTab({
- name: 'Configuration',
- path: `/device/configuration`,
- elementType: { type: 'device', derivation: 'configuration' },
- })
- }
- />
-
- handleCreateTab({
- name: 'Orchestrators',
- path: `/device/orchestrators`,
- elementType: { type: 'device', derivation: 'orchestrators' },
- })
- }
- />
+ {capabilities.hasLocalSerialPorts && (
+
+ handleCreateTab({
+ name: 'Configuration',
+ path: `/device/configuration`,
+ elementType: { type: 'device', derivation: 'configuration' },
+ })
+ }
+ />
+ )}
+ {capabilities.hasOrchestratorDevices && (
+
+ handleCreateTab({
+ name: 'Orchestrators',
+ path: `/device/orchestrators`,
+ elementType: { type: 'device', derivation: 'orchestrators' },
+ })
+ }
+ />
+ )}
{/* Project Servers tree branch */}
-
- {[...(servers || [])]
- .sort((a, b) => a.name.localeCompare(b.name))
- .map((server) => (
-
- handleCreateTab({
- name: server.name,
- path: `/servers/${server.name}`,
- elementType: { type: 'server', protocol: server.protocol },
- })
- }
- />
- ))}
-
+ {capabilities.hasLocalSerialPorts && (
+
+ {[...(servers || [])]
+ .sort((a, b) => a.name.localeCompare(b.name))
+ .map((server) => (
+
+ handleCreateTab({
+ name: server.name,
+ path: `/servers/${server.name}`,
+ elementType: { type: 'server', protocol: server.protocol },
+ })
+ }
+ />
+ ))}
+
+ )}
{/* Project Remote Devices tree branch */}
diff --git a/src2/frontend/components/_organisms/global-variables-editor/index.tsx b/src/frontend/components/_organisms/global-variables-editor/index.tsx
similarity index 91%
rename from src2/frontend/components/_organisms/global-variables-editor/index.tsx
rename to src/frontend/components/_organisms/global-variables-editor/index.tsx
index 67d70a410..8eb31492f 100644
--- a/src2/frontend/components/_organisms/global-variables-editor/index.tsx
+++ b/src/frontend/components/_organisms/global-variables-editor/index.tsx
@@ -1,20 +1,20 @@
// import * as PrimitiveSwitch from '@radix-ui/react-switch'
+import { useCallback, useEffect, useRef, useState } from 'react'
+
+import type { PLCGlobalVariable } from '../../../../middleware/shared/ports/types'
+import { CodeIcon } from '../../../assets/icons/interface/CodeIcon'
import { MinusIcon } from '../../../assets/icons/interface/Minus'
import { PlusIcon } from '../../../assets/icons/interface/Plus'
import { StickArrowIcon } from '../../../assets/icons/interface/StickArrow'
-import { CodeIcon } from '../../../assets/icons/interface/CodeIcon'
import { TableIcon } from '../../../assets/icons/interface/TableIcon'
import { useOpenPLCStore } from '../../../store'
import type { GlobalVariablesTableType } from '../../../store/slices/editor'
-import { PLCGlobalVariable } from '../../../../middleware/shared/ports/types'
import { cn } from '../../../utils/cn'
-import { useEffect, useRef, useState } from 'react'
-
+import { parseIecStringToVariables } from '../../../utils/generate-iec-string-to-variables'
+import { generateIecVariablesToString } from '../../../utils/generate-iec-variables-to-string'
import TableActions from '../../_atoms/table-actions'
import { toast } from '../../_features/[app]/toast/use-toast'
import { GlobalVariablesTable } from '../../_molecules/global-variables-table'
-import { parseIecStringToVariables } from '../../../utils/generate-iec-string-to-variables'
-import { generateIecVariablesToString } from '../../../utils/generate-iec-variables-to-string'
import { VariablesCodeEditor } from '../variables-code-editor'
const GlobalVariablesEditor = () => {
@@ -26,15 +26,36 @@ const GlobalVariablesEditor = () => {
},
project: {
data: {
- configuration: {
+ configurations: {
resource: { globalVariables },
},
},
},
editorActions: { updateModelVariables, updateModelVariablesForName },
- projectActions: { createVariable, deleteVariable, rearrangeVariables, setGlobalVariables, pushToHistory },
+ projectActions: { createVariable, deleteVariable, rearrangeVariables, setGlobalVariables },
sharedWorkspaceActions: { handleFileAndWorkspaceSavedState },
+ workspaceActions: { removeDebugVariable },
+ } = useOpenPLCStore()
+
+ const {
+ project: {
+ data: { pous: snapshotPous, configurations },
+ },
+ snapshotActions: { pushToHistory: rawPushToHistory },
} = useOpenPLCStore()
+
+ const pushToHistory = useCallback(
+ (pouName: string) => {
+ const pou = snapshotPous.find((p) => p.name === pouName)
+ if (!pou) return
+ rawPushToHistory(pouName, {
+ variables: pou.interface?.variables ?? [],
+ body: pou.body.value,
+ globalVariables: configurations.resource.globalVariables,
+ })
+ },
+ [snapshotPous, configurations.resource.globalVariables, rawPushToHistory],
+ )
/**
* Table data and column filters states to keep track of the table data and column filters
*/
@@ -61,7 +82,7 @@ const GlobalVariablesEditor = () => {
*/
useEffect(() => {
const variablesToTable = globalVariables.filter((variable) => variable.name)
- setTableData(variablesToTable)
+ setTableData(variablesToTable as PLCGlobalVariable[])
}, [editor, globalVariables])
useEffect(() => {
@@ -194,7 +215,7 @@ const GlobalVariablesEditor = () => {
scope: 'global',
data: {
name: 'GlobalVar',
- type: { definition: 'base-type', value: 'dint' },
+ type: { definition: 'base-type', value: 'DINT' },
class: 'global',
location: '',
documentation: '',
@@ -210,8 +231,9 @@ const GlobalVariablesEditor = () => {
return
}
- const variable: PLCGlobalVariable =
+ const variable = (
selectedRow === ROWS_NOT_SELECTED ? variables[variables.length - 1] : variables[selectedRow]
+ ) as PLCGlobalVariable
if (selectedRow === ROWS_NOT_SELECTED) {
createVariable({ scope: 'global', data: { ...variable } })
@@ -241,6 +263,10 @@ const GlobalVariablesEditor = () => {
pushToHistory(editor.meta.name)
const selectedRow = parseInt(editorVariables.selectedRow)
+ const variableToDelete = globalVariables.filter((v) => v.name)[selectedRow]
+ if (variableToDelete) {
+ removeDebugVariable(`resource:${variableToDelete.name}`)
+ }
deleteVariable({ scope: 'global', rowId: selectedRow })
const variables = globalVariables.filter((variable) => variable.name)
@@ -301,7 +327,7 @@ const GlobalVariablesEditor = () => {
{editorVariables.display === 'table' && (
{
updateModelLadder({ openRung: { rungId: rung.id, open: isOpen } })
- // eslint-disable-next-line react-hooks/exhaustive-deps
}, [])
useEffect(() => {
setIsOpen(getIsRungOpen({ rungId: rung.id }))
- // eslint-disable-next-line react-hooks/exhaustive-deps
}, [rung])
const style = {
diff --git a/src2/frontend/components/_organisms/instances-editor/index.tsx b/src/frontend/components/_organisms/instances-editor/index.tsx
similarity index 93%
rename from src2/frontend/components/_organisms/instances-editor/index.tsx
rename to src/frontend/components/_organisms/instances-editor/index.tsx
index f0cef44c7..936476251 100644
--- a/src2/frontend/components/_organisms/instances-editor/index.tsx
+++ b/src/frontend/components/_organisms/instances-editor/index.tsx
@@ -1,16 +1,16 @@
+import { useCallback, useEffect, useState } from 'react'
+
+import type { PLCInstance } from '../../../../middleware/shared/ports/types'
+import { CodeIcon } from '../../../assets/icons/interface/CodeIcon'
import { MinusIcon } from '../../../assets/icons/interface/Minus'
import { PlusIcon } from '../../../assets/icons/interface/Plus'
import { StickArrowIcon } from '../../../assets/icons/interface/StickArrow'
-import { CodeIcon } from '../../../assets/icons/interface/CodeIcon'
import { TableIcon } from '../../../assets/icons/interface/TableIcon'
import { useOpenPLCStore } from '../../../store'
import type { InstanceType } from '../../../store/slices/editor'
-import type { PLCInstance } from '../../../../middleware/shared/ports/types'
import { cn } from '../../../utils/cn'
import { parseResourceConfigurationToString } from '../../../utils/parse-resource-configuration-to-string'
import { parseResourceStringToConfiguration } from '../../../utils/parse-resource-string-to-configuration'
-import { useEffect, useState } from 'react'
-
import TableActions from '../../_atoms/table-actions'
import { toast } from '../../_features/[app]/toast/use-toast'
import { InstancesTable } from '../../_molecules/instances-table'
@@ -26,16 +26,36 @@ const InstancesEditor = () => {
},
project: {
data: {
- configuration: {
+ configurations: {
resource: { instances, tasks },
},
},
},
editorActions: { updateModelInstances },
- projectActions: { createInstance, rearrangeInstances, deleteInstance, setInstances, setTasks, pushToHistory },
+ projectActions: { createInstance, rearrangeInstances, deleteInstance, setInstances, setTasks },
sharedWorkspaceActions: { handleFileAndWorkspaceSavedState },
} = useOpenPLCStore()
+ const {
+ project: {
+ data: { pous: snapshotPous, configurations },
+ },
+ snapshotActions: { pushToHistory: rawPushToHistory },
+ } = useOpenPLCStore()
+
+ const pushToHistory = useCallback(
+ (pouName: string) => {
+ const pou = snapshotPous.find((p) => p.name === pouName)
+ if (!pou) return
+ rawPushToHistory(pouName, {
+ variables: pou.interface?.variables ?? [],
+ body: pou.body.value,
+ globalVariables: configurations.resource.globalVariables,
+ })
+ },
+ [snapshotPous, configurations.resource.globalVariables, rawPushToHistory],
+ )
+
const [instanceData, setInstanceData] = useState([])
const [editorCode, setEditorCode] = useState(() => parseResourceConfigurationToString(tasks, instanceData))
const [parseError, setParseError] = useState(null)
@@ -91,7 +111,6 @@ const InstancesEditor = () => {
selectedRow: editorInstances.display === 'table' ? parseInt(editorInstances.selectedRow) : ROWS_NOT_SELECTED,
})
} else {
- // @ts-expect-error: 'selectedRow' is not required when display is 'code'
updateModelInstances({
display: 'code',
})
@@ -126,8 +145,8 @@ const InstancesEditor = () => {
createInstance({
data: {
name: 'instance0',
- pouName: '',
- taskName: '',
+ program: '',
+ task: '',
},
})
updateModelInstances({
diff --git a/src2/frontend/components/_organisms/modals/confirm-device-switch-modal.tsx b/src/frontend/components/_organisms/modals/confirm-device-switch-modal.tsx
similarity index 99%
rename from src2/frontend/components/_organisms/modals/confirm-device-switch-modal.tsx
rename to src/frontend/components/_organisms/modals/confirm-device-switch-modal.tsx
index 05a4ae3a3..15743c701 100644
--- a/src2/frontend/components/_organisms/modals/confirm-device-switch-modal.tsx
+++ b/src/frontend/components/_organisms/modals/confirm-device-switch-modal.tsx
@@ -1,6 +1,5 @@
import { WarningIcon } from '../../../assets/icons/interface/Warning'
import { useOpenPLCStore } from '../../../store'
-
import { Modal, ModalContent } from '../../_molecules/modal'
const ConfirmDeviceSwitchModal = () => {
diff --git a/src2/frontend/components/_organisms/modals/debugger-ip-input-modal.tsx b/src/frontend/components/_organisms/modals/debugger-ip-input-modal.tsx
similarity index 100%
rename from src2/frontend/components/_organisms/modals/debugger-ip-input-modal.tsx
rename to src/frontend/components/_organisms/modals/debugger-ip-input-modal.tsx
index 1e6d34145..7b31360d5 100644
--- a/src2/frontend/components/_organisms/modals/debugger-ip-input-modal.tsx
+++ b/src/frontend/components/_organisms/modals/debugger-ip-input-modal.tsx
@@ -1,6 +1,6 @@
-import { useOpenPLCStore } from '../../../store'
import { useEffect, useState } from 'react'
+import { useOpenPLCStore } from '../../../store'
import { Label } from '../../_atoms/label'
import { Modal, ModalContent, ModalTitle } from '../../_molecules/modal'
diff --git a/src2/frontend/components/_organisms/modals/debugger-message-modal.tsx b/src/frontend/components/_organisms/modals/debugger-message-modal.tsx
similarity index 99%
rename from src2/frontend/components/_organisms/modals/debugger-message-modal.tsx
rename to src/frontend/components/_organisms/modals/debugger-message-modal.tsx
index e4afbfdf0..d12f9d65a 100644
--- a/src2/frontend/components/_organisms/modals/debugger-message-modal.tsx
+++ b/src/frontend/components/_organisms/modals/debugger-message-modal.tsx
@@ -1,5 +1,4 @@
import { useOpenPLCStore } from '../../../store'
-
import { Modal, ModalContent, ModalTitle } from '../../_molecules/modal'
const DebuggerMessageModal = () => {
diff --git a/src2/frontend/components/_organisms/modals/delete-confirmation-modal.tsx b/src/frontend/components/_organisms/modals/delete-confirmation-modal.tsx
similarity index 97%
rename from src2/frontend/components/_organisms/modals/delete-confirmation-modal.tsx
rename to src/frontend/components/_organisms/modals/delete-confirmation-modal.tsx
index 5a965d4d2..15c2e6b07 100644
--- a/src2/frontend/components/_organisms/modals/delete-confirmation-modal.tsx
+++ b/src/frontend/components/_organisms/modals/delete-confirmation-modal.tsx
@@ -1,10 +1,9 @@
-import { BasicNodeData } from '../../_atoms/graphical-editor/ladder/utils/types'
-import { toast } from '../../_features/[app]/toast/use-toast'
-import { useOpenPLCStore } from '../../../store'
-import type { RungLadderState } from '../../../store/slices/ladder'
import type { PLCVariable } from '../../../../middleware/shared/ports/types'
import { WarningIcon } from '../../../assets/icons/interface/Warning'
-
+import { useOpenPLCStore } from '../../../store'
+import type { RungLadderState } from '../../../store/slices/ladder'
+import { BasicNodeData } from '../../_atoms/graphical-editor/ladder/utils/types'
+import { toast } from '../../_features/[app]/toast/use-toast'
import { Modal, ModalContent } from '../../_molecules/modal'
type ConfirmDeleteElementProps = {
@@ -29,7 +28,9 @@ const compareVariableTypes = (type1: PLCVariable['type'], type2: PLCVariable['ty
* Resolve the element name and type from modal data.
* Handles both the new format `{ name, elementType }` and the legacy format `{ leafLang, label }`.
*/
-function resolveDeleteTarget(data: unknown): { name: string; elementType: 'pou' | 'datatype' | 'server' | 'remote-device' } | null {
+function resolveDeleteTarget(
+ data: unknown,
+): { name: string; elementType: 'pou' | 'datatype' | 'server' | 'remote-device' } | null {
if (!data || typeof data !== 'object') return null
// New format from shared slice deleteRequest actions
@@ -108,7 +109,7 @@ const ConfirmDeleteElementModal = ({ rung, isOpen, ...rest }: ConfirmDeleteEleme
variableIndex = variables.findIndex((variable) => {
if (variable.name.toLowerCase() !== variableData.name.toLowerCase()) return false
if ('type' in variableData && variableData.type) {
- return compareVariableTypes(variable.type, variableData.type as PLCVariable['type'])
+ return compareVariableTypes(variable.type, variableData.type)
}
return true
})
diff --git a/src/frontend/components/_organisms/modals/index.ts b/src/frontend/components/_organisms/modals/index.ts
new file mode 100644
index 000000000..7eaaf7ed2
--- /dev/null
+++ b/src/frontend/components/_organisms/modals/index.ts
@@ -0,0 +1,2 @@
+export { RuntimeCreateUserModal } from './runtime-create-user-modal'
+export { RuntimeLoginModal } from './runtime-login-modal'
diff --git a/src2/frontend/components/_organisms/modals/quit-application-modal.tsx b/src/frontend/components/_organisms/modals/quit-application-modal.tsx
similarity index 100%
rename from src2/frontend/components/_organisms/modals/quit-application-modal.tsx
rename to src/frontend/components/_organisms/modals/quit-application-modal.tsx
index e0b4dfc70..703ef8cf4 100644
--- a/src2/frontend/components/_organisms/modals/quit-application-modal.tsx
+++ b/src/frontend/components/_organisms/modals/quit-application-modal.tsx
@@ -1,8 +1,8 @@
-import { WarningIcon } from '../../../assets/icons/interface/Warning'
-import { useOpenPLCStore } from '../../../store'
-import { useWindow } from '../../../../middleware/shared/providers'
import { ComponentPropsWithoutRef } from 'react'
+import { useWindow } from '../../../../middleware/shared/providers'
+import { WarningIcon } from '../../../assets/icons/interface/Warning'
+import { useOpenPLCStore } from '../../../store'
import { Modal, ModalContent } from '../../_molecules/modal'
type QuitApplicationModalProps = ComponentPropsWithoutRef & {
diff --git a/src2/frontend/components/_organisms/modals/runtime-connection-lost-modal.tsx b/src/frontend/components/_organisms/modals/runtime-connection-lost-modal.tsx
similarity index 99%
rename from src2/frontend/components/_organisms/modals/runtime-connection-lost-modal.tsx
rename to src/frontend/components/_organisms/modals/runtime-connection-lost-modal.tsx
index cd9cf382b..472af5cb5 100644
--- a/src2/frontend/components/_organisms/modals/runtime-connection-lost-modal.tsx
+++ b/src/frontend/components/_organisms/modals/runtime-connection-lost-modal.tsx
@@ -1,6 +1,5 @@
import { WarningIcon } from '../../../assets/icons/interface/Warning'
import { useOpenPLCStore } from '../../../store'
-
import { Modal, ModalContent, ModalTitle } from '../../_molecules/modal'
const RuntimeConnectionLostModal = () => {
diff --git a/src2/frontend/components/_organisms/modals/runtime-create-user-modal.tsx b/src/frontend/components/_organisms/modals/runtime-create-user-modal.tsx
similarity index 98%
rename from src2/frontend/components/_organisms/modals/runtime-create-user-modal.tsx
rename to src/frontend/components/_organisms/modals/runtime-create-user-modal.tsx
index aa7a69d6f..9585bc2c5 100644
--- a/src2/frontend/components/_organisms/modals/runtime-create-user-modal.tsx
+++ b/src/frontend/components/_organisms/modals/runtime-create-user-modal.tsx
@@ -1,7 +1,8 @@
-import { useOpenPLCStore } from '../../../store'
-import { useRuntime } from '../../../../middleware/shared/providers'
import { useState } from 'react'
+import { useRuntime } from '../../../../middleware/shared/providers'
+import { useOpenPLCStore } from '../../../store'
+import { getErrorMessage } from '../../../utils/get-error-message'
import { Label } from '../../_atoms/label'
import { Modal, ModalContent, ModalTitle } from '../../_molecules/modal'
@@ -53,7 +54,7 @@ const RuntimeCreateUserModal = () => {
setError('Failed to create user: ' + (result.error || 'Unknown error'))
}
} catch (err) {
- setError('Error: ' + String(err))
+ setError('Error: ' + getErrorMessage(err))
} finally {
setIsLoading(false)
}
diff --git a/src2/frontend/components/_organisms/modals/runtime-login-modal.tsx b/src/frontend/components/_organisms/modals/runtime-login-modal.tsx
similarity index 97%
rename from src2/frontend/components/_organisms/modals/runtime-login-modal.tsx
rename to src/frontend/components/_organisms/modals/runtime-login-modal.tsx
index c559629f1..aa01f0714 100644
--- a/src2/frontend/components/_organisms/modals/runtime-login-modal.tsx
+++ b/src/frontend/components/_organisms/modals/runtime-login-modal.tsx
@@ -1,7 +1,8 @@
-import { useOpenPLCStore } from '../../../store'
-import { useRuntime } from '../../../../middleware/shared/providers'
import { useState } from 'react'
+import { useRuntime } from '../../../../middleware/shared/providers'
+import { useOpenPLCStore } from '../../../store'
+import { getErrorMessage } from '../../../utils/get-error-message'
import { Label } from '../../_atoms/label'
import { Modal, ModalContent, ModalTitle } from '../../_molecules/modal'
@@ -42,7 +43,7 @@ const RuntimeLoginModal = () => {
setError('Login failed: ' + (result.error || 'Invalid credentials'))
}
} catch (err) {
- setError('Error: ' + String(err))
+ setError('Error: ' + getErrorMessage(err))
} finally {
setIsLoading(false)
}
diff --git a/src/frontend/components/_organisms/modals/save-changes-file-modal.tsx b/src/frontend/components/_organisms/modals/save-changes-file-modal.tsx
new file mode 100644
index 000000000..4d93f3e37
--- /dev/null
+++ b/src/frontend/components/_organisms/modals/save-changes-file-modal.tsx
@@ -0,0 +1,164 @@
+import { ComponentPropsWithoutRef } from 'react'
+
+import { useProject } from '../../../../middleware/shared/providers'
+import { WarningIcon } from '../../../assets/icons/interface/Warning'
+import { useOpenPLCStore } from '../../../store'
+import type { FBDFlowType } from '../../../store/slices/fbd'
+import type { LadderFlowType } from '../../../store/slices/ladder'
+import { getExtensionFromLanguage, getFolderFromPouType } from '../../../utils/PLC/pou-file-extensions'
+import { parseGraphicalPouFromString, parseTextualPouFromString } from '../../../utils/PLC/pou-text-parser'
+import { prepareSavePayload } from '../../../utils/save-project'
+import { toast } from '../../_features/[app]/toast/use-toast'
+import { Modal, ModalContent, ModalTitle } from '../../_molecules/modal'
+
+export type SaveChangesFileModalData = {
+ fileName: string
+}
+
+export type SaveChangesFileModalProps = ComponentPropsWithoutRef & {
+ isOpen: boolean
+ data: SaveChangesFileModalData
+}
+
+const SaveChangesFileModal = ({ isOpen, data, ...rest }: SaveChangesFileModalProps) => {
+ const {
+ project,
+ editor: activeEditor,
+ editors,
+ deviceDefinitions,
+ modalActions: { closeModal, onOpenChange },
+ projectActions: { updatePou },
+ sharedWorkspaceActions: { forceCloseFile },
+ fileActions: { updateFile, setAllToSaved },
+ workspaceActions: { setEditingState },
+ snapshotActions: { markAllSaved },
+ ladderFlowActions: { addLadderFlow },
+ fbdFlowActions: { addFBDFlow },
+ } = useOpenPLCStore()
+
+ const projectPort = useProject()
+ const { fileName } = data
+
+ const handleSave = async () => {
+ closeModal()
+
+ const params = prepareSavePayload({
+ projectPath: project.meta.path,
+ projectName: project.meta.name,
+ projectData: project.data,
+ deviceConfiguration: deviceDefinitions.configuration,
+ devicePinMapping: deviceDefinitions.pinMapping.pins,
+ editors,
+ activeEditor,
+ })
+ const result = await projectPort.saveProject(params)
+ if (!result.success) {
+ toast({
+ title: 'Error saving file!',
+ description: result.error ?? 'Save failed',
+ variant: 'fail',
+ })
+ return
+ }
+
+ setEditingState('saved')
+ setAllToSaved()
+ markAllSaved()
+ forceCloseFile(fileName)
+ }
+
+ const handleDontSave = async () => {
+ closeModal()
+
+ // Reload the POU from disk to discard in-memory changes
+ const pou = project.data.pous.find((p) => p.name === fileName)
+ if (pou) {
+ try {
+ const language = pou.body.language
+ const ext = getExtensionFromLanguage(language)
+ const folder = getFolderFromPouType(pou.pouType)
+ const fullPath = `${project.meta.path}/pous/${folder}/${fileName}${ext}`
+
+ const result = await projectPort.readFileContent(fullPath)
+ if (result.success && result.content) {
+ const isGraphical = language === 'ld' || language === 'fbd'
+
+ const parsed = isGraphical
+ ? parseGraphicalPouFromString(result.content, language, pou.pouType)
+ : parseTextualPouFromString(result.content, language, pou.pouType)
+
+ // Restore POU body in the project store
+ updatePou({ name: fileName, content: parsed.body })
+
+ // For graphical POUs, also restore the flow state (nodes, edges, positions).
+ // The parsed body.value is the full flow type (same as what addLadderFlow/addFBDFlow
+ // receive during project open).
+ if (language === 'ld' && parsed.body.value) {
+ addLadderFlow(parsed.body.value as LadderFlowType)
+ } else if (language === 'fbd' && parsed.body.value) {
+ addFBDFlow(parsed.body.value as FBDFlowType)
+ }
+ }
+ } catch {
+ // If reload fails, just close without restoring — same as web fallback
+ }
+ }
+
+ updateFile({ name: fileName, saved: true })
+ forceCloseFile(fileName)
+ }
+
+ const handleCancel = () => {
+ closeModal()
+ }
+
+ return (
+ {
+ if (!open) {
+ handleCancel()
+ }
+ onOpenChange('save-changes-file', open)
+ }}
+ {...rest}
+ >
+
+ Save file changes
+
+
+
+
+ {fileName} has unsaved changes. Do you want to save before closing?
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
+
+export { SaveChangesFileModal }
diff --git a/src2/frontend/components/_organisms/modals/save-changes-modal.tsx b/src/frontend/components/_organisms/modals/save-changes-modal.tsx
similarity index 77%
rename from src2/frontend/components/_organisms/modals/save-changes-modal.tsx
rename to src/frontend/components/_organisms/modals/save-changes-modal.tsx
index e70018918..03a7728a4 100644
--- a/src2/frontend/components/_organisms/modals/save-changes-modal.tsx
+++ b/src/frontend/components/_organisms/modals/save-changes-modal.tsx
@@ -1,8 +1,10 @@
-import { WarningIcon } from '../../../assets/icons/interface/Warning'
-import { useOpenPLCStore } from '../../../store'
-import { useProject, useWindow, useCapabilities } from '../../../../middleware/shared/providers'
import { ComponentPropsWithoutRef } from 'react'
+import { useCapabilities, useProject, useWindow } from '../../../../middleware/shared/providers'
+import { WarningIcon } from '../../../assets/icons/interface/Warning'
+import { useOpenPLCStore } from '../../../store'
+import { prepareSavePayload } from '../../../utils/save-project'
+import { toast } from '../../_features/[app]/toast/use-toast'
import { Modal, ModalContent, ModalTitle } from '../../_molecules/modal'
/**
@@ -26,13 +28,19 @@ export type ValidationContext =
export type SaveChangeModalProps = ComponentPropsWithoutRef & {
isOpen: boolean
validationContext: ValidationContext
+ /** Callback to execute after save+close completes (e.g., re-open recent project). */
+ onAfterAction?: () => void
}
-const SaveChangesModal = ({ isOpen, validationContext, ...rest }: SaveChangeModalProps) => {
+const SaveChangesModal = ({ isOpen, validationContext, onAfterAction, ...rest }: SaveChangeModalProps) => {
const {
project,
+ editor: activeEditor,
+ editors,
deviceDefinitions,
workspaceActions: { setEditingState },
+ fileActions: { setAllToSaved },
+ snapshotActions: { markAllSaved },
modalActions: { closeModal, onOpenChange, openModal },
} = useOpenPLCStore()
@@ -40,8 +48,12 @@ const SaveChangesModal = ({ isOpen, validationContext, ...rest }: SaveChangeModa
const windowPort = useWindow()
const capabilities = useCapabilities()
+ const {
+ sharedWorkspaceActions: { clearStatesOnCloseProject },
+ } = useOpenPLCStore()
+
const clearAndClose = () => {
- // Web navigates back; editor resets editing state
+ clearStatesOnCloseProject()
setEditingState('initial-state')
if (!capabilities.hasLocalFilesystem) {
window.history.back()
@@ -52,15 +64,32 @@ const SaveChangesModal = ({ isOpen, validationContext, ...rest }: SaveChangeModa
closeModal()
if (operation === 'save') {
- const result = await projectPort.saveProject({
+ const params = prepareSavePayload({
projectPath: project.meta.path,
+ projectName: project.meta.name,
projectData: project.data,
deviceConfiguration: deviceDefinitions.configuration,
devicePinMapping: deviceDefinitions.pinMapping.pins,
+ editors,
+ activeEditor,
})
+ const result = await projectPort.saveProject(params)
if (!result.success) {
+ toast({
+ title: 'Error in the save request!',
+ description: result.error ?? 'Save failed',
+ variant: 'fail',
+ })
return
}
+ setEditingState('saved')
+ setAllToSaved()
+ markAllSaved()
+ toast({
+ title: 'Changes saved!',
+ description: 'The project was saved successfully!',
+ variant: 'default',
+ })
}
switch (validationContext) {
@@ -72,10 +101,9 @@ const SaveChangesModal = ({ isOpen, validationContext, ...rest }: SaveChangeModa
await projectPort.openProject()
return
case 'open-recent-project':
- // Editor-specific: handled via IPC callback outside the modal
- return
case 'open-project-by-path':
- // Editor-specific: handled via IPC callback outside the modal
+ // Execute the deferred action (e.g., re-open the recent project)
+ onAfterAction?.()
return
case 'close-project':
clearAndClose()
diff --git a/src2/frontend/components/_organisms/modals/server-ip-mismatch-modal.tsx b/src/frontend/components/_organisms/modals/server-ip-mismatch-modal.tsx
similarity index 97%
rename from src2/frontend/components/_organisms/modals/server-ip-mismatch-modal.tsx
rename to src/frontend/components/_organisms/modals/server-ip-mismatch-modal.tsx
index eabf312bb..67910dc17 100644
--- a/src2/frontend/components/_organisms/modals/server-ip-mismatch-modal.tsx
+++ b/src/frontend/components/_organisms/modals/server-ip-mismatch-modal.tsx
@@ -1,7 +1,7 @@
-import { WarningIcon } from '../../../assets/icons/interface/Warning'
-import { useOpenPLCStore } from '../../../store'
import { ComponentPropsWithoutRef } from 'react'
+import { WarningIcon } from '../../../assets/icons/interface/Warning'
+import { useOpenPLCStore } from '../../../store'
import { Modal, ModalContent, ModalTitle } from '../../_molecules/modal'
export type ServerIpMismatch = {
@@ -101,7 +101,7 @@ const ServerIpMismatchModal = ({ isOpen, ...rest }: ServerIpMismatchModalProps)
diff --git a/src/renderer/components/_organisms/navigation/index.tsx b/src/frontend/components/_organisms/navigation/index.tsx
similarity index 100%
rename from src/renderer/components/_organisms/navigation/index.tsx
rename to src/frontend/components/_organisms/navigation/index.tsx
diff --git a/src2/frontend/components/_organisms/panel/__tests__/panel.test.tsx b/src/frontend/components/_organisms/panel/__tests__/panel.test.tsx
similarity index 90%
rename from src2/frontend/components/_organisms/panel/__tests__/panel.test.tsx
rename to src/frontend/components/_organisms/panel/__tests__/panel.test.tsx
index ccf9f76b7..4cd0e6b6b 100644
--- a/src2/frontend/components/_organisms/panel/__tests__/panel.test.tsx
+++ b/src/frontend/components/_organisms/panel/__tests__/panel.test.tsx
@@ -2,8 +2,16 @@ import { render } from '@testing-library/react'
// Mock react-resizable-panels
vi.mock('react-resizable-panels', () => ({
- Panel: ({ children, ...props }: { children?: React.ReactNode }) => {children} ,
- PanelGroup: ({ children, ...props }: { children?: React.ReactNode }) => {children} ,
+ Panel: ({ children, ...props }: { children?: React.ReactNode }) => (
+
+ {children}
+
+ ),
+ PanelGroup: ({ children, ...props }: { children?: React.ReactNode }) => (
+
+ {children}
+
+ ),
PanelResizeHandle: ({ children, ...props }: { children?: React.ReactNode }) => (
{children}
diff --git a/src2/frontend/components/_organisms/panel/index.tsx b/src/frontend/components/_organisms/panel/index.tsx
similarity index 99%
rename from src2/frontend/components/_organisms/panel/index.tsx
rename to src/frontend/components/_organisms/panel/index.tsx
index e58ba585a..2c9d194a0 100644
--- a/src2/frontend/components/_organisms/panel/index.tsx
+++ b/src/frontend/components/_organisms/panel/index.tsx
@@ -1,8 +1,9 @@
import { DragHandleDots2Icon } from '@radix-ui/react-icons'
-import { cn } from '../../../utils/cn'
import { ComponentProps } from 'react'
import { Panel, PanelGroup, PanelResizeHandle } from 'react-resizable-panels'
+import { cn } from '../../../utils/cn'
+
type IResizablePanelGroupProps = ComponentProps
const ResizablePanelGroup = ({ className, ...res }: IResizablePanelGroupProps) => (
diff --git a/src2/frontend/components/_organisms/pin-mapping-editor/index.tsx b/src/frontend/components/_organisms/pin-mapping-editor/index.tsx
similarity index 100%
rename from src2/frontend/components/_organisms/pin-mapping-editor/index.tsx
rename to src/frontend/components/_organisms/pin-mapping-editor/index.tsx
diff --git a/src2/frontend/components/_organisms/plc-logs/filters.tsx b/src/frontend/components/_organisms/plc-logs/filters.tsx
similarity index 99%
rename from src2/frontend/components/_organisms/plc-logs/filters.tsx
rename to src/frontend/components/_organisms/plc-logs/filters.tsx
index 0dd1fd880..1f9c7ab84 100644
--- a/src2/frontend/components/_organisms/plc-logs/filters.tsx
+++ b/src/frontend/components/_organisms/plc-logs/filters.tsx
@@ -1,10 +1,11 @@
+import { ChevronDown, Download, Filter, Search, X } from 'lucide-react'
+import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react'
+
+import { isV4Logs, RuntimeLogEntry, RuntimeLogLevel } from '../../../../middleware/shared/ports'
import { useOpenPLCStore } from '../../../store'
import { TimestampFormat } from '../../../store/slices/console/types'
-import { isV4Logs, RuntimeLogEntry, RuntimeLogLevel } from '../../../../middleware/shared/ports'
import { cn } from '../../../utils/cn'
import formatTimestamp from '../../../utils/format-timestamp'
-import { ChevronDown, Download, Filter, Search, X } from 'lucide-react'
-import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react'
type LogLevel = 'debug' | 'info' | 'warning' | 'error'
type ExportFormat = 'txt' | 'csv' | 'json'
diff --git a/src2/frontend/components/_organisms/plc-logs/index.tsx b/src/frontend/components/_organisms/plc-logs/index.tsx
similarity index 100%
rename from src2/frontend/components/_organisms/plc-logs/index.tsx
rename to src/frontend/components/_organisms/plc-logs/index.tsx
index bc7fe3881..ac69f67d2 100644
--- a/src2/frontend/components/_organisms/plc-logs/index.tsx
+++ b/src/frontend/components/_organisms/plc-logs/index.tsx
@@ -1,9 +1,9 @@
-import { useOpenPLCStore } from '../../../store'
-import { isV4Logs, RuntimeLogEntry, RuntimeLogLevel } from '../../../../middleware/shared/ports'
-import formatTimestamp from '../../../utils/format-timestamp'
import { debounce } from 'lodash'
import { memo, useEffect, useMemo, useRef } from 'react'
+import { isV4Logs, RuntimeLogEntry, RuntimeLogLevel } from '../../../../middleware/shared/ports'
+import { useOpenPLCStore } from '../../../store'
+import formatTimestamp from '../../../utils/format-timestamp'
import { LogComponent, LogLevel } from '../console/log'
const mapV4LevelToLogLevel = (level: RuntimeLogLevel): LogLevel => {
diff --git a/src2/frontend/components/_organisms/project-filter-bar/index.tsx b/src/frontend/components/_organisms/project-filter-bar/index.tsx
similarity index 100%
rename from src2/frontend/components/_organisms/project-filter-bar/index.tsx
rename to src/frontend/components/_organisms/project-filter-bar/index.tsx
index 9bcc4ce6f..62522284a 100644
--- a/src2/frontend/components/_organisms/project-filter-bar/index.tsx
+++ b/src/frontend/components/_organisms/project-filter-bar/index.tsx
@@ -1,9 +1,9 @@
import * as PrimitiveDropdown from '@radix-ui/react-dropdown-menu'
+import { ReactNode, useEffect, useState } from 'react'
+
import { ArrowIcon } from '../../../assets/icons/interface/Arrow'
import { MagnifierIcon } from '../../../assets/icons/interface/Magnifier'
import { useOpenPLCStore } from '../../../store'
-import { ReactNode, useEffect, useState } from 'react'
-
import { InputWithRef } from '../../_atoms/input'
interface ProjectFilterBarProps {
diff --git a/src2/frontend/components/_organisms/task-editor/index.tsx b/src/frontend/components/_organisms/task-editor/index.tsx
similarity index 94%
rename from src2/frontend/components/_organisms/task-editor/index.tsx
rename to src/frontend/components/_organisms/task-editor/index.tsx
index 8856ab26b..2ff871db6 100644
--- a/src2/frontend/components/_organisms/task-editor/index.tsx
+++ b/src/frontend/components/_organisms/task-editor/index.tsx
@@ -1,16 +1,16 @@
+import { useCallback, useEffect, useState } from 'react'
+
+import type { PLCTask } from '../../../../middleware/shared/ports/types'
+import { CodeIcon } from '../../../assets/icons/interface/CodeIcon'
import { MinusIcon } from '../../../assets/icons/interface/Minus'
import { PlusIcon } from '../../../assets/icons/interface/Plus'
import { StickArrowIcon } from '../../../assets/icons/interface/StickArrow'
-import { CodeIcon } from '../../../assets/icons/interface/CodeIcon'
import { TableIcon } from '../../../assets/icons/interface/TableIcon'
import { useOpenPLCStore } from '../../../store'
import type { TaskType } from '../../../store/slices/editor'
-import type { PLCTask } from '../../../../middleware/shared/ports/types'
import { cn } from '../../../utils/cn'
import { parseResourceConfigurationToString } from '../../../utils/parse-resource-configuration-to-string'
import { parseResourceStringToConfiguration } from '../../../utils/parse-resource-string-to-configuration'
-import { useEffect, useState } from 'react'
-
import TableActions from '../../_atoms/table-actions'
import { toast } from '../../_features/[app]/toast/use-toast'
import { TaskTable } from '../../_molecules/task-table'
@@ -26,16 +26,36 @@ const TaskEditor = () => {
},
project: {
data: {
- configuration: {
+ configurations: {
resource: { tasks, instances },
},
},
},
editorActions: { updateModelTasks },
- projectActions: { createTask, rearrangeTasks, deleteTask, setTasks, setInstances, pushToHistory },
+ projectActions: { createTask, rearrangeTasks, deleteTask, setTasks, setInstances },
sharedWorkspaceActions: { handleFileAndWorkspaceSavedState },
} = useOpenPLCStore()
+ const {
+ project: {
+ data: { pous: snapshotPous, configurations },
+ },
+ snapshotActions: { pushToHistory: rawPushToHistory },
+ } = useOpenPLCStore()
+
+ const pushToHistory = useCallback(
+ (pouName: string) => {
+ const pou = snapshotPous.find((p) => p.name === pouName)
+ if (!pou) return
+ rawPushToHistory(pouName, {
+ variables: pou.interface?.variables ?? [],
+ body: pou.body.value,
+ globalVariables: configurations.resource.globalVariables,
+ })
+ },
+ [snapshotPous, configurations.resource.globalVariables, rawPushToHistory],
+ )
+
const [taskData, setTaskData] = useState([])
const [editorCode, setEditorCode] = useState(() => parseResourceConfigurationToString(taskData, instances))
const [parseError, setParseError] = useState(null)
@@ -87,7 +107,6 @@ const TaskEditor = () => {
selectedRow: editorTasks.display === 'table' ? parseInt(editorTasks.selectedRow) : ROWS_NOT_SELECTED,
})
} else {
- // @ts-expect-error: 'selectedRow' is not required when display is 'code'
updateModelTasks({
display: 'code',
})
diff --git a/src/renderer/components/_organisms/title-bar/index.tsx b/src/frontend/components/_organisms/title-bar/index.tsx
similarity index 100%
rename from src/renderer/components/_organisms/title-bar/index.tsx
rename to src/frontend/components/_organisms/title-bar/index.tsx
diff --git a/src2/frontend/components/_organisms/title-bar/slots/center-slot.tsx b/src/frontend/components/_organisms/title-bar/slots/center-slot.tsx
similarity index 100%
rename from src2/frontend/components/_organisms/title-bar/slots/center-slot.tsx
rename to src/frontend/components/_organisms/title-bar/slots/center-slot.tsx
index 254a02abc..dab0e2fee 100644
--- a/src2/frontend/components/_organisms/title-bar/slots/center-slot.tsx
+++ b/src/frontend/components/_organisms/title-bar/slots/center-slot.tsx
@@ -1,6 +1,6 @@
+import { useCapabilities } from '../../../../../middleware/shared/providers'
import { OpenPLCIcon } from '../../../../assets/icons/oplc'
import { useOpenPLCStore } from '../../../../store'
-import { useCapabilities } from '../../../../../middleware/shared/providers'
import { cn } from '../../../../utils/cn'
const TitleBarCenterSlot = () => {
diff --git a/src/renderer/components/_organisms/title-bar/slots/index.ts b/src/frontend/components/_organisms/title-bar/slots/index.ts
similarity index 100%
rename from src/renderer/components/_organisms/title-bar/slots/index.ts
rename to src/frontend/components/_organisms/title-bar/slots/index.ts
diff --git a/src2/frontend/components/_organisms/title-bar/slots/left-slot.tsx b/src/frontend/components/_organisms/title-bar/slots/left-slot.tsx
similarity index 100%
rename from src2/frontend/components/_organisms/title-bar/slots/left-slot.tsx
rename to src/frontend/components/_organisms/title-bar/slots/left-slot.tsx
index e09328d57..e740640b3 100644
--- a/src2/frontend/components/_organisms/title-bar/slots/left-slot.tsx
+++ b/src/frontend/components/_organisms/title-bar/slots/left-slot.tsx
@@ -1,7 +1,7 @@
+import { useCapabilities } from '../../../../../middleware/shared/providers'
import { OpenPLCIcon } from '../../../../assets/icons/oplc'
-import { MenuBar } from '../../../_molecules/menu-bar'
import { useOpenPLCStore } from '../../../../store'
-import { useCapabilities } from '../../../../../middleware/shared/providers'
+import { MenuBar } from '../../../_molecules/menu-bar'
export const TitleBarLeftSlot = () => {
const caps = useCapabilities()
diff --git a/src2/frontend/components/_organisms/title-bar/slots/right-slot.tsx b/src/frontend/components/_organisms/title-bar/slots/right-slot.tsx
similarity index 100%
rename from src2/frontend/components/_organisms/title-bar/slots/right-slot.tsx
rename to src/frontend/components/_organisms/title-bar/slots/right-slot.tsx
diff --git a/src2/frontend/components/_organisms/variables-code-editor/index.tsx b/src/frontend/components/_organisms/variables-code-editor/index.tsx
similarity index 100%
rename from src2/frontend/components/_organisms/variables-code-editor/index.tsx
rename to src/frontend/components/_organisms/variables-code-editor/index.tsx
diff --git a/src2/frontend/components/_organisms/variables-editor/index.tsx b/src/frontend/components/_organisms/variables-editor/index.tsx
similarity index 94%
rename from src2/frontend/components/_organisms/variables-editor/index.tsx
rename to src/frontend/components/_organisms/variables-editor/index.tsx
index 358deb129..d44fed81c 100644
--- a/src2/frontend/components/_organisms/variables-editor/index.tsx
+++ b/src/frontend/components/_organisms/variables-editor/index.tsx
@@ -1,30 +1,37 @@
+import { ColumnFiltersState } from '@tanstack/react-table'
+import { useCallback, useEffect, useRef, useState } from 'react'
+
+import { PLCVariable } from '../../../../middleware/shared/ports/types'
+import { CodeIcon } from '../../../assets/icons/interface/CodeIcon'
import { MinusIcon } from '../../../assets/icons/interface/Minus'
import { PlusIcon } from '../../../assets/icons/interface/Plus'
import { StickArrowIcon } from '../../../assets/icons/interface/StickArrow'
-import { CodeIcon } from '../../../assets/icons/interface/CodeIcon'
import { TableIcon } from '../../../assets/icons/interface/TableIcon'
import { useOpenPLCStore } from '../../../store'
+import type { VariablesTable as VariablesTableType } from '../../../store/slices/editor'
import type { FBDFlowActions, FBDFlowState } from '../../../store/slices/fbd'
import type { LadderFlowActions, LadderFlowState } from '../../../store/slices/ladder'
-import type { VariablesTable as VariablesTableType } from '../../../store/slices/editor'
-import { TypeChangeValidationResult, validateTypeChange, } from '../../../store/slices/project/validation/type-change'
-import { syncNodesWithVariables as syncNodesWithVariablesUtil, syncNodesWithVariablesFBD as syncNodesWithVariablesFBDUtil, } from '../../../utils/graphical/sync-nodes-with-variables'
-import { findAllReferencesToVariable, propagateVariableRename, type ReferenceImpactAnalysis, } from '../../../utils/variable-references'
-import { baseTypes } from '../../../utils/plc-constants'
-import { PLCVariable } from '../../../../middleware/shared/ports/types'
+import { TypeChangeValidationResult, validateTypeChange } from '../../../store/slices/project/validation/type-change'
import { cn } from '../../../utils/cn'
import { parseIecStringToVariables } from '../../../utils/generate-iec-string-to-variables'
import { generateIecVariablesToString } from '../../../utils/generate-iec-variables-to-string'
-import { ColumnFiltersState } from '@tanstack/react-table'
-import { useEffect, useRef, useState } from 'react'
-
+import {
+ syncNodesWithVariables as syncNodesWithVariablesUtil,
+ syncNodesWithVariablesFBD as syncNodesWithVariablesFBDUtil,
+} from '../../../utils/graphical/sync-nodes-with-variables'
+import { baseTypes } from '../../../utils/plc-constants'
+import {
+ findAllReferencesToVariable,
+ propagateVariableRename,
+ type ReferenceImpactAnalysis,
+} from '../../../utils/variable-references'
import { InputWithRef } from '../../_atoms/input'
import { Select, SelectContent, SelectItem, SelectTrigger } from '../../_atoms/select'
import TableActions from '../../_atoms/table-actions'
import { toast } from '../../_features/[app]/toast/use-toast'
-import { VariablesTable } from '../../_molecules/variables-table'
import { RenameImpactModal } from '../../_molecules/rename-impact-modal'
import { TypeChangeModal } from '../../_molecules/type-change-modal'
+import { VariablesTable } from '../../_molecules/variables-table'
import { VariablesCodeEditor } from '../variables-code-editor'
const VariablesEditor = () => {
@@ -55,11 +62,30 @@ const VariablesEditor = () => {
setPouVariables,
updatePou,
updateVariable,
- pushToHistory,
},
sharedWorkspaceActions: { handleFileAndWorkspaceSavedState },
} = useOpenPLCStore()
+ const {
+ project: {
+ data: { pous: snapshotPous, configurations },
+ },
+ snapshotActions: { pushToHistory: rawPushToHistory },
+ } = useOpenPLCStore()
+
+ const pushToHistory = useCallback(
+ (pouName: string) => {
+ const pou = snapshotPous.find((p) => p.name === pouName)
+ if (!pou) return
+ rawPushToHistory(pouName, {
+ variables: pou.interface?.variables ?? [],
+ body: pou.body.value,
+ globalVariables: configurations.resource.globalVariables,
+ })
+ },
+ [snapshotPous, configurations.resource.globalVariables, rawPushToHistory],
+ )
+
/**
* Table data and column filters states to keep track of the table data and column filters
*/
@@ -75,7 +101,7 @@ const VariablesEditor = () => {
) {
return editor.variable.code
}
- return generateIecVariablesToString(tableData as PLCVariable[])
+ return generateIecVariablesToString(tableData)
})
const [parseError, setParseError] = useState(null)
const [pouDescription, setPouDescription] = useState('')
@@ -115,23 +141,23 @@ const VariablesEditor = () => {
}
})
- const pou = pous.find((p) => p.data.name === editor.meta.name)
+ const pou = pous.find((p) => p.name === editor.meta.name)
useEffect(() => {
- const data = pou?.data.documentation
+ const data = pou?.documentation
if (data) setPouDescription(data)
return () => {
setPouDescription('')
}
- }, [editor, pou?.data.documentation])
+ }, [editor, pou?.documentation])
/**
* Update the table data and the editor's variables when the editor or the pous change
*/
useEffect(() => {
if (pou) {
- setTableData(pou.data.variables)
- if (pou.type === 'function') {
- setReturnType(pou.data.returnType)
+ setTableData(pou.interface?.variables ?? [])
+ if (pou.pouType === 'function') {
+ setReturnType(pou.interface?.returnType ?? 'BOOL')
}
} else {
setTableData([])
@@ -148,7 +174,7 @@ const VariablesEditor = () => {
useEffect(() => {
if (editorVariables.display !== 'code') {
- setEditorCode(generateIecVariablesToString(tableData as PLCVariable[]))
+ setEditorCode(generateIecVariablesToString(tableData))
}
}, [tableData, editorVariables.display])
@@ -291,7 +317,8 @@ const VariablesEditor = () => {
pushToHistory(editor.meta.name)
- const variables = pous.filter((pou) => pou.data.name === editor.meta.name)[0].data.variables
+ const matchedPou = pous.find((p) => p.name === editor.meta.name)
+ const variables = matchedPou?.interface?.variables ?? []
const selectedRow = parseInt(editorVariables.selectedRow)
const language = 'language' in editor.meta ? editor.meta.language : null
@@ -304,7 +331,7 @@ const VariablesEditor = () => {
data: {
name: 'LocalVar',
class: defaultClass,
- type: { definition: 'base-type', value: 'dint' },
+ type: { definition: 'base-type', value: 'DINT' },
location: '',
documentation: '',
debug: false,
@@ -328,7 +355,7 @@ const VariablesEditor = () => {
data: {
...variable,
class: defaultClass,
- type: variable.type.definition === 'derived' ? { definition: 'base-type', value: 'dint' } : variable.type,
+ type: variable.type.definition === 'derived' ? { definition: 'base-type', value: 'DINT' } : variable.type,
},
})
updateModelVariables({
@@ -344,7 +371,7 @@ const VariablesEditor = () => {
data: {
...variable,
class: defaultClass,
- type: variable.type.definition === 'derived' ? { definition: 'base-type', value: 'dint' } : variable.type,
+ type: variable.type.definition === 'derived' ? { definition: 'base-type', value: 'DINT' } : variable.type,
},
rowToInsert: selectedRow + 1,
})
@@ -361,7 +388,8 @@ const VariablesEditor = () => {
pushToHistory(editor.meta.name)
const selectedRow = parseInt(editorVariables.selectedRow)
- const variables = pous.filter((pou) => pou.data.name === editor.meta.name)[0].data.variables
+ const deletePou = pous.find((p) => p.name === editor.meta.name)
+ const variables = deletePou?.interface?.variables ?? []
const variableToDelete = variables[selectedRow]
if (variableToDelete) {
@@ -792,7 +820,7 @@ const VariablesEditor = () => {
})
const response = setPouVariables({
- pouName: pou?.data?.name ?? '',
+ pouName: pou?.name ?? '',
variables: finalVariables,
})
@@ -808,8 +836,8 @@ const VariablesEditor = () => {
fbdFlows: freshFBDFlows,
} = useOpenPLCStore.getState()
- const freshPou = freshPous.find((p) => p.data.name === editor.meta.name)
- const freshVariables = freshPou?.data.variables ?? []
+ const freshPou = freshPous.find((p) => p.name === editor.meta.name)
+ const freshVariables = freshPou?.interface?.variables ?? []
if (language === 'ld') {
syncNodesWithVariablesUtil(freshVariables, freshLadderFlows, updateNode)
@@ -850,7 +878,7 @@ const VariablesEditor = () => {
setParseError(null)
handleFileAndWorkspaceSavedState(editor.meta.name)
- if (freshPou && 'variablesText' in freshPou.data) {
+ if (freshPou && freshPou.interface && 'variablesText' in freshPou.interface) {
clearPouVariablesText(editor.meta.name)
}
diff --git a/src/frontend/components/_organisms/workspace-activity-bar/default.tsx b/src/frontend/components/_organisms/workspace-activity-bar/default.tsx
new file mode 100644
index 000000000..d7728c051
--- /dev/null
+++ b/src/frontend/components/_organisms/workspace-activity-bar/default.tsx
@@ -0,0 +1,667 @@
+import { useCallback, useEffect, useRef, useState } from 'react'
+
+import type { DebugConnectionConfig } from '../../../../middleware/shared/ports/types'
+import { useCompiler, useDebugger, useProject, useRuntime, useSimulator } from '../../../../middleware/shared/providers'
+import { StopIcon } from '../../../assets/icons/interface/Stop'
+import { useDebugPolling } from '../../../hooks/useDebugPolling'
+import { useDebugSession } from '../../../hooks/useDebugSession'
+import { useOpenPLCStore } from '../../../store'
+import type { RuntimeConnection } from '../../../store/slices/device/types'
+import { cn } from '../../../utils/cn'
+import { logCompilerEvent } from '../../../utils/debugger-session'
+import { isOpenPLCRuntimeTarget, isOpenPLCRuntimeV4Target } from '../../../utils/device'
+import { getErrorMessage } from '../../../utils/get-error-message'
+import { prepareSavePayload } from '../../../utils/save-project'
+import { ChatButton } from '../../_molecules/workspace-activity-bar/default/chat'
+import { DebuggerButton } from '../../_molecules/workspace-activity-bar/default/debugger'
+import { DownloadButton } from '../../_molecules/workspace-activity-bar/default/download'
+import { PlayButton } from '../../_molecules/workspace-activity-bar/default/play'
+import { SearchButton } from '../../_molecules/workspace-activity-bar/default/search'
+import { ZoomButton } from '../../_molecules/workspace-activity-bar/default/zoom'
+import { TooltipSidebarWrapperButton } from '../../_molecules/workspace-activity-bar/tooltip-button'
+
+const showDebuggerMessage = (
+ type: 'info' | 'warning' | 'error' | 'question',
+ title: string,
+ message: string,
+ buttons: string[],
+): Promise => {
+ return new Promise((resolve) => {
+ useOpenPLCStore.getState().modalActions.openModal('debugger-message', {
+ type,
+ title,
+ message,
+ buttons,
+ onResponse: (buttonIndex: number) => resolve(buttonIndex),
+ })
+ })
+}
+
+const showDebuggerIpInput = (title: string, message: string, defaultValue: string): Promise => {
+ return new Promise((resolve) => {
+ useOpenPLCStore.getState().modalActions.openModal('debugger-ip-input', {
+ title,
+ message,
+ defaultValue,
+ onSubmit: (value: string) => resolve(value),
+ onCancel: () => resolve(null),
+ })
+ })
+}
+
+const disabledButtonClass = 'cursor-not-allowed opacity-50 [&>*:first-child]:hover:bg-transparent'
+
+type DefaultWorkspaceActivityBarProps = {
+ zoom?: {
+ onClick: () => void
+ }
+}
+
+export const DefaultWorkspaceActivityBar = ({ zoom }: DefaultWorkspaceActivityBarProps) => {
+ const {
+ project: { data: projectData, meta: projectMeta },
+ deviceDefinitions,
+ deviceAvailableOptions: { availableBoards },
+ consoleActions: { addLog },
+ } = useOpenPLCStore()
+
+ const compiler = useCompiler()
+ const runtime = useRuntime()
+ const simulator = useSimulator()
+ const debuggerPort = useDebugger()
+ const projectPort = useProject()
+ const debugSession = useDebugSession()
+ useDebugPolling({ debugTreesRef: debugSession.debugTreesRef })
+
+ const [isCompiling, setIsCompiling] = useState(false)
+ const [isDebuggerProcessing, setIsDebuggerProcessing] = useState(false)
+ const [simulatorRunning, setSimulatorRunning] = useState(false)
+ const pendingSimulatorDebugRef = useRef(false)
+
+ const connectionStatus = useOpenPLCStore((state) => state.runtimeConnection.connectionStatus)
+ const plcStatus = useOpenPLCStore((state): RuntimeConnection['plcStatus'] => state.runtimeConnection.plcStatus)
+ const jwtToken = useOpenPLCStore((state) => state.runtimeConnection.jwtToken)
+ const editingState = useOpenPLCStore((state) => state.workspace.editingState)
+ const isDebuggerVisible = useOpenPLCStore((state) => state.workspace.isDebuggerVisible)
+
+ const currentBoardInfo = availableBoards.get(deviceDefinitions.configuration.deviceBoard)
+ const isSimulatorBoard = currentBoardInfo?.compiler === 'simulator'
+
+ // Sync simulatorRunning when the simulator stops externally
+ useEffect(() => {
+ const unsub = simulator.onStopped(() => {
+ pendingSimulatorDebugRef.current = false
+ setSimulatorRunning(false)
+ const { workspace } = useOpenPLCStore.getState()
+ if (workspace.isDebuggerVisible) {
+ void debugSession.stopSession()
+ }
+ })
+ return unsub
+ }, [simulator, debugSession])
+
+ // Stop simulator if the board is switched away while it's running
+ const prevIsSimulatorBoardRef = useRef(isSimulatorBoard)
+ useEffect(() => {
+ const wasSimulator = prevIsSimulatorBoardRef.current
+ prevIsSimulatorBoardRef.current = isSimulatorBoard
+
+ if (wasSimulator && !isSimulatorBoard && simulator.isRunning()) {
+ addLog({
+ id: crypto.randomUUID(),
+ level: 'info',
+ message: 'Board changed from simulator. Stopping simulator.',
+ })
+ void simulator.stop()
+ if (isDebuggerVisible) {
+ const { workspaceActions } = useOpenPLCStore.getState()
+ workspaceActions.clearDebugState()
+ }
+ }
+ }, [isSimulatorBoard, isDebuggerVisible, simulator, addLog])
+
+ const executeSave = useCallback(async (): Promise => {
+ const state = useOpenPLCStore.getState()
+ const { workspaceActions, fileActions, snapshotActions, editors } = state
+ const activeEditor = editors[0] ?? { type: 'available', meta: { name: '' } }
+ try {
+ workspaceActions.setEditingState('save-request')
+ const payload = prepareSavePayload({
+ projectPath: projectMeta.path,
+ projectName: projectMeta.name,
+ projectData,
+ deviceConfiguration: deviceDefinitions.configuration,
+ devicePinMapping: deviceDefinitions.pinMapping.pins,
+ editors,
+ activeEditor,
+ })
+ const res = await projectPort.saveProject(payload)
+ if (res.success) {
+ workspaceActions.setEditingState('saved')
+ fileActions.setAllToSaved()
+ snapshotActions.markAllSaved()
+ return true
+ }
+ workspaceActions.setEditingState('unsaved')
+ addLog({ id: crypto.randomUUID(), level: 'error', message: `Save failed: ${res.error ?? 'Unknown error'}` })
+ return false
+ } catch {
+ workspaceActions.setEditingState('unsaved')
+ return false
+ }
+ }, [projectPort, projectMeta, projectData, deviceDefinitions, addLog])
+
+ // ---------------------------------------------------------------------------
+ // Build (Compile)
+ // ---------------------------------------------------------------------------
+
+ const handleBuild = useCallback(async () => {
+ if (isCompiling) return
+
+ if (editingState === 'unsaved') {
+ const saved = await executeSave()
+ if (!saved) return
+ }
+
+ setIsCompiling(true)
+ addLog({ id: crypto.randomUUID(), level: 'info', message: 'Build process started' })
+
+ try {
+ const result = await compiler.compileProgram(
+ {
+ projectData,
+ boardTarget: deviceDefinitions.configuration.deviceBoard,
+ projectPath: projectMeta.path,
+ compileOnly: deviceDefinitions.configuration.compileOnly,
+ isSimulator: isSimulatorBoard,
+ runtimeIpAddress: deviceDefinitions.configuration.runtimeIpAddress || null,
+ runtimeJwtToken: jwtToken || null,
+ },
+ (event) => {
+ if (event.plcStatus) {
+ useOpenPLCStore
+ .getState()
+ .deviceActions.setPlcRuntimeStatus(event.plcStatus as NonNullable)
+ }
+ logCompilerEvent(event, addLog)
+ if (event.firmwarePath && isSimulatorBoard) {
+ void simulator.loadFirmware(event.firmwarePath).then((loadResult) => {
+ if (loadResult.success) {
+ setSimulatorRunning(true)
+ addLog({ id: crypto.randomUUID(), level: 'info', message: 'Simulator is running.' })
+ if (pendingSimulatorDebugRef.current) {
+ pendingSimulatorDebugRef.current = false
+ void debugSession.connectAndStart()
+ }
+ } else {
+ pendingSimulatorDebugRef.current = false
+ addLog({
+ id: crypto.randomUUID(),
+ level: 'error',
+ message: `Failed to start simulator: ${loadResult.error ?? 'Unknown error'}`,
+ })
+ }
+ })
+ }
+ },
+ )
+
+ if (!result.success) {
+ addLog({ id: crypto.randomUUID(), level: 'error', message: result.error ?? 'Compilation failed' })
+ }
+ } catch (err: unknown) {
+ addLog({ id: crypto.randomUUID(), level: 'error', message: `Build error: ${getErrorMessage(err)}` })
+ } finally {
+ setIsCompiling(false)
+ }
+ }, [
+ compiler,
+ projectData,
+ projectMeta,
+ deviceDefinitions,
+ isSimulatorBoard,
+ simulator,
+ debugSession,
+ addLog,
+ isCompiling,
+ editingState,
+ executeSave,
+ jwtToken,
+ ])
+
+ const handleBuildRef = useRef(handleBuild)
+ handleBuildRef.current = handleBuild
+
+ // ---------------------------------------------------------------------------
+ // PLC control (Start/Stop for runtime targets)
+ // ---------------------------------------------------------------------------
+
+ const handlePlcControl = useCallback(async (): Promise => {
+ if (!jwtToken || connectionStatus !== 'connected') return
+
+ try {
+ if (plcStatus === 'RUNNING') {
+ const result = await runtime.stopPlc()
+ if (!result.success) {
+ addLog({
+ id: crypto.randomUUID(),
+ level: 'error',
+ message: `Failed to stop PLC: ${result.error ?? 'Unknown error'}`,
+ })
+ return
+ }
+ } else {
+ const result = await runtime.startPlc()
+ if (!result.success) {
+ addLog({
+ id: crypto.randomUUID(),
+ level: 'error',
+ message: `Failed to start PLC: ${result.error ?? 'Unknown error'}`,
+ })
+ return
+ }
+ }
+
+ const statusResult = await runtime.getStatus()
+ if (statusResult.success && statusResult.status) {
+ useOpenPLCStore
+ .getState()
+ .deviceActions.setPlcRuntimeStatus(statusResult.status as NonNullable)
+ }
+ } catch (error: unknown) {
+ addLog({ id: crypto.randomUUID(), level: 'error', message: `PLC control error: ${getErrorMessage(error)}` })
+ }
+ }, [runtime, jwtToken, connectionStatus, plcStatus, addLog])
+
+ // ---------------------------------------------------------------------------
+ // Simulator control (Start/Stop simulator + auto-debug)
+ // ---------------------------------------------------------------------------
+
+ const handleSimulatorControl = useCallback(async (): Promise => {
+ try {
+ if (simulatorRunning) {
+ await debugSession.stopSession()
+ setSimulatorRunning(false)
+ addLog({ id: crypto.randomUUID(), level: 'info', message: 'Simulator stopped.' })
+ } else {
+ pendingSimulatorDebugRef.current = true
+ handleBuildRef.current().catch(() => {
+ pendingSimulatorDebugRef.current = false
+ })
+ }
+ } catch (error: unknown) {
+ pendingSimulatorDebugRef.current = false
+ addLog({ id: crypto.randomUUID(), level: 'error', message: `Simulator control error: ${getErrorMessage(error)}` })
+ }
+ }, [debugSession, simulatorRunning, addLog])
+
+ // ---------------------------------------------------------------------------
+ // MD5 verification — runs after debug compilation for non-simulator
+ // ---------------------------------------------------------------------------
+
+ const handleMd5Verification = async (
+ projectPath: string,
+ boardTarget: string,
+ debugConfig: DebugConnectionConfig,
+ isRuntimeTarget: boolean,
+ ) => {
+ const { consoleActions, runtimeConnection, deviceActions } = useOpenPLCStore.getState()
+
+ try {
+ // If runtime target + PLC stopped, offer to start
+ if (isRuntimeTarget && runtimeConnection.plcStatus === 'STOPPED' && runtimeConnection.jwtToken) {
+ const response = await showDebuggerMessage(
+ 'question',
+ 'PLC Stopped',
+ 'The PLC is currently stopped. The debugger requires the PLC to be running. Would you like to start the PLC now?',
+ ['Yes', 'No'],
+ )
+ if (response === 1) {
+ consoleActions.addLog({ id: crypto.randomUUID(), level: 'info', message: 'Debugger session cancelled.' })
+ setIsDebuggerProcessing(false)
+ return
+ }
+
+ consoleActions.addLog({ id: crypto.randomUUID(), level: 'info', message: 'Starting PLC...' })
+ const startResult = await runtime.startPlc()
+ if (!startResult.success) {
+ await showDebuggerMessage(
+ 'error',
+ 'Start PLC Failed',
+ `Could not start the PLC: ${startResult.error || 'Unknown error'}`,
+ ['OK'],
+ )
+ setIsDebuggerProcessing(false)
+ return
+ }
+ deviceActions.setPlcRuntimeStatus('RUNNING')
+ await new Promise((resolve) => setTimeout(resolve, 2000))
+ }
+
+ // Read local MD5
+ consoleActions.addLog({ id: crypto.randomUUID(), level: 'info', message: 'Verifying program MD5...' })
+ const md5Result = await debuggerPort.readProgramMd5(projectPath, boardTarget)
+ if (!md5Result.success || !md5Result.md5) {
+ await showDebuggerMessage('error', 'MD5 Extraction Failed', md5Result.error ?? 'Could not extract MD5', ['OK'])
+ setIsDebuggerProcessing(false)
+ return
+ }
+
+ // Connect debug transport before MD5 verification — the web platform
+ // needs an active transport (WebRTC or HTTP fallback) to query the device.
+ // connect() is idempotent: connectAndStart will reuse this connection.
+ const preConnectResult = await debuggerPort.connect(debugConfig)
+ if (!preConnectResult.success) {
+ await showDebuggerMessage(
+ 'error',
+ 'Connection Error',
+ `Could not connect to debug target: ${preConnectResult.error ?? 'Unknown error'}`,
+ ['OK'],
+ )
+ setIsDebuggerProcessing(false)
+ return
+ }
+
+ const verifyResult = await debuggerPort.verifyMd5(md5Result.md5, debugConfig)
+ if (!verifyResult.success) {
+ await debuggerPort.disconnect()
+ await showDebuggerMessage(
+ 'error',
+ 'Connection Error',
+ `Could not verify MD5: ${verifyResult.error ?? 'Unknown error'}`,
+ ['OK'],
+ )
+ setIsDebuggerProcessing(false)
+ return
+ }
+
+ if (verifyResult.match) {
+ consoleActions.addLog({ id: crypto.randomUUID(), level: 'info', message: 'MD5 verified. Starting debugger...' })
+ await debugSession.connectAndStart(debugConfig)
+ setIsDebuggerProcessing(false)
+ } else {
+ // Disconnect before re-upload; the recursive call will reconnect
+ await debuggerPort.disconnect()
+
+ consoleActions.addLog({
+ id: crypto.randomUUID(),
+ level: 'warning',
+ message: `MD5 mismatch. Target: ${verifyResult.targetMd5}, Expected: ${md5Result.md5}`,
+ })
+ const response = await showDebuggerMessage(
+ 'warning',
+ 'Program Mismatch',
+ 'The program on the target does not match. Upload the current project?',
+ ['Yes', 'No'],
+ )
+ if (response === 0) {
+ const runtimeIpAddress = deviceDefinitions.configuration.runtimeIpAddress || null
+ const runtimeJwtToken = useOpenPLCStore.getState().runtimeConnection.jwtToken || null
+ const compileResult = await compiler.compileProgram(
+ {
+ projectData,
+ boardTarget,
+ projectPath,
+ compileOnly: false,
+ isSimulator: false,
+ runtimeIpAddress,
+ runtimeJwtToken,
+ },
+ (event) => logCompilerEvent(event, consoleActions.addLog),
+ )
+ if (compileResult.success) {
+ consoleActions.addLog({
+ id: crypto.randomUUID(),
+ level: 'info',
+ message: 'Upload completed. Re-verifying...',
+ })
+ await new Promise((resolve) => setTimeout(resolve, 2000))
+ void handleMd5Verification(projectPath, boardTarget, debugConfig, isRuntimeTarget)
+ } else {
+ consoleActions.addLog({
+ id: crypto.randomUUID(),
+ level: 'error',
+ message: `Upload failed: ${compileResult.error ?? 'Unknown error'}`,
+ })
+ setIsDebuggerProcessing(false)
+ }
+ } else {
+ setIsDebuggerProcessing(false)
+ }
+ }
+ } catch (error: unknown) {
+ await debuggerPort.disconnect()
+ consoleActions.addLog({
+ id: crypto.randomUUID(),
+ level: 'error',
+ message: `MD5 verification error: ${getErrorMessage(error)}`,
+ })
+ setIsDebuggerProcessing(false)
+ }
+ }
+
+ // ---------------------------------------------------------------------------
+ // Debugger click — full orchestration for non-simulator targets
+ // ---------------------------------------------------------------------------
+
+ const handleDebuggerClick = useCallback(async () => {
+ if (isSimulatorBoard) return
+
+ const { workspace, project, deviceDefinitions: devDefs, consoleActions, deviceActions } = useOpenPLCStore.getState()
+
+ // Toggle off
+ if (workspace.isDebuggerVisible) {
+ await debugSession.stopSession()
+ return
+ }
+
+ if (isDebuggerProcessing) return
+ setIsDebuggerProcessing(true)
+
+ try {
+ if (editingState === 'unsaved') {
+ const saved = await executeSave()
+ if (!saved) {
+ setIsDebuggerProcessing(false)
+ return
+ }
+ }
+
+ const boardTarget = devDefs.configuration.deviceBoard
+ const projectPath = project.meta.path
+ const boardInfo = availableBoards.get(boardTarget)
+ const isRuntimeTarget = isOpenPLCRuntimeTarget(boardInfo)
+
+ // Resolve connection config
+ let debugConfig: DebugConnectionConfig = { connectionType: 'tcp', connectionParams: {} }
+
+ if (isRuntimeTarget) {
+ const rtConn = useOpenPLCStore.getState().runtimeConnection
+ const runtimeIpAddress = devDefs.configuration.runtimeIpAddress
+ if (!runtime.isReadyForDebug?.() || rtConn.connectionStatus !== 'connected') {
+ await showDebuggerMessage('warning', 'Connection Required', 'Connect to the target first.', ['OK'])
+ setIsDebuggerProcessing(false)
+ return
+ }
+ if (isOpenPLCRuntimeV4Target(boardTarget)) {
+ const token = rtConn.jwtToken || undefined
+ if (!token) {
+ await showDebuggerMessage(
+ 'error',
+ 'Authentication Required',
+ 'JWT token missing. Reconnect to the runtime.',
+ ['OK'],
+ )
+ setIsDebuggerProcessing(false)
+ return
+ }
+ debugConfig = {
+ connectionType: 'websocket',
+ connectionParams: { ipAddress: runtimeIpAddress, jwtToken: token },
+ }
+ } else {
+ debugConfig = { connectionType: 'tcp', connectionParams: { ipAddress: runtimeIpAddress } }
+ }
+ } else {
+ // Embedded hardware — determine TCP or RTU
+ const { modbusTCP, modbusRTU, communicationPreferences } = devDefs.configuration.communicationConfiguration
+ if (!communicationPreferences.enabledRTU && !communicationPreferences.enabledTCP) {
+ await showDebuggerMessage('warning', 'Modbus Required', 'Modbus must be enabled for debugging.', ['OK'])
+ setIsDebuggerProcessing(false)
+ return
+ }
+
+ let useModbusTcp = communicationPreferences.enabledTCP
+ if (communicationPreferences.enabledRTU && communicationPreferences.enabledTCP) {
+ const resp = await showDebuggerMessage('question', 'Select Protocol', 'Which Modbus protocol?', [
+ 'RTU (Serial)',
+ 'TCP',
+ ])
+ useModbusTcp = resp === 1
+ }
+
+ if (useModbusTcp) {
+ let targetIp: string | undefined
+ if (communicationPreferences.enabledDHCP) {
+ const previousIp = useOpenPLCStore.getState().deviceDefinitions.temporaryDhcpIp || ''
+ const result = await showDebuggerIpInput('Target IP Address', 'Enter the target device IP:', previousIp)
+ if (!result) {
+ setIsDebuggerProcessing(false)
+ return
+ }
+ targetIp = result
+ deviceActions.setTemporaryDhcpIp(targetIp)
+ } else {
+ targetIp = modbusTCP.tcpStaticHostConfiguration.ipAddress || undefined
+ if (!targetIp) {
+ await showDebuggerMessage('error', 'Configuration Error', 'No IP configured for Modbus TCP.', ['OK'])
+ setIsDebuggerProcessing(false)
+ return
+ }
+ }
+ debugConfig = { connectionType: 'tcp', connectionParams: { ipAddress: targetIp } }
+ } else {
+ const rtuPort = devDefs.configuration.communicationPort
+ const rtuSlaveId = modbusRTU.rtuSlaveId ?? undefined
+ if (!rtuPort) {
+ await showDebuggerMessage('error', 'Configuration Error', 'No port selected for Modbus RTU.', ['OK'])
+ setIsDebuggerProcessing(false)
+ return
+ }
+ if (rtuSlaveId === undefined) {
+ await showDebuggerMessage('error', 'Configuration Error', 'No slave ID configured for Modbus RTU.', ['OK'])
+ setIsDebuggerProcessing(false)
+ return
+ }
+ consoleActions.addLog({
+ id: crypto.randomUUID(),
+ level: 'info',
+ message: `Using RTU: Port=${rtuPort}, Baud=${modbusRTU.rtuBaudRate}, SlaveID=${rtuSlaveId}`,
+ })
+ debugConfig = {
+ connectionType: 'rtu',
+ connectionParams: { port: rtuPort, baudRate: parseInt(modbusRTU.rtuBaudRate, 10), slaveId: rtuSlaveId },
+ }
+ }
+ }
+
+ // Debug compilation
+ consoleActions.addLog({ id: crypto.randomUUID(), level: 'info', message: 'Starting debug compilation...' })
+ const debugCompileResult = await compiler.compileForDebug({ projectData, boardTarget, projectPath }, (event) =>
+ logCompilerEvent(event, consoleActions.addLog),
+ )
+ if (!debugCompileResult.success) {
+ consoleActions.addLog({
+ id: crypto.randomUUID(),
+ level: 'error',
+ message: `Debug compilation failed: ${debugCompileResult.error ?? 'Unknown error'}`,
+ })
+ setIsDebuggerProcessing(false)
+ return
+ }
+
+ void handleMd5Verification(projectPath, boardTarget, debugConfig, isRuntimeTarget)
+ } catch (error: unknown) {
+ consoleActions.addLog({
+ id: crypto.randomUUID(),
+ level: 'error',
+ message: `Debugger init error: ${getErrorMessage(error)}`,
+ })
+ setIsDebuggerProcessing(false)
+ }
+ }, [
+ debuggerPort,
+ runtime,
+ compiler,
+ debugSession,
+ projectData,
+ deviceDefinitions,
+ projectMeta,
+ availableBoards,
+ isSimulatorBoard,
+ isDebuggerProcessing,
+ editingState,
+ executeSave,
+ addLog,
+ ])
+
+ // ---------------------------------------------------------------------------
+ // JSX
+ // ---------------------------------------------------------------------------
+
+ return (
+ <>
+
+
+
+
+
+
+
+ void handleBuild()}
+ />
+
+
+ void handleSimulatorControl() : () => void handlePlcControl()}
+ disabled={isSimulatorBoard ? isCompiling || isDebuggerProcessing : connectionStatus !== 'connected'}
+ className={cn(
+ isSimulatorBoard
+ ? isCompiling || isDebuggerProcessing
+ ? disabledButtonClass
+ : ''
+ : connectionStatus !== 'connected'
+ ? disabledButtonClass
+ : '',
+ )}
+ >
+ {(isSimulatorBoard ? simulatorRunning : plcStatus === 'RUNNING') ? : null}
+
+
+
+ void handleDebuggerClick()}
+ disabled={isDebuggerProcessing || isSimulatorBoard}
+ isActive={isDebuggerVisible}
+ className={cn((isDebuggerProcessing || isSimulatorBoard) && disabledButtonClass)}
+ />
+
+
+ >
+ )
+}
diff --git a/src2/frontend/components/_organisms/workspace-activity-bar/fbd-toolbox.tsx b/src/frontend/components/_organisms/workspace-activity-bar/fbd-toolbox.tsx
similarity index 100%
rename from src2/frontend/components/_organisms/workspace-activity-bar/fbd-toolbox.tsx
rename to src/frontend/components/_organisms/workspace-activity-bar/fbd-toolbox.tsx
diff --git a/src2/frontend/components/_organisms/workspace-activity-bar/index.tsx b/src/frontend/components/_organisms/workspace-activity-bar/index.tsx
similarity index 99%
rename from src2/frontend/components/_organisms/workspace-activity-bar/index.tsx
rename to src/frontend/components/_organisms/workspace-activity-bar/index.tsx
index f55130f0a..edd83abbc 100644
--- a/src2/frontend/components/_organisms/workspace-activity-bar/index.tsx
+++ b/src/frontend/components/_organisms/workspace-activity-bar/index.tsx
@@ -1,5 +1,4 @@
import { useOpenPLCStore } from '../../../store'
-
import { DividerActivityBar } from '../../_atoms/workspace-activity-bar/divider'
import { ExitButton } from '../../_molecules/workspace-activity-bar/default/exit'
import { TooltipSidebarWrapperButton } from '../../_molecules/workspace-activity-bar/tooltip-button'
diff --git a/src2/frontend/components/_organisms/workspace-activity-bar/ladder-toolbox.tsx b/src/frontend/components/_organisms/workspace-activity-bar/ladder-toolbox.tsx
similarity index 90%
rename from src2/frontend/components/_organisms/workspace-activity-bar/ladder-toolbox.tsx
rename to src/frontend/components/_organisms/workspace-activity-bar/ladder-toolbox.tsx
index 54ba4ff0c..a6733487a 100644
--- a/src2/frontend/components/_organisms/workspace-activity-bar/ladder-toolbox.tsx
+++ b/src/frontend/components/_organisms/workspace-activity-bar/ladder-toolbox.tsx
@@ -1,8 +1,8 @@
import { useOpenPLCStore } from '../../../store'
-import { getFunctionBlockVariablesToCleanup } from '../../../utils/graphical/get-function-block-variables-to-cleanup'
import { cn } from '../../../utils/cn'
-
+import { getFunctionBlockVariablesToCleanup } from '../../../utils/graphical/get-function-block-variables-to-cleanup'
import { DividerActivityBar } from '../../_atoms/workspace-activity-bar/divider'
+import { removeElements } from '../../_molecules/graphical-editor/ladder/rung/ladder-utils/elements'
import { DeleteElementButton } from '../../_molecules/workspace-activity-bar/default/exit'
import { BlockButton } from '../../_molecules/workspace-activity-bar/ladder/block'
import { CoilButton } from '../../_molecules/workspace-activity-bar/ladder/coil'
@@ -66,11 +66,12 @@ export const LadderToolbox = () => {
const allNodesToRemove = flow?.rungs.flatMap((rung) => rung.selectedNodes || []) || []
flow?.rungs.forEach((rung) => {
- ladderFlowActions.removeNodes({
- nodes: rung.selectedNodes || [],
- editorName: editor.meta.name,
- rungId: rung.id,
- })
+ const selectedNodes = rung.selectedNodes || []
+ if (selectedNodes.length === 0) return
+
+ const { nodes: newNodes, edges: newEdges } = removeElements({ ...rung }, selectedNodes)
+ ladderFlowActions.setNodes({ editorName: editor.meta.name, rungId: rung.id, nodes: newNodes })
+ ladderFlowActions.setEdges({ editorName: editor.meta.name, rungId: rung.id, edges: newEdges })
ladderFlowActions.setSelectedNodes({
editorName: editor.meta.name,
rungId: rung.id,
diff --git a/src2/frontend/components/_templates/.gitkeep b/src/frontend/components/_templates/.gitkeep
similarity index 100%
rename from src2/frontend/components/_templates/.gitkeep
rename to src/frontend/components/_templates/.gitkeep
diff --git a/src/renderer/components/_templates/[editors]/device-editor-slot.tsx b/src/frontend/components/_templates/[editors]/device-editor-slot.tsx
similarity index 100%
rename from src/renderer/components/_templates/[editors]/device-editor-slot.tsx
rename to src/frontend/components/_templates/[editors]/device-editor-slot.tsx
diff --git a/src/renderer/components/_templates/[editors]/device-editor-template.tsx b/src/frontend/components/_templates/[editors]/device-editor-template.tsx
similarity index 100%
rename from src/renderer/components/_templates/[editors]/device-editor-template.tsx
rename to src/frontend/components/_templates/[editors]/device-editor-template.tsx
diff --git a/src/renderer/components/_templates/[start]/main-content.tsx b/src/frontend/components/_templates/[start]/main-content.tsx
similarity index 100%
rename from src/renderer/components/_templates/[start]/main-content.tsx
rename to src/frontend/components/_templates/[start]/main-content.tsx
diff --git a/src/renderer/components/_templates/[start]/side-content.tsx b/src/frontend/components/_templates/[start]/side-content.tsx
similarity index 100%
rename from src/renderer/components/_templates/[start]/side-content.tsx
rename to src/frontend/components/_templates/[start]/side-content.tsx
diff --git a/src2/frontend/components/_templates/[workspace]/main-content.tsx b/src/frontend/components/_templates/[workspace]/main-content.tsx
similarity index 99%
rename from src2/frontend/components/_templates/[workspace]/main-content.tsx
rename to src/frontend/components/_templates/[workspace]/main-content.tsx
index 420fcfe02..293aa90d3 100644
--- a/src2/frontend/components/_templates/[workspace]/main-content.tsx
+++ b/src/frontend/components/_templates/[workspace]/main-content.tsx
@@ -1,7 +1,8 @@
-import { cn } from '../../../utils/cn'
-import { useOpenPLCStore } from '../../../store'
import { ComponentPropsWithoutRef } from 'react'
+import { useOpenPLCStore } from '../../../store'
+import { cn } from '../../../utils/cn'
+
type IWorkspaceMainContentProps = ComponentPropsWithoutRef<'div'>
const WorkspaceMainContent = (props: IWorkspaceMainContentProps) => {
const {
diff --git a/src/renderer/components/_templates/[workspace]/side-content.tsx b/src/frontend/components/_templates/[workspace]/side-content.tsx
similarity index 100%
rename from src/renderer/components/_templates/[workspace]/side-content.tsx
rename to src/frontend/components/_templates/[workspace]/side-content.tsx
diff --git a/src2/frontend/components/_templates/accelerator-handler.tsx b/src/frontend/components/_templates/accelerator-handler.tsx
similarity index 62%
rename from src2/frontend/components/_templates/accelerator-handler.tsx
rename to src/frontend/components/_templates/accelerator-handler.tsx
index 6dbaac415..a4c94ce64 100644
--- a/src2/frontend/components/_templates/accelerator-handler.tsx
+++ b/src/frontend/components/_templates/accelerator-handler.tsx
@@ -1,8 +1,16 @@
-import { useAccelerator, useCompiler, useProject, useWindow, useCapabilities } from '../../../middleware/shared/providers'
+import { useCallback, useEffect, useRef, useState } from 'react'
+
+import {
+ useAccelerator,
+ useCapabilities,
+ useCompiler,
+ useProject,
+ useTheme,
+ useWindow,
+} from '../../../middleware/shared/providers'
import { useOpenPLCStore } from '../../store'
import type { ModalTypes } from '../../store/slices/modal'
-import { useEffect, useState } from 'react'
-
+import { prepareSavePayload } from '../../utils/save-project'
import { toast } from '../_features/[app]/toast/use-toast'
const quitAppRequest = (isUnsaved: boolean, openModal: (modal: ModalTypes, data?: unknown) => void) => {
@@ -20,6 +28,7 @@ const AcceleratorHandler = () => {
const compilerPort = useCompiler()
const projectPort = useProject()
const windowPort = useWindow()
+ const themePort = useTheme()
const capabilities = useCapabilities()
const [requestFlag, setRequestFlag] = useState(false)
@@ -28,18 +37,82 @@ const AcceleratorHandler = () => {
const {
project,
editor: { meta },
+ editor: activeEditor,
+ editors,
deviceDefinitions,
workspace: { editingState, systemConfigs, close },
modalActions: { openModal },
- sharedWorkspaceActions: { closeProject },
- workspaceActions: { switchAppTheme, toggleMaximizedWindow, setCloseWindow, setCloseApp, setCloseAppDarwin },
+ sharedWorkspaceActions: { closeProject, handleOpenProjectResponse },
+ workspaceActions: {
+ switchAppTheme,
+ toggleMaximizedWindow,
+ setCloseWindow,
+ setCloseAppDarwin,
+ setEditingState,
+ setModalOpen,
+ toggleCollapse,
+ },
tabsActions: { removeTab },
+ fileActions: { setAllToSaved },
pouActions: { deleteRequest: deletePouRequest },
datatypeActions: { deleteRequest: deleteDatatypeRequest },
- snapshotActions: { undo, redo },
+ snapshotActions: { undo, redo, markAllSaved },
} = useOpenPLCStore()
const isMonacoFocused: boolean = useOpenPLCStore((state) => state.isMonacoFocused)
const selectedProjectTreeLeaf = useOpenPLCStore((state) => state.workspace.selectedProjectTreeLeaf)
+ const pendingRecentProjectRef = useRef(null)
+
+ /**
+ * Shared save logic: sanitizes POUs, collects debug variables, saves, and updates state.
+ */
+ const executeSave = useCallback(async (): Promise<{ success: boolean }> => {
+ setEditingState('save-request')
+ toast({
+ title: 'Save changes',
+ description: 'Trying to save the changes in the project file.',
+ variant: 'warn',
+ })
+
+ try {
+ const params = prepareSavePayload({
+ projectPath: project.meta.path,
+ projectName: project.meta.name,
+ projectData: project.data,
+ deviceConfiguration: deviceDefinitions.configuration,
+ devicePinMapping: deviceDefinitions.pinMapping.pins,
+ editors,
+ activeEditor,
+ })
+
+ const res = await projectPort.saveProject(params)
+ if (res.success) {
+ setEditingState('saved')
+ setAllToSaved()
+ markAllSaved()
+ toast({
+ title: 'Changes saved!',
+ description: 'The project was saved successfully!',
+ variant: 'default',
+ })
+ } else {
+ setEditingState('unsaved')
+ toast({
+ title: 'Error in the save request!',
+ description: res.error ?? 'Save failed',
+ variant: 'fail',
+ })
+ }
+ return { success: res.success }
+ } catch {
+ setEditingState('unsaved')
+ toast({
+ title: 'Error in the save request!',
+ description: 'An unexpected error occurred while saving.',
+ variant: 'fail',
+ })
+ return { success: false }
+ }
+ }, [project, deviceDefinitions, editors, activeEditor, projectPort, setEditingState, setAllToSaved])
/**
* Export project accelerator
@@ -121,15 +194,27 @@ const AcceleratorHandler = () => {
* Open recent project (editor-specific — data passed via IPC accelerator)
*/
useEffect(() => {
- const unsub = accelerator.onOpenRecent(() => {
+ const unsub = accelerator.onOpenRecent((projectData?: unknown) => {
switch (editingState) {
case 'saved':
case 'initial-state':
- // Recent project data is passed by the adapter via IPC callback
+ // Process immediately — data comes from the main process IPC event
+ if (projectData) {
+ handleOpenProjectResponse(projectData as Parameters[0])
+ }
break
case 'unsaved':
+ // Store pending data and show save modal with callback
+ pendingRecentProjectRef.current = projectData ?? null
openModal('save-changes-project', {
validationContext: 'open-recent-project',
+ onAfterAction: () => {
+ const data = pendingRecentProjectRef.current
+ pendingRecentProjectRef.current = null
+ if (data) {
+ handleOpenProjectResponse(data as Parameters[0])
+ }
+ },
})
break
case 'save-request':
@@ -144,7 +229,7 @@ const AcceleratorHandler = () => {
}
})
return unsub
- }, [editingState, accelerator, openModal])
+ }, [editingState, accelerator, openModal, handleOpenProjectResponse])
/**
* Close project
@@ -157,19 +242,14 @@ const AcceleratorHandler = () => {
}, [editingState, accelerator, closeProject])
/**
- * Save project
+ * Save project (Cmd+Shift+S)
*/
useEffect(() => {
const unsub = accelerator.onSaveProject(() => {
- void projectPort.saveProject({
- projectPath: project.meta.path,
- projectData: project.data,
- deviceConfiguration: deviceDefinitions.configuration,
- devicePinMapping: deviceDefinitions.pinMapping.pins,
- })
+ void executeSave()
})
return unsub
- }, [project, deviceDefinitions, accelerator, projectPort])
+ }, [accelerator, executeSave])
/**
* Delete file
@@ -218,19 +298,34 @@ const AcceleratorHandler = () => {
}, [selectedProjectTreeLeaf, accelerator, removeTab])
/**
- * Save file (saves entire project since files are part of project XML)
+ * Save file (Cmd+S) — saves entire project since files are part of project XML
*/
useEffect(() => {
const unsub = accelerator.onSaveFile(() => {
- void projectPort.saveProject({
- projectPath: project.meta.path,
- projectData: project.data,
- deviceConfiguration: deviceDefinitions.configuration,
- devicePinMapping: deviceDefinitions.pinMapping.pins,
- })
+ void executeSave()
})
return unsub
- }, [selectedProjectTreeLeaf, accelerator, projectPort, project, deviceDefinitions])
+ }, [accelerator, executeSave])
+
+ /**
+ * Find in project (Cmd+Shift+F)
+ */
+ useEffect(() => {
+ const unsub = accelerator.onFindInProject(() => {
+ setModalOpen('findInProject', true)
+ })
+ return unsub
+ }, [accelerator, setModalOpen])
+
+ /**
+ * Switch perspective (F12)
+ */
+ useEffect(() => {
+ const unsub = accelerator.onSwitchPerspective(() => {
+ toggleCollapse()
+ })
+ return unsub
+ }, [accelerator, toggleCollapse])
/**
* Undo / Redo
@@ -251,9 +346,36 @@ const AcceleratorHandler = () => {
return unsub
}, [meta.name, isMonacoFocused, accelerator, redo])
+ /**
+ * Quit app (Ctrl+Q on Windows/Linux)
+ */
+ useEffect(() => {
+ const unsub = accelerator.onQuitApp(() => {
+ quitAppRequest(editingState === 'unsaved', openModal)
+ })
+ return unsub
+ }, [editingState, accelerator, openModal])
+
+ /**
+ * Theme update from main process
+ */
+ useEffect(() => {
+ const unsub = themePort.onThemeChanged(() => {
+ switchAppTheme()
+ })
+ return unsub
+ }, [themePort, switchAppTheme])
+
/**
* Window lifecycle events (editor-only, gated by capabilities)
*/
+ useEffect(() => {
+ if (!capabilities.hasNativeWindowControls) return
+
+ const unsub = windowPort.enableAutoCloseHandshake?.()
+ return unsub
+ }, [capabilities.hasNativeWindowControls, windowPort])
+
useEffect(() => {
if (!capabilities.hasNativeWindowControls) return
@@ -263,6 +385,15 @@ const AcceleratorHandler = () => {
return unsub
}, [capabilities.hasNativeWindowControls, windowPort, setCloseWindow])
+ useEffect(() => {
+ if (!capabilities.hasNativeWindowControls) return
+
+ const unsub = windowPort.onDarwinAppQuitting?.(() => {
+ setCloseAppDarwin(true)
+ })
+ return unsub
+ }, [capabilities.hasNativeWindowControls, windowPort, setCloseAppDarwin])
+
useEffect(() => {
if (!capabilities.hasNativeWindowControls) return
diff --git a/src2/frontend/components/_templates/app-layout.tsx b/src/frontend/components/_templates/app-layout.tsx
similarity index 89%
rename from src2/frontend/components/_templates/app-layout.tsx
rename to src/frontend/components/_templates/app-layout.tsx
index 0903b1c8b..b7cfba765 100644
--- a/src2/frontend/components/_templates/app-layout.tsx
+++ b/src/frontend/components/_templates/app-layout.tsx
@@ -1,27 +1,27 @@
-import { useOpenPLCStore } from '../../store'
-import { useSystem, useProject, useCapabilities } from '../../../middleware/shared/providers'
-import { cn } from '../../utils/cn'
import { ComponentPropsWithoutRef, ReactNode, useEffect, useState } from 'react'
+import { useProject, useSystem } from '../../../middleware/shared/providers'
+import { useOpenPLCStore } from '../../store'
+import type { RungLadderState } from '../../store/slices/ladder'
+import { cn } from '../../utils/cn'
+import { ResolutionWarning } from '../_atoms/resolution-warning-message'
import Toaster from '../_features/[app]/toast/toaster'
import { ProjectModal } from '../_features/[start]/new-project/project-modal'
-import { ConfirmDeleteElementModal } from '../_organisms/modals/delete-confirmation-modal'
+import { RuntimeCreateUserModal, RuntimeLoginModal } from '../_organisms/modals'
import { DebuggerMessageModal } from '../_organisms/modals/debugger-message-modal'
+import { ConfirmDeleteElementModal } from '../_organisms/modals/delete-confirmation-modal'
import { QuitApplicationModal } from '../_organisms/modals/quit-application-modal'
import { RuntimeConnectionLostModal } from '../_organisms/modals/runtime-connection-lost-modal'
+import type { SaveChangesFileModalData } from '../_organisms/modals/save-changes-file-modal'
import { SaveChangesFileModal } from '../_organisms/modals/save-changes-file-modal'
+import type { SaveChangeModalProps } from '../_organisms/modals/save-changes-modal'
import { SaveChangesModal } from '../_organisms/modals/save-changes-modal'
import { ServerIpMismatchModal } from '../_organisms/modals/server-ip-mismatch-modal'
-import type { SaveChangeModalProps } from '../_organisms/modals/save-changes-modal'
-import type { SaveChangesFileModalData } from '../_organisms/modals/save-changes-file-modal'
-import type { RungLadderState } from '../../store/slices/ladder'
import { TitleBar } from '../_organisms/title-bar'
-import { ResolutionWarning } from '../_atoms/resolution-warning-message'
import { AcceleratorHandler } from './accelerator-handler'
type AppLayoutProps = ComponentPropsWithoutRef<'main'>
const AppLayout = ({ children, ...rest }: AppLayoutProps): ReactNode => {
- const capabilities = useCapabilities()
const system = useSystem()
const projectPort = useProject()
const [showComponent, setShowComponent] = useState(true)
@@ -84,6 +84,10 @@ const AppLayout = ({ children, ...rest }: AppLayoutProps): ReactNode => {
validationContext={
(modals['save-changes-project'].data as SaveChangeModalProps)?.validationContext ?? 'close-project'
}
+ onAfterAction={
+ (modals['save-changes-project'].data as SaveChangeModalProps & { onAfterAction?: () => void })
+ ?.onAfterAction
+ }
/>
)}
{modals?.['save-changes-file']?.open === true && (
@@ -106,7 +110,9 @@ const AppLayout = ({ children, ...rest }: AppLayoutProps): ReactNode => {
)}
{modals?.['runtime-connection-lost']?.open === true && }
{modals?.['debugger-message']?.open === true && }
- {capabilities.hasNativeMenu && }
+ {modals?.['runtime-login']?.open === true && }
+ {modals?.['runtime-create-user']?.open === true && }
+
diff --git a/src2/frontend/components/ui/scroll-area/display.tsx b/src/frontend/components/ui/scroll-area/display.tsx
similarity index 99%
rename from src2/frontend/components/ui/scroll-area/display.tsx
rename to src/frontend/components/ui/scroll-area/display.tsx
index 067f977f1..99c3b4934 100644
--- a/src2/frontend/components/ui/scroll-area/display.tsx
+++ b/src/frontend/components/ui/scroll-area/display.tsx
@@ -1,6 +1,7 @@
-import { cn } from '../../../utils/cn'
import { ForwardedRef, forwardRef, HTMLAttributes } from 'react'
+import { cn } from '../../../utils/cn'
+
type CustomDisplayProps = HTMLAttributes
const CustomDisplay = forwardRef(
diff --git a/src/renderer/components/ui/scroll-area/index.ts b/src/frontend/components/ui/scroll-area/index.ts
similarity index 100%
rename from src/renderer/components/ui/scroll-area/index.ts
rename to src/frontend/components/ui/scroll-area/index.ts
diff --git a/src2/frontend/components/ui/scroll-area/root.tsx b/src/frontend/components/ui/scroll-area/root.tsx
similarity index 99%
rename from src2/frontend/components/ui/scroll-area/root.tsx
rename to src/frontend/components/ui/scroll-area/root.tsx
index a9b5106b8..b75a8064d 100644
--- a/src2/frontend/components/ui/scroll-area/root.tsx
+++ b/src/frontend/components/ui/scroll-area/root.tsx
@@ -1,7 +1,8 @@
import * as ScrollAreaPrimitive from '@radix-ui/react-scroll-area'
-import { cn } from '../../../utils/cn'
import { ComponentPropsWithoutRef, ElementRef, forwardRef } from 'react'
+import { cn } from '../../../utils/cn'
+
const Root = forwardRef<
ElementRef,
ComponentPropsWithoutRef
diff --git a/src2/frontend/components/ui/scroll-area/scrollbar.tsx b/src/frontend/components/ui/scroll-area/scrollbar.tsx
similarity index 99%
rename from src2/frontend/components/ui/scroll-area/scrollbar.tsx
rename to src/frontend/components/ui/scroll-area/scrollbar.tsx
index 09ac8bd7e..33c4b0c2f 100644
--- a/src2/frontend/components/ui/scroll-area/scrollbar.tsx
+++ b/src/frontend/components/ui/scroll-area/scrollbar.tsx
@@ -1,7 +1,8 @@
import * as ScrollAreaPrimitive from '@radix-ui/react-scroll-area'
-import { cn } from '../../../utils/cn'
import { ComponentPropsWithoutRef, ElementRef, forwardRef } from 'react'
+import { cn } from '../../../utils/cn'
+
const ScrollBar = forwardRef<
ElementRef,
ComponentPropsWithoutRef
diff --git a/src2/frontend/components/ui/scroll-area/viewport.tsx b/src/frontend/components/ui/scroll-area/viewport.tsx
similarity index 99%
rename from src2/frontend/components/ui/scroll-area/viewport.tsx
rename to src/frontend/components/ui/scroll-area/viewport.tsx
index e172f42fb..4510408a9 100644
--- a/src2/frontend/components/ui/scroll-area/viewport.tsx
+++ b/src/frontend/components/ui/scroll-area/viewport.tsx
@@ -1,7 +1,8 @@
import * as ScrollAreaPrimitive from '@radix-ui/react-scroll-area'
-import { cn } from '../../../utils/cn'
import { ComponentPropsWithoutRef, ElementRef, forwardRef } from 'react'
+import { cn } from '../../../utils/cn'
+
const Viewport = forwardRef<
ElementRef,
ComponentPropsWithoutRef
diff --git a/src/renderer/data/constants/icon-styles.ts b/src/frontend/data/constants/icon-styles.ts
similarity index 100%
rename from src/renderer/data/constants/icon-styles.ts
rename to src/frontend/data/constants/icon-styles.ts
diff --git a/src2/frontend/data/constants/language-icons.ts b/src/frontend/data/constants/language-icons.ts
similarity index 100%
rename from src2/frontend/data/constants/language-icons.ts
rename to src/frontend/data/constants/language-icons.ts
diff --git a/src2/frontend/data/constants/pou-icons.ts b/src/frontend/data/constants/pou-icons.ts
similarity index 100%
rename from src2/frontend/data/constants/pou-icons.ts
rename to src/frontend/data/constants/pou-icons.ts
index ac2a0e9b7..213cf2878 100644
--- a/src2/frontend/data/constants/pou-icons.ts
+++ b/src/frontend/data/constants/pou-icons.ts
@@ -1,7 +1,7 @@
import { DataTypeIcon } from '../../assets/icons/project/DataType'
import { DeviceIcon } from '../../assets/icons/project/Device'
-import { FunctionBlockIcon } from '../../assets/icons/project/FunctionBlock'
import { FunctionIcon } from '../../assets/icons/project/Function'
+import { FunctionBlockIcon } from '../../assets/icons/project/FunctionBlock'
import { ProgramIcon } from '../../assets/icons/project/Program'
import { ResourceIcon } from '../../assets/icons/project/Resource'
diff --git a/src/frontend/data/library/MQTT.ts b/src/frontend/data/library/MQTT.ts
new file mode 100644
index 000000000..27331fe63
--- /dev/null
+++ b/src/frontend/data/library/MQTT.ts
@@ -0,0 +1,197 @@
+import { z } from 'zod'
+
+import { BaseLibraryPouSchema, BaseLibraryVariableSchema } from '../../../middleware/shared/ports/plc-schemas'
+
+/** Library-level schema (name + version + paths). Not in plc-schemas so defined locally. */
+const BaseLibrarySchema = z.object({
+ name: z.string(),
+ version: z.string(),
+ author: z.string(),
+ stPath: z.string(),
+ cPath: z.string(),
+})
+
+const MQTTVariablesSchema = BaseLibraryVariableSchema
+
+const MQTTPouSchema = BaseLibraryPouSchema.extend({
+ variables: z.array(MQTTVariablesSchema),
+})
+
+export const MQTTLibrarySchema = BaseLibrarySchema.extend({
+ pous: z.array(MQTTPouSchema),
+})
+
+type MQTTLibrary = z.infer
+
+const MQTT: MQTTLibrary = {
+ name: 'MQTT',
+ version: '1.0.0',
+ author: 'Autonomy Logic',
+ stPath: 'src/renderer/data/library/mqtt/st',
+ cPath: 'src/renderer/data/library/mqtt/c',
+ pous: [
+ {
+ name: 'MQTT_RECEIVE',
+ type: 'function-block',
+ language: 'st',
+ variables: [
+ { name: 'RECEIVE', class: 'input', type: { definition: 'base-type', value: 'BOOL' }, documentation: 'RECEIVE' },
+ { name: 'TOPIC', class: 'input', type: { definition: 'base-type', value: 'STRING' }, documentation: 'TOPIC' },
+ {
+ name: 'RECEIVED',
+ class: 'output',
+ type: { definition: 'base-type', value: 'BOOL' },
+ documentation: 'RECEIVED',
+ },
+ {
+ name: 'MESSAGE',
+ class: 'output',
+ type: { definition: 'base-type', value: 'STRING' },
+ documentation: 'MESSAGE',
+ },
+ ],
+ body: 'RECEIVED := 0;',
+ documentation:
+ 'Receive MQTT messages for a particular TOPIC when RECEIVE is active. You must subscribe to a topic first before you can start receiving messages for that particular topic. Once a message is received, RECEIVED output is triggered, and MESSAGE will contain the received message as a STRING.',
+ },
+ {
+ name: 'MQTT_SEND',
+ type: 'function-block',
+ language: 'st',
+ variables: [
+ { name: 'SEND', class: 'input', type: { definition: 'base-type', value: 'BOOL' }, documentation: 'SEND' },
+ { name: 'TOPIC', class: 'input', type: { definition: 'base-type', value: 'STRING' }, documentation: 'TOPIC' },
+ {
+ name: 'MESSAGE',
+ class: 'input',
+ type: { definition: 'base-type', value: 'STRING' },
+ documentation: 'MESSAGE',
+ },
+ {
+ name: 'SUCCESS',
+ class: 'output',
+ type: { definition: 'base-type', value: 'BOOL' },
+ documentation: 'SUCCESS',
+ },
+ ],
+ body: 'SUCCESS := 0;',
+ documentation:
+ 'Sends a MESSAGE to a particular TOPIC when SEND input is triggered. Keep in mind that SEND is not configured as a rising edge input, which means that MQTT_SEND will continuously send messages every scan cycle while SEND is TRUE. If the message was sent without errors, SUCCESS will be TRUE.',
+ },
+ {
+ name: 'MQTT_CONNECT',
+ type: 'function-block',
+ language: 'st',
+ variables: [
+ { name: 'CONNECT', class: 'input', type: { definition: 'base-type', value: 'BOOL' }, documentation: 'CONNECT' },
+ { name: 'BROKER', class: 'input', type: { definition: 'base-type', value: 'STRING' }, documentation: 'BROKER' },
+ { name: 'PORT', class: 'input', type: { definition: 'base-type', value: 'UINT' }, documentation: 'PORT' },
+ {
+ name: 'SUCCESS',
+ class: 'output',
+ type: { definition: 'base-type', value: 'BOOL' },
+ documentation: 'SUCCESS',
+ },
+ ],
+ body: 'SUCCESS := 0;',
+ documentation:
+ 'Connect to a BROKER at a given PORT when CONNECT is triggered. If a successful connection is made, SUCCESS is set to TRUE',
+ },
+ {
+ name: 'MQTT_CONNECT_AUTH',
+ type: 'function-block',
+ language: 'st',
+ variables: [
+ { name: 'CONNECT', class: 'input', type: { definition: 'base-type', value: 'BOOL' }, documentation: 'CONNECT' },
+ { name: 'BROKER', class: 'input', type: { definition: 'base-type', value: 'STRING' }, documentation: 'BROKER' },
+ { name: 'PORT', class: 'input', type: { definition: 'base-type', value: 'UINT' }, documentation: 'PORT' },
+ { name: 'USER', class: 'input', type: { definition: 'base-type', value: 'STRING' }, documentation: 'USER' },
+ {
+ name: 'PASSWORD',
+ class: 'input',
+ type: { definition: 'base-type', value: 'STRING' },
+ documentation: 'PASSWORD',
+ },
+ {
+ name: 'SUCCESS',
+ class: 'output',
+ type: { definition: 'base-type', value: 'BOOL' },
+ documentation: 'SUCCESS',
+ },
+ ],
+ body: 'SUCCESS := 0;',
+ documentation:
+ 'Connect to an authenticated BROKER at a given PORT using the credentials from USER and PASSWORD when CONNECT is triggered. If a successful connection is made, SUCCESS is set to TRUE',
+ },
+ {
+ name: 'MQTT_SUBSCRIBE',
+ type: 'function-block',
+ language: 'st',
+ variables: [
+ {
+ name: 'SUBSCRIBE',
+ class: 'input',
+ type: { definition: 'base-type', value: 'BOOL' },
+ documentation: 'SUBSCRIBE',
+ },
+ { name: 'TOPIC', class: 'input', type: { definition: 'base-type', value: 'STRING' }, documentation: 'TOPIC' },
+ {
+ name: 'SUCCESS',
+ class: 'output',
+ type: { definition: 'base-type', value: 'BOOL' },
+ documentation: 'SUCCESS',
+ },
+ ],
+ body: 'SUCCESS := 0;',
+ documentation:
+ 'Subscribe to a given TOPIC when SUBSCRIBE input is triggered. Upon a successful subscription, SUCCESS is set to TRUE. Keep in mind that once you subscribe to a topic, OpenPLC will start receiving messages sent to that topic and storing them in a message pool. You must use the MQTT_RECEIVE block to retrieve messages from the pool and free up space to receive more messages. The maximum pool size is currently limited to 10 messages. If you let messages accumulate in the pool you will start loosing messages once the pool is full.',
+ },
+ {
+ name: 'MQTT_UNSUBSCRIBE',
+ type: 'function-block',
+ language: 'st',
+ variables: [
+ {
+ name: 'UNSUBSCRIBE',
+ class: 'input',
+ type: { definition: 'base-type', value: 'BOOL' },
+ documentation: 'UNSUBSCRIBE',
+ },
+ { name: 'TOPIC', class: 'input', type: { definition: 'base-type', value: 'STRING' }, documentation: 'TOPIC' },
+ {
+ name: 'SUCCESS',
+ class: 'output',
+ type: { definition: 'base-type', value: 'BOOL' },
+ documentation: 'SUCCESS',
+ },
+ ],
+ body: 'SUCCESS := 0;',
+ documentation:
+ 'Unsubscribe to a given TOPIC when UNSUBSCRIBE input is triggered. Upon a successful unsubscription, SUCCESS is set to TRUE. Keep in mind that once you unsubscribe to a topic, OpenPLC will stop storing messages sent to that topic in the message pool. However, messages received previously and not captured with a MQTT_RECEIVE block will remain in the pool using up pool space.',
+ },
+ {
+ name: 'MQTT_DISCONNECT',
+ type: 'function-block',
+ language: 'st',
+ variables: [
+ {
+ name: 'DISCONNECT',
+ class: 'input',
+ type: { definition: 'base-type', value: 'BOOL' },
+ documentation: 'DISCONNECT',
+ },
+ {
+ name: 'SUCCESS',
+ class: 'output',
+ type: { definition: 'base-type', value: 'BOOL' },
+ documentation: 'SUCCESS',
+ },
+ ],
+ body: 'SUCCESS := 0;',
+ documentation:
+ 'Disconnects from the current broker when DISCONNECT is set to TRUE. Upon a successful disconnection, SUCCESS is set to TRUE.',
+ },
+ ],
+}
+
+export { MQTT }
diff --git a/src/frontend/data/library/P1AM.ts b/src/frontend/data/library/P1AM.ts
new file mode 100644
index 000000000..8a0a2d7d8
--- /dev/null
+++ b/src/frontend/data/library/P1AM.ts
@@ -0,0 +1,180 @@
+import { z } from 'zod'
+
+import { BaseLibraryPouSchema, BaseLibraryVariableSchema } from '../../../middleware/shared/ports/plc-schemas'
+
+/** Library-level schema (name + version + paths). Not in plc-schemas so defined locally. */
+const BaseLibrarySchema = z.object({
+ name: z.string(),
+ version: z.string(),
+ author: z.string(),
+ stPath: z.string(),
+ cPath: z.string(),
+})
+
+const P1AMVariablesSchema = BaseLibraryVariableSchema
+
+const P1AMPouSchema = BaseLibraryPouSchema.extend({
+ variables: z.array(P1AMVariablesSchema),
+})
+
+export const P1AMLibrarySchema = BaseLibrarySchema.extend({
+ pous: z.array(P1AMPouSchema),
+})
+
+type P1AMLibrary = z.infer
+
+const P1AM: P1AMLibrary = {
+ name: 'P1AM',
+ version: '1.0.0',
+ author: 'Autonomy Logic',
+ stPath: 'src/renderer/data/library/p1am/st',
+ cPath: 'src/renderer/data/library/p1am/c',
+ pous: [
+ {
+ name: 'P1AM_INIT',
+ type: 'function-block',
+ language: 'st',
+ variables: [
+ { name: 'INIT', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'SUCCESS', class: 'output', type: { definition: 'base-type', value: 'SINT' } },
+ ],
+ body: 'SUCCESS := 0;',
+ documentation:
+ "Initialize P1AM Modules and return the number of initialized modules on SUCCESS. If SUCCESS is zero, an error has occurred, or there aren't any modules on the bus",
+ },
+ {
+ name: 'P1_16CDR',
+ type: 'function-block',
+ language: 'st',
+ variables: [
+ { name: 'SLOT', class: 'input', type: { definition: 'base-type', value: 'SINT' } },
+ { name: 'O1', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'O2', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'O3', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'O4', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'O5', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'O6', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'O7', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'O8', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'I1', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'I2', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'I3', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'I4', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'I5', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'I6', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'I7', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'I8', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ ],
+ body: 'I1 := 0;',
+ documentation:
+ 'Get all inputs and update all outputs from P1-16CDR module. Also works with P1-15CDD1 and P1-15CDD2',
+ },
+ {
+ name: 'P1_08N',
+ type: 'function-block',
+ language: 'st',
+ variables: [
+ { name: 'SLOT', class: 'input', type: { definition: 'base-type', value: 'SINT' } },
+ { name: 'I1', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'I2', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'I3', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'I4', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'I5', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'I6', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'I7', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'I8', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ ],
+ body: 'I1 := 0;',
+ documentation: 'Get all inputs from P1-08Nxx modules. Compatible with P1-08NA, P1-08ND3, P1-08NE3 and P1-08SIM',
+ },
+ {
+ name: 'P1_16N',
+ type: 'function-block',
+ language: 'st',
+ variables: [
+ { name: 'SLOT', class: 'input', type: { definition: 'base-type', value: 'SINT' } },
+ { name: 'I1', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'I2', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'I3', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'I4', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'I5', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'I6', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'I7', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'I8', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'I9', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'I10', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'I11', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'I12', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'I13', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'I14', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'I15', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'I16', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ ],
+ body: 'I1 := 0;',
+ documentation: 'Get all inputs from P1-16Nxx modules. Compatible with P1-16ND3 and P1-16NE3',
+ },
+ {
+ name: 'P1_08T',
+ type: 'function-block',
+ language: 'st',
+ variables: [
+ { name: 'SLOT', class: 'input', type: { definition: 'base-type', value: 'SINT' } },
+ { name: 'O1', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'O2', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'O3', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'O4', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'O5', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'O6', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'O7', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'O8', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'DUMMY', class: 'local', type: { definition: 'base-type', value: 'SINT' } },
+ ],
+ body: 'DUMMY := SLOT;',
+ documentation: 'Set all outputs on P1-08Txx modules. Compatible with P1-08TA, P1-08TD1, P1-08TD2 and P1-08TRS',
+ },
+ {
+ name: 'P1_16TR',
+ type: 'function-block',
+ language: 'st',
+ variables: [
+ { name: 'SLOT', class: 'input', type: { definition: 'base-type', value: 'SINT' } },
+ { name: 'O1', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'O2', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'O3', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'O4', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'O5', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'O6', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'O7', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'O8', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'O9', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'O10', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'O11', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'O12', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'O13', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'O14', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'O15', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'O16', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'DUMMY', class: 'local', type: { definition: 'base-type', value: 'SINT' } },
+ ],
+ body: 'DUMMY := SLOT;',
+ documentation: 'Set all outputs on P1-16TR modules. Also compatible with P1-15TD1 and P1-15TD2',
+ },
+ {
+ name: 'P1_04AD',
+ type: 'function-block',
+ language: 'st',
+ variables: [
+ { name: 'SLOT', class: 'input', type: { definition: 'base-type', value: 'SINT' } },
+ { name: 'I1', class: 'output', type: { definition: 'base-type', value: 'UINT' } },
+ { name: 'I2', class: 'output', type: { definition: 'base-type', value: 'UINT' } },
+ { name: 'I3', class: 'output', type: { definition: 'base-type', value: 'UINT' } },
+ { name: 'I4', class: 'output', type: { definition: 'base-type', value: 'UINT' } },
+ { name: 'DUMMY', class: 'local', type: { definition: 'base-type', value: 'SINT' } },
+ ],
+ body: 'DUMMY := SLOT;',
+ documentation: 'Get all analog inputs from P1-04ADxx modules. Compatible with P1-04AD, P1-04ADL-1 and P1-04ADL-2',
+ },
+ ],
+}
+
+export { P1AM }
diff --git a/src/frontend/data/library/additional-function-blocks.ts b/src/frontend/data/library/additional-function-blocks.ts
new file mode 100644
index 000000000..fdd3e9b74
--- /dev/null
+++ b/src/frontend/data/library/additional-function-blocks.ts
@@ -0,0 +1,341 @@
+import { z } from 'zod'
+
+import {
+ BaseLibraryPouSchema,
+ BaseLibraryVariableSchema,
+ baseTypeSchema,
+} from '../../../middleware/shared/ports/plc-schemas'
+
+/** Library-level schema (name + version + paths). Not in plc-schemas so defined locally. */
+const BaseLibrarySchema = z.object({
+ name: z.string(),
+ version: z.string(),
+ author: z.string(),
+ stPath: z.string(),
+ cPath: z.string(),
+})
+
+const AdditionalFunctionBlocksVariablesSchema = BaseLibraryVariableSchema.extend({
+ type: z.discriminatedUnion('definition', [
+ z.object({
+ definition: z.literal('base-type'),
+ value: baseTypeSchema,
+ }),
+ z.object({
+ definition: z.literal('derived-type'),
+ value: z.string(),
+ }),
+ ]),
+ initialValue: z
+ .lazy((): z.Schema => AdditionalFunctionBlocksVariablesSchema.pick({ type: true }))
+ .optional(),
+})
+
+const AdditionalFunctionBlocksPouSchema = BaseLibraryPouSchema.extend({
+ variables: z.array(AdditionalFunctionBlocksVariablesSchema),
+})
+
+export const AdditionalFunctionBlocksLibrarySchema = BaseLibrarySchema.extend({
+ pous: z.array(AdditionalFunctionBlocksPouSchema),
+})
+
+type AdditionalFunctionBlocksLibrary = z.infer
+
+const AdditionalFunctionBlocks: AdditionalFunctionBlocksLibrary = {
+ name: 'Additional Function Blocks',
+ version: '1.0.0',
+ author: 'Autonomy Logic',
+ stPath: 'dummypath/wichwillbereplacedlater',
+ cPath: 'dummypath/wichwillbereplacedlater',
+ pous: [
+ {
+ name: 'RTC',
+ type: 'function-block',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'BOOL' },
+ documentation: '0 - current time, 1 - load time from PDT',
+ },
+ {
+ name: 'PDT',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DT' },
+ documentation: 'Preset datetime',
+ },
+ {
+ name: 'Q',
+ class: 'output',
+ type: { definition: 'base-type', value: 'BOOL' },
+ initialValue: { value: 'FALSE' },
+ documentation: 'Copy of IN',
+ },
+ {
+ name: 'CDT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'DT' },
+ documentation: 'Datetime, current or relative to PDT',
+ },
+ {
+ name: 'PREV_IN',
+ class: 'local',
+ type: { definition: 'base-type', value: 'BOOL' },
+ initialValue: { value: 'FALSE' },
+ },
+ { name: 'OFFSET', class: 'local', type: { definition: 'base-type', value: 'TIME' } },
+ { name: 'CURRENT_TIME', class: 'local', type: { definition: 'base-type', value: 'DT' } },
+ ],
+ body: '{__SET_VAR(data__->,CURRENT_TIME,,__CURRENT_TIME)}\n\n IF IN\n THEN\n IF NOT PREV_IN\n THEN\n OFFSET := PDT - CURRENT_TIME;\n END_IF;\n\n (* PDT + time since PDT was loaded *)\n CDT := CURRENT_TIME + OFFSET;\n ELSE\n CDT := CURRENT_TIME;\n END_IF;\n\n Q := IN;\n PREV_IN := IN;',
+ documentation:
+ 'The real time clock has many uses including time stamping, setting dates and times of day in batch reports, in alarm messages and so on.',
+ },
+ {
+ name: 'INTEGRAL',
+ type: 'function-block',
+ language: 'st',
+ variables: [
+ {
+ name: 'RUN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'BOOL' },
+ documentation: '1 = integrate, 0 = hold',
+ },
+ {
+ name: 'R1',
+ class: 'input',
+ type: { definition: 'base-type', value: 'BOOL' },
+ documentation: 'Overriding reset',
+ },
+ {
+ name: 'XIN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'REAL' },
+ documentation: 'Input variable',
+ },
+ {
+ name: 'X0',
+ class: 'input',
+ type: { definition: 'base-type', value: 'REAL' },
+ documentation: 'Initial value',
+ },
+ {
+ name: 'CYCLE',
+ class: 'input',
+ type: { definition: 'base-type', value: 'TIME' },
+ documentation: 'Sampling period',
+ },
+ { name: 'Q', class: 'output', type: { definition: 'base-type', value: 'BOOL' }, documentation: 'NOT R1' },
+ {
+ name: 'XOUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'REAL' },
+ documentation: 'Integrated output',
+ },
+ ],
+ body: 'Q := NOT R1 ;\nIF R1 THEN XOUT := X0;\nELSIF RUN THEN XOUT := XOUT + XIN * TIME_TO_REAL(CYCLE);\nEND_IF;',
+ documentation: 'The integral function block integrates the value of input XIN over time.',
+ },
+ {
+ name: 'DERIVATIVE',
+ type: 'function-block',
+ language: 'st',
+ variables: [
+ { name: 'RUN', class: 'input', type: { definition: 'base-type', value: 'BOOL' }, documentation: '0 = reset' },
+ {
+ name: 'XIN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'REAL' },
+ documentation: 'Input to be differentiated',
+ },
+ {
+ name: 'CYCLE',
+ class: 'input',
+ type: { definition: 'base-type', value: 'TIME' },
+ documentation: 'Sampling period',
+ },
+ {
+ name: 'XOUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'REAL' },
+ documentation: 'Differentiated output',
+ },
+ { name: 'X1', class: 'local', type: { definition: 'base-type', value: 'REAL' } },
+ { name: 'X2', class: 'local', type: { definition: 'base-type', value: 'REAL' } },
+ { name: 'X3', class: 'local', type: { definition: 'base-type', value: 'REAL' } },
+ ],
+ body: 'IF RUN THEN\n XOUT := (3.0 * (XIN - X3) + X1 - X2)\n / (10.0 * TIME_TO_REAL(CYCLE));\n X3 := X2;\n X2 := X1;\n X1 := XIN;\nELSE \n XOUT := 0.0;\n X1 := XIN;\n X2 := XIN;\n X3 := XIN;\nEND_IF;',
+ documentation:
+ 'The derivative function block produces an output XOUT proportional to the rate of change of the input XIN.',
+ },
+ {
+ name: 'PID',
+ type: 'function-block',
+ language: 'st',
+ variables: [
+ {
+ name: 'AUTO',
+ class: 'input',
+ type: { definition: 'base-type', value: 'BOOL' },
+ documentation: '0 - manual, 1 - automatic',
+ },
+ {
+ name: 'PV',
+ class: 'input',
+ type: { definition: 'base-type', value: 'REAL' },
+ documentation: 'Process variable',
+ },
+ { name: 'SP', class: 'input', type: { definition: 'base-type', value: 'REAL' }, documentation: 'Set point' },
+ {
+ name: 'X0',
+ class: 'input',
+ type: { definition: 'base-type', value: 'REAL' },
+ documentation: 'Manual output adjustment - Typically from transfer station',
+ },
+ {
+ name: 'KP',
+ class: 'input',
+ type: { definition: 'base-type', value: 'REAL' },
+ documentation: 'Proportional gain',
+ },
+ { name: 'TR', class: 'input', type: { definition: 'base-type', value: 'REAL' }, documentation: 'Reset time' },
+ {
+ name: 'TD',
+ class: 'input',
+ type: { definition: 'base-type', value: 'REAL' },
+ documentation: 'Derivative time constant',
+ },
+ {
+ name: 'CYCLE',
+ class: 'input',
+ type: { definition: 'base-type', value: 'TIME' },
+ documentation: 'Sampling period',
+ },
+ { name: 'XOUT', class: 'output', type: { definition: 'base-type', value: 'REAL' } },
+ { name: 'ERROR', class: 'local', type: { definition: 'base-type', value: 'REAL' }, documentation: 'PV - SP' },
+ {
+ name: 'ITERM',
+ class: 'local',
+ type: { definition: 'derived-type', value: 'INTEGRAL' },
+ documentation: 'FB for integral term',
+ },
+ {
+ name: 'DTERM',
+ class: 'local',
+ type: { definition: 'derived-type', value: 'DERIVATIVE' },
+ documentation: 'FB for derivative term',
+ },
+ ],
+ body: 'ERROR := PV - SP ;\n(*** Adjust ITERM so that XOUT := X0 when AUTO = 0 ***)\nITERM(RUN := AUTO, R1 := NOT AUTO, XIN := ERROR,\n X0 := TR * (X0 - ERROR), CYCLE := CYCLE);\nDTERM(RUN := AUTO, XIN := ERROR, CYCLE := CYCLE);\nXOUT := KP * (ERROR + ITERM.XOUT/TR + DTERM.XOUT*TD);',
+ documentation:
+ 'The PID (proportional, Integral, Derivative) function block provides the classical three term controller for closed loop control.',
+ },
+ {
+ name: 'RAMP',
+ type: 'function-block',
+ language: 'st',
+ variables: [
+ {
+ name: 'RUN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'BOOL' },
+ documentation: '0 - track X0, 1 - ramp to/track X1',
+ },
+ { name: 'X0', class: 'input', type: { definition: 'base-type', value: 'REAL' } },
+ { name: 'X1', class: 'input', type: { definition: 'base-type', value: 'REAL' } },
+ {
+ name: 'TR',
+ class: 'input',
+ type: { definition: 'base-type', value: 'TIME' },
+ documentation: 'Ramp duration',
+ },
+ {
+ name: 'CYCLE',
+ class: 'input',
+ type: { definition: 'base-type', value: 'TIME' },
+ documentation: 'Sampling period',
+ },
+ {
+ name: 'BUSY',
+ class: 'output',
+ type: { definition: 'base-type', value: 'BOOL' },
+ documentation: 'BUSY = 1 during ramping period',
+ },
+ {
+ name: 'XOUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'REAL' },
+ initialValue: { value: '0.0' },
+ },
+ {
+ name: 'XI',
+ class: 'local',
+ type: { definition: 'base-type', value: 'REAL' },
+ initialValue: { value: '0.0' },
+ documentation: 'Initial value',
+ },
+ {
+ name: 'T',
+ class: 'local',
+ type: { definition: 'base-type', value: 'TIME' },
+ initialValue: { value: 'T#0s' },
+ documentation: 'Elapsed time of ramp',
+ },
+ ],
+ body: `BUSY := RUN ;
+IF RUN THEN
+ IF T >= TR THEN
+ BUSY := 0;
+ XOUT := X1;
+ ELSE XOUT := XI + (X1-XI) * TIME_TO_REAL(T)
+ / TIME_TO_REAL(TR);
+ T := T + CYCLE;
+ END_IF;
+ELSE
+ XOUT := X0;
+ XI := X0;
+ T := T#0s;
+END_IF;`,
+ documentation: 'The RAMP function block is modelled on example given in the standard.',
+ },
+ {
+ name: 'HYSTERESIS',
+ type: 'function-block',
+ language: 'st',
+ variables: [
+ {
+ name: 'XIN1',
+ class: 'input',
+ type: { definition: 'base-type', value: 'REAL' },
+ },
+ {
+ name: 'XIN2',
+ class: 'input',
+ type: { definition: 'base-type', value: 'REAL' },
+ },
+ {
+ name: 'EPS',
+ class: 'input',
+ type: { definition: 'base-type', value: 'REAL' },
+ },
+ {
+ name: 'Q',
+ class: 'output',
+ type: { definition: 'base-type', value: 'BOOL' },
+ },
+ ],
+ body: `IF Q THEN
+ IF XIN1 < (XIN2 - EPS) THEN
+ Q := 0;
+ END_IF;
+ELSIF XIN1 > (XIN2 + EPS) THEN
+ Q := 1;
+END_IF;`,
+ documentation:
+ 'The hysteresis function block provides a hysteresis boolean output driven by the difference of two floating point (REAL) inputs XIN1 and XIN2.',
+ },
+ ],
+}
+
+export { AdditionalFunctionBlocks }
diff --git a/src/frontend/data/library/arduino-function-blocks.ts b/src/frontend/data/library/arduino-function-blocks.ts
new file mode 100644
index 000000000..591bef82a
--- /dev/null
+++ b/src/frontend/data/library/arduino-function-blocks.ts
@@ -0,0 +1,439 @@
+import { z } from 'zod'
+
+import { BaseLibraryPouSchema, BaseLibraryVariableSchema } from '../../../middleware/shared/ports/plc-schemas'
+
+/** Library-level schema (name + version + paths). Not in plc-schemas so defined locally. */
+const BaseLibrarySchema = z.object({
+ name: z.string(),
+ version: z.string(),
+ author: z.string(),
+ stPath: z.string(),
+ cPath: z.string(),
+})
+
+const ArduinoFunctionBlocksVariableSchema = BaseLibraryVariableSchema
+
+const ArduinoFunctionBlocksPouSchema = BaseLibraryPouSchema.extend({
+ variables: z.array(ArduinoFunctionBlocksVariableSchema),
+})
+
+export const ArduinoFunctionBlocksLibrarySchema = BaseLibrarySchema.extend({
+ pous: z.array(ArduinoFunctionBlocksPouSchema),
+})
+
+type ArduinoFunctionBlocksLibrary = z.infer
+
+const ArduinoFunctionBlocks: ArduinoFunctionBlocksLibrary = {
+ name: 'Arduino Function Blocks',
+ version: '1.0.0',
+ author: 'Autonomy Logic',
+ stPath: 'src/renderer/data/library/arduino-function-blocks/st',
+ cPath: 'src/renderer/data/library/arduino-function-blocks/c',
+ pous: [
+ {
+ name: 'DS18B20',
+ type: 'function-block',
+ language: 'st',
+ variables: [
+ {
+ name: 'PIN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'SINT' },
+ documentation: 'Arduino pin where sensor is connected to',
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'REAL' },
+ documentation: 'Temperature output in Celsius',
+ },
+ ],
+ body: 'OUT := 0.0;',
+ documentation: 'Reads temperature from one DS18B20 one-wire sensor connected to the pin specified in PIN',
+ },
+ {
+ name: 'DS18B20_2_OUT',
+ type: 'function-block',
+ language: 'st',
+ variables: [
+ {
+ name: 'PIN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'SINT' },
+ documentation: 'Arduino pin where sensor is connected to',
+ },
+ {
+ name: 'OUT_0',
+ class: 'output',
+ type: { definition: 'base-type', value: 'REAL' },
+ documentation: 'Temperature output in Celsius',
+ },
+ {
+ name: 'OUT_1',
+ class: 'output',
+ type: { definition: 'base-type', value: 'REAL' },
+ documentation: 'Temperature output in Celsius',
+ },
+ ],
+ body: 'OUT := 0.0;',
+ documentation:
+ 'Reads temperature from two DS18B20 one-wire sensors. Both sensors must be on the same bus connected to the pin specified in PIN',
+ },
+ {
+ name: 'DS18B20_3_OUT',
+ type: 'function-block',
+ language: 'st',
+ variables: [
+ {
+ name: 'PIN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'SINT' },
+ documentation: 'Arduino pin where sensor is connected to',
+ },
+ {
+ name: 'OUT_0',
+ class: 'output',
+ type: { definition: 'base-type', value: 'REAL' },
+ documentation: 'Temperature output in Celsius',
+ },
+ {
+ name: 'OUT_1',
+ class: 'output',
+ type: { definition: 'base-type', value: 'REAL' },
+ documentation: 'Temperature output in Celsius',
+ },
+ {
+ name: 'OUT_2',
+ class: 'output',
+ type: { definition: 'base-type', value: 'REAL' },
+ documentation: 'Temperature output in Celsius',
+ },
+ ],
+ body: 'OUT := 0.0;',
+ documentation:
+ 'Reads temperature from three DS18B20 one-wire sensors. All sensors must be on the same bus connected to the pin specified in PIN',
+ },
+ {
+ name: 'DS18B20_4_OUT',
+ type: 'function-block',
+ language: 'st',
+ variables: [
+ {
+ name: 'PIN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'SINT' },
+ documentation: 'Arduino pin where sensor is connected to',
+ },
+ {
+ name: 'OUT_0',
+ class: 'output',
+ type: { definition: 'base-type', value: 'REAL' },
+ documentation: 'Temperature output in Celsius',
+ },
+ {
+ name: 'OUT_1',
+ class: 'output',
+ type: { definition: 'base-type', value: 'REAL' },
+ documentation: 'Temperature output in Celsius',
+ },
+ {
+ name: 'OUT_2',
+ class: 'output',
+ type: { definition: 'base-type', value: 'REAL' },
+ documentation: 'Temperature output in Celsius',
+ },
+ {
+ name: 'OUT_3',
+ class: 'output',
+ type: { definition: 'base-type', value: 'REAL' },
+ documentation: 'Temperature output in Celsius',
+ },
+ ],
+ body: 'OUT := 0.0;',
+ documentation:
+ 'Reads temperature from four DS18B20 one-wire sensors. All sensors must be on the same bus connected to the pin specified in PIN',
+ },
+ {
+ name: 'DS18B20_5_OUT',
+ type: 'function-block',
+ language: 'st',
+ variables: [
+ {
+ name: 'PIN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'SINT' },
+ documentation: 'Arduino pin where sensor is connected to',
+ },
+ {
+ name: 'OUT_0',
+ class: 'output',
+ type: { definition: 'base-type', value: 'REAL' },
+ documentation: 'Temperature output in Celsius',
+ },
+ {
+ name: 'OUT_1',
+ class: 'output',
+ type: { definition: 'base-type', value: 'REAL' },
+ documentation: 'Temperature output in Celsius',
+ },
+ {
+ name: 'OUT_2',
+ class: 'output',
+ type: { definition: 'base-type', value: 'REAL' },
+ documentation: 'Temperature output in Celsius',
+ },
+ {
+ name: 'OUT_3',
+ class: 'output',
+ type: { definition: 'base-type', value: 'REAL' },
+ documentation: 'Temperature output in Celsius',
+ },
+ {
+ name: 'OUT_4',
+ class: 'output',
+ type: { definition: 'base-type', value: 'REAL' },
+ documentation: 'Temperature output in Celsius',
+ },
+ ],
+ body: 'OUT := 0.0;',
+ documentation:
+ 'Reads temperature from five DS18B20 one-wire sensors. All sensors must be on the same bus connected to the pin specified in PIN',
+ },
+ {
+ name: 'CLOUD_ADD_BOOL',
+ type: 'function-block',
+ language: 'st',
+ variables: [
+ { name: 'VAR_NAME', class: 'input', type: { definition: 'base-type', value: 'STRING' } },
+ { name: 'BOOL_VAR', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ ],
+ body: 'SSID := SSID;',
+ documentation:
+ 'Add a BOOL variable to sync with the Arduino Cloud. VAR_NAME must have the same name as the variable set up in the Arduino IoT Cloud',
+ },
+ {
+ name: 'CLOUD_ADD_DINT',
+ type: 'function-block',
+ language: 'st',
+ variables: [
+ { name: 'VAR_NAME', class: 'input', type: { definition: 'base-type', value: 'STRING' } },
+ { name: 'DINT_VAR', class: 'input', type: { definition: 'base-type', value: 'DINT' } },
+ ],
+ body: 'SSID := SSID;',
+ documentation:
+ 'Add an DINT variable (Arduino int) to sync with the Arduino Cloud. VAR_NAME must have the same name as the variable set up in the Arduino IoT Cloud',
+ },
+ {
+ name: 'CLOUD_ADD_REAL',
+ type: 'function-block',
+ language: 'st',
+ variables: [
+ { name: 'VAR_NAME', class: 'input', type: { definition: 'base-type', value: 'STRING' } },
+ { name: 'REAL_VAR', class: 'input', type: { definition: 'base-type', value: 'REAL' } },
+ ],
+ body: 'SSID := SSID;',
+ documentation:
+ 'Add a REAL variable (Arduino float) to sync with the Arduino Cloud. VAR_NAME must have the same name as the variable set up in the Arduino IoT Cloud',
+ },
+ {
+ name: 'CLOUD_BEGIN',
+ type: 'function-block',
+ language: 'st',
+ variables: [
+ { name: 'THING_ID', class: 'input', type: { definition: 'base-type', value: 'STRING' } },
+ { name: 'SSID', class: 'input', type: { definition: 'base-type', value: 'STRING' } },
+ { name: 'PASS', class: 'input', type: { definition: 'base-type', value: 'STRING' } },
+ ],
+ body: 'SSID := SSID;',
+ documentation:
+ 'Setup and initialize Arduino Cloud communication. Must be called before adding any variables (properties).',
+ },
+ {
+ name: 'PWM_CONTROLLER',
+ type: 'function-block',
+ language: 'st',
+ variables: [
+ { name: 'CHANNEL', class: 'input', type: { definition: 'base-type', value: 'SINT' }, documentation: 'CHANNEL' },
+ { name: 'FREQ', class: 'input', type: { definition: 'base-type', value: 'REAL' }, documentation: 'FREQ' },
+ { name: 'DUTY', class: 'input', type: { definition: 'base-type', value: 'REAL' }, documentation: 'DUTY' },
+ {
+ name: 'internal_ch',
+ class: 'local',
+ type: { definition: 'base-type', value: 'SINT' },
+ documentation: 'internal_ch',
+ },
+ {
+ name: 'internal_freq',
+ class: 'local',
+ type: { definition: 'base-type', value: 'REAL' },
+ documentation: 'internal_freq',
+ },
+ {
+ name: 'internal_duty',
+ class: 'local',
+ type: { definition: 'base-type', value: 'REAL' },
+ documentation: 'internal_duty',
+ },
+ {
+ name: 'SUCCESS',
+ class: 'output',
+ type: { definition: 'base-type', value: 'BOOL' },
+ documentation: 'SUCCESS',
+ },
+ ],
+ body: `
+ IF CHANNEL < 1 THEN
+ SUCCESS := FALSE;
+ RETURN;
+ END_IF;
+
+
+ IF (CHANNEL <> internal_ch) OR (FREQ <> internal_freq) OR (DUTY <> internal_duty) THEN
+ SUCCESS := TRUE;
+ END_IF;
+ `,
+ documentation:
+ 'Configures the CPU internal PWM peripheral to generate a PWM signal through hardware. If the CPU does not have a PWM peripheral, compiling this block will result in a compilation error. CHANNEL is the PWM channel number. For most Arduino boards that number is the pin number for the PWM capable pin. FREQ is the desired PWM frequency in Hz. DUTY is the PWM duty cycle (between 0 and 100).',
+ },
+ {
+ name: 'ARDUINOCAN_CONF',
+ type: 'function-block',
+ language: 'st',
+ variables: [
+ {
+ name: 'EN_PIN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'WORD' },
+ documentation: 'Arduino CAN Enable pin',
+ },
+ {
+ name: 'BR',
+ class: 'input',
+ type: { definition: 'base-type', value: 'LINT' },
+ documentation: 'Arduino CAN Baudrate',
+ },
+ {
+ name: 'DONE',
+ class: 'output',
+ type: { definition: 'base-type', value: 'BOOL' },
+ documentation: 'Arduino CAN configuration Done flag',
+ },
+ ],
+ body: 'DONE := FALSE;',
+ documentation: 'Configure Arduino CAN communication',
+ },
+ {
+ name: 'ARDUINOCAN_WRITE',
+ type: 'function-block',
+ language: 'st',
+ variables: [
+ {
+ name: 'ID',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DWORD' },
+ documentation: 'Arduino CAN message ID',
+ },
+ {
+ name: 'D0',
+ class: 'input',
+ type: { definition: 'base-type', value: 'USINT' },
+ documentation: 'Arduino CAN first payload byte',
+ },
+ {
+ name: 'D1',
+ class: 'input',
+ type: { definition: 'base-type', value: 'USINT' },
+ documentation: 'Arduino CAN second payload byte',
+ },
+ {
+ name: 'D2',
+ class: 'input',
+ type: { definition: 'base-type', value: 'USINT' },
+ documentation: 'Arduino CAN third payload byte',
+ },
+ {
+ name: 'D3',
+ class: 'input',
+ type: { definition: 'base-type', value: 'USINT' },
+ documentation: 'Arduino CAN fourth payload byte',
+ },
+ {
+ name: 'D4',
+ class: 'input',
+ type: { definition: 'base-type', value: 'USINT' },
+ documentation: 'Arduino CAN fifth payload byte',
+ },
+ {
+ name: 'D5',
+ class: 'input',
+ type: { definition: 'base-type', value: 'USINT' },
+ documentation: 'Arduino CAN sixth payload byte',
+ },
+ {
+ name: 'D6',
+ class: 'input',
+ type: { definition: 'base-type', value: 'USINT' },
+ documentation: 'Arduino CAN seventh payload byte',
+ },
+ {
+ name: 'D7',
+ class: 'input',
+ type: { definition: 'base-type', value: 'USINT' },
+ documentation: 'Arduino CAN eighth payload byte',
+ },
+ {
+ name: 'DONE',
+ class: 'output',
+ type: { definition: 'base-type', value: 'BOOL' },
+ documentation: 'Arduino CAN write done flag',
+ },
+ ],
+ body: 'DONE := FALSE;',
+ documentation: 'Write data to Arduino CAN bus',
+ },
+ {
+ name: 'ARDUINOCAN_WRITE_WORD',
+ type: 'function-block',
+ language: 'st',
+ variables: [
+ {
+ name: 'ID',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DWORD' },
+ documentation: 'Arduino CAN message ID',
+ },
+ {
+ name: 'DATA',
+ class: 'input',
+ type: { definition: 'base-type', value: 'LWORD' },
+ documentation: 'Arduino CAN payload',
+ },
+ {
+ name: 'DONE',
+ class: 'output',
+ type: { definition: 'base-type', value: 'BOOL' },
+ documentation: 'Arduino CAN write done flag',
+ },
+ ],
+ body: 'DONE := FALSE;',
+ documentation: 'Write word data to Arduino CAN bus',
+ },
+ {
+ name: 'ARDUINOCAN_READ',
+ type: 'function-block',
+ language: 'st',
+ variables: [
+ {
+ name: 'DATA',
+ class: 'output',
+ type: { definition: 'base-type', value: 'LWORD' },
+ documentation: 'Arduino CAN readed data from arduino can message',
+ },
+ ],
+ body: 'DATA := 0;',
+ documentation: 'CAN READ',
+ },
+ ],
+}
+
+export { ArduinoFunctionBlocks }
diff --git a/src/frontend/data/library/communication-blocks.ts b/src/frontend/data/library/communication-blocks.ts
new file mode 100644
index 000000000..c2b0b938b
--- /dev/null
+++ b/src/frontend/data/library/communication-blocks.ts
@@ -0,0 +1,92 @@
+import { z } from 'zod'
+
+import { BaseLibraryPouSchema, BaseLibraryVariableSchema } from '../../../middleware/shared/ports/plc-schemas'
+
+/** Library-level schema (name + version + paths). Not in plc-schemas so defined locally. */
+const BaseLibrarySchema = z.object({
+ name: z.string(),
+ version: z.string(),
+ author: z.string(),
+ stPath: z.string(),
+ cPath: z.string(),
+})
+
+const CommunicationBlocksVariableSchema = BaseLibraryVariableSchema
+
+const CommunicationBlocksPouSchema = BaseLibraryPouSchema.extend({
+ variables: z.array(CommunicationBlocksVariableSchema),
+})
+
+export const CommunicationBlocksLibrarySchema = BaseLibrarySchema.extend({
+ pous: z.array(CommunicationBlocksPouSchema),
+})
+
+type CommunicationBlocksLibrary = z.infer
+
+const CommunicationBlocks: CommunicationBlocksLibrary = {
+ name: 'Communication Blocks',
+ version: '1.0.0',
+ author: 'Autonomy Logic',
+ stPath: 'src/renderer/data/library/communication-blocks/st',
+ cPath: 'src/renderer/data/library/communication-blocks/c',
+ pous: [
+ {
+ name: 'TCP_CONNECT',
+ type: 'function-block',
+ language: 'st',
+ variables: [
+ { name: 'CONNECT', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'IP_ADDRESS', class: 'input', type: { definition: 'base-type', value: 'STRING' } },
+ { name: 'PORT', class: 'input', type: { definition: 'base-type', value: 'INT' } },
+ { name: 'UDP', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'SOCKET_ID', class: 'output', type: { definition: 'base-type', value: 'INT' } },
+ ],
+ body: 'SOCKET_ID := 0;',
+ documentation:
+ 'Connect to a remote TCP server when CONNECT is TRUE. Upon success, this block returns the connection ID on SOCKET_ID. If SOCKET_ID is less than zero, then the connection was not successfull',
+ },
+ {
+ name: 'TCP_SEND',
+ type: 'function-block',
+ language: 'st',
+ variables: [
+ { name: 'SEND', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'SOCKET_ID', class: 'input', type: { definition: 'base-type', value: 'INT' } },
+ { name: 'MSG', class: 'input', type: { definition: 'base-type', value: 'STRING' } },
+ { name: 'BYTES_SENT', class: 'output', type: { definition: 'base-type', value: 'INT' } },
+ ],
+ body: 'BYTES_SENT := 0;',
+ documentation:
+ 'Send a message to a remote device using TCP/IP when SEND is TRUE. SOCKET_ID must receive a connection ID from a successfull connection using the TCP_Connect block. BYTES_SENT returns the number of bytes sent to the remote device. If BYTES_SENT is less than zero then an error occurred while trying to send the message',
+ },
+ {
+ name: 'TCP_RECEIVE',
+ type: 'function-block',
+ language: 'st',
+ variables: [
+ { name: 'RECEIVE', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'SOCKET_ID', class: 'input', type: { definition: 'base-type', value: 'INT' } },
+ { name: 'BYTES_RECEIVED', class: 'output', type: { definition: 'base-type', value: 'INT' } },
+ { name: 'MSG', class: 'output', type: { definition: 'base-type', value: 'STRING' } },
+ ],
+ body: 'BYTES_RECEIVED := 0;',
+ documentation:
+ 'Send a message to a remote device using TCP/IP when SEND is TRUE. SOCKET_ID must receive a connection ID from a successfull connection using the TCP_Connect block. BYTES_RECEIVED returns the number of bytes received from the remote device. MSG is a String containing the message received',
+ },
+ {
+ name: 'TCP_CLOSE',
+ type: 'function-block',
+ language: 'st',
+ variables: [
+ { name: 'CLOSE', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'SOCKET_ID', class: 'input', type: { definition: 'base-type', value: 'INT' } },
+ { name: 'SUCCESS', class: 'output', type: { definition: 'base-type', value: 'INT' } },
+ ],
+ body: 'SUCCESS := 0;',
+ documentation:
+ 'Close the TCP connection with the remote server. If SUCCESS is less than zero, then the connection was not successfully closed, or the connection does not exist anymore.',
+ },
+ ],
+}
+
+export { CommunicationBlocks }
diff --git a/src/frontend/data/library/function/arithmetic.ts b/src/frontend/data/library/function/arithmetic.ts
new file mode 100644
index 000000000..f52a5d660
--- /dev/null
+++ b/src/frontend/data/library/function/arithmetic.ts
@@ -0,0 +1,222 @@
+import { z } from 'zod'
+
+import {
+ BaseLibraryPouSchema,
+ BaseLibraryVariableSchema,
+ baseTypeSchema,
+ genericTypeSchema,
+} from '../../../../middleware/shared/ports/plc-schemas'
+
+/** Library-level schema (name + version + paths). Not in plc-schemas so defined locally. */
+const BaseLibrarySchema = z.object({
+ name: z.string(),
+ version: z.string(),
+ author: z.string(),
+ stPath: z.string(),
+ cPath: z.string(),
+})
+
+const ArithmeticVariableSchema = BaseLibraryVariableSchema.extend({
+ type: z.discriminatedUnion('definition', [
+ z.object({
+ definition: z.literal('base-type'),
+ value: baseTypeSchema,
+ }),
+ z.object({
+ definition: z.literal('generic-type'),
+ value: genericTypeSchema.keyof(),
+ }),
+ ]),
+})
+
+const ArithmeticPouSchema = BaseLibraryPouSchema.extend({
+ variables: z.array(ArithmeticVariableSchema),
+})
+
+const ArithmeticLibrarySchema = BaseLibrarySchema.extend({
+ pous: z.array(ArithmeticPouSchema),
+})
+
+type ArithmeticLibrary = z.infer
+
+const Arithmetic: ArithmeticLibrary = {
+ name: 'Arithmetic',
+ version: '1.0.0',
+ author: 'Autonomy Logic',
+ stPath: 'path/to/st/file',
+ cPath: 'path/to/c/file',
+ pous: [
+ {
+ name: 'ADD',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN1',
+ class: 'input',
+ type: { definition: 'generic-type', value: 'ANY_NUM' },
+ },
+ {
+ name: 'IN2',
+ class: 'input',
+ type: { definition: 'generic-type', value: 'ANY_NUM' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'generic-type', value: 'ANY_NUM' },
+ },
+ ],
+ body: 'Addition',
+ documentation: '(IN1: ANY_NUM, IN2:ANY_NUM) => OUT:ANY_NUM',
+ extensible: true,
+ },
+ {
+ name: 'MUL',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN1',
+ class: 'input',
+ type: { definition: 'generic-type', value: 'ANY_NUM' },
+ },
+ {
+ name: 'IN2',
+ class: 'input',
+ type: { definition: 'generic-type', value: 'ANY_NUM' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'generic-type', value: 'ANY_NUM' },
+ },
+ ],
+ body: 'Multiplication',
+ documentation: '(IN1: ANY_NUM, IN2:ANY_NUM) => OUT:ANY_NUM',
+ extensible: true,
+ },
+ {
+ name: 'SUB',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN1',
+ class: 'input',
+ type: { definition: 'generic-type', value: 'ANY_NUM' },
+ },
+ {
+ name: 'IN2',
+ class: 'input',
+ type: { definition: 'generic-type', value: 'ANY_NUM' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'generic-type', value: 'ANY_NUM' },
+ },
+ ],
+ body: 'Subtraction',
+ documentation: '(IN1: ANY_NUM, IN2:ANY_NUM) => OUT:ANY_NUM',
+ extensible: false,
+ },
+ {
+ name: 'DIV',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN1',
+ class: 'input',
+ type: { definition: 'generic-type', value: 'ANY_NUM' },
+ },
+ {
+ name: 'IN2',
+ class: 'input',
+ type: { definition: 'generic-type', value: 'ANY_NUM' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'generic-type', value: 'ANY_NUM' },
+ },
+ ],
+ body: 'Division',
+ documentation: '(IN1: ANY_NUM, IN2:ANY_NUM) => OUT:ANY_NUM',
+ extensible: false,
+ },
+ {
+ name: 'MOD',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN1',
+ class: 'input',
+ type: { definition: 'generic-type', value: 'ANY_INT' },
+ },
+ {
+ name: 'IN2',
+ class: 'input',
+ type: { definition: 'generic-type', value: 'ANY_INT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'generic-type', value: 'ANY_INT' },
+ },
+ ],
+ body: 'Remainder (modulo)',
+ documentation: '(IN1: ANY_INT, IN2:ANY_INT) => OUT:ANY_INT',
+ extensible: false,
+ },
+ {
+ name: 'EXPT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN1',
+ class: 'input',
+ type: { definition: 'generic-type', value: 'ANY_REAL' },
+ },
+ {
+ name: 'IN2',
+ class: 'input',
+ type: { definition: 'generic-type', value: 'ANY_REAL' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'generic-type', value: 'ANY_REAL' },
+ },
+ ],
+ body: 'Exponent',
+ documentation: '(IN1: ANY_REAL, IN2:ANY_REAL) => OUT:ANY_REAL',
+ extensible: false,
+ },
+ {
+ name: 'MOVE',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'generic-type', value: 'ANY' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'generic-type', value: 'ANY' },
+ },
+ ],
+ body: 'Assignment',
+ documentation: '(IN: ANY, OUT:ANY) => OUT:ANY',
+ extensible: false,
+ },
+ ],
+}
+
+export { Arithmetic, ArithmeticLibrarySchema }
diff --git a/src/frontend/data/library/function/bit-shift.ts b/src/frontend/data/library/function/bit-shift.ts
new file mode 100644
index 000000000..dca87bc5a
--- /dev/null
+++ b/src/frontend/data/library/function/bit-shift.ts
@@ -0,0 +1,152 @@
+import { z } from 'zod'
+
+import {
+ BaseLibraryPouSchema,
+ BaseLibraryVariableSchema,
+ baseTypeSchema,
+ genericTypeSchema,
+} from '../../../../middleware/shared/ports/plc-schemas'
+
+/** Library-level schema (name + version + paths). Not in plc-schemas so defined locally. */
+const BaseLibrarySchema = z.object({
+ name: z.string(),
+ version: z.string(),
+ author: z.string(),
+ stPath: z.string(),
+ cPath: z.string(),
+})
+
+const BitShiftVariableSchema = BaseLibraryVariableSchema.extend({
+ type: z.discriminatedUnion('definition', [
+ z.object({
+ definition: z.literal('base-type'),
+ value: baseTypeSchema,
+ }),
+ z.object({
+ definition: z.literal('generic-type'),
+ value: genericTypeSchema.keyof(),
+ }),
+ ]),
+})
+
+const BitShiftPouSchema = BaseLibraryPouSchema.extend({
+ variables: z.array(BitShiftVariableSchema),
+})
+
+const BitShiftLibrarySchema = BaseLibrarySchema.extend({
+ pous: z.array(BitShiftPouSchema),
+})
+
+type BitShiftLibrary = z.infer
+
+const BitShift: BitShiftLibrary = {
+ name: 'BitShift',
+ version: '1.0.0',
+ author: 'Autonomy Logic',
+ stPath: 'path/to/st/file',
+ cPath: 'path/to/c/file',
+ pous: [
+ {
+ name: 'SHL',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'generic-type', value: 'ANY_BIT' },
+ },
+ {
+ name: 'N',
+ class: 'input',
+ type: { definition: 'base-type', value: 'INT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'generic-type', value: 'ANY_BIT' },
+ },
+ ],
+ body: 'Shift Left',
+ documentation: '(IN: ANY_BIT, N:INT) => OUT:ANY_BIT',
+ extensible: false,
+ },
+ {
+ name: 'SHR',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'generic-type', value: 'ANY_BIT' },
+ },
+ {
+ name: 'N',
+ class: 'input',
+ type: { definition: 'base-type', value: 'INT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'generic-type', value: 'ANY_BIT' },
+ },
+ ],
+ body: 'Shift Right',
+ documentation: '(IN: ANY_BIT, N:INT) => OUT:ANY_BIT',
+ extensible: false,
+ },
+ {
+ name: 'ROR',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'generic-type', value: 'ANY_BIT' }, // need review
+ },
+ {
+ name: 'N',
+ class: 'input',
+ type: { definition: 'base-type', value: 'INT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'generic-type', value: 'ANY_BIT' }, // need review
+ },
+ ],
+ body: 'Rotate Right',
+ documentation: '(IN: ANY_NBIT, N:INT) => OUT:ANY_NBIT',
+ extensible: false,
+ },
+ {
+ name: 'ROL',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'generic-type', value: 'ANY_BIT' }, // need review
+ },
+ {
+ name: 'N',
+ class: 'input',
+ type: { definition: 'base-type', value: 'INT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'generic-type', value: 'ANY_BIT' }, // need review
+ },
+ ],
+ body: 'Rotate Left',
+ documentation: '(IN: ANY_NBIT, N:INT) => OUT:ANY_NBIT',
+ extensible: false,
+ },
+ ],
+}
+
+export { BitShift, BitShiftLibrarySchema }
diff --git a/src/frontend/data/library/function/bitwise.ts b/src/frontend/data/library/function/bitwise.ts
new file mode 100644
index 000000000..4215cbb3d
--- /dev/null
+++ b/src/frontend/data/library/function/bitwise.ts
@@ -0,0 +1,147 @@
+import { z } from 'zod'
+
+import {
+ BaseLibraryPouSchema,
+ BaseLibraryVariableSchema,
+ baseTypeSchema,
+ genericTypeSchema,
+} from '../../../../middleware/shared/ports/plc-schemas'
+
+/** Library-level schema (name + version + paths). Not in plc-schemas so defined locally. */
+const BaseLibrarySchema = z.object({
+ name: z.string(),
+ version: z.string(),
+ author: z.string(),
+ stPath: z.string(),
+ cPath: z.string(),
+})
+
+const BitwiseVariableSchema = BaseLibraryVariableSchema.extend({
+ type: z.discriminatedUnion('definition', [
+ z.object({
+ definition: z.literal('base-type'),
+ value: baseTypeSchema,
+ }),
+ z.object({
+ definition: z.literal('generic-type'),
+ value: genericTypeSchema.keyof(),
+ }),
+ ]),
+})
+
+const BitwisePouSchema = BaseLibraryPouSchema.extend({
+ variables: z.array(BitwiseVariableSchema),
+})
+
+const BitwiseLibrarySchema = BaseLibrarySchema.extend({
+ pous: z.array(BitwisePouSchema),
+})
+
+type BitwiseLibrary = z.infer
+
+const Bitwise: BitwiseLibrary = {
+ name: 'Bitwise',
+ version: '1.0.0',
+ author: 'Autonomy Logic',
+ stPath: 'path/to/st/file',
+ cPath: 'path/to/c/file',
+ pous: [
+ {
+ name: 'AND',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN1',
+ class: 'input',
+ type: { definition: 'generic-type', value: 'ANY_BIT' },
+ },
+ {
+ name: 'IN2',
+ class: 'input',
+ type: { definition: 'generic-type', value: 'ANY_BIT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'generic-type', value: 'ANY_BIT' },
+ },
+ ],
+ body: 'Bitwise AND',
+ documentation: '(IN1: ANY_BIT, IN2:ANY_BIT) => OUT:ANY_BIT',
+ extensible: true,
+ },
+ {
+ name: 'OR',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN1',
+ class: 'input',
+ type: { definition: 'generic-type', value: 'ANY_BIT' },
+ },
+ {
+ name: 'IN2',
+ class: 'input',
+ type: { definition: 'generic-type', value: 'ANY_BIT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'generic-type', value: 'ANY_BIT' },
+ },
+ ],
+ body: 'Bitwise OR',
+ documentation: '(IN1: ANY_BIT, IN2:ANY_BIT) => OUT:ANY_BIT',
+ extensible: true,
+ },
+ {
+ name: 'XOR',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN1',
+ class: 'input',
+ type: { definition: 'generic-type', value: 'ANY_BIT' },
+ },
+ {
+ name: 'IN2',
+ class: 'input',
+ type: { definition: 'generic-type', value: 'ANY_BIT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'generic-type', value: 'ANY_BIT' },
+ },
+ ],
+ body: 'Bitwise XOR',
+ documentation: '(IN1: ANY_BIT, IN2:ANY_BIT) => OUT:ANY_BIT',
+ extensible: true,
+ },
+ {
+ name: 'NOT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'generic-type', value: 'ANY_BIT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'generic-type', value: 'ANY_BIT' },
+ },
+ ],
+ body: 'Bitwise NOT',
+ documentation: '(IN: ANY_BIT) => OUT:ANY_BIT',
+ extensible: false,
+ },
+ ],
+}
+
+export { Bitwise, BitwiseLibrarySchema }
diff --git a/src/frontend/data/library/function/character-string.ts b/src/frontend/data/library/function/character-string.ts
new file mode 100644
index 000000000..1fc004242
--- /dev/null
+++ b/src/frontend/data/library/function/character-string.ts
@@ -0,0 +1,322 @@
+import { z } from 'zod'
+
+import {
+ BaseLibraryPouSchema,
+ BaseLibraryVariableSchema,
+ baseTypeSchema,
+ genericTypeSchema,
+} from '../../../../middleware/shared/ports/plc-schemas'
+
+/** Library-level schema (name + version + paths). Not in plc-schemas so defined locally. */
+const BaseLibrarySchema = z.object({
+ name: z.string(),
+ version: z.string(),
+ author: z.string(),
+ stPath: z.string(),
+ cPath: z.string(),
+})
+
+const CharacterStringVariableSchema = BaseLibraryVariableSchema.extend({
+ type: z.discriminatedUnion('definition', [
+ z.object({
+ definition: z.literal('base-type'),
+ value: baseTypeSchema,
+ }),
+ z.object({
+ definition: z.literal('generic-type'),
+ value: genericTypeSchema.keyof(),
+ }),
+ ]),
+})
+
+const CharacterStringPouSchema = BaseLibraryPouSchema.extend({
+ variables: z.array(CharacterStringVariableSchema),
+})
+
+const CharacterStringLibrarySchema = BaseLibrarySchema.extend({
+ pous: z.array(CharacterStringPouSchema),
+})
+
+type CharacterStringLibrary = z.infer
+
+const CharacterString: CharacterStringLibrary = {
+ name: 'CharacterString',
+ version: '1.0.0',
+ author: 'Autonomy Logic',
+ stPath: 'path/to/st/file',
+ cPath: 'path/to/c/file',
+ pous: [
+ {
+ name: 'LEN',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'STRING' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'INT' },
+ },
+ ],
+ body: 'Length of string',
+ documentation: '(IN:STRING) => OUT:INT',
+ extensible: false,
+ },
+ {
+ name: 'LEFT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'STRING' },
+ },
+ {
+ name: 'L',
+ class: 'input',
+ type: { definition: 'generic-type', value: 'ANY_INT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'STRING' },
+ },
+ ],
+ body: 'String left of',
+ documentation: '(IN:STRING, L:ANY_INT) => OUT:STRING',
+ extensible: false,
+ },
+ {
+ name: 'RIGHT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'STRING' },
+ },
+ {
+ name: 'L',
+ class: 'input',
+ type: { definition: 'generic-type', value: 'ANY_INT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'STRING' },
+ },
+ ],
+ body: 'String right of',
+ documentation: '(IN:STRING, L:ANY_INT) => OUT:STRING',
+ extensible: false,
+ },
+ {
+ name: 'MID',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'STRING' },
+ },
+ {
+ name: 'L',
+ class: 'input',
+ type: { definition: 'generic-type', value: 'ANY_INT' },
+ },
+ {
+ name: 'S',
+ class: 'input',
+ type: { definition: 'generic-type', value: 'ANY_INT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'STRING' },
+ },
+ ],
+ body: 'String from middle of',
+ documentation: '(IN:STRING, L:ANY_INT, S:ANY_INT) => OUT:STRING',
+ extensible: false,
+ },
+ {
+ name: 'CONCAT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN1',
+ class: 'input',
+ type: { definition: 'base-type', value: 'STRING' },
+ },
+ {
+ name: 'IN2',
+ class: 'input',
+ type: { definition: 'base-type', value: 'STRING' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'STRING' },
+ },
+ ],
+ body: 'Concatenation',
+ documentation: '(IN1:STRING, IN2:STRING) => OUT:STRING',
+ extensible: true,
+ },
+ {
+ name: 'CONCAT_DATE_TOD',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN1',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DATE' },
+ },
+ {
+ name: 'IN2',
+ class: 'input',
+ type: { definition: 'base-type', value: 'TOD' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'DT' },
+ },
+ ],
+ body: 'Time concatenation',
+ documentation: '(IN1:DATE, IN2:TOD) => OUT:DT',
+ extensible: false,
+ },
+ {
+ name: 'INSERT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN1',
+ class: 'input',
+ type: { definition: 'base-type', value: 'STRING' },
+ },
+ {
+ name: 'IN2',
+ class: 'input',
+ type: { definition: 'base-type', value: 'STRING' },
+ },
+ {
+ name: 'P',
+ class: 'input',
+ type: { definition: 'generic-type', value: 'ANY_INT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'STRING' },
+ },
+ ],
+ body: 'Insertion (into)',
+ documentation: '(IN1:STRING, IN2:STRING, P:ANY_INT) => OUT:STRING',
+ extensible: false,
+ },
+ {
+ name: 'DELETE',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'STRING' },
+ },
+ {
+ name: 'L',
+ class: 'input',
+ type: { definition: 'generic-type', value: 'ANY_INT' },
+ },
+ {
+ name: 'P',
+ class: 'input',
+ type: { definition: 'generic-type', value: 'ANY_INT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'STRING' },
+ },
+ ],
+ body: 'Deletion (within)',
+ documentation: '(IN:STRING, L:ANY_INT, P:ANY_INT) => OUT:STRING',
+ extensible: false,
+ },
+ {
+ name: 'REPLACE',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN1',
+ class: 'input',
+ type: { definition: 'base-type', value: 'STRING' },
+ },
+ {
+ name: 'IN2',
+ class: 'input',
+ type: { definition: 'base-type', value: 'STRING' },
+ },
+ {
+ name: 'L',
+ class: 'input',
+ type: { definition: 'generic-type', value: 'ANY_INT' },
+ },
+ {
+ name: 'P',
+ class: 'input',
+ type: { definition: 'generic-type', value: 'ANY_INT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'STRING' },
+ },
+ ],
+ body: 'Replacement (within)',
+ documentation: '(IN1:STRING, IN2:STRING, L:ANY_INT, P:ANY_INT) => OUT:STRING',
+ extensible: false,
+ },
+ {
+ name: 'FIND',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN1',
+ class: 'input',
+ type: { definition: 'base-type', value: 'STRING' },
+ },
+ {
+ name: 'IN2',
+ class: 'input',
+ type: { definition: 'base-type', value: 'STRING' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'INT' },
+ },
+ ],
+ body: 'Find position',
+ documentation: '(IN1:STRING, IN2:STRING) => OUT:INT',
+ extensible: false,
+ },
+ ],
+}
+
+export { CharacterString, CharacterStringLibrarySchema }
diff --git a/src/frontend/data/library/function/comparison.ts b/src/frontend/data/library/function/comparison.ts
new file mode 100644
index 000000000..2e3de2dd7
--- /dev/null
+++ b/src/frontend/data/library/function/comparison.ts
@@ -0,0 +1,202 @@
+import { z } from 'zod'
+
+import {
+ BaseLibraryPouSchema,
+ BaseLibraryVariableSchema,
+ baseTypeSchema,
+ genericTypeSchema,
+} from '../../../../middleware/shared/ports/plc-schemas'
+
+/** Library-level schema (name + version + paths). Not in plc-schemas so defined locally. */
+const BaseLibrarySchema = z.object({
+ name: z.string(),
+ version: z.string(),
+ author: z.string(),
+ stPath: z.string(),
+ cPath: z.string(),
+})
+
+const ComparisonVariableSchema = BaseLibraryVariableSchema.extend({
+ type: z.discriminatedUnion('definition', [
+ z.object({
+ definition: z.literal('base-type'),
+ value: baseTypeSchema,
+ }),
+ z.object({
+ definition: z.literal('generic-type'),
+ value: genericTypeSchema.keyof(),
+ }),
+ ]),
+})
+
+const ComparisonPouSchema = BaseLibraryPouSchema.extend({
+ variables: z.array(ComparisonVariableSchema),
+})
+
+const ComparisonLibrarySchema = BaseLibrarySchema.extend({
+ pous: z.array(ComparisonPouSchema),
+})
+
+type ComparisonLibrary = z.infer
+
+const Comparison: ComparisonLibrary = {
+ name: 'Comparison',
+ version: '1.0.0',
+ author: 'Autonomy Logic',
+ stPath: 'path/to/st/file',
+ cPath: 'path/to/c/file',
+ pous: [
+ {
+ name: 'GT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN1',
+ class: 'input',
+ type: { definition: 'generic-type', value: 'ANY' },
+ },
+ {
+ name: 'IN2',
+ class: 'input',
+ type: { definition: 'generic-type', value: 'ANY' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'BOOL' },
+ },
+ ],
+ body: 'Greater Than',
+ documentation: '(IN1: ANY, IN2: ANY) => OUT:BOOL',
+ extensible: true,
+ },
+ {
+ name: 'GE',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN1',
+ class: 'input',
+ type: { definition: 'generic-type', value: 'ANY' },
+ },
+ {
+ name: 'IN2',
+ class: 'input',
+ type: { definition: 'generic-type', value: 'ANY' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'BOOL' },
+ },
+ ],
+ body: 'Greater Than or equal to',
+ documentation: '(IN1: ANY, IN2: ANY) => OUT:BOOL',
+ extensible: true,
+ },
+ {
+ name: 'EQ',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN1',
+ class: 'input',
+ type: { definition: 'generic-type', value: 'ANY' },
+ },
+ {
+ name: 'IN2',
+ class: 'input',
+ type: { definition: 'generic-type', value: 'ANY' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'BOOL' },
+ },
+ ],
+ body: 'Equal to',
+ documentation: '(IN1: ANY, IN2: ANY) => OUT:BOOL',
+ extensible: true,
+ },
+ {
+ name: 'LT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN1',
+ class: 'input',
+ type: { definition: 'generic-type', value: 'ANY' },
+ },
+ {
+ name: 'IN2',
+ class: 'input',
+ type: { definition: 'generic-type', value: 'ANY' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'BOOL' },
+ },
+ ],
+ body: 'Less Than',
+ documentation: '(IN1: ANY, IN2: ANY) => OUT:BOOL',
+ extensible: true,
+ },
+ {
+ name: 'LE',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN1',
+ class: 'input',
+ type: { definition: 'generic-type', value: 'ANY' },
+ },
+ {
+ name: 'IN2',
+ class: 'input',
+ type: { definition: 'generic-type', value: 'ANY' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'BOOL' },
+ },
+ ],
+ body: 'Less Than or equal to',
+ documentation: '(IN1: ANY, IN2: ANY) => OUT:BOOL',
+ extensible: true,
+ },
+ {
+ name: 'NE',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN1',
+ class: 'input',
+ type: { definition: 'generic-type', value: 'ANY' },
+ },
+ {
+ name: 'IN2',
+ class: 'input',
+ type: { definition: 'generic-type', value: 'ANY' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'BOOL' },
+ },
+ ],
+ body: 'Not Equal to',
+ documentation: '(IN1: ANY, IN2: ANY) => OUT:BOOL',
+ extensible: false,
+ },
+ ],
+}
+
+export { Comparison, ComparisonLibrarySchema }
diff --git a/src/renderer/data/library/function/index.ts b/src/frontend/data/library/function/index.ts
similarity index 100%
rename from src/renderer/data/library/function/index.ts
rename to src/frontend/data/library/function/index.ts
diff --git a/src/frontend/data/library/function/numerical.ts b/src/frontend/data/library/function/numerical.ts
new file mode 100644
index 000000000..e98d19794
--- /dev/null
+++ b/src/frontend/data/library/function/numerical.ts
@@ -0,0 +1,272 @@
+import { z } from 'zod'
+
+import {
+ BaseLibraryPouSchema,
+ BaseLibraryVariableSchema,
+ baseTypeSchema,
+ genericTypeSchema,
+} from '../../../../middleware/shared/ports/plc-schemas'
+
+/** Library-level schema (name + version + paths). Not in plc-schemas so defined locally. */
+const BaseLibrarySchema = z.object({
+ name: z.string(),
+ version: z.string(),
+ author: z.string(),
+ stPath: z.string(),
+ cPath: z.string(),
+})
+
+const NumericalVariableSchema = BaseLibraryVariableSchema.extend({
+ type: z.discriminatedUnion('definition', [
+ z.object({
+ definition: z.literal('base-type'),
+ value: baseTypeSchema,
+ }),
+ z.object({
+ definition: z.literal('generic-type'),
+ value: genericTypeSchema.keyof(),
+ }),
+ ]),
+})
+
+const NumericalPouSchema = BaseLibraryPouSchema.extend({
+ variables: z.array(NumericalVariableSchema),
+})
+
+const NumericalLibrarySchema = BaseLibrarySchema.extend({
+ pous: z.array(NumericalPouSchema),
+})
+
+type NumericalLibrary = z.infer
+
+const Numerical: NumericalLibrary = {
+ name: 'Numerical',
+ version: '1.0.0',
+ author: 'Autonomy Logic',
+ stPath: 'path/to/st/file',
+ cPath: 'path/to/c/file',
+ pous: [
+ {
+ name: 'ABS',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'generic-type', value: 'ANY_NUM' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'generic-type', value: 'ANY_NUM' },
+ },
+ ],
+ body: 'Absolute value',
+ documentation: '(IN:ANY_NUM) => OUT:ANY_NUM',
+ extensible: false,
+ },
+ {
+ name: 'SQRT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'generic-type', value: 'ANY_REAL' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'generic-type', value: 'ANY_REAL' },
+ },
+ ],
+ body: 'Square root (base 2)',
+ documentation: '(IN:ANY_REAL) => OUT:ANY_REAL',
+ extensible: false,
+ },
+ {
+ name: 'LN',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'generic-type', value: 'ANY_REAL' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'generic-type', value: 'ANY_REAL' },
+ },
+ ],
+ body: 'Arc tangent',
+ documentation: '(IN:ANY_REAL) => OUT:ANY_REAL',
+ extensible: false,
+ },
+ {
+ name: 'LOG',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'generic-type', value: 'ANY_REAL' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'generic-type', value: 'ANY_REAL' },
+ },
+ ],
+ body: 'Logarithm to base 10',
+ documentation: '(IN:ANY_REAL) => OUT:ANY_REAL',
+ extensible: false,
+ },
+ {
+ name: 'EXP',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'generic-type', value: 'ANY_REAL' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'generic-type', value: 'ANY_REAL' },
+ },
+ ],
+ body: 'Exponentiation',
+ documentation: '(IN:ANY_REAL) => OUT:ANY_REAL',
+ extensible: false,
+ },
+ {
+ name: 'SIN',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'generic-type', value: 'ANY_REAL' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'generic-type', value: 'ANY_REAL' },
+ },
+ ],
+ body: 'Sine',
+ documentation: '(IN:ANY_REAL) => OUT:ANY_REAL',
+ extensible: false,
+ },
+ {
+ name: 'COS',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'generic-type', value: 'ANY_REAL' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'generic-type', value: 'ANY_REAL' },
+ },
+ ],
+ body: 'Cosine',
+ documentation: '(IN:ANY_REAL) => OUT:ANY_REAL',
+ extensible: false,
+ },
+ {
+ name: 'TAN',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'generic-type', value: 'ANY_REAL' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'generic-type', value: 'ANY_REAL' },
+ },
+ ],
+ body: 'Tangent',
+ documentation: '(IN:ANY_REAL) => OUT:ANY_REAL',
+ extensible: false,
+ },
+ {
+ name: 'ASIN',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'generic-type', value: 'ANY_REAL' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'generic-type', value: 'ANY_REAL' },
+ },
+ ],
+ body: 'Arc sine',
+ documentation: '(IN:ANY_REAL) => OUT:ANY_REAL',
+ extensible: false,
+ },
+ {
+ name: 'ACOS',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'generic-type', value: 'ANY_REAL' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'generic-type', value: 'ANY_REAL' },
+ },
+ ],
+ body: 'Arc cosine',
+ documentation: '(IN:ANY_REAL) => OUT:ANY_REAL',
+ extensible: false,
+ },
+ {
+ name: 'ATAN',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'generic-type', value: 'ANY_REAL' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'generic-type', value: 'ANY_REAL' },
+ },
+ ],
+ body: 'Arc tangent',
+ documentation: '(IN:ANY_REAL) => OUT:ANY_REAL',
+ extensible: false,
+ },
+ ],
+}
+
+export { Numerical, NumericalLibrarySchema }
diff --git a/src/frontend/data/library/function/selection.ts b/src/frontend/data/library/function/selection.ts
new file mode 100644
index 000000000..20e1a2466
--- /dev/null
+++ b/src/frontend/data/library/function/selection.ts
@@ -0,0 +1,192 @@
+import { z } from 'zod'
+
+import {
+ BaseLibraryPouSchema,
+ BaseLibraryVariableSchema,
+ baseTypeSchema,
+ genericTypeSchema,
+} from '../../../../middleware/shared/ports/plc-schemas'
+
+/** Library-level schema (name + version + paths). Not in plc-schemas so defined locally. */
+const BaseLibrarySchema = z.object({
+ name: z.string(),
+ version: z.string(),
+ author: z.string(),
+ stPath: z.string(),
+ cPath: z.string(),
+})
+
+const SelectionVariableSchema = BaseLibraryVariableSchema.extend({
+ type: z.discriminatedUnion('definition', [
+ z.object({
+ definition: z.literal('base-type'),
+ value: baseTypeSchema,
+ }),
+ z.object({
+ definition: z.literal('generic-type'),
+ value: genericTypeSchema.keyof(),
+ }),
+ ]),
+})
+
+const SelectionPouSchema = BaseLibraryPouSchema.extend({
+ variables: z.array(SelectionVariableSchema),
+})
+
+const SelectionLibrarySchema = BaseLibrarySchema.extend({
+ pous: z.array(SelectionPouSchema),
+})
+
+type SelectionLibrary = z.infer
+
+const Selection: SelectionLibrary = {
+ name: 'Selection',
+ version: '1.0.0',
+ author: 'Autonomy Logic',
+ stPath: 'path/to/st/file',
+ cPath: 'path/to/c/file',
+ pous: [
+ {
+ name: 'SEL',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'G',
+ class: 'input',
+ type: { definition: 'base-type', value: 'BOOL' },
+ },
+ {
+ name: 'IN0',
+ class: 'input',
+ type: { definition: 'generic-type', value: 'ANY' },
+ },
+ {
+ name: 'IN1',
+ class: 'input',
+ type: { definition: 'generic-type', value: 'ANY' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'generic-type', value: 'ANY' },
+ },
+ ],
+ body: 'Binary selection (1 of 2)',
+ documentation: '(G:BOOL, IN0:ANY, IN1:ANY) => OUT:ANY',
+ extensible: false,
+ },
+ {
+ name: 'MAX',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN1',
+ class: 'input',
+ type: { definition: 'generic-type', value: 'ANY' },
+ },
+ {
+ name: 'IN2',
+ class: 'input',
+ type: { definition: 'generic-type', value: 'ANY' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'generic-type', value: 'ANY' },
+ },
+ ],
+ body: 'Maximum',
+ documentation: '(IN1:ANY, IN2:ANY) => OUT:ANY',
+ extensible: true,
+ },
+ {
+ name: 'MIN',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN1',
+ class: 'input',
+ type: { definition: 'generic-type', value: 'ANY' },
+ },
+ {
+ name: 'IN2',
+ class: 'input',
+ type: { definition: 'generic-type', value: 'ANY' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'generic-type', value: 'ANY' },
+ },
+ ],
+ body: 'Minimum',
+ documentation: '(IN1:ANY, IN2:ANY) => OUT:ANY',
+ extensible: true,
+ },
+ {
+ name: 'LIMIT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'MN',
+ class: 'input',
+ type: { definition: 'generic-type', value: 'ANY' },
+ },
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'generic-type', value: 'ANY' },
+ },
+ {
+ name: 'MX',
+ class: 'input',
+ type: { definition: 'generic-type', value: 'ANY' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'generic-type', value: 'ANY' },
+ },
+ ],
+ body: 'Limitation',
+ documentation: '(MN:ANY, IN:ANY, MX:ANY) => OUT:ANY',
+ extensible: false,
+ },
+ {
+ name: 'MUX',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'K',
+ class: 'input',
+ type: { definition: 'base-type', value: 'INT' },
+ },
+ {
+ name: 'IN0',
+ class: 'input',
+ type: { definition: 'generic-type', value: 'ANY' },
+ },
+ {
+ name: 'IN1',
+ class: 'input',
+ type: { definition: 'generic-type', value: 'ANY' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'generic-type', value: 'ANY' },
+ },
+ ],
+ body: 'Multiplexer (select 1 of N)',
+ documentation: '(K:INT, IN0:ANY, IN1:ANY) => OUT:ANY',
+ extensible: true,
+ },
+ ],
+}
+
+export { Selection, SelectionLibrarySchema }
diff --git a/src/frontend/data/library/function/time.ts b/src/frontend/data/library/function/time.ts
new file mode 100644
index 000000000..47b0fd8cd
--- /dev/null
+++ b/src/frontend/data/library/function/time.ts
@@ -0,0 +1,327 @@
+import { z } from 'zod'
+
+import {
+ BaseLibraryPouSchema,
+ BaseLibraryVariableSchema,
+ baseTypeSchema,
+ genericTypeSchema,
+} from '../../../../middleware/shared/ports/plc-schemas'
+
+/** Library-level schema (name + version + paths). Not in plc-schemas so defined locally. */
+const BaseLibrarySchema = z.object({
+ name: z.string(),
+ version: z.string(),
+ author: z.string(),
+ stPath: z.string(),
+ cPath: z.string(),
+})
+
+const TimeVariableSchema = BaseLibraryVariableSchema.extend({
+ type: z.discriminatedUnion('definition', [
+ z.object({
+ definition: z.literal('base-type'),
+ value: baseTypeSchema,
+ }),
+ z.object({
+ definition: z.literal('generic-type'),
+ value: genericTypeSchema.keyof(),
+ }),
+ ]),
+})
+
+const TimePouSchema = BaseLibraryPouSchema.extend({
+ variables: z.array(TimeVariableSchema),
+})
+
+const TimeLibrarySchema = BaseLibrarySchema.extend({
+ pous: z.array(TimePouSchema),
+})
+
+type TimeLibrary = z.infer
+
+const Time: TimeLibrary = {
+ name: 'Time',
+ version: '1.0.0',
+ author: 'Autonomy Logic',
+ stPath: 'path/to/st/file',
+ cPath: 'path/to/c/file',
+ pous: [
+ {
+ name: 'ADD_TIME',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN1',
+ class: 'input',
+ type: { definition: 'base-type', value: 'TIME' },
+ },
+ {
+ name: 'IN2',
+ class: 'input',
+ type: { definition: 'base-type', value: 'TIME' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'TIME' },
+ },
+ ],
+ body: 'Time addition',
+ documentation: '(IN1:TIME, IN2:TIME) => OUT:TIME',
+ extensible: false,
+ },
+ {
+ name: 'ADD_TOD_TIME',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN1',
+ class: 'input',
+ type: { definition: 'base-type', value: 'TOD' },
+ },
+ {
+ name: 'IN2',
+ class: 'input',
+ type: { definition: 'base-type', value: 'TIME' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'TOD' },
+ },
+ ],
+ body: 'Time-of-day addition',
+ documentation: '(IN1:TOD, IN2:TIME) => OUT:TOD',
+ extensible: false,
+ },
+ {
+ name: 'ADD_DT_TIME',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN1',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DT' },
+ },
+ {
+ name: 'IN2',
+ class: 'input',
+ type: { definition: 'base-type', value: 'TIME' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'DT' },
+ },
+ ],
+ body: 'Date addition',
+ documentation: '(IN1:DT, IN2:TIME) => OUT:DT',
+ extensible: false,
+ },
+ {
+ name: 'MUL_TIME',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN1',
+ class: 'input',
+ type: { definition: 'base-type', value: 'TIME' },
+ },
+ {
+ name: 'IN2',
+ class: 'input',
+ type: { definition: 'generic-type', value: 'ANY_NUM' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'TIME' },
+ },
+ ],
+ body: 'Time multiplication',
+ documentation: '(IN1:TIME, IN2:ANY_NUM) => OUT:TIME',
+ extensible: false,
+ },
+ {
+ name: 'SUB_TIME',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN1',
+ class: 'input',
+ type: { definition: 'base-type', value: 'TIME' },
+ },
+ {
+ name: 'IN2',
+ class: 'input',
+ type: { definition: 'base-type', value: 'TIME' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'TIME' },
+ },
+ ],
+ body: 'Time subtraction',
+ documentation: '(IN1:TIME, IN2:TIME) => OUT:TIME',
+ extensible: false,
+ },
+ {
+ name: 'SUB_DATE',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN1',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DATE' },
+ },
+ {
+ name: 'IN2',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DATE' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'TIME' },
+ },
+ ],
+ body: 'Date subtraction',
+ documentation: '(IN1:DATE, IN2:DATE) => OUT:TIME',
+ extensible: false,
+ },
+ {
+ name: 'SUB_TOD_TIME',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN1',
+ class: 'input',
+ type: { definition: 'base-type', value: 'TOD' },
+ },
+ {
+ name: 'IN2',
+ class: 'input',
+ type: { definition: 'base-type', value: 'TIME' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'TOD' },
+ },
+ ],
+ body: 'Time-of-day subtraction',
+ documentation: '(IN1:TOD, IN2:TIME) => OUT:TOD',
+ extensible: false,
+ },
+ {
+ name: 'SUB_TOD',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN1',
+ class: 'input',
+ type: { definition: 'base-type', value: 'TOD' },
+ },
+ {
+ name: 'IN2',
+ class: 'input',
+ type: { definition: 'base-type', value: 'TOD' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'TIME' },
+ },
+ ],
+ body: 'Time-of-day subtraction',
+ documentation: '(IN1:TOD, IN2:TOD) => OUT:TIME',
+ extensible: false,
+ },
+ {
+ name: 'SUB_DT_TIME',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN1',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DT' },
+ },
+ {
+ name: 'IN2',
+ class: 'input',
+ type: { definition: 'base-type', value: 'TIME' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'DT' },
+ },
+ ],
+ body: 'Date and time subtraction',
+ documentation: '(IN1:DT, IN2:TIME) => OUT:DT',
+ extensible: false,
+ },
+ {
+ name: 'SUB_DT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN1',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DT' },
+ },
+ {
+ name: 'IN2',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'TIME' },
+ },
+ ],
+ body: 'Date and time subtraction',
+ documentation: '(IN1:DT, IN2:DT) => OUT:TIME',
+ extensible: false,
+ },
+ {
+ name: 'DIV_TIME',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN1',
+ class: 'input',
+ type: { definition: 'base-type', value: 'TIME' },
+ },
+ {
+ name: 'IN2',
+ class: 'input',
+ type: { definition: 'generic-type', value: 'ANY_NUM' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'TIME' },
+ },
+ ],
+ body: 'Time division',
+ documentation: '(IN1:TIME, IN2:ANY_NUM) => OUT:TIME',
+ extensible: false,
+ },
+ ],
+}
+
+export { Time, TimeLibrarySchema }
diff --git a/src/frontend/data/library/function/type-conversion.ts b/src/frontend/data/library/function/type-conversion.ts
new file mode 100644
index 000000000..69a9af3fa
--- /dev/null
+++ b/src/frontend/data/library/function/type-conversion.ts
@@ -0,0 +1,7812 @@
+import { z } from 'zod'
+
+import {
+ BaseLibraryPouSchema,
+ BaseLibraryVariableSchema,
+ baseTypeSchema,
+ genericTypeSchema,
+} from '../../../../middleware/shared/ports/plc-schemas'
+
+/** Library-level schema (name + version + paths). Not in plc-schemas so defined locally. */
+const BaseLibrarySchema = z.object({
+ name: z.string(),
+ version: z.string(),
+ author: z.string(),
+ stPath: z.string(),
+ cPath: z.string(),
+})
+
+const TypeConversionVariableSchema = BaseLibraryVariableSchema.extend({
+ type: z.discriminatedUnion('definition', [
+ z.object({
+ definition: z.literal('base-type'),
+ value: baseTypeSchema,
+ }),
+ z.object({
+ definition: z.literal('generic-type'),
+ value: genericTypeSchema.keyof(),
+ }),
+ ]),
+})
+
+const TypeConversionPouSchema = BaseLibraryPouSchema.extend({
+ variables: z.array(TypeConversionVariableSchema),
+})
+
+const TypeConversionLibrarySchema = BaseLibrarySchema.extend({
+ pous: z.array(TypeConversionPouSchema),
+})
+
+type TypeConversionLibrary = z.infer
+
+const TypeConversion: TypeConversionLibrary = {
+ name: 'TypeConversion',
+ version: '1.0.0',
+ author: 'Autonomy Logic',
+ stPath: 'path/to/st/file',
+ cPath: 'path/to/c/file',
+ pous: [
+ {
+ name: 'BOOL_TO_SINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'BOOL' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'SINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: BOOL) => OUT: SINT',
+ extensible: false,
+ },
+ {
+ name: 'BOOL_TO_INT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'BOOL' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'INT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: BOOL) => OUT: INT',
+ extensible: false,
+ },
+ {
+ name: 'BOOL_TO_DINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'BOOL' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'DINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: BOOL) => OUT: DINT',
+ extensible: false,
+ },
+ {
+ name: 'BOOL_TO_LINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'BOOL' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'LINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: BOOL) => OUT: LINT',
+ extensible: false,
+ },
+ {
+ name: 'BOOL_TO_USINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'BOOL' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'USINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: BOOL) => OUT: USINT',
+ extensible: false,
+ },
+ {
+ name: 'BOOL_TO_UINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'BOOL' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'UINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: BOOL) => OUT: UINT',
+ extensible: false,
+ },
+ {
+ name: 'BOOL_TO_UDINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'BOOL' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'UDINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: BOOL) => OUT: UDINT',
+ extensible: false,
+ },
+ {
+ name: 'BOOL_TO_ULINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'BOOL' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'ULINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: BOOL) => OUT: ULINT',
+ extensible: false,
+ },
+ {
+ name: 'BOOL_TO_REAL',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'BOOL' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'REAL' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: BOOL) => OUT: REAL',
+ extensible: false,
+ },
+ {
+ name: 'BOOL_TO_LREAL',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'BOOL' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'LREAL' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: BOOL) => OUT: LREAL',
+ extensible: false,
+ },
+ {
+ name: 'BOOL_TO_TIME',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'BOOL' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'TIME' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: BOOL) => OUT: TIME',
+ extensible: false,
+ },
+ {
+ name: 'BOOL_TO_DATE',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'BOOL' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'DATE' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: BOOL) => OUT: DATE',
+ extensible: false,
+ },
+ {
+ name: 'BOOL_TO_TOD',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'BOOL' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'TOD' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: BOOL) => OUT: TOD',
+ extensible: false,
+ },
+ {
+ name: 'BOOL_TO_DT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'BOOL' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'DT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: BOOL) => OUT: DT',
+ extensible: false,
+ },
+ {
+ name: 'BOOL_TO_STRING',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'BOOL' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'STRING' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: BOOL) => OUT: STRING',
+ extensible: false,
+ },
+ {
+ name: 'BOOL_TO_BYTE',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'BOOL' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'BYTE' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: BOOL) => OUT: BYTE',
+ extensible: false,
+ },
+ {
+ name: 'BOOL_TO_WORD',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'BOOL' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'WORD' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: BOOL) => OUT: WORD',
+ extensible: false,
+ },
+ {
+ name: 'BOOL_TO_DWORD',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'BOOL' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'DWORD' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: BOOL) => OUT: DWORD',
+ extensible: false,
+ },
+ {
+ name: 'BOOL_TO_LWORD',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'BOOL' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'LWORD' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: BOOL) => OUT: LWORD',
+ extensible: false,
+ },
+ {
+ name: 'SINT_TO_BOOL',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'SINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'BOOL' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: SINT) => OUT: BOOL',
+ extensible: false,
+ },
+ {
+ name: 'SINT_TO_INT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'SINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'INT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: SINT) => OUT: INT',
+ extensible: false,
+ },
+ {
+ name: 'SINT_TO_DINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'SINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'DINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: SINT) => OUT: DINT',
+ extensible: false,
+ },
+ {
+ name: 'SINT_TO_LINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'SINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'LINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: SINT) => OUT: LINT',
+ extensible: false,
+ },
+ {
+ name: 'SINT_TO_USINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'SINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'USINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: SINT) => OUT: USINT',
+ extensible: false,
+ },
+ {
+ name: 'SINT_TO_UINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'SINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'UINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: SINT) => OUT: UINT',
+ extensible: false,
+ },
+ {
+ name: 'SINT_TO_UDINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'SINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'UDINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: SINT) => OUT: UDINT',
+ extensible: false,
+ },
+ {
+ name: 'SINT_TO_ULINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'SINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'ULINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: SINT) => OUT: ULINT',
+ extensible: false,
+ },
+ {
+ name: 'SINT_TO_REAL',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'SINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'REAL' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: SINT) => OUT: REAL',
+ extensible: false,
+ },
+ {
+ name: 'SINT_TO_LREAL',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'SINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'LREAL' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: SINT) => OUT: LREAL',
+ extensible: false,
+ },
+ {
+ name: 'SINT_TO_TIME',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'SINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'TIME' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: SINT) => OUT: TIME',
+ extensible: false,
+ },
+ {
+ name: 'SINT_TO_DATE',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'SINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'DATE' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: SINT) => OUT: DATE',
+ extensible: false,
+ },
+ {
+ name: 'SINT_TO_TOD',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'SINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'TOD' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: SINT) => OUT: TOD',
+ extensible: false,
+ },
+ {
+ name: 'SINT_TO_DT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'SINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'DT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: SINT) => OUT: DT',
+ extensible: false,
+ },
+ {
+ name: 'SINT_TO_STRING',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'SINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'STRING' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: SINT) => OUT: STRING',
+ extensible: false,
+ },
+ {
+ name: 'SINT_TO_BYTE',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'SINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'BYTE' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: SINT) => OUT: BYTE',
+ extensible: false,
+ },
+ {
+ name: 'SINT_TO_WORD',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'SINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'WORD' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: SINT) => OUT: WORD',
+ extensible: false,
+ },
+ {
+ name: 'SINT_TO_DWORD',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'SINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'DWORD' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: SINT) => OUT: DWORD',
+ extensible: false,
+ },
+ {
+ name: 'SINT_TO_LWORD',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'SINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'LWORD' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: SINT) => OUT: LWORD',
+ extensible: false,
+ },
+ {
+ name: 'INT_TO_BOOL',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'INT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'BOOL' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: INT) => OUT: BOOL',
+ extensible: false,
+ },
+ {
+ name: 'INT_TO_SINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'INT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'SINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: INT) => OUT: SINT',
+ extensible: false,
+ },
+ {
+ name: 'INT_TO_DINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'INT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'DINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: INT) => OUT: DINT',
+ extensible: false,
+ },
+ {
+ name: 'INT_TO_LINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'INT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'LINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: INT) => OUT: LINT',
+ extensible: false,
+ },
+ {
+ name: 'INT_TO_USINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'INT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'USINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: INT) => OUT: USINT',
+ extensible: false,
+ },
+ {
+ name: 'INT_TO_UINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'INT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'UINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: INT) => OUT: UINT',
+ extensible: false,
+ },
+ {
+ name: 'INT_TO_UDINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'INT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'UDINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: INT) => OUT: UDINT',
+ extensible: false,
+ },
+ {
+ name: 'INT_TO_ULINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'INT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'ULINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: INT) => OUT: ULINT',
+ extensible: false,
+ },
+ {
+ name: 'INT_TO_REAL',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'INT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'REAL' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: INT) => OUT: REAL',
+ extensible: false,
+ },
+ {
+ name: 'INT_TO_LREAL',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'INT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'LREAL' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: INT) => OUT: LREAL',
+ extensible: false,
+ },
+ {
+ name: 'INT_TO_TIME',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'INT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'TIME' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: INT) => OUT: TIME',
+ extensible: false,
+ },
+ {
+ name: 'INT_TO_DATE',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'INT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'DATE' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: INT) => OUT: DATE',
+ extensible: false,
+ },
+ {
+ name: 'INT_TO_TOD',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'INT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'TOD' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: INT) => OUT: TOD',
+ extensible: false,
+ },
+ {
+ name: 'INT_TO_DT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'INT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'DT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: INT) => OUT: DT',
+ extensible: false,
+ },
+ {
+ name: 'INT_TO_STRING',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'INT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'STRING' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: INT) => OUT: STRING',
+ extensible: false,
+ },
+ {
+ name: 'INT_TO_BYTE',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'INT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'BYTE' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: INT) => OUT: BYTE',
+ extensible: false,
+ },
+ {
+ name: 'INT_TO_WORD',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'INT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'WORD' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: INT) => OUT: WORD',
+ extensible: false,
+ },
+ {
+ name: 'INT_TO_DWORD',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'INT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'DWORD' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: INT) => OUT: DWORD',
+ extensible: false,
+ },
+ {
+ name: 'INT_TO_LWORD',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'INT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'LWORD' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: INT) => OUT: LWORD',
+ extensible: false,
+ },
+ {
+ name: 'DINT_TO_BOOL',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'BOOL' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: DINT) => OUT: BOOL',
+ extensible: false,
+ },
+ {
+ name: 'DINT_TO_SINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'SINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: DINT) => OUT: SINT',
+ extensible: false,
+ },
+ {
+ name: 'DINT_TO_INT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'INT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: DINT) => OUT: INT',
+ extensible: false,
+ },
+ {
+ name: 'DINT_TO_LINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'LINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: DINT) => OUT: LINT',
+ extensible: false,
+ },
+ {
+ name: 'DINT_TO_USINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'USINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: DINT) => OUT: USINT',
+ extensible: false,
+ },
+ {
+ name: 'DINT_TO_UINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'UINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: DINT) => OUT: UINT',
+ extensible: false,
+ },
+ {
+ name: 'DINT_TO_UDINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'UDINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: DINT) => OUT: UDINT',
+ extensible: false,
+ },
+ {
+ name: 'DINT_TO_ULINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'ULINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: DINT) => OUT: ULINT',
+ extensible: false,
+ },
+ {
+ name: 'DINT_TO_REAL',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'REAL' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: DINT) => OUT: REAL',
+ extensible: false,
+ },
+ {
+ name: 'DINT_TO_LREAL',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'LREAL' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: DINT) => OUT: LREAL',
+ extensible: false,
+ },
+ {
+ name: 'DINT_TO_TIME',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'TIME' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: DINT) => OUT: TIME',
+ extensible: false,
+ },
+ {
+ name: 'DINT_TO_DATE',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'DATE' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: DINT) => OUT: DATE',
+ extensible: false,
+ },
+ {
+ name: 'DINT_TO_TOD',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'TOD' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: DINT) => OUT: TOD',
+ extensible: false,
+ },
+ {
+ name: 'DINT_TO_DT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'DT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: DINT) => OUT: DT',
+ extensible: false,
+ },
+ {
+ name: 'DINT_TO_STRING',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'STRING' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: DINT) => OUT: STRING',
+ extensible: false,
+ },
+ {
+ name: 'DINT_TO_BYTE',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'BYTE' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: DINT) => OUT: BYTE',
+ extensible: false,
+ },
+ {
+ name: 'DINT_TO_WORD',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'WORD' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: DINT) => OUT: WORD',
+ extensible: false,
+ },
+ {
+ name: 'DINT_TO_DWORD',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'DWORD' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: DINT) => OUT: DWORD',
+ extensible: false,
+ },
+ {
+ name: 'DINT_TO_LWORD',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'LWORD' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: DINT) => OUT: LWORD',
+ extensible: false,
+ },
+ {
+ name: 'LINT_TO_BOOL',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'LINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'BOOL' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: LINT) => OUT: BOOL',
+ extensible: false,
+ },
+ {
+ name: 'LINT_TO_SINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'LINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'SINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: LINT) => OUT: SINT',
+ extensible: false,
+ },
+ {
+ name: 'LINT_TO_INT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'LINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'INT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: LINT) => OUT: INT',
+ extensible: false,
+ },
+ {
+ name: 'LINT_TO_DINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'LINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'DINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: LINT) => OUT: DINT',
+ extensible: false,
+ },
+ {
+ name: 'LINT_TO_USINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'LINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'USINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: LINT) => OUT: USINT',
+ extensible: false,
+ },
+ {
+ name: 'LINT_TO_UINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'LINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'UINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: LINT) => OUT: UINT',
+ extensible: false,
+ },
+ {
+ name: 'LINT_TO_UDINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'LINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'UDINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: LINT) => OUT: UDINT',
+ extensible: false,
+ },
+ {
+ name: 'LINT_TO_ULINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'LINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'ULINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: LINT) => OUT: ULINT',
+ extensible: false,
+ },
+ {
+ name: 'LINT_TO_REAL',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'LINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'REAL' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: LINT) => OUT: REAL',
+ extensible: false,
+ },
+ {
+ name: 'LINT_TO_LREAL',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'LINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'LREAL' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: LINT) => OUT: LREAL',
+ extensible: false,
+ },
+ {
+ name: 'LINT_TO_TIME',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'LINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'TIME' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: LINT) => OUT: TIME',
+ extensible: false,
+ },
+ {
+ name: 'LINT_TO_DATE',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'LINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'DATE' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: LINT) => OUT: DATE',
+ extensible: false,
+ },
+ {
+ name: 'LINT_TO_TOD',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'LINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'TOD' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: LINT) => OUT: TOD',
+ extensible: false,
+ },
+ {
+ name: 'LINT_TO_DT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'LINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'DT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: LINT) => OUT: DT',
+ extensible: false,
+ },
+ {
+ name: 'LINT_TO_STRING',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'LINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'STRING' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: LINT) => OUT: STRING',
+ extensible: false,
+ },
+ {
+ name: 'LINT_TO_BYTE',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'LINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'BYTE' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: LINT) => OUT: BYTE',
+ extensible: false,
+ },
+ {
+ name: 'LINT_TO_WORD',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'LINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'WORD' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: LINT) => OUT: WORD',
+ extensible: false,
+ },
+ {
+ name: 'LINT_TO_DWORD',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'LINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'DWORD' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: LINT) => OUT: DWORD',
+ extensible: false,
+ },
+ {
+ name: 'LINT_TO_LWORD',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'LINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'LWORD' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: LINT) => OUT: LWORD',
+ extensible: false,
+ },
+ {
+ name: 'USINT_TO_BOOL',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'USINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'BOOL' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: USINT) => OUT: BOOL',
+ extensible: false,
+ },
+ {
+ name: 'USINT_TO_SINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'USINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'SINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: USINT) => OUT: SINT',
+ extensible: false,
+ },
+ {
+ name: 'USINT_TO_INT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'USINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'INT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: USINT) => OUT: INT',
+ extensible: false,
+ },
+ {
+ name: 'USINT_TO_DINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'USINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'DINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: USINT) => OUT: DINT',
+ extensible: false,
+ },
+ {
+ name: 'USINT_TO_LINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'USINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'LINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: USINT) => OUT: LINT',
+ extensible: false,
+ },
+ {
+ name: 'USINT_TO_UINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'USINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'UINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: USINT) => OUT: UINT',
+ extensible: false,
+ },
+ {
+ name: 'USINT_TO_UDINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'USINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'UDINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: USINT) => OUT: UDINT',
+ extensible: false,
+ },
+ {
+ name: 'USINT_TO_ULINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'USINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'ULINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: USINT) => OUT: ULINT',
+ extensible: false,
+ },
+ {
+ name: 'USINT_TO_REAL',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'USINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'REAL' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: USINT) => OUT: REAL',
+ extensible: false,
+ },
+ {
+ name: 'USINT_TO_LREAL',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'USINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'LREAL' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: USINT) => OUT: LREAL',
+ extensible: false,
+ },
+ {
+ name: 'USINT_TO_TIME',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'USINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'TIME' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: USINT) => OUT: TIME',
+ extensible: false,
+ },
+ {
+ name: 'USINT_TO_DATE',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'USINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'DATE' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: USINT) => OUT: DATE',
+ extensible: false,
+ },
+ {
+ name: 'USINT_TO_TOD',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'USINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'TOD' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: USINT) => OUT: TOD',
+ extensible: false,
+ },
+ {
+ name: 'USINT_TO_DT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'USINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'DT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: USINT) => OUT: DT',
+ extensible: false,
+ },
+ {
+ name: 'USINT_TO_STRING',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'USINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'STRING' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: USINT) => OUT: STRING',
+ extensible: false,
+ },
+ {
+ name: 'USINT_TO_BYTE',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'USINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'BYTE' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: USINT) => OUT: BYTE',
+ extensible: false,
+ },
+ {
+ name: 'USINT_TO_WORD',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'USINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'WORD' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: USINT) => OUT: WORD',
+ extensible: false,
+ },
+ {
+ name: 'USINT_TO_DWORD',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'USINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'DWORD' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: USINT) => OUT: DWORD',
+ extensible: false,
+ },
+ {
+ name: 'USINT_TO_LWORD',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'USINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'LWORD' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: USINT) => OUT: LWORD',
+ extensible: false,
+ },
+ {
+ name: 'UINT_TO_BOOL',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'UINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'BOOL' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: UINT) => OUT: BOOL',
+ extensible: false,
+ },
+ {
+ name: 'UINT_TO_SINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'UINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'SINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: UINT) => OUT: SINT',
+ extensible: false,
+ },
+ {
+ name: 'UINT_TO_INT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'UINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'INT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: UINT) => OUT: INT',
+ extensible: false,
+ },
+ {
+ name: 'UINT_TO_DINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'UINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'DINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: UINT) => OUT: DINT',
+ extensible: false,
+ },
+ {
+ name: 'UINT_TO_LINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'UINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'LINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: UINT) => OUT: LINT',
+ extensible: false,
+ },
+ {
+ name: 'UINT_TO_USINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'UINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'USINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: UINT) => OUT: USINT',
+ extensible: false,
+ },
+ {
+ name: 'UINT_TO_UDINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'UINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'UDINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: UINT) => OUT: UDINT',
+ extensible: false,
+ },
+ {
+ name: 'UINT_TO_ULINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'UINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'ULINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: UINT) => OUT: ULINT',
+ extensible: false,
+ },
+ {
+ name: 'UINT_TO_REAL',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'UINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'REAL' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: UINT) => OUT: REAL',
+ extensible: false,
+ },
+ {
+ name: 'UINT_TO_LREAL',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'UINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'LREAL' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: UINT) => OUT: LREAL',
+ extensible: false,
+ },
+ {
+ name: 'UINT_TO_TIME',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'UINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'TIME' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: UINT) => OUT: TIME',
+ extensible: false,
+ },
+ {
+ name: 'UINT_TO_DATE',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'UINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'DATE' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: UINT) => OUT: DATE',
+ extensible: false,
+ },
+ {
+ name: 'UINT_TO_TOD',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'UINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'TOD' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: UINT) => OUT: TOD',
+ extensible: false,
+ },
+ {
+ name: 'UINT_TO_DT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'UINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'DT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: UINT) => OUT: DT',
+ extensible: false,
+ },
+ {
+ name: 'UINT_TO_STRING',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'UINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'STRING' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: UINT) => OUT: STRING',
+ extensible: false,
+ },
+ {
+ name: 'UINT_TO_BYTE',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'UINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'BYTE' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: UINT) => OUT: BYTE',
+ extensible: false,
+ },
+ {
+ name: 'UINT_TO_WORD',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'UINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'WORD' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: UINT) => OUT: WORD',
+ extensible: false,
+ },
+ {
+ name: 'UINT_TO_DWORD',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'UINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'DWORD' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: UINT) => OUT: DWORD',
+ extensible: false,
+ },
+ {
+ name: 'UINT_TO_LWORD',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'UINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'LWORD' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: UINT) => OUT: LWORD',
+ extensible: false,
+ },
+ {
+ name: 'UDINT_TO_BOOL',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'UDINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'BOOL' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: UDINT) => OUT: BOOL',
+ extensible: false,
+ },
+ {
+ name: 'UDINT_TO_SINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'UDINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'SINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: UDINT) => OUT: SINT',
+ extensible: false,
+ },
+ {
+ name: 'UDINT_TO_INT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'UDINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'INT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: UDINT) => OUT: INT',
+ extensible: false,
+ },
+ {
+ name: 'UDINT_TO_DINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'UDINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'DINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: UDINT) => OUT: DINT',
+ extensible: false,
+ },
+ {
+ name: 'UDINT_TO_LINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'UDINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'LINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: UDINT) => OUT: LINT',
+ extensible: false,
+ },
+ {
+ name: 'UDINT_TO_USINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'UDINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'USINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: UDINT) => OUT: USINT',
+ extensible: false,
+ },
+ {
+ name: 'UDINT_TO_UINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'UDINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'UINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: UDINT) => OUT: UINT',
+ extensible: false,
+ },
+ {
+ name: 'UDINT_TO_ULINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'UDINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'ULINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: UDINT) => OUT: ULINT',
+ extensible: false,
+ },
+ {
+ name: 'UDINT_TO_REAL',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'UDINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'REAL' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: UDINT) => OUT: REAL',
+ extensible: false,
+ },
+ {
+ name: 'UDINT_TO_LREAL',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'UDINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'LREAL' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: UDINT) => OUT: LREAL',
+ extensible: false,
+ },
+ {
+ name: 'UDINT_TO_TIME',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'UDINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'TIME' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: UDINT) => OUT: TIME',
+ extensible: false,
+ },
+ {
+ name: 'UDINT_TO_DATE',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'UDINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'DATE' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: UDINT) => OUT: DATE',
+ extensible: false,
+ },
+ {
+ name: 'UDINT_TO_TOD',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'UDINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'TOD' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: UDINT) => OUT: TOD',
+ extensible: false,
+ },
+ {
+ name: 'UDINT_TO_DT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'UDINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'DT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: UDINT) => OUT: DT',
+ extensible: false,
+ },
+ {
+ name: 'UDINT_TO_STRING',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'UDINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'STRING' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: UDINT) => OUT: STRING',
+ extensible: false,
+ },
+ {
+ name: 'UDINT_TO_BYTE',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'UDINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'BYTE' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: UDINT) => OUT: BYTE',
+ extensible: false,
+ },
+ {
+ name: 'UDINT_TO_WORD',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'UDINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'WORD' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: UDINT) => OUT: WORD',
+ extensible: false,
+ },
+ {
+ name: 'UDINT_TO_DWORD',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'UDINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'DWORD' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: UDINT) => OUT: DWORD',
+ extensible: false,
+ },
+ {
+ name: 'UDINT_TO_LWORD',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'UDINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'LWORD' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: UDINT) => OUT: LWORD',
+ extensible: false,
+ },
+ {
+ name: 'ULINT_TO_BOOL',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'ULINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'BOOL' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: ULINT) => OUT: BOOL',
+ extensible: false,
+ },
+ {
+ name: 'ULINT_TO_SINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'ULINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'SINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: ULINT) => OUT: SINT',
+ extensible: false,
+ },
+ {
+ name: 'ULINT_TO_INT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'ULINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'INT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: ULINT) => OUT: INT',
+ extensible: false,
+ },
+ {
+ name: 'ULINT_TO_DINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'ULINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'DINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: ULINT) => OUT: DINT',
+ extensible: false,
+ },
+ {
+ name: 'ULINT_TO_LINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'ULINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'LINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: ULINT) => OUT: LINT',
+ extensible: false,
+ },
+ {
+ name: 'ULINT_TO_USINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'ULINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'USINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: ULINT) => OUT: USINT',
+ extensible: false,
+ },
+ {
+ name: 'ULINT_TO_UINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'ULINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'UINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: ULINT) => OUT: UINT',
+ extensible: false,
+ },
+ {
+ name: 'ULINT_TO_UDINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'ULINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'UDINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: ULINT) => OUT: UDINT',
+ extensible: false,
+ },
+ {
+ name: 'ULINT_TO_REAL',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'ULINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'REAL' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: ULINT) => OUT: REAL',
+ extensible: false,
+ },
+ {
+ name: 'ULINT_TO_LREAL',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'ULINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'LREAL' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: ULINT) => OUT: LREAL',
+ extensible: false,
+ },
+ {
+ name: 'ULINT_TO_TIME',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'ULINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'TIME' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: ULINT) => OUT: TIME',
+ extensible: false,
+ },
+ {
+ name: 'ULINT_TO_DATE',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'ULINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'DATE' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: ULINT) => OUT: DATE',
+ extensible: false,
+ },
+ {
+ name: 'ULINT_TO_TOD',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'ULINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'TOD' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: ULINT) => OUT: TOD',
+ extensible: false,
+ },
+ {
+ name: 'ULINT_TO_DT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'ULINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'DT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: ULINT) => OUT: DT',
+ extensible: false,
+ },
+ {
+ name: 'ULINT_TO_STRING',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'ULINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'STRING' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: ULINT) => OUT: STRING',
+ extensible: false,
+ },
+ {
+ name: 'ULINT_TO_BYTE',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'ULINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'BYTE' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: ULINT) => OUT: BYTE',
+ extensible: false,
+ },
+ {
+ name: 'ULINT_TO_WORD',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'ULINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'WORD' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: ULINT) => OUT: WORD',
+ extensible: false,
+ },
+ {
+ name: 'ULINT_TO_DWORD',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'ULINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'DWORD' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: ULINT) => OUT: DWORD',
+ extensible: false,
+ },
+ {
+ name: 'ULINT_TO_LWORD',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'ULINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'LWORD' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: ULINT) => OUT: LWORD',
+ extensible: false,
+ },
+ {
+ name: 'REAL_TO_BOOL',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'REAL' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'BOOL' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: REAL) => OUT: BOOL',
+ extensible: false,
+ },
+ {
+ name: 'REAL_TO_SINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'REAL' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'SINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: REAL) => OUT: SINT',
+ extensible: false,
+ },
+ {
+ name: 'REAL_TO_INT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'REAL' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'INT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: REAL) => OUT: INT',
+ extensible: false,
+ },
+ {
+ name: 'REAL_TO_DINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'REAL' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'DINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: REAL) => OUT: DINT',
+ extensible: false,
+ },
+ {
+ name: 'REAL_TO_LINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'REAL' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'LINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: REAL) => OUT: LINT',
+ extensible: false,
+ },
+ {
+ name: 'REAL_TO_USINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'REAL' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'USINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: REAL) => OUT: USINT',
+ extensible: false,
+ },
+ {
+ name: 'REAL_TO_UINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'REAL' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'UINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: REAL) => OUT: UINT',
+ extensible: false,
+ },
+ {
+ name: 'REAL_TO_UDINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'REAL' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'UDINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: REAL) => OUT: UDINT',
+ extensible: false,
+ },
+ {
+ name: 'REAL_TO_ULINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'REAL' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'ULINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: REAL) => OUT: ULINT',
+ extensible: false,
+ },
+ {
+ name: 'REAL_TO_LREAL',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'REAL' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'LREAL' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: REAL) => OUT: LREAL',
+ extensible: false,
+ },
+ {
+ name: 'REAL_TO_TIME',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'REAL' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'TIME' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: REAL) => OUT: TIME',
+ extensible: false,
+ },
+ {
+ name: 'REAL_TO_DATE',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'REAL' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'DATE' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: REAL) => OUT: DATE',
+ extensible: false,
+ },
+ {
+ name: 'REAL_TO_TOD',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'REAL' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'TOD' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: REAL) => OUT: TOD',
+ extensible: false,
+ },
+ {
+ name: 'REAL_TO_DT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'REAL' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'DT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: REAL) => OUT: DT',
+ extensible: false,
+ },
+ {
+ name: 'REAL_TO_STRING',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'REAL' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'STRING' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: REAL) => OUT: STRING',
+ extensible: false,
+ },
+ {
+ name: 'REAL_TO_BYTE',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'REAL' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'BYTE' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: REAL) => OUT: BYTE',
+ extensible: false,
+ },
+ {
+ name: 'REAL_TO_WORD',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'REAL' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'WORD' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: REAL) => OUT: WORD',
+ extensible: false,
+ },
+ {
+ name: 'REAL_TO_DWORD',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'REAL' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'DWORD' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: REAL) => OUT: DWORD',
+ extensible: false,
+ },
+ {
+ name: 'REAL_TO_LWORD',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'REAL' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'LWORD' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: REAL) => OUT: LWORD',
+ extensible: false,
+ },
+ {
+ name: 'LREAL_TO_BOOL',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'LREAL' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'BOOL' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: LREAL) => OUT: BOOL',
+ extensible: false,
+ },
+ {
+ name: 'LREAL_TO_SINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'LREAL' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'SINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: LREAL) => OUT: SINT',
+ extensible: false,
+ },
+ {
+ name: 'LREAL_TO_INT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'LREAL' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'INT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: LREAL) => OUT: INT',
+ extensible: false,
+ },
+ {
+ name: 'LREAL_TO_DINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'LREAL' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'DINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: LREAL) => OUT: DINT',
+ extensible: false,
+ },
+ {
+ name: 'LREAL_TO_LINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'LREAL' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'LINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: LREAL) => OUT: LINT',
+ extensible: false,
+ },
+ {
+ name: 'LREAL_TO_USINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'LREAL' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'USINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: LREAL) => OUT: USINT',
+ extensible: false,
+ },
+ {
+ name: 'LREAL_TO_UINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'LREAL' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'UINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: LREAL) => OUT: UINT',
+ extensible: false,
+ },
+ {
+ name: 'LREAL_TO_UDINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'LREAL' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'UDINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: LREAL) => OUT: UDINT',
+ extensible: false,
+ },
+ {
+ name: 'LREAL_TO_ULINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'LREAL' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'ULINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: LREAL) => OUT: ULINT',
+ extensible: false,
+ },
+ {
+ name: 'LREAL_TO_REAL',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'LREAL' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'REAL' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: LREAL) => OUT: REAL',
+ extensible: false,
+ },
+ {
+ name: 'LREAL_TO_TIME',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'LREAL' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'TIME' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: LREAL) => OUT: TIME',
+ extensible: false,
+ },
+ {
+ name: 'LREAL_TO_DATE',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'LREAL' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'DATE' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: LREAL) => OUT: DATE',
+ extensible: false,
+ },
+ {
+ name: 'LREAL_TO_TOD',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'LREAL' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'TOD' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: LREAL) => OUT: TOD',
+ extensible: false,
+ },
+ {
+ name: 'LREAL_TO_DT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'LREAL' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'DT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: LREAL) => OUT: DT',
+ extensible: false,
+ },
+ {
+ name: 'LREAL_TO_STRING',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'LREAL' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'STRING' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: LREAL) => OUT: STRING',
+ extensible: false,
+ },
+ {
+ name: 'LREAL_TO_BYTE',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'LREAL' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'BYTE' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: LREAL) => OUT: BYTE',
+ extensible: false,
+ },
+ {
+ name: 'LREAL_TO_WORD',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'LREAL' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'WORD' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: LREAL) => OUT: WORD',
+ extensible: false,
+ },
+ {
+ name: 'LREAL_TO_DWORD',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'LREAL' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'DWORD' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: LREAL) => OUT: DWORD',
+ extensible: false,
+ },
+ {
+ name: 'LREAL_TO_LWORD',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'LREAL' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'LWORD' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: LREAL) => OUT: LWORD',
+ extensible: false,
+ },
+ {
+ name: 'TIME_TO_BOOL',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'TIME' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'BOOL' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: TIME) => OUT: BOOL',
+ extensible: false,
+ },
+ {
+ name: 'TIME_TO_SINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'TIME' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'SINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: TIME) => OUT: SINT',
+ extensible: false,
+ },
+ {
+ name: 'TIME_TO_INT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'TIME' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'INT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: TIME) => OUT: INT',
+ extensible: false,
+ },
+ {
+ name: 'TIME_TO_DINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'TIME' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'DINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: TIME) => OUT: DINT',
+ extensible: false,
+ },
+ {
+ name: 'TIME_TO_LINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'TIME' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'LINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: TIME) => OUT: LINT',
+ extensible: false,
+ },
+ {
+ name: 'TIME_TO_USINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'TIME' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'USINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: TIME) => OUT: USINT',
+ extensible: false,
+ },
+ {
+ name: 'TIME_TO_UINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'TIME' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'UINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: TIME) => OUT: UINT',
+ extensible: false,
+ },
+ {
+ name: 'TIME_TO_UDINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'TIME' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'UDINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: TIME) => OUT: UDINT',
+ extensible: false,
+ },
+ {
+ name: 'TIME_TO_ULINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'TIME' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'ULINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: TIME) => OUT: ULINT',
+ extensible: false,
+ },
+ {
+ name: 'TIME_TO_REAL',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'TIME' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'REAL' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: TIME) => OUT: REAL',
+ extensible: false,
+ },
+ {
+ name: 'TIME_TO_LREAL',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'TIME' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'LREAL' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: TIME) => OUT: LREAL',
+ extensible: false,
+ },
+ {
+ name: 'TIME_TO_DATE',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'TIME' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'DATE' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: TIME) => OUT: DATE',
+ extensible: false,
+ },
+ {
+ name: 'TIME_TO_TOD',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'TIME' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'TOD' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: TIME) => OUT: TOD',
+ extensible: false,
+ },
+ {
+ name: 'TIME_TO_DT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'TIME' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'DT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: TIME) => OUT: DT',
+ extensible: false,
+ },
+ {
+ name: 'TIME_TO_STRING',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'TIME' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'STRING' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: TIME) => OUT: STRING',
+ extensible: false,
+ },
+ {
+ name: 'TIME_TO_BYTE',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'TIME' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'BYTE' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: TIME) => OUT: BYTE',
+ extensible: false,
+ },
+ {
+ name: 'TIME_TO_WORD',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'TIME' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'WORD' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: TIME) => OUT: WORD',
+ extensible: false,
+ },
+ {
+ name: 'TIME_TO_DWORD',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'TIME' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'DWORD' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: TIME) => OUT: DWORD',
+ extensible: false,
+ },
+ {
+ name: 'TIME_TO_LWORD',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'TIME' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'LWORD' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: TIME) => OUT: LWORD',
+ extensible: false,
+ },
+ {
+ name: 'DATE_TO_BOOL',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DATE' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'BOOL' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: DATE) => OUT: BOOL',
+ extensible: false,
+ },
+ {
+ name: 'DATE_TO_SINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DATE' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'SINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: DATE) => OUT: SINT',
+ extensible: false,
+ },
+ {
+ name: 'DATE_TO_INT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DATE' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'INT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: DATE) => OUT: INT',
+ extensible: false,
+ },
+ {
+ name: 'DATE_TO_DINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DATE' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'DINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: DATE) => OUT: DINT',
+ extensible: false,
+ },
+ {
+ name: 'DATE_TO_LINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DATE' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'LINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: DATE) => OUT: LINT',
+ extensible: false,
+ },
+ {
+ name: 'DATE_TO_USINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DATE' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'USINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: DATE) => OUT: USINT',
+ extensible: false,
+ },
+ {
+ name: 'DATE_TO_UINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DATE' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'UINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: DATE) => OUT: UINT',
+ extensible: false,
+ },
+ {
+ name: 'DATE_TO_UDINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DATE' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'UDINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: DATE) => OUT: UDINT',
+ extensible: false,
+ },
+ {
+ name: 'DATE_TO_ULINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DATE' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'ULINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: DATE) => OUT: ULINT',
+ extensible: false,
+ },
+ {
+ name: 'DATE_TO_REAL',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DATE' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'REAL' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: DATE) => OUT: REAL',
+ extensible: false,
+ },
+ {
+ name: 'DATE_TO_LREAL',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DATE' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'LREAL' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: DATE) => OUT: LREAL',
+ extensible: false,
+ },
+ {
+ name: 'DATE_TO_TIME',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DATE' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'TIME' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: DATE) => OUT: TIME',
+ extensible: false,
+ },
+ {
+ name: 'DATE_TO_TOD',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DATE' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'TOD' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: DATE) => OUT: TOD',
+ extensible: false,
+ },
+ {
+ name: 'DATE_TO_DT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DATE' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'DT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: DATE) => OUT: DT',
+ extensible: false,
+ },
+ {
+ name: 'DATE_TO_STRING',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DATE' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'STRING' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: DATE) => OUT: STRING',
+ extensible: false,
+ },
+ {
+ name: 'DATE_TO_BYTE',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DATE' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'BYTE' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: DATE) => OUT: BYTE',
+ extensible: false,
+ },
+ {
+ name: 'DATE_TO_WORD',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DATE' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'WORD' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: DATE) => OUT: WORD',
+ extensible: false,
+ },
+ {
+ name: 'DATE_TO_DWORD',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DATE' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'DWORD' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: DATE) => OUT: DWORD',
+ extensible: false,
+ },
+ {
+ name: 'DATE_TO_LWORD',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DATE' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'LWORD' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: DATE) => OUT: LWORD',
+ extensible: false,
+ },
+ {
+ name: 'TOD_TO_BOOL',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'TOD' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'BOOL' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: TOD) => OUT: BOOL',
+ extensible: false,
+ },
+ {
+ name: 'TOD_TO_SINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'TOD' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'SINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: TOD) => OUT: SINT',
+ extensible: false,
+ },
+ {
+ name: 'TOD_TO_INT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'TOD' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'INT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: TOD) => OUT: INT',
+ extensible: false,
+ },
+ {
+ name: 'TOD_TO_DINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'TOD' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'DINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: TOD) => OUT: DINT',
+ extensible: false,
+ },
+ {
+ name: 'TOD_TO_LINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'TOD' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'LINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: TOD) => OUT: LINT',
+ extensible: false,
+ },
+ {
+ name: 'TOD_TO_USINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'TOD' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'USINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: TOD) => OUT: USINT',
+ extensible: false,
+ },
+ {
+ name: 'TOD_TO_UINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'TOD' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'UINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: TOD) => OUT: UINT',
+ extensible: false,
+ },
+ {
+ name: 'TOD_TO_UDINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'TOD' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'UDINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: TOD) => OUT: UDINT',
+ extensible: false,
+ },
+ {
+ name: 'TOD_TO_ULINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'TOD' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'ULINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: TOD) => OUT: ULINT',
+ extensible: false,
+ },
+ {
+ name: 'TOD_TO_REAL',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'TOD' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'REAL' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: TOD) => OUT: REAL',
+ extensible: false,
+ },
+ {
+ name: 'TOD_TO_LREAL',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'TOD' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'LREAL' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: TOD) => OUT: LREAL',
+ extensible: false,
+ },
+ {
+ name: 'TOD_TO_TIME',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'TOD' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'TIME' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: TOD) => OUT: TIME',
+ extensible: false,
+ },
+ {
+ name: 'TOD_TO_DATE',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'TOD' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'DATE' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: TOD) => OUT: DATE',
+ extensible: false,
+ },
+ {
+ name: 'TOD_TO_DT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'TOD' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'DT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: TOD) => OUT: DT',
+ extensible: false,
+ },
+ {
+ name: 'TOD_TO_STRING',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'TOD' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'STRING' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: TOD) => OUT: STRING',
+ extensible: false,
+ },
+ {
+ name: 'TOD_TO_BYTE',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'TOD' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'BYTE' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: TOD) => OUT: BYTE',
+ extensible: false,
+ },
+ {
+ name: 'TOD_TO_WORD',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'TOD' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'WORD' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: TOD) => OUT: WORD',
+ extensible: false,
+ },
+ {
+ name: 'TOD_TO_DWORD',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'TOD' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'DWORD' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: TOD) => OUT: DWORD',
+ extensible: false,
+ },
+ {
+ name: 'TOD_TO_LWORD',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'TOD' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'LWORD' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: TOD) => OUT: LWORD',
+ extensible: false,
+ },
+ {
+ name: 'DT_TO_BOOL',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'BOOL' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: DT) => OUT: BOOL',
+ extensible: false,
+ },
+ {
+ name: 'DT_TO_SINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'SINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: DT) => OUT: SINT',
+ extensible: false,
+ },
+ {
+ name: 'DT_TO_INT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'INT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: DT) => OUT: INT',
+ extensible: false,
+ },
+ {
+ name: 'DT_TO_DINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'DINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: DT) => OUT: DINT',
+ extensible: false,
+ },
+ {
+ name: 'DT_TO_LINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'LINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: DT) => OUT: LINT',
+ extensible: false,
+ },
+ {
+ name: 'DT_TO_USINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'USINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: DT) => OUT: USINT',
+ extensible: false,
+ },
+ {
+ name: 'DT_TO_UINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'UINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: DT) => OUT: UINT',
+ extensible: false,
+ },
+ {
+ name: 'DT_TO_UDINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'UDINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: DT) => OUT: UDINT',
+ extensible: false,
+ },
+ {
+ name: 'DT_TO_ULINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'ULINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: DT) => OUT: ULINT',
+ extensible: false,
+ },
+ {
+ name: 'DT_TO_REAL',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'REAL' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: DT) => OUT: REAL',
+ extensible: false,
+ },
+ {
+ name: 'DT_TO_LREAL',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'LREAL' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: DT) => OUT: LREAL',
+ extensible: false,
+ },
+ {
+ name: 'DT_TO_TIME',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'TIME' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: DT) => OUT: TIME',
+ extensible: false,
+ },
+ {
+ name: 'DT_TO_DATE',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'DATE' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: DT) => OUT: DATE',
+ extensible: false,
+ },
+ {
+ name: 'DT_TO_TOD',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'TOD' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: DT) => OUT: TOD',
+ extensible: false,
+ },
+ {
+ name: 'DT_TO_STRING',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'STRING' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: DT) => OUT: STRING',
+ extensible: false,
+ },
+ {
+ name: 'DT_TO_BYTE',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'BYTE' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: DT) => OUT: BYTE',
+ extensible: false,
+ },
+ {
+ name: 'DT_TO_WORD',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'WORD' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: DT) => OUT: WORD',
+ extensible: false,
+ },
+ {
+ name: 'DT_TO_DWORD',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'DWORD' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: DT) => OUT: DWORD',
+ extensible: false,
+ },
+ {
+ name: 'DT_TO_LWORD',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'LWORD' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: DT) => OUT: LWORD',
+ extensible: false,
+ },
+ {
+ name: 'STRING_TO_BOOL',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'STRING' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'BOOL' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: STRING) => OUT: BOOL',
+ extensible: false,
+ },
+ {
+ name: 'STRING_TO_SINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'STRING' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'SINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: STRING) => OUT: SINT',
+ extensible: false,
+ },
+ {
+ name: 'STRING_TO_INT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'STRING' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'INT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: STRING) => OUT: INT',
+ extensible: false,
+ },
+ {
+ name: 'STRING_TO_DINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'STRING' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'DINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: STRING) => OUT: DINT',
+ extensible: false,
+ },
+ {
+ name: 'STRING_TO_LINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'STRING' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'LINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: STRING) => OUT: LINT',
+ extensible: false,
+ },
+ {
+ name: 'STRING_TO_USINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'STRING' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'USINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: STRING) => OUT: USINT',
+ extensible: false,
+ },
+ {
+ name: 'STRING_TO_UINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'STRING' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'UINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: STRING) => OUT: UINT',
+ extensible: false,
+ },
+ {
+ name: 'STRING_TO_UDINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'STRING' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'UDINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: STRING) => OUT: UDINT',
+ extensible: false,
+ },
+ {
+ name: 'STRING_TO_ULINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'STRING' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'ULINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: STRING) => OUT: ULINT',
+ extensible: false,
+ },
+ {
+ name: 'STRING_TO_REAL',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'STRING' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'REAL' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: STRING) => OUT: REAL',
+ extensible: false,
+ },
+ {
+ name: 'STRING_TO_LREAL',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'STRING' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'LREAL' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: STRING) => OUT: LREAL',
+ extensible: false,
+ },
+ {
+ name: 'STRING_TO_TIME',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'STRING' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'TIME' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: STRING) => OUT: TIME',
+ extensible: false,
+ },
+ {
+ name: 'STRING_TO_DATE',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'STRING' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'DATE' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: STRING) => OUT: DATE',
+ extensible: false,
+ },
+ {
+ name: 'STRING_TO_TOD',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'STRING' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'TOD' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: STRING) => OUT: TOD',
+ extensible: false,
+ },
+ {
+ name: 'STRING_TO_DT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'STRING' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'DT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: STRING) => OUT: DT',
+ extensible: false,
+ },
+ {
+ name: 'STRING_TO_BYTE',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'STRING' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'BYTE' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: STRING) => OUT: BYTE',
+ extensible: false,
+ },
+ {
+ name: 'STRING_TO_WORD',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'STRING' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'WORD' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: STRING) => OUT: WORD',
+ extensible: false,
+ },
+ {
+ name: 'STRING_TO_DWORD',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'STRING' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'DWORD' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: STRING) => OUT: DWORD',
+ extensible: false,
+ },
+ {
+ name: 'STRING_TO_LWORD',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'STRING' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'LWORD' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: STRING) => OUT: LWORD',
+ extensible: false,
+ },
+ {
+ name: 'BYTE_TO_BOOL',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'BYTE' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'BOOL' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: BYTE) => OUT: BOOL',
+ extensible: false,
+ },
+ {
+ name: 'BYTE_TO_SINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'BYTE' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'SINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: BYTE) => OUT: SINT',
+ extensible: false,
+ },
+ {
+ name: 'BYTE_TO_INT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'BYTE' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'INT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: BYTE) => OUT: INT',
+ extensible: false,
+ },
+ {
+ name: 'BYTE_TO_DINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'BYTE' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'DINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: BYTE) => OUT: DINT',
+ extensible: false,
+ },
+ {
+ name: 'BYTE_TO_LINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'BYTE' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'LINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: BYTE) => OUT: LINT',
+ extensible: false,
+ },
+ {
+ name: 'BYTE_TO_USINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'BYTE' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'USINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: BYTE) => OUT: USINT',
+ extensible: false,
+ },
+ {
+ name: 'BYTE_TO_UINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'BYTE' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'UINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: BYTE) => OUT: UINT',
+ extensible: false,
+ },
+ {
+ name: 'BYTE_TO_UDINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'BYTE' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'UDINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: BYTE) => OUT: UDINT',
+ extensible: false,
+ },
+ {
+ name: 'BYTE_TO_ULINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'BYTE' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'ULINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: BYTE) => OUT: ULINT',
+ extensible: false,
+ },
+ {
+ name: 'BYTE_TO_REAL',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'BYTE' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'REAL' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: BYTE) => OUT: REAL',
+ extensible: false,
+ },
+ {
+ name: 'BYTE_TO_LREAL',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'BYTE' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'LREAL' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: BYTE) => OUT: LREAL',
+ extensible: false,
+ },
+ {
+ name: 'BYTE_TO_TIME',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'BYTE' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'TIME' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: BYTE) => OUT: TIME',
+ extensible: false,
+ },
+ {
+ name: 'BYTE_TO_DATE',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'BYTE' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'DATE' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: BYTE) => OUT: DATE',
+ extensible: false,
+ },
+ {
+ name: 'BYTE_TO_TOD',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'BYTE' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'TOD' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: BYTE) => OUT: TOD',
+ extensible: false,
+ },
+ {
+ name: 'BYTE_TO_DT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'BYTE' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'DT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: BYTE) => OUT: DT',
+ extensible: false,
+ },
+ {
+ name: 'BYTE_TO_STRING',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'BYTE' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'STRING' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: BYTE) => OUT: STRING',
+ extensible: false,
+ },
+ {
+ name: 'BYTE_TO_WORD',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'BYTE' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'WORD' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: BYTE) => OUT: WORD',
+ extensible: false,
+ },
+ {
+ name: 'BYTE_TO_DWORD',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'BYTE' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'DWORD' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: BYTE) => OUT: DWORD',
+ extensible: false,
+ },
+ {
+ name: 'BYTE_TO_LWORD',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'BYTE' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'LWORD' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: BYTE) => OUT: LWORD',
+ extensible: false,
+ },
+ {
+ name: 'WORD_TO_BOOL',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'WORD' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'BOOL' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: WORD) => OUT: BOOL',
+ extensible: false,
+ },
+ {
+ name: 'WORD_TO_SINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'WORD' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'SINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: WORD) => OUT: SINT',
+ extensible: false,
+ },
+ {
+ name: 'WORD_TO_INT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'WORD' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'INT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: WORD) => OUT: INT',
+ extensible: false,
+ },
+ {
+ name: 'WORD_TO_DINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'WORD' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'DINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: WORD) => OUT: DINT',
+ extensible: false,
+ },
+ {
+ name: 'WORD_TO_LINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'WORD' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'LINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: WORD) => OUT: LINT',
+ extensible: false,
+ },
+ {
+ name: 'WORD_TO_USINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'WORD' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'USINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: WORD) => OUT: USINT',
+ extensible: false,
+ },
+ {
+ name: 'WORD_TO_UINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'WORD' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'UINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: WORD) => OUT: UINT',
+ extensible: false,
+ },
+ {
+ name: 'WORD_TO_UDINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'WORD' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'UDINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: WORD) => OUT: UDINT',
+ extensible: false,
+ },
+ {
+ name: 'WORD_TO_ULINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'WORD' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'ULINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: WORD) => OUT: ULINT',
+ extensible: false,
+ },
+ {
+ name: 'WORD_TO_REAL',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'WORD' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'REAL' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: WORD) => OUT: REAL',
+ extensible: false,
+ },
+ {
+ name: 'WORD_TO_LREAL',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'WORD' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'LREAL' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: WORD) => OUT: LREAL',
+ extensible: false,
+ },
+ {
+ name: 'WORD_TO_TIME',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'WORD' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'TIME' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: WORD) => OUT: TIME',
+ extensible: false,
+ },
+ {
+ name: 'WORD_TO_DATE',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'WORD' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'DATE' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: WORD) => OUT: DATE',
+ extensible: false,
+ },
+ {
+ name: 'WORD_TO_TOD',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'WORD' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'TOD' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: WORD) => OUT: TOD',
+ extensible: false,
+ },
+ {
+ name: 'WORD_TO_DT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'WORD' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'DT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: WORD) => OUT: DT',
+ extensible: false,
+ },
+ {
+ name: 'WORD_TO_BYTE',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'WORD' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'BYTE' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: WORD) => OUT: BYTE',
+ extensible: false,
+ },
+ {
+ name: 'WORD_TO_STRING',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'WORD' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'STRING' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: WORD) => OUT: STRING',
+ extensible: false,
+ },
+ {
+ name: 'DWORD_TO_BOOL',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DWORD' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'BOOL' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: DWORD) => OUT: BOOL',
+ extensible: false,
+ },
+ {
+ name: 'DWORD_TO_SINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DWORD' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'SINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: DWORD) => OUT: SINT',
+ extensible: false,
+ },
+ {
+ name: 'DWORD_TO_INT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DWORD' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'INT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: DWORD) => OUT: INT',
+ extensible: false,
+ },
+ {
+ name: 'DWORD_TO_DINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DWORD' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'DINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: DWORD) => OUT: DINT',
+ extensible: false,
+ },
+ {
+ name: 'DWORD_TO_LINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DWORD' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'LINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: DWORD) => OUT: LINT',
+ extensible: false,
+ },
+ {
+ name: 'DWORD_TO_USINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DWORD' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'USINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: DWORD) => OUT: USINT',
+ extensible: false,
+ },
+ {
+ name: 'DWORD_TO_UINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DWORD' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'UINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: DWORD) => OUT: UINT',
+ extensible: false,
+ },
+ {
+ name: 'DWORD_TO_UDINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DWORD' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'UDINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: DWORD) => OUT: UDINT',
+ extensible: false,
+ },
+ {
+ name: 'DWORD_TO_ULINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DWORD' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'ULINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: DWORD) => OUT: ULINT',
+ extensible: false,
+ },
+ {
+ name: 'DWORD_TO_REAL',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DWORD' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'REAL' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: DWORD) => OUT: REAL',
+ extensible: false,
+ },
+ {
+ name: 'DWORD_TO_LREAL',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DWORD' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'LREAL' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: DWORD) => OUT: LREAL',
+ extensible: false,
+ },
+ {
+ name: 'DWORD_TO_TIME',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DWORD' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'TIME' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: DWORD) => OUT: TIME',
+ extensible: false,
+ },
+ {
+ name: 'DWORD_TO_DATE',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DWORD' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'DATE' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: DWORD) => OUT: DATE',
+ extensible: false,
+ },
+ {
+ name: 'DWORD_TO_TOD',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DWORD' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'TOD' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: DWORD) => OUT: TOD',
+ extensible: false,
+ },
+ {
+ name: 'DWORD_TO_DT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DWORD' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'DT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: DWORD) => OUT: DT',
+ extensible: false,
+ },
+ {
+ name: 'DWORD_TO_BYTE',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DWORD' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'BYTE' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: DWORD) => OUT: BYTE',
+ extensible: false,
+ },
+ {
+ name: 'DWORD_TO_WORD',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DWORD' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'WORD' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: DWORD) => OUT: WORD',
+ extensible: false,
+ },
+ {
+ name: 'DWORD_TO_STRING',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DWORD' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'STRING' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: DWORD) => OUT: STRING',
+ extensible: false,
+ },
+ {
+ name: 'LWORD_TO_BOOL',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'LWORD' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'BOOL' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: LWORD) => OUT: BOOL',
+ extensible: false,
+ },
+ {
+ name: 'LWORD_TO_SINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'LWORD' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'SINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: LWORD) => OUT: SINT',
+ extensible: false,
+ },
+ {
+ name: 'LWORD_TO_INT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'LWORD' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'INT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: LWORD) => OUT: INT',
+ extensible: false,
+ },
+ {
+ name: 'LWORD_TO_DINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'LWORD' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'DINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: LWORD) => OUT: DINT',
+ extensible: false,
+ },
+ {
+ name: 'LWORD_TO_LINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'LWORD' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'LINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: LWORD) => OUT: LINT',
+ extensible: false,
+ },
+ {
+ name: 'LWORD_TO_USINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'LWORD' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'USINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: LWORD) => OUT: USINT',
+ extensible: false,
+ },
+ {
+ name: 'LWORD_TO_UINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'LWORD' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'UINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: LWORD) => OUT: UINT',
+ extensible: false,
+ },
+ {
+ name: 'LWORD_TO_UDINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'LWORD' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'UDINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: LWORD) => OUT: UDINT',
+ extensible: false,
+ },
+ {
+ name: 'LWORD_TO_ULINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'LWORD' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'ULINT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: LWORD) => OUT: ULINT',
+ extensible: false,
+ },
+ {
+ name: 'LWORD_TO_REAL',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'LWORD' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'REAL' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: LWORD) => OUT: REAL',
+ extensible: false,
+ },
+ {
+ name: 'LWORD_TO_LREAL',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'LWORD' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'LREAL' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: LWORD) => OUT: LREAL',
+ extensible: false,
+ },
+ {
+ name: 'LWORD_TO_TIME',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'LWORD' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'TIME' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: LWORD) => OUT: TIME',
+ extensible: false,
+ },
+ {
+ name: 'LWORD_TO_DATE',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'LWORD' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'DATE' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: LWORD) => OUT: DATE',
+ extensible: false,
+ },
+ {
+ name: 'LWORD_TO_TOD',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'LWORD' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'TOD' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: LWORD) => OUT: TOD',
+ extensible: false,
+ },
+ {
+ name: 'LWORD_TO_DT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'LWORD' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'DT' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: LWORD) => OUT: DT',
+ extensible: false,
+ },
+ {
+ name: 'LWORD_TO_BYTE',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'LWORD' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'BYTE' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: LWORD) => OUT: BYTE',
+ extensible: false,
+ },
+ {
+ name: 'LWORD_TO_WORD',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'LWORD' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'WORD' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: LWORD) => OUT: WORD',
+ extensible: false,
+ },
+ {
+ name: 'LWORD_TO_DWORD',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'LWORD' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'DWORD' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: LWORD) => OUT: DWORD',
+ extensible: false,
+ },
+ {
+ name: 'LWORD_TO_STRING',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'LWORD' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'STRING' },
+ },
+ ],
+ body: 'Data type conversion',
+ documentation: '(IN: LWORD) => OUT: STRING',
+ extensible: false,
+ },
+ {
+ name: 'TRUNC',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'generic-type', value: 'ANY_REAL' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'generic-type', value: 'ANY_INT' },
+ },
+ ],
+ body: 'Rounding up/down',
+ documentation: '(IN: ANY_REAL) => OUT: ANY_INT',
+ extensible: false,
+ },
+ {
+ name: 'BCD_TO_USINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'BYTE' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'USINT' },
+ },
+ ],
+ body: 'Conversion from BCD',
+ documentation: '(IN: BYTE) => OUT: USINT',
+ extensible: false,
+ },
+ {
+ name: 'BCD_TO_UINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'WORD' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'UINT' },
+ },
+ ],
+ body: 'Conversion from BCD',
+ documentation: '(IN: WORD) => OUT: UINT',
+ extensible: false,
+ },
+ {
+ name: 'BCD_TO_UDINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DWORD' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'UDINT' },
+ },
+ ],
+ body: 'Conversion from BCD',
+ documentation: '(IN: DWORD) => OUT: UDINT',
+ extensible: false,
+ },
+ {
+ name: 'BCD_TO_ULINT',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'LWORD' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'ULINT' },
+ },
+ ],
+ body: 'Conversion from BCD',
+ documentation: '(IN: LWORD) => OUT: ULINT',
+ extensible: false,
+ },
+ {
+ name: 'USINT_TO_BCD',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'USINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'BYTE' },
+ },
+ ],
+ body: 'Conversion to BCD',
+ documentation: '(IN: USINT) => OUT: BYTE',
+ extensible: false,
+ },
+ {
+ name: 'UINT_TO_BCD',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'UINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'WORD' },
+ },
+ ],
+ body: 'Conversion to BCD',
+ documentation: '(IN: UINT) => OUT: WORD',
+ extensible: false,
+ },
+ {
+ name: 'UDINT_TO_BCD',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'UDINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'DWORD' },
+ },
+ ],
+ body: 'Conversion to BCD',
+ documentation: '(IN: UDINT) => OUT: DWORD',
+ extensible: false,
+ },
+ {
+ name: 'ULINT_TO_BCD',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'ULINT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'LWORD' },
+ },
+ ],
+ body: 'Conversion to BCD',
+ documentation: '(IN: ULINT) => OUT: LWORD',
+ extensible: false,
+ },
+ {
+ name: 'DATE_AND_TIME_TO_TIME_OF_DAY',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'TOD' },
+ },
+ ],
+ body: 'Conversion to time-of-day',
+ documentation: '(IN: DT) => OUT: TOD',
+ extensible: false,
+ },
+ {
+ name: 'DATE_AND_TIME_TO_DATE',
+ type: 'function',
+ language: 'st',
+ variables: [
+ {
+ name: 'IN',
+ class: 'input',
+ type: { definition: 'base-type', value: 'DT' },
+ },
+ {
+ name: 'OUT',
+ class: 'output',
+ type: { definition: 'base-type', value: 'DATE' },
+ },
+ ],
+ body: 'Conversion to date',
+ documentation: '(IN: DT) => OUT: DATE',
+ extensible: false,
+ },
+ ],
+}
+
+export { TypeConversion, TypeConversionLibrarySchema }
diff --git a/src/renderer/data/library/index.ts b/src/frontend/data/library/index.ts
similarity index 100%
rename from src/renderer/data/library/index.ts
rename to src/frontend/data/library/index.ts
diff --git a/src/frontend/data/library/jaguar.ts b/src/frontend/data/library/jaguar.ts
new file mode 100644
index 000000000..af0b77bd5
--- /dev/null
+++ b/src/frontend/data/library/jaguar.ts
@@ -0,0 +1,77 @@
+import { z } from 'zod'
+
+import { BaseLibraryPouSchema, BaseLibraryVariableSchema } from '../../../middleware/shared/ports/plc-schemas'
+
+/** Library-level schema (name + version + paths). Not in plc-schemas so defined locally. */
+const BaseLibrarySchema = z.object({
+ name: z.string(),
+ version: z.string(),
+ author: z.string(),
+ stPath: z.string(),
+ cPath: z.string(),
+})
+
+const JaguarVariablesSchema = BaseLibraryVariableSchema
+
+const JaguarPouSchema = BaseLibraryPouSchema.extend({
+ variables: z.array(JaguarVariablesSchema),
+})
+
+export const JaguarLibrarySchema = BaseLibrarySchema.extend({
+ pous: z.array(JaguarPouSchema),
+})
+
+type JaguarLibrary = z.infer
+
+const Jaguar: JaguarLibrary = {
+ name: 'Jaguar',
+ version: '1.0.0',
+ author: 'Autonomy Logic',
+ stPath: 'src/renderer/data/library/jaguar/st',
+ cPath: 'src/renderer/data/library/jaguar/c',
+ pous: [
+ {
+ name: 'ADC_CONFIG',
+ type: 'function-block',
+ language: 'st',
+ variables: [
+ { name: 'ADC_CH', class: 'input', type: { definition: 'base-type', value: 'INT' }, documentation: 'ADC_CH' },
+ {
+ name: 'ADC_TYPE',
+ class: 'input',
+ type: { definition: 'base-type', value: 'INT' },
+ documentation: 'ADC_TYPE',
+ },
+ {
+ name: 'ADC_CH_LOCAL',
+ class: 'local',
+ type: { definition: 'base-type', value: 'SINT' },
+ documentation: 'ADC_CH_LOCAL',
+ },
+ {
+ name: 'ADC_TYPE_LOCAL',
+ class: 'local',
+ type: { definition: 'base-type', value: 'SINT' },
+ documentation: 'ADC_TYPE_LOCAL',
+ },
+ {
+ name: 'SUCCESS',
+ class: 'output',
+ type: { definition: 'base-type', value: 'BOOL' },
+ documentation: 'SUCCESS',
+ },
+ ],
+ body: `IF ADC_CH <> ADC_CH_LOCAL OR ADC_TYPE <> ADC_TYPE_LOCAL THEN
+ ADC_CH_LOCAL := ADC_CH;
+ ADC_TYPE_LOCAL := ADC_TYPE;
+ SUCCESS := TRUE;
+ ELSE
+ SUCCESS := FALSE;
+ END_IF;`,
+ documentation:
+ 'Configures the analog channel inputs on the Jaguar board. ADC_CH must be between 0 - 3. ADC_TYPE must be between 0 - 3, where 0 = unipolar 10V, 1 = bipolar 10V, 2 = unipolar 5V, and 3 = bipolar 5V. Upon successful configuration of the ADC, SUCCESS is set to TRUE.',
+ },
+ ],
+}
+
+export { Jaguar }
diff --git a/src/frontend/data/library/sequent-microsystems-modules.ts b/src/frontend/data/library/sequent-microsystems-modules.ts
new file mode 100644
index 000000000..56e2e3b3c
--- /dev/null
+++ b/src/frontend/data/library/sequent-microsystems-modules.ts
@@ -0,0 +1,350 @@
+import { z } from 'zod'
+
+import {
+ BaseLibraryPouSchema,
+ BaseLibraryVariableSchema,
+ baseTypeSchema,
+} from '../../../middleware/shared/ports/plc-schemas'
+
+/** Library-level schema (name + version + paths). Not in plc-schemas so defined locally. */
+const BaseLibrarySchema = z.object({
+ name: z.string(),
+ version: z.string(),
+ author: z.string(),
+ stPath: z.string(),
+ cPath: z.string(),
+})
+
+const SequentMicrosystemsModulesVariablesSchema = BaseLibraryVariableSchema.extend({
+ type: z.discriminatedUnion('definition', [
+ z.object({
+ definition: z.literal('base-type'),
+ value: baseTypeSchema,
+ }),
+ z.object({
+ definition: z.literal('derived-type'),
+ value: z.string(),
+ }),
+ ]),
+ initialValue: z
+ .lazy((): z.Schema => SequentMicrosystemsModulesVariablesSchema.pick({ type: true }))
+ .optional(),
+})
+
+const SequentMicrosystemsModulesPouSchema = BaseLibraryPouSchema.extend({
+ variables: z.array(SequentMicrosystemsModulesVariablesSchema),
+})
+
+export const SequentMicrosystemsModulesLibrarySchema = BaseLibrarySchema.extend({
+ pous: z.array(SequentMicrosystemsModulesPouSchema),
+})
+
+type SequentMicrosystemsModulesLibrary = z.infer
+
+const SequentMicrosystemsModules: SequentMicrosystemsModulesLibrary = {
+ name: 'Sequent Microsystems Modules',
+ version: '1.0.0',
+ author: 'Autonomy Logic',
+ stPath: 'dummypath/wichwillbereplacedlater',
+ cPath: 'dummypath/wichwillbereplacedlater',
+ pous: [
+ {
+ name: 'SM_8RELAY',
+ type: 'function-block',
+ language: 'st',
+ variables: [
+ { name: 'STACK', class: 'input', type: { definition: 'base-type', value: 'SINT' } },
+ { name: '01', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: '02', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: '03', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: '04', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: '05', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: '06', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: '07', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: '08', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'DUMMY', class: 'output', type: { definition: 'base-type', value: 'SINT' } },
+ ],
+ body: 'DUMMY := STACK;',
+ documentation: 'Update all outputs from 8-relays card',
+ },
+ {
+ name: 'SM_16RELAY',
+ type: 'function-block',
+ language: 'st',
+ variables: [
+ { name: 'STACK', class: 'input', type: { definition: 'base-type', value: 'SINT' } },
+ { name: '01', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: '02', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: '03', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: '04', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: '05', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: '06', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: '07', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: '08', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: '09', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: '010', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: '011', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: '012', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: '013', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: '014', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: '015', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: '016', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'DUMMY', class: 'output', type: { definition: 'base-type', value: 'SINT' } },
+ ],
+ body: 'DUMMY := STACK;',
+ documentation: 'Update all outputs from 16-relays card',
+ },
+ {
+ name: 'SM_8DIN',
+ type: 'function-block',
+ language: 'st',
+ variables: [
+ { name: 'STACK', class: 'input', type: { definition: 'base-type', value: 'SINT' } },
+ { name: 'I1', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'I2', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'I3', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'I4', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'I5', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'I6', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'I7', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'I8', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ ],
+ body: 'I1 := 0;',
+ documentation: 'Get all inputs from Sequent microsystems 8 HV Inputs modules',
+ },
+ {
+ name: 'SM_16DIN',
+ type: 'function-block',
+ language: 'st',
+ variables: [
+ { name: 'STACK', class: 'input', type: { definition: 'base-type', value: 'SINT' } },
+ { name: 'I1', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'I2', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'I3', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'I4', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'I5', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'I6', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'I7', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'I8', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'I9', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'I10', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'I11', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'I12', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'I13', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'I14', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'I15', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'I16', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ ],
+ body: 'I1 := 0;',
+ documentation: 'Get all inputs from Sequent microsystems 16 digital inputs modules.',
+ },
+ {
+ name: 'SM_4REL4IN',
+ type: 'function-block',
+ language: 'st',
+ variables: [
+ { name: 'STACK', class: 'input', type: { definition: 'base-type', value: 'SINT' } },
+ { name: 'RELAY1', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'RELAY2', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'RELAY3', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'RELAY4', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'OPTO1', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'OPTO2', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'OPTO3', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'OPTO4', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'AC_OPTO1', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'AC_OPTO2', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'AC_OPTO3', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'AC_OPTO4', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'PWM1', class: 'output', type: { definition: 'base-type', value: 'REAL' } },
+ { name: 'PWM2', class: 'output', type: { definition: 'base-type', value: 'REAL' } },
+ { name: 'PWM3', class: 'output', type: { definition: 'base-type', value: 'REAL' } },
+ { name: 'PWM4', class: 'output', type: { definition: 'base-type', value: 'REAL' } },
+ { name: 'FREQ1', class: 'output', type: { definition: 'base-type', value: 'UINT' } },
+ { name: 'FREQ2', class: 'output', type: { definition: 'base-type', value: 'UINT' } },
+ { name: 'FREQ3', class: 'output', type: { definition: 'base-type', value: 'UINT' } },
+ { name: 'FREQ4', class: 'output', type: { definition: 'base-type', value: 'UINT' } },
+ { name: 'BUTTON', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ ],
+ body: 'OPTO1 := 0;',
+ documentation: 'Get all inputs from and set all outputs to SM_4REL4IN modules',
+ },
+ {
+ name: 'SM_INDUSTRIAL',
+ type: 'function-block',
+ language: 'st',
+ variables: [
+ { name: 'STACK', class: 'input', type: { definition: 'base-type', value: 'SINT' } },
+ { name: 'LED1', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'LED2', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'LED3', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'LED4', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'Q0_10V1', class: 'input', type: { definition: 'base-type', value: 'REAL' } },
+ { name: 'Q0_10V2', class: 'input', type: { definition: 'base-type', value: 'REAL' } },
+ { name: 'Q0_10V3', class: 'input', type: { definition: 'base-type', value: 'REAL' } },
+ { name: 'Q0_10V4', class: 'input', type: { definition: 'base-type', value: 'REAL' } },
+ { name: 'Q4_20MA1', class: 'input', type: { definition: 'base-type', value: 'REAL' } },
+ { name: 'Q4_20MA2', class: 'input', type: { definition: 'base-type', value: 'REAL' } },
+ { name: 'Q4_20MA3', class: 'input', type: { definition: 'base-type', value: 'REAL' } },
+ { name: 'Q4_20MA4', class: 'input', type: { definition: 'base-type', value: 'REAL' } },
+ { name: 'QOD1', class: 'input', type: { definition: 'base-type', value: 'REAL' } },
+ { name: 'QOD2', class: 'input', type: { definition: 'base-type', value: 'REAL' } },
+ { name: 'QOD3', class: 'input', type: { definition: 'base-type', value: 'REAL' } },
+ { name: 'QOD4', class: 'input', type: { definition: 'base-type', value: 'REAL' } },
+ { name: 'OPTO1', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'OPTO2', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'OPTO3', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'OPTO4', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'I0_10V1', class: 'output', type: { definition: 'base-type', value: 'REAL' } },
+ { name: 'I0_10V2', class: 'output', type: { definition: 'base-type', value: 'REAL' } },
+ { name: 'I0_10V3', class: 'output', type: { definition: 'base-type', value: 'REAL' } },
+ { name: 'I0_10V4', class: 'output', type: { definition: 'base-type', value: 'REAL' } },
+ { name: 'I4_20MA1', class: 'output', type: { definition: 'base-type', value: 'REAL' } },
+ { name: 'I4_20MA2', class: 'output', type: { definition: 'base-type', value: 'REAL' } },
+ { name: 'I4_20MA3', class: 'output', type: { definition: 'base-type', value: 'REAL' } },
+ { name: 'I4_20MA4', class: 'output', type: { definition: 'base-type', value: 'REAL' } },
+ { name: 'OWB_T1', class: 'output', type: { definition: 'base-type', value: 'REAL' } },
+ { name: 'OWB_T2', class: 'output', type: { definition: 'base-type', value: 'REAL' } },
+ { name: 'OWB_T3', class: 'output', type: { definition: 'base-type', value: 'REAL' } },
+ { name: 'OWB_T4', class: 'output', type: { definition: 'base-type', value: 'REAL' } },
+ ],
+ body: 'OPTO1 := 0;',
+ documentation: 'Get all input and set all outputs of a Sequent Microsystems Industrial Automation card.',
+ },
+ {
+ name: 'SM_RTD',
+ type: 'function-block',
+ language: 'st',
+ variables: [
+ { name: 'STACK', class: 'input', type: { definition: 'base-type', value: 'SINT' } },
+ { name: 'TEMP1', class: 'output', type: { definition: 'base-type', value: 'REAL' } },
+ { name: 'TEMP2', class: 'output', type: { definition: 'base-type', value: 'REAL' } },
+ { name: 'TEMP3', class: 'output', type: { definition: 'base-type', value: 'REAL' } },
+ { name: 'TEMP4', class: 'output', type: { definition: 'base-type', value: 'REAL' } },
+ { name: 'TEMP5', class: 'output', type: { definition: 'base-type', value: 'REAL' } },
+ { name: 'TEMP6', class: 'output', type: { definition: 'base-type', value: 'REAL' } },
+ { name: 'TEMP7', class: 'output', type: { definition: 'base-type', value: 'REAL' } },
+ { name: 'TEMP8', class: 'output', type: { definition: 'base-type', value: 'REAL' } },
+ ],
+ body: 'TEMP1 := 0.0;',
+ documentation: 'Get all temperature inputs from SM_RTD modules as REAL values in deg Celsius',
+ },
+ {
+ name: 'SM_BAS',
+ type: 'function-block',
+ language: 'st',
+ variables: [
+ { name: 'STACK', class: 'input', type: { definition: 'base-type', value: 'SINT' } },
+ { name: 'TRIAC1', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'TRIAC2', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'TRIAC3', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'TRIAC4', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'LED1', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'LED2', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'LED3', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'LED4', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'IN1_T', class: 'input', type: { definition: 'base-type', value: 'UINT' } },
+ { name: 'IN2_T', class: 'input', type: { definition: 'base-type', value: 'UINT' } },
+ { name: 'IN3_T', class: 'input', type: { definition: 'base-type', value: 'UINT' } },
+ { name: 'IN4_T', class: 'input', type: { definition: 'base-type', value: 'UINT' } },
+ { name: 'IN5_T', class: 'input', type: { definition: 'base-type', value: 'UINT' } },
+ { name: 'IN6_T', class: 'input', type: { definition: 'base-type', value: 'UINT' } },
+ { name: 'IN7_T', class: 'input', type: { definition: 'base-type', value: 'UINT' } },
+ { name: 'IN8_T', class: 'input', type: { definition: 'base-type', value: 'UINT' } },
+ { name: 'Q0_10V1', class: 'input', type: { definition: 'base-type', value: 'REAL' } },
+ { name: 'Q0_10V2', class: 'input', type: { definition: 'base-type', value: 'REAL' } },
+ { name: 'Q0_10V3', class: 'input', type: { definition: 'base-type', value: 'REAL' } },
+ { name: 'Q0_10V4', class: 'input', type: { definition: 'base-type', value: 'REAL' } },
+ { name: 'UNIV1', class: 'output', type: { definition: 'base-type', value: 'REAL' } },
+ { name: 'UNIV2', class: 'output', type: { definition: 'base-type', value: 'REAL' } },
+ { name: 'UNIV3', class: 'output', type: { definition: 'base-type', value: 'REAL' } },
+ { name: 'UNIV4', class: 'output', type: { definition: 'base-type', value: 'REAL' } },
+ { name: 'UNIV5', class: 'output', type: { definition: 'base-type', value: 'REAL' } },
+ { name: 'UNIV6', class: 'output', type: { definition: 'base-type', value: 'REAL' } },
+ { name: 'UNIV7', class: 'output', type: { definition: 'base-type', value: 'REAL' } },
+ { name: 'UNIV8', class: 'output', type: { definition: 'base-type', value: 'REAL' } },
+ { name: 'DRY_C1', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'DRY_C2', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'DRY_C3', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'DRY_C4', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'DRY_C5', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'DRY_C6', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'DRY_C7', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'DRY_C8', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'OWB_T1', class: 'output', type: { definition: 'base-type', value: 'REAL' } },
+ { name: 'OWB_T2', class: 'output', type: { definition: 'base-type', value: 'REAL' } },
+ { name: 'OWB_T3', class: 'output', type: { definition: 'base-type', value: 'REAL' } },
+ { name: 'OWB_T4', class: 'output', type: { definition: 'base-type', value: 'REAL' } },
+ ],
+ body: 'DRY_C1 := 0;',
+ documentation: 'Get all input and set all outputs of a Sequent Microsystems Building Automation card.',
+ },
+ {
+ name: 'SM_HOME',
+ type: 'function-block',
+ language: 'st',
+ variables: [
+ { name: 'STACK', class: 'input', type: { definition: 'base-type', value: 'SINT' } },
+ { name: 'RELAY1', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'RELAY2', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'RELAY3', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'RELAY4', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'RELAY5', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'RELAY6', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'RELAY7', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'RELAY8', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'Q0_10V1', class: 'input', type: { definition: 'base-type', value: 'REAL' } },
+ { name: 'Q0_10V2', class: 'input', type: { definition: 'base-type', value: 'REAL' } },
+ { name: 'Q0_10V3', class: 'input', type: { definition: 'base-type', value: 'REAL' } },
+ { name: 'Q0_10V4', class: 'input', type: { definition: 'base-type', value: 'REAL' } },
+ { name: 'QOD1', class: 'input', type: { definition: 'base-type', value: 'REAL' } },
+ { name: 'QOD2', class: 'input', type: { definition: 'base-type', value: 'REAL' } },
+ { name: 'QOD3', class: 'input', type: { definition: 'base-type', value: 'REAL' } },
+ { name: 'QOD4', class: 'input', type: { definition: 'base-type', value: 'REAL' } },
+ { name: 'OPTO1', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'OPTO2', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'OPTO3', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'OPTO4', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'OPTO5', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'OPTO6', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'OPTO7', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'OPTO8', class: 'output', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'ADC1', class: 'output', type: { definition: 'base-type', value: 'REAL' } },
+ { name: 'ADC2', class: 'output', type: { definition: 'base-type', value: 'REAL' } },
+ { name: 'ADC3', class: 'output', type: { definition: 'base-type', value: 'REAL' } },
+ { name: 'ADC4', class: 'output', type: { definition: 'base-type', value: 'REAL' } },
+ { name: 'ADC5', class: 'output', type: { definition: 'base-type', value: 'REAL' } },
+ { name: 'ADC6', class: 'output', type: { definition: 'base-type', value: 'REAL' } },
+ { name: 'ADC7', class: 'output', type: { definition: 'base-type', value: 'REAL' } },
+ { name: 'ADC8', class: 'output', type: { definition: 'base-type', value: 'REAL' } },
+ { name: 'OWB_T1', class: 'output', type: { definition: 'base-type', value: 'REAL' } },
+ { name: 'OWB_T2', class: 'output', type: { definition: 'base-type', value: 'REAL' } },
+ { name: 'OWB_T3', class: 'output', type: { definition: 'base-type', value: 'REAL' } },
+ { name: 'OWB_T4', class: 'output', type: { definition: 'base-type', value: 'REAL' } },
+ ],
+ body: 'OPTO1 := 0;',
+ documentation: 'Get all inputs and set all outputs of a Sequent Microsystems Home Automation card.',
+ },
+ {
+ name: 'SM_8MOSFET',
+ type: 'function-block',
+ language: 'st',
+ variables: [
+ { name: 'STACK', class: 'input', type: { definition: 'base-type', value: 'SINT' } },
+ { name: 'MOS1', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'MOS2', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'MOS3', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'MOS4', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'MOS5', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'MOS6', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'MOS7', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'MOS8', class: 'input', type: { definition: 'base-type', value: 'BOOL' } },
+ { name: 'DUMMY', class: 'local', type: { definition: 'base-type', value: 'SINT' } },
+ ],
+ body: 'DUMMY := STACK;',
+ documentation: 'Update all outputs from 8-mosfets card',
+ },
+ ],
+}
+
+export { SequentMicrosystemsModules }
diff --git a/src2/frontend/data/library/standard-function-blocks.ts b/src/frontend/data/library/standard-function-blocks.ts
similarity index 99%
rename from src2/frontend/data/library/standard-function-blocks.ts
rename to src/frontend/data/library/standard-function-blocks.ts
index 4318cc2c1..272ec9c7a 100644
--- a/src2/frontend/data/library/standard-function-blocks.ts
+++ b/src/frontend/data/library/standard-function-blocks.ts
@@ -1,6 +1,11 @@
-import { BaseLibraryPouSchema, BaseLibraryVariableSchema, baseTypeSchema } from '../../../middleware/shared/ports/plc-schemas'
import { z } from 'zod'
+import {
+ BaseLibraryPouSchema,
+ BaseLibraryVariableSchema,
+ baseTypeSchema,
+} from '../../../middleware/shared/ports/plc-schemas'
+
/** Library-level schema (name + version + paths). Not in plc-schemas so defined locally. */
const BaseLibrarySchema = z.object({
name: z.string(),
diff --git a/src2/frontend/data/sources/POU.tsx b/src/frontend/data/sources/POU.tsx
similarity index 100%
rename from src2/frontend/data/sources/POU.tsx
rename to src/frontend/data/sources/POU.tsx
index 557b59bb8..bb9618929 100644
--- a/src2/frontend/data/sources/POU.tsx
+++ b/src/frontend/data/sources/POU.tsx
@@ -1,8 +1,8 @@
import { CppIcon } from '../../assets/icons/project/Cpp'
import { DataTypeIcon } from '../../assets/icons/project/DataType'
import { FBDIcon } from '../../assets/icons/project/FBD'
-import { FunctionBlockIcon } from '../../assets/icons/project/FunctionBlock'
import { FunctionIcon } from '../../assets/icons/project/Function'
+import { FunctionBlockIcon } from '../../assets/icons/project/FunctionBlock'
import { ILIcon } from '../../assets/icons/project/IL'
import { LDIcon } from '../../assets/icons/project/LD'
import { ProgramIcon } from '../../assets/icons/project/Program'
diff --git a/src2/frontend/data/sources/data-type.tsx b/src/frontend/data/sources/data-type.tsx
similarity index 100%
rename from src2/frontend/data/sources/data-type.tsx
rename to src/frontend/data/sources/data-type.tsx
diff --git a/src/frontend/env.d.ts b/src/frontend/env.d.ts
new file mode 100644
index 000000000..fbad0dd0c
--- /dev/null
+++ b/src/frontend/env.d.ts
@@ -0,0 +1,7 @@
+interface ImportMetaEnv {
+ readonly [key: string]: string | undefined
+}
+
+interface ImportMeta {
+ readonly env: ImportMetaEnv
+}
diff --git a/src2/frontend/hooks/.gitkeep b/src/frontend/hooks/.gitkeep
similarity index 100%
rename from src2/frontend/hooks/.gitkeep
rename to src/frontend/hooks/.gitkeep
diff --git a/src2/frontend/hooks/use-debug-composite-key.ts b/src/frontend/hooks/use-debug-composite-key.ts
similarity index 99%
rename from src2/frontend/hooks/use-debug-composite-key.ts
rename to src/frontend/hooks/use-debug-composite-key.ts
index a4146b237..1fb937861 100644
--- a/src2/frontend/hooks/use-debug-composite-key.ts
+++ b/src/frontend/hooks/use-debug-composite-key.ts
@@ -1,6 +1,7 @@
-import { useOpenPLCStore } from '../store'
import { useCallback, useMemo } from 'react'
+import { useOpenPLCStore } from '../store'
+
/**
* Hook that returns a memoized function to build composite keys for debug variable lookups.
* Handles both program POUs (simple `pouName:variableName` format) and function block POUs
diff --git a/src/frontend/hooks/use-pou-snapshot.ts b/src/frontend/hooks/use-pou-snapshot.ts
new file mode 100644
index 000000000..acbcc670d
--- /dev/null
+++ b/src/frontend/hooks/use-pou-snapshot.ts
@@ -0,0 +1,38 @@
+import { useCallback } from 'react'
+
+import { useOpenPLCStore } from '../store'
+
+/**
+ * Convenience hook wrapping snapshotActions.pushToHistory().
+ * Captures the current POU state (variables, body, globalVariables, and
+ * graphical flow state for LD/FBD) and pushes it to the undo history.
+ */
+export function usePouSnapshot() {
+ const {
+ project,
+ ladderFlows,
+ fbdFlows,
+ snapshotActions: { pushToHistory, undo, redo },
+ } = useOpenPLCStore()
+
+ const captureAndPush = useCallback(
+ (pouName: string) => {
+ const pou = project.data.pous.find((p) => p.name === pouName)
+ if (!pou) return
+
+ const ladderFlow = ladderFlows.find((f) => f.name === pouName)
+ const fbdFlow = fbdFlows.find((f) => f.name === pouName)
+
+ pushToHistory(pouName, {
+ variables: JSON.parse(JSON.stringify(pou.interface?.variables ?? [])),
+ body: JSON.parse(JSON.stringify(pou.body.value)),
+ ladderFlow: ladderFlow ? JSON.parse(JSON.stringify(ladderFlow)) : undefined,
+ fbdFlow: fbdFlow ? JSON.parse(JSON.stringify(fbdFlow)) : undefined,
+ globalVariables: JSON.parse(JSON.stringify(project.data.configurations.resource.globalVariables)),
+ })
+ },
+ [project.data.pous, project.data.configurations.resource.globalVariables, ladderFlows, fbdFlows, pushToHistory],
+ )
+
+ return { captureAndPush, undo, redo }
+}
diff --git a/src2/frontend/hooks/use-remove-tab.tsx b/src/frontend/hooks/use-remove-tab.tsx
similarity index 99%
rename from src2/frontend/hooks/use-remove-tab.tsx
rename to src/frontend/hooks/use-remove-tab.tsx
index 1805067ac..22b4aad3d 100644
--- a/src2/frontend/hooks/use-remove-tab.tsx
+++ b/src/frontend/hooks/use-remove-tab.tsx
@@ -1,6 +1,7 @@
-import { useOpenPLCStore } from '../store'
import { useState } from 'react'
+import { useOpenPLCStore } from '../store'
+
const useHandleRemoveTab = () => {
const {
sharedWorkspaceActions: { closeFile },
diff --git a/src2/frontend/hooks/use-runtime-polling.ts b/src/frontend/hooks/use-runtime-polling.ts
similarity index 100%
rename from src2/frontend/hooks/use-runtime-polling.ts
rename to src/frontend/hooks/use-runtime-polling.ts
index 2aba485cc..dcad0d03b 100644
--- a/src2/frontend/hooks/use-runtime-polling.ts
+++ b/src/frontend/hooks/use-runtime-polling.ts
@@ -1,8 +1,8 @@
import { useCallback, useEffect, useRef } from 'react'
+import type { PlcStatus } from '../../middleware/shared/ports/types'
import { useRuntime } from '../../middleware/shared/providers'
import { useOpenPLCStore } from '../store'
-import type { PlcStatus } from '../../middleware/shared/ports/types'
// Unified polling interval for both status and logs (in milliseconds).
const POLL_INTERVAL_MS = 2000
diff --git a/src2/frontend/hooks/use-store-selectors.ts b/src/frontend/hooks/use-store-selectors.ts
similarity index 98%
rename from src2/frontend/hooks/use-store-selectors.ts
rename to src/frontend/hooks/use-store-selectors.ts
index 677d87673..03b7c5e65 100644
--- a/src2/frontend/hooks/use-store-selectors.ts
+++ b/src/frontend/hooks/use-store-selectors.ts
@@ -99,7 +99,7 @@ const remoteDeviceSelectors = {
for (const device of remoteDevices) {
if (!device.modbusTcpConfig?.ioGroups) continue
for (const ioGroup of device.modbusTcpConfig.ioGroups) {
- for (const point of ioGroup.ioPoints) {
+ for (const point of ioGroup.ioPoints ?? []) {
ioPoints.push({
deviceName: device.name,
ioGroupName: ioGroup.name,
@@ -107,7 +107,7 @@ const remoteDeviceSelectors = {
ioPointName: point.name,
ioPointType: point.type,
iecLocation: point.iecLocation,
- alias: point.alias,
+ alias: point.alias ?? '',
})
}
}
diff --git a/src2/frontend/hooks/useDebugPolling.ts b/src/frontend/hooks/useDebugPolling.ts
similarity index 64%
rename from src2/frontend/hooks/useDebugPolling.ts
rename to src/frontend/hooks/useDebugPolling.ts
index 40190c15c..bdb277bad 100644
--- a/src2/frontend/hooks/useDebugPolling.ts
+++ b/src/frontend/hooks/useDebugPolling.ts
@@ -2,47 +2,50 @@
* Debug Polling Hook
*
* When the debugger is visible, polls variable values from the runtime
- * via debugBridge.getVariablesList() at a transport-aware interval.
+ * via DebuggerPort.getVariablesList() at a board-aware interval.
*
- * Mirrors the desktop editor's polling loop (workspace-screen.tsx lines 1533-1676):
+ * Platform-agnostic — the DebuggerPort adapter handles the actual transport
+ * (IPC to main process, HTTP, WebRTC, simulator virtual serial port, etc.).
+ *
+ * Polling behavior:
+ * - Polls ONLY variables that are actively needed (watched, forced, graphed,
+ * visible on the active diagram, or referenced in ST/IL source text)
* - Single-batch-per-cycle with round-robin offset
* - Dynamic batch sizing (halves on ERROR_OUT_OF_MEMORY)
* - lastIndex-aware advancement (runtime may return partial data)
* - isPolling guard to skip tick if previous poll is in progress
+ * - Diagram/source scan results are cached per {pouName, language, fbContext}
+ * since the editor is read-only during debug
*
- * Polling intervals per transport:
- * - Simulator (Modbus RTU): 50ms (matches desktop DEBUGGER_POLL_INTERVAL_MS)
- * - WebRTC DataChannel: 200ms
- * - HTTP fallback: 2000ms
- *
- * The hook subscribes to the store's debugTransport field so the interval
- * automatically adjusts when the transport changes (e.g. HTTP → WebRTC upgrade).
+ * Polling intervals:
+ * - Simulator board: 50ms (Modbus RTU frame timing)
+ * - Other boards: 200ms (general purpose)
*/
import { useCallback, useEffect, useRef } from 'react'
-import { useOpenPLCStore } from '../store'
-import { debugBridge } from '../services/debug/debug-bridge'
-import { getTypeSizeByName, parseValueByTypeName } from '../utils/variable-sizes'
import type { DebugTreeNode } from '../../middleware/shared/ports/types'
+import { useDebugger } from '../../middleware/shared/providers'
+import { openPLCStoreBase, useOpenPLCStore } from '../store'
+import { buildActiveIndexSet } from '../utils/debug-polling-filter'
+import { getTypeSizeByName, parseValueByTypeName } from '../utils/variable-sizes'
-/** Polling interval for Modbus RTU / simulator (matches desktop editor). */
+/** Polling interval for simulator boards (Modbus RTU). */
const SIMULATOR_POLL_INTERVAL_MS = 50
-/** Polling interval for WebRTC DataChannel. */
-const WEBRTC_POLL_INTERVAL_MS = 200
-/** Polling interval for HTTP fallback. */
-const HTTP_POLL_INTERVAL_MS = 2000
+/** Polling interval for non-simulator boards. */
+const DEFAULT_POLL_INTERVAL_MS = 200
-/** Default batch size for WebRTC/HTTP transports. */
+/** Default batch size for variable polling. */
const DEFAULT_BATCH_SIZE = 60
-/** Batch size for Modbus RTU / simulator (matches desktop editor). */
+/** Batch size for simulator (smaller due to RTU frame limits). */
const RTU_BATCH_SIZE = 20
const MIN_BATCH_SIZE = 2
/**
* Collect ALL leaf indexes from a tree (ignoring expansion state).
+ * Used to build the full index→metadata lookup for parsing responses.
*/
-function collectAllLeafIndexes(nodes: DebugTreeNode[]): Map {
+function collectAllLeafMeta(nodes: DebugTreeNode[]): Map {
const result = new Map()
function walk(node: DebugTreeNode) {
@@ -62,22 +65,13 @@ function collectAllLeafIndexes(nodes: DebugTreeNode[]): Map>
}
export function useDebugPolling({ debugTreesRef }: UseDebugPollingOptions): void {
+ const debuggerPort = useDebugger()
const isDebuggerVisible = useOpenPLCStore((state) => state.workspace.isDebuggerVisible)
- const debugTransport = useOpenPLCStore((state) => state.session.debugTransport)
const { workspaceActions, consoleActions } = useOpenPLCStore()
const pollingIntervalRef = useRef(null)
@@ -86,62 +80,74 @@ export function useDebugPolling({ debugTreesRef }: UseDebugPollingOptions): void
const batchOffsetRef = useRef(0)
const isPollingRef = useRef(false)
- // Dynamic batch size — starts at max for the transport, halves on memory errors
+ // Dynamic batch size — starts at max, halves on memory errors
const batchSizeRef = useRef(DEFAULT_BATCH_SIZE)
- // Cached leaf index data — computed once when debugger starts, cleared when it stops.
- const cachedLeavesRef = useRef |