Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -441,9 +441,12 @@ const SelectableClassCell = ({

const language = 'language' in editor.meta ? editor.meta.language : null
const getVariableClasses = () => {
if (language === 'python' || language === 'cpp') {
if (language === 'python') {
return ['input', 'output']
}
if (language === 'cpp') {
return ['input', 'output', 'local']
}
return ['input', 'output', 'inOut', 'external', 'local', 'temp']
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,7 @@ const VariablesEditor = () => {
const selectedRow = parseInt(editorVariables.selectedRow)

const language = 'language' in editor.meta ? editor.meta.language : null
const defaultClass: PLCVariable['class'] = language === 'python' || language === 'cpp' ? 'input' : 'local'
const defaultClass: PLCVariable['class'] = language === 'python' ? 'input' : 'local'

if (variables.length === 0) {
createVariable({
Expand Down
22 changes: 6 additions & 16 deletions src/utils/cpp/generateCBlocksCode.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { PLCVariable } from '@root/types/PLC/open-plc'
import { generateStructMember, isArrayVariable } from '@root/utils/PLC/array-codegen-helpers'

import { getExposedCppVariables } from './shared'

type CppPouData = {
name: string
code: string
Expand All @@ -26,17 +28,12 @@ const processUserCode = (pou: CppPouData): string => {
const setupFunctionName = `${pou.name.toLowerCase()}_setup`
const loopFunctionName = `${pou.name.toLowerCase()}_loop`

const inputVariables = pou.variables.filter((v) => v.class === 'input')
const outputVariables = pou.variables.filter((v) => v.class === 'output')
const exposedVariables = getExposedCppVariables(pou.variables)

let processedCode = `//definition of external blocks - ${pou.name.toUpperCase()}\n`
processedCode += `typedef struct {\n`

inputVariables.forEach((variable) => {
processedCode += generateStructMember(variable)
})

outputVariables.forEach((variable) => {
exposedVariables.forEach((variable) => {
processedCode += generateStructMember(variable)
})

Expand All @@ -45,11 +42,7 @@ const processUserCode = (pou: CppPouData): string => {
processedCode += `extern "C" void ${setupFunctionName}(${structName} *vars);\n`
processedCode += `extern "C" void ${loopFunctionName}(${structName} *vars);\n\n`

inputVariables.forEach((variable) => {
processedCode += generateDefine(variable)
})

outputVariables.forEach((variable) => {
exposedVariables.forEach((variable) => {
processedCode += generateDefine(variable)
})

Expand All @@ -67,10 +60,7 @@ const processUserCode = (pou: CppPouData): string => {
processedCode += modifiedUserCode
processedCode += '\n'

inputVariables.forEach((variable) => {
processedCode += generateUndef(variable)
})
outputVariables.forEach((variable) => {
exposedVariables.forEach((variable) => {
processedCode += generateUndef(variable)
})
processedCode += '\n'
Expand Down
11 changes: 4 additions & 7 deletions src/utils/cpp/generateCBlocksHeader.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { PLCVariable } from '@root/types/PLC/open-plc'
import { generateStructMember } from '@root/utils/PLC/array-codegen-helpers'

import { getExposedCppVariables } from './shared'

type CppPouData = {
name: string
variables: PLCVariable[]
Expand All @@ -17,17 +19,12 @@ const generateCBlocksHeader = (cppPous: CppPouData[]): string => {
const setupFunctionName = `${pou.name.toLowerCase()}_setup`
const loopFunctionName = `${pou.name.toLowerCase()}_loop`

const inputVariables = pou.variables.filter((v) => v.class === 'input')
const outputVariables = pou.variables.filter((v) => v.class === 'output')
const exposedVariables = getExposedCppVariables(pou.variables)

headerContent += `//definition of external blocks - ${pou.name.toUpperCase()}\n`
headerContent += `typedef struct {\n`

inputVariables.forEach((variable) => {
headerContent += generateStructMember(variable)
})

outputVariables.forEach((variable) => {
exposedVariables.forEach((variable) => {
headerContent += generateStructMember(variable)
})

Expand Down
88 changes: 88 additions & 0 deletions src/utils/cpp/generateCppBridge.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import type { PLCVariable } from '@root/types/PLC/open-plc'

import { generateCBlocksCode } from './generateCBlocksCode'
import { generateCBlocksHeader } from './generateCBlocksHeader'
import { generateSTCode } from './generateSTCode'

const inputVar: PLCVariable = {
name: 'IN',
class: 'input',
type: {
definition: 'base-type',
value: 'int',
},
location: '',
documentation: '',
}

const outputVar: PLCVariable = {
name: 'OUT',
class: 'output',
type: {
definition: 'base-type',
value: 'int',
},
location: '',
documentation: '',
}

const localVar: PLCVariable = {
name: 'counter',
class: 'local',
type: {
definition: 'base-type',
value: 'int',
},
location: '',
documentation: '',
initialValue: '0',
}

const runtimeVar: PLCVariable = {
name: 'hasBeenInitialized',
class: 'local',
type: {
definition: 'base-type',
value: 'bool',
},
location: '',
documentation: '',
initialValue: '0',
}

describe('C/C++ FB bridge generation', () => {
it('includes user local variables in the generated ST wrapper', () => {
const stCode = generateSTCode({
pouName: 'CounterBlock',
allVariables: [inputVar, outputVar, localVar, runtimeVar],
})

expect(stCode).toContain('vars.COUNTER = &data__->COUNTER.value;')
expect(stCode).not.toContain('vars.HASBEENINITIALIZED')
})

it('includes user local variables in the generated header and code bridge', () => {
const variables = [inputVar, outputVar, localVar, runtimeVar]

const header = generateCBlocksHeader([
{
name: 'CounterBlock',
variables,
},
])

const code = generateCBlocksCode([
{
name: 'CounterBlock',
variables,
code: `void setup() { counter = 1; }\nvoid loop() { counter += IN; OUT = counter; }`,
},
])

expect(header).toContain('IEC_INT *COUNTER;')
expect(header).not.toContain('HASBEENINITIALIZED')

expect(code).toContain('#define counter (*(vars->COUNTER))')
expect(code).not.toContain('#define hasBeenInitialized')
})
})
13 changes: 10 additions & 3 deletions src/utils/cpp/generateSTCode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import {
isArrayVariable,
} from '@root/utils/PLC/array-codegen-helpers'

import { getExposedCppVariables } from './shared'

type STCodeGenerationParams = {
pouName: string
allVariables: PLCVariable[]
Expand Down Expand Up @@ -72,14 +74,16 @@ const generateOutputArrayCopyBack = (outputVariables: PLCVariable[]): string =>
const generateSTCode = (params: STCodeGenerationParams): string => {
const { pouName, allVariables } = params

const inputVariables = allVariables.filter((v) => v.class === 'input')
const outputVariables = allVariables.filter((v) => v.class === 'output')
const exposedVariables = getExposedCppVariables(allVariables)
const inputVariables = exposedVariables.filter((v) => v.class === 'input')
const outputVariables = exposedVariables.filter((v) => v.class === 'output')
const localVariables = exposedVariables.filter((v) => v.class === 'local')

const structName = `${pouName.toUpperCase()}_VARS`
const setupFunctionName = `${pouName.toLowerCase()}_setup`
const loopFunctionName = `${pouName.toLowerCase()}_loop`

const allArrayVariables = [...inputVariables, ...outputVariables].filter(isArrayVariable)
const allArrayVariables = exposedVariables.filter(isArrayVariable)

const flatArrayDecl = generateFlatArrayDeclarations(allArrayVariables)
const flatArrayCopiesIn = generateFlatArrayCopiesIn(allArrayVariables)
Expand All @@ -91,6 +95,9 @@ const generateSTCode = (params: STCodeGenerationParams): string => {
outputVariables.forEach((variable) => {
variableAssignments += generateVariableAssignment(variable)
})
localVariables.forEach((variable) => {
variableAssignments += generateVariableAssignment(variable)
})

const outputCopyBack = generateOutputArrayCopyBack(outputVariables)

Expand Down
19 changes: 19 additions & 0 deletions src/utils/cpp/shared.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { PLCVariable } from '@root/types/PLC/open-plc'

const CPP_RUNTIME_LOCAL_VARIABLES = new Set(['hasBeenInitialized'])

const getExposedCppVariables = (variables: PLCVariable[]): PLCVariable[] => {
return variables.filter((variable) => {
if (variable.class === 'input' || variable.class === 'output') {
return true
}

if (variable.class === 'local') {
return !CPP_RUNTIME_LOCAL_VARIABLES.has(variable.name)
}

return false
})
}

export { getExposedCppVariables }