From fcde587ae0255f4c510e4067c4c384a93ff84337 Mon Sep 17 00:00:00 2001 From: Valentina Danilova Date: Thu, 5 May 2022 20:54:29 +0300 Subject: [PATCH 01/21] declaration --- .idea/runConfigurations.xml | 10 - .../org.fbme.ide.integration.fordiac.msd | 2 - .../org.fbme.ide.enas.lang.mpl | 1 - .../org.fbme.ide.enas.analyzer.msd | 1 - .../models/org.fbme.language.build.mps | 12 +- .../org.fbme.ide.attributes.mpl | 4 +- ...iec61499.lang.generator.main@generator.mps | 1 + .../org.fbme.ide.iec61499.lang.behavior.mps | 6 + .../org.fbme.ide.iec61499.lang.editor.mps | 22 ++ .../org.fbme.ide.iec61499.lang.structure.mps | 140 ++++++++ .../org.fbme.ide.iec61499.lang.mpl | 4 - .../org.fbme.ide.meta.editor.mpl | 3 - .../org.fbme.ide.st.lang.mpl | 3 - .../org.fbme.ide.util.lang.mpl | 1 - ...bme.ide.iec61499.adapter.interfacepart.mps | 340 ++++++++++++++++++ .../org.fbme.ide.iec61499.repository.mps | 48 +++ .../org.fbme.ide.iec61499.adapter.msd | 4 +- code/library/org.fbme.lib.msd | 1 - .../org/fbme/lib/iec61499/IEC61499Factory.kt | 1 + .../fbme/lib/iec61499/parser/RootConverter.kt | 4 + .../stringify/RootDeclarationPrinter.kt | 1 + .../models/org.fbme.platform.build.mps | 3 +- .../org.fbme.ide.platform.persistence.mps | 158 +++++--- .../org.fbme.ide.platform.projectWizard.mps | 2 +- .../org.fbme.ide.platform.msd | 5 +- .../org.fbme.ide.richediting.lang.mpl | 4 - .../org.fbme.ide.richediting.msd | 3 - ...e.iec61499.lang.sandbox.mpsPersistence.mps | 6 + 28 files changed, 694 insertions(+), 96 deletions(-) delete mode 100644 .idea/runConfigurations.xml diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml deleted file mode 100644 index 797acea53..000000000 --- a/.idea/runConfigurations.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/code/4diac-integration/solutions/org.fbme.ide.integration.fordiac/org.fbme.ide.integration.fordiac.msd b/code/4diac-integration/solutions/org.fbme.ide.integration.fordiac/org.fbme.ide.integration.fordiac.msd index 812bf3bf0..688cd966e 100644 --- a/code/4diac-integration/solutions/org.fbme.ide.integration.fordiac/org.fbme.ide.integration.fordiac.msd +++ b/code/4diac-integration/solutions/org.fbme.ide.integration.fordiac/org.fbme.ide.integration.fordiac.msd @@ -41,7 +41,6 @@ - @@ -70,7 +69,6 @@ - diff --git a/code/enas/languages/org.fbme.ide.enas.lang/org.fbme.ide.enas.lang.mpl b/code/enas/languages/org.fbme.ide.enas.lang/org.fbme.ide.enas.lang.mpl index 914089d7e..c09c763b5 100644 --- a/code/enas/languages/org.fbme.ide.enas.lang/org.fbme.ide.enas.lang.mpl +++ b/code/enas/languages/org.fbme.ide.enas.lang/org.fbme.ide.enas.lang.mpl @@ -97,7 +97,6 @@ - diff --git a/code/enas/solutions/org.fbme.ide.enas.analyzer/org.fbme.ide.enas.analyzer.msd b/code/enas/solutions/org.fbme.ide.enas.analyzer/org.fbme.ide.enas.analyzer.msd index bb81bf1e5..66726340f 100644 --- a/code/enas/solutions/org.fbme.ide.enas.analyzer/org.fbme.ide.enas.analyzer.msd +++ b/code/enas/solutions/org.fbme.ide.enas.analyzer/org.fbme.ide.enas.analyzer.msd @@ -34,7 +34,6 @@ - diff --git a/code/language/buildsolution/models/org.fbme.language.build.mps b/code/language/buildsolution/models/org.fbme.language.build.mps index ae10dbb23..119f29018 100644 --- a/code/language/buildsolution/models/org.fbme.language.build.mps +++ b/code/language/buildsolution/models/org.fbme.language.build.mps @@ -91,6 +91,7 @@ + @@ -285,6 +286,7 @@ + @@ -321,11 +323,6 @@ - - - - - @@ -836,11 +833,6 @@ - - - - - diff --git a/code/language/languages/org.fbme.ide.attributes/org.fbme.ide.attributes.mpl b/code/language/languages/org.fbme.ide.attributes/org.fbme.ide.attributes.mpl index f0fff8c64..a13769751 100644 --- a/code/language/languages/org.fbme.ide.attributes/org.fbme.ide.attributes.mpl +++ b/code/language/languages/org.fbme.ide.attributes/org.fbme.ide.attributes.mpl @@ -98,10 +98,12 @@ + + - + diff --git a/code/language/languages/org.fbme.ide.iec61499.lang/generator/template/org.fbme.ide.iec61499.lang.generator.main@generator.mps b/code/language/languages/org.fbme.ide.iec61499.lang/generator/template/org.fbme.ide.iec61499.lang.generator.main@generator.mps index 0d483cb3c..3cd1cdb50 100644 --- a/code/language/languages/org.fbme.ide.iec61499.lang/generator/template/org.fbme.ide.iec61499.lang.generator.main@generator.mps +++ b/code/language/languages/org.fbme.ide.iec61499.lang/generator/template/org.fbme.ide.iec61499.lang.generator.main@generator.mps @@ -3,6 +3,7 @@ + diff --git a/code/language/languages/org.fbme.ide.iec61499.lang/models/org.fbme.ide.iec61499.lang.behavior.mps b/code/language/languages/org.fbme.ide.iec61499.lang/models/org.fbme.ide.iec61499.lang.behavior.mps index 726abe59b..1230b013e 100644 --- a/code/language/languages/org.fbme.ide.iec61499.lang/models/org.fbme.ide.iec61499.lang.behavior.mps +++ b/code/language/languages/org.fbme.ide.iec61499.lang/models/org.fbme.ide.iec61499.lang.behavior.mps @@ -4575,5 +4575,11 @@ + + + + + + diff --git a/code/language/languages/org.fbme.ide.iec61499.lang/models/org.fbme.ide.iec61499.lang.editor.mps b/code/language/languages/org.fbme.ide.iec61499.lang/models/org.fbme.ide.iec61499.lang.editor.mps index f84cf3fb0..a0a0bf531 100644 --- a/code/language/languages/org.fbme.ide.iec61499.lang/models/org.fbme.ide.iec61499.lang.editor.mps +++ b/code/language/languages/org.fbme.ide.iec61499.lang/models/org.fbme.ide.iec61499.lang.editor.mps @@ -4349,5 +4349,27 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/code/language/languages/org.fbme.ide.iec61499.lang/models/org.fbme.ide.iec61499.lang.structure.mps b/code/language/languages/org.fbme.ide.iec61499.lang/models/org.fbme.ide.iec61499.lang.structure.mps index 024e980e3..d227c5619 100644 --- a/code/language/languages/org.fbme.ide.iec61499.lang/models/org.fbme.ide.iec61499.lang.structure.mps +++ b/code/language/languages/org.fbme.ide.iec61499.lang/models/org.fbme.ide.iec61499.lang.structure.mps @@ -1659,5 +1659,145 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/code/language/languages/org.fbme.ide.iec61499.lang/org.fbme.ide.iec61499.lang.mpl b/code/language/languages/org.fbme.ide.iec61499.lang/org.fbme.ide.iec61499.lang.mpl index 36a249129..0f237762b 100644 --- a/code/language/languages/org.fbme.ide.iec61499.lang/org.fbme.ide.iec61499.lang.mpl +++ b/code/language/languages/org.fbme.ide.iec61499.lang/org.fbme.ide.iec61499.lang.mpl @@ -53,7 +53,6 @@ - @@ -86,7 +85,6 @@ - @@ -103,7 +101,6 @@ - @@ -131,7 +128,6 @@ - diff --git a/code/language/languages/org.fbme.ide.meta.editor/org.fbme.ide.meta.editor.mpl b/code/language/languages/org.fbme.ide.meta.editor/org.fbme.ide.meta.editor.mpl index cf8d5f739..a3d761735 100644 --- a/code/language/languages/org.fbme.ide.meta.editor/org.fbme.ide.meta.editor.mpl +++ b/code/language/languages/org.fbme.ide.meta.editor/org.fbme.ide.meta.editor.mpl @@ -142,7 +142,6 @@ - @@ -158,7 +157,6 @@ - @@ -194,7 +192,6 @@ - diff --git a/code/language/languages/org.fbme.ide.st.lang/org.fbme.ide.st.lang.mpl b/code/language/languages/org.fbme.ide.st.lang/org.fbme.ide.st.lang.mpl index 4029d747e..bd112958f 100644 --- a/code/language/languages/org.fbme.ide.st.lang/org.fbme.ide.st.lang.mpl +++ b/code/language/languages/org.fbme.ide.st.lang/org.fbme.ide.st.lang.mpl @@ -80,14 +80,12 @@ - - @@ -105,7 +103,6 @@ - diff --git a/code/language/languages/org.fbme.ide.util.lang/org.fbme.ide.util.lang.mpl b/code/language/languages/org.fbme.ide.util.lang/org.fbme.ide.util.lang.mpl index e28f8489c..3d1e0b10d 100644 --- a/code/language/languages/org.fbme.ide.util.lang/org.fbme.ide.util.lang.mpl +++ b/code/language/languages/org.fbme.ide.util.lang/org.fbme.ide.util.lang.mpl @@ -53,7 +53,6 @@ - diff --git a/code/language/solutions/org.fbme.ide.iec61499.adapter/models/org.fbme.ide.iec61499.adapter.interfacepart.mps b/code/language/solutions/org.fbme.ide.iec61499.adapter/models/org.fbme.ide.iec61499.adapter.interfacepart.mps index 5acb82c1d..60e49281d 100644 --- a/code/language/solutions/org.fbme.ide.iec61499.adapter/models/org.fbme.ide.iec61499.adapter.interfacepart.mps +++ b/code/language/solutions/org.fbme.ide.iec61499.adapter/models/org.fbme.ide.iec61499.adapter.interfacepart.mps @@ -7539,5 +7539,345 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/code/language/solutions/org.fbme.ide.iec61499.adapter/models/org.fbme.ide.iec61499.repository.mps b/code/language/solutions/org.fbme.ide.iec61499.adapter/models/org.fbme.ide.iec61499.repository.mps index 2ccca6507..a7fd18600 100644 --- a/code/language/solutions/org.fbme.ide.iec61499.adapter/models/org.fbme.ide.iec61499.repository.mps +++ b/code/language/solutions/org.fbme.ide.iec61499.adapter/models/org.fbme.ide.iec61499.repository.mps @@ -307,6 +307,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/code/language/solutions/org.fbme.ide.iec61499.adapter/org.fbme.ide.iec61499.adapter.msd b/code/language/solutions/org.fbme.ide.iec61499.adapter/org.fbme.ide.iec61499.adapter.msd index ffcdaf254..e8b9bdfb2 100644 --- a/code/language/solutions/org.fbme.ide.iec61499.adapter/org.fbme.ide.iec61499.adapter.msd +++ b/code/language/solutions/org.fbme.ide.iec61499.adapter/org.fbme.ide.iec61499.adapter.msd @@ -23,7 +23,7 @@ 8865b7a8-5271-43d3-884c-6fd1d9cfdd34(MPS.OpenAPI) 3f233e7f-b8a6-46d2-a57f-795d56775243(Annotations) 6594f340-4d73-4027-b7d3-c6ca2e70a53b(org.fbme.ide.iec61499.lang) - 1db6de07-b355-4c0f-9979-75b4ac1e8215(org.fbme.lib) + 1db6de07-b355-4c0f-9979-75b4ac1e8215(org.fbme.lib) 14f8fb68-9526-41ae-a986-e33a7382fe12(org.fbme.ide.util.lang) 6ed54515-acc8-4d1e-a16c-9fd6cfe951ea(MPS.Core) 491a88b6-52bd-4c4e-a61a-8496046b69aa(org.fbme.ide.attributes) @@ -37,7 +37,6 @@ - @@ -55,7 +54,6 @@ - diff --git a/code/library/org.fbme.lib.msd b/code/library/org.fbme.lib.msd index 5b109d71a..4ceeb26ce 100644 --- a/code/library/org.fbme.lib.msd +++ b/code/library/org.fbme.lib.msd @@ -31,7 +31,6 @@ - diff --git a/code/library/src/main/kotlin/org/fbme/lib/iec61499/IEC61499Factory.kt b/code/library/src/main/kotlin/org/fbme/lib/iec61499/IEC61499Factory.kt index 0f4c938b8..8169e2b25 100644 --- a/code/library/src/main/kotlin/org/fbme/lib/iec61499/IEC61499Factory.kt +++ b/code/library/src/main/kotlin/org/fbme/lib/iec61499/IEC61499Factory.kt @@ -18,6 +18,7 @@ interface IEC61499Factory { fun createApplicationDeclaration(identifier: Identifier?): ApplicationDeclaration fun createBasicFBTypeDeclaration(identifier: Identifier?): BasicFBTypeDeclaration fun createCompositeFBTypeDeclaration(identifier: Identifier?): CompositeFBTypeDeclaration + fun createCATBlockTypeDeclaration(identifier: Identifier?): CATBlockTypeDeclaration fun createDeviceDeclaration(identifier: Identifier?): DeviceDeclaration fun createDeviceTypeDeclaration(identifier: Identifier?): DeviceTypeDeclaration fun createParameterAssignment(): ParameterAssignment diff --git a/code/library/src/main/kotlin/org/fbme/lib/iec61499/parser/RootConverter.kt b/code/library/src/main/kotlin/org/fbme/lib/iec61499/parser/RootConverter.kt index 846047d7f..f88e60a35 100644 --- a/code/library/src/main/kotlin/org/fbme/lib/iec61499/parser/RootConverter.kt +++ b/code/library/src/main/kotlin/org/fbme/lib/iec61499/parser/RootConverter.kt @@ -47,6 +47,10 @@ class RootConverter( return SystemConverter(arguments()).extract() } + fun convertCATConfiguration(): CATBlockTypeDeclaration { + return CATBlockTypeConverter(arguments()).extract() + } + private fun arguments(): ConverterArgumentsHolder { return ConverterArgumentsHolder(myFactory, myStFactory, myLocus, myDocument.rootElement) } diff --git a/code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/RootDeclarationPrinter.kt b/code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/RootDeclarationPrinter.kt index 240dbf903..1e148e158 100644 --- a/code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/RootDeclarationPrinter.kt +++ b/code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/RootDeclarationPrinter.kt @@ -12,6 +12,7 @@ class RootDeclarationPrinter(private val myDeclaration: Declaration) { is AdapterTypeDeclaration -> AdapterTypePrinter(myDeclaration).print() is BasicFBTypeDeclaration -> BasicFBTypePrinter(myDeclaration).print() is CompositeFBTypeDeclaration -> CompositeFBTypePrinter(myDeclaration).print() + is CATBlockTypeDeclaration -> CATBlockTypePrinter(myDeclaration).print() is DeviceTypeDeclaration -> DeviceTypePrinter(myDeclaration).print() is ResourceTypeDeclaration -> ResourceTypePrinter(myDeclaration).print() is ServiceInterfaceFBTypeDeclaration -> ServiceInterfaceFBTypePrinter(myDeclaration).print() diff --git a/code/platform/buildsolution/models/org.fbme.platform.build.mps b/code/platform/buildsolution/models/org.fbme.platform.build.mps index de8423fd8..dd39f2612 100644 --- a/code/platform/buildsolution/models/org.fbme.platform.build.mps +++ b/code/platform/buildsolution/models/org.fbme.platform.build.mps @@ -256,9 +256,9 @@ - + @@ -351,6 +351,7 @@ + diff --git a/code/platform/solutions/org.fbme.ide.platform/models/org.fbme.ide.platform.persistence.mps b/code/platform/solutions/org.fbme.ide.platform/models/org.fbme.ide.platform.persistence.mps index 90631f7c8..244796f43 100644 --- a/code/platform/solutions/org.fbme.ide.platform/models/org.fbme.ide.platform.persistence.mps +++ b/code/platform/solutions/org.fbme.ide.platform/models/org.fbme.ide.platform.persistence.mps @@ -609,6 +609,19 @@ + + + + + + + + + + + + + @@ -658,70 +671,80 @@ - - - - + + + + - + - - - - - - - - + + + + + + + + + + + + + - - + + + + + + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + @@ -3790,6 +3813,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -3960,6 +4013,25 @@ + + + + + + + + + + + + + + + + + + + @@ -6456,14 +6528,6 @@ - - - - - - - - @@ -6487,6 +6551,14 @@ + + + + + + + + diff --git a/code/platform/solutions/org.fbme.ide.platform/models/org.fbme.ide.platform.projectWizard.mps b/code/platform/solutions/org.fbme.ide.platform/models/org.fbme.ide.platform.projectWizard.mps index c7ed31827..c09dc118f 100644 --- a/code/platform/solutions/org.fbme.ide.platform/models/org.fbme.ide.platform.projectWizard.mps +++ b/code/platform/solutions/org.fbme.ide.platform/models/org.fbme.ide.platform.projectWizard.mps @@ -359,7 +359,7 @@ - + diff --git a/code/platform/solutions/org.fbme.ide.platform/org.fbme.ide.platform.msd b/code/platform/solutions/org.fbme.ide.platform/org.fbme.ide.platform.msd index 1c83b7a64..35271484e 100644 --- a/code/platform/solutions/org.fbme.ide.platform/org.fbme.ide.platform.msd +++ b/code/platform/solutions/org.fbme.ide.platform/org.fbme.ide.platform.msd @@ -27,7 +27,7 @@ 5fa23c0a-216d-4571-a163-e286643e6f5f(jetbrains.mps.generator) 479c7a8c-02f9-43b5-9139-d910cb22f298(jetbrains.mps.core.xml) 1db6de07-b355-4c0f-9979-75b4ac1e8215(org.fbme.lib) - 86441d7a-e194-42da-81a5-2161ec62a379(MPS.Workbench) + 86441d7a-e194-42da-81a5-2161ec62a379(MPS.Workbench) 1ed103c3-3aa6-49b7-9c21-6765ee11f224(MPS.Editor) 25092e07-e655-497c-92fb-558a8e3080ed(jetbrains.mps.ide.ui) 6ed54515-acc8-4d1e-a16c-9fd6cfe951ea(MPS.Core) @@ -40,7 +40,6 @@ - @@ -49,7 +48,6 @@ - @@ -75,7 +73,6 @@ - diff --git a/code/richediting/languages/org.fbme.ide.richediting.lang/org.fbme.ide.richediting.lang.mpl b/code/richediting/languages/org.fbme.ide.richediting.lang/org.fbme.ide.richediting.lang.mpl index 13e4e4b39..e07a1fd57 100644 --- a/code/richediting/languages/org.fbme.ide.richediting.lang/org.fbme.ide.richediting.lang.mpl +++ b/code/richediting/languages/org.fbme.ide.richediting.lang/org.fbme.ide.richediting.lang.mpl @@ -36,7 +36,6 @@ - @@ -47,7 +46,6 @@ - @@ -56,7 +54,6 @@ - @@ -74,7 +71,6 @@ - diff --git a/code/richediting/solutions/org.fbme.ide.richediting/org.fbme.ide.richediting.msd b/code/richediting/solutions/org.fbme.ide.richediting/org.fbme.ide.richediting.msd index 1c96ac24a..1bfafbd26 100644 --- a/code/richediting/solutions/org.fbme.ide.richediting/org.fbme.ide.richediting.msd +++ b/code/richediting/solutions/org.fbme.ide.richediting/org.fbme.ide.richediting.msd @@ -62,7 +62,6 @@ - @@ -86,13 +85,11 @@ - - diff --git a/samples/sandbox/solutions/org.fbme.ide.sandbox/models/org.fbme.ide.iec61499.lang.sandbox.mpsPersistence.mps b/samples/sandbox/solutions/org.fbme.ide.sandbox/models/org.fbme.ide.iec61499.lang.sandbox.mpsPersistence.mps index c9a32f9b0..12753822b 100644 --- a/samples/sandbox/solutions/org.fbme.ide.sandbox/models/org.fbme.ide.iec61499.lang.sandbox.mpsPersistence.mps +++ b/samples/sandbox/solutions/org.fbme.ide.sandbox/models/org.fbme.ide.iec61499.lang.sandbox.mpsPersistence.mps @@ -1534,5 +1534,11 @@ + + + + + + From 19a1820f00e615b7a40b36f78526e93b3771bd30 Mon Sep 17 00:00:00 2001 From: Valentina Danilova Date: Fri, 5 Aug 2022 16:58:47 +0300 Subject: [PATCH 02/21] problem with build --- .idea/ant.xml | 6 ++++++ .idea/codeStyles/Project.xml | 7 +++++++ .idea/compiler.xml | 19 +------------------ .idea/libraries/ant_antlr.xml | 9 +++++++++ .idea/libraries/ant_launcher.xml | 9 +++++++++ .idea/libraries/apache_ant_junit.xml | 14 ++++++++++++++ .idea/misc.xml | 2 +- build-bootstrap.xml | 19 +++++++++++++------ .../models/org.fbme.language.build.mps | 4 +++- .../org.fbme.ide.iec61499.lang.structure.mps | 1 + .../models/org.fbme.platform.build.mps | 1 - 11 files changed, 64 insertions(+), 27 deletions(-) create mode 100644 .idea/ant.xml create mode 100644 .idea/codeStyles/Project.xml create mode 100644 .idea/libraries/ant_antlr.xml create mode 100644 .idea/libraries/ant_launcher.xml create mode 100644 .idea/libraries/apache_ant_junit.xml diff --git a/.idea/ant.xml b/.idea/ant.xml new file mode 100644 index 000000000..a2a476982 --- /dev/null +++ b/.idea/ant.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml new file mode 100644 index 000000000..919ce1f1f --- /dev/null +++ b/.idea/codeStyles/Project.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml index c8952aa4d..fb7f4a8a4 100644 --- a/.idea/compiler.xml +++ b/.idea/compiler.xml @@ -1,23 +1,6 @@ - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/.idea/libraries/ant_antlr.xml b/.idea/libraries/ant_antlr.xml new file mode 100644 index 000000000..59652667b --- /dev/null +++ b/.idea/libraries/ant_antlr.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/ant_launcher.xml b/.idea/libraries/ant_launcher.xml new file mode 100644 index 000000000..ef0794b5f --- /dev/null +++ b/.idea/libraries/ant_launcher.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/apache_ant_junit.xml b/.idea/libraries/apache_ant_junit.xml new file mode 100644 index 000000000..9b11bfcbb --- /dev/null +++ b/.idea/libraries/apache_ant_junit.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml index 5d9825616..e36899607 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -4,7 +4,7 @@ - + \ No newline at end of file diff --git a/build-bootstrap.xml b/build-bootstrap.xml index edff3b90f..056a9f206 100644 --- a/build-bootstrap.xml +++ b/build-bootstrap.xml @@ -40,9 +40,16 @@ - + + + + + + + + mps.build.number=${mps.build.number}${line.separator}mps.date=${mps.date}${line.separator}mps.build.vcs.number=${mps.build.vcs.number}${line.separator}mps.teamcity.buildConfName=${mps.teamcity.buildConfName}${line.separator}mps.idea.platform.build.number=${mps.idea.platform.build.number}${line.separator}mps.mps.build.counter=${mps.mps.build.counter}${line.separator}mpsBootstrapCore.version.major=${mpsBootstrapCore.version.major}${line.separator}mpsBootstrapCore.version.minor=${mpsBootstrapCore.version.minor}${line.separator}mpsBootstrapCore.version.bugfixNr=${mpsBootstrapCore.version.bugfixNr}${line.separator}mpsBootstrapCore.version.eap=${mpsBootstrapCore.version.eap}${line.separator}mpsBootstrapCore.version=${mpsBootstrapCore.version}${line.separator}fbme_platform.ide-version=${fbme_platform.ide-version}${line.separator}fbme_language.ide-version=${fbme_language.ide-version}${line.separator}fbme_richediting.ide-version=${fbme_richediting.ide-version}${line.separator}fbme_fordiac.ide-version=${fbme_fordiac.ide-version}${line.separator}fbme_smvdebugger.ide-version=${fbme_smvdebugger.ide-version}${line.separator}fbme_nxt.ide-version=${fbme_nxt.ide-version} @@ -69,7 +76,8 @@ - + + @@ -88,7 +96,9 @@ + + @@ -135,7 +145,6 @@ - @@ -174,9 +183,7 @@ - - - + diff --git a/code/language/buildsolution/models/org.fbme.language.build.mps b/code/language/buildsolution/models/org.fbme.language.build.mps index d56eb6b33..fc95c7f10 100644 --- a/code/language/buildsolution/models/org.fbme.language.build.mps +++ b/code/language/buildsolution/models/org.fbme.language.build.mps @@ -83,6 +83,7 @@ + @@ -167,9 +168,9 @@ - + @@ -259,6 +260,7 @@ + diff --git a/code/language/languages/org.fbme.ide.iec61499.lang/models/org.fbme.ide.iec61499.lang.structure.mps b/code/language/languages/org.fbme.ide.iec61499.lang/models/org.fbme.ide.iec61499.lang.structure.mps index 954fc515e..8fe8929e9 100644 --- a/code/language/languages/org.fbme.ide.iec61499.lang/models/org.fbme.ide.iec61499.lang.structure.mps +++ b/code/language/languages/org.fbme.ide.iec61499.lang/models/org.fbme.ide.iec61499.lang.structure.mps @@ -1719,6 +1719,7 @@ + diff --git a/code/platform/buildsolution/models/org.fbme.platform.build.mps b/code/platform/buildsolution/models/org.fbme.platform.build.mps index 919aeda3b..cb7617f90 100644 --- a/code/platform/buildsolution/models/org.fbme.platform.build.mps +++ b/code/platform/buildsolution/models/org.fbme.platform.build.mps @@ -229,7 +229,6 @@ - From 42a2ecdf5c2fb5e099203a92eaea88dafff6d0f9 Mon Sep 17 00:00:00 2001 From: "radimir.sorokin" Date: Fri, 5 Aug 2022 16:41:31 +0200 Subject: [PATCH 03/21] Regenerate build-bootstrap.xml, specify right jdk in project settings --- .idea/misc.xml | 2 +- build-bootstrap.xml | 19 ++++++------------- 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/.idea/misc.xml b/.idea/misc.xml index e36899607..5d9825616 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -4,7 +4,7 @@ - + \ No newline at end of file diff --git a/build-bootstrap.xml b/build-bootstrap.xml index 056a9f206..edff3b90f 100644 --- a/build-bootstrap.xml +++ b/build-bootstrap.xml @@ -40,16 +40,9 @@ - - - - + - - - - mps.build.number=${mps.build.number}${line.separator}mps.date=${mps.date}${line.separator}mps.build.vcs.number=${mps.build.vcs.number}${line.separator}mps.teamcity.buildConfName=${mps.teamcity.buildConfName}${line.separator}mps.idea.platform.build.number=${mps.idea.platform.build.number}${line.separator}mps.mps.build.counter=${mps.mps.build.counter}${line.separator}mpsBootstrapCore.version.major=${mpsBootstrapCore.version.major}${line.separator}mpsBootstrapCore.version.minor=${mpsBootstrapCore.version.minor}${line.separator}mpsBootstrapCore.version.bugfixNr=${mpsBootstrapCore.version.bugfixNr}${line.separator}mpsBootstrapCore.version.eap=${mpsBootstrapCore.version.eap}${line.separator}mpsBootstrapCore.version=${mpsBootstrapCore.version}${line.separator}fbme_platform.ide-version=${fbme_platform.ide-version}${line.separator}fbme_language.ide-version=${fbme_language.ide-version}${line.separator}fbme_richediting.ide-version=${fbme_richediting.ide-version}${line.separator}fbme_fordiac.ide-version=${fbme_fordiac.ide-version}${line.separator}fbme_smvdebugger.ide-version=${fbme_smvdebugger.ide-version}${line.separator}fbme_nxt.ide-version=${fbme_nxt.ide-version} @@ -76,8 +69,7 @@ - - + @@ -96,9 +88,7 @@ - - @@ -145,6 +135,7 @@ + @@ -183,7 +174,9 @@ - + + + From 4e96af1890d3bd2c91506d73b92901df91197482 Mon Sep 17 00:00:00 2001 From: Valentina Danilova Date: Fri, 5 Aug 2022 19:10:22 +0300 Subject: [PATCH 04/21] ignored? declarations --- .../declarations/CATBlockTypeDeclaration.kt | 10 +++++++ .../iec61499/parser/CATBlockTypeConverter.kt | 28 +++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 code/library/src/main/kotlin/org/fbme/lib/iec61499/declarations/CATBlockTypeDeclaration.kt create mode 100644 code/library/src/main/kotlin/org/fbme/lib/iec61499/parser/CATBlockTypeConverter.kt diff --git a/code/library/src/main/kotlin/org/fbme/lib/iec61499/declarations/CATBlockTypeDeclaration.kt b/code/library/src/main/kotlin/org/fbme/lib/iec61499/declarations/CATBlockTypeDeclaration.kt new file mode 100644 index 000000000..e8b18d6e6 --- /dev/null +++ b/code/library/src/main/kotlin/org/fbme/lib/iec61499/declarations/CATBlockTypeDeclaration.kt @@ -0,0 +1,10 @@ +package org.fbme.lib.iec61499.declarations + +import org.fbme.lib.common.Declaration +import org.fbme.lib.common.RootElement + +interface CATBlockTypeDeclaration : Declaration, RootElement { + val hmiInterface: HMIInterfaceTypeDeclaration + val subCATs: List + var blockDeclaration: CompositeFBTypeDeclaration +} \ No newline at end of file diff --git a/code/library/src/main/kotlin/org/fbme/lib/iec61499/parser/CATBlockTypeConverter.kt b/code/library/src/main/kotlin/org/fbme/lib/iec61499/parser/CATBlockTypeConverter.kt new file mode 100644 index 000000000..c6bdc4adb --- /dev/null +++ b/code/library/src/main/kotlin/org/fbme/lib/iec61499/parser/CATBlockTypeConverter.kt @@ -0,0 +1,28 @@ +package org.fbme.lib.iec61499.parser + +import org.fbme.lib.common.Identifier +import org.fbme.lib.common.Reference +import org.fbme.lib.iec61499.declarations.CATBlockTypeDeclaration +import org.fbme.lib.iec61499.declarations.CompositeFBTypeDeclaration +import org.fbme.lib.iec61499.fbnetwork.FunctionBlockDeclaration + +class CATBlockTypeConverter(arguments: ConverterArguments) : + DeclarationConverterBase(arguments) { + override fun extractDeclarationBody(identifier: Identifier?): CATBlockTypeDeclaration { + checkNotNull(element) + val fbtd = factory.createCATBlockTypeDeclaration(identifier) + fbtd.blockDeclaration = CompositeBlockConverter(with(this.element.getChild("Composite"))).extract() +// FBInterfaceConverter(this, fbtd).extractInterface() +// FBInterfaceAdaptersConverter(this, fbtd).extractAdapters() +// FBNetworkConverter(with(element.getChild("SubCAT")), fbtd.network).extractNetwork() + return fbtd + } + private inner class CompositeBlockConverter(arguments: ConverterArguments) : + DeclarationConverterBase(arguments) { + override fun extractDeclarationBody(identifier: Identifier?): CompositeFBTypeDeclaration { + checkNotNull(element) + val fbd = factory.createCompositeFBTypeDeclaration(identifier) + return fbd + } + } +} \ No newline at end of file From b3ec7131d045bcab3d3fe18517ac744b677badbb Mon Sep 17 00:00:00 2001 From: Valentina Danilova Date: Sat, 6 Aug 2022 05:25:24 +0300 Subject: [PATCH 05/21] . --- .../iec61499/declarations/DependentFilesDefinition.kt | 5 +++++ .../declarations/HMIInterfaceTypeDeclaration.kt | 10 ++++++++++ .../lib/iec61499/declarations/SubCATDeclaration.kt | 8 ++++++++ .../fbme/lib/iec61499/declarations/SymbolDefinition.kt | 5 +++++ 4 files changed, 28 insertions(+) create mode 100644 code/library/src/main/kotlin/org/fbme/lib/iec61499/declarations/DependentFilesDefinition.kt create mode 100644 code/library/src/main/kotlin/org/fbme/lib/iec61499/declarations/HMIInterfaceTypeDeclaration.kt create mode 100644 code/library/src/main/kotlin/org/fbme/lib/iec61499/declarations/SubCATDeclaration.kt create mode 100644 code/library/src/main/kotlin/org/fbme/lib/iec61499/declarations/SymbolDefinition.kt diff --git a/code/library/src/main/kotlin/org/fbme/lib/iec61499/declarations/DependentFilesDefinition.kt b/code/library/src/main/kotlin/org/fbme/lib/iec61499/declarations/DependentFilesDefinition.kt new file mode 100644 index 000000000..4de6a8b2e --- /dev/null +++ b/code/library/src/main/kotlin/org/fbme/lib/iec61499/declarations/DependentFilesDefinition.kt @@ -0,0 +1,5 @@ +package org.fbme.lib.iec61499.declarations + +interface DependentFilesDefinition { + var value: String +} \ No newline at end of file diff --git a/code/library/src/main/kotlin/org/fbme/lib/iec61499/declarations/HMIInterfaceTypeDeclaration.kt b/code/library/src/main/kotlin/org/fbme/lib/iec61499/declarations/HMIInterfaceTypeDeclaration.kt new file mode 100644 index 000000000..9a31b1307 --- /dev/null +++ b/code/library/src/main/kotlin/org/fbme/lib/iec61499/declarations/HMIInterfaceTypeDeclaration.kt @@ -0,0 +1,10 @@ +package org.fbme.lib.iec61499.declarations + +import org.fbme.lib.common.ContainedElement +import org.fbme.lib.common.Declaration +import org.fbme.lib.common.Reference + +interface HMIInterfaceTypeDeclaration : Declaration, ContainedElement { +// val symbol: SymbolDefinition +// val blockDeclaration: Reference +} \ No newline at end of file diff --git a/code/library/src/main/kotlin/org/fbme/lib/iec61499/declarations/SubCATDeclaration.kt b/code/library/src/main/kotlin/org/fbme/lib/iec61499/declarations/SubCATDeclaration.kt new file mode 100644 index 000000000..e123165a4 --- /dev/null +++ b/code/library/src/main/kotlin/org/fbme/lib/iec61499/declarations/SubCATDeclaration.kt @@ -0,0 +1,8 @@ +package org.fbme.lib.iec61499.declarations + +import org.fbme.lib.common.ContainedElement +import org.fbme.lib.common.Declaration + +interface SubCATDeclaration: Declaration, ContainedElement { + +} diff --git a/code/library/src/main/kotlin/org/fbme/lib/iec61499/declarations/SymbolDefinition.kt b/code/library/src/main/kotlin/org/fbme/lib/iec61499/declarations/SymbolDefinition.kt new file mode 100644 index 000000000..da071c7f3 --- /dev/null +++ b/code/library/src/main/kotlin/org/fbme/lib/iec61499/declarations/SymbolDefinition.kt @@ -0,0 +1,5 @@ +package org.fbme.lib.iec61499.declarations + +interface SymbolDefinition { + var children: List +} \ No newline at end of file From ac0b770e79ce0185927be94f1f0e4370512709c8 Mon Sep 17 00:00:00 2001 From: Valentina Danilova Date: Sat, 6 Aug 2022 05:34:42 +0300 Subject: [PATCH 06/21] . --- .../iec61499/stringify/CATBlockTypePrinter.kt | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/CATBlockTypePrinter.kt diff --git a/code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/CATBlockTypePrinter.kt b/code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/CATBlockTypePrinter.kt new file mode 100644 index 000000000..7b7401803 --- /dev/null +++ b/code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/CATBlockTypePrinter.kt @@ -0,0 +1,22 @@ +package org.fbme.lib.iec61499.stringify + +import org.fbme.lib.iec61499.declarations.CATBlockTypeDeclaration +import org.fbme.lib.iec61499.declarations.CompositeFBTypeDeclaration +import org.jdom.Element + +class CATBlockTypePrinter(declaration: CATBlockTypeDeclaration) : + DeclarationPrinterBase(declaration, "CAT") { + override fun printDeclarationBody(element: Element) { + element.setAttribute("name", this.element.name) + element.addContent(CompositeBlockPrinter(this.element.blockDeclaration).print()) +// element.addContent(HMIInterfacePrinter(this.element.hmiInterface).print()) +// element.addContent(SubCATPrinter(this.element.subCATs).print()) + } + + private class CompositeBlockPrinter(fb: CompositeFBTypeDeclaration) : + DeclarationPrinterBase(fb, "Composite") { + override fun printDeclarationBody(element: Element) { +// element.setAttribute("Type", this.element.typeReference.presentation) + } + } +} \ No newline at end of file From 790039ffb4bb641918c8097544834fb8dbdb494c Mon Sep 17 00:00:00 2001 From: "radimir.sorokin" Date: Sat, 6 Aug 2022 06:07:24 +0200 Subject: [PATCH 07/21] Fix broken reference --- .../models/org.fbme.ide.platform.projectWizard.mps | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/platform/solutions/org.fbme.ide.platform/models/org.fbme.ide.platform.projectWizard.mps b/code/platform/solutions/org.fbme.ide.platform/models/org.fbme.ide.platform.projectWizard.mps index 87ab6b010..d95bd3591 100644 --- a/code/platform/solutions/org.fbme.ide.platform/models/org.fbme.ide.platform.projectWizard.mps +++ b/code/platform/solutions/org.fbme.ide.platform/models/org.fbme.ide.platform.projectWizard.mps @@ -360,7 +360,7 @@ - + From f2673dfc5d235bf6c64e6179152984d913fffd9b Mon Sep 17 00:00:00 2001 From: Valentina Danilova Date: Fri, 21 Apr 2023 18:46:03 +0300 Subject: [PATCH 08/21] converting --- .idea/compiler.xml | 8 -- .idea/modules/fbme.iml | 8 -- .../org.fbme.ide.iec61499.lang.behavior.mps | 6 - .../org.fbme.ide.iec61499.lang.editor.mps | 130 +++++++++++++++++ .../org.fbme.ide.iec61499.lang.structure.mps | 68 ++++----- ...bme.ide.iec61499.adapter.interfacepart.mps | 136 ++++++++++++------ .../org.fbme.ide.iec61499.repository.mps | 108 ++++++++++++++ .../repository/PlatformDeclarationsScope.kt | 4 + .../fbme/lib/iec61499/DeclarationsScope.kt | 1 + .../declarations/CATBlockTypeDeclaration.kt | 1 - .../HMIInterfaceTypeDeclaration.kt | 5 +- .../fbme/lib/iec61499/parser/RootConverter.kt | 1 + .../org.fbme.ide.platform.persistence.mps | 75 ++++------ 13 files changed, 395 insertions(+), 156 deletions(-) delete mode 100644 .idea/modules/fbme.iml diff --git a/.idea/compiler.xml b/.idea/compiler.xml index 58d13c02c..c8952aa4d 100644 --- a/.idea/compiler.xml +++ b/.idea/compiler.xml @@ -1,14 +1,6 @@ - - - - - - - - diff --git a/.idea/modules/fbme.iml b/.idea/modules/fbme.iml deleted file mode 100644 index f49154055..000000000 --- a/.idea/modules/fbme.iml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/code/language/languages/org.fbme.ide.iec61499.lang/models/org.fbme.ide.iec61499.lang.behavior.mps b/code/language/languages/org.fbme.ide.iec61499.lang/models/org.fbme.ide.iec61499.lang.behavior.mps index 27250743c..e5cb9e719 100644 --- a/code/language/languages/org.fbme.ide.iec61499.lang/models/org.fbme.ide.iec61499.lang.behavior.mps +++ b/code/language/languages/org.fbme.ide.iec61499.lang/models/org.fbme.ide.iec61499.lang.behavior.mps @@ -4599,11 +4599,5 @@ - - - - - - diff --git a/code/language/languages/org.fbme.ide.iec61499.lang/models/org.fbme.ide.iec61499.lang.editor.mps b/code/language/languages/org.fbme.ide.iec61499.lang/models/org.fbme.ide.iec61499.lang.editor.mps index 032b8336a..2819c72df 100644 --- a/code/language/languages/org.fbme.ide.iec61499.lang/models/org.fbme.ide.iec61499.lang.editor.mps +++ b/code/language/languages/org.fbme.ide.iec61499.lang/models/org.fbme.ide.iec61499.lang.editor.mps @@ -4401,6 +4401,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/code/language/languages/org.fbme.ide.iec61499.lang/models/org.fbme.ide.iec61499.lang.structure.mps b/code/language/languages/org.fbme.ide.iec61499.lang/models/org.fbme.ide.iec61499.lang.structure.mps index cde800b0c..ccfc0f531 100644 --- a/code/language/languages/org.fbme.ide.iec61499.lang/models/org.fbme.ide.iec61499.lang.structure.mps +++ b/code/language/languages/org.fbme.ide.iec61499.lang/models/org.fbme.ide.iec61499.lang.structure.mps @@ -1564,46 +1564,23 @@ - - + + - - - + + - - - - - - - - - - - - - - - - - - - - - - @@ -1613,31 +1590,38 @@ - - - - - - - + + + + + + - - + + - - + + + - - + + - + + + + + + + + - + diff --git a/code/language/solutions/org.fbme.ide.iec61499.adapter/models/org.fbme.ide.iec61499.adapter.interfacepart.mps b/code/language/solutions/org.fbme.ide.iec61499.adapter/models/org.fbme.ide.iec61499.adapter.interfacepart.mps index 59a58fc00..8625fca65 100644 --- a/code/language/solutions/org.fbme.ide.iec61499.adapter/models/org.fbme.ide.iec61499.adapter.interfacepart.mps +++ b/code/language/solutions/org.fbme.ide.iec61499.adapter/models/org.fbme.ide.iec61499.adapter.interfacepart.mps @@ -107,6 +107,7 @@ + @@ -7707,46 +7708,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -7911,6 +7872,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/code/language/solutions/org.fbme.ide.iec61499.adapter/models/org.fbme.ide.iec61499.repository.mps b/code/language/solutions/org.fbme.ide.iec61499.adapter/models/org.fbme.ide.iec61499.repository.mps index fbd55a6da..f5e7bb020 100644 --- a/code/language/solutions/org.fbme.ide.iec61499.adapter/models/org.fbme.ide.iec61499.repository.mps +++ b/code/language/solutions/org.fbme.ide.iec61499.adapter/models/org.fbme.ide.iec61499.repository.mps @@ -93,6 +93,9 @@ + + + @@ -354,6 +357,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -4048,6 +4090,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/code/language/src/main/kotlin/org/fbme/ide/iec61499/repository/PlatformDeclarationsScope.kt b/code/language/src/main/kotlin/org/fbme/ide/iec61499/repository/PlatformDeclarationsScope.kt index eca6aeb1d..7cc9736b6 100644 --- a/code/language/src/main/kotlin/org/fbme/ide/iec61499/repository/PlatformDeclarationsScope.kt +++ b/code/language/src/main/kotlin/org/fbme/ide/iec61499/repository/PlatformDeclarationsScope.kt @@ -17,6 +17,10 @@ internal class PlatformDeclarationsScope( return myRepository.getAdapter(findNode(identifier), CompositeFBTypeDeclaration::class.java) } + override fun findCATBlockTypeDeclaration(identifier: Identifier): CATBlockTypeDeclaration? { + return myRepository.getAdapter(findNode(identifier), CATBlockTypeDeclaration::class.java) + } + override fun findBasicFBTypeDeclaration(identifier: Identifier): BasicFBTypeDeclaration? { return myRepository.getAdapter(findNode(identifier), BasicFBTypeDeclaration::class.java) } diff --git a/code/library/src/main/kotlin/org/fbme/lib/iec61499/DeclarationsScope.kt b/code/library/src/main/kotlin/org/fbme/lib/iec61499/DeclarationsScope.kt index 3e35d940a..73f634785 100644 --- a/code/library/src/main/kotlin/org/fbme/lib/iec61499/DeclarationsScope.kt +++ b/code/library/src/main/kotlin/org/fbme/lib/iec61499/DeclarationsScope.kt @@ -6,6 +6,7 @@ import org.fbme.lib.iec61499.fbnetwork.FunctionBlockDeclaration interface DeclarationsScope { fun findCompositeFBTypeDeclaration(identifier: Identifier): CompositeFBTypeDeclaration? + fun findCATBlockTypeDeclaration(identifier: Identifier): CATBlockTypeDeclaration? fun findBasicFBTypeDeclaration(identifier: Identifier): BasicFBTypeDeclaration? fun findServiceFBTypeDeclaration(identifier: Identifier): ServiceInterfaceFBTypeDeclaration? fun findAdapterTypeDeclaration(identifier: Identifier): AdapterTypeDeclaration? diff --git a/code/library/src/main/kotlin/org/fbme/lib/iec61499/declarations/CATBlockTypeDeclaration.kt b/code/library/src/main/kotlin/org/fbme/lib/iec61499/declarations/CATBlockTypeDeclaration.kt index e8b18d6e6..5c96df53c 100644 --- a/code/library/src/main/kotlin/org/fbme/lib/iec61499/declarations/CATBlockTypeDeclaration.kt +++ b/code/library/src/main/kotlin/org/fbme/lib/iec61499/declarations/CATBlockTypeDeclaration.kt @@ -5,6 +5,5 @@ import org.fbme.lib.common.RootElement interface CATBlockTypeDeclaration : Declaration, RootElement { val hmiInterface: HMIInterfaceTypeDeclaration - val subCATs: List var blockDeclaration: CompositeFBTypeDeclaration } \ No newline at end of file diff --git a/code/library/src/main/kotlin/org/fbme/lib/iec61499/declarations/HMIInterfaceTypeDeclaration.kt b/code/library/src/main/kotlin/org/fbme/lib/iec61499/declarations/HMIInterfaceTypeDeclaration.kt index 9a31b1307..34eb52794 100644 --- a/code/library/src/main/kotlin/org/fbme/lib/iec61499/declarations/HMIInterfaceTypeDeclaration.kt +++ b/code/library/src/main/kotlin/org/fbme/lib/iec61499/declarations/HMIInterfaceTypeDeclaration.kt @@ -5,6 +5,7 @@ import org.fbme.lib.common.Declaration import org.fbme.lib.common.Reference interface HMIInterfaceTypeDeclaration : Declaration, ContainedElement { -// val symbol: SymbolDefinition -// val blockDeclaration: Reference + val inputs: MutableList + val outputs: MutableList + val source: String } \ No newline at end of file diff --git a/code/library/src/main/kotlin/org/fbme/lib/iec61499/parser/RootConverter.kt b/code/library/src/main/kotlin/org/fbme/lib/iec61499/parser/RootConverter.kt index f2463666f..0165e9143 100644 --- a/code/library/src/main/kotlin/org/fbme/lib/iec61499/parser/RootConverter.kt +++ b/code/library/src/main/kotlin/org/fbme/lib/iec61499/parser/RootConverter.kt @@ -10,6 +10,7 @@ class RootConverter( ) { fun convertFBType(): FBTypeDeclaration { val root = myDocument.rootElement + var decl = myConfiguration.createBasicFbTypeConverter(arguments()).extract().algorithms.get(0).body!!. if (root.getChild("FBNetwork") != null) { return myConfiguration.createCompositeFbTypeConverter(arguments()).extract() } diff --git a/code/platform/solutions/org.fbme.ide.platform/models/org.fbme.ide.platform.persistence.mps b/code/platform/solutions/org.fbme.ide.platform/models/org.fbme.ide.platform.persistence.mps index 14a464586..dd05a0e1f 100644 --- a/code/platform/solutions/org.fbme.ide.platform/models/org.fbme.ide.platform.persistence.mps +++ b/code/platform/solutions/org.fbme.ide.platform/models/org.fbme.ide.platform.persistence.mps @@ -96,6 +96,7 @@ + @@ -357,6 +358,13 @@ + + + + + + + @@ -3153,6 +3161,24 @@ + + + + + + + + + + + + + + + + + + @@ -3594,36 +3620,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -3794,25 +3790,6 @@ - - - - - - - - - - - - - - - - - - - From bc164aa3318ba6008db6f105edc108ebe77d5b73 Mon Sep 17 00:00:00 2001 From: Valentina Danilova Date: Fri, 21 Apr 2023 16:48:34 +0300 Subject: [PATCH 09/21] converters and printers --- .idea/compiler.xml | 8 + .idea/jarRepositories.xml | 46 +- .mps/runConfigurations/MPS_with_IEC_61499.xml | 6 +- .../org.fbme.ide.iec61499.lang.editor.mps | 141 +---- .../org.fbme.ide.iec61499.lang.structure.mps | 120 +---- ...bme.ide.iec61499.adapter.interfacepart.mps | 506 ++++++++---------- .../org/fbme/lib/iec61499/IEC61499Factory.kt | 1 + .../declarations/CATBlockTypeDeclaration.kt | 7 +- .../HMIInterfaceTypeDeclaration.kt | 8 +- .../iec61499/parser/CATBlockTypeConverter.kt | 15 +- .../fbme/lib/iec61499/parser/RootConverter.kt | 4 +- .../iec61499/stringify/CATBlockTypePrinter.kt | 20 +- .../stringify/RootDeclarationPrinter.kt | 4 +- .../hmi-blocks/JSON_DESERIALIZER.fbt | 76 +++ .../main/resources/hmi-blocks/JSON_FORMER.fbt | 67 +++ .../main/resources/hmi-blocks/JSON_PARSER.fbt | 108 ++++ .../resources/hmi-blocks/JSON_SERIALIZER.fbt | 89 +++ .../resources/hmi-blocks/TYPE_DETECTOR.fbt | 60 +++ .../resources/hmi-blocks/TYPE_SERIALIZER.fbt | 94 ++++ .../importer/BasicFbTypeNxtImporterTest.java | 1 + .../org.fbme.ide.platform.persistence.mps | 357 +++++++++++- .../src/test/kotlin/HmiPrinterTest.kt | 36 ++ 22 files changed, 1202 insertions(+), 572 deletions(-) create mode 100644 code/library/src/main/resources/hmi-blocks/JSON_DESERIALIZER.fbt create mode 100644 code/library/src/main/resources/hmi-blocks/JSON_FORMER.fbt create mode 100644 code/library/src/main/resources/hmi-blocks/JSON_PARSER.fbt create mode 100644 code/library/src/main/resources/hmi-blocks/JSON_SERIALIZER.fbt create mode 100644 code/library/src/main/resources/hmi-blocks/TYPE_DETECTOR.fbt create mode 100644 code/library/src/main/resources/hmi-blocks/TYPE_SERIALIZER.fbt create mode 100644 code/platform/src/test/kotlin/HmiPrinterTest.kt diff --git a/.idea/compiler.xml b/.idea/compiler.xml index c8952aa4d..58d13c02c 100644 --- a/.idea/compiler.xml +++ b/.idea/compiler.xml @@ -1,6 +1,14 @@ + + + + + + + + diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml index dc08c64af..121160ee8 100644 --- a/.idea/jarRepositories.xml +++ b/.idea/jarRepositories.xml @@ -6,36 +6,26 @@ \ No newline at end of file diff --git a/.mps/runConfigurations/MPS_with_IEC_61499.xml b/.mps/runConfigurations/MPS_with_IEC_61499.xml index 20ed40dd2..d787223d3 100644 --- a/.mps/runConfigurations/MPS_with_IEC_61499.xml +++ b/.mps/runConfigurations/MPS_with_IEC_61499.xml @@ -4,15 +4,13 @@ diff --git a/code/language/languages/org.fbme.ide.iec61499.lang/models/org.fbme.ide.iec61499.lang.editor.mps b/code/language/languages/org.fbme.ide.iec61499.lang/models/org.fbme.ide.iec61499.lang.editor.mps index 2819c72df..84cdad963 100644 --- a/code/language/languages/org.fbme.ide.iec61499.lang/models/org.fbme.ide.iec61499.lang.editor.mps +++ b/code/language/languages/org.fbme.ide.iec61499.lang/models/org.fbme.ide.iec61499.lang.editor.mps @@ -4396,26 +4396,29 @@ - + - - - - - - - + + + + - - - - + + + + - + + + + + + + @@ -4423,113 +4426,13 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + diff --git a/code/language/languages/org.fbme.ide.iec61499.lang/models/org.fbme.ide.iec61499.lang.structure.mps b/code/language/languages/org.fbme.ide.iec61499.lang/models/org.fbme.ide.iec61499.lang.structure.mps index ccfc0f531..45e2d2b89 100644 --- a/code/language/languages/org.fbme.ide.iec61499.lang/models/org.fbme.ide.iec61499.lang.structure.mps +++ b/code/language/languages/org.fbme.ide.iec61499.lang/models/org.fbme.ide.iec61499.lang.structure.mps @@ -1564,122 +1564,40 @@ - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - + + - - - - - - + + - - - - + + + - - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - + + + + + + + diff --git a/code/language/solutions/org.fbme.ide.iec61499.adapter/models/org.fbme.ide.iec61499.adapter.interfacepart.mps b/code/language/solutions/org.fbme.ide.iec61499.adapter/models/org.fbme.ide.iec61499.adapter.interfacepart.mps index 8625fca65..69ef97ce9 100644 --- a/code/language/solutions/org.fbme.ide.iec61499.adapter/models/org.fbme.ide.iec61499.adapter.interfacepart.mps +++ b/code/language/solutions/org.fbme.ide.iec61499.adapter/models/org.fbme.ide.iec61499.adapter.interfacepart.mps @@ -7614,135 +7614,281 @@ - - + + + + - - - + + + + + + - - - - - - - - - - - - - - - + + + + + + + + + + + - + + + + + + + - - + + + + + - - - - - - - - - - - - + + + + + + + + - - - - - + + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - + + + + + + + + + + + - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - - - - - + + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - - + + + + + + + + + + + + + + + + + + + + + + + + - - - - + - + + @@ -7759,76 +7905,14 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + @@ -7851,126 +7935,10 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + diff --git a/code/library/src/main/kotlin/org/fbme/lib/iec61499/IEC61499Factory.kt b/code/library/src/main/kotlin/org/fbme/lib/iec61499/IEC61499Factory.kt index 83f63f4b5..99f791479 100644 --- a/code/library/src/main/kotlin/org/fbme/lib/iec61499/IEC61499Factory.kt +++ b/code/library/src/main/kotlin/org/fbme/lib/iec61499/IEC61499Factory.kt @@ -19,6 +19,7 @@ interface IEC61499Factory { fun createBasicFBTypeDeclaration(identifier: Identifier?): BasicFBTypeDeclaration fun createCompositeFBTypeDeclaration(identifier: Identifier?): CompositeFBTypeDeclaration fun createCATBlockTypeDeclaration(identifier: Identifier?): CATBlockTypeDeclaration + fun createHMIBlockTypeDeclaration(identifier: Identifier?): HMIInterfaceTypeDeclaration fun createDeviceDeclaration(identifier: Identifier?): DeviceDeclaration fun createDeviceTypeDeclaration(identifier: Identifier?): DeviceTypeDeclaration fun createParameterAssignment(): ParameterAssignment diff --git a/code/library/src/main/kotlin/org/fbme/lib/iec61499/declarations/CATBlockTypeDeclaration.kt b/code/library/src/main/kotlin/org/fbme/lib/iec61499/declarations/CATBlockTypeDeclaration.kt index 5c96df53c..c9f27cd00 100644 --- a/code/library/src/main/kotlin/org/fbme/lib/iec61499/declarations/CATBlockTypeDeclaration.kt +++ b/code/library/src/main/kotlin/org/fbme/lib/iec61499/declarations/CATBlockTypeDeclaration.kt @@ -2,8 +2,11 @@ package org.fbme.lib.iec61499.declarations import org.fbme.lib.common.Declaration import org.fbme.lib.common.RootElement +import org.fbme.lib.common.Reference + interface CATBlockTypeDeclaration : Declaration, RootElement { - val hmiInterface: HMIInterfaceTypeDeclaration - var blockDeclaration: CompositeFBTypeDeclaration + val hmiInterface: Reference + val blockDeclaration: Reference + val interfaceFileName: String } \ No newline at end of file diff --git a/code/library/src/main/kotlin/org/fbme/lib/iec61499/declarations/HMIInterfaceTypeDeclaration.kt b/code/library/src/main/kotlin/org/fbme/lib/iec61499/declarations/HMIInterfaceTypeDeclaration.kt index 34eb52794..e9bfcdb47 100644 --- a/code/library/src/main/kotlin/org/fbme/lib/iec61499/declarations/HMIInterfaceTypeDeclaration.kt +++ b/code/library/src/main/kotlin/org/fbme/lib/iec61499/declarations/HMIInterfaceTypeDeclaration.kt @@ -1,11 +1,5 @@ package org.fbme.lib.iec61499.declarations -import org.fbme.lib.common.ContainedElement -import org.fbme.lib.common.Declaration -import org.fbme.lib.common.Reference -interface HMIInterfaceTypeDeclaration : Declaration, ContainedElement { - val inputs: MutableList - val outputs: MutableList - val source: String +interface HMIInterfaceTypeDeclaration : FBTypeDeclaration { } \ No newline at end of file diff --git a/code/library/src/main/kotlin/org/fbme/lib/iec61499/parser/CATBlockTypeConverter.kt b/code/library/src/main/kotlin/org/fbme/lib/iec61499/parser/CATBlockTypeConverter.kt index c6bdc4adb..8a9e7525e 100644 --- a/code/library/src/main/kotlin/org/fbme/lib/iec61499/parser/CATBlockTypeConverter.kt +++ b/code/library/src/main/kotlin/org/fbme/lib/iec61499/parser/CATBlockTypeConverter.kt @@ -11,18 +11,9 @@ class CATBlockTypeConverter(arguments: ConverterArguments) : override fun extractDeclarationBody(identifier: Identifier?): CATBlockTypeDeclaration { checkNotNull(element) val fbtd = factory.createCATBlockTypeDeclaration(identifier) - fbtd.blockDeclaration = CompositeBlockConverter(with(this.element.getChild("Composite"))).extract() -// FBInterfaceConverter(this, fbtd).extractInterface() -// FBInterfaceAdaptersConverter(this, fbtd).extractAdapters() -// FBNetworkConverter(with(element.getChild("SubCAT")), fbtd.network).extractNetwork() + fbtd.blockDeclaration.setTargetName(element.getChild("Composite").getAttributeValue("Type")) + fbtd.hmiInterface.setTargetName(element.getChild("HMI").getAttributeValue("Type")) + return fbtd } - private inner class CompositeBlockConverter(arguments: ConverterArguments) : - DeclarationConverterBase(arguments) { - override fun extractDeclarationBody(identifier: Identifier?): CompositeFBTypeDeclaration { - checkNotNull(element) - val fbd = factory.createCompositeFBTypeDeclaration(identifier) - return fbd - } - } } \ No newline at end of file diff --git a/code/library/src/main/kotlin/org/fbme/lib/iec61499/parser/RootConverter.kt b/code/library/src/main/kotlin/org/fbme/lib/iec61499/parser/RootConverter.kt index 0165e9143..3e4233d51 100644 --- a/code/library/src/main/kotlin/org/fbme/lib/iec61499/parser/RootConverter.kt +++ b/code/library/src/main/kotlin/org/fbme/lib/iec61499/parser/RootConverter.kt @@ -10,7 +10,9 @@ class RootConverter( ) { fun convertFBType(): FBTypeDeclaration { val root = myDocument.rootElement - var decl = myConfiguration.createBasicFbTypeConverter(arguments()).extract().algorithms.get(0).body!!. + if (root.getAttribute("UsedInCAT") != null && root.getAttribute("UsedInCAT").value == "TRUE") { + return HMIInterfaceConverter(arguments()).extract() + } if (root.getChild("FBNetwork") != null) { return myConfiguration.createCompositeFbTypeConverter(arguments()).extract() } diff --git a/code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/CATBlockTypePrinter.kt b/code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/CATBlockTypePrinter.kt index 7b7401803..15e06b1d6 100644 --- a/code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/CATBlockTypePrinter.kt +++ b/code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/CATBlockTypePrinter.kt @@ -2,21 +2,29 @@ package org.fbme.lib.iec61499.stringify import org.fbme.lib.iec61499.declarations.CATBlockTypeDeclaration import org.fbme.lib.iec61499.declarations.CompositeFBTypeDeclaration +import org.fbme.lib.iec61499.fbnetwork.FunctionBlockDeclaration import org.jdom.Element class CATBlockTypePrinter(declaration: CATBlockTypeDeclaration) : DeclarationPrinterBase(declaration, "CAT") { override fun printDeclarationBody(element: Element) { element.setAttribute("name", this.element.name) - element.addContent(CompositeBlockPrinter(this.element.blockDeclaration).print()) -// element.addContent(HMIInterfacePrinter(this.element.hmiInterface).print()) -// element.addContent(SubCATPrinter(this.element.subCATs).print()) + element.addContent(CompositePrinter(this.element).print()) + element.addContent(HMIPrinter(this.element).print()) } - private class CompositeBlockPrinter(fb: CompositeFBTypeDeclaration) : - DeclarationPrinterBase(fb, "Composite") { + private class CompositePrinter(fb: CATBlockTypeDeclaration) : + DeclarationPrinterBase(fb, "Composite") { override fun printDeclarationBody(element: Element) { -// element.setAttribute("Type", this.element.typeReference.presentation) + element.setAttribute("Type", this.element.blockDeclaration.presentation) + } + } + + private class HMIPrinter(fb: CATBlockTypeDeclaration) : + DeclarationPrinterBase(fb, "HMI") { + override fun printDeclarationBody(element: Element) { + element.setAttribute("Type", this.element.hmiInterface.presentation) + element.setAttribute("InterfaceFile", this.element.interfaceFileName) } } } \ No newline at end of file diff --git a/code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/RootDeclarationPrinter.kt b/code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/RootDeclarationPrinter.kt index b5f607323..fde14210a 100644 --- a/code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/RootDeclarationPrinter.kt +++ b/code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/RootDeclarationPrinter.kt @@ -2,17 +2,19 @@ package org.fbme.lib.iec61499.stringify import org.fbme.lib.common.Declaration import org.fbme.lib.iec61499.declarations.* +import org.fbme.lib.iec61499.parser.ConverterArguments import org.jdom.DocType import org.jdom.Document import org.jdom.Element -class RootDeclarationPrinter(private val myDeclaration: Declaration) { +class RootDeclarationPrinter(private val myDeclaration: Declaration, val converterArguments: ConverterArguments) { fun print(): Document { val rootElement: Element = when (myDeclaration) { is AdapterTypeDeclaration -> AdapterTypePrinter(myDeclaration).print() is BasicFBTypeDeclaration -> BasicFBTypePrinter(myDeclaration).print() is CompositeFBTypeDeclaration -> CompositeFBTypePrinter(myDeclaration).print() is CATBlockTypeDeclaration -> CATBlockTypePrinter(myDeclaration).print() + is HMIInterfaceTypeDeclaration -> HMIBlockPrinter(myDeclaration, converterArguments).print() is DeviceTypeDeclaration -> DeviceTypePrinter(myDeclaration).print() is ResourceTypeDeclaration -> ResourceTypePrinter(myDeclaration).print() is ServiceInterfaceFBTypeDeclaration -> ServiceInterfaceFBTypePrinter(myDeclaration).print() diff --git a/code/library/src/main/resources/hmi-blocks/JSON_DESERIALIZER.fbt b/code/library/src/main/resources/hmi-blocks/JSON_DESERIALIZER.fbt new file mode 100644 index 000000000..9d8cc093e --- /dev/null +++ b/code/library/src/main/resources/hmi-blocks/JSON_DESERIALIZER.fbt @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/code/library/src/main/resources/hmi-blocks/JSON_FORMER.fbt b/code/library/src/main/resources/hmi-blocks/JSON_FORMER.fbt new file mode 100644 index 000000000..c4d253659 --- /dev/null +++ b/code/library/src/main/resources/hmi-blocks/JSON_FORMER.fbt @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/code/library/src/main/resources/hmi-blocks/JSON_PARSER.fbt b/code/library/src/main/resources/hmi-blocks/JSON_PARSER.fbt new file mode 100644 index 000000000..0ec15d196 --- /dev/null +++ b/code/library/src/main/resources/hmi-blocks/JSON_PARSER.fbt @@ -0,0 +1,108 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/code/library/src/main/resources/hmi-blocks/JSON_SERIALIZER.fbt b/code/library/src/main/resources/hmi-blocks/JSON_SERIALIZER.fbt new file mode 100644 index 000000000..280f68cd2 --- /dev/null +++ b/code/library/src/main/resources/hmi-blocks/JSON_SERIALIZER.fbt @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/code/library/src/main/resources/hmi-blocks/TYPE_DETECTOR.fbt b/code/library/src/main/resources/hmi-blocks/TYPE_DETECTOR.fbt new file mode 100644 index 000000000..ea9ffb7af --- /dev/null +++ b/code/library/src/main/resources/hmi-blocks/TYPE_DETECTOR.fbt @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/code/library/src/main/resources/hmi-blocks/TYPE_SERIALIZER.fbt b/code/library/src/main/resources/hmi-blocks/TYPE_SERIALIZER.fbt new file mode 100644 index 000000000..bdc97c05d --- /dev/null +++ b/code/library/src/main/resources/hmi-blocks/TYPE_SERIALIZER.fbt @@ -0,0 +1,94 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/code/nxt-integration/src/test/java/org/fbme/integration/nxt/importer/BasicFbTypeNxtImporterTest.java b/code/nxt-integration/src/test/java/org/fbme/integration/nxt/importer/BasicFbTypeNxtImporterTest.java index b61570cd7..91c1579b7 100644 --- a/code/nxt-integration/src/test/java/org/fbme/integration/nxt/importer/BasicFbTypeNxtImporterTest.java +++ b/code/nxt-integration/src/test/java/org/fbme/integration/nxt/importer/BasicFbTypeNxtImporterTest.java @@ -3,6 +3,7 @@ import org.fbme.ide.platform.testing.PlatformTestBase; import org.fbme.ide.platform.testing.PlatformTestRunner; import org.fbme.lib.iec61499.declarations.BasicFBTypeDeclaration; +import org.fbme.lib.iec61499.stringify.BasicFBTypePrinter; import org.fbme.lib.st.types.ElementaryType; import org.junit.Assert; import org.junit.Test; diff --git a/code/platform/solutions/org.fbme.ide.platform/models/org.fbme.ide.platform.persistence.mps b/code/platform/solutions/org.fbme.ide.platform/models/org.fbme.ide.platform.persistence.mps index dd05a0e1f..f42548005 100644 --- a/code/platform/solutions/org.fbme.ide.platform/models/org.fbme.ide.platform.persistence.mps +++ b/code/platform/solutions/org.fbme.ide.platform/models/org.fbme.ide.platform.persistence.mps @@ -96,7 +96,6 @@ - @@ -150,6 +149,9 @@ + + + @@ -358,13 +360,6 @@ - - - - - - - @@ -3024,12 +3019,285 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -3061,10 +3329,13 @@ - + + + + @@ -3161,24 +3432,6 @@ - - - - - - - - - - - - - - - - - - @@ -3620,6 +3873,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -3657,6 +3940,7 @@ + @@ -3790,6 +4074,25 @@ + + + + + + + + + + + + + + + + + + + diff --git a/code/platform/src/test/kotlin/HmiPrinterTest.kt b/code/platform/src/test/kotlin/HmiPrinterTest.kt new file mode 100644 index 000000000..759a91da3 --- /dev/null +++ b/code/platform/src/test/kotlin/HmiPrinterTest.kt @@ -0,0 +1,36 @@ +import org.fbme.ide.platform.testing.PlatformTestBase +import org.fbme.ide.platform.testing.PlatformTestRunner +import org.fbme.lib.iec61499.parser.STConverter +import org.fbme.lib.iec61499.stringify.HMIInterfaceTypeGenerator.Companion.generateDispatchIn +import org.fbme.lib.st.types.ElementaryType +import org.jdom.Document +import org.jdom.Element +import org.jdom.output.XMLOutputter +import org.junit.Test +import org.junit.runner.RunWith +import java.io.FileOutputStream +import java.io.OutputStream + + +@RunWith(PlatformTestRunner::class) +class HMIPrinterTest : PlatformTestBase() { + @Test + fun parseTest1() { + print("Started") + var fileName = "DISPATCH_IN.fbt" + val resElement: Element = Element("DISPATCH_IN") + var p = factory.createParameterDeclaration(null) + p.type = ElementaryType.STRING + p.name = "COUNT" + p.initialValue = STConverter.parseLiteral(stFactory, "'1'") + +// generateDispatchIn(resElement, factory, stFactory, listOf(p)) +// resElement.print(PrettyPrinter()) + // List dependentList = new DependentDeclarationPrinter(declaration).print(); + val stream: OutputStream = FileOutputStream(fileName) + val xmlOutputter = XMLOutputter() + var doc = Document() + doc.setRootElement(resElement) + xmlOutputter.output(doc, stream) + } +} \ No newline at end of file From 1a598135192612b6da2e595000060870f7ebab06 Mon Sep 17 00:00:00 2001 From: Valentina Danilova Date: Sat, 13 May 2023 14:02:25 +0300 Subject: [PATCH 10/21] . --- .idea/compiler.xml | 8 ------ .../iec61499/parser/HMIInterfaceConverter.kt | 27 +++++++++++++++++++ .../DependentDeclarationGenerator.kt | 23 ++++++++++++++++ .../stringify/HMIInterfaceTypeGenerator.kt | 4 +-- 4 files changed, 52 insertions(+), 10 deletions(-) create mode 100644 code/library/src/main/kotlin/org/fbme/lib/iec61499/parser/HMIInterfaceConverter.kt create mode 100644 code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/DependentDeclarationGenerator.kt diff --git a/.idea/compiler.xml b/.idea/compiler.xml index 58d13c02c..c8952aa4d 100644 --- a/.idea/compiler.xml +++ b/.idea/compiler.xml @@ -1,14 +1,6 @@ - - - - - - - - diff --git a/code/library/src/main/kotlin/org/fbme/lib/iec61499/parser/HMIInterfaceConverter.kt b/code/library/src/main/kotlin/org/fbme/lib/iec61499/parser/HMIInterfaceConverter.kt new file mode 100644 index 000000000..879d7eead --- /dev/null +++ b/code/library/src/main/kotlin/org/fbme/lib/iec61499/parser/HMIInterfaceConverter.kt @@ -0,0 +1,27 @@ +package org.fbme.lib.iec61499.parser + +import org.fbme.lib.common.Identifier +import org.fbme.lib.common.Reference +import org.fbme.lib.iec61499.declarations.CATBlockTypeDeclaration +import org.fbme.lib.iec61499.declarations.CompositeFBTypeDeclaration +import org.fbme.lib.iec61499.declarations.HMIInterfaceTypeDeclaration +import org.fbme.lib.iec61499.fbnetwork.FunctionBlockDeclaration + +class HMIInterfaceConverter(arguments: ConverterArguments) : + DeclarationConverterBase(arguments) { + override fun extractDeclarationBody(identifier: Identifier?): HMIInterfaceTypeDeclaration { + checkNotNull(element) + val fbtd = factory.createHMIBlockTypeDeclaration(identifier) + val interfaceListElement = element.getChild("InterfaceList") + ParameterDeclarationConverter.extractAll( + with(interfaceListElement.getChild("InputVars")), + fbtd.inputParameters + ) + ParameterDeclarationConverter.extractAll( + with(interfaceListElement.getChild("InputVars")), + fbtd.outputParameters + ) + + return fbtd + } +} \ No newline at end of file diff --git a/code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/DependentDeclarationGenerator.kt b/code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/DependentDeclarationGenerator.kt new file mode 100644 index 000000000..1cefd2826 --- /dev/null +++ b/code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/DependentDeclarationGenerator.kt @@ -0,0 +1,23 @@ +package org.fbme.lib.iec61499.stringify + +import org.fbme.lib.common.Declaration +import org.fbme.lib.common.RootElement +import org.fbme.lib.iec61499.declarations.CATBlockTypeDeclaration +import org.fbme.lib.iec61499.declarations.FBTypeDeclaration +import org.fbme.lib.iec61499.declarations.HMIInterfaceTypeDeclaration +import org.fbme.lib.iec61499.parser.ConverterArguments + +class DependentDeclarationGenerator(private val myDeclaration: Declaration, private val converterArguments: ConverterArguments) { + + + fun generate(): List { + val rootElements: List = when (myDeclaration) { + is HMIInterfaceTypeDeclaration -> HMIInterfaceTypeGenerator(myDeclaration, converterArguments).generateDependents() + else -> error("Unrecognized root declaration") + } + + + return rootElements + } + +} \ No newline at end of file diff --git a/code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/HMIInterfaceTypeGenerator.kt b/code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/HMIInterfaceTypeGenerator.kt index b78854d18..314ff9e0e 100644 --- a/code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/HMIInterfaceTypeGenerator.kt +++ b/code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/HMIInterfaceTypeGenerator.kt @@ -159,8 +159,8 @@ companion object { } return STConverter.parseStatementListWithDeclarations( stFactory, - { t, u -> parameterCollector.apply(t, u) }, - code + code, + { t, u -> parameterCollector.apply(t, u) } ) } From a251f0a6ddaf5bda845530c82ae83a08921b83b4 Mon Sep 17 00:00:00 2001 From: Valentina Danilova Date: Sat, 13 May 2023 14:20:01 +0300 Subject: [PATCH 11/21] support new format of persistence --- .../repository/PlatformDeclarationsScope.kt | 2 +- .../DependentDeclarationGenerator.kt | 3 +- .../lib/iec61499/stringify/HMIBlockPrinter.kt | 12 ++++--- .../stringify/HMIInterfaceTypeGenerator.kt | 33 +++++++------------ .../stringify/RootDeclarationPrinter.kt | 3 +- .../persistence/Iec61499ModelFactory.kt | 9 ++++- 6 files changed, 31 insertions(+), 31 deletions(-) diff --git a/code/language/src/main/kotlin/org/fbme/ide/iec61499/repository/PlatformDeclarationsScope.kt b/code/language/src/main/kotlin/org/fbme/ide/iec61499/repository/PlatformDeclarationsScope.kt index 16a901dab..a0c3f5053 100644 --- a/code/language/src/main/kotlin/org/fbme/ide/iec61499/repository/PlatformDeclarationsScope.kt +++ b/code/language/src/main/kotlin/org/fbme/ide/iec61499/repository/PlatformDeclarationsScope.kt @@ -18,7 +18,7 @@ internal class PlatformDeclarationsScope( } override fun findCATBlockTypeDeclaration(identifier: Identifier): CATBlockTypeDeclaration? { - return myRepository.getAdapter(findNode(identifier), CATBlockTypeDeclaration::class.java) + return findNode(identifier)?.let {myRepository.getAdapter(it, CATBlockTypeDeclaration::class.java)} } override fun findBasicFBTypeDeclaration(identifier: Identifier): BasicFBTypeDeclaration? { diff --git a/code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/DependentDeclarationGenerator.kt b/code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/DependentDeclarationGenerator.kt index 1cefd2826..f9a795f8c 100644 --- a/code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/DependentDeclarationGenerator.kt +++ b/code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/DependentDeclarationGenerator.kt @@ -6,8 +6,9 @@ import org.fbme.lib.iec61499.declarations.CATBlockTypeDeclaration import org.fbme.lib.iec61499.declarations.FBTypeDeclaration import org.fbme.lib.iec61499.declarations.HMIInterfaceTypeDeclaration import org.fbme.lib.iec61499.parser.ConverterArguments +import org.fbme.lib.iec61499.parser.Iec61499ConverterConfiguration -class DependentDeclarationGenerator(private val myDeclaration: Declaration, private val converterArguments: ConverterArguments) { +class DependentDeclarationGenerator(private val myDeclaration: Declaration, private val converterArguments: Iec61499ConverterConfiguration) { fun generate(): List { diff --git a/code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/HMIBlockPrinter.kt b/code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/HMIBlockPrinter.kt index 3435cbf7a..25350ebbc 100644 --- a/code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/HMIBlockPrinter.kt +++ b/code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/HMIBlockPrinter.kt @@ -3,14 +3,16 @@ package org.fbme.lib.iec61499.stringify import org.fbme.lib.iec61499.declarations.CompositeFBTypeDeclaration import org.fbme.lib.iec61499.declarations.HMIInterfaceTypeDeclaration import org.fbme.lib.iec61499.parser.ConverterArguments +import org.fbme.lib.iec61499.parser.Iec61499ConverterConfiguration import org.fbme.lib.iec61499.parser.STConverter import org.fbme.lib.st.types.ElementaryType import org.jdom.Element -class HMIBlockPrinter(declaration: HMIInterfaceTypeDeclaration, val converterArguments: ConverterArguments) : +class HMIBlockPrinter(declaration: HMIInterfaceTypeDeclaration, val converterArguments: Iec61499ConverterConfiguration) : DeclarationPrinterBase(declaration, "FBType") { - + val factory = converterArguments.entryFactory + val stFactory = converterArguments.stEntryFactory override fun printDeclarationBody(element: Element) { element.addContent(FBInterfacePrinterWithAdapters(this.element).print()) val cFB = CompositeFBTypePrinter(generateComposite()).print().children @@ -21,14 +23,14 @@ class HMIBlockPrinter(declaration: HMIInterfaceTypeDeclaration, val converterArg } fun generateComposite(): CompositeFBTypeDeclaration { - var cFB = converterArguments.factory.createCompositeFBTypeDeclaration(null) + var cFB = factory.createCompositeFBTypeDeclaration(null) cFB.name = this.element.name cFB.inputParameters.addAll(this.element.inputParameters) cFB.outputParameters.addAll(this.element.outputParameters) - val initEvent = converterArguments.factory.createEventDeclaration(null) + val initEvent = factory.createEventDeclaration(null) initEvent.name = "INIT" initEvent.associations - val mappingInput = converterArguments.factory.createParameterDeclaration(null) + val mappingInput = factory.createParameterDeclaration(null) mappingInput.name = "MAPPING" mappingInput.type = ElementaryType.STRING cFB.inputEvents.add(initEvent) diff --git a/code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/HMIInterfaceTypeGenerator.kt b/code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/HMIInterfaceTypeGenerator.kt index 314ff9e0e..d2a5e75dc 100644 --- a/code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/HMIInterfaceTypeGenerator.kt +++ b/code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/HMIInterfaceTypeGenerator.kt @@ -8,6 +8,7 @@ import org.fbme.lib.iec61499.fbnetwork.EntryKind import org.fbme.lib.iec61499.fbnetwork.FunctionBlockDeclaration import org.fbme.lib.iec61499.parser.CompositeFBTypeConverter import org.fbme.lib.iec61499.parser.ConverterArguments +import org.fbme.lib.iec61499.parser.Iec61499ConverterConfiguration import org.fbme.lib.iec61499.parser.STConverter import org.fbme.lib.st.STFactory import org.fbme.lib.st.expressions.Expression @@ -17,15 +18,18 @@ import org.fbme.lib.st.types.ElementaryType import org.jdom.Element import java.util.function.BiFunction -class HMIInterfaceTypeGenerator(val declaration: HMIInterfaceTypeDeclaration, val converterArguments: ConverterArguments) { +class HMIInterfaceTypeGenerator(val declaration: HMIInterfaceTypeDeclaration, val converterArguments: Iec61499ConverterConfiguration) { + val factory = converterArguments.entryFactory + val stFactory = converterArguments.stEntryFactory + fun generateDependents(): List { val elements = mutableListOf() - val outFb = generateDispatchOut(converterArguments.factory, converterArguments.stFactory, declaration.outputParameters) + val outFb = generateDispatchOut(factory, stFactory, declaration.outputParameters) elements.add(outFb) val inFb = generateDispatchIn( - converterArguments.factory, - converterArguments.stFactory, + factory, + stFactory, declaration.inputParameters ) elements.add(inFb) @@ -34,21 +38,6 @@ class HMIInterfaceTypeGenerator(val declaration: HMIInterfaceTypeDeclaration, va return elements } - fun printComposite(element: Element, outEl: FunctionBlockDeclaration, inEl: FunctionBlockDeclaration) { - val composite = converterArguments.factory.createCompositeFBTypeDeclaration(null) - composite.network.functionBlocks.add(outEl) - composite.network.functionBlocks.add(inEl) - CompositeFBTypeConverter(converterArguments).extract() -// composite.network.functionBlocks.add(jsonSerializer) -// composite.network.functionBlocks.add(jsonDeserializer) -// composite.network.functionBlocks.add(publish) -// composite.network.functionBlocks.add(subscribe) - val connection = converterArguments.factory.createFBNetworkConnection(EntryKind.EVENT) -// connection.sourceReference(outEl, jsonSerializer) -// connection.sourceReference(inEl, jsonDeserializer) - composite.network.dataConnections - element.addContent(CompositeFBTypePrinter(composite).print()) - } companion object { val CONNECTION_TYPES = listOf( @@ -190,15 +179,15 @@ companion object { private fun createFunctionBlockDeclaration(name: String, type: DataType, x: Int, y: Int, assignments: List): FunctionBlockDeclaration { - val block = converterArguments.factory.createFunctionBlockDeclaration(null) + val block = factory.createFunctionBlockDeclaration(null) block.name = name block.typeReference.setTargetName(type.stringify()) block.x = x block.y = y val parameterAssignments = assignments.map { - val parameterAssign = converterArguments.factory.createParameterAssignment() - parameterAssign.value = STConverter.parseLiteral(converterArguments.stFactory, it) + val parameterAssign = factory.createParameterAssignment() + parameterAssign.value = STConverter.parseLiteral(stFactory, it) // parameterAssign.parameterReference.setTargetName(it.third) parameterAssign } diff --git a/code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/RootDeclarationPrinter.kt b/code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/RootDeclarationPrinter.kt index fde14210a..bda80f13a 100644 --- a/code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/RootDeclarationPrinter.kt +++ b/code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/RootDeclarationPrinter.kt @@ -3,11 +3,12 @@ package org.fbme.lib.iec61499.stringify import org.fbme.lib.common.Declaration import org.fbme.lib.iec61499.declarations.* import org.fbme.lib.iec61499.parser.ConverterArguments +import org.fbme.lib.iec61499.parser.Iec61499ConverterConfiguration import org.jdom.DocType import org.jdom.Document import org.jdom.Element -class RootDeclarationPrinter(private val myDeclaration: Declaration, val converterArguments: ConverterArguments) { +class RootDeclarationPrinter(private val myDeclaration: Declaration, val converterArguments: Iec61499ConverterConfiguration) { fun print(): Document { val rootElement: Element = when (myDeclaration) { is AdapterTypeDeclaration -> AdapterTypePrinter(myDeclaration).print() diff --git a/code/platform/src/main/kotlin/org/fbme/ide/platform/persistence/Iec61499ModelFactory.kt b/code/platform/src/main/kotlin/org/fbme/ide/platform/persistence/Iec61499ModelFactory.kt index bd307a0af..5a41129c8 100644 --- a/code/platform/src/main/kotlin/org/fbme/ide/platform/persistence/Iec61499ModelFactory.kt +++ b/code/platform/src/main/kotlin/org/fbme/ide/platform/persistence/Iec61499ModelFactory.kt @@ -24,6 +24,7 @@ import org.fbme.ide.iec61499.repository.PlatformElement import org.fbme.ide.iec61499.repository.PlatformElementsOwner import org.fbme.ide.iec61499.repository.PlatformRepository import org.fbme.ide.platform.MpsLanguages +import org.fbme.ide.platform.converter.PlatformConverter import org.fbme.ide.platform.converter.PlatformConverter.create import org.fbme.lib.common.Declaration import org.fbme.lib.common.RootElement @@ -270,8 +271,11 @@ class Iec61499ModelFactory : ModelFactory, DataLocationAwareModelFactory { // Write nodes to xml files for (rootNode in model.rootNodes) { + val owner = PlatformElementsOwner() + val conf = PlatformConverter.STANDARD_CONFIG_FACTORY.createConfiguration(owner) + val declaration = platformRepository.getAdapter(rootNode, Declaration::class.java) - val document = RootDeclarationPrinter(declaration!!).print() + val document = RootDeclarationPrinter(declaration!!, conf).print() val folderName = rootNode.getProperty(SNodeUtil.property_BaseConcept_virtualPackage).orEmpty().replace(".", "/") val fileLocalName = rootNode.name + "." + getExtensionOfSource(rootNode, platformRepository) @@ -307,6 +311,7 @@ class Iec61499ModelFactory : ModelFactory, DataLocationAwareModelFactory { const val DEV_FILE_EXT = "dev" const val SEG_FILE_EXT = "seg" const val SYS_FILE_EXT = "sys" + const val CFG_FILE_EXT = "cfg" const val HEADER_FILE_EXT = "iec61499" const val HEADER_FILE = "header.iec61499" @@ -340,6 +345,7 @@ class Iec61499ModelFactory : ModelFactory, DataLocationAwareModelFactory { DEV_FILE_EXT -> (converter.convertDeviceType() as PlatformElement).node SEG_FILE_EXT -> (converter.convertSegmentType() as PlatformElement).node SYS_FILE_EXT -> (converter.convertSystemConfiguration() as PlatformElement).node + CFG_FILE_EXT -> (converter.convertCATConfiguration() as PlatformElement).node else -> null } } @@ -354,6 +360,7 @@ class Iec61499ModelFactory : ModelFactory, DataLocationAwareModelFactory { is DeviceTypeDeclaration -> DEV_FILE_EXT is SegmentTypeDeclaration -> SEG_FILE_EXT is SystemDeclaration -> SYS_FILE_EXT + is CATBlockTypeDeclaration -> SYS_FILE_EXT else -> null } } From dbb6393af298d05b818afbb22e173454eabe5501 Mon Sep 17 00:00:00 2001 From: Valentina Danilova Date: Sun, 14 May 2023 15:23:48 +0300 Subject: [PATCH 12/21] hmi and dependent generation --- .mps/encodings.xml | 4 - .../hmi-blocks/JSON_DESERIALIZER.fbt | 0 .../hmi-blocks/JSON_FORMER.fbt | 0 .../hmi-blocks/JSON_PARSER.fbt | 0 .../hmi-blocks/JSON_SERIALIZER.fbt | 0 .../hmi-blocks/TYPE_DETECTOR.fbt | 0 .../hmi-blocks/TYPE_SERIALIZER.fbt | 0 .../org.fbme.ide.iec61499.lang.editor.mps | 6 + ...bme.ide.iec61499.adapter.interfacepart.mps | 27 +++ .../declarations/CATBlockTypeDeclaration.kt | 2 +- .../iec61499/parser/CATBlockTypeConverter.kt | 2 +- .../iec61499/parser/HMIInterfaceConverter.kt | 2 +- .../fbme/lib/iec61499/parser/RootConverter.kt | 2 +- .../DependentDeclarationGenerator.kt | 2 +- .../lib/iec61499/stringify/HMIBlockPrinter.kt | 201 +++++++++++++++++- .../stringify/HMIInterfaceTypeGenerator.kt | 174 +++++++++------ .../persistence/Iec61499ModelFactory.kt | 23 +- 17 files changed, 366 insertions(+), 79 deletions(-) delete mode 100644 .mps/encodings.xml rename code/{library/src/main/resources => 4diac-integration/solutions/stdlib/models/iec61499.4diac.stdlib}/hmi-blocks/JSON_DESERIALIZER.fbt (100%) rename code/{library/src/main/resources => 4diac-integration/solutions/stdlib/models/iec61499.4diac.stdlib}/hmi-blocks/JSON_FORMER.fbt (100%) rename code/{library/src/main/resources => 4diac-integration/solutions/stdlib/models/iec61499.4diac.stdlib}/hmi-blocks/JSON_PARSER.fbt (100%) rename code/{library/src/main/resources => 4diac-integration/solutions/stdlib/models/iec61499.4diac.stdlib}/hmi-blocks/JSON_SERIALIZER.fbt (100%) rename code/{library/src/main/resources => 4diac-integration/solutions/stdlib/models/iec61499.4diac.stdlib}/hmi-blocks/TYPE_DETECTOR.fbt (100%) rename code/{library/src/main/resources => 4diac-integration/solutions/stdlib/models/iec61499.4diac.stdlib}/hmi-blocks/TYPE_SERIALIZER.fbt (100%) diff --git a/.mps/encodings.xml b/.mps/encodings.xml deleted file mode 100644 index 15a15b218..000000000 --- a/.mps/encodings.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/code/library/src/main/resources/hmi-blocks/JSON_DESERIALIZER.fbt b/code/4diac-integration/solutions/stdlib/models/iec61499.4diac.stdlib/hmi-blocks/JSON_DESERIALIZER.fbt similarity index 100% rename from code/library/src/main/resources/hmi-blocks/JSON_DESERIALIZER.fbt rename to code/4diac-integration/solutions/stdlib/models/iec61499.4diac.stdlib/hmi-blocks/JSON_DESERIALIZER.fbt diff --git a/code/library/src/main/resources/hmi-blocks/JSON_FORMER.fbt b/code/4diac-integration/solutions/stdlib/models/iec61499.4diac.stdlib/hmi-blocks/JSON_FORMER.fbt similarity index 100% rename from code/library/src/main/resources/hmi-blocks/JSON_FORMER.fbt rename to code/4diac-integration/solutions/stdlib/models/iec61499.4diac.stdlib/hmi-blocks/JSON_FORMER.fbt diff --git a/code/library/src/main/resources/hmi-blocks/JSON_PARSER.fbt b/code/4diac-integration/solutions/stdlib/models/iec61499.4diac.stdlib/hmi-blocks/JSON_PARSER.fbt similarity index 100% rename from code/library/src/main/resources/hmi-blocks/JSON_PARSER.fbt rename to code/4diac-integration/solutions/stdlib/models/iec61499.4diac.stdlib/hmi-blocks/JSON_PARSER.fbt diff --git a/code/library/src/main/resources/hmi-blocks/JSON_SERIALIZER.fbt b/code/4diac-integration/solutions/stdlib/models/iec61499.4diac.stdlib/hmi-blocks/JSON_SERIALIZER.fbt similarity index 100% rename from code/library/src/main/resources/hmi-blocks/JSON_SERIALIZER.fbt rename to code/4diac-integration/solutions/stdlib/models/iec61499.4diac.stdlib/hmi-blocks/JSON_SERIALIZER.fbt diff --git a/code/library/src/main/resources/hmi-blocks/TYPE_DETECTOR.fbt b/code/4diac-integration/solutions/stdlib/models/iec61499.4diac.stdlib/hmi-blocks/TYPE_DETECTOR.fbt similarity index 100% rename from code/library/src/main/resources/hmi-blocks/TYPE_DETECTOR.fbt rename to code/4diac-integration/solutions/stdlib/models/iec61499.4diac.stdlib/hmi-blocks/TYPE_DETECTOR.fbt diff --git a/code/library/src/main/resources/hmi-blocks/TYPE_SERIALIZER.fbt b/code/4diac-integration/solutions/stdlib/models/iec61499.4diac.stdlib/hmi-blocks/TYPE_SERIALIZER.fbt similarity index 100% rename from code/library/src/main/resources/hmi-blocks/TYPE_SERIALIZER.fbt rename to code/4diac-integration/solutions/stdlib/models/iec61499.4diac.stdlib/hmi-blocks/TYPE_SERIALIZER.fbt diff --git a/code/language/languages/org.fbme.ide.iec61499.lang/models/org.fbme.ide.iec61499.lang.editor.mps b/code/language/languages/org.fbme.ide.iec61499.lang/models/org.fbme.ide.iec61499.lang.editor.mps index 84cdad963..3d440c81f 100644 --- a/code/language/languages/org.fbme.ide.iec61499.lang/models/org.fbme.ide.iec61499.lang.editor.mps +++ b/code/language/languages/org.fbme.ide.iec61499.lang/models/org.fbme.ide.iec61499.lang.editor.mps @@ -4406,6 +4406,9 @@ + + + @@ -4415,6 +4418,9 @@ + + + diff --git a/code/language/solutions/org.fbme.ide.iec61499.adapter/models/org.fbme.ide.iec61499.adapter.interfacepart.mps b/code/language/solutions/org.fbme.ide.iec61499.adapter/models/org.fbme.ide.iec61499.adapter.interfacepart.mps index a71448294..a50c13f3a 100644 --- a/code/language/solutions/org.fbme.ide.iec61499.adapter/models/org.fbme.ide.iec61499.adapter.interfacepart.mps +++ b/code/language/solutions/org.fbme.ide.iec61499.adapter/models/org.fbme.ide.iec61499.adapter.interfacepart.mps @@ -7740,6 +7740,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/code/library/src/main/kotlin/org/fbme/lib/iec61499/declarations/CATBlockTypeDeclaration.kt b/code/library/src/main/kotlin/org/fbme/lib/iec61499/declarations/CATBlockTypeDeclaration.kt index c9f27cd00..84632a1d4 100644 --- a/code/library/src/main/kotlin/org/fbme/lib/iec61499/declarations/CATBlockTypeDeclaration.kt +++ b/code/library/src/main/kotlin/org/fbme/lib/iec61499/declarations/CATBlockTypeDeclaration.kt @@ -8,5 +8,5 @@ import org.fbme.lib.common.Reference interface CATBlockTypeDeclaration : Declaration, RootElement { val hmiInterface: Reference val blockDeclaration: Reference - val interfaceFileName: String + var interfaceFileName: String } \ No newline at end of file diff --git a/code/library/src/main/kotlin/org/fbme/lib/iec61499/parser/CATBlockTypeConverter.kt b/code/library/src/main/kotlin/org/fbme/lib/iec61499/parser/CATBlockTypeConverter.kt index 8a9e7525e..29a275664 100644 --- a/code/library/src/main/kotlin/org/fbme/lib/iec61499/parser/CATBlockTypeConverter.kt +++ b/code/library/src/main/kotlin/org/fbme/lib/iec61499/parser/CATBlockTypeConverter.kt @@ -13,7 +13,7 @@ class CATBlockTypeConverter(arguments: ConverterArguments) : val fbtd = factory.createCATBlockTypeDeclaration(identifier) fbtd.blockDeclaration.setTargetName(element.getChild("Composite").getAttributeValue("Type")) fbtd.hmiInterface.setTargetName(element.getChild("HMI").getAttributeValue("Type")) - + fbtd.interfaceFileName = element.getChild("HMI").getAttributeValue("InterfaceFile") return fbtd } } \ No newline at end of file diff --git a/code/library/src/main/kotlin/org/fbme/lib/iec61499/parser/HMIInterfaceConverter.kt b/code/library/src/main/kotlin/org/fbme/lib/iec61499/parser/HMIInterfaceConverter.kt index 879d7eead..08b3bcab6 100644 --- a/code/library/src/main/kotlin/org/fbme/lib/iec61499/parser/HMIInterfaceConverter.kt +++ b/code/library/src/main/kotlin/org/fbme/lib/iec61499/parser/HMIInterfaceConverter.kt @@ -18,7 +18,7 @@ class HMIInterfaceConverter(arguments: ConverterArguments) : fbtd.inputParameters ) ParameterDeclarationConverter.extractAll( - with(interfaceListElement.getChild("InputVars")), + with(interfaceListElement.getChild("OutputVars")), fbtd.outputParameters ) diff --git a/code/library/src/main/kotlin/org/fbme/lib/iec61499/parser/RootConverter.kt b/code/library/src/main/kotlin/org/fbme/lib/iec61499/parser/RootConverter.kt index 3e4233d51..cbbff2411 100644 --- a/code/library/src/main/kotlin/org/fbme/lib/iec61499/parser/RootConverter.kt +++ b/code/library/src/main/kotlin/org/fbme/lib/iec61499/parser/RootConverter.kt @@ -10,7 +10,7 @@ class RootConverter( ) { fun convertFBType(): FBTypeDeclaration { val root = myDocument.rootElement - if (root.getAttribute("UsedInCAT") != null && root.getAttribute("UsedInCAT").value == "TRUE") { + if (root.getAttribute("UsedInCAT") != null && root.getAttribute("UsedInCAT").value == "True") { return HMIInterfaceConverter(arguments()).extract() } if (root.getChild("FBNetwork") != null) { diff --git a/code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/DependentDeclarationGenerator.kt b/code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/DependentDeclarationGenerator.kt index f9a795f8c..a63070b9f 100644 --- a/code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/DependentDeclarationGenerator.kt +++ b/code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/DependentDeclarationGenerator.kt @@ -14,7 +14,7 @@ class DependentDeclarationGenerator(private val myDeclaration: Declaration, priv fun generate(): List { val rootElements: List = when (myDeclaration) { is HMIInterfaceTypeDeclaration -> HMIInterfaceTypeGenerator(myDeclaration, converterArguments).generateDependents() - else -> error("Unrecognized root declaration") + else -> listOf() } diff --git a/code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/HMIBlockPrinter.kt b/code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/HMIBlockPrinter.kt index 25350ebbc..7b1efc3a4 100644 --- a/code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/HMIBlockPrinter.kt +++ b/code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/HMIBlockPrinter.kt @@ -1,10 +1,15 @@ package org.fbme.lib.iec61499.stringify +import org.fbme.lib.iec61499.IEC61499Factory import org.fbme.lib.iec61499.declarations.CompositeFBTypeDeclaration +import org.fbme.lib.iec61499.declarations.EventDeclaration import org.fbme.lib.iec61499.declarations.HMIInterfaceTypeDeclaration -import org.fbme.lib.iec61499.parser.ConverterArguments +import org.fbme.lib.iec61499.declarations.ParameterDeclaration +import org.fbme.lib.iec61499.fbnetwork.EntryKind +import org.fbme.lib.iec61499.fbnetwork.FunctionBlockDeclaration import org.fbme.lib.iec61499.parser.Iec61499ConverterConfiguration import org.fbme.lib.iec61499.parser.STConverter +import org.fbme.lib.st.STFactory import org.fbme.lib.st.types.ElementaryType import org.jdom.Element @@ -17,16 +22,31 @@ class HMIBlockPrinter(declaration: HMIInterfaceTypeDeclaration, val converterArg element.addContent(FBInterfacePrinterWithAdapters(this.element).print()) val cFB = CompositeFBTypePrinter(generateComposite()).print().children for (c in cFB) { - element.addContent(c) + element.addContent(c.clone().detach()) } element.setAttribute("UsedInCAT", "True") } fun generateComposite(): CompositeFBTypeDeclaration { - var cFB = factory.createCompositeFBTypeDeclaration(null) + val cFB = factory.createCompositeFBTypeDeclaration(null) cFB.name = this.element.name - cFB.inputParameters.addAll(this.element.inputParameters) - cFB.outputParameters.addAll(this.element.outputParameters) + this.element.inputParameters.forEach { + if (it.name != "MAPPING") { + val pD = factory.createParameterDeclaration(null) + pD.name = it.name + pD.type = it.type + pD.initialValue = it.initialValue + cFB.inputParameters.add(pD) + } + } + this.element.outputParameters.forEach { + val pD = factory.createParameterDeclaration(null) + pD.name = it.name + pD.type = it.type + pD.initialValue = it.initialValue + cFB.outputParameters.add(pD) + } + val initEvent = factory.createEventDeclaration(null) initEvent.name = "INIT" initEvent.associations @@ -34,6 +54,177 @@ class HMIBlockPrinter(declaration: HMIInterfaceTypeDeclaration, val converterArg mappingInput.name = "MAPPING" mappingInput.type = ElementaryType.STRING cFB.inputEvents.add(initEvent) + + if (this.element.inputParameters.size - 1 > 0) { +// NEEDED FUNCTION BLOCKS GENERATION + + cFB.network.functionBlocks.add(generateCommunicationBlock("PUBLISH", factory, stFactory)) + cFB.network.functionBlocks.add(generateFunctionDeclarationNoParam("JSON_SERIALIZER", factory)) + cFB.network.functionBlocks.add(generateFunctionDeclarationNoParam("DISPATCH_OUT_${element.name}", factory)) + +// EVENTS GENERATION + + val cEInitPublish = factory.createFBNetworkConnection(EntryKind.EVENT) + cEInitPublish.sourceReference.setFQName("INIT") + cEInitPublish.targetReference.setFQName("PUBLISH_1.INIT") + cFB.network.eventConnections.add(cEInitPublish) + + val cESerializerPublish = factory.createFBNetworkConnection(EntryKind.EVENT) + cESerializerPublish.sourceReference.setFQName("JSON_SERIALIZER.RES") + cESerializerPublish.targetReference.setFQName("PUBLISH_1.REQ") + cFB.network.eventConnections.add(cESerializerPublish) + + this.element.inputParameters.stream().filter{it.name != "MAPPING"} + .forEach{ + val event = generateEventForParameter(it, factory) + cFB.inputEvents.add(event) + val cEDispatch = factory.createFBNetworkConnection(EntryKind.EVENT) + cEDispatch.sourceReference.setFQName(event.name) + cEDispatch.targetReference.setFQName("DISPATCH_OUT_${this.element.name}.${event.name}") + cFB.network.eventConnections.add(cEDispatch) + } + +// DATA CONNECTIONS GENERATION + + val cDSerializerPublish = factory.createFBNetworkConnection(EntryKind.DATA) + cDSerializerPublish.sourceReference.setFQName("JSON_SERIALIZER.MSG") + cDSerializerPublish.targetReference.setFQName("PUBLISH_1.SD_1") + cFB.network.dataConnections.add(cDSerializerPublish) + + this.element.inputParameters.stream() + .forEach{ + val cDDispatch = factory.createFBNetworkConnection(EntryKind.DATA) + cDDispatch.sourceReference.setFQName(it.name) + cDDispatch.targetReference.setFQName("DISPATCH_OUT_${this.element.name}.${it.name}") + cFB.network.dataConnections.add(cDDispatch) + } + + val cDNameSerialize = factory.createFBNetworkConnection(EntryKind.DATA) + cDNameSerialize.sourceReference.setFQName("DISPATCH_OUT_${this.element.name}.NAME") + cDNameSerialize.targetReference.setFQName("JSON_SERIALIZER.NAME") + cFB.network.dataConnections.add(cDNameSerialize) + +// CONNECTIONS FOR DIFFERENT DATA TYPES + + HMIInterfaceTypeGenerator.CONNECTION_TYPES.forEach { + val cEDispatch = factory.createFBNetworkConnection(EntryKind.EVENT) + cEDispatch.sourceReference.setFQName("DISPATCH_OUT_${this.element.name}.IS_${it.name}") + cEDispatch.targetReference.setFQName("JSON_SERIALIZER.IS_${it.name}") + cFB.network.eventConnections.add(cEDispatch) + val cDDispatch = factory.createFBNetworkConnection(EntryKind.DATA) + cDDispatch.sourceReference.setFQName("DISPATCH_OUT_${this.element.name}.${it.name}_VALUE") + cDDispatch.targetReference.setFQName("JSON_SERIALIZER.${it.name}_VALUE") + cFB.network.dataConnections.add(cDDispatch) + } + + } + + if (this.element.outputParameters.size > 0) { +// NEEDED FUNCTION BLOCKS GENERATION + + cFB.network.functionBlocks.add(generateCommunicationBlock("SUBSCRIBE", factory, stFactory)) + cFB.network.functionBlocks.add(generateFunctionDeclarationNoParam("JSON_DESERIALIZER", factory)) + cFB.network.functionBlocks.add(generateFunctionDeclarationNoParam("DISPATCH_IN_${element.name}", factory)) + +// EVENTS GENERATION + + val cEInitSubscribe = factory.createFBNetworkConnection(EntryKind.EVENT) + cEInitSubscribe.sourceReference.setFQName("INIT") + cEInitSubscribe.targetReference.setFQName("SUBSCRIBE_1.INIT") + cFB.network.eventConnections.add(cEInitSubscribe) + + val cESubscribeDeserialize = factory.createFBNetworkConnection(EntryKind.EVENT) + cESubscribeDeserialize.sourceReference.setFQName("SUBSCRIBE_1.IND") + cESubscribeDeserialize.targetReference.setFQName("JSON_DESERIALIZER.REQ") + cFB.network.eventConnections.add(cESubscribeDeserialize) + + val cEDeserializeDispatch = factory.createFBNetworkConnection(EntryKind.EVENT) + cEDeserializeDispatch.sourceReference.setFQName("JSON_DESERIALIZER.RES") + cEDeserializeDispatch.targetReference.setFQName("DISPATCH_IN_${this.element}.REQ") + cFB.network.eventConnections.add(cEDeserializeDispatch) + + this.element.outputParameters.forEach { + val event = generateEventForParameter(it, factory) + cFB.outputEvents.add(event) + + val cEDispatchRes = factory.createFBNetworkConnection(EntryKind.EVENT) + cEDispatchRes.sourceReference.setFQName("DISPATCH_IN_${this.element}.${event.name}") + cEDispatchRes.targetReference.setFQName(event.name) + cFB.network.eventConnections.add(cEDispatchRes) + } + +// DATA GENERATION + + val cDSubscribeDeserialize = factory.createFBNetworkConnection(EntryKind.DATA) + cDSubscribeDeserialize.sourceReference.setFQName("SUBSCRIBE_1.RD_1") + cDSubscribeDeserialize.targetReference.setFQName("JSON_DESERIALIZER.DATA") + cFB.network.dataConnections.add(cDSubscribeDeserialize) + + val cDDeserializeName = factory.createFBNetworkConnection(EntryKind.DATA) + cDDeserializeName.sourceReference.setFQName("JSON_DESERIALIZER.NAME") + cDDeserializeName.targetReference.setFQName("DISPATCH_IN_${this.element.name}.NAME") + cFB.network.dataConnections.add(cDDeserializeName) + + val cDMappingDispatch = factory.createFBNetworkConnection(EntryKind.DATA) + cDMappingDispatch.sourceReference.setFQName("MAPPING") + cDMappingDispatch.targetReference.setFQName("DISPATCH_IN_${this.element.name}.MAPPING") + cFB.network.dataConnections.add(cDMappingDispatch) + + this.element.outputParameters.forEach { + val cEDispatchRes = factory.createFBNetworkConnection(EntryKind.DATA) + cEDispatchRes.sourceReference.setFQName("DISPATCH_IN_${this.element.name}.${it.name}") + cEDispatchRes.targetReference.setFQName(it.name) + cFB.network.eventConnections.add(cEDispatchRes) + } + + HMIInterfaceTypeGenerator.CONNECTION_TYPES.forEach { + val cDDispatch = factory.createFBNetworkConnection(EntryKind.DATA) + cDDispatch.sourceReference.setFQName("JSON_DESERIALIZER.${it.name}_VALUE") + cDDispatch.targetReference.setFQName("DISPATCH_IN_${this.element.name}.${it.name}_VALUE") + cFB.network.dataConnections.add(cDDispatch) + } + } + + return cFB } + + fun generateEventForParameter(parameter: ParameterDeclaration, factory: IEC61499Factory): EventDeclaration { + val currEvent = factory.createEventDeclaration(null) + currEvent.name = "IS_${parameter.name}" + val assoc = factory.createEventAssociation() + assoc.parameterReference.setTarget(parameter) + currEvent.associations.add(assoc) + return currEvent + } + + fun generateCommunicationBlock(name: String, factory: IEC61499Factory, stFactory: STFactory): FunctionBlockDeclaration { + val fB = factory.createFunctionBlockDeclaration(null) + fB.name = name + val idPD = factory.createParameterDeclaration(null) + idPD.name = "ID" + idPD.type = ElementaryType.WSTRING + val host = factory.createParameterAssignment() + host.parameterReference.setTarget(idPD) + host.value = STConverter.parseLiteral(stFactory, "225.0.0.2:65011") + fB.parameters.add(host) + + val qiPD = factory.createParameterDeclaration(null) + qiPD.name = "QI" + qiPD.type = ElementaryType.BOOL + val qi = factory.createParameterAssignment() + qi.parameterReference.setTarget(idPD) + qi.value = STConverter.parseLiteral(stFactory, "1") + fB.parameters.add(qi) + + fB.typeReference.setTargetName(name) + return fB + } + + fun generateFunctionDeclarationNoParam(name: String, factory: IEC61499Factory): FunctionBlockDeclaration { + val fB = factory.createFunctionBlockDeclaration(null) + fB.name = name + fB.typeReference.setTargetName(name) + return fB + } } \ No newline at end of file diff --git a/code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/HMIInterfaceTypeGenerator.kt b/code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/HMIInterfaceTypeGenerator.kt index d2a5e75dc..8570a836a 100644 --- a/code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/HMIInterfaceTypeGenerator.kt +++ b/code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/HMIInterfaceTypeGenerator.kt @@ -1,13 +1,9 @@ package org.fbme.lib.iec61499.stringify -import org.fbme.lib.common.Declaration import org.fbme.lib.common.Identifier import org.fbme.lib.iec61499.IEC61499Factory import org.fbme.lib.iec61499.declarations.* -import org.fbme.lib.iec61499.fbnetwork.EntryKind import org.fbme.lib.iec61499.fbnetwork.FunctionBlockDeclaration -import org.fbme.lib.iec61499.parser.CompositeFBTypeConverter -import org.fbme.lib.iec61499.parser.ConverterArguments import org.fbme.lib.iec61499.parser.Iec61499ConverterConfiguration import org.fbme.lib.iec61499.parser.STConverter import org.fbme.lib.st.STFactory @@ -15,7 +11,6 @@ import org.fbme.lib.st.expressions.Expression import org.fbme.lib.st.statements.Statement import org.fbme.lib.st.types.DataType import org.fbme.lib.st.types.ElementaryType -import org.jdom.Element import java.util.function.BiFunction class HMIInterfaceTypeGenerator(val declaration: HMIInterfaceTypeDeclaration, val converterArguments: Iec61499ConverterConfiguration) { @@ -25,12 +20,13 @@ class HMIInterfaceTypeGenerator(val declaration: HMIInterfaceTypeDeclaration, va fun generateDependents(): List { val elements = mutableListOf() - val outFb = generateDispatchOut(factory, stFactory, declaration.outputParameters) + val outFb = generateDispatchOut(factory, stFactory, declaration.inputParameters, declaration.name) elements.add(outFb) val inFb = generateDispatchIn( factory, stFactory, - declaration.inputParameters + declaration.outputParameters, + declaration.name ) elements.add(inFb) // val hmiElement = Element(declaration.name) @@ -48,31 +44,69 @@ companion object { ElementaryType.STRING ) - fun generateDispatchOut(factory: IEC61499Factory, stFactory: STFactory, outputVars: List): FBTypeDeclaration { + fun generateDispatchOut(factory: IEC61499Factory, stFactory: STFactory, outputVars: List, name: String = ""): FBTypeDeclaration { val bfb = factory.createBasicFBTypeDeclaration(null) + bfb.name = "DISPATCH_OUT_${name}" - for (oV in outputVars) { + val startState = factory.createStateDeclaration(null) + startState.name = "START" + bfb.ecc.states.add(startState) + val nameDeclaration = generateParameterDeclaration(factory, "NAME", ElementaryType.STRING, listOf()) + val mappingDeclaration = generateParameterDeclaration(factory, "MAPPING", ElementaryType.STRING, listOf()) + bfb.inputParameters.add(mappingDeclaration) + bfb.outputParameters.add(nameDeclaration) + + val outConnections = generateTypedConnections(factory, listOf(), CONNECTION_TYPES) + bfb.outputParameters.addAll(outConnections) + val typedEventsMap = mutableMapOf() + outConnections.forEach { + val typedEvent = factory.createEventDeclaration(null) + typedEvent.name = "IS_${it.type}" + val assoc = factory.createEventAssociation() + assoc.parameterReference.setTarget(it) + typedEvent.associations.add(assoc) + + val nameAssoc = factory.createEventAssociation() + nameAssoc.parameterReference.setTarget(nameDeclaration) + typedEvent.associations.add(nameAssoc) + bfb.outputEvents.add(typedEvent) + typedEventsMap.put(it.type!!, typedEvent) } - for (oV in outputVars) { + + for (iV in outputVars) { val state = factory.createStateDeclaration(null) - state.name = "SET_${oV.name}" + state.name = "SET_${iV.name}" val action = factory.createStateAction() val event = factory.createEventDeclaration(null) - val eventAssociation = factory.createEventAssociation() - eventAssociation.parameterReference.setTarget(factory.createParameterDeclaration(null)) - event.name = "RES_${oV.type}" - event.associations.add(eventAssociation) -// action.event.setTarget(PortPath.createEventPortPath(bfb, event)) + event.name = "IS_${iV.name}" + val mappingAssoc = factory.createEventAssociation() + mappingAssoc.parameterReference.setTarget(mappingDeclaration) + event.associations.add(mappingAssoc) + val currParameter = generateParameterDeclaration(factory, iV.name, iV.type, listOf(event)) + currParameter.initialValue = iV.initialValue + bfb.inputParameters.add(currParameter) + bfb.inputEvents.add(event) val algorithm = factory.createAlgorithmDeclaration(null) - algorithm.name = "set${oV.name}" + algorithm.name = "set${iV.name}" val algorithmBody = factory.createAlgorithmBody(AlgorithmLanguage.ST) - val outCode = generateOutCode(oV, algorithm, factory, stFactory) + val outCode = generateOutCode(iV, algorithm, factory, stFactory) algorithmBody.statements.addAll(outCode) algorithm.body = algorithmBody - stFactory.createVariableReference() + action.algorithm.setTarget(algorithm) + bfb.algorithms.add(algorithm) state.actions.add(action) bfb.ecc.states.add(state) + + val fromStartTransition = factory.createStateTransition() + fromStartTransition.condition.eventReference.setFQName("IS_${iV.name}") + fromStartTransition.sourceReference.setTarget(startState) + fromStartTransition.targetReference.setTarget(state) + bfb.ecc.transitions.add(fromStartTransition) + val toStartTransition = factory.createStateTransition() + toStartTransition.sourceReference.setTarget(state) + toStartTransition.targetReference.setTarget(startState) + bfb.ecc.transitions.add(toStartTransition) } return bfb @@ -85,58 +119,88 @@ companion object { val startState = factory.createStateDeclaration(null) startState.name = "START" bfb.ecc.states.add(startState) - val inConnections = generateTypedConnections(factory, CONNECTION_TYPES) + val reqEvent = factory.createEventDeclaration(null) + reqEvent.name = "REQ" + bfb.inputEvents.add(reqEvent) + val inConnections = generateTypedConnections(factory, listOf(reqEvent), CONNECTION_TYPES) + val nameDeclaration = generateParameterDeclaration(factory, "NAME", ElementaryType.STRING, listOf(reqEvent)) + val mappingDeclaration = generateParameterDeclaration(factory, "MAPPING", ElementaryType.STRING, listOf(reqEvent)) bfb.inputParameters.addAll(inConnections) - for (oV in inputVars) { - val state = factory.createStateDeclaration(null) - state.name = "SET_${oV.name}" - val action = factory.createStateAction() + bfb.inputParameters.add(nameDeclaration) + bfb.inputParameters.add(mappingDeclaration) + for (iV in inputVars) { + if (iV.name == "MAPPING") { + continue + } + val event = factory.createEventDeclaration(null) val eventAssociation = factory.createEventAssociation() + + val state = factory.createStateDeclaration(null) + state.name = "SET_${iV.name}" + val action = factory.createStateAction() val currParameter = factory.createParameterDeclaration(null) - currParameter.name = oV.name - currParameter.type = oV.type - currParameter.initialValue = oV.initialValue + currParameter.name = iV.name + currParameter.type = iV.type + currParameter.initialValue = iV.initialValue bfb.outputParameters.add(currParameter) eventAssociation.parameterReference.setTarget(currParameter) - event.name = "RES_${oV.type}" + event.name = "IS_${iV.name}" event.associations.add(eventAssociation) -// action.event.setTarget(PortPath.createEventPortPath(bfb, event)) + bfb.outputEvents.add(event) val algorithm = factory.createAlgorithmDeclaration(null) - algorithm.name = "set${oV.name}" + algorithm.name = "set${iV.name}" val algorithmBody = factory.createAlgorithmBody(AlgorithmLanguage.ST) - val outCode = generateInCode(oV, algorithm, factory, stFactory) + val outCode = generateInCode(iV, algorithm, factory, stFactory) algorithmBody.statements.addAll(outCode) algorithm.body = algorithmBody action.algorithm.setTarget(algorithm) bfb.algorithms.add(algorithm) state.actions.add(action) bfb.ecc.states.add(state) + val fromStartTransition = factory.createStateTransition() + fromStartTransition.condition.setGuardCondition(generateInGuard(iV, stFactory)) + fromStartTransition.sourceReference.setTarget(startState) + fromStartTransition.targetReference.setTarget(state) + bfb.ecc.transitions.add(fromStartTransition) + val toStartTransition = factory.createStateTransition() + toStartTransition.sourceReference.setTarget(state) + toStartTransition.targetReference.setTarget(startState) + bfb.ecc.transitions.add(toStartTransition) } -// for (oV in inputVars) { -// val stateTransition = factory.createStateTransition() -// stateTransition.condition.setGuardCondition(generateInGuard(oV, stFactory)) -// bfb.ecc.transitions.add(stateTransition) -// } return bfb } - fun generateTypedConnections(factory: IEC61499Factory, types: List): List { + fun generateTypedConnections(factory: IEC61499Factory, events: List, types: List): List { val resTypes = mutableListOf() types.forEach { val p = factory.createParameterDeclaration(null) p.type = it p.name = "${p.type}_VALUE" resTypes.add(p) + events.forEach { + val assoc = factory.createEventAssociation() + assoc.parameterReference.setTarget(p) + it.associations.add(assoc) + } } - val p = factory.createParameterDeclaration(null) - p.type = ElementaryType.STRING - p.name = "NAME" - resTypes.add(p) return resTypes } + fun generateParameterDeclaration(factory: IEC61499Factory, name: String, type: DataType?, associatedEvents: List): ParameterDeclaration { + val p_ = factory.createParameterDeclaration(null) + p_.type = type + p_.name = name + associatedEvents.forEach { + val assoc = factory.createEventAssociation() + assoc.parameterReference.setTarget(p_) + it.associations.add(assoc) + } + return p_ + } + + fun generateCode(code: String, factory: IEC61499Factory, stFactory: STFactory, algorithmDeclaration: AlgorithmDeclaration): List { val parameterCollector = BiFunction { name: Identifier?, type: DataType? -> @@ -154,44 +218,26 @@ companion object { } fun generateOutCode(p: ParameterDeclaration, algorithmDeclaration: AlgorithmDeclaration, factory: IEC61499Factory, stFactory: STFactory): List { - var code = "VAR \n" + + val code = "VAR \n" + "TAG: STRING;\n" + "END_VAR;" + "TAG:= '#${p.name}';\n" + "NAME:=CONCAT(MAPPING, TAG);\n" + - "VALUE:=${p.name};]]>" - var statementList = generateCode(code, factory, stFactory, algorithmDeclaration) + "${p.type}_VALUE:=${p.name};]]>" + val statementList = generateCode(code, factory, stFactory, algorithmDeclaration) return statementList } fun generateInCode(p: ParameterDeclaration, algorithmDeclaration: AlgorithmDeclaration, factory: IEC61499Factory, stFactory: STFactory): List { - var code = "${p.name}:= ${p.type!!.stringify()}_VALUE;" + val code = "${p.name}:= ${p.type!!.stringify()}_VALUE;" return generateCode(code, factory, stFactory, algorithmDeclaration) } fun generateInGuard(p: ParameterDeclaration, stFactory: STFactory): Expression { - var code = "(LEFT(NAME, LEN(NAME) - 7) = MAPPING) AND (RIGHT(NAME, LEN(NAME) - LEN(NAME) + ${p.name.length + 1}) = '#${p.name}')" + val code = "(LEFT(NAME, LEN(NAME) - 7) = MAPPING) AND (RIGHT(NAME, LEN(NAME) - LEN(NAME) + ${p.name.length + 1}) = '#${p.name}')" return STConverter.parseExpression(stFactory, code)!! } } - - - private fun createFunctionBlockDeclaration(name: String, type: DataType, x: Int, y: Int, assignments: List): FunctionBlockDeclaration { - val block = factory.createFunctionBlockDeclaration(null) - block.name = name - block.typeReference.setTargetName(type.stringify()) - block.x = x - block.y = y - - val parameterAssignments = assignments.map { - val parameterAssign = factory.createParameterAssignment() - parameterAssign.value = STConverter.parseLiteral(stFactory, it) -// parameterAssign.parameterReference.setTargetName(it.third) - parameterAssign - } - block.parameters.addAll(parameterAssignments) - return block - } } \ No newline at end of file diff --git a/code/platform/src/main/kotlin/org/fbme/ide/platform/persistence/Iec61499ModelFactory.kt b/code/platform/src/main/kotlin/org/fbme/ide/platform/persistence/Iec61499ModelFactory.kt index 5a41129c8..3a1c9395a 100644 --- a/code/platform/src/main/kotlin/org/fbme/ide/platform/persistence/Iec61499ModelFactory.kt +++ b/code/platform/src/main/kotlin/org/fbme/ide/platform/persistence/Iec61499ModelFactory.kt @@ -29,6 +29,7 @@ import org.fbme.ide.platform.converter.PlatformConverter.create import org.fbme.lib.common.Declaration import org.fbme.lib.common.RootElement import org.fbme.lib.iec61499.declarations.* +import org.fbme.lib.iec61499.stringify.DependentDeclarationGenerator import org.fbme.lib.iec61499.stringify.RootDeclarationPrinter import org.jdom.Document import org.jetbrains.mps.openapi.model.SModel @@ -46,6 +47,7 @@ import java.io.InputStreamReader import java.io.OutputStream import java.util.* import java.util.stream.Collectors +import kotlin.io.path.Path class Iec61499ModelFactory : ModelFactory, DataLocationAwareModelFactory { private fun supportedFileExtension(fileExt: String): Boolean { @@ -56,6 +58,7 @@ class Iec61499ModelFactory : ModelFactory, DataLocationAwareModelFactory { || fileExt == DEV_FILE_EXT || fileExt == SYS_FILE_EXT || fileExt == SEG_FILE_EXT + || fileExt == CFG_FILE_EXT } override fun supports(dataSource: DataSource): Boolean { @@ -269,6 +272,24 @@ class Iec61499ModelFactory : ModelFactory, DataLocationAwareModelFactory { .getComponent(MPSCoreComponents::class.java).moduleRepository val platformRepository = PlatformRepository(repository) + val dependents = mutableListOf() + for (rootNode in model.rootNodes) { + val owner = PlatformElementsOwner() + val conf = PlatformConverter.STANDARD_CONFIG_FACTORY.createConfiguration(owner) + + val declaration = platformRepository.getAdapter(rootNode, Declaration::class.java) + + val els = DependentDeclarationGenerator(declaration, conf).generate() + els.forEach { + val node = (it as PlatformElement).node + node.setProperty(SNodeUtil.property_BaseConcept_virtualPackage, rootNode.getProperty(SNodeUtil.property_BaseConcept_virtualPackage).orEmpty()) + dependents.add(node) + } + } + + LOG.info("Dependents size: {}", dependents.size) + dependents.forEach { model.addRootNode(it) } + // Write nodes to xml files for (rootNode in model.rootNodes) { val owner = PlatformElementsOwner() @@ -360,7 +381,7 @@ class Iec61499ModelFactory : ModelFactory, DataLocationAwareModelFactory { is DeviceTypeDeclaration -> DEV_FILE_EXT is SegmentTypeDeclaration -> SEG_FILE_EXT is SystemDeclaration -> SYS_FILE_EXT - is CATBlockTypeDeclaration -> SYS_FILE_EXT + is CATBlockTypeDeclaration -> CFG_FILE_EXT else -> null } } From 6d1dddd2f4300da8a2862dc7dd66f7bbb305ddef Mon Sep 17 00:00:00 2001 From: Valentina Danilova Date: Wed, 17 May 2023 14:58:49 +0300 Subject: [PATCH 13/21] generators --- .mps/modules.xml | 1 + .../org.fbme.ide.integration.fordiac.mps | 13 + .../org.fbme.ide.iec61499.lang.actions.mps | 3 + .../org.fbme.ide.iec61499.lang.editor.mps | 21 +- .../org.fbme.ide.iec61499.lang.intentions.mps | 268 ++++++++++++++++++ .../org.fbme.ide.iec61499.lang.mpl | 4 + .../repository/PlatformElementsOwner.kt | 2 +- .../HMIInterfaceTypeDeclaration.kt | 2 +- .../lib/iec61499/stringify/HMIBlockPrinter.kt | 221 +-------------- .../stringify/HMIInterfaceTypeGenerator.kt | 202 ++++++++++++- .../persistence/Iec61499ModelFactory.kt | 39 ++- .../src/test/kotlin/HmiPrinterTest.kt | 36 --- solutions/WaterTank/WaterTank.msd | 30 ++ .../WaterTank/models/WaterTank.water_tank.mps | 18 ++ 14 files changed, 595 insertions(+), 265 deletions(-) create mode 100644 code/language/languages/org.fbme.ide.iec61499.lang/models/org.fbme.ide.iec61499.lang.intentions.mps delete mode 100644 code/platform/src/test/kotlin/HmiPrinterTest.kt create mode 100644 solutions/WaterTank/WaterTank.msd create mode 100644 solutions/WaterTank/models/WaterTank.water_tank.mps diff --git a/.mps/modules.xml b/.mps/modules.xml index 13a61f80f..9ca59999e 100644 --- a/.mps/modules.xml +++ b/.mps/modules.xml @@ -33,6 +33,7 @@ + \ No newline at end of file diff --git a/code/4diac-integration/solutions/org.fbme.ide.integration.fordiac/models/org.fbme.ide.integration.fordiac.mps b/code/4diac-integration/solutions/org.fbme.ide.integration.fordiac/models/org.fbme.ide.integration.fordiac.mps index d79377fa0..4c8fe5821 100644 --- a/code/4diac-integration/solutions/org.fbme.ide.integration.fordiac/models/org.fbme.ide.integration.fordiac.mps +++ b/code/4diac-integration/solutions/org.fbme.ide.integration.fordiac/models/org.fbme.ide.integration.fordiac.mps @@ -474,6 +474,7 @@ + @@ -487,6 +488,7 @@ + @@ -3052,6 +3054,17 @@ + + + + + + + + + + + diff --git a/code/language/languages/org.fbme.ide.iec61499.lang/models/org.fbme.ide.iec61499.lang.actions.mps b/code/language/languages/org.fbme.ide.iec61499.lang/models/org.fbme.ide.iec61499.lang.actions.mps index 957e003e7..299199ef6 100644 --- a/code/language/languages/org.fbme.ide.iec61499.lang/models/org.fbme.ide.iec61499.lang.actions.mps +++ b/code/language/languages/org.fbme.ide.iec61499.lang/models/org.fbme.ide.iec61499.lang.actions.mps @@ -114,5 +114,8 @@ + + + diff --git a/code/language/languages/org.fbme.ide.iec61499.lang/models/org.fbme.ide.iec61499.lang.editor.mps b/code/language/languages/org.fbme.ide.iec61499.lang/models/org.fbme.ide.iec61499.lang.editor.mps index 3d440c81f..537cf030b 100644 --- a/code/language/languages/org.fbme.ide.iec61499.lang/models/org.fbme.ide.iec61499.lang.editor.mps +++ b/code/language/languages/org.fbme.ide.iec61499.lang/models/org.fbme.ide.iec61499.lang.editor.mps @@ -170,6 +170,7 @@ + @@ -4413,7 +4414,10 @@ - + + + + @@ -4433,12 +4437,21 @@ - - - + + + + + + + + + + + + diff --git a/code/language/languages/org.fbme.ide.iec61499.lang/models/org.fbme.ide.iec61499.lang.intentions.mps b/code/language/languages/org.fbme.ide.iec61499.lang/models/org.fbme.ide.iec61499.lang.intentions.mps new file mode 100644 index 000000000..e6a4884b9 --- /dev/null +++ b/code/language/languages/org.fbme.ide.iec61499.lang/models/org.fbme.ide.iec61499.lang.intentions.mps @@ -0,0 +1,268 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/code/language/languages/org.fbme.ide.iec61499.lang/org.fbme.ide.iec61499.lang.mpl b/code/language/languages/org.fbme.ide.iec61499.lang/org.fbme.ide.iec61499.lang.mpl index 9304586c9..5e19666f5 100644 --- a/code/language/languages/org.fbme.ide.iec61499.lang/org.fbme.ide.iec61499.lang.mpl +++ b/code/language/languages/org.fbme.ide.iec61499.lang/org.fbme.ide.iec61499.lang.mpl @@ -73,6 +73,7 @@ 1db6de07-b355-4c0f-9979-75b4ac1e8215(org.fbme.lib) ce018f97-56b9-4ee7-9b5f-2d462b6628bf(org.fbme.platform.lib) d7eb0a2a-bd50-4576-beae-e4a89db35f20(jetbrains.mps.lang.scopes.runtime) + 1ed103c3-3aa6-49b7-9c21-6765ee11f224(MPS.Editor) @@ -125,7 +126,10 @@ + + + diff --git a/code/language/src/main/kotlin/org/fbme/ide/iec61499/repository/PlatformElementsOwner.kt b/code/language/src/main/kotlin/org/fbme/ide/iec61499/repository/PlatformElementsOwner.kt index 4dd6c3a65..12ad891fb 100644 --- a/code/language/src/main/kotlin/org/fbme/ide/iec61499/repository/PlatformElementsOwner.kt +++ b/code/language/src/main/kotlin/org/fbme/ide/iec61499/repository/PlatformElementsOwner.kt @@ -15,7 +15,7 @@ open class PlatformElementsOwner { if (adapter == null) { elements.remove(node) } - return requiredClass.cast(adapter)!! + return requiredClass.cast(adapter) } private fun adapt(node: SNode): Element? { diff --git a/code/library/src/main/kotlin/org/fbme/lib/iec61499/declarations/HMIInterfaceTypeDeclaration.kt b/code/library/src/main/kotlin/org/fbme/lib/iec61499/declarations/HMIInterfaceTypeDeclaration.kt index e9bfcdb47..8a4908a4f 100644 --- a/code/library/src/main/kotlin/org/fbme/lib/iec61499/declarations/HMIInterfaceTypeDeclaration.kt +++ b/code/library/src/main/kotlin/org/fbme/lib/iec61499/declarations/HMIInterfaceTypeDeclaration.kt @@ -1,5 +1,5 @@ package org.fbme.lib.iec61499.declarations -interface HMIInterfaceTypeDeclaration : FBTypeDeclaration { +interface HMIInterfaceTypeDeclaration : FBTypeDeclaration{ } \ No newline at end of file diff --git a/code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/HMIBlockPrinter.kt b/code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/HMIBlockPrinter.kt index 7b1efc3a4..7eaea2f42 100644 --- a/code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/HMIBlockPrinter.kt +++ b/code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/HMIBlockPrinter.kt @@ -1,230 +1,23 @@ package org.fbme.lib.iec61499.stringify -import org.fbme.lib.iec61499.IEC61499Factory -import org.fbme.lib.iec61499.declarations.CompositeFBTypeDeclaration -import org.fbme.lib.iec61499.declarations.EventDeclaration import org.fbme.lib.iec61499.declarations.HMIInterfaceTypeDeclaration -import org.fbme.lib.iec61499.declarations.ParameterDeclaration -import org.fbme.lib.iec61499.fbnetwork.EntryKind -import org.fbme.lib.iec61499.fbnetwork.FunctionBlockDeclaration import org.fbme.lib.iec61499.parser.Iec61499ConverterConfiguration -import org.fbme.lib.iec61499.parser.STConverter -import org.fbme.lib.st.STFactory -import org.fbme.lib.st.types.ElementaryType import org.jdom.Element class HMIBlockPrinter(declaration: HMIInterfaceTypeDeclaration, val converterArguments: Iec61499ConverterConfiguration) : - DeclarationPrinterBase(declaration, "FBType") { + DeclarationPrinterBase(declaration, "HMIDeclaration") { val factory = converterArguments.entryFactory val stFactory = converterArguments.stEntryFactory override fun printDeclarationBody(element: Element) { element.addContent(FBInterfacePrinterWithAdapters(this.element).print()) - val cFB = CompositeFBTypePrinter(generateComposite()).print().children - for (c in cFB) { - element.addContent(c.clone().detach()) - } +// val cFB = CompositeFBTypePrinter(HMIInterfaceTypeGenerator.generateComposite(factory, stFactory, this.element)).print().children +// for (c in cFB) { +// element.addContent(c.clone().detach()) +// } + addNullableContent(element, ParameterDeclarationPrinter.printAll("InputVars", this.element.inputParameters)) + addNullableContent(element, ParameterDeclarationPrinter.printAll("OutputVars", this.element.outputParameters)) element.setAttribute("UsedInCAT", "True") } - fun generateComposite(): CompositeFBTypeDeclaration { - val cFB = factory.createCompositeFBTypeDeclaration(null) - cFB.name = this.element.name - this.element.inputParameters.forEach { - if (it.name != "MAPPING") { - val pD = factory.createParameterDeclaration(null) - pD.name = it.name - pD.type = it.type - pD.initialValue = it.initialValue - cFB.inputParameters.add(pD) - } - } - this.element.outputParameters.forEach { - val pD = factory.createParameterDeclaration(null) - pD.name = it.name - pD.type = it.type - pD.initialValue = it.initialValue - cFB.outputParameters.add(pD) - } - - val initEvent = factory.createEventDeclaration(null) - initEvent.name = "INIT" - initEvent.associations - val mappingInput = factory.createParameterDeclaration(null) - mappingInput.name = "MAPPING" - mappingInput.type = ElementaryType.STRING - cFB.inputEvents.add(initEvent) - - if (this.element.inputParameters.size - 1 > 0) { -// NEEDED FUNCTION BLOCKS GENERATION - - cFB.network.functionBlocks.add(generateCommunicationBlock("PUBLISH", factory, stFactory)) - cFB.network.functionBlocks.add(generateFunctionDeclarationNoParam("JSON_SERIALIZER", factory)) - cFB.network.functionBlocks.add(generateFunctionDeclarationNoParam("DISPATCH_OUT_${element.name}", factory)) - -// EVENTS GENERATION - - val cEInitPublish = factory.createFBNetworkConnection(EntryKind.EVENT) - cEInitPublish.sourceReference.setFQName("INIT") - cEInitPublish.targetReference.setFQName("PUBLISH_1.INIT") - cFB.network.eventConnections.add(cEInitPublish) - - val cESerializerPublish = factory.createFBNetworkConnection(EntryKind.EVENT) - cESerializerPublish.sourceReference.setFQName("JSON_SERIALIZER.RES") - cESerializerPublish.targetReference.setFQName("PUBLISH_1.REQ") - cFB.network.eventConnections.add(cESerializerPublish) - - this.element.inputParameters.stream().filter{it.name != "MAPPING"} - .forEach{ - val event = generateEventForParameter(it, factory) - cFB.inputEvents.add(event) - val cEDispatch = factory.createFBNetworkConnection(EntryKind.EVENT) - cEDispatch.sourceReference.setFQName(event.name) - cEDispatch.targetReference.setFQName("DISPATCH_OUT_${this.element.name}.${event.name}") - cFB.network.eventConnections.add(cEDispatch) - } - -// DATA CONNECTIONS GENERATION - - val cDSerializerPublish = factory.createFBNetworkConnection(EntryKind.DATA) - cDSerializerPublish.sourceReference.setFQName("JSON_SERIALIZER.MSG") - cDSerializerPublish.targetReference.setFQName("PUBLISH_1.SD_1") - cFB.network.dataConnections.add(cDSerializerPublish) - - this.element.inputParameters.stream() - .forEach{ - val cDDispatch = factory.createFBNetworkConnection(EntryKind.DATA) - cDDispatch.sourceReference.setFQName(it.name) - cDDispatch.targetReference.setFQName("DISPATCH_OUT_${this.element.name}.${it.name}") - cFB.network.dataConnections.add(cDDispatch) - } - - val cDNameSerialize = factory.createFBNetworkConnection(EntryKind.DATA) - cDNameSerialize.sourceReference.setFQName("DISPATCH_OUT_${this.element.name}.NAME") - cDNameSerialize.targetReference.setFQName("JSON_SERIALIZER.NAME") - cFB.network.dataConnections.add(cDNameSerialize) - -// CONNECTIONS FOR DIFFERENT DATA TYPES - - HMIInterfaceTypeGenerator.CONNECTION_TYPES.forEach { - val cEDispatch = factory.createFBNetworkConnection(EntryKind.EVENT) - cEDispatch.sourceReference.setFQName("DISPATCH_OUT_${this.element.name}.IS_${it.name}") - cEDispatch.targetReference.setFQName("JSON_SERIALIZER.IS_${it.name}") - cFB.network.eventConnections.add(cEDispatch) - val cDDispatch = factory.createFBNetworkConnection(EntryKind.DATA) - cDDispatch.sourceReference.setFQName("DISPATCH_OUT_${this.element.name}.${it.name}_VALUE") - cDDispatch.targetReference.setFQName("JSON_SERIALIZER.${it.name}_VALUE") - cFB.network.dataConnections.add(cDDispatch) - } - - } - - if (this.element.outputParameters.size > 0) { -// NEEDED FUNCTION BLOCKS GENERATION - - cFB.network.functionBlocks.add(generateCommunicationBlock("SUBSCRIBE", factory, stFactory)) - cFB.network.functionBlocks.add(generateFunctionDeclarationNoParam("JSON_DESERIALIZER", factory)) - cFB.network.functionBlocks.add(generateFunctionDeclarationNoParam("DISPATCH_IN_${element.name}", factory)) - -// EVENTS GENERATION - - val cEInitSubscribe = factory.createFBNetworkConnection(EntryKind.EVENT) - cEInitSubscribe.sourceReference.setFQName("INIT") - cEInitSubscribe.targetReference.setFQName("SUBSCRIBE_1.INIT") - cFB.network.eventConnections.add(cEInitSubscribe) - - val cESubscribeDeserialize = factory.createFBNetworkConnection(EntryKind.EVENT) - cESubscribeDeserialize.sourceReference.setFQName("SUBSCRIBE_1.IND") - cESubscribeDeserialize.targetReference.setFQName("JSON_DESERIALIZER.REQ") - cFB.network.eventConnections.add(cESubscribeDeserialize) - - val cEDeserializeDispatch = factory.createFBNetworkConnection(EntryKind.EVENT) - cEDeserializeDispatch.sourceReference.setFQName("JSON_DESERIALIZER.RES") - cEDeserializeDispatch.targetReference.setFQName("DISPATCH_IN_${this.element}.REQ") - cFB.network.eventConnections.add(cEDeserializeDispatch) - - this.element.outputParameters.forEach { - val event = generateEventForParameter(it, factory) - cFB.outputEvents.add(event) - - val cEDispatchRes = factory.createFBNetworkConnection(EntryKind.EVENT) - cEDispatchRes.sourceReference.setFQName("DISPATCH_IN_${this.element}.${event.name}") - cEDispatchRes.targetReference.setFQName(event.name) - cFB.network.eventConnections.add(cEDispatchRes) - } - -// DATA GENERATION - - val cDSubscribeDeserialize = factory.createFBNetworkConnection(EntryKind.DATA) - cDSubscribeDeserialize.sourceReference.setFQName("SUBSCRIBE_1.RD_1") - cDSubscribeDeserialize.targetReference.setFQName("JSON_DESERIALIZER.DATA") - cFB.network.dataConnections.add(cDSubscribeDeserialize) - - val cDDeserializeName = factory.createFBNetworkConnection(EntryKind.DATA) - cDDeserializeName.sourceReference.setFQName("JSON_DESERIALIZER.NAME") - cDDeserializeName.targetReference.setFQName("DISPATCH_IN_${this.element.name}.NAME") - cFB.network.dataConnections.add(cDDeserializeName) - - val cDMappingDispatch = factory.createFBNetworkConnection(EntryKind.DATA) - cDMappingDispatch.sourceReference.setFQName("MAPPING") - cDMappingDispatch.targetReference.setFQName("DISPATCH_IN_${this.element.name}.MAPPING") - cFB.network.dataConnections.add(cDMappingDispatch) - - this.element.outputParameters.forEach { - val cEDispatchRes = factory.createFBNetworkConnection(EntryKind.DATA) - cEDispatchRes.sourceReference.setFQName("DISPATCH_IN_${this.element.name}.${it.name}") - cEDispatchRes.targetReference.setFQName(it.name) - cFB.network.eventConnections.add(cEDispatchRes) - } - - HMIInterfaceTypeGenerator.CONNECTION_TYPES.forEach { - val cDDispatch = factory.createFBNetworkConnection(EntryKind.DATA) - cDDispatch.sourceReference.setFQName("JSON_DESERIALIZER.${it.name}_VALUE") - cDDispatch.targetReference.setFQName("DISPATCH_IN_${this.element.name}.${it.name}_VALUE") - cFB.network.dataConnections.add(cDDispatch) - } - } - - - return cFB - } - - fun generateEventForParameter(parameter: ParameterDeclaration, factory: IEC61499Factory): EventDeclaration { - val currEvent = factory.createEventDeclaration(null) - currEvent.name = "IS_${parameter.name}" - val assoc = factory.createEventAssociation() - assoc.parameterReference.setTarget(parameter) - currEvent.associations.add(assoc) - return currEvent - } - - fun generateCommunicationBlock(name: String, factory: IEC61499Factory, stFactory: STFactory): FunctionBlockDeclaration { - val fB = factory.createFunctionBlockDeclaration(null) - fB.name = name - val idPD = factory.createParameterDeclaration(null) - idPD.name = "ID" - idPD.type = ElementaryType.WSTRING - val host = factory.createParameterAssignment() - host.parameterReference.setTarget(idPD) - host.value = STConverter.parseLiteral(stFactory, "225.0.0.2:65011") - fB.parameters.add(host) - - val qiPD = factory.createParameterDeclaration(null) - qiPD.name = "QI" - qiPD.type = ElementaryType.BOOL - val qi = factory.createParameterAssignment() - qi.parameterReference.setTarget(idPD) - qi.value = STConverter.parseLiteral(stFactory, "1") - fB.parameters.add(qi) - - fB.typeReference.setTargetName(name) - return fB - } - - fun generateFunctionDeclarationNoParam(name: String, factory: IEC61499Factory): FunctionBlockDeclaration { - val fB = factory.createFunctionBlockDeclaration(null) - fB.name = name - fB.typeReference.setTargetName(name) - return fB - } } \ No newline at end of file diff --git a/code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/HMIInterfaceTypeGenerator.kt b/code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/HMIInterfaceTypeGenerator.kt index 8570a836a..be081f12a 100644 --- a/code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/HMIInterfaceTypeGenerator.kt +++ b/code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/HMIInterfaceTypeGenerator.kt @@ -3,6 +3,7 @@ package org.fbme.lib.iec61499.stringify import org.fbme.lib.common.Identifier import org.fbme.lib.iec61499.IEC61499Factory import org.fbme.lib.iec61499.declarations.* +import org.fbme.lib.iec61499.fbnetwork.EntryKind import org.fbme.lib.iec61499.fbnetwork.FunctionBlockDeclaration import org.fbme.lib.iec61499.parser.Iec61499ConverterConfiguration import org.fbme.lib.iec61499.parser.STConverter @@ -29,8 +30,8 @@ class HMIInterfaceTypeGenerator(val declaration: HMIInterfaceTypeDeclaration, va declaration.name ) elements.add(inFb) -// val hmiElement = Element(declaration.name) -// printComposite(hmiElement, outFb, inFb) + val compositeHMI = generateComposite(factory, stFactory, declaration) + elements.add(compositeHMI) return elements } @@ -238,6 +239,203 @@ companion object { val code = "(LEFT(NAME, LEN(NAME) - 7) = MAPPING) AND (RIGHT(NAME, LEN(NAME) - LEN(NAME) + ${p.name.length + 1}) = '#${p.name}')" return STConverter.parseExpression(stFactory, code)!! } + + fun generateComposite(factory: IEC61499Factory, stFactory: STFactory, declaration: HMIInterfaceTypeDeclaration): CompositeFBTypeDeclaration { + var cFB = factory.createCompositeFBTypeDeclaration(null) + cFB.name = declaration.name + "_HMI_COMPOSITE" + declaration.inputParameters.forEach { + if (it.name != "MAPPING") { + val pD = factory.createParameterDeclaration(null) + pD.name = it.name + pD.type = it.type + pD.initialValue = it.initialValue + cFB.inputParameters.add(pD) + } + } + declaration.outputParameters.forEach { + val pD = factory.createParameterDeclaration(null) + pD.name = it.name + pD.type = it.type + pD.initialValue = it.initialValue + cFB.outputParameters.add(pD) + } + + val initEvent = factory.createEventDeclaration(null) + initEvent.name = "INIT" + initEvent.associations + val mappingInput = factory.createParameterDeclaration(null) + mappingInput.name = "MAPPING" + mappingInput.type = ElementaryType.STRING + cFB.inputParameters.add(mappingInput) + cFB.inputEvents.add(initEvent) + + if (cFB.inputParameters.size - 1 > 0) { +// NEEDED FUNCTION BLOCKS GENERATION + + cFB.network.functionBlocks.add(generateCommunicationBlock("PUBLISH_1", factory, stFactory)) + cFB.network.functionBlocks.add(generateFunctionDeclarationNoParam("JSON_SERIALIZER", factory)) + cFB.network.functionBlocks.add(generateFunctionDeclarationNoParam("DISPATCH_OUT_${declaration.name}", factory)) + +// EVENTS GENERATION + + val cEInitPublish = factory.createFBNetworkConnection(EntryKind.EVENT) + cEInitPublish.sourceReference.setFQName("INIT") + cEInitPublish.targetReference.setFQName("PUBLISH_1.INIT") + cFB.network.eventConnections.add(cEInitPublish) + + val cESerializerPublish = factory.createFBNetworkConnection(EntryKind.EVENT) + cESerializerPublish.sourceReference.setFQName("JSON_SERIALIZER.RES") + cESerializerPublish.targetReference.setFQName("PUBLISH_1.REQ") + cFB.network.eventConnections.add(cESerializerPublish) + + declaration.inputParameters.stream().filter{it.name != "MAPPING"} + .forEach{ + val event = generateEventForParameter(it, factory) + cFB.inputEvents.add(event) + val cEDispatch = factory.createFBNetworkConnection(EntryKind.EVENT) + cEDispatch.sourceReference.setFQName(event.name) + cEDispatch.targetReference.setFQName("DISPATCH_OUT_${declaration.name}.${event.name}") + cFB.network.eventConnections.add(cEDispatch) + } + +// DATA CONNECTIONS GENERATION + + val cDSerializerPublish = factory.createFBNetworkConnection(EntryKind.DATA) + cDSerializerPublish.sourceReference.setFQName("JSON_SERIALIZER.MSG") + cDSerializerPublish.targetReference.setFQName("PUBLISH_1.SD_1") + cFB.network.dataConnections.add(cDSerializerPublish) + + declaration.inputParameters.stream() + .forEach{ + val cDDispatch = factory.createFBNetworkConnection(EntryKind.DATA) + cDDispatch.sourceReference.setFQName(it.name) + cDDispatch.targetReference.setFQName("DISPATCH_OUT_${declaration.name}.${it.name}") + cFB.network.dataConnections.add(cDDispatch) + } + + val cDNameSerialize = factory.createFBNetworkConnection(EntryKind.DATA) + cDNameSerialize.sourceReference.setFQName("DISPATCH_OUT_${declaration.name}.NAME") + cDNameSerialize.targetReference.setFQName("JSON_SERIALIZER.NAME") + cFB.network.dataConnections.add(cDNameSerialize) + +// CONNECTIONS FOR DIFFERENT DATA TYPES + + HMIInterfaceTypeGenerator.CONNECTION_TYPES.forEach { + val cEDispatch = factory.createFBNetworkConnection(EntryKind.EVENT) + cEDispatch.sourceReference.setFQName("DISPATCH_OUT_${declaration.name}.IS_${it.name}") + cEDispatch.targetReference.setFQName("JSON_SERIALIZER.IS_${it.name}") + cFB.network.eventConnections.add(cEDispatch) + val cDDispatch = factory.createFBNetworkConnection(EntryKind.DATA) + cDDispatch.sourceReference.setFQName("DISPATCH_OUT_${declaration.name}.${it.name}_VALUE") + cDDispatch.targetReference.setFQName("JSON_SERIALIZER.${it.name}_VALUE") + cFB.network.dataConnections.add(cDDispatch) + } + + } + + if (declaration.outputParameters.size > 0) { +// NEEDED FUNCTION BLOCKS GENERATION + + cFB.network.functionBlocks.add(generateCommunicationBlock("SUBSCRIBE_1", factory, stFactory, 65012)) + cFB.network.functionBlocks.add(generateFunctionDeclarationNoParam("JSON_DESERIALIZER", factory)) + cFB.network.functionBlocks.add(generateFunctionDeclarationNoParam("DISPATCH_IN_${declaration.name}", factory)) + +// EVENTS GENERATION + + val cEInitSubscribe = factory.createFBNetworkConnection(EntryKind.EVENT) + cEInitSubscribe.sourceReference.setFQName("INIT") + cEInitSubscribe.targetReference.setFQName("SUBSCRIBE_1.INIT") + cFB.network.eventConnections.add(cEInitSubscribe) + + val cESubscribeDeserialize = factory.createFBNetworkConnection(EntryKind.EVENT) + cESubscribeDeserialize.sourceReference.setFQName("SUBSCRIBE_1.IND") + cESubscribeDeserialize.targetReference.setFQName("JSON_DESERIALIZER.REQ") + cFB.network.eventConnections.add(cESubscribeDeserialize) + + val cEDeserializeDispatch = factory.createFBNetworkConnection(EntryKind.EVENT) + cEDeserializeDispatch.sourceReference.setFQName("JSON_DESERIALIZER.RES") + cEDeserializeDispatch.targetReference.setFQName("DISPATCH_IN_${declaration.name}.REQ") + cFB.network.eventConnections.add(cEDeserializeDispatch) + + declaration.outputParameters.forEach { + val event = generateEventForParameter(it, factory) + cFB.outputEvents.add(event) + + val cEDispatchRes = factory.createFBNetworkConnection(EntryKind.EVENT) + cEDispatchRes.sourceReference.setFQName("DISPATCH_IN_${declaration.name}.${event.name}") + cEDispatchRes.targetReference.setFQName(event.name) + cFB.network.eventConnections.add(cEDispatchRes) + } + +// DATA GENERATION + + val cDSubscribeDeserialize = factory.createFBNetworkConnection(EntryKind.DATA) + cDSubscribeDeserialize.sourceReference.setFQName("SUBSCRIBE_1.RD_1") + cDSubscribeDeserialize.targetReference.setFQName("JSON_DESERIALIZER.DATA") + cFB.network.dataConnections.add(cDSubscribeDeserialize) + + val cDDeserializeName = factory.createFBNetworkConnection(EntryKind.DATA) + cDDeserializeName.sourceReference.setFQName("JSON_DESERIALIZER.NAME") + cDDeserializeName.targetReference.setFQName("DISPATCH_IN_${declaration.name}.NAME") + cFB.network.dataConnections.add(cDDeserializeName) + + val cDMappingDispatch = factory.createFBNetworkConnection(EntryKind.DATA) + cDMappingDispatch.sourceReference.setFQName("MAPPING") + cDMappingDispatch.targetReference.setFQName("DISPATCH_IN_${declaration.name}.MAPPING") + cFB.network.dataConnections.add(cDMappingDispatch) + + declaration.outputParameters.forEach { + val cEDispatchRes = factory.createFBNetworkConnection(EntryKind.DATA) + cEDispatchRes.sourceReference.setFQName("DISPATCH_IN_${declaration.name}.${it.name}") + cEDispatchRes.targetReference.setFQName(it.name) + cFB.network.dataConnections.add(cEDispatchRes) + } + + HMIInterfaceTypeGenerator.CONNECTION_TYPES.forEach { + val cDDispatch = factory.createFBNetworkConnection(EntryKind.DATA) + cDDispatch.sourceReference.setFQName("JSON_DESERIALIZER.${it.name}_VALUE") + cDDispatch.targetReference.setFQName("DISPATCH_IN_${declaration.name}.${it.name}_VALUE") + cFB.network.dataConnections.add(cDDispatch) + } + } + + + return cFB + } + + fun generateEventForParameter(parameter: ParameterDeclaration, factory: IEC61499Factory): EventDeclaration { + val currEvent = factory.createEventDeclaration(null) + currEvent.name = "IS_${parameter.name}" + val assoc = factory.createEventAssociation() + assoc.parameterReference.setTarget(parameter) + currEvent.associations.add(assoc) + return currEvent + } + + fun generateCommunicationBlock(name: String, factory: IEC61499Factory, stFactory: STFactory, port: Int = 65011): FunctionBlockDeclaration { + val fB = factory.createFunctionBlockDeclaration(null) + fB.name = name + val host = factory.createParameterAssignment() + host.parameterReference.setTargetName("ID") + host.value = STConverter.parseLiteral(stFactory, "\"225.0.0.2:${port}\"") + fB.parameters.add(host) + + + val qi = factory.createParameterAssignment() + qi.parameterReference.setTargetName("QI") + qi.value = STConverter.parseLiteral(stFactory, "1") + fB.parameters.add(qi) + + fB.typeReference.setTargetName(name) + return fB + } + + fun generateFunctionDeclarationNoParam(name: String, factory: IEC61499Factory): FunctionBlockDeclaration { + val fB = factory.createFunctionBlockDeclaration(null) + fB.name = name + fB.typeReference.setTargetName(name) + return fB + } } } \ No newline at end of file diff --git a/code/platform/src/main/kotlin/org/fbme/ide/platform/persistence/Iec61499ModelFactory.kt b/code/platform/src/main/kotlin/org/fbme/ide/platform/persistence/Iec61499ModelFactory.kt index 3a1c9395a..14c0a0e65 100644 --- a/code/platform/src/main/kotlin/org/fbme/ide/platform/persistence/Iec61499ModelFactory.kt +++ b/code/platform/src/main/kotlin/org/fbme/ide/platform/persistence/Iec61499ModelFactory.kt @@ -15,6 +15,12 @@ import jetbrains.mps.persistence.DataLocationAwareModelFactory import jetbrains.mps.smodel.SModel.ImportElement import jetbrains.mps.smodel.SModelId import jetbrains.mps.smodel.SNodeUtil +import jetbrains.mps.smodel.adapter.ids.SContainmentLinkId +import jetbrains.mps.smodel.adapter.ids.SPropertyId +import jetbrains.mps.smodel.adapter.structure.MetaAdapterFactory +import jetbrains.mps.smodel.adapter.structure.link.SContainmentLinkAdapter +import jetbrains.mps.smodel.adapter.structure.link.SContainmentLinkAdapterById +import jetbrains.mps.smodel.adapter.structure.property.SPropertyAdapter import jetbrains.mps.util.FileUtil import jetbrains.mps.util.JDOMUtil import jetbrains.mps.util.NameUtil @@ -29,6 +35,8 @@ import org.fbme.ide.platform.converter.PlatformConverter.create import org.fbme.lib.common.Declaration import org.fbme.lib.common.RootElement import org.fbme.lib.iec61499.declarations.* +import org.fbme.lib.iec61499.parser.Iec61499ConverterConfiguration +import org.fbme.lib.iec61499.parser.StandardIec61499ConverterConfiguration import org.fbme.lib.iec61499.stringify.DependentDeclarationGenerator import org.fbme.lib.iec61499.stringify.RootDeclarationPrinter import org.jdom.Document @@ -272,28 +280,43 @@ class Iec61499ModelFactory : ModelFactory, DataLocationAwareModelFactory { .getComponent(MPSCoreComponents::class.java).moduleRepository val platformRepository = PlatformRepository(repository) + val nodesToDelete = mutableListOf() val dependents = mutableListOf() for (rootNode in model.rootNodes) { + if (rootNode.getProperty(SNodeUtil.property_BaseConcept_virtualPackage).orEmpty().endsWith("_dependent")) { +// c.dropReference(it.link) + nodesToDelete.add(rootNode) + continue + } val owner = PlatformElementsOwner() val conf = PlatformConverter.STANDARD_CONFIG_FACTORY.createConfiguration(owner) - val declaration = platformRepository.getAdapter(rootNode, Declaration::class.java) val els = DependentDeclarationGenerator(declaration, conf).generate() - els.forEach { - val node = (it as PlatformElement).node - node.setProperty(SNodeUtil.property_BaseConcept_virtualPackage, rootNode.getProperty(SNodeUtil.property_BaseConcept_virtualPackage).orEmpty()) + els.forEach { element -> + val node = (element as PlatformElement).node + node.setProperty(SNodeUtil.property_BaseConcept_virtualPackage, rootNode.getProperty(SNodeUtil.property_BaseConcept_virtualPackage).orEmpty() + ".${rootNode.name}_dependent") dependents.add(node) } } + LOG.info("Deleting nodes size: {}", nodesToDelete.size) + nodesToDelete.forEach { + model.enterUpdateMode() + model.removeRootNode(it) + it.delete() + model.leaveUpdateMode() + } LOG.info("Dependents size: {}", dependents.size) - dependents.forEach { model.addRootNode(it) } + dependents.forEach { + model.enterUpdateMode() + model.addRootNode(it) + model.leaveUpdateMode() + } // Write nodes to xml files for (rootNode in model.rootNodes) { - val owner = PlatformElementsOwner() - val conf = PlatformConverter.STANDARD_CONFIG_FACTORY.createConfiguration(owner) + val conf = StandardIec61499ConverterConfiguration(platformRepository.iec61499Factory, platformRepository.stFactory) val declaration = platformRepository.getAdapter(rootNode, Declaration::class.java) val document = RootDeclarationPrinter(declaration!!, conf).print() @@ -322,6 +345,8 @@ class Iec61499ModelFactory : ModelFactory, DataLocationAwareModelFactory { } } + + companion object { private val LOG = LoggerFactory.getLogger(Iec61499ModelFactory::class.java) diff --git a/code/platform/src/test/kotlin/HmiPrinterTest.kt b/code/platform/src/test/kotlin/HmiPrinterTest.kt deleted file mode 100644 index 759a91da3..000000000 --- a/code/platform/src/test/kotlin/HmiPrinterTest.kt +++ /dev/null @@ -1,36 +0,0 @@ -import org.fbme.ide.platform.testing.PlatformTestBase -import org.fbme.ide.platform.testing.PlatformTestRunner -import org.fbme.lib.iec61499.parser.STConverter -import org.fbme.lib.iec61499.stringify.HMIInterfaceTypeGenerator.Companion.generateDispatchIn -import org.fbme.lib.st.types.ElementaryType -import org.jdom.Document -import org.jdom.Element -import org.jdom.output.XMLOutputter -import org.junit.Test -import org.junit.runner.RunWith -import java.io.FileOutputStream -import java.io.OutputStream - - -@RunWith(PlatformTestRunner::class) -class HMIPrinterTest : PlatformTestBase() { - @Test - fun parseTest1() { - print("Started") - var fileName = "DISPATCH_IN.fbt" - val resElement: Element = Element("DISPATCH_IN") - var p = factory.createParameterDeclaration(null) - p.type = ElementaryType.STRING - p.name = "COUNT" - p.initialValue = STConverter.parseLiteral(stFactory, "'1'") - -// generateDispatchIn(resElement, factory, stFactory, listOf(p)) -// resElement.print(PrettyPrinter()) - // List dependentList = new DependentDeclarationPrinter(declaration).print(); - val stream: OutputStream = FileOutputStream(fileName) - val xmlOutputter = XMLOutputter() - var doc = Document() - doc.setRootElement(resElement) - xmlOutputter.output(doc, stream) - } -} \ No newline at end of file diff --git a/solutions/WaterTank/WaterTank.msd b/solutions/WaterTank/WaterTank.msd new file mode 100644 index 000000000..c098be686 --- /dev/null +++ b/solutions/WaterTank/WaterTank.msd @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + b8a7e14f-52ea-4ee2-b17e-26c27da8084c(IEC-61499) + 5aff85f5-c1e8-49b6-a1f1-66d79702cceb(org.fbme.ide.iec61499.adapter) + + + + + + + + + + + + + + diff --git a/solutions/WaterTank/models/WaterTank.water_tank.mps b/solutions/WaterTank/models/WaterTank.water_tank.mps new file mode 100644 index 000000000..5b459894f --- /dev/null +++ b/solutions/WaterTank/models/WaterTank.water_tank.mps @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + From 49c46c67501757fa3aeca5c2455731a9ccc88f84 Mon Sep 17 00:00:00 2001 From: Valentina Danilova Date: Wed, 17 May 2023 16:09:51 +0300 Subject: [PATCH 14/21] check inputs and outputs --- .../stringify/HMIInterfaceTypeGenerator.kt | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/HMIInterfaceTypeGenerator.kt b/code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/HMIInterfaceTypeGenerator.kt index be081f12a..3f723ce25 100644 --- a/code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/HMIInterfaceTypeGenerator.kt +++ b/code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/HMIInterfaceTypeGenerator.kt @@ -21,15 +21,19 @@ class HMIInterfaceTypeGenerator(val declaration: HMIInterfaceTypeDeclaration, va fun generateDependents(): List { val elements = mutableListOf() - val outFb = generateDispatchOut(factory, stFactory, declaration.inputParameters, declaration.name) - elements.add(outFb) - val inFb = generateDispatchIn( - factory, - stFactory, - declaration.outputParameters, - declaration.name - ) - elements.add(inFb) + if (declaration.inputParameters.size > 0) { + val outFb = generateDispatchOut(factory, stFactory, declaration.inputParameters, declaration.name) + elements.add(outFb) + } + if (declaration.outputParameters.size > 0) { + val inFb = generateDispatchIn( + factory, + stFactory, + declaration.outputParameters, + declaration.name + ) + elements.add(inFb) + } val compositeHMI = generateComposite(factory, stFactory, declaration) elements.add(compositeHMI) return elements @@ -236,7 +240,7 @@ companion object { } fun generateInGuard(p: ParameterDeclaration, stFactory: STFactory): Expression { - val code = "(LEFT(NAME, LEN(NAME) - 7) = MAPPING) AND (RIGHT(NAME, LEN(NAME) - LEN(NAME) + ${p.name.length + 1}) = '#${p.name}')" + val code = "(LEFT(NAME, LEN(NAME) - ${p.name.length + 2}) = MAPPING) AND (RIGHT(NAME, LEN(NAME) - LEN(NAME) + ${p.name.length + 1}) = '#${p.name}')" return STConverter.parseExpression(stFactory, code)!! } From 57e867b3a0ae15f05ceb510680076aa07096b026 Mon Sep 17 00:00:00 2001 From: Valentina Danilova Date: Thu, 18 May 2023 10:42:38 +0300 Subject: [PATCH 15/21] . --- .../stringify/HMIInterfaceTypeGenerator.kt | 2 +- .../WaterTank/models/WaterTank.water_tank.mps | 27 +++++++++++++++++-- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/HMIInterfaceTypeGenerator.kt b/code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/HMIInterfaceTypeGenerator.kt index 3f723ce25..17ca8c5c2 100644 --- a/code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/HMIInterfaceTypeGenerator.kt +++ b/code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/HMIInterfaceTypeGenerator.kt @@ -246,7 +246,7 @@ companion object { fun generateComposite(factory: IEC61499Factory, stFactory: STFactory, declaration: HMIInterfaceTypeDeclaration): CompositeFBTypeDeclaration { var cFB = factory.createCompositeFBTypeDeclaration(null) - cFB.name = declaration.name + "_HMI_COMPOSITE" + cFB.name = declaration.name + "_HMI" declaration.inputParameters.forEach { if (it.name != "MAPPING") { val pD = factory.createParameterDeclaration(null) diff --git a/solutions/WaterTank/models/WaterTank.water_tank.mps b/solutions/WaterTank/models/WaterTank.water_tank.mps index 5b459894f..29796e363 100644 --- a/solutions/WaterTank/models/WaterTank.water_tank.mps +++ b/solutions/WaterTank/models/WaterTank.water_tank.mps @@ -10,9 +10,32 @@ - + + + + + + + + + + + + - + + + + + + + + + + + + + From 3ba5d5f04376a6d66860df5bb7485308645937ce Mon Sep 17 00:00:00 2001 From: Valentina Danilova Date: Fri, 2 Jun 2023 17:43:55 +0300 Subject: [PATCH 16/21] add visuals --- .idea/compiler.xml | 8 - code/cat_visual/README.md | 14 + code/cat_visual/build.gradle.kts | 49 ++ code/cat_visual/gradle.properties | 1 + code/cat_visual/gradlew | 185 ++++++ code/cat_visual/gradlew.bat | 89 +++ code/cat_visual/settings.gradle.kts | 10 + code/cat_visual/src/main/kotlin/Main.kt | 79 +++ .../src/main/kotlin/canvas/Canvas.kt | 16 + .../src/main/kotlin/canvas/UpperPlate.kt | 91 +++ .../main/kotlin/canvas/items/CustomItem.kt | 182 ++++++ .../connection/ConnectionFieldRegistry.kt | 45 ++ .../src/main/kotlin/connection/clients.kt | 174 ++++++ .../main/kotlin/connection/field/BoolField.kt | 37 ++ .../connection/field/ConnectionField.kt | 61 ++ .../kotlin/connection/field/DoubleField.kt | 36 ++ .../kotlin/connection/field/FloatField.kt | 33 ++ .../main/kotlin/connection/field/IntField.kt | 238 ++++++++ .../kotlin/connection/field/StringField.kt | 31 + .../kotlin/connection/field/WStringField.kt | 31 + .../connection/provider/ConnectionProvider.kt | 89 +++ .../kotlin/example/COUNTER/COMMON_CONF.xml | 9 + .../src/main/kotlin/example/COUNTER/COUNT.xml | 0 .../main/kotlin/example/COUNTER/COUNTER.kt | 44 ++ .../main/kotlin/example/COUNTER/COUNTER.xml | 10 + .../kotlin/example/COUNTER/COUNTER_CONF.xml | 10 + .../kotlin/example/COUNTER/COUNTER_PLAIN.xml | 10 + .../src/main/kotlin/example/COUNTER/LAMP.xml | 10 + .../main/kotlin/example/COUNTER/TOGGLE.xml | 0 .../main/kotlin/example/INCHOICE/INCHOICE.kt | 75 +++ .../example/INCHOICE/INCHOICE_HMI.cnv.xml | 17 + .../kotlin/example/WATER_TANK/WATER_TANK.kt | 121 ++++ .../kotlin/example/WATER_TANK/WATER_TANK.xml | 16 + .../example/WATER_TANK/WATER_TANK_CONF.xml | 10 + .../example/WATER_TANK/WATER_TANK_PLAIN.xml | 16 + .../kotlin/lib/elements/figures/elements.kt | 212 +++++++ .../kotlin/lib/elements/getters/elements.kt | 221 +++++++ .../kotlin/lib/elements/setters/elements.kt | 549 ++++++++++++++++++ .../src/main/kotlin/lib/visual/Positioning.kt | 32 + .../src/main/kotlin/lib/visual/colors.kt | 51 ++ .../main/kotlin/serializer/serialization.kt | 155 +++++ .../cat_visual/src/test/kotlin/MockBackend.kt | 13 + .../src/test/kotlin/WaterTankTest.kt | 90 +++ settings.gradle.kts | 29 +- 44 files changed, 3177 insertions(+), 22 deletions(-) create mode 100644 code/cat_visual/README.md create mode 100644 code/cat_visual/build.gradle.kts create mode 100644 code/cat_visual/gradle.properties create mode 100755 code/cat_visual/gradlew create mode 100644 code/cat_visual/gradlew.bat create mode 100644 code/cat_visual/settings.gradle.kts create mode 100644 code/cat_visual/src/main/kotlin/Main.kt create mode 100644 code/cat_visual/src/main/kotlin/canvas/Canvas.kt create mode 100644 code/cat_visual/src/main/kotlin/canvas/UpperPlate.kt create mode 100644 code/cat_visual/src/main/kotlin/canvas/items/CustomItem.kt create mode 100644 code/cat_visual/src/main/kotlin/connection/ConnectionFieldRegistry.kt create mode 100644 code/cat_visual/src/main/kotlin/connection/clients.kt create mode 100644 code/cat_visual/src/main/kotlin/connection/field/BoolField.kt create mode 100644 code/cat_visual/src/main/kotlin/connection/field/ConnectionField.kt create mode 100644 code/cat_visual/src/main/kotlin/connection/field/DoubleField.kt create mode 100644 code/cat_visual/src/main/kotlin/connection/field/FloatField.kt create mode 100644 code/cat_visual/src/main/kotlin/connection/field/IntField.kt create mode 100644 code/cat_visual/src/main/kotlin/connection/field/StringField.kt create mode 100644 code/cat_visual/src/main/kotlin/connection/field/WStringField.kt create mode 100644 code/cat_visual/src/main/kotlin/connection/provider/ConnectionProvider.kt create mode 100644 code/cat_visual/src/main/kotlin/example/COUNTER/COMMON_CONF.xml create mode 100644 code/cat_visual/src/main/kotlin/example/COUNTER/COUNT.xml create mode 100644 code/cat_visual/src/main/kotlin/example/COUNTER/COUNTER.kt create mode 100644 code/cat_visual/src/main/kotlin/example/COUNTER/COUNTER.xml create mode 100644 code/cat_visual/src/main/kotlin/example/COUNTER/COUNTER_CONF.xml create mode 100644 code/cat_visual/src/main/kotlin/example/COUNTER/COUNTER_PLAIN.xml create mode 100644 code/cat_visual/src/main/kotlin/example/COUNTER/LAMP.xml create mode 100644 code/cat_visual/src/main/kotlin/example/COUNTER/TOGGLE.xml create mode 100644 code/cat_visual/src/main/kotlin/example/INCHOICE/INCHOICE.kt create mode 100644 code/cat_visual/src/main/kotlin/example/INCHOICE/INCHOICE_HMI.cnv.xml create mode 100644 code/cat_visual/src/main/kotlin/example/WATER_TANK/WATER_TANK.kt create mode 100644 code/cat_visual/src/main/kotlin/example/WATER_TANK/WATER_TANK.xml create mode 100644 code/cat_visual/src/main/kotlin/example/WATER_TANK/WATER_TANK_CONF.xml create mode 100644 code/cat_visual/src/main/kotlin/example/WATER_TANK/WATER_TANK_PLAIN.xml create mode 100644 code/cat_visual/src/main/kotlin/lib/elements/figures/elements.kt create mode 100644 code/cat_visual/src/main/kotlin/lib/elements/getters/elements.kt create mode 100644 code/cat_visual/src/main/kotlin/lib/elements/setters/elements.kt create mode 100644 code/cat_visual/src/main/kotlin/lib/visual/Positioning.kt create mode 100644 code/cat_visual/src/main/kotlin/lib/visual/colors.kt create mode 100644 code/cat_visual/src/main/kotlin/serializer/serialization.kt create mode 100644 code/cat_visual/src/test/kotlin/MockBackend.kt create mode 100644 code/cat_visual/src/test/kotlin/WaterTankTest.kt diff --git a/.idea/compiler.xml b/.idea/compiler.xml index 58d13c02c..c8952aa4d 100644 --- a/.idea/compiler.xml +++ b/.idea/compiler.xml @@ -1,14 +1,6 @@ - - - - - - - - diff --git a/code/cat_visual/README.md b/code/cat_visual/README.md new file mode 100644 index 000000000..a2cb49d34 --- /dev/null +++ b/code/cat_visual/README.md @@ -0,0 +1,14 @@ +# compose_template + +Виды примитивных блоков для поддержки +* checkbox +* radio +* text choice +* different toggles + +Interfaces: +* Zoomable +* Positioned +* ZIndexed +* Grouped +* \ No newline at end of file diff --git a/code/cat_visual/build.gradle.kts b/code/cat_visual/build.gradle.kts new file mode 100644 index 000000000..7586c8f9e --- /dev/null +++ b/code/cat_visual/build.gradle.kts @@ -0,0 +1,49 @@ +import org.jetbrains.compose.compose +import org.jetbrains.compose.desktop.application.dsl.TargetFormat +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile + +plugins { + kotlin + id("org.jetbrains.compose") version "1.3.1" + kotlin("plugin.serialization") version "1.8.0" +} + +group = "fbme" +version = "1.0" + +repositories { + google() + mavenCentral() + maven("https://maven.pkg.jetbrains.space/public/p/compose/dev") +} + +dependencies { + implementation(compose.desktop.currentOs) + implementation("com.hierynomus:asn-one:0.5.0") + implementation(kotlin("stdlib-jdk8")) + implementation("io.github.pdvrieze.xmlutil:serialization-jvm:0.84.3") + implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.0") +} + +tasks.withType { + kotlinOptions.jvmTarget = "11" +} + +compose.desktop { + application { + mainClass = "MainKt" + nativeDistributions { + targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb) + packageName = "compose" + packageVersion = "1.0.0" + } + } +} +val compileKotlin: KotlinCompile by tasks +compileKotlin.kotlinOptions { + jvmTarget = "1.8" +} +val compileTestKotlin: KotlinCompile by tasks +compileTestKotlin.kotlinOptions { + jvmTarget = "1.8" +} \ No newline at end of file diff --git a/code/cat_visual/gradle.properties b/code/cat_visual/gradle.properties new file mode 100644 index 000000000..7fc6f1ff2 --- /dev/null +++ b/code/cat_visual/gradle.properties @@ -0,0 +1 @@ +kotlin.code.style=official diff --git a/code/cat_visual/gradlew b/code/cat_visual/gradlew new file mode 100755 index 000000000..744e882ed --- /dev/null +++ b/code/cat_visual/gradlew @@ -0,0 +1,185 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MSYS* | MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=`expr $i + 1` + done + case $i in + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=`save "$@"` + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +exec "$JAVACMD" "$@" diff --git a/code/cat_visual/gradlew.bat b/code/cat_visual/gradlew.bat new file mode 100644 index 000000000..ac1b06f93 --- /dev/null +++ b/code/cat_visual/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/code/cat_visual/settings.gradle.kts b/code/cat_visual/settings.gradle.kts new file mode 100644 index 000000000..bbba57708 --- /dev/null +++ b/code/cat_visual/settings.gradle.kts @@ -0,0 +1,10 @@ +pluginManagement { + repositories { + google() + gradlePluginPortal() + maven("https://maven.pkg.jetbrains.space/public/p/compose/dev") + } + +} +rootProject.name = "compose" + diff --git a/code/cat_visual/src/main/kotlin/Main.kt b/code/cat_visual/src/main/kotlin/Main.kt new file mode 100644 index 000000000..f5710a74d --- /dev/null +++ b/code/cat_visual/src/main/kotlin/Main.kt @@ -0,0 +1,79 @@ +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Scaffold +import androidx.compose.runtime.Composable +import androidx.compose.runtime.snapshots.SnapshotStateList +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.dp +import androidx.compose.ui.window.Window +import androidx.compose.ui.window.application +import androidx.compose.ui.window.rememberWindowState +import canvas.items.CustomItem +import connection.* +import connection.field.BoolField +import connection.field.TYPE_ID +import example.COUNTER.CounterLampHMI +import example.WATER_TANK.System +import example.WATER_TANK.WaterTank +import serializer.PlainMapping +import serializer.getConf +import serializer.getMapping +import serializer.getPlainMapping +import java.io.BufferedReader +import java.io.File +import java.io.InputStreamReader +import java.net.DatagramPacket +import java.net.InetAddress +import java.net.ServerSocket + +@Composable +fun CanvasContext(listFigures: SnapshotStateList) { + Scaffold { innerPadding -> + Box(Modifier.fillMaxHeight().fillMaxWidth().background(Color.Gray)) { + listFigures.forEach { f -> f.create() } + } + } +} + +fun buildMappingClient(modelFile: String, configFile: String = "", mode: String = ""): AbstractClient { + if (mode.equals("plain")) { + val modelText = File(modelFile).readText() + val mapping = getPlainMapping(modelText) + + return PlainClient(mapping) + } + + val modelText = File(modelFile).readText() + val mapping = getMapping(modelText) + val configText = File(configFile).readText() + val conf = getConf(configText) + + if (mode.equals("json")) { + return JSONClient(mapping, conf) + } + return NamedClient(mapping, conf) +} + +//val client = buildMappingClient("src/main/kotlin/example/COUNTER/COUNTER.xml", "src/main/kotlin/example/COUNTER/COUNTER_CONF.xml", "") +val client = buildMappingClient("src/main/kotlin/example/COUNTER/COUNTER.xml", "src/main/kotlin/example/COUNTER/COMMON_CONF.xml", "json") +//val client = buildMappingClient("src/main/kotlin/example/WATER_TANK/WATER_TANK.xml", "src/main/kotlin/example/WATER_TANK/WATER_TANK_CONF.xml", "") +//val client = buildMappingClient("src/main/kotlin/example/WATER_TANK/WATER_TANK.xml", "src/main/kotlin/example/WATER_TANK/COMMON_CONF.xml", "json") + + +fun main() = application { + Window( + onCloseRequest = ::exitApplication, + title = "Canvas for CAT", + state = rememberWindowState(width = 600.dp, height = 600.dp) + ) { + MaterialTheme { + CounterLampHMI(client, "1") + client.retrieveValues() + } + } +} \ No newline at end of file diff --git a/code/cat_visual/src/main/kotlin/canvas/Canvas.kt b/code/cat_visual/src/main/kotlin/canvas/Canvas.kt new file mode 100644 index 000000000..1688219d8 --- /dev/null +++ b/code/cat_visual/src/main/kotlin/canvas/Canvas.kt @@ -0,0 +1,16 @@ +import androidx.compose.desktop.ui.tooling.preview.Preview +import androidx.compose.foundation.Canvas +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.material.Button +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Text +import androidx.compose.runtime.* +import androidx.compose.ui.Modifier + +@Composable +fun CustomCanvas() { + Canvas(modifier = Modifier.fillMaxSize()) { + } +} + diff --git a/code/cat_visual/src/main/kotlin/canvas/UpperPlate.kt b/code/cat_visual/src/main/kotlin/canvas/UpperPlate.kt new file mode 100644 index 000000000..12a011b5c --- /dev/null +++ b/code/cat_visual/src/main/kotlin/canvas/UpperPlate.kt @@ -0,0 +1,91 @@ +import androidx.compose.desktop.ui.tooling.preview.Preview +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.material.Button +import androidx.compose.material.Checkbox +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Text +import androidx.compose.runtime.* +import androidx.compose.ui.unit.dp + +@Composable +fun UpperPlate() { + Row(horizontalArrangement = Arrangement.spacedBy(5.dp)) { + PointerButton() + } +} +@Composable +@Preview +fun PointerButton() { + var text by remember { mutableStateOf("P") } + + MaterialTheme { + Button(onClick = { + text = "O" + }) { + Text(text) + } + } +} + +@Composable +@Preview +fun RectangleButton(onClickFun: () -> Unit) { + var text by remember { mutableStateOf("R") } + + MaterialTheme { + Button(onClick = onClickFun) { + Text(text) + } + } +} + + +@Composable +@Preview +fun CheckboxButton(onClickFun: () -> Unit) { + var text by remember { mutableStateOf("CB") } + + MaterialTheme { + Button(onClick = onClickFun) { + Text(text) + } + } +} + +@Composable +@Preview +fun RadioButton(onClickFun: () -> Unit) { + var text by remember { mutableStateOf("RB") } + + MaterialTheme { + Button(onClick = onClickFun) { + Text(text) + } + } +} + +@Composable +@Preview +fun ToggleButton(onClickFun: () -> Unit) { + var text by remember { mutableStateOf("TB") } + + MaterialTheme { + Button(onClick = onClickFun) { + Text(text) + } + } +} + +@Composable +@Preview +fun DropdownButton(onClickFun: () -> Unit) { + var text by remember { mutableStateOf("DB") } + + MaterialTheme { + Button(onClick = onClickFun) { + Text(text) + } + } +} diff --git a/code/cat_visual/src/main/kotlin/canvas/items/CustomItem.kt b/code/cat_visual/src/main/kotlin/canvas/items/CustomItem.kt new file mode 100644 index 000000000..86447e4cf --- /dev/null +++ b/code/cat_visual/src/main/kotlin/canvas/items/CustomItem.kt @@ -0,0 +1,182 @@ +package canvas.items + +import androidx.compose.animation.animateContentSize +import androidx.compose.foundation.Canvas +import androidx.compose.foundation.background +import androidx.compose.foundation.gestures.* +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.selection.selectable +import androidx.compose.material.RadioButton +import androidx.compose.material.Text +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.RectangleShape +import androidx.compose.ui.graphics.graphicsLayer +import androidx.compose.ui.input.pointer.PointerEventPass +import androidx.compose.ui.input.pointer.PointerEventType +import androidx.compose.ui.input.pointer.onPointerEvent +import androidx.compose.ui.input.pointer.pointerInput +import androidx.compose.ui.layout.onGloballyPositioned +import androidx.compose.ui.layout.onSizeChanged +import androidx.compose.ui.semantics.Role +import androidx.compose.ui.unit.IntOffset +import androidx.compose.ui.unit.IntSize +import androidx.compose.ui.unit.dp + +enum class ItemType { + RECTANGLE, RADIO, CHECKBOX +} + +@Composable +fun ZoomableBox( + modifier: Modifier = Modifier, + minScale: Float = 0.1f, + maxScale: Float = 5f, + content: @Composable ZoomableBoxScope.() -> Unit +) { + var scale by remember { mutableStateOf(1f) } + var offsetX by remember { mutableStateOf(0f) } + var offsetY by remember { mutableStateOf(0f) } + var size by remember { mutableStateOf(IntSize(50, 50)) } + Box( + modifier = modifier +// .clip(RectangleShape) + .onSizeChanged { size = it } + .pointerInput(Unit) { + detectTransformGestures { _, pan, zoom, _ -> + scale = maxOf(minScale, minOf(scale * zoom, maxScale)) + val maxX = (size.width * (scale - 1)) / 2 + val minX = -maxX + offsetX = maxOf(minX, minOf(maxX, offsetX + pan.x)) + val maxY = (size.height * (scale - 1)) / 2 + val minY = -maxY + offsetY = maxOf(minY, minOf(maxY, offsetY + pan.y)) + } + } + ) { + val scope = ZoomableBoxScopeImpl(scale, offsetX, offsetY) + scope.content() + println(scale) + println(offsetX) + println(offsetY) + println(size) + } +} + +interface ZoomableBoxScope { + val scale: Float + val offsetX: Float + val offsetY: Float +} + +private data class ZoomableBoxScopeImpl( + override val scale: Float, + override val offsetX: Float, + override val offsetY: Float +) : ZoomableBoxScope + + +abstract interface CustomItem { + @Composable + fun create(); +} + +class RectangleCustomItem : CustomItem { + var c = Color.Blue + @Composable + fun RectangleItem() { + var color by remember { mutableStateOf(c) } + ZoomableBox { + Box( + modifier = Modifier + .graphicsLayer( + scaleX = scale, + scaleY = scale, + translationX = offsetX, + translationY = offsetY + ) + .background(color = color) + .width(600.dp) + .height(600.dp) + ) { + } + } + + } + + @Composable + override fun create() { + return RectangleItem(); + } +} + +class CheckboxCustomItem : CustomItem { + var c = Color.Blue + @Composable + fun RectangleItem() { + var color by remember { mutableStateOf(c) } + ZoomableBox { + Box( + modifier = Modifier + .graphicsLayer( + scaleX = scale, + scaleY = scale, + translationX = offsetX, + translationY = offsetY + ) + .background(color = color) + .width(600.dp) + .height(600.dp) + ) { + } + } + + } + + @Composable + override fun create() { + return RectangleItem(); + } +} + +class RadioCustomItem : CustomItem { + var c = Color.Blue + @Composable + fun RadioItem(items: List) { + var color by remember { mutableStateOf(c) } + var selectedValue by remember { mutableStateOf("") } + val isSelectedItem: (String) -> Boolean = { selectedValue == it } + val onChangeState: (String) -> Unit = { selectedValue = it } + ZoomableBox { + items.forEach { item -> + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier.selectable( + selected = isSelectedItem(item), + onClick = { onChangeState(item) }, + role = Role.RadioButton + ).padding(8.dp) + ) { + RadioButton( + selected = isSelectedItem(item), + onClick = null + ) + Text( + text = item, + modifier = Modifier.fillMaxWidth() + ) + } + } + } + + } + + @Composable + override fun create() { + val items = listOf("Item1", "Item2") + return RadioItem(items); + } +} diff --git a/code/cat_visual/src/main/kotlin/connection/ConnectionFieldRegistry.kt b/code/cat_visual/src/main/kotlin/connection/ConnectionFieldRegistry.kt new file mode 100644 index 000000000..96b524370 --- /dev/null +++ b/code/cat_visual/src/main/kotlin/connection/ConnectionFieldRegistry.kt @@ -0,0 +1,45 @@ +package connection + +import connection.field.ConnectionField +import connection.field.TYPE_ID +import connection.provider.ConnectionProvider +import connection.provider.UDPConnectionProvider + + +class ConnectionFieldRegistry { + private val providerRegistry: MutableMap, ConnectionProvider> = mutableMapOf() + private val fieldRegistry: MutableMap,ConnectionProvider> > = mutableMapOf() + + fun getConnection(name: String, type: TYPE_ID, host: String, port: Int): Pair,ConnectionProvider> { + if (name in fieldRegistry) { + return fieldRegistry[name]!! + } + val providerAddress = Pair(host, port) + val provider = providerRegistry.computeIfAbsent(providerAddress, { UDPConnectionProvider(port, host) }) + val field = ConnectionField.create(type) + val connection = Pair(field, provider) + fieldRegistry[name] = connection + return connection + } + + fun getConnection(name: String): Pair,ConnectionProvider>? { + if (name in fieldRegistry) { + return fieldRegistry[name]!! + } + return null + } + + fun getField(name: String): ConnectionField? { + if (name in fieldRegistry) { + return fieldRegistry[name]!!.first + } + return null + } + + fun getConnector(hostPort: Pair): ConnectionProvider? { + if (hostPort in providerRegistry) { + return providerRegistry[hostPort]!! + } + return null + } +} \ No newline at end of file diff --git a/code/cat_visual/src/main/kotlin/connection/clients.kt b/code/cat_visual/src/main/kotlin/connection/clients.kt new file mode 100644 index 000000000..99a76bee1 --- /dev/null +++ b/code/cat_visual/src/main/kotlin/connection/clients.kt @@ -0,0 +1,174 @@ +package connection + +import connection.field.ConnectionField +import connection.field.StringField +import connection.field.TYPE_ID +import connection.provider.ConnectionProvider +import kotlinx.serialization.Serializable +import kotlinx.serialization.decodeFromString +import kotlinx.serialization.encodeToString +import kotlinx.serialization.json.Json +import serializer.Conf +import serializer.Mapping +import serializer.PlainMapping +import java.nio.ByteBuffer + +abstract class AbstractClient() { + abstract fun getField(name: String): ConnectionField?; + abstract fun sendValue(name: String) + abstract fun retrieveValues(callbacks: Map Unit> = mapOf(), isInput: Boolean = true) +} + +abstract class UDPClient(): AbstractClient() { + protected val registry: ConnectionFieldRegistry = ConnectionFieldRegistry() + val inputs: MutableSet = mutableSetOf() + val outputs: MutableSet = mutableSetOf() + val inputConnections: MutableList = mutableListOf() + val outputConnections: MutableList = mutableListOf() + + override fun getField(name: String): ConnectionField? { + return registry.getConnection(name)?.first + } +} + +class PlainClient(mapping: PlainMapping): UDPClient() { + init { + mapping.inputs.inputs.forEach({ + registry.getConnection(it.name, TYPE_ID.valueOf(it.type), it.host, it.port) + inputs.add(it.name) + inputConnections.add(registry.getConnection(it.name)!!.second) + }) + mapping.outputs.outputs.forEach({ + registry.getConnection(it.name, TYPE_ID.valueOf(it.type), it.host, it.port) + outputs.add(it.name) + outputConnections.add(registry.getConnection(it.name)!!.second) + }) + } + + override fun sendValue(name: String) { + val fieldConnector = registry.getConnection(name) + val field = fieldConnector!!.first + val connector = fieldConnector.second + connector.request(field, ByteArray(0)) + } + + override fun retrieveValues(callbacks: Map Unit>, isInput: Boolean) { + val units = if (isInput) inputs else outputs + units.forEach{ + val fieldConnector = registry.getConnection(it) + val field = fieldConnector!!.first + val connector = fieldConnector.second + connector.response({ba -> Pair(Pair(field, ba), it)}, callbacks=callbacks) + } + } +} + +class NamedClient(mapping: Mapping, conf: Conf): UDPClient() { + val nameField: ConnectionField = StringField() + val inputsTypes: MutableMap> = mutableMapOf() + val outputsTypes: MutableMap> = mutableMapOf() + + init { + conf.inputs.inputs.forEach({ + inputsTypes.put(TYPE_ID.valueOf(it.type), Pair(it.host, it.port)) + }) + conf.outputs.outputs.forEach({ + outputsTypes.put(TYPE_ID.valueOf(it.type), Pair(it.host, it.port)) + }) + mapping.inputs.inputs.forEach { + val hostPort = inputsTypes.get(TYPE_ID.valueOf(it.type)) + registry.getConnection(it.name, TYPE_ID.valueOf(it.type), hostPort!!.first, hostPort.second) + inputs.add(it.name) + } + mapping.outputs.outputs.forEach({ + val hostPort = outputsTypes.get(TYPE_ID.valueOf(it.type)) + registry.getConnection(it.name, TYPE_ID.valueOf(it.type), hostPort!!.first, hostPort.second) + outputs.add(it.name) + }) + inputsTypes.values.forEach({ + inputConnections.add(registry.getConnector(it)!!) + }) + outputsTypes.values.forEach({ + outputConnections.add(registry.getConnector(it)!!) + }) + } + + override fun sendValue(name: String) { + val fieldConnector = registry.getConnection(name) + val field = fieldConnector!!.first + val connector = fieldConnector.second + nameField.setValue(name) + connector.request(field, nameField.getFromFBValue()) + } + + override fun retrieveValues(callbacks: Map Unit>, isInput: Boolean) { + val units = if (isInput) inputConnections else outputConnections + units.forEach { + it.response({ ba -> + var size = ByteBuffer.wrap(ba).getShort(1) + val name = String(ba.copyOfRange(3, 3 + size.toInt())) + val offset = 3 + size.toInt() + registry.getConnection(name) + val field = registry.getConnection(name)!!.first + Pair(Pair(field, ba.copyOfRange(offset, ba.size)), name) + }, callbacks= callbacks) + } + } +} + +class JSONClient(mapping: Mapping, conf: Conf): UDPClient() { + val MSG_TYPE: TYPE_ID = TYPE_ID.STRING + val nameField: ConnectionField = StringField() + val inputsTypes: MutableMap> = mutableMapOf() + val outputsTypes: MutableMap> = mutableMapOf() + + @Serializable + data class Msg(val NAME: String, val TYPE: String, val VALUE: String) + init { + conf.inputs.inputs.forEach({ + inputsTypes.put(TYPE_ID.valueOf(it.type), Pair(it.host, it.port)) + }) + conf.outputs.outputs.forEach({ + outputsTypes.put(TYPE_ID.valueOf(it.type), Pair(it.host, it.port)) + }) + mapping.inputs.inputs.forEach { + val hostPort = inputsTypes.get(MSG_TYPE) + registry.getConnection("${mapping.id}#${it.name}", TYPE_ID.valueOf(it.type), hostPort!!.first, hostPort.second) + inputs.add(it.name) + } + mapping.outputs.outputs.forEach({ + val hostPort = outputsTypes.get(MSG_TYPE) + registry.getConnection("${mapping.id}#${it.name}", TYPE_ID.valueOf(it.type), hostPort!!.first, hostPort.second) + outputs.add(it.name) + }) + conf.inputs.inputs.forEach({ + inputConnections.add(registry.getConnector(Pair(it.host, it.port))!!) + }) + conf.outputs.outputs.forEach({ + outputConnections.add(registry.getConnector(Pair(it.host, it.port))!!) + }) + } + + override fun sendValue(name: String) { + val fieldConnector = registry.getConnection(name) + val field = fieldConnector!!.first + val connector = fieldConnector.second + val data = Msg(name, field.getTypeID().name, field.getMsgValue()) + val msg = Json.encodeToString(data) + connector.request(msg) + } + + override fun retrieveValues(callbacks: Map Unit>, isInput: Boolean) { + val units = if (isInput) inputConnections else outputConnections + units.forEach { + it.response({ + val msg = Json.decodeFromString(it) + val field = registry.getField(msg.NAME)!! + println("GETTING ${field.getTypeID()}") + field.getFBValue(msg.VALUE) + println("GOT ${field.getValue()}") + msg.NAME + }, true, callbacks= callbacks) + } + } +} \ No newline at end of file diff --git a/code/cat_visual/src/main/kotlin/connection/field/BoolField.kt b/code/cat_visual/src/main/kotlin/connection/field/BoolField.kt new file mode 100644 index 000000000..a2384a409 --- /dev/null +++ b/code/cat_visual/src/main/kotlin/connection/field/BoolField.kt @@ -0,0 +1,37 @@ +package connection.field + +import androidx.compose.runtime.MutableState +import androidx.compose.runtime.mutableStateOf + +data class BoolField(override var content:Boolean = false, override val contentState: MutableState = mutableStateOf(content)): ConnectionField(content, contentState) { + + val TRUE_VALUE:Byte = 65 + val FALSE_VALUE:Byte = 64 + + + override fun getFromFBValue():ByteArray { + val res = ByteArray(1) + res[0] = if (content) TRUE_VALUE else FALSE_VALUE + return res + } + + override fun getFBValue(d: ByteArray) { + setValue(d[0] == TRUE_VALUE) + } + + override fun getFBValue(d: String) { + setValue(d.equals("TRUE")); + } + + override fun getMsgValue(): String { + if (content) { + return "TRUE"; + } + return "FALSE"; + } + + override fun getTypeID(): TYPE_ID { + return TYPE_ID.BOOL + } + +} \ No newline at end of file diff --git a/code/cat_visual/src/main/kotlin/connection/field/ConnectionField.kt b/code/cat_visual/src/main/kotlin/connection/field/ConnectionField.kt new file mode 100644 index 000000000..4d539ee6e --- /dev/null +++ b/code/cat_visual/src/main/kotlin/connection/field/ConnectionField.kt @@ -0,0 +1,61 @@ +package connection.field + +import androidx.compose.runtime.MutableState +import kotlinx.coroutines.Dispatchers +import java.lang.UnsupportedOperationException + + +abstract class ConnectionField(open var content: V, open val contentState: MutableState) { + companion object { + fun create(type: TYPE_ID):ConnectionField { +// println(type) + return when (type) { + TYPE_ID.BOOL -> BoolField() + TYPE_ID.REAL -> FloatField(0f) + TYPE_ID.LREAL -> DoubleField(0.0) + TYPE_ID.STRING -> StringField() + TYPE_ID.SINT -> SIntField(0) + TYPE_ID.USINT -> USIntField(0u) + TYPE_ID.INT -> IntField(0) + TYPE_ID.UINT -> UIntField(0u) + TYPE_ID.DINT -> DIntField(0) + TYPE_ID.UDINT -> UDIntField(0u) + TYPE_ID.LINT -> LIntField(0) + TYPE_ID.ULINT -> ULIntField(0u) + else -> {throw UnsupportedOperationException("Unsupported type literal")} + } + } + } + abstract fun getFromFBValue():ByteArray + abstract fun getMsgValue():String + abstract fun getFBValue(d: ByteArray) + abstract fun getFBValue(d: String) + abstract fun getTypeID():TYPE_ID + fun getValue():V { + return content + } + fun setValue(v:V) { + println("!!! BEFORE SET ${content}") + content = v + contentState.value = content + println("!!! SET ${content}") + } +} + +enum class TYPE_ID(val code: Int) { + BOOL(65), + SINT(66), + INT(67), + DINT(68), + LINT(69), + USINT(70), + UINT(71), + UDINT(72), + ULINT(73), + REAL(74), + LREAL(75), + STRING(80), + WSTRING(85), + DATE_AND_TIME(79), + ARRAY(118) +} \ No newline at end of file diff --git a/code/cat_visual/src/main/kotlin/connection/field/DoubleField.kt b/code/cat_visual/src/main/kotlin/connection/field/DoubleField.kt new file mode 100644 index 000000000..4c456030b --- /dev/null +++ b/code/cat_visual/src/main/kotlin/connection/field/DoubleField.kt @@ -0,0 +1,36 @@ +package connection.field; + +import androidx.compose.runtime.MutableState +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.sourceInformation +import java.nio.ByteBuffer +import java.util.* + +data class DoubleField(var defaultValue:Double, override var content:Double = 0.0, override val contentState: MutableState = mutableStateOf(defaultValue)): ConnectionField(content, contentState) { + + override fun getFromFBValue(): ByteArray { + val bytes: ByteArray = ByteBuffer.allocate(5).put(getTypeID().code.toByte()).putDouble(content).array() + return bytes + } + + override fun getMsgValue(): String { + return getValue().toString() + } + + override fun getFBValue(d: ByteArray) { + var buf = ByteBuffer.wrap(d) + + if (buf[0] == TYPE_ID.LREAL.code.toByte()) { + setValue(ByteBuffer.wrap(d).getDouble(1)) + } + } + + override fun getFBValue(d: String) { + setValue(d.toDouble()) + } + + override fun getTypeID(): TYPE_ID { +// TODO("add support of just SINT") + return TYPE_ID.LREAL + } +} diff --git a/code/cat_visual/src/main/kotlin/connection/field/FloatField.kt b/code/cat_visual/src/main/kotlin/connection/field/FloatField.kt new file mode 100644 index 000000000..e44ab1d30 --- /dev/null +++ b/code/cat_visual/src/main/kotlin/connection/field/FloatField.kt @@ -0,0 +1,33 @@ +package connection.field; + +import androidx.compose.runtime.MutableState +import androidx.compose.runtime.mutableStateOf +import java.nio.ByteBuffer + +data class FloatField(var defaultValue:Float, override var content:Float = 0f, override val contentState: MutableState = mutableStateOf(defaultValue)): ConnectionField(content, contentState) { + + override fun getFromFBValue(): ByteArray { + val bytes: ByteArray = ByteBuffer.allocate(5).put(getTypeID().code.toByte()).putFloat(content).array() + return bytes + } + + override fun getMsgValue(): String { + return getValue().toString() + } + + override fun getFBValue(d: ByteArray) { + var buf = ByteBuffer.wrap(d) + + if (buf[0] == TYPE_ID.REAL.code.toByte()) { + setValue(ByteBuffer.wrap(d).getFloat(1)) + } + } + + override fun getFBValue(d: String) { + setValue(d.toFloat()) + } + + override fun getTypeID(): TYPE_ID { + return TYPE_ID.REAL + } +} diff --git a/code/cat_visual/src/main/kotlin/connection/field/IntField.kt b/code/cat_visual/src/main/kotlin/connection/field/IntField.kt new file mode 100644 index 000000000..4ba3719ca --- /dev/null +++ b/code/cat_visual/src/main/kotlin/connection/field/IntField.kt @@ -0,0 +1,238 @@ +package connection.field; + +import androidx.compose.runtime.MutableState +import androidx.compose.runtime.mutableStateOf +import java.nio.ByteBuffer + +data class SIntField(var defaultValue:Byte, override var content:Byte = 0, override val contentState: MutableState = mutableStateOf(defaultValue)): ConnectionField(content, contentState) { + + override fun getFromFBValue(): ByteArray { + val bytes: ByteArray = ByteBuffer.allocate(5).put(getTypeID().code.toByte()).put(content).array() + return bytes + } + + override fun getMsgValue(): String { + return getValue().toString() + } + + override fun getFBValue(d: ByteArray) { + var buf = ByteBuffer.wrap(d) + + if (buf[0] == TYPE_ID.SINT.code.toByte()) { + setValue(ByteBuffer.wrap(d).get(1)) + } + println(d.contentToString()) + } + + override fun getFBValue(d: String) { + setValue(d.toByte()) + } + + override fun getTypeID(): TYPE_ID { + return TYPE_ID.SINT + } +} + +data class USIntField(var defaultValue:UByte, override var content:UByte = 0u, override val contentState: MutableState = mutableStateOf(defaultValue)): ConnectionField(content, contentState) { + + override fun getFromFBValue(): ByteArray { + val bytes: ByteArray = ByteBuffer.allocate(5).put(getTypeID().code.toByte()).put(content.toByte()).array() + return bytes + } + + override fun getMsgValue(): String { + return getValue().toString() + } + + override fun getFBValue(d: ByteArray) { + var buf = ByteBuffer.wrap(d) + + if (buf[0] == TYPE_ID.UINT.code.toByte()) { + setValue(ByteBuffer.wrap(d).get(1).toUByte()) + } + println(d.contentToString()) + } + + override fun getFBValue(d: String) { + setValue(d.toUByte()) + } + + override fun getTypeID(): TYPE_ID { + return TYPE_ID.USINT + } +} + +data class IntField(var defaultValue:Short, override var content:Short = 0, override val contentState: MutableState = mutableStateOf(defaultValue)): ConnectionField(content, contentState) { + + override fun getFromFBValue(): ByteArray { + val bytes: ByteArray = ByteBuffer.allocate(5).put(getTypeID().code.toByte()).putShort(content).array() + return bytes + } + + override fun getMsgValue(): String { + return getValue().toString() + } + + override fun getFBValue(d: ByteArray) { + var buf = ByteBuffer.wrap(d) + + if (buf[0] == TYPE_ID.INT.code.toByte()) { + setValue(ByteBuffer.wrap(d).getShort(1)) + } + println(d.contentToString()) + } + + override fun getFBValue(d: String) { + setValue(d.toShort()) + } + + override fun getTypeID(): TYPE_ID { + return TYPE_ID.INT + } +} + +data class UIntField(var defaultValue:UShort, override var content:UShort = 0u, override val contentState: MutableState = mutableStateOf(defaultValue)): ConnectionField(content, contentState) { + + override fun getFromFBValue(): ByteArray { + val bytes: ByteArray = ByteBuffer.allocate(5).put(getTypeID().code.toByte()).putShort(content.toShort()).array() + return bytes + } + + override fun getMsgValue(): String { + return getValue().toString() + } + + override fun getFBValue(d: ByteArray) { + var buf = ByteBuffer.wrap(d) + + if (buf[0] == TYPE_ID.UINT.code.toByte()) { + setValue(ByteBuffer.wrap(d).getShort(1).toUShort()) + } + println(d.contentToString()) + } + + override fun getFBValue(d: String) { + setValue(d.toUShort()) + } + + override fun getTypeID(): TYPE_ID { + return TYPE_ID.UINT + } +} + +data class DIntField(var defaultValue:Int, override var content:Int = 0, override val contentState: MutableState = mutableStateOf(defaultValue)): ConnectionField(content, contentState) { + + override fun getFromFBValue(): ByteArray { + val bytes: ByteArray = ByteBuffer.allocate(5).put(getTypeID().code.toByte()).putInt(content).array() + return bytes + } + + override fun getMsgValue(): String { + return getValue().toString() + } + + override fun getFBValue(d: ByteArray) { + var buf = ByteBuffer.wrap(d) + + if (buf[0] == TYPE_ID.DINT.code.toByte()) { + setValue(ByteBuffer.wrap(d).getInt(1)) + } + println(d.contentToString()) + } + + override fun getFBValue(d: String) { + setValue(d.toInt()) + } + + override fun getTypeID(): TYPE_ID { + return TYPE_ID.DINT + } +} + +data class UDIntField(var defaultValue:UInt, override var content:UInt = 0u, override val contentState: MutableState = mutableStateOf(defaultValue)): ConnectionField(content, contentState) { + + override fun getFromFBValue(): ByteArray { + val bytes: ByteArray = ByteBuffer.allocate(9).put(getTypeID().code.toByte()).putInt(content.toInt()).array() + return bytes + } + + override fun getMsgValue(): String { + return getValue().toString() + } + + override fun getFBValue(d: ByteArray) { + var buf = ByteBuffer.wrap(d) + + if (buf[0] == TYPE_ID.UDINT.code.toByte()) { + setValue(ByteBuffer.wrap(d).getInt(1).toUInt()) + } + println(d.contentToString()) + } + + override fun getFBValue(d: String) { + setValue(d.toUInt()) + } + + override fun getTypeID(): TYPE_ID { + return TYPE_ID.UDINT + } +} + + +data class LIntField(var defaultValue:Long, override var content:Long = 0, override val contentState: MutableState = mutableStateOf(defaultValue)): ConnectionField(content, contentState) { + + override fun getFromFBValue(): ByteArray { + val bytes: ByteArray = ByteBuffer.allocate(5).put(getTypeID().code.toByte()).putLong(content).array() + return bytes + } + + override fun getMsgValue(): String { + return getValue().toString() + } + + override fun getFBValue(d: ByteArray) { + var buf = ByteBuffer.wrap(d) + + if (buf[0] == TYPE_ID.LINT.code.toByte()) { + setValue(ByteBuffer.wrap(d).getLong(1)) + } + println(d.contentToString()) + } + + override fun getFBValue(d: String) { + setValue(d.toLong()) + } + + override fun getTypeID(): TYPE_ID { + return TYPE_ID.LINT + } +} + +data class ULIntField(var defaultValue:ULong, override var content:ULong = 0uL, override val contentState: MutableState = mutableStateOf(defaultValue)): ConnectionField(content, contentState) { + + override fun getFromFBValue(): ByteArray { + val bytes: ByteArray = ByteBuffer.allocate(9).put(getTypeID().code.toByte()).putLong(content.toLong()).array() + return bytes + } + + override fun getMsgValue(): String { + return getValue().toString() + } + + override fun getFBValue(d: ByteArray) { + var buf = ByteBuffer.wrap(d) + + if (buf[0] == TYPE_ID.UDINT.code.toByte()) { + setValue(ByteBuffer.wrap(d).getLong(1).toULong()) + } + println(d.contentToString()) + } + + override fun getFBValue(d: String) { + setValue(d.toULong()) + } + + override fun getTypeID(): TYPE_ID { + return TYPE_ID.ULINT + } +} diff --git a/code/cat_visual/src/main/kotlin/connection/field/StringField.kt b/code/cat_visual/src/main/kotlin/connection/field/StringField.kt new file mode 100644 index 000000000..d57e7afff --- /dev/null +++ b/code/cat_visual/src/main/kotlin/connection/field/StringField.kt @@ -0,0 +1,31 @@ +package connection.field + +import androidx.compose.runtime.MutableState +import androidx.compose.runtime.mutableStateOf +import java.nio.ByteBuffer + +data class StringField(override var content:String = "", override val contentState: MutableState = mutableStateOf(content)): ConnectionField(content, contentState) { + override fun getFromFBValue(): ByteArray { + val contentBytes: ByteArray = content.toByteArray() + return ByteBuffer.allocate(contentBytes.size + 3).put(TYPE_ID.STRING.code.toByte()).putShort(content.length.toShort()).put(contentBytes).array() + } + + override fun getMsgValue(): String { + return content + } + + override fun getFBValue(d: ByteArray) { + var size = ByteBuffer.wrap(d).getShort(1) + setValue(String(d.copyOfRange(3, 3 + size.toInt()))) + println(d.contentToString()) + } + + override fun getFBValue(d: String) { + setValue(d) + } + + override fun getTypeID(): TYPE_ID { + return TYPE_ID.STRING + } + +} \ No newline at end of file diff --git a/code/cat_visual/src/main/kotlin/connection/field/WStringField.kt b/code/cat_visual/src/main/kotlin/connection/field/WStringField.kt new file mode 100644 index 000000000..41ef84f6d --- /dev/null +++ b/code/cat_visual/src/main/kotlin/connection/field/WStringField.kt @@ -0,0 +1,31 @@ +package connection.field + +import androidx.compose.runtime.MutableState +import androidx.compose.runtime.mutableStateOf +import java.nio.ByteBuffer + +data class WStringField(override var content:String = "", override val contentState: MutableState = mutableStateOf(content)): ConnectionField(content, contentState) { + override fun getFromFBValue(): ByteArray { + val contentBytes: ByteArray = content.toByteArray(Charsets.UTF_16) + return ByteBuffer.allocate(contentBytes.size * 2 + 3).put(getTypeID().code.toByte()).putShort((content.length.toShort() * 2).toShort()).put(contentBytes).array() + } + + override fun getMsgValue(): String { + TODO("Not yet implemented") + } + + override fun getFBValue(d: ByteArray) { + var size = ByteBuffer.wrap(d).getShort(1) + setValue(String(d.copyOfRange(3, 3 + size.toInt()), Charsets.UTF_16)) + println(d.contentToString()) + } + + override fun getFBValue(d: String) { + TODO("Not yet implemented") + } + + override fun getTypeID(): TYPE_ID { + return TYPE_ID.WSTRING + } + +} \ No newline at end of file diff --git a/code/cat_visual/src/main/kotlin/connection/provider/ConnectionProvider.kt b/code/cat_visual/src/main/kotlin/connection/provider/ConnectionProvider.kt new file mode 100644 index 000000000..a81d45400 --- /dev/null +++ b/code/cat_visual/src/main/kotlin/connection/provider/ConnectionProvider.kt @@ -0,0 +1,89 @@ +package connection.provider + +import connection.ConnectionFieldRegistry +import connection.field.ConnectionField +import connection.field.TYPE_ID +import java.io.BufferedReader +import java.io.InputStreamReader +import java.io.PrintWriter +import java.net.DatagramPacket +import java.net.InetAddress +import java.net.MulticastSocket +import java.net.ServerSocket +import java.net.Socket +import java.nio.ByteBuffer +import kotlin.concurrent.thread + +abstract class ConnectionProvider(private val port: Int, private val host: String = "225.0.0.1") { + abstract fun response(fieldGetter: (ByteArray) -> Pair, ByteArray>, String>, ping:Long = 500, callbacks: Map Unit> = mapOf()) + abstract fun response(fieldSetter: (String) -> String, log: Boolean, ping:Long = 500, callbacks: Map Unit> = mapOf()) + abstract fun request(field: ConnectionField, prefix: ByteArray) + abstract fun request(msg: String) +} + +class UDPConnectionProvider(private val port: Int, private val host: String = "225.0.0.1"): ConnectionProvider(port, host) { + val group = InetAddress.getByName(host); + val socket = MulticastSocket(port); + + + init { + socket.joinGroup(group) + } + + var ind = 0 + + override fun response(fieldGetter: (ByteArray) -> Pair, ByteArray>, String>, ping:Long, callbacks: Map Unit>) { + thread { + while (true) { + val buf = ByteArray(1024); + val recv = DatagramPacket(buf, buf.size); + socket.receive(recv) + val fieldData = fieldGetter(recv.data) + val field = fieldData.first.first + val data = fieldData.first.second + val name = fieldData.second + println("GETTING ${field.getTypeID()}") + field.getFBValue(data) + callbacks.getOrDefault(name, {})() + println("GOT ${field.getValue()}") + Thread.sleep(ping) + } + } + } + + override fun request(field: ConnectionField, prefix: ByteArray) { + println("SENDING ${field.getValue()}") + var msg = field.getFromFBValue() + msg = prefix.plus(msg) + val hi = DatagramPacket(msg, msg.size, + group, port); + socket.send(hi) + } + + override fun request(msgJ: String) { + println("SENDING ${msgJ}") + val contentBytes = msgJ.toByteArray() + val msg = ByteBuffer.allocate(contentBytes.size + 3).put(TYPE_ID.STRING.code.toByte()).putShort(msgJ.length.toShort()).put(contentBytes).array() + val hi = DatagramPacket(msg, msg.size, + group, port); + socket.send(hi) + } + + override fun response(fieldSetter: (String) -> String, log: Boolean, ping:Long, callbacks: Map Unit>) { + thread { + while (true) { + + val buf = ByteArray(1024); + val recv = DatagramPacket(buf, buf.size); + socket.receive(recv) + var size = ByteBuffer.wrap(recv.data).getShort(1) + var msg = String(recv.data.copyOfRange(3, 3 + size.toInt())) + if (log) println("MESSAGE $msg") + val name = fieldSetter(msg) + callbacks.getOrDefault(name, {})() + Thread.sleep(ping) + } + } + } + +} \ No newline at end of file diff --git a/code/cat_visual/src/main/kotlin/example/COUNTER/COMMON_CONF.xml b/code/cat_visual/src/main/kotlin/example/COUNTER/COMMON_CONF.xml new file mode 100644 index 000000000..b887ebd85 --- /dev/null +++ b/code/cat_visual/src/main/kotlin/example/COUNTER/COMMON_CONF.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/code/cat_visual/src/main/kotlin/example/COUNTER/COUNT.xml b/code/cat_visual/src/main/kotlin/example/COUNTER/COUNT.xml new file mode 100644 index 000000000..e69de29bb diff --git a/code/cat_visual/src/main/kotlin/example/COUNTER/COUNTER.kt b/code/cat_visual/src/main/kotlin/example/COUNTER/COUNTER.kt new file mode 100644 index 000000000..309fe7173 --- /dev/null +++ b/code/cat_visual/src/main/kotlin/example/COUNTER/COUNTER.kt @@ -0,0 +1,44 @@ +package example.COUNTER + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.width +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.dp +import connection.AbstractClient +import connection.ConnectionFieldRegistry +import lib.elements.getters.Bulb +import lib.elements.getters.TextBox +import lib.elements.setters.Checkbox +import lib.elements.setters.Toggle +import lib.visual.PositionedBox + + +@Composable +fun LampHMI(client: AbstractClient, id: String) { + Bulb("$id#LAMP", client) +} +@Composable +fun ToggleHMI(client: AbstractClient, id: String) { + Toggle("$id#TOGGLE", client) +} + +@Composable +fun CounterHMI(client: AbstractClient, id: String) { + Row { + Text("Count of changes: ") + TextBox("$id#COUNT", client, Modifier.width(40.dp).height(30.dp).background(Color.LightGray)) +// PositionedBox( children = {Indicator("count", "225.0.0.2", 65003, registry, 0, 100, 1000.dp)}, x = 100, y = 100) + } +} + +@Composable +fun CounterLampHMI(client: AbstractClient, id: String) { + PositionedBox(children = {CounterHMI(client, "1")}, x = 200) + LampHMI(client, "1") + PositionedBox(children = {example.COUNTER.ToggleHMI(client, "1")}, x = 300, y = 100) +} \ No newline at end of file diff --git a/code/cat_visual/src/main/kotlin/example/COUNTER/COUNTER.xml b/code/cat_visual/src/main/kotlin/example/COUNTER/COUNTER.xml new file mode 100644 index 000000000..869c96923 --- /dev/null +++ b/code/cat_visual/src/main/kotlin/example/COUNTER/COUNTER.xml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/code/cat_visual/src/main/kotlin/example/COUNTER/COUNTER_CONF.xml b/code/cat_visual/src/main/kotlin/example/COUNTER/COUNTER_CONF.xml new file mode 100644 index 000000000..bb9432301 --- /dev/null +++ b/code/cat_visual/src/main/kotlin/example/COUNTER/COUNTER_CONF.xml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/code/cat_visual/src/main/kotlin/example/COUNTER/COUNTER_PLAIN.xml b/code/cat_visual/src/main/kotlin/example/COUNTER/COUNTER_PLAIN.xml new file mode 100644 index 000000000..8998ad64d --- /dev/null +++ b/code/cat_visual/src/main/kotlin/example/COUNTER/COUNTER_PLAIN.xml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/code/cat_visual/src/main/kotlin/example/COUNTER/LAMP.xml b/code/cat_visual/src/main/kotlin/example/COUNTER/LAMP.xml new file mode 100644 index 000000000..869c96923 --- /dev/null +++ b/code/cat_visual/src/main/kotlin/example/COUNTER/LAMP.xml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/code/cat_visual/src/main/kotlin/example/COUNTER/TOGGLE.xml b/code/cat_visual/src/main/kotlin/example/COUNTER/TOGGLE.xml new file mode 100644 index 000000000..e69de29bb diff --git a/code/cat_visual/src/main/kotlin/example/INCHOICE/INCHOICE.kt b/code/cat_visual/src/main/kotlin/example/INCHOICE/INCHOICE.kt new file mode 100644 index 000000000..b835fd35d --- /dev/null +++ b/code/cat_visual/src/main/kotlin/example/INCHOICE/INCHOICE.kt @@ -0,0 +1,75 @@ +//package example.INCHOICE +// +//import androidx.compose.foundation.background +//import androidx.compose.foundation.layout.Box +//import androidx.compose.foundation.layout.Column +//import androidx.compose.foundation.layout.height +//import androidx.compose.foundation.layout.width +//import androidx.compose.material.Switch +//import androidx.compose.material.Text +//import androidx.compose.runtime.* +//import androidx.compose.ui.Modifier +//import androidx.compose.ui.graphics.Color +//import androidx.compose.ui.unit.dp +//import connection.field.BoolField +//import connection.field.ConnectionField +//import connection.field.StringField +//import connection.provider.ConnectionProvider +// +//val field: ConnectionField = BoolField() +//val toggleField: ConnectionField = BoolField() +//val ipField: ConnectionField = StringField() +// +//var connectionProvider: ConnectionProvider = ConnectionProvider(field, 65001) +//var connectionProviderToggle: ConnectionProvider = ConnectionProvider(toggleField, 65000) +//var connectionProviderIpText: ConnectionProvider = ConnectionProvider(ipField, 65002) +// +// +//val ping = 1 +// +//@Composable +//fun LampToggle() { +// val checkedState = remember { toggleField } +// Switch( +// checked = checkedState.contentState.value, +// onCheckedChange = { +// checkedState.setValue(it) +// connectionProviderToggle.request()} +// ) +//} +// +// +//val trueColor = Color.Yellow +//val falseColor = Color.Black +// +// +//@Composable +//fun Lamp_HMI() { +// fun getColor(s: Boolean): Color { +// if (s) { +// return trueColor +// } else { +// return falseColor +// } +// } +// +// +// var checkedState = remember{ field } +// Column { +// Box( +// modifier = Modifier.background(color = if (checkedState.contentState.value) trueColor else falseColor) +// .width(600.dp) +// .height(600.dp) +// ) { +// connectionProvider.response() +// } +// Box( +// modifier = Modifier.background(color = Color.Gray) +// .width(200.dp) +// .height(200.dp) +// ) { +// Text(ipField.contentState.value) +// connectionProviderIpText.response() +// } +// } +//} diff --git a/code/cat_visual/src/main/kotlin/example/INCHOICE/INCHOICE_HMI.cnv.xml b/code/cat_visual/src/main/kotlin/example/INCHOICE/INCHOICE_HMI.cnv.xml new file mode 100644 index 000000000..5297eeccc --- /dev/null +++ b/code/cat_visual/src/main/kotlin/example/INCHOICE/INCHOICE_HMI.cnv.xml @@ -0,0 +1,17 @@ + + + + CHOICES + + + I + + + + + + + + + + \ No newline at end of file diff --git a/code/cat_visual/src/main/kotlin/example/WATER_TANK/WATER_TANK.kt b/code/cat_visual/src/main/kotlin/example/WATER_TANK/WATER_TANK.kt new file mode 100644 index 000000000..3d66990ed --- /dev/null +++ b/code/cat_visual/src/main/kotlin/example/WATER_TANK/WATER_TANK.kt @@ -0,0 +1,121 @@ +package example.WATER_TANK + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp +import androidx.compose.ui.zIndex +import connection.AbstractClient +import connection.ConnectionFieldRegistry +import lib.elements.* +import lib.elements.getters.Bulb +import lib.elements.getters.LightingText +import lib.elements.getters.VerticalIndicator +import lib.elements.setters.RoundKnob +import lib.visual.PositionedBox + +@Composable +fun WaterTank(client: AbstractClient) { + + Box { + PositionedBox(@Composable { LampIndicator("lampIndicator1", client) }, 120, 190) + PositionedBox(@Composable { LampIndicator("lampIndicator2", client) }, 120, 380) + PositionedBox(@Composable { PipeConnector(Color.Gray, 100.dp, 30.dp) }, 150, 100) + PositionedBox(@Composable { Figure(RoundedCornerShape(100.dp), + modifier = Modifier.size(200.dp, 300.dp) + .background(brush = METALLIC_BRUSH, shape = RoundedCornerShape(20.dp)) + ) + }, 200, 150, zIndex = 2f) + PositionedBox(@Composable { Pipe(Color.Gray, 100.dp, 30.dp) }, 400, 400) + PositionedBox(@Composable { + VerticalIndicator( + "tankIndicator", client, + color = Color.Blue, step = 20f, minTemperature = 0f, maxTemperature = 100f, + trackHeight = 200.dp, indicatorWidth = 20.dp + ) + }, 300, 200, zIndex = 3f) + } +} + +@Composable +fun LampIndicator(name: String, client: AbstractClient, pipeSize: Dp = 30.dp) { + Row { + PositionedBox(@Composable { + Bulb( + name, + client, + size = pipeSize, + borderWidth = 4.dp, + modifier = Modifier.zIndex(2f) + ) + }, pipeSize.value / 2) + Pipe(Color.Gray, 100.dp, pipeSize) + } +} + + +@Composable +fun System(client: AbstractClient) { + PositionedBox(@Composable { + RoundKnob( + "knob1", + client, + 0..100, + 0f, + knobSize = 60.dp, + knobColor = Color.Red + ) + }, 10, 50) + PositionedBox(@Composable { + RoundKnob( + "knob2", + client, + 0..100, + 0f, + knobSize = 60.dp, + knobColor = Color.Blue + ) + }, 10, 120) + WaterTank(client) + PositionedBox(@Composable { + VerticalIndicator( + "outputIndicator", client, + color = Color.Red, step = 20f, minTemperature = 0f, maxTemperature = 100f, + trackHeight = 200.dp, indicatorWidth = 20.dp + ) + }, 440, 150, zIndex = 3f) + PositionedBox(@Composable { + LightingText( + "stateInlet", + client, + "Inlet", + width = 70.dp, + height = 25.dp, + borderWidth = 5.dp + ) + }, 500, 150) + PositionedBox(@Composable { + LightingText( + "stateHeat", + client, + "Heat", + width = 70.dp, + height = 25.dp, + borderWidth = 5.dp + ) + }, 500, 200) + PositionedBox(@Composable { + LightingText( + "stateOutlet", + client, + "Outlet", + width = 70.dp, + height = 25.dp, + borderWidth = 5.dp + ) + }, 500, 250) +} \ No newline at end of file diff --git a/code/cat_visual/src/main/kotlin/example/WATER_TANK/WATER_TANK.xml b/code/cat_visual/src/main/kotlin/example/WATER_TANK/WATER_TANK.xml new file mode 100644 index 000000000..bba095874 --- /dev/null +++ b/code/cat_visual/src/main/kotlin/example/WATER_TANK/WATER_TANK.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/code/cat_visual/src/main/kotlin/example/WATER_TANK/WATER_TANK_CONF.xml b/code/cat_visual/src/main/kotlin/example/WATER_TANK/WATER_TANK_CONF.xml new file mode 100644 index 000000000..b7461d6df --- /dev/null +++ b/code/cat_visual/src/main/kotlin/example/WATER_TANK/WATER_TANK_CONF.xml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/code/cat_visual/src/main/kotlin/example/WATER_TANK/WATER_TANK_PLAIN.xml b/code/cat_visual/src/main/kotlin/example/WATER_TANK/WATER_TANK_PLAIN.xml new file mode 100644 index 000000000..f59dbb5dc --- /dev/null +++ b/code/cat_visual/src/main/kotlin/example/WATER_TANK/WATER_TANK_PLAIN.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/code/cat_visual/src/main/kotlin/lib/elements/figures/elements.kt b/code/cat_visual/src/main/kotlin/lib/elements/figures/elements.kt new file mode 100644 index 000000000..d23a47a84 --- /dev/null +++ b/code/cat_visual/src/main/kotlin/lib/elements/figures/elements.kt @@ -0,0 +1,212 @@ +package lib.elements + +import androidx.compose.animation.core.AnimationSpec +import androidx.compose.animation.core.animateFloatAsState +import androidx.compose.animation.core.tween +import androidx.compose.foundation.Canvas +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.shape.CutCornerShape +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.MaterialTheme +import androidx.compose.runtime.Composable +import androidx.compose.runtime.MutableState +import androidx.compose.runtime.getValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.draw.rotate +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.geometry.Size +import androidx.compose.ui.graphics.* +import androidx.compose.ui.graphics.drawscope.Stroke +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp + + +@Composable +fun Rectangle(color: Color, width: Dp, height: Dp) { + Box( + modifier = Modifier.background(color = color) + .width(width) + .height(height) + ) { + } +} + +@Composable +fun Rectangle(color: Color, size: Dp) { + Box( + modifier = Modifier.background(color = color) + .size(size) + ) { + } +} + +@Composable +fun Round(color: Color, width: Dp, height: Dp) { + Box( + modifier = Modifier.background(color = color) + .clip(CircleShape) + .width(width) + .height(height) + ) { + } +} + +@Composable +fun Round(color: Color, size: Dp) { + Box( + modifier = Modifier.background(color = color) + .clip(CircleShape) + .size(size) + ) { + } +} + +@Composable +fun Round(modifier: Modifier, width: Dp, height: Dp) { + Box( + modifier = Modifier + .clip(CircleShape) + .width(width) + .height(height) + .then(modifier) + ) { + } +} + +@Composable +fun RoundedRectangle(color: Color, width: Dp, height: Dp, radius: Dp) { + Box( + modifier = Modifier.background(color = color) + .clip(RoundedCornerShape(radius)) + .width(width) + .height(height) + ) { + } +} + +@Composable +fun RoundedRectangle(color: Color, size: Dp, radius: Dp) { + Box( + modifier = Modifier.background(color = color) + .clip(RoundedCornerShape(radius)) + .size(size) + ) { + } +} + + +@Composable +fun RoundedRectangle(modifier: Modifier, width: Dp, height: Dp, radius: Dp) { + Box( + modifier = modifier + .clip(RoundedCornerShape(radius)) + .width(width) + .height(height) + ) { + } +} + +@Composable +fun CutRectangle(color: Color, width: Dp, height: Dp, radius: Dp) { + Figure(shape = CutCornerShape(radius), + modifier = Modifier.background(color = color) + .width(width) + .height(height) + ) +} + +@Composable +fun CutRectangle(color: Color, size: Dp, radius: Dp) { + Figure( + shape = CutCornerShape(radius), + modifier = Modifier.background(color = color) + .clip(CutCornerShape(radius)) + .size(size) + ) +} + + +@Composable +fun Figure(shape: Shape = RectangleShape, modifier: Modifier = Modifier) { + Box(modifier = modifier.clip(shape)){ + } +} + +@Composable +fun OneDAnimatedComposable( + content: @Composable () -> Unit, + isAtTheEnd: Boolean, + targetValue: Float, + horizontally: Boolean = true, + animationSpec: AnimationSpec = tween(durationMillis = 1000), +) { + val animatedValue by animateFloatAsState( + targetValue = if (isAtTheEnd) targetValue else 0f, + animationSpec = animationSpec + ) + + var modifier:Modifier = Modifier; + if (horizontally) { + modifier = modifier.offset(x = animatedValue.dp) + } else { + modifier = modifier.offset(y = animatedValue.dp) + } + Box( + modifier = modifier + ) { + content() + } +} + +@Composable +fun Pipe( + color: Color, + pipeWidth: Dp, + pipeHeight: Dp, + modifier: Modifier = Modifier +) { + Box( + modifier = modifier + .width(pipeWidth) + .height(pipeHeight) + .background(brush = Brush.verticalGradient(listOf(color, color.copy(alpha = 0.2f), color))) + ){} +} + +@Composable +fun PipeConnector( + color: Color, + connectorWidth: Dp, + connectorHeight: Dp, + modifier: Modifier = Modifier +) { + Box(modifier = modifier) { + Box( + modifier = Modifier + .offset() + .width(connectorWidth) + .height(connectorHeight) + .background( + brush = Brush.verticalGradient(listOf(color, color.copy(alpha = 0.2f), color)), + shape = RoundedCornerShape(0.dp, connectorHeight, connectorHeight, 0.dp) + ) + ) {} + val rotatedBoxOffset = connectorWidth / 2 - connectorHeight /2 + Box( + modifier = Modifier + .offset(x = rotatedBoxOffset, y = rotatedBoxOffset) + .rotate(-90f) + .width(connectorWidth) + .height(connectorHeight) + .background( + brush = Brush.verticalGradient(listOf(color, color.copy(alpha = 0.2f), color)), + shape = RoundedCornerShape(0.dp, connectorHeight, connectorHeight, 0.dp) + ) + ) {} + } + +} \ No newline at end of file diff --git a/code/cat_visual/src/main/kotlin/lib/elements/getters/elements.kt b/code/cat_visual/src/main/kotlin/lib/elements/getters/elements.kt new file mode 100644 index 000000000..3be2f0045 --- /dev/null +++ b/code/cat_visual/src/main/kotlin/lib/elements/getters/elements.kt @@ -0,0 +1,221 @@ +package lib.elements.getters + +import androidx.compose.foundation.* +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Brush +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.RectangleShape +import androidx.compose.ui.graphics.StrokeCap +import androidx.compose.ui.graphics.drawscope.Stroke +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.font.SystemFontFamily +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.TextUnit +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.compose.ui.zIndex +import connection.AbstractClient +import connection.ConnectionFieldRegistry +import connection.field.ConnectionField +import connection.field.TYPE_ID +import connection.provider.ConnectionProvider +import lib.elements.* + +@Composable +fun Bulb(name: String, client: AbstractClient, + size: Dp = 60.dp, borderWidth:Dp = 10.dp, + modifier: Modifier = Modifier + ) { + + val field = client.getField(name) as ConnectionField + + var checkedStateBulb = remember { field } + Round( + modifier.background(brush = if (checkedStateBulb.contentState.value) LIGHT_RADIAL_BRUSH else DARK_RADIAL_BRUSH) + .border(width = borderWidth, brush = METALLIC_BRUSH, shape = CircleShape), + size, + size + ) +} + + +@Composable +fun LightingText(name: String, client: AbstractClient, + text:String, + width: Dp = 60.dp, height: Dp = 60.dp, borderWidth:Dp = 10.dp, + modifier: Modifier = Modifier, lightBrush: Brush = LIGHT_RADIAL_BRUSH + ) { + + val field = client.getField(name) as ConnectionField + + var checkedStateBulb = remember { field } + + Box( + modifier = modifier.background(brush = if (checkedStateBulb.contentState.value) lightBrush else DARK_RADIAL_BRUSH, shape = RoundedCornerShape(height / 4)) + .border(width = borderWidth, brush = METALLIC_BRUSH, shape = RoundedCornerShape(height / 4)) + .widthIn(min = width) + .heightIn(min = height) + .clip(RoundedCornerShape(height / 4)), + ) { + Text(text, modifier = Modifier.align(Alignment.Center)) + } +} + +@Composable +fun TextBox( + name: String, + client: AbstractClient, + modifier: Modifier = Modifier.focusable(true) +) { + val field = client.getField(name) + + var checkedState = remember { field } + Box( + modifier = modifier.then(Modifier.fillMaxWidth().fillMaxHeight()) + ) { + Text(checkedState!!.contentState.value.toString()) + } +} + +@Composable +fun Indicator( + name: String, client: AbstractClient, + minIndicatorValue: Int, maxIndicatorValue: Int, size: Dp, + indicatorThickness: Dp = 28.dp, + animationDuration: Int = 1000, + animationDelay: Int = 0 +) { + val field = client.getField(name) as ConnectionField + + var checkedState = remember { field } + Box( + contentAlignment = Alignment.Center, + modifier = Modifier.wrapContentSize().padding(indicatorThickness) + ) { + Canvas( + modifier = Modifier + .height(size + indicatorThickness) + .width(size + indicatorThickness) + ) { + drawArc( + color = Color.LightGray, + startAngle = 0f, + sweepAngle = -180f, + useCenter = false, + style = Stroke(width = indicatorThickness.toPx(), cap = StrokeCap.Round) + ) + + var sweepAngle = 0f; + if (checkedState.contentState.value.toInt() != 0) { + sweepAngle = (checkedState.contentState.value.toInt() / (maxIndicatorValue - minIndicatorValue).toFloat()) * 180f + } + + // Foreground circle + drawArc( + color = Color.Red, + startAngle = 180f, + sweepAngle = sweepAngle, + useCenter = false, + style = Stroke(indicatorThickness.toPx(), cap = StrokeCap.Round) + ) + + + } + Text( + text = checkedState.contentState.value.toString(), + color = Color.Black, + style = MaterialTheme.typography.body1, + textAlign = TextAlign.Center, + modifier = Modifier + .align(Alignment.Center), + fontSize = 30.sp + ) + } +} + + +@Composable +fun VerticalIndicator( + name: String, client: AbstractClient, + temperature: Float = 0f, + maxTemperature: Float, + minTemperature: Float, + color: Color, + step: Float, + modifier: Modifier = Modifier, + trackHeight: Dp = 400.dp, + indicatorWidth: Dp = 48.dp, + legendFontSize: TextUnit = 12.sp, + legendFontColor: Color = Color.Black, + font: SystemFontFamily = FontFamily.Default, + showCurrentState: Boolean = false +) { + val field = client.getField(name) as ConnectionField + var checkedState = remember { field } + + val stepCount = ((maxTemperature - minTemperature) / step).toInt() + val temperatureRange = maxTemperature - minTemperature + + Box( + modifier = modifier + .width(indicatorWidth) + .height(trackHeight) + .background(Color.LightGray) + .border(BorderStroke(3.dp, METALLIC_BRUSH), RectangleShape) + ) { + val temperatureOffset = (checkedState.contentState.value.toFloat() - minTemperature) / temperatureRange + val indicatorHeight = (temperatureOffset * trackHeight.value).dp + + + Box( + modifier = Modifier + .fillMaxWidth() + .height(indicatorHeight) + .background(color) + .align(Alignment.BottomCenter) + ) { + + if (showCurrentState) { + Text( + text = "${checkedState.contentState.value}", + fontSize = 16.sp, + fontWeight = FontWeight.Bold, + color = legendFontColor, + modifier = Modifier.offset(y = trackHeight) + ) + } + } + + } + for (i in (minTemperature.toInt()..maxTemperature.toInt()).reversed() step step.toInt()) { + val halfLegendHeight = legendFontSize.value.dp / 2f + val labelOffset = ((i - minTemperature) / temperatureRange).coerceIn(0f, 1f) + val labelTop = (((1f - labelOffset) * (trackHeight.value)) - halfLegendHeight.value).coerceIn(0f, trackHeight.value).dp + Box(modifier = Modifier.width(indicatorWidth * 2)) { + Text( + modifier = Modifier.offset(x = indicatorWidth, y = labelTop), + text = "$i", + fontSize = legendFontSize, + fontWeight = FontWeight.Light, + fontFamily = font, + color = legendFontColor, + softWrap = false, + lineHeight = legendFontSize + ) + } + } + +} \ No newline at end of file diff --git a/code/cat_visual/src/main/kotlin/lib/elements/setters/elements.kt b/code/cat_visual/src/main/kotlin/lib/elements/setters/elements.kt new file mode 100644 index 000000000..a13e073dd --- /dev/null +++ b/code/cat_visual/src/main/kotlin/lib/elements/setters/elements.kt @@ -0,0 +1,549 @@ +package lib.elements.setters + +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.foundation.* +import androidx.compose.foundation.gestures.* +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.lazy.itemsIndexed +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.material.* +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.ArrowDropDown +import androidx.compose.material.icons.filled.Check +import androidx.compose.material.icons.filled.Done +import androidx.compose.runtime.Composable +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.getValue +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.draw.rotate +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.geometry.Size +import androidx.compose.ui.graphics.* +import androidx.compose.ui.graphics.drawscope.Stroke +import androidx.compose.ui.input.pointer.consumeAllChanges +import androidx.compose.ui.input.pointer.consumePositionChange +import androidx.compose.ui.input.pointer.pointerInput +import androidx.compose.ui.input.pointer.positionChange +import androidx.compose.ui.layout.boundsInWindow +import androidx.compose.ui.layout.onGloballyPositioned +import androidx.compose.ui.layout.onSizeChanged +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.input.ImeAction +import androidx.compose.ui.text.input.KeyboardType +import androidx.compose.ui.text.input.TextFieldValue +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.* +import androidx.compose.ui.zIndex +import connection.AbstractClient +import connection.ConnectionFieldRegistry +import connection.field.* +import connection.provider.ConnectionProvider +import lib.elements.METALLIC_BRUSH +import java.lang.UnsupportedOperationException +import kotlin.concurrent.thread +import kotlin.math.PI +import kotlin.math.atan2 +import kotlin.math.roundToInt + +@Composable +fun CustomButton( + text: String, + onClick: () -> Unit, + modifier: Modifier = Modifier, + buttonColors: ButtonColors = ButtonDefaults.buttonColors(), + textColor: Color = Color.Black, + backgroundColor: Color = Color.White, + borderColor: Color = Color.Transparent, + borderWidth: Int = 0, + cornerRadius: Int = 0 +) { + Button( + onClick = onClick, + modifier = modifier, + colors = buttonColors, + shape = RoundedCornerShape(cornerRadius.dp), + border = BorderStroke(width = borderWidth.dp, color = borderColor), + contentPadding = PaddingValues(16.dp), + elevation = ButtonDefaults.elevation(defaultElevation = 0.dp, pressedElevation = 2.dp) + ) { + Text( + text = text, + color = textColor, + modifier = Modifier.padding(4.dp) + ) + } +} + +@Composable +fun Toggle( + name: String, client: AbstractClient, + modifier: Modifier = Modifier, + onCheckedChange: (Boolean) -> Unit = {} +) { + val toggleField = client.getField(name) as ConnectionField + + val checkedStateToggle = remember { toggleField } + Switch( + modifier = modifier.size(24.dp), + checked = checkedStateToggle.contentState.value, + onCheckedChange = { + checkedStateToggle.setValue(it) + client.sendValue(name) + onCheckedChange(it) + } + ) +} + +@Composable +fun Checkbox( + name: String, client: AbstractClient, + modifier: Modifier = Modifier, + onCheckedChange: (Boolean) -> Unit = {}, + checkboxColor: Color = MaterialTheme.colors.primary, + checkmarkColor: Color = Color.White, + disabledColor: Color = MaterialTheme.colors.onSurface.copy(alpha = 0.38f), + contentDescription: String? = null +) { + val checkboxField = client.getField(name) as ConnectionField + + val checkedStateCheckbox = remember { checkboxField } + + Box( + modifier = modifier + .clickable( + onClick = { + val changedValue = !checkedStateCheckbox.contentState.value + checkedStateCheckbox.setValue(changedValue) + client.sendValue(name) + onCheckedChange(changedValue) + }) + .size(24.dp), + contentAlignment = Alignment.Center + ) { + val backgroundColor = if (checkedStateCheckbox.contentState.value) checkboxColor else disabledColor + Box( + modifier = Modifier + .size(20.dp) + .background(color = backgroundColor) + .border(width = 2.dp, brush = METALLIC_BRUSH, shape = RectangleShape), + contentAlignment = Alignment.Center + ) { + if (checkedStateCheckbox.contentState.value) { + Icon( + imageVector = Icons.Default.Check, + contentDescription = contentDescription, + tint = checkmarkColor, + modifier = Modifier.size(12.dp) + ) + } + } + } +} + +@Composable +fun ListBox( + name: String, client: AbstractClient, + modifier: Modifier = Modifier, + items: List, + onItemSelected: (String) -> Unit = {}, + dropdownMaxHeight: Dp = 240.dp, + content: @Composable (String) -> Unit +) { + val comboBoxField = client.getField(name) as ConnectionField + + val checkedStateComboBox = remember { comboBoxField } + var expanded by remember { mutableStateOf(false) } + var dropdownHeight by remember { mutableStateOf(0.dp) } + val density = LocalDensity.current + val dropdownHeightPx = with(density) { dropdownHeight.toPx() } + var selectedItem: String by remember { mutableStateOf("") } + var textfieldSize by remember { mutableStateOf(0) } + val interactionSource = remember { + MutableInteractionSource() + } + + Column( + modifier = modifier.wrapContentSize().clickable( + interactionSource = interactionSource, + indication = null, + onClick = { + expanded = false + } + ), + horizontalAlignment = Alignment.Start + ) { + Box( + modifier = Modifier + .fillMaxWidth() + .background(color = Color.White, shape = MaterialTheme.shapes.medium) + .padding(horizontal = 16.dp, vertical = 12.dp) + ) { + Row(verticalAlignment = Alignment.CenterVertically, + modifier = Modifier.onSizeChanged { + textfieldSize = it.width +// print(textfieldSize) + }) { + + Box(modifier = Modifier.weight(1f)) { + content(selectedItem) + } + Icon(imageVector = Icons.Default.ArrowDropDown, + contentDescription = null, + Modifier.size(24.dp).alignByBaseline().clickable { expanded = !expanded }) + + } + } + DropdownMenu( + expanded = expanded, + onDismissRequest = { expanded = false }, + modifier = Modifier + .heightIn(max = dropdownMaxHeight) + .width(with(LocalDensity.current) { textfieldSize.toDp() }) + .onSizeChanged { dropdownHeight = it.height.dp } + ) { + items.forEach { item -> + DropdownMenuItem( + onClick = { + checkedStateComboBox.setValue(item) + client.sendValue(name) + onItemSelected(item) + selectedItem = item + expanded = false + }, + modifier = Modifier + .fillMaxWidth() + .heightIn(min = 48.dp) + ) { + content(item) + } + } + } + } +} + + +@Composable +fun ComboBox( + name: String, client: AbstractClient, + modifier: Modifier = Modifier, + items: List, + onItemSelected: (String) -> Unit = {}, + dropdownMaxHeight: Dp = 240.dp, + content: @Composable (String) -> Unit +) { + val comboBoxField = client.getField(name) as ConnectionField + + val checkedStateComboBox = remember { comboBoxField } + var expanded by remember { mutableStateOf(false) } + var dropdownHeight by remember { mutableStateOf(0.dp) } + var selectedItem by remember { mutableStateOf("") } + var textfieldSize by remember { mutableStateOf(0) } + val scrollState = rememberScrollState() + + Column( + modifier = modifier.wrapContentSize(), + horizontalAlignment = Alignment.Start + ) { + + Box(modifier = Modifier.fillMaxWidth()) { + OutlinedTextField( + value = selectedItem, + onValueChange = { + selectedItem = it + expanded = true + }, + modifier = Modifier.fillMaxWidth(), + label = { Text("Select an item") }, + keyboardOptions = KeyboardOptions( + keyboardType = KeyboardType.Text, + imeAction = ImeAction.Done + ), + trailingIcon = { + Icon( + Icons.Default.ArrowDropDown, + "Drop Down", + Modifier.size(24.dp).clickable { expanded = !expanded } + ) + } + ) + } + AnimatedVisibility(visible = expanded) { + Card( + modifier = Modifier + .padding(horizontal = 5.dp) + .fillMaxWidth(), + elevation = 15.dp + ) { + var currItems: List = items.sorted() + if (selectedItem.isNotEmpty()) { + currItems = items.filter { it.lowercase().contains(selectedItem.lowercase()) } + } + LazyColumn { + items(currItems){ item -> + Box( + modifier = Modifier.clickable { + checkedStateComboBox.setValue(item) + client.sendValue(name) + onItemSelected(item) + selectedItem = item + expanded = false + } + .fillMaxWidth() + .heightIn(min = 48.dp) + ) { + content(item) + } + } + } + + } + } + } +} + +@Composable +fun InputTextBox( + name: String, client: AbstractClient, + modifier: Modifier = Modifier, + onItemChanged: (String) -> Unit = {}, + hintText: String = "Write something" +) { + val textBoxField = client.getField(name) as ConnectionField + val checkedStateTextBox = remember { textBoxField } + var selectedItem: String by remember { mutableStateOf("") } + Box(modifier = Modifier.fillMaxWidth()) { + OutlinedTextField( + value = selectedItem, + onValueChange = { + selectedItem = it + }, + modifier = modifier.fillMaxWidth(), + label = { Text(hintText) }, + keyboardOptions = KeyboardOptions( + keyboardType = KeyboardType.Text, + imeAction = ImeAction.Done + ), + trailingIcon = { + Icon( + Icons.Default.Check, + "Drop Down", + Modifier.size(24.dp).clickable { + checkedStateTextBox.setValue(selectedItem) + client.sendValue(name) + onItemChanged(checkedStateTextBox.getValue()) + } + ) + } + ) + } +} + + + +@Composable +fun HorizontalTracker( + name: String, client: AbstractClient, + range: ClosedFloatingPointRange, + initialValue: Float, + onValueSelected: (Float) -> Unit = {}, + modifier: Modifier = Modifier, + thumbColor: Color = Color.Magenta, + trackColor: Color = Color.LightGray, + borderWidth: Dp = 3.dp, + thumbSize: Dp = 24.dp, + trackWidth: Dp = 100.dp, + trackHeight: Dp = 24.dp, + legend: Boolean = true, + steps: Int = 0, + tickSize: Dp = 1.dp, + legendFontSize: TextUnit = 10.sp +) { + val trackerField = client.getField(name) as ConnectionField + val checkedStateTracker = remember { trackerField } + + var offsetX by remember { mutableStateOf(0f) } + var position by remember { mutableStateOf(getThumbPosition(initialValue, range, thumbSize, trackWidth)) } + var selectedValue by remember { mutableStateOf(initialValue) } + + Box(modifier = modifier.padding(thumbSize / 2)) { + Spacer( + modifier = Modifier + .width(trackWidth) + .height(trackHeight) + .background(trackColor) + .zIndex(1f) + .border(BorderStroke(borderWidth, METALLIC_BRUSH)) + ) + + Box( + modifier = Modifier + .offset(x = position) + .size(thumbSize) + .background(thumbColor, CircleShape) + .zIndex(2f) + .pointerInput(Unit) { + detectDragGestures( + onDragStart = { + }, + onDragEnd = { + val newValue = ((position.value + thumbSize.value / 2) / trackWidth.value) * (range.endInclusive - range.start) + selectedValue = newValue.coerceIn(range) + checkedStateTracker.setValue(selectedValue) + client.sendValue(name) + onValueSelected(selectedValue) + }, + onDragCancel = { + }, + onDrag = { change, _ -> + offsetX = change.positionChange().x + position = max(0.dp - thumbSize / 2, min(position + offsetX.toDp(), trackWidth - thumbSize / 2)) + change.consumePositionChange() + } + ) + } + ) + + if (legend && steps > 0) { + val tickPositions = + (0..steps).map { Pair(range.start + it.toFloat() / steps * (range.endInclusive - range.start), it) } + tickPositions.forEach { position -> + val tickPosition = getTickPosition(position.first, range, thumbSize) + Column(modifier = Modifier.offset(x = tickPosition.dp).zIndex(0f)) { + Spacer( + modifier = Modifier + .height(trackHeight + tickSize) + .width(1.dp) + .background(Color.Black) + + ) + Text(position.second.toString(), modifier = Modifier.align(Alignment.CenterHorizontally), fontSize = legendFontSize) + } + } + } + } +} + +fun getThumbPosition(value: Float, range: ClosedFloatingPointRange, thumbWidth: Dp, trackWidth: Dp): Dp { + val normalizedValue = (value - range.start) / (range.endInclusive - range.start) + return trackWidth * normalizedValue + thumbWidth / 2 +} + +fun getTickPosition(value: Float, range: ClosedFloatingPointRange, thumbWidth: Dp): Float { + val normalizedValue = (value - range.start) / (range.endInclusive - range.start) + val availableWidth = (range.endInclusive - range.start) + return availableWidth * normalizedValue +} + + +@Composable +fun RoundKnob( + name: String, client: AbstractClient, + range: IntRange, + value: Float, + onValueSelected: (Number) -> Unit = {}, + knobSize: Dp = 48.dp, + strokeWidth: Dp = 4.dp, + knobColor: Color = MaterialTheme.colors.primary, + legendColor: Color = MaterialTheme.colors.onBackground +) { + val knobField = client.getField(name) as ConnectionField + val checkedStateKnob = remember { knobField } + + var rotationAngle by remember { mutableStateOf(calculateRotationAngle(value, range))} + var currValue by remember { mutableStateOf(value) } + var offsetX by remember { mutableStateOf(0f) } + var offsetY by remember { mutableStateOf(0f) } + var centerX by remember { mutableStateOf(0f) } + var centerY by remember { mutableStateOf(0f) } + Box( + contentAlignment = Alignment.Center, + modifier = Modifier.size(knobSize) + ) { + Box(modifier = Modifier.pointerInput(Unit) { + detectDragGestures( + onDragStart = { + }, + onDragEnd = { + var angle = atan2(centerY - offsetY, centerX - offsetX) * (180f / PI).toFloat() - 90 + if (angle < -180) { + angle = (angle + 360) % 360 + } + rotationAngle = (angle).coerceIn(-150f, 150f) + currValue = calculateValue(rotationAngle, range) + + checkedStateKnob.setValue(currValue) + client.sendValue(name) + onValueSelected(currValue) + }, + onDrag = { change, dragAmount -> + offsetX = change.position.x + offsetY = change.position.y + var angle = atan2(centerY - offsetY, centerX - offsetX) * (180f / PI).toFloat() - 90 + if (angle < -180) { + angle = (angle + 360) % 360 + } + rotationAngle = (angle).coerceIn(-150f , 150f) + currValue = calculateValue(rotationAngle, range) + change.consumePositionChange() + } + ) + }) { + Canvas(modifier = Modifier.matchParentSize().onGloballyPositioned { + val windowBounds = it.boundsInWindow() + centerX = windowBounds.size.width / 2f + centerY = windowBounds.size.height / 2f + }) { + drawCircle( + brush = METALLIC_BRUSH, + radius = size.minDimension / 2, + style = Stroke(width = strokeWidth.toPx()) + ) + } + + Canvas( + modifier = Modifier + .size(knobSize) + .rotate(rotationAngle) + ) { + drawLine( + color = knobColor, + start = Offset(x = size.width / 2, y = 0f), + end = Offset(x = size.width / 2, y = size.height / 2), + strokeWidth = strokeWidth.toPx(), + cap = StrokeCap.Round + ) + } + } + + Text( + text = currValue.toString(), + color = legendColor, + style = MaterialTheme.typography.body1, + textAlign = TextAlign.Center, + modifier = Modifier + .align(Alignment.BottomCenter) + .padding(bottom = 8.dp) + ) + } +} + +private fun calculateRotationAngle(value: Float, range: IntRange):Float { + val ratio = (value - range.start) / (range.endInclusive - range.start) + return ratio * 300 - 150 +} + +private fun calculateValue(rotationAngle: Float, range: IntRange): Float { + val ratio = (rotationAngle + 150) / 300 + val value = ratio * (range.endInclusive - range.start) + range.start + return value +} diff --git a/code/cat_visual/src/main/kotlin/lib/visual/Positioning.kt b/code/cat_visual/src/main/kotlin/lib/visual/Positioning.kt new file mode 100644 index 000000000..7f8ae0082 --- /dev/null +++ b/code/cat_visual/src/main/kotlin/lib/visual/Positioning.kt @@ -0,0 +1,32 @@ +package lib.visual + +import androidx.compose.foundation.layout.* +import androidx.compose.runtime.Composable + +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.IntOffset +import androidx.compose.ui.unit.dp +import androidx.compose.ui.zIndex + +@Composable +fun PositionedBox(children: @Composable () -> Unit, x: Int = 0, y:Int = 0, zIndex: Float = 1f) { + Box(modifier = Modifier. + zIndex(zIndex) + .offset {IntOffset(x, y)} + .wrapContentSize()) { + children() + } +} + +@Composable +fun PositionedBox(children: @Composable () -> Unit, x: Float = 0f, y:Float = 0f, zIndex: Float = 1f) { + Box(modifier = Modifier. + zIndex(zIndex) + .offset(x.dp, y.dp) + .wrapContentSize()) { + children() + } +} + + diff --git a/code/cat_visual/src/main/kotlin/lib/visual/colors.kt b/code/cat_visual/src/main/kotlin/lib/visual/colors.kt new file mode 100644 index 000000000..f67d03cf3 --- /dev/null +++ b/code/cat_visual/src/main/kotlin/lib/visual/colors.kt @@ -0,0 +1,51 @@ +package lib.elements + +import androidx.compose.ui.graphics.Brush +import androidx.compose.ui.graphics.Color + + + + +val LIGHT_RADIAL_BRUSH = Brush.radialGradient( + colors = listOf( + Color.Yellow, + Color(0xFFFFA500) + ) +) + +val GREEN_RADIAL_BRUSH = Brush.radialGradient( + colors = listOf( + Color.Gray, + Color.Yellow + ) +) + +val DARK_RADIAL_BRUSH = Brush.radialGradient( + colors = listOf( + Color.DarkGray, + Color.Gray + ) +) + +val LIGHT_HORIZONTAL_BRUSH = Brush.horizontalGradient( + colors = listOf( + Color.Yellow, + Color(0xFFA500FF) + ) +) + +val DARK_HORIZONTAL_BRUSH = Brush.horizontalGradient( + colors = listOf( + Color.Black, + Color.Gray + ) +) + +val METALLIC_BRUSH = Brush.linearGradient( + colors = listOf( + Color.White, + Color.Gray, + Color.DarkGray + ) +) + diff --git a/code/cat_visual/src/main/kotlin/serializer/serialization.kt b/code/cat_visual/src/main/kotlin/serializer/serialization.kt new file mode 100644 index 000000000..9b4923cea --- /dev/null +++ b/code/cat_visual/src/main/kotlin/serializer/serialization.kt @@ -0,0 +1,155 @@ +package serializer + +import kotlinx.serialization.Serializable +import kotlinx.serialization.modules.SerializersModule +import kotlinx.serialization.serializer +import nl.adaptivity.xmlutil.XmlDeclMode +import nl.adaptivity.xmlutil.serialization.XML +import nl.adaptivity.xmlutil.serialization.XmlElement +import nl.adaptivity.xmlutil.serialization.XmlSerialName + +@Serializable +@XmlSerialName("Mapping", "", "") +data class PlainMapping( + val inputs: PlainInputs, + val outputs: PlainOutputs, +) + +@Serializable +@XmlSerialName("Inputs", "", "") +data class PlainInputs( + val inputs: List +) + +@Serializable +@XmlSerialName("Input", "", "") +data class PlainInput( + val name: String, + val type: String, + val host: String, + val port: Int +) + +@Serializable +@XmlSerialName("Outputs", "", "") +data class PlainOutputs( + val outputs: List + +) + +@Serializable +@XmlSerialName("Output", "", "") +data class PlainOutput( + val name: String, + val type: String, + val host: String, + val port: Int +) + + +fun getPlainMapping(modelText: String): PlainMapping { + val module = SerializersModule {} + val xml = XML(module) { + indentString = " " + xmlDeclMode = XmlDeclMode.Minimal + autoPolymorphic = true + } + + val serializer = serializer() + return xml.decodeFromString(serializer, modelText) +} + +@Serializable +@XmlSerialName("Mapping", "", "") +data class Mapping( + val id: String, + val inputs: Inputs, + val outputs: Outputs, +) + +@Serializable +@XmlSerialName("Inputs", "", "") +data class Inputs( + val inputs: List +) + +@Serializable +@XmlSerialName("Input", "", "") +data class Input( + val name: String, + val type: String +) + +@Serializable +@XmlSerialName("Outputs", "", "") +data class Outputs( + val outputs: List +) + +@Serializable +@XmlSerialName("Output", "", "") +data class Output( + val name: String, + val type: String +) + + +fun getMapping(modelText: String): Mapping { + val module = SerializersModule {} + val xml = XML(module) { + indentString = " " + xmlDeclMode = XmlDeclMode.Minimal + autoPolymorphic = true + } + + val serializer = serializer() + return xml.decodeFromString(serializer, modelText) +} + + +@Serializable +@XmlSerialName("Conf", "", "") +data class Conf( + val inputs: ConfInputs, + val outputs: ConfOutputs, +) + +@Serializable +@XmlSerialName("Inputs", "", "") +data class ConfInputs( + val inputs: List +) +@Serializable +@XmlSerialName("Input", "", "") +data class ConfInput( + val type: String, + val host: String, + val port: Int +) + +@Serializable +@XmlSerialName("Outputs", "", "") +data class ConfOutputs( + val outputs: List +) + +@Serializable +@XmlSerialName("Output", "", "") +data class ConfOutput( + val type: String, + val host: String, + val port: Int +) + + +fun getConf(modelText: String): Conf { + val module = SerializersModule {} + val xml = XML(module) { + indentString = " " + xmlDeclMode = XmlDeclMode.Minimal + autoPolymorphic = true + } + + val serializer = serializer() + return xml.decodeFromString(serializer, modelText) +} \ No newline at end of file diff --git a/code/cat_visual/src/test/kotlin/MockBackend.kt b/code/cat_visual/src/test/kotlin/MockBackend.kt new file mode 100644 index 000000000..079444c19 --- /dev/null +++ b/code/cat_visual/src/test/kotlin/MockBackend.kt @@ -0,0 +1,13 @@ +import connection.AbstractClient +import connection.ConnectionFieldRegistry +import connection.field.ConnectionField +import connection.field.TYPE_ID +import serializer.Mapping +import serializer.PlainMapping +import serializer.getMapping +import serializer.getPlainMapping +import java.io.File + +class FieldWithCallback(val field: ConnectionField, val callback: (V) -> Unit) + + diff --git a/code/cat_visual/src/test/kotlin/WaterTankTest.kt b/code/cat_visual/src/test/kotlin/WaterTankTest.kt new file mode 100644 index 000000000..a3559bc1e --- /dev/null +++ b/code/cat_visual/src/test/kotlin/WaterTankTest.kt @@ -0,0 +1,90 @@ +import connection.field.ConnectionField +import kotlin.concurrent.thread + +val client = buildMappingClient("src/main/kotlin/example/WATER_TANK/WATER_TANK.xml", "src/main/kotlin/example/WATER_TANK/WATER_TANK_CONF.xml", mode = "") + + +val TANK_VOLUME = 100 +val MAX_TEMP = 100 + +var isInlet: FieldWithCallback = FieldWithCallback(client.getField("stateInlet") as ConnectionField, + {client.sendValue("stateInlet")}) +var isHeat: FieldWithCallback = FieldWithCallback(client.getField("stateHeat") as ConnectionField, + {client.sendValue("stateHeat")}) +var isOutlet: FieldWithCallback = FieldWithCallback(client.getField("stateOutlet") as ConnectionField, + {client.sendValue("stateOutlet")}) +var lamp1: FieldWithCallback = FieldWithCallback(client.getField("lampIndicator1") as ConnectionField, + {client.sendValue("lampIndicator1")}) +var lamp2: FieldWithCallback = FieldWithCallback(client.getField("lampIndicator2") as ConnectionField, + {client.sendValue("lampIndicator2")}) +var tankIndicator: FieldWithCallback = FieldWithCallback(client.getField("tankIndicator") as ConnectionField, + {client.sendValue("tankIndicator")}) +var outputIndicator: FieldWithCallback = FieldWithCallback(client.getField("outputIndicator") as ConnectionField, + {client.sendValue("outputIndicator")}) +var knob1: FieldWithCallback = FieldWithCallback(client.getField("knob1") as ConnectionField, { + runUpdate() +}) +var knob2: FieldWithCallback = FieldWithCallback(client.getField("knob2") as ConnectionField, { + runUpdate() +}) + + +fun runSimulation(){ + client.retrieveValues(mapOf(Pair("knob1", {knob1.callback(0)}), Pair("knob2", {knob2.callback(0)})), false) +} + +fun runUpdate() { + if (knob1.field.getValue() == 0) { + return + } + if (isInlet.field.getValue() || isHeat.field.getValue() || isOutlet.field.getValue()) { + return + } + isInlet.field.setValue(true) + isInlet.callback(true) + lamp1.field.setValue(true) + lamp1.callback(true) + var currTankState = 0 + while (currTankState < TANK_VOLUME) { + currTankState += knob1.field.getValue() / 2 + tankIndicator.field.setValue(currTankState.toFloat()) + tankIndicator.callback(currTankState.toFloat()) + Thread.sleep( 500) + } + isInlet.field.setValue(false) + isInlet.callback(false) + lamp1.field.setValue(false) + lamp1.callback(false) + isHeat.field.setValue(true) + isHeat.callback(true) + var currTemp = knob2.field.getValue() + while (currTemp < MAX_TEMP) { + currTemp += 10 + outputIndicator.field.setValue(currTemp.toFloat()) + outputIndicator.callback(currTemp.toFloat()) + Thread.sleep(500) + } + isHeat.field.setValue(false) + isHeat.callback(false) + isOutlet.field.setValue(true) + isOutlet.callback(true) + lamp2.field.setValue(true) + lamp2.callback(true) + currTankState = TANK_VOLUME + while (currTankState > 0) { + currTankState -= knob1.field.getValue() / 2 + tankIndicator.field.setValue(currTankState.toFloat()) + tankIndicator.callback(currTankState.toFloat()) + Thread.sleep( 500) + } + isOutlet.field.setValue(false) + isOutlet.callback(false) + lamp2.field.setValue(false) + lamp2.callback(false) + outputIndicator.field.setValue(0f) + outputIndicator.callback(0f) +} + +fun main() { + runSimulation() +} \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index 14f191ebb..979cf2ffc 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,20 +1,21 @@ rootProject.name = "FBME" include( - "code:4diac-integration", - "code:enas", - "code:language", - "code:library", - "code:nxt-integration", - "code:platform", - "code:richediting", - "code:scenes", - "code:smv-debugger", - "code:debugger", +"code:4diac-integration", +"code:enas", +"code:language", +"code:library", +"code:nxt-integration", +"code:platform", +"code:richediting", +"code:scenes", +"code:smv-debugger", +"code:debugger", - "docs", +"docs", - "samples:statistics-plugin", - "samples:sandbox", - "samples:smv-debugger" +"samples:statistics-plugin", +"samples:sandbox", +"samples:smv-debugger", +"cat_visual" ) \ No newline at end of file From 94b24129c61ac76cab940a7c32a8eb48dcd4f18f Mon Sep 17 00:00:00 2001 From: Valentina Danilova Date: Fri, 2 Jun 2023 17:43:55 +0300 Subject: [PATCH 17/21] add visuals --- .idea/compiler.xml | 8 - code/cat_visual/README.md | 14 + code/cat_visual/build.gradle.kts | 49 ++ code/cat_visual/gradle.properties | 1 + code/cat_visual/gradlew | 185 ++++++ code/cat_visual/gradlew.bat | 89 +++ code/cat_visual/settings.gradle.kts | 10 + code/cat_visual/src/main/kotlin/Main.kt | 79 +++ .../src/main/kotlin/canvas/Canvas.kt | 16 + .../src/main/kotlin/canvas/UpperPlate.kt | 91 +++ .../main/kotlin/canvas/items/CustomItem.kt | 182 ++++++ .../connection/ConnectionFieldRegistry.kt | 45 ++ .../src/main/kotlin/connection/clients.kt | 174 ++++++ .../main/kotlin/connection/field/BoolField.kt | 37 ++ .../connection/field/ConnectionField.kt | 61 ++ .../kotlin/connection/field/DoubleField.kt | 36 ++ .../kotlin/connection/field/FloatField.kt | 33 ++ .../main/kotlin/connection/field/IntField.kt | 238 ++++++++ .../kotlin/connection/field/StringField.kt | 31 + .../kotlin/connection/field/WStringField.kt | 31 + .../connection/provider/ConnectionProvider.kt | 89 +++ .../kotlin/example/COUNTER/COMMON_CONF.xml | 9 + .../src/main/kotlin/example/COUNTER/COUNT.xml | 0 .../main/kotlin/example/COUNTER/COUNTER.kt | 44 ++ .../main/kotlin/example/COUNTER/COUNTER.xml | 10 + .../kotlin/example/COUNTER/COUNTER_CONF.xml | 10 + .../kotlin/example/COUNTER/COUNTER_PLAIN.xml | 10 + .../src/main/kotlin/example/COUNTER/LAMP.xml | 10 + .../main/kotlin/example/COUNTER/TOGGLE.xml | 0 .../main/kotlin/example/INCHOICE/INCHOICE.kt | 75 +++ .../example/INCHOICE/INCHOICE_HMI.cnv.xml | 17 + .../kotlin/example/WATER_TANK/WATER_TANK.kt | 121 ++++ .../kotlin/example/WATER_TANK/WATER_TANK.xml | 16 + .../example/WATER_TANK/WATER_TANK_CONF.xml | 10 + .../example/WATER_TANK/WATER_TANK_PLAIN.xml | 16 + .../kotlin/lib/elements/figures/elements.kt | 212 +++++++ .../kotlin/lib/elements/getters/elements.kt | 221 +++++++ .../kotlin/lib/elements/setters/elements.kt | 549 ++++++++++++++++++ .../src/main/kotlin/lib/visual/Positioning.kt | 32 + .../src/main/kotlin/lib/visual/colors.kt | 51 ++ .../main/kotlin/serializer/serialization.kt | 155 +++++ .../cat_visual/src/test/kotlin/MockBackend.kt | 13 + .../src/test/kotlin/WaterTankTest.kt | 90 +++ settings.gradle.kts | 29 +- 44 files changed, 3177 insertions(+), 22 deletions(-) create mode 100644 code/cat_visual/README.md create mode 100644 code/cat_visual/build.gradle.kts create mode 100644 code/cat_visual/gradle.properties create mode 100755 code/cat_visual/gradlew create mode 100644 code/cat_visual/gradlew.bat create mode 100644 code/cat_visual/settings.gradle.kts create mode 100644 code/cat_visual/src/main/kotlin/Main.kt create mode 100644 code/cat_visual/src/main/kotlin/canvas/Canvas.kt create mode 100644 code/cat_visual/src/main/kotlin/canvas/UpperPlate.kt create mode 100644 code/cat_visual/src/main/kotlin/canvas/items/CustomItem.kt create mode 100644 code/cat_visual/src/main/kotlin/connection/ConnectionFieldRegistry.kt create mode 100644 code/cat_visual/src/main/kotlin/connection/clients.kt create mode 100644 code/cat_visual/src/main/kotlin/connection/field/BoolField.kt create mode 100644 code/cat_visual/src/main/kotlin/connection/field/ConnectionField.kt create mode 100644 code/cat_visual/src/main/kotlin/connection/field/DoubleField.kt create mode 100644 code/cat_visual/src/main/kotlin/connection/field/FloatField.kt create mode 100644 code/cat_visual/src/main/kotlin/connection/field/IntField.kt create mode 100644 code/cat_visual/src/main/kotlin/connection/field/StringField.kt create mode 100644 code/cat_visual/src/main/kotlin/connection/field/WStringField.kt create mode 100644 code/cat_visual/src/main/kotlin/connection/provider/ConnectionProvider.kt create mode 100644 code/cat_visual/src/main/kotlin/example/COUNTER/COMMON_CONF.xml create mode 100644 code/cat_visual/src/main/kotlin/example/COUNTER/COUNT.xml create mode 100644 code/cat_visual/src/main/kotlin/example/COUNTER/COUNTER.kt create mode 100644 code/cat_visual/src/main/kotlin/example/COUNTER/COUNTER.xml create mode 100644 code/cat_visual/src/main/kotlin/example/COUNTER/COUNTER_CONF.xml create mode 100644 code/cat_visual/src/main/kotlin/example/COUNTER/COUNTER_PLAIN.xml create mode 100644 code/cat_visual/src/main/kotlin/example/COUNTER/LAMP.xml create mode 100644 code/cat_visual/src/main/kotlin/example/COUNTER/TOGGLE.xml create mode 100644 code/cat_visual/src/main/kotlin/example/INCHOICE/INCHOICE.kt create mode 100644 code/cat_visual/src/main/kotlin/example/INCHOICE/INCHOICE_HMI.cnv.xml create mode 100644 code/cat_visual/src/main/kotlin/example/WATER_TANK/WATER_TANK.kt create mode 100644 code/cat_visual/src/main/kotlin/example/WATER_TANK/WATER_TANK.xml create mode 100644 code/cat_visual/src/main/kotlin/example/WATER_TANK/WATER_TANK_CONF.xml create mode 100644 code/cat_visual/src/main/kotlin/example/WATER_TANK/WATER_TANK_PLAIN.xml create mode 100644 code/cat_visual/src/main/kotlin/lib/elements/figures/elements.kt create mode 100644 code/cat_visual/src/main/kotlin/lib/elements/getters/elements.kt create mode 100644 code/cat_visual/src/main/kotlin/lib/elements/setters/elements.kt create mode 100644 code/cat_visual/src/main/kotlin/lib/visual/Positioning.kt create mode 100644 code/cat_visual/src/main/kotlin/lib/visual/colors.kt create mode 100644 code/cat_visual/src/main/kotlin/serializer/serialization.kt create mode 100644 code/cat_visual/src/test/kotlin/MockBackend.kt create mode 100644 code/cat_visual/src/test/kotlin/WaterTankTest.kt diff --git a/.idea/compiler.xml b/.idea/compiler.xml index 58d13c02c..c8952aa4d 100644 --- a/.idea/compiler.xml +++ b/.idea/compiler.xml @@ -1,14 +1,6 @@ - - - - - - - - diff --git a/code/cat_visual/README.md b/code/cat_visual/README.md new file mode 100644 index 000000000..a2cb49d34 --- /dev/null +++ b/code/cat_visual/README.md @@ -0,0 +1,14 @@ +# compose_template + +Виды примитивных блоков для поддержки +* checkbox +* radio +* text choice +* different toggles + +Interfaces: +* Zoomable +* Positioned +* ZIndexed +* Grouped +* \ No newline at end of file diff --git a/code/cat_visual/build.gradle.kts b/code/cat_visual/build.gradle.kts new file mode 100644 index 000000000..7586c8f9e --- /dev/null +++ b/code/cat_visual/build.gradle.kts @@ -0,0 +1,49 @@ +import org.jetbrains.compose.compose +import org.jetbrains.compose.desktop.application.dsl.TargetFormat +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile + +plugins { + kotlin + id("org.jetbrains.compose") version "1.3.1" + kotlin("plugin.serialization") version "1.8.0" +} + +group = "fbme" +version = "1.0" + +repositories { + google() + mavenCentral() + maven("https://maven.pkg.jetbrains.space/public/p/compose/dev") +} + +dependencies { + implementation(compose.desktop.currentOs) + implementation("com.hierynomus:asn-one:0.5.0") + implementation(kotlin("stdlib-jdk8")) + implementation("io.github.pdvrieze.xmlutil:serialization-jvm:0.84.3") + implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.0") +} + +tasks.withType { + kotlinOptions.jvmTarget = "11" +} + +compose.desktop { + application { + mainClass = "MainKt" + nativeDistributions { + targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb) + packageName = "compose" + packageVersion = "1.0.0" + } + } +} +val compileKotlin: KotlinCompile by tasks +compileKotlin.kotlinOptions { + jvmTarget = "1.8" +} +val compileTestKotlin: KotlinCompile by tasks +compileTestKotlin.kotlinOptions { + jvmTarget = "1.8" +} \ No newline at end of file diff --git a/code/cat_visual/gradle.properties b/code/cat_visual/gradle.properties new file mode 100644 index 000000000..7fc6f1ff2 --- /dev/null +++ b/code/cat_visual/gradle.properties @@ -0,0 +1 @@ +kotlin.code.style=official diff --git a/code/cat_visual/gradlew b/code/cat_visual/gradlew new file mode 100755 index 000000000..744e882ed --- /dev/null +++ b/code/cat_visual/gradlew @@ -0,0 +1,185 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MSYS* | MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=`expr $i + 1` + done + case $i in + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=`save "$@"` + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +exec "$JAVACMD" "$@" diff --git a/code/cat_visual/gradlew.bat b/code/cat_visual/gradlew.bat new file mode 100644 index 000000000..ac1b06f93 --- /dev/null +++ b/code/cat_visual/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/code/cat_visual/settings.gradle.kts b/code/cat_visual/settings.gradle.kts new file mode 100644 index 000000000..bbba57708 --- /dev/null +++ b/code/cat_visual/settings.gradle.kts @@ -0,0 +1,10 @@ +pluginManagement { + repositories { + google() + gradlePluginPortal() + maven("https://maven.pkg.jetbrains.space/public/p/compose/dev") + } + +} +rootProject.name = "compose" + diff --git a/code/cat_visual/src/main/kotlin/Main.kt b/code/cat_visual/src/main/kotlin/Main.kt new file mode 100644 index 000000000..f5710a74d --- /dev/null +++ b/code/cat_visual/src/main/kotlin/Main.kt @@ -0,0 +1,79 @@ +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Scaffold +import androidx.compose.runtime.Composable +import androidx.compose.runtime.snapshots.SnapshotStateList +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.dp +import androidx.compose.ui.window.Window +import androidx.compose.ui.window.application +import androidx.compose.ui.window.rememberWindowState +import canvas.items.CustomItem +import connection.* +import connection.field.BoolField +import connection.field.TYPE_ID +import example.COUNTER.CounterLampHMI +import example.WATER_TANK.System +import example.WATER_TANK.WaterTank +import serializer.PlainMapping +import serializer.getConf +import serializer.getMapping +import serializer.getPlainMapping +import java.io.BufferedReader +import java.io.File +import java.io.InputStreamReader +import java.net.DatagramPacket +import java.net.InetAddress +import java.net.ServerSocket + +@Composable +fun CanvasContext(listFigures: SnapshotStateList) { + Scaffold { innerPadding -> + Box(Modifier.fillMaxHeight().fillMaxWidth().background(Color.Gray)) { + listFigures.forEach { f -> f.create() } + } + } +} + +fun buildMappingClient(modelFile: String, configFile: String = "", mode: String = ""): AbstractClient { + if (mode.equals("plain")) { + val modelText = File(modelFile).readText() + val mapping = getPlainMapping(modelText) + + return PlainClient(mapping) + } + + val modelText = File(modelFile).readText() + val mapping = getMapping(modelText) + val configText = File(configFile).readText() + val conf = getConf(configText) + + if (mode.equals("json")) { + return JSONClient(mapping, conf) + } + return NamedClient(mapping, conf) +} + +//val client = buildMappingClient("src/main/kotlin/example/COUNTER/COUNTER.xml", "src/main/kotlin/example/COUNTER/COUNTER_CONF.xml", "") +val client = buildMappingClient("src/main/kotlin/example/COUNTER/COUNTER.xml", "src/main/kotlin/example/COUNTER/COMMON_CONF.xml", "json") +//val client = buildMappingClient("src/main/kotlin/example/WATER_TANK/WATER_TANK.xml", "src/main/kotlin/example/WATER_TANK/WATER_TANK_CONF.xml", "") +//val client = buildMappingClient("src/main/kotlin/example/WATER_TANK/WATER_TANK.xml", "src/main/kotlin/example/WATER_TANK/COMMON_CONF.xml", "json") + + +fun main() = application { + Window( + onCloseRequest = ::exitApplication, + title = "Canvas for CAT", + state = rememberWindowState(width = 600.dp, height = 600.dp) + ) { + MaterialTheme { + CounterLampHMI(client, "1") + client.retrieveValues() + } + } +} \ No newline at end of file diff --git a/code/cat_visual/src/main/kotlin/canvas/Canvas.kt b/code/cat_visual/src/main/kotlin/canvas/Canvas.kt new file mode 100644 index 000000000..1688219d8 --- /dev/null +++ b/code/cat_visual/src/main/kotlin/canvas/Canvas.kt @@ -0,0 +1,16 @@ +import androidx.compose.desktop.ui.tooling.preview.Preview +import androidx.compose.foundation.Canvas +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.material.Button +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Text +import androidx.compose.runtime.* +import androidx.compose.ui.Modifier + +@Composable +fun CustomCanvas() { + Canvas(modifier = Modifier.fillMaxSize()) { + } +} + diff --git a/code/cat_visual/src/main/kotlin/canvas/UpperPlate.kt b/code/cat_visual/src/main/kotlin/canvas/UpperPlate.kt new file mode 100644 index 000000000..12a011b5c --- /dev/null +++ b/code/cat_visual/src/main/kotlin/canvas/UpperPlate.kt @@ -0,0 +1,91 @@ +import androidx.compose.desktop.ui.tooling.preview.Preview +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.material.Button +import androidx.compose.material.Checkbox +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Text +import androidx.compose.runtime.* +import androidx.compose.ui.unit.dp + +@Composable +fun UpperPlate() { + Row(horizontalArrangement = Arrangement.spacedBy(5.dp)) { + PointerButton() + } +} +@Composable +@Preview +fun PointerButton() { + var text by remember { mutableStateOf("P") } + + MaterialTheme { + Button(onClick = { + text = "O" + }) { + Text(text) + } + } +} + +@Composable +@Preview +fun RectangleButton(onClickFun: () -> Unit) { + var text by remember { mutableStateOf("R") } + + MaterialTheme { + Button(onClick = onClickFun) { + Text(text) + } + } +} + + +@Composable +@Preview +fun CheckboxButton(onClickFun: () -> Unit) { + var text by remember { mutableStateOf("CB") } + + MaterialTheme { + Button(onClick = onClickFun) { + Text(text) + } + } +} + +@Composable +@Preview +fun RadioButton(onClickFun: () -> Unit) { + var text by remember { mutableStateOf("RB") } + + MaterialTheme { + Button(onClick = onClickFun) { + Text(text) + } + } +} + +@Composable +@Preview +fun ToggleButton(onClickFun: () -> Unit) { + var text by remember { mutableStateOf("TB") } + + MaterialTheme { + Button(onClick = onClickFun) { + Text(text) + } + } +} + +@Composable +@Preview +fun DropdownButton(onClickFun: () -> Unit) { + var text by remember { mutableStateOf("DB") } + + MaterialTheme { + Button(onClick = onClickFun) { + Text(text) + } + } +} diff --git a/code/cat_visual/src/main/kotlin/canvas/items/CustomItem.kt b/code/cat_visual/src/main/kotlin/canvas/items/CustomItem.kt new file mode 100644 index 000000000..86447e4cf --- /dev/null +++ b/code/cat_visual/src/main/kotlin/canvas/items/CustomItem.kt @@ -0,0 +1,182 @@ +package canvas.items + +import androidx.compose.animation.animateContentSize +import androidx.compose.foundation.Canvas +import androidx.compose.foundation.background +import androidx.compose.foundation.gestures.* +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.selection.selectable +import androidx.compose.material.RadioButton +import androidx.compose.material.Text +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.RectangleShape +import androidx.compose.ui.graphics.graphicsLayer +import androidx.compose.ui.input.pointer.PointerEventPass +import androidx.compose.ui.input.pointer.PointerEventType +import androidx.compose.ui.input.pointer.onPointerEvent +import androidx.compose.ui.input.pointer.pointerInput +import androidx.compose.ui.layout.onGloballyPositioned +import androidx.compose.ui.layout.onSizeChanged +import androidx.compose.ui.semantics.Role +import androidx.compose.ui.unit.IntOffset +import androidx.compose.ui.unit.IntSize +import androidx.compose.ui.unit.dp + +enum class ItemType { + RECTANGLE, RADIO, CHECKBOX +} + +@Composable +fun ZoomableBox( + modifier: Modifier = Modifier, + minScale: Float = 0.1f, + maxScale: Float = 5f, + content: @Composable ZoomableBoxScope.() -> Unit +) { + var scale by remember { mutableStateOf(1f) } + var offsetX by remember { mutableStateOf(0f) } + var offsetY by remember { mutableStateOf(0f) } + var size by remember { mutableStateOf(IntSize(50, 50)) } + Box( + modifier = modifier +// .clip(RectangleShape) + .onSizeChanged { size = it } + .pointerInput(Unit) { + detectTransformGestures { _, pan, zoom, _ -> + scale = maxOf(minScale, minOf(scale * zoom, maxScale)) + val maxX = (size.width * (scale - 1)) / 2 + val minX = -maxX + offsetX = maxOf(minX, minOf(maxX, offsetX + pan.x)) + val maxY = (size.height * (scale - 1)) / 2 + val minY = -maxY + offsetY = maxOf(minY, minOf(maxY, offsetY + pan.y)) + } + } + ) { + val scope = ZoomableBoxScopeImpl(scale, offsetX, offsetY) + scope.content() + println(scale) + println(offsetX) + println(offsetY) + println(size) + } +} + +interface ZoomableBoxScope { + val scale: Float + val offsetX: Float + val offsetY: Float +} + +private data class ZoomableBoxScopeImpl( + override val scale: Float, + override val offsetX: Float, + override val offsetY: Float +) : ZoomableBoxScope + + +abstract interface CustomItem { + @Composable + fun create(); +} + +class RectangleCustomItem : CustomItem { + var c = Color.Blue + @Composable + fun RectangleItem() { + var color by remember { mutableStateOf(c) } + ZoomableBox { + Box( + modifier = Modifier + .graphicsLayer( + scaleX = scale, + scaleY = scale, + translationX = offsetX, + translationY = offsetY + ) + .background(color = color) + .width(600.dp) + .height(600.dp) + ) { + } + } + + } + + @Composable + override fun create() { + return RectangleItem(); + } +} + +class CheckboxCustomItem : CustomItem { + var c = Color.Blue + @Composable + fun RectangleItem() { + var color by remember { mutableStateOf(c) } + ZoomableBox { + Box( + modifier = Modifier + .graphicsLayer( + scaleX = scale, + scaleY = scale, + translationX = offsetX, + translationY = offsetY + ) + .background(color = color) + .width(600.dp) + .height(600.dp) + ) { + } + } + + } + + @Composable + override fun create() { + return RectangleItem(); + } +} + +class RadioCustomItem : CustomItem { + var c = Color.Blue + @Composable + fun RadioItem(items: List) { + var color by remember { mutableStateOf(c) } + var selectedValue by remember { mutableStateOf("") } + val isSelectedItem: (String) -> Boolean = { selectedValue == it } + val onChangeState: (String) -> Unit = { selectedValue = it } + ZoomableBox { + items.forEach { item -> + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier.selectable( + selected = isSelectedItem(item), + onClick = { onChangeState(item) }, + role = Role.RadioButton + ).padding(8.dp) + ) { + RadioButton( + selected = isSelectedItem(item), + onClick = null + ) + Text( + text = item, + modifier = Modifier.fillMaxWidth() + ) + } + } + } + + } + + @Composable + override fun create() { + val items = listOf("Item1", "Item2") + return RadioItem(items); + } +} diff --git a/code/cat_visual/src/main/kotlin/connection/ConnectionFieldRegistry.kt b/code/cat_visual/src/main/kotlin/connection/ConnectionFieldRegistry.kt new file mode 100644 index 000000000..96b524370 --- /dev/null +++ b/code/cat_visual/src/main/kotlin/connection/ConnectionFieldRegistry.kt @@ -0,0 +1,45 @@ +package connection + +import connection.field.ConnectionField +import connection.field.TYPE_ID +import connection.provider.ConnectionProvider +import connection.provider.UDPConnectionProvider + + +class ConnectionFieldRegistry { + private val providerRegistry: MutableMap, ConnectionProvider> = mutableMapOf() + private val fieldRegistry: MutableMap,ConnectionProvider> > = mutableMapOf() + + fun getConnection(name: String, type: TYPE_ID, host: String, port: Int): Pair,ConnectionProvider> { + if (name in fieldRegistry) { + return fieldRegistry[name]!! + } + val providerAddress = Pair(host, port) + val provider = providerRegistry.computeIfAbsent(providerAddress, { UDPConnectionProvider(port, host) }) + val field = ConnectionField.create(type) + val connection = Pair(field, provider) + fieldRegistry[name] = connection + return connection + } + + fun getConnection(name: String): Pair,ConnectionProvider>? { + if (name in fieldRegistry) { + return fieldRegistry[name]!! + } + return null + } + + fun getField(name: String): ConnectionField? { + if (name in fieldRegistry) { + return fieldRegistry[name]!!.first + } + return null + } + + fun getConnector(hostPort: Pair): ConnectionProvider? { + if (hostPort in providerRegistry) { + return providerRegistry[hostPort]!! + } + return null + } +} \ No newline at end of file diff --git a/code/cat_visual/src/main/kotlin/connection/clients.kt b/code/cat_visual/src/main/kotlin/connection/clients.kt new file mode 100644 index 000000000..99a76bee1 --- /dev/null +++ b/code/cat_visual/src/main/kotlin/connection/clients.kt @@ -0,0 +1,174 @@ +package connection + +import connection.field.ConnectionField +import connection.field.StringField +import connection.field.TYPE_ID +import connection.provider.ConnectionProvider +import kotlinx.serialization.Serializable +import kotlinx.serialization.decodeFromString +import kotlinx.serialization.encodeToString +import kotlinx.serialization.json.Json +import serializer.Conf +import serializer.Mapping +import serializer.PlainMapping +import java.nio.ByteBuffer + +abstract class AbstractClient() { + abstract fun getField(name: String): ConnectionField?; + abstract fun sendValue(name: String) + abstract fun retrieveValues(callbacks: Map Unit> = mapOf(), isInput: Boolean = true) +} + +abstract class UDPClient(): AbstractClient() { + protected val registry: ConnectionFieldRegistry = ConnectionFieldRegistry() + val inputs: MutableSet = mutableSetOf() + val outputs: MutableSet = mutableSetOf() + val inputConnections: MutableList = mutableListOf() + val outputConnections: MutableList = mutableListOf() + + override fun getField(name: String): ConnectionField? { + return registry.getConnection(name)?.first + } +} + +class PlainClient(mapping: PlainMapping): UDPClient() { + init { + mapping.inputs.inputs.forEach({ + registry.getConnection(it.name, TYPE_ID.valueOf(it.type), it.host, it.port) + inputs.add(it.name) + inputConnections.add(registry.getConnection(it.name)!!.second) + }) + mapping.outputs.outputs.forEach({ + registry.getConnection(it.name, TYPE_ID.valueOf(it.type), it.host, it.port) + outputs.add(it.name) + outputConnections.add(registry.getConnection(it.name)!!.second) + }) + } + + override fun sendValue(name: String) { + val fieldConnector = registry.getConnection(name) + val field = fieldConnector!!.first + val connector = fieldConnector.second + connector.request(field, ByteArray(0)) + } + + override fun retrieveValues(callbacks: Map Unit>, isInput: Boolean) { + val units = if (isInput) inputs else outputs + units.forEach{ + val fieldConnector = registry.getConnection(it) + val field = fieldConnector!!.first + val connector = fieldConnector.second + connector.response({ba -> Pair(Pair(field, ba), it)}, callbacks=callbacks) + } + } +} + +class NamedClient(mapping: Mapping, conf: Conf): UDPClient() { + val nameField: ConnectionField = StringField() + val inputsTypes: MutableMap> = mutableMapOf() + val outputsTypes: MutableMap> = mutableMapOf() + + init { + conf.inputs.inputs.forEach({ + inputsTypes.put(TYPE_ID.valueOf(it.type), Pair(it.host, it.port)) + }) + conf.outputs.outputs.forEach({ + outputsTypes.put(TYPE_ID.valueOf(it.type), Pair(it.host, it.port)) + }) + mapping.inputs.inputs.forEach { + val hostPort = inputsTypes.get(TYPE_ID.valueOf(it.type)) + registry.getConnection(it.name, TYPE_ID.valueOf(it.type), hostPort!!.first, hostPort.second) + inputs.add(it.name) + } + mapping.outputs.outputs.forEach({ + val hostPort = outputsTypes.get(TYPE_ID.valueOf(it.type)) + registry.getConnection(it.name, TYPE_ID.valueOf(it.type), hostPort!!.first, hostPort.second) + outputs.add(it.name) + }) + inputsTypes.values.forEach({ + inputConnections.add(registry.getConnector(it)!!) + }) + outputsTypes.values.forEach({ + outputConnections.add(registry.getConnector(it)!!) + }) + } + + override fun sendValue(name: String) { + val fieldConnector = registry.getConnection(name) + val field = fieldConnector!!.first + val connector = fieldConnector.second + nameField.setValue(name) + connector.request(field, nameField.getFromFBValue()) + } + + override fun retrieveValues(callbacks: Map Unit>, isInput: Boolean) { + val units = if (isInput) inputConnections else outputConnections + units.forEach { + it.response({ ba -> + var size = ByteBuffer.wrap(ba).getShort(1) + val name = String(ba.copyOfRange(3, 3 + size.toInt())) + val offset = 3 + size.toInt() + registry.getConnection(name) + val field = registry.getConnection(name)!!.first + Pair(Pair(field, ba.copyOfRange(offset, ba.size)), name) + }, callbacks= callbacks) + } + } +} + +class JSONClient(mapping: Mapping, conf: Conf): UDPClient() { + val MSG_TYPE: TYPE_ID = TYPE_ID.STRING + val nameField: ConnectionField = StringField() + val inputsTypes: MutableMap> = mutableMapOf() + val outputsTypes: MutableMap> = mutableMapOf() + + @Serializable + data class Msg(val NAME: String, val TYPE: String, val VALUE: String) + init { + conf.inputs.inputs.forEach({ + inputsTypes.put(TYPE_ID.valueOf(it.type), Pair(it.host, it.port)) + }) + conf.outputs.outputs.forEach({ + outputsTypes.put(TYPE_ID.valueOf(it.type), Pair(it.host, it.port)) + }) + mapping.inputs.inputs.forEach { + val hostPort = inputsTypes.get(MSG_TYPE) + registry.getConnection("${mapping.id}#${it.name}", TYPE_ID.valueOf(it.type), hostPort!!.first, hostPort.second) + inputs.add(it.name) + } + mapping.outputs.outputs.forEach({ + val hostPort = outputsTypes.get(MSG_TYPE) + registry.getConnection("${mapping.id}#${it.name}", TYPE_ID.valueOf(it.type), hostPort!!.first, hostPort.second) + outputs.add(it.name) + }) + conf.inputs.inputs.forEach({ + inputConnections.add(registry.getConnector(Pair(it.host, it.port))!!) + }) + conf.outputs.outputs.forEach({ + outputConnections.add(registry.getConnector(Pair(it.host, it.port))!!) + }) + } + + override fun sendValue(name: String) { + val fieldConnector = registry.getConnection(name) + val field = fieldConnector!!.first + val connector = fieldConnector.second + val data = Msg(name, field.getTypeID().name, field.getMsgValue()) + val msg = Json.encodeToString(data) + connector.request(msg) + } + + override fun retrieveValues(callbacks: Map Unit>, isInput: Boolean) { + val units = if (isInput) inputConnections else outputConnections + units.forEach { + it.response({ + val msg = Json.decodeFromString(it) + val field = registry.getField(msg.NAME)!! + println("GETTING ${field.getTypeID()}") + field.getFBValue(msg.VALUE) + println("GOT ${field.getValue()}") + msg.NAME + }, true, callbacks= callbacks) + } + } +} \ No newline at end of file diff --git a/code/cat_visual/src/main/kotlin/connection/field/BoolField.kt b/code/cat_visual/src/main/kotlin/connection/field/BoolField.kt new file mode 100644 index 000000000..a2384a409 --- /dev/null +++ b/code/cat_visual/src/main/kotlin/connection/field/BoolField.kt @@ -0,0 +1,37 @@ +package connection.field + +import androidx.compose.runtime.MutableState +import androidx.compose.runtime.mutableStateOf + +data class BoolField(override var content:Boolean = false, override val contentState: MutableState = mutableStateOf(content)): ConnectionField(content, contentState) { + + val TRUE_VALUE:Byte = 65 + val FALSE_VALUE:Byte = 64 + + + override fun getFromFBValue():ByteArray { + val res = ByteArray(1) + res[0] = if (content) TRUE_VALUE else FALSE_VALUE + return res + } + + override fun getFBValue(d: ByteArray) { + setValue(d[0] == TRUE_VALUE) + } + + override fun getFBValue(d: String) { + setValue(d.equals("TRUE")); + } + + override fun getMsgValue(): String { + if (content) { + return "TRUE"; + } + return "FALSE"; + } + + override fun getTypeID(): TYPE_ID { + return TYPE_ID.BOOL + } + +} \ No newline at end of file diff --git a/code/cat_visual/src/main/kotlin/connection/field/ConnectionField.kt b/code/cat_visual/src/main/kotlin/connection/field/ConnectionField.kt new file mode 100644 index 000000000..4d539ee6e --- /dev/null +++ b/code/cat_visual/src/main/kotlin/connection/field/ConnectionField.kt @@ -0,0 +1,61 @@ +package connection.field + +import androidx.compose.runtime.MutableState +import kotlinx.coroutines.Dispatchers +import java.lang.UnsupportedOperationException + + +abstract class ConnectionField(open var content: V, open val contentState: MutableState) { + companion object { + fun create(type: TYPE_ID):ConnectionField { +// println(type) + return when (type) { + TYPE_ID.BOOL -> BoolField() + TYPE_ID.REAL -> FloatField(0f) + TYPE_ID.LREAL -> DoubleField(0.0) + TYPE_ID.STRING -> StringField() + TYPE_ID.SINT -> SIntField(0) + TYPE_ID.USINT -> USIntField(0u) + TYPE_ID.INT -> IntField(0) + TYPE_ID.UINT -> UIntField(0u) + TYPE_ID.DINT -> DIntField(0) + TYPE_ID.UDINT -> UDIntField(0u) + TYPE_ID.LINT -> LIntField(0) + TYPE_ID.ULINT -> ULIntField(0u) + else -> {throw UnsupportedOperationException("Unsupported type literal")} + } + } + } + abstract fun getFromFBValue():ByteArray + abstract fun getMsgValue():String + abstract fun getFBValue(d: ByteArray) + abstract fun getFBValue(d: String) + abstract fun getTypeID():TYPE_ID + fun getValue():V { + return content + } + fun setValue(v:V) { + println("!!! BEFORE SET ${content}") + content = v + contentState.value = content + println("!!! SET ${content}") + } +} + +enum class TYPE_ID(val code: Int) { + BOOL(65), + SINT(66), + INT(67), + DINT(68), + LINT(69), + USINT(70), + UINT(71), + UDINT(72), + ULINT(73), + REAL(74), + LREAL(75), + STRING(80), + WSTRING(85), + DATE_AND_TIME(79), + ARRAY(118) +} \ No newline at end of file diff --git a/code/cat_visual/src/main/kotlin/connection/field/DoubleField.kt b/code/cat_visual/src/main/kotlin/connection/field/DoubleField.kt new file mode 100644 index 000000000..4c456030b --- /dev/null +++ b/code/cat_visual/src/main/kotlin/connection/field/DoubleField.kt @@ -0,0 +1,36 @@ +package connection.field; + +import androidx.compose.runtime.MutableState +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.sourceInformation +import java.nio.ByteBuffer +import java.util.* + +data class DoubleField(var defaultValue:Double, override var content:Double = 0.0, override val contentState: MutableState = mutableStateOf(defaultValue)): ConnectionField(content, contentState) { + + override fun getFromFBValue(): ByteArray { + val bytes: ByteArray = ByteBuffer.allocate(5).put(getTypeID().code.toByte()).putDouble(content).array() + return bytes + } + + override fun getMsgValue(): String { + return getValue().toString() + } + + override fun getFBValue(d: ByteArray) { + var buf = ByteBuffer.wrap(d) + + if (buf[0] == TYPE_ID.LREAL.code.toByte()) { + setValue(ByteBuffer.wrap(d).getDouble(1)) + } + } + + override fun getFBValue(d: String) { + setValue(d.toDouble()) + } + + override fun getTypeID(): TYPE_ID { +// TODO("add support of just SINT") + return TYPE_ID.LREAL + } +} diff --git a/code/cat_visual/src/main/kotlin/connection/field/FloatField.kt b/code/cat_visual/src/main/kotlin/connection/field/FloatField.kt new file mode 100644 index 000000000..e44ab1d30 --- /dev/null +++ b/code/cat_visual/src/main/kotlin/connection/field/FloatField.kt @@ -0,0 +1,33 @@ +package connection.field; + +import androidx.compose.runtime.MutableState +import androidx.compose.runtime.mutableStateOf +import java.nio.ByteBuffer + +data class FloatField(var defaultValue:Float, override var content:Float = 0f, override val contentState: MutableState = mutableStateOf(defaultValue)): ConnectionField(content, contentState) { + + override fun getFromFBValue(): ByteArray { + val bytes: ByteArray = ByteBuffer.allocate(5).put(getTypeID().code.toByte()).putFloat(content).array() + return bytes + } + + override fun getMsgValue(): String { + return getValue().toString() + } + + override fun getFBValue(d: ByteArray) { + var buf = ByteBuffer.wrap(d) + + if (buf[0] == TYPE_ID.REAL.code.toByte()) { + setValue(ByteBuffer.wrap(d).getFloat(1)) + } + } + + override fun getFBValue(d: String) { + setValue(d.toFloat()) + } + + override fun getTypeID(): TYPE_ID { + return TYPE_ID.REAL + } +} diff --git a/code/cat_visual/src/main/kotlin/connection/field/IntField.kt b/code/cat_visual/src/main/kotlin/connection/field/IntField.kt new file mode 100644 index 000000000..4ba3719ca --- /dev/null +++ b/code/cat_visual/src/main/kotlin/connection/field/IntField.kt @@ -0,0 +1,238 @@ +package connection.field; + +import androidx.compose.runtime.MutableState +import androidx.compose.runtime.mutableStateOf +import java.nio.ByteBuffer + +data class SIntField(var defaultValue:Byte, override var content:Byte = 0, override val contentState: MutableState = mutableStateOf(defaultValue)): ConnectionField(content, contentState) { + + override fun getFromFBValue(): ByteArray { + val bytes: ByteArray = ByteBuffer.allocate(5).put(getTypeID().code.toByte()).put(content).array() + return bytes + } + + override fun getMsgValue(): String { + return getValue().toString() + } + + override fun getFBValue(d: ByteArray) { + var buf = ByteBuffer.wrap(d) + + if (buf[0] == TYPE_ID.SINT.code.toByte()) { + setValue(ByteBuffer.wrap(d).get(1)) + } + println(d.contentToString()) + } + + override fun getFBValue(d: String) { + setValue(d.toByte()) + } + + override fun getTypeID(): TYPE_ID { + return TYPE_ID.SINT + } +} + +data class USIntField(var defaultValue:UByte, override var content:UByte = 0u, override val contentState: MutableState = mutableStateOf(defaultValue)): ConnectionField(content, contentState) { + + override fun getFromFBValue(): ByteArray { + val bytes: ByteArray = ByteBuffer.allocate(5).put(getTypeID().code.toByte()).put(content.toByte()).array() + return bytes + } + + override fun getMsgValue(): String { + return getValue().toString() + } + + override fun getFBValue(d: ByteArray) { + var buf = ByteBuffer.wrap(d) + + if (buf[0] == TYPE_ID.UINT.code.toByte()) { + setValue(ByteBuffer.wrap(d).get(1).toUByte()) + } + println(d.contentToString()) + } + + override fun getFBValue(d: String) { + setValue(d.toUByte()) + } + + override fun getTypeID(): TYPE_ID { + return TYPE_ID.USINT + } +} + +data class IntField(var defaultValue:Short, override var content:Short = 0, override val contentState: MutableState = mutableStateOf(defaultValue)): ConnectionField(content, contentState) { + + override fun getFromFBValue(): ByteArray { + val bytes: ByteArray = ByteBuffer.allocate(5).put(getTypeID().code.toByte()).putShort(content).array() + return bytes + } + + override fun getMsgValue(): String { + return getValue().toString() + } + + override fun getFBValue(d: ByteArray) { + var buf = ByteBuffer.wrap(d) + + if (buf[0] == TYPE_ID.INT.code.toByte()) { + setValue(ByteBuffer.wrap(d).getShort(1)) + } + println(d.contentToString()) + } + + override fun getFBValue(d: String) { + setValue(d.toShort()) + } + + override fun getTypeID(): TYPE_ID { + return TYPE_ID.INT + } +} + +data class UIntField(var defaultValue:UShort, override var content:UShort = 0u, override val contentState: MutableState = mutableStateOf(defaultValue)): ConnectionField(content, contentState) { + + override fun getFromFBValue(): ByteArray { + val bytes: ByteArray = ByteBuffer.allocate(5).put(getTypeID().code.toByte()).putShort(content.toShort()).array() + return bytes + } + + override fun getMsgValue(): String { + return getValue().toString() + } + + override fun getFBValue(d: ByteArray) { + var buf = ByteBuffer.wrap(d) + + if (buf[0] == TYPE_ID.UINT.code.toByte()) { + setValue(ByteBuffer.wrap(d).getShort(1).toUShort()) + } + println(d.contentToString()) + } + + override fun getFBValue(d: String) { + setValue(d.toUShort()) + } + + override fun getTypeID(): TYPE_ID { + return TYPE_ID.UINT + } +} + +data class DIntField(var defaultValue:Int, override var content:Int = 0, override val contentState: MutableState = mutableStateOf(defaultValue)): ConnectionField(content, contentState) { + + override fun getFromFBValue(): ByteArray { + val bytes: ByteArray = ByteBuffer.allocate(5).put(getTypeID().code.toByte()).putInt(content).array() + return bytes + } + + override fun getMsgValue(): String { + return getValue().toString() + } + + override fun getFBValue(d: ByteArray) { + var buf = ByteBuffer.wrap(d) + + if (buf[0] == TYPE_ID.DINT.code.toByte()) { + setValue(ByteBuffer.wrap(d).getInt(1)) + } + println(d.contentToString()) + } + + override fun getFBValue(d: String) { + setValue(d.toInt()) + } + + override fun getTypeID(): TYPE_ID { + return TYPE_ID.DINT + } +} + +data class UDIntField(var defaultValue:UInt, override var content:UInt = 0u, override val contentState: MutableState = mutableStateOf(defaultValue)): ConnectionField(content, contentState) { + + override fun getFromFBValue(): ByteArray { + val bytes: ByteArray = ByteBuffer.allocate(9).put(getTypeID().code.toByte()).putInt(content.toInt()).array() + return bytes + } + + override fun getMsgValue(): String { + return getValue().toString() + } + + override fun getFBValue(d: ByteArray) { + var buf = ByteBuffer.wrap(d) + + if (buf[0] == TYPE_ID.UDINT.code.toByte()) { + setValue(ByteBuffer.wrap(d).getInt(1).toUInt()) + } + println(d.contentToString()) + } + + override fun getFBValue(d: String) { + setValue(d.toUInt()) + } + + override fun getTypeID(): TYPE_ID { + return TYPE_ID.UDINT + } +} + + +data class LIntField(var defaultValue:Long, override var content:Long = 0, override val contentState: MutableState = mutableStateOf(defaultValue)): ConnectionField(content, contentState) { + + override fun getFromFBValue(): ByteArray { + val bytes: ByteArray = ByteBuffer.allocate(5).put(getTypeID().code.toByte()).putLong(content).array() + return bytes + } + + override fun getMsgValue(): String { + return getValue().toString() + } + + override fun getFBValue(d: ByteArray) { + var buf = ByteBuffer.wrap(d) + + if (buf[0] == TYPE_ID.LINT.code.toByte()) { + setValue(ByteBuffer.wrap(d).getLong(1)) + } + println(d.contentToString()) + } + + override fun getFBValue(d: String) { + setValue(d.toLong()) + } + + override fun getTypeID(): TYPE_ID { + return TYPE_ID.LINT + } +} + +data class ULIntField(var defaultValue:ULong, override var content:ULong = 0uL, override val contentState: MutableState = mutableStateOf(defaultValue)): ConnectionField(content, contentState) { + + override fun getFromFBValue(): ByteArray { + val bytes: ByteArray = ByteBuffer.allocate(9).put(getTypeID().code.toByte()).putLong(content.toLong()).array() + return bytes + } + + override fun getMsgValue(): String { + return getValue().toString() + } + + override fun getFBValue(d: ByteArray) { + var buf = ByteBuffer.wrap(d) + + if (buf[0] == TYPE_ID.UDINT.code.toByte()) { + setValue(ByteBuffer.wrap(d).getLong(1).toULong()) + } + println(d.contentToString()) + } + + override fun getFBValue(d: String) { + setValue(d.toULong()) + } + + override fun getTypeID(): TYPE_ID { + return TYPE_ID.ULINT + } +} diff --git a/code/cat_visual/src/main/kotlin/connection/field/StringField.kt b/code/cat_visual/src/main/kotlin/connection/field/StringField.kt new file mode 100644 index 000000000..d57e7afff --- /dev/null +++ b/code/cat_visual/src/main/kotlin/connection/field/StringField.kt @@ -0,0 +1,31 @@ +package connection.field + +import androidx.compose.runtime.MutableState +import androidx.compose.runtime.mutableStateOf +import java.nio.ByteBuffer + +data class StringField(override var content:String = "", override val contentState: MutableState = mutableStateOf(content)): ConnectionField(content, contentState) { + override fun getFromFBValue(): ByteArray { + val contentBytes: ByteArray = content.toByteArray() + return ByteBuffer.allocate(contentBytes.size + 3).put(TYPE_ID.STRING.code.toByte()).putShort(content.length.toShort()).put(contentBytes).array() + } + + override fun getMsgValue(): String { + return content + } + + override fun getFBValue(d: ByteArray) { + var size = ByteBuffer.wrap(d).getShort(1) + setValue(String(d.copyOfRange(3, 3 + size.toInt()))) + println(d.contentToString()) + } + + override fun getFBValue(d: String) { + setValue(d) + } + + override fun getTypeID(): TYPE_ID { + return TYPE_ID.STRING + } + +} \ No newline at end of file diff --git a/code/cat_visual/src/main/kotlin/connection/field/WStringField.kt b/code/cat_visual/src/main/kotlin/connection/field/WStringField.kt new file mode 100644 index 000000000..41ef84f6d --- /dev/null +++ b/code/cat_visual/src/main/kotlin/connection/field/WStringField.kt @@ -0,0 +1,31 @@ +package connection.field + +import androidx.compose.runtime.MutableState +import androidx.compose.runtime.mutableStateOf +import java.nio.ByteBuffer + +data class WStringField(override var content:String = "", override val contentState: MutableState = mutableStateOf(content)): ConnectionField(content, contentState) { + override fun getFromFBValue(): ByteArray { + val contentBytes: ByteArray = content.toByteArray(Charsets.UTF_16) + return ByteBuffer.allocate(contentBytes.size * 2 + 3).put(getTypeID().code.toByte()).putShort((content.length.toShort() * 2).toShort()).put(contentBytes).array() + } + + override fun getMsgValue(): String { + TODO("Not yet implemented") + } + + override fun getFBValue(d: ByteArray) { + var size = ByteBuffer.wrap(d).getShort(1) + setValue(String(d.copyOfRange(3, 3 + size.toInt()), Charsets.UTF_16)) + println(d.contentToString()) + } + + override fun getFBValue(d: String) { + TODO("Not yet implemented") + } + + override fun getTypeID(): TYPE_ID { + return TYPE_ID.WSTRING + } + +} \ No newline at end of file diff --git a/code/cat_visual/src/main/kotlin/connection/provider/ConnectionProvider.kt b/code/cat_visual/src/main/kotlin/connection/provider/ConnectionProvider.kt new file mode 100644 index 000000000..a81d45400 --- /dev/null +++ b/code/cat_visual/src/main/kotlin/connection/provider/ConnectionProvider.kt @@ -0,0 +1,89 @@ +package connection.provider + +import connection.ConnectionFieldRegistry +import connection.field.ConnectionField +import connection.field.TYPE_ID +import java.io.BufferedReader +import java.io.InputStreamReader +import java.io.PrintWriter +import java.net.DatagramPacket +import java.net.InetAddress +import java.net.MulticastSocket +import java.net.ServerSocket +import java.net.Socket +import java.nio.ByteBuffer +import kotlin.concurrent.thread + +abstract class ConnectionProvider(private val port: Int, private val host: String = "225.0.0.1") { + abstract fun response(fieldGetter: (ByteArray) -> Pair, ByteArray>, String>, ping:Long = 500, callbacks: Map Unit> = mapOf()) + abstract fun response(fieldSetter: (String) -> String, log: Boolean, ping:Long = 500, callbacks: Map Unit> = mapOf()) + abstract fun request(field: ConnectionField, prefix: ByteArray) + abstract fun request(msg: String) +} + +class UDPConnectionProvider(private val port: Int, private val host: String = "225.0.0.1"): ConnectionProvider(port, host) { + val group = InetAddress.getByName(host); + val socket = MulticastSocket(port); + + + init { + socket.joinGroup(group) + } + + var ind = 0 + + override fun response(fieldGetter: (ByteArray) -> Pair, ByteArray>, String>, ping:Long, callbacks: Map Unit>) { + thread { + while (true) { + val buf = ByteArray(1024); + val recv = DatagramPacket(buf, buf.size); + socket.receive(recv) + val fieldData = fieldGetter(recv.data) + val field = fieldData.first.first + val data = fieldData.first.second + val name = fieldData.second + println("GETTING ${field.getTypeID()}") + field.getFBValue(data) + callbacks.getOrDefault(name, {})() + println("GOT ${field.getValue()}") + Thread.sleep(ping) + } + } + } + + override fun request(field: ConnectionField, prefix: ByteArray) { + println("SENDING ${field.getValue()}") + var msg = field.getFromFBValue() + msg = prefix.plus(msg) + val hi = DatagramPacket(msg, msg.size, + group, port); + socket.send(hi) + } + + override fun request(msgJ: String) { + println("SENDING ${msgJ}") + val contentBytes = msgJ.toByteArray() + val msg = ByteBuffer.allocate(contentBytes.size + 3).put(TYPE_ID.STRING.code.toByte()).putShort(msgJ.length.toShort()).put(contentBytes).array() + val hi = DatagramPacket(msg, msg.size, + group, port); + socket.send(hi) + } + + override fun response(fieldSetter: (String) -> String, log: Boolean, ping:Long, callbacks: Map Unit>) { + thread { + while (true) { + + val buf = ByteArray(1024); + val recv = DatagramPacket(buf, buf.size); + socket.receive(recv) + var size = ByteBuffer.wrap(recv.data).getShort(1) + var msg = String(recv.data.copyOfRange(3, 3 + size.toInt())) + if (log) println("MESSAGE $msg") + val name = fieldSetter(msg) + callbacks.getOrDefault(name, {})() + Thread.sleep(ping) + } + } + } + +} \ No newline at end of file diff --git a/code/cat_visual/src/main/kotlin/example/COUNTER/COMMON_CONF.xml b/code/cat_visual/src/main/kotlin/example/COUNTER/COMMON_CONF.xml new file mode 100644 index 000000000..b887ebd85 --- /dev/null +++ b/code/cat_visual/src/main/kotlin/example/COUNTER/COMMON_CONF.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/code/cat_visual/src/main/kotlin/example/COUNTER/COUNT.xml b/code/cat_visual/src/main/kotlin/example/COUNTER/COUNT.xml new file mode 100644 index 000000000..e69de29bb diff --git a/code/cat_visual/src/main/kotlin/example/COUNTER/COUNTER.kt b/code/cat_visual/src/main/kotlin/example/COUNTER/COUNTER.kt new file mode 100644 index 000000000..309fe7173 --- /dev/null +++ b/code/cat_visual/src/main/kotlin/example/COUNTER/COUNTER.kt @@ -0,0 +1,44 @@ +package example.COUNTER + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.width +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.dp +import connection.AbstractClient +import connection.ConnectionFieldRegistry +import lib.elements.getters.Bulb +import lib.elements.getters.TextBox +import lib.elements.setters.Checkbox +import lib.elements.setters.Toggle +import lib.visual.PositionedBox + + +@Composable +fun LampHMI(client: AbstractClient, id: String) { + Bulb("$id#LAMP", client) +} +@Composable +fun ToggleHMI(client: AbstractClient, id: String) { + Toggle("$id#TOGGLE", client) +} + +@Composable +fun CounterHMI(client: AbstractClient, id: String) { + Row { + Text("Count of changes: ") + TextBox("$id#COUNT", client, Modifier.width(40.dp).height(30.dp).background(Color.LightGray)) +// PositionedBox( children = {Indicator("count", "225.0.0.2", 65003, registry, 0, 100, 1000.dp)}, x = 100, y = 100) + } +} + +@Composable +fun CounterLampHMI(client: AbstractClient, id: String) { + PositionedBox(children = {CounterHMI(client, "1")}, x = 200) + LampHMI(client, "1") + PositionedBox(children = {example.COUNTER.ToggleHMI(client, "1")}, x = 300, y = 100) +} \ No newline at end of file diff --git a/code/cat_visual/src/main/kotlin/example/COUNTER/COUNTER.xml b/code/cat_visual/src/main/kotlin/example/COUNTER/COUNTER.xml new file mode 100644 index 000000000..869c96923 --- /dev/null +++ b/code/cat_visual/src/main/kotlin/example/COUNTER/COUNTER.xml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/code/cat_visual/src/main/kotlin/example/COUNTER/COUNTER_CONF.xml b/code/cat_visual/src/main/kotlin/example/COUNTER/COUNTER_CONF.xml new file mode 100644 index 000000000..bb9432301 --- /dev/null +++ b/code/cat_visual/src/main/kotlin/example/COUNTER/COUNTER_CONF.xml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/code/cat_visual/src/main/kotlin/example/COUNTER/COUNTER_PLAIN.xml b/code/cat_visual/src/main/kotlin/example/COUNTER/COUNTER_PLAIN.xml new file mode 100644 index 000000000..8998ad64d --- /dev/null +++ b/code/cat_visual/src/main/kotlin/example/COUNTER/COUNTER_PLAIN.xml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/code/cat_visual/src/main/kotlin/example/COUNTER/LAMP.xml b/code/cat_visual/src/main/kotlin/example/COUNTER/LAMP.xml new file mode 100644 index 000000000..869c96923 --- /dev/null +++ b/code/cat_visual/src/main/kotlin/example/COUNTER/LAMP.xml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/code/cat_visual/src/main/kotlin/example/COUNTER/TOGGLE.xml b/code/cat_visual/src/main/kotlin/example/COUNTER/TOGGLE.xml new file mode 100644 index 000000000..e69de29bb diff --git a/code/cat_visual/src/main/kotlin/example/INCHOICE/INCHOICE.kt b/code/cat_visual/src/main/kotlin/example/INCHOICE/INCHOICE.kt new file mode 100644 index 000000000..b835fd35d --- /dev/null +++ b/code/cat_visual/src/main/kotlin/example/INCHOICE/INCHOICE.kt @@ -0,0 +1,75 @@ +//package example.INCHOICE +// +//import androidx.compose.foundation.background +//import androidx.compose.foundation.layout.Box +//import androidx.compose.foundation.layout.Column +//import androidx.compose.foundation.layout.height +//import androidx.compose.foundation.layout.width +//import androidx.compose.material.Switch +//import androidx.compose.material.Text +//import androidx.compose.runtime.* +//import androidx.compose.ui.Modifier +//import androidx.compose.ui.graphics.Color +//import androidx.compose.ui.unit.dp +//import connection.field.BoolField +//import connection.field.ConnectionField +//import connection.field.StringField +//import connection.provider.ConnectionProvider +// +//val field: ConnectionField = BoolField() +//val toggleField: ConnectionField = BoolField() +//val ipField: ConnectionField = StringField() +// +//var connectionProvider: ConnectionProvider = ConnectionProvider(field, 65001) +//var connectionProviderToggle: ConnectionProvider = ConnectionProvider(toggleField, 65000) +//var connectionProviderIpText: ConnectionProvider = ConnectionProvider(ipField, 65002) +// +// +//val ping = 1 +// +//@Composable +//fun LampToggle() { +// val checkedState = remember { toggleField } +// Switch( +// checked = checkedState.contentState.value, +// onCheckedChange = { +// checkedState.setValue(it) +// connectionProviderToggle.request()} +// ) +//} +// +// +//val trueColor = Color.Yellow +//val falseColor = Color.Black +// +// +//@Composable +//fun Lamp_HMI() { +// fun getColor(s: Boolean): Color { +// if (s) { +// return trueColor +// } else { +// return falseColor +// } +// } +// +// +// var checkedState = remember{ field } +// Column { +// Box( +// modifier = Modifier.background(color = if (checkedState.contentState.value) trueColor else falseColor) +// .width(600.dp) +// .height(600.dp) +// ) { +// connectionProvider.response() +// } +// Box( +// modifier = Modifier.background(color = Color.Gray) +// .width(200.dp) +// .height(200.dp) +// ) { +// Text(ipField.contentState.value) +// connectionProviderIpText.response() +// } +// } +//} diff --git a/code/cat_visual/src/main/kotlin/example/INCHOICE/INCHOICE_HMI.cnv.xml b/code/cat_visual/src/main/kotlin/example/INCHOICE/INCHOICE_HMI.cnv.xml new file mode 100644 index 000000000..5297eeccc --- /dev/null +++ b/code/cat_visual/src/main/kotlin/example/INCHOICE/INCHOICE_HMI.cnv.xml @@ -0,0 +1,17 @@ + + + + CHOICES + + + I + + + + + + + + + + \ No newline at end of file diff --git a/code/cat_visual/src/main/kotlin/example/WATER_TANK/WATER_TANK.kt b/code/cat_visual/src/main/kotlin/example/WATER_TANK/WATER_TANK.kt new file mode 100644 index 000000000..3d66990ed --- /dev/null +++ b/code/cat_visual/src/main/kotlin/example/WATER_TANK/WATER_TANK.kt @@ -0,0 +1,121 @@ +package example.WATER_TANK + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp +import androidx.compose.ui.zIndex +import connection.AbstractClient +import connection.ConnectionFieldRegistry +import lib.elements.* +import lib.elements.getters.Bulb +import lib.elements.getters.LightingText +import lib.elements.getters.VerticalIndicator +import lib.elements.setters.RoundKnob +import lib.visual.PositionedBox + +@Composable +fun WaterTank(client: AbstractClient) { + + Box { + PositionedBox(@Composable { LampIndicator("lampIndicator1", client) }, 120, 190) + PositionedBox(@Composable { LampIndicator("lampIndicator2", client) }, 120, 380) + PositionedBox(@Composable { PipeConnector(Color.Gray, 100.dp, 30.dp) }, 150, 100) + PositionedBox(@Composable { Figure(RoundedCornerShape(100.dp), + modifier = Modifier.size(200.dp, 300.dp) + .background(brush = METALLIC_BRUSH, shape = RoundedCornerShape(20.dp)) + ) + }, 200, 150, zIndex = 2f) + PositionedBox(@Composable { Pipe(Color.Gray, 100.dp, 30.dp) }, 400, 400) + PositionedBox(@Composable { + VerticalIndicator( + "tankIndicator", client, + color = Color.Blue, step = 20f, minTemperature = 0f, maxTemperature = 100f, + trackHeight = 200.dp, indicatorWidth = 20.dp + ) + }, 300, 200, zIndex = 3f) + } +} + +@Composable +fun LampIndicator(name: String, client: AbstractClient, pipeSize: Dp = 30.dp) { + Row { + PositionedBox(@Composable { + Bulb( + name, + client, + size = pipeSize, + borderWidth = 4.dp, + modifier = Modifier.zIndex(2f) + ) + }, pipeSize.value / 2) + Pipe(Color.Gray, 100.dp, pipeSize) + } +} + + +@Composable +fun System(client: AbstractClient) { + PositionedBox(@Composable { + RoundKnob( + "knob1", + client, + 0..100, + 0f, + knobSize = 60.dp, + knobColor = Color.Red + ) + }, 10, 50) + PositionedBox(@Composable { + RoundKnob( + "knob2", + client, + 0..100, + 0f, + knobSize = 60.dp, + knobColor = Color.Blue + ) + }, 10, 120) + WaterTank(client) + PositionedBox(@Composable { + VerticalIndicator( + "outputIndicator", client, + color = Color.Red, step = 20f, minTemperature = 0f, maxTemperature = 100f, + trackHeight = 200.dp, indicatorWidth = 20.dp + ) + }, 440, 150, zIndex = 3f) + PositionedBox(@Composable { + LightingText( + "stateInlet", + client, + "Inlet", + width = 70.dp, + height = 25.dp, + borderWidth = 5.dp + ) + }, 500, 150) + PositionedBox(@Composable { + LightingText( + "stateHeat", + client, + "Heat", + width = 70.dp, + height = 25.dp, + borderWidth = 5.dp + ) + }, 500, 200) + PositionedBox(@Composable { + LightingText( + "stateOutlet", + client, + "Outlet", + width = 70.dp, + height = 25.dp, + borderWidth = 5.dp + ) + }, 500, 250) +} \ No newline at end of file diff --git a/code/cat_visual/src/main/kotlin/example/WATER_TANK/WATER_TANK.xml b/code/cat_visual/src/main/kotlin/example/WATER_TANK/WATER_TANK.xml new file mode 100644 index 000000000..bba095874 --- /dev/null +++ b/code/cat_visual/src/main/kotlin/example/WATER_TANK/WATER_TANK.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/code/cat_visual/src/main/kotlin/example/WATER_TANK/WATER_TANK_CONF.xml b/code/cat_visual/src/main/kotlin/example/WATER_TANK/WATER_TANK_CONF.xml new file mode 100644 index 000000000..b7461d6df --- /dev/null +++ b/code/cat_visual/src/main/kotlin/example/WATER_TANK/WATER_TANK_CONF.xml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/code/cat_visual/src/main/kotlin/example/WATER_TANK/WATER_TANK_PLAIN.xml b/code/cat_visual/src/main/kotlin/example/WATER_TANK/WATER_TANK_PLAIN.xml new file mode 100644 index 000000000..f59dbb5dc --- /dev/null +++ b/code/cat_visual/src/main/kotlin/example/WATER_TANK/WATER_TANK_PLAIN.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/code/cat_visual/src/main/kotlin/lib/elements/figures/elements.kt b/code/cat_visual/src/main/kotlin/lib/elements/figures/elements.kt new file mode 100644 index 000000000..d23a47a84 --- /dev/null +++ b/code/cat_visual/src/main/kotlin/lib/elements/figures/elements.kt @@ -0,0 +1,212 @@ +package lib.elements + +import androidx.compose.animation.core.AnimationSpec +import androidx.compose.animation.core.animateFloatAsState +import androidx.compose.animation.core.tween +import androidx.compose.foundation.Canvas +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.shape.CutCornerShape +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.MaterialTheme +import androidx.compose.runtime.Composable +import androidx.compose.runtime.MutableState +import androidx.compose.runtime.getValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.draw.rotate +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.geometry.Size +import androidx.compose.ui.graphics.* +import androidx.compose.ui.graphics.drawscope.Stroke +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp + + +@Composable +fun Rectangle(color: Color, width: Dp, height: Dp) { + Box( + modifier = Modifier.background(color = color) + .width(width) + .height(height) + ) { + } +} + +@Composable +fun Rectangle(color: Color, size: Dp) { + Box( + modifier = Modifier.background(color = color) + .size(size) + ) { + } +} + +@Composable +fun Round(color: Color, width: Dp, height: Dp) { + Box( + modifier = Modifier.background(color = color) + .clip(CircleShape) + .width(width) + .height(height) + ) { + } +} + +@Composable +fun Round(color: Color, size: Dp) { + Box( + modifier = Modifier.background(color = color) + .clip(CircleShape) + .size(size) + ) { + } +} + +@Composable +fun Round(modifier: Modifier, width: Dp, height: Dp) { + Box( + modifier = Modifier + .clip(CircleShape) + .width(width) + .height(height) + .then(modifier) + ) { + } +} + +@Composable +fun RoundedRectangle(color: Color, width: Dp, height: Dp, radius: Dp) { + Box( + modifier = Modifier.background(color = color) + .clip(RoundedCornerShape(radius)) + .width(width) + .height(height) + ) { + } +} + +@Composable +fun RoundedRectangle(color: Color, size: Dp, radius: Dp) { + Box( + modifier = Modifier.background(color = color) + .clip(RoundedCornerShape(radius)) + .size(size) + ) { + } +} + + +@Composable +fun RoundedRectangle(modifier: Modifier, width: Dp, height: Dp, radius: Dp) { + Box( + modifier = modifier + .clip(RoundedCornerShape(radius)) + .width(width) + .height(height) + ) { + } +} + +@Composable +fun CutRectangle(color: Color, width: Dp, height: Dp, radius: Dp) { + Figure(shape = CutCornerShape(radius), + modifier = Modifier.background(color = color) + .width(width) + .height(height) + ) +} + +@Composable +fun CutRectangle(color: Color, size: Dp, radius: Dp) { + Figure( + shape = CutCornerShape(radius), + modifier = Modifier.background(color = color) + .clip(CutCornerShape(radius)) + .size(size) + ) +} + + +@Composable +fun Figure(shape: Shape = RectangleShape, modifier: Modifier = Modifier) { + Box(modifier = modifier.clip(shape)){ + } +} + +@Composable +fun OneDAnimatedComposable( + content: @Composable () -> Unit, + isAtTheEnd: Boolean, + targetValue: Float, + horizontally: Boolean = true, + animationSpec: AnimationSpec = tween(durationMillis = 1000), +) { + val animatedValue by animateFloatAsState( + targetValue = if (isAtTheEnd) targetValue else 0f, + animationSpec = animationSpec + ) + + var modifier:Modifier = Modifier; + if (horizontally) { + modifier = modifier.offset(x = animatedValue.dp) + } else { + modifier = modifier.offset(y = animatedValue.dp) + } + Box( + modifier = modifier + ) { + content() + } +} + +@Composable +fun Pipe( + color: Color, + pipeWidth: Dp, + pipeHeight: Dp, + modifier: Modifier = Modifier +) { + Box( + modifier = modifier + .width(pipeWidth) + .height(pipeHeight) + .background(brush = Brush.verticalGradient(listOf(color, color.copy(alpha = 0.2f), color))) + ){} +} + +@Composable +fun PipeConnector( + color: Color, + connectorWidth: Dp, + connectorHeight: Dp, + modifier: Modifier = Modifier +) { + Box(modifier = modifier) { + Box( + modifier = Modifier + .offset() + .width(connectorWidth) + .height(connectorHeight) + .background( + brush = Brush.verticalGradient(listOf(color, color.copy(alpha = 0.2f), color)), + shape = RoundedCornerShape(0.dp, connectorHeight, connectorHeight, 0.dp) + ) + ) {} + val rotatedBoxOffset = connectorWidth / 2 - connectorHeight /2 + Box( + modifier = Modifier + .offset(x = rotatedBoxOffset, y = rotatedBoxOffset) + .rotate(-90f) + .width(connectorWidth) + .height(connectorHeight) + .background( + brush = Brush.verticalGradient(listOf(color, color.copy(alpha = 0.2f), color)), + shape = RoundedCornerShape(0.dp, connectorHeight, connectorHeight, 0.dp) + ) + ) {} + } + +} \ No newline at end of file diff --git a/code/cat_visual/src/main/kotlin/lib/elements/getters/elements.kt b/code/cat_visual/src/main/kotlin/lib/elements/getters/elements.kt new file mode 100644 index 000000000..3be2f0045 --- /dev/null +++ b/code/cat_visual/src/main/kotlin/lib/elements/getters/elements.kt @@ -0,0 +1,221 @@ +package lib.elements.getters + +import androidx.compose.foundation.* +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Brush +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.RectangleShape +import androidx.compose.ui.graphics.StrokeCap +import androidx.compose.ui.graphics.drawscope.Stroke +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.font.SystemFontFamily +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.TextUnit +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.compose.ui.zIndex +import connection.AbstractClient +import connection.ConnectionFieldRegistry +import connection.field.ConnectionField +import connection.field.TYPE_ID +import connection.provider.ConnectionProvider +import lib.elements.* + +@Composable +fun Bulb(name: String, client: AbstractClient, + size: Dp = 60.dp, borderWidth:Dp = 10.dp, + modifier: Modifier = Modifier + ) { + + val field = client.getField(name) as ConnectionField + + var checkedStateBulb = remember { field } + Round( + modifier.background(brush = if (checkedStateBulb.contentState.value) LIGHT_RADIAL_BRUSH else DARK_RADIAL_BRUSH) + .border(width = borderWidth, brush = METALLIC_BRUSH, shape = CircleShape), + size, + size + ) +} + + +@Composable +fun LightingText(name: String, client: AbstractClient, + text:String, + width: Dp = 60.dp, height: Dp = 60.dp, borderWidth:Dp = 10.dp, + modifier: Modifier = Modifier, lightBrush: Brush = LIGHT_RADIAL_BRUSH + ) { + + val field = client.getField(name) as ConnectionField + + var checkedStateBulb = remember { field } + + Box( + modifier = modifier.background(brush = if (checkedStateBulb.contentState.value) lightBrush else DARK_RADIAL_BRUSH, shape = RoundedCornerShape(height / 4)) + .border(width = borderWidth, brush = METALLIC_BRUSH, shape = RoundedCornerShape(height / 4)) + .widthIn(min = width) + .heightIn(min = height) + .clip(RoundedCornerShape(height / 4)), + ) { + Text(text, modifier = Modifier.align(Alignment.Center)) + } +} + +@Composable +fun TextBox( + name: String, + client: AbstractClient, + modifier: Modifier = Modifier.focusable(true) +) { + val field = client.getField(name) + + var checkedState = remember { field } + Box( + modifier = modifier.then(Modifier.fillMaxWidth().fillMaxHeight()) + ) { + Text(checkedState!!.contentState.value.toString()) + } +} + +@Composable +fun Indicator( + name: String, client: AbstractClient, + minIndicatorValue: Int, maxIndicatorValue: Int, size: Dp, + indicatorThickness: Dp = 28.dp, + animationDuration: Int = 1000, + animationDelay: Int = 0 +) { + val field = client.getField(name) as ConnectionField + + var checkedState = remember { field } + Box( + contentAlignment = Alignment.Center, + modifier = Modifier.wrapContentSize().padding(indicatorThickness) + ) { + Canvas( + modifier = Modifier + .height(size + indicatorThickness) + .width(size + indicatorThickness) + ) { + drawArc( + color = Color.LightGray, + startAngle = 0f, + sweepAngle = -180f, + useCenter = false, + style = Stroke(width = indicatorThickness.toPx(), cap = StrokeCap.Round) + ) + + var sweepAngle = 0f; + if (checkedState.contentState.value.toInt() != 0) { + sweepAngle = (checkedState.contentState.value.toInt() / (maxIndicatorValue - minIndicatorValue).toFloat()) * 180f + } + + // Foreground circle + drawArc( + color = Color.Red, + startAngle = 180f, + sweepAngle = sweepAngle, + useCenter = false, + style = Stroke(indicatorThickness.toPx(), cap = StrokeCap.Round) + ) + + + } + Text( + text = checkedState.contentState.value.toString(), + color = Color.Black, + style = MaterialTheme.typography.body1, + textAlign = TextAlign.Center, + modifier = Modifier + .align(Alignment.Center), + fontSize = 30.sp + ) + } +} + + +@Composable +fun VerticalIndicator( + name: String, client: AbstractClient, + temperature: Float = 0f, + maxTemperature: Float, + minTemperature: Float, + color: Color, + step: Float, + modifier: Modifier = Modifier, + trackHeight: Dp = 400.dp, + indicatorWidth: Dp = 48.dp, + legendFontSize: TextUnit = 12.sp, + legendFontColor: Color = Color.Black, + font: SystemFontFamily = FontFamily.Default, + showCurrentState: Boolean = false +) { + val field = client.getField(name) as ConnectionField + var checkedState = remember { field } + + val stepCount = ((maxTemperature - minTemperature) / step).toInt() + val temperatureRange = maxTemperature - minTemperature + + Box( + modifier = modifier + .width(indicatorWidth) + .height(trackHeight) + .background(Color.LightGray) + .border(BorderStroke(3.dp, METALLIC_BRUSH), RectangleShape) + ) { + val temperatureOffset = (checkedState.contentState.value.toFloat() - minTemperature) / temperatureRange + val indicatorHeight = (temperatureOffset * trackHeight.value).dp + + + Box( + modifier = Modifier + .fillMaxWidth() + .height(indicatorHeight) + .background(color) + .align(Alignment.BottomCenter) + ) { + + if (showCurrentState) { + Text( + text = "${checkedState.contentState.value}", + fontSize = 16.sp, + fontWeight = FontWeight.Bold, + color = legendFontColor, + modifier = Modifier.offset(y = trackHeight) + ) + } + } + + } + for (i in (minTemperature.toInt()..maxTemperature.toInt()).reversed() step step.toInt()) { + val halfLegendHeight = legendFontSize.value.dp / 2f + val labelOffset = ((i - minTemperature) / temperatureRange).coerceIn(0f, 1f) + val labelTop = (((1f - labelOffset) * (trackHeight.value)) - halfLegendHeight.value).coerceIn(0f, trackHeight.value).dp + Box(modifier = Modifier.width(indicatorWidth * 2)) { + Text( + modifier = Modifier.offset(x = indicatorWidth, y = labelTop), + text = "$i", + fontSize = legendFontSize, + fontWeight = FontWeight.Light, + fontFamily = font, + color = legendFontColor, + softWrap = false, + lineHeight = legendFontSize + ) + } + } + +} \ No newline at end of file diff --git a/code/cat_visual/src/main/kotlin/lib/elements/setters/elements.kt b/code/cat_visual/src/main/kotlin/lib/elements/setters/elements.kt new file mode 100644 index 000000000..a13e073dd --- /dev/null +++ b/code/cat_visual/src/main/kotlin/lib/elements/setters/elements.kt @@ -0,0 +1,549 @@ +package lib.elements.setters + +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.foundation.* +import androidx.compose.foundation.gestures.* +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.lazy.itemsIndexed +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.material.* +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.ArrowDropDown +import androidx.compose.material.icons.filled.Check +import androidx.compose.material.icons.filled.Done +import androidx.compose.runtime.Composable +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.getValue +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.draw.rotate +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.geometry.Size +import androidx.compose.ui.graphics.* +import androidx.compose.ui.graphics.drawscope.Stroke +import androidx.compose.ui.input.pointer.consumeAllChanges +import androidx.compose.ui.input.pointer.consumePositionChange +import androidx.compose.ui.input.pointer.pointerInput +import androidx.compose.ui.input.pointer.positionChange +import androidx.compose.ui.layout.boundsInWindow +import androidx.compose.ui.layout.onGloballyPositioned +import androidx.compose.ui.layout.onSizeChanged +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.input.ImeAction +import androidx.compose.ui.text.input.KeyboardType +import androidx.compose.ui.text.input.TextFieldValue +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.* +import androidx.compose.ui.zIndex +import connection.AbstractClient +import connection.ConnectionFieldRegistry +import connection.field.* +import connection.provider.ConnectionProvider +import lib.elements.METALLIC_BRUSH +import java.lang.UnsupportedOperationException +import kotlin.concurrent.thread +import kotlin.math.PI +import kotlin.math.atan2 +import kotlin.math.roundToInt + +@Composable +fun CustomButton( + text: String, + onClick: () -> Unit, + modifier: Modifier = Modifier, + buttonColors: ButtonColors = ButtonDefaults.buttonColors(), + textColor: Color = Color.Black, + backgroundColor: Color = Color.White, + borderColor: Color = Color.Transparent, + borderWidth: Int = 0, + cornerRadius: Int = 0 +) { + Button( + onClick = onClick, + modifier = modifier, + colors = buttonColors, + shape = RoundedCornerShape(cornerRadius.dp), + border = BorderStroke(width = borderWidth.dp, color = borderColor), + contentPadding = PaddingValues(16.dp), + elevation = ButtonDefaults.elevation(defaultElevation = 0.dp, pressedElevation = 2.dp) + ) { + Text( + text = text, + color = textColor, + modifier = Modifier.padding(4.dp) + ) + } +} + +@Composable +fun Toggle( + name: String, client: AbstractClient, + modifier: Modifier = Modifier, + onCheckedChange: (Boolean) -> Unit = {} +) { + val toggleField = client.getField(name) as ConnectionField + + val checkedStateToggle = remember { toggleField } + Switch( + modifier = modifier.size(24.dp), + checked = checkedStateToggle.contentState.value, + onCheckedChange = { + checkedStateToggle.setValue(it) + client.sendValue(name) + onCheckedChange(it) + } + ) +} + +@Composable +fun Checkbox( + name: String, client: AbstractClient, + modifier: Modifier = Modifier, + onCheckedChange: (Boolean) -> Unit = {}, + checkboxColor: Color = MaterialTheme.colors.primary, + checkmarkColor: Color = Color.White, + disabledColor: Color = MaterialTheme.colors.onSurface.copy(alpha = 0.38f), + contentDescription: String? = null +) { + val checkboxField = client.getField(name) as ConnectionField + + val checkedStateCheckbox = remember { checkboxField } + + Box( + modifier = modifier + .clickable( + onClick = { + val changedValue = !checkedStateCheckbox.contentState.value + checkedStateCheckbox.setValue(changedValue) + client.sendValue(name) + onCheckedChange(changedValue) + }) + .size(24.dp), + contentAlignment = Alignment.Center + ) { + val backgroundColor = if (checkedStateCheckbox.contentState.value) checkboxColor else disabledColor + Box( + modifier = Modifier + .size(20.dp) + .background(color = backgroundColor) + .border(width = 2.dp, brush = METALLIC_BRUSH, shape = RectangleShape), + contentAlignment = Alignment.Center + ) { + if (checkedStateCheckbox.contentState.value) { + Icon( + imageVector = Icons.Default.Check, + contentDescription = contentDescription, + tint = checkmarkColor, + modifier = Modifier.size(12.dp) + ) + } + } + } +} + +@Composable +fun ListBox( + name: String, client: AbstractClient, + modifier: Modifier = Modifier, + items: List, + onItemSelected: (String) -> Unit = {}, + dropdownMaxHeight: Dp = 240.dp, + content: @Composable (String) -> Unit +) { + val comboBoxField = client.getField(name) as ConnectionField + + val checkedStateComboBox = remember { comboBoxField } + var expanded by remember { mutableStateOf(false) } + var dropdownHeight by remember { mutableStateOf(0.dp) } + val density = LocalDensity.current + val dropdownHeightPx = with(density) { dropdownHeight.toPx() } + var selectedItem: String by remember { mutableStateOf("") } + var textfieldSize by remember { mutableStateOf(0) } + val interactionSource = remember { + MutableInteractionSource() + } + + Column( + modifier = modifier.wrapContentSize().clickable( + interactionSource = interactionSource, + indication = null, + onClick = { + expanded = false + } + ), + horizontalAlignment = Alignment.Start + ) { + Box( + modifier = Modifier + .fillMaxWidth() + .background(color = Color.White, shape = MaterialTheme.shapes.medium) + .padding(horizontal = 16.dp, vertical = 12.dp) + ) { + Row(verticalAlignment = Alignment.CenterVertically, + modifier = Modifier.onSizeChanged { + textfieldSize = it.width +// print(textfieldSize) + }) { + + Box(modifier = Modifier.weight(1f)) { + content(selectedItem) + } + Icon(imageVector = Icons.Default.ArrowDropDown, + contentDescription = null, + Modifier.size(24.dp).alignByBaseline().clickable { expanded = !expanded }) + + } + } + DropdownMenu( + expanded = expanded, + onDismissRequest = { expanded = false }, + modifier = Modifier + .heightIn(max = dropdownMaxHeight) + .width(with(LocalDensity.current) { textfieldSize.toDp() }) + .onSizeChanged { dropdownHeight = it.height.dp } + ) { + items.forEach { item -> + DropdownMenuItem( + onClick = { + checkedStateComboBox.setValue(item) + client.sendValue(name) + onItemSelected(item) + selectedItem = item + expanded = false + }, + modifier = Modifier + .fillMaxWidth() + .heightIn(min = 48.dp) + ) { + content(item) + } + } + } + } +} + + +@Composable +fun ComboBox( + name: String, client: AbstractClient, + modifier: Modifier = Modifier, + items: List, + onItemSelected: (String) -> Unit = {}, + dropdownMaxHeight: Dp = 240.dp, + content: @Composable (String) -> Unit +) { + val comboBoxField = client.getField(name) as ConnectionField + + val checkedStateComboBox = remember { comboBoxField } + var expanded by remember { mutableStateOf(false) } + var dropdownHeight by remember { mutableStateOf(0.dp) } + var selectedItem by remember { mutableStateOf("") } + var textfieldSize by remember { mutableStateOf(0) } + val scrollState = rememberScrollState() + + Column( + modifier = modifier.wrapContentSize(), + horizontalAlignment = Alignment.Start + ) { + + Box(modifier = Modifier.fillMaxWidth()) { + OutlinedTextField( + value = selectedItem, + onValueChange = { + selectedItem = it + expanded = true + }, + modifier = Modifier.fillMaxWidth(), + label = { Text("Select an item") }, + keyboardOptions = KeyboardOptions( + keyboardType = KeyboardType.Text, + imeAction = ImeAction.Done + ), + trailingIcon = { + Icon( + Icons.Default.ArrowDropDown, + "Drop Down", + Modifier.size(24.dp).clickable { expanded = !expanded } + ) + } + ) + } + AnimatedVisibility(visible = expanded) { + Card( + modifier = Modifier + .padding(horizontal = 5.dp) + .fillMaxWidth(), + elevation = 15.dp + ) { + var currItems: List = items.sorted() + if (selectedItem.isNotEmpty()) { + currItems = items.filter { it.lowercase().contains(selectedItem.lowercase()) } + } + LazyColumn { + items(currItems){ item -> + Box( + modifier = Modifier.clickable { + checkedStateComboBox.setValue(item) + client.sendValue(name) + onItemSelected(item) + selectedItem = item + expanded = false + } + .fillMaxWidth() + .heightIn(min = 48.dp) + ) { + content(item) + } + } + } + + } + } + } +} + +@Composable +fun InputTextBox( + name: String, client: AbstractClient, + modifier: Modifier = Modifier, + onItemChanged: (String) -> Unit = {}, + hintText: String = "Write something" +) { + val textBoxField = client.getField(name) as ConnectionField + val checkedStateTextBox = remember { textBoxField } + var selectedItem: String by remember { mutableStateOf("") } + Box(modifier = Modifier.fillMaxWidth()) { + OutlinedTextField( + value = selectedItem, + onValueChange = { + selectedItem = it + }, + modifier = modifier.fillMaxWidth(), + label = { Text(hintText) }, + keyboardOptions = KeyboardOptions( + keyboardType = KeyboardType.Text, + imeAction = ImeAction.Done + ), + trailingIcon = { + Icon( + Icons.Default.Check, + "Drop Down", + Modifier.size(24.dp).clickable { + checkedStateTextBox.setValue(selectedItem) + client.sendValue(name) + onItemChanged(checkedStateTextBox.getValue()) + } + ) + } + ) + } +} + + + +@Composable +fun HorizontalTracker( + name: String, client: AbstractClient, + range: ClosedFloatingPointRange, + initialValue: Float, + onValueSelected: (Float) -> Unit = {}, + modifier: Modifier = Modifier, + thumbColor: Color = Color.Magenta, + trackColor: Color = Color.LightGray, + borderWidth: Dp = 3.dp, + thumbSize: Dp = 24.dp, + trackWidth: Dp = 100.dp, + trackHeight: Dp = 24.dp, + legend: Boolean = true, + steps: Int = 0, + tickSize: Dp = 1.dp, + legendFontSize: TextUnit = 10.sp +) { + val trackerField = client.getField(name) as ConnectionField + val checkedStateTracker = remember { trackerField } + + var offsetX by remember { mutableStateOf(0f) } + var position by remember { mutableStateOf(getThumbPosition(initialValue, range, thumbSize, trackWidth)) } + var selectedValue by remember { mutableStateOf(initialValue) } + + Box(modifier = modifier.padding(thumbSize / 2)) { + Spacer( + modifier = Modifier + .width(trackWidth) + .height(trackHeight) + .background(trackColor) + .zIndex(1f) + .border(BorderStroke(borderWidth, METALLIC_BRUSH)) + ) + + Box( + modifier = Modifier + .offset(x = position) + .size(thumbSize) + .background(thumbColor, CircleShape) + .zIndex(2f) + .pointerInput(Unit) { + detectDragGestures( + onDragStart = { + }, + onDragEnd = { + val newValue = ((position.value + thumbSize.value / 2) / trackWidth.value) * (range.endInclusive - range.start) + selectedValue = newValue.coerceIn(range) + checkedStateTracker.setValue(selectedValue) + client.sendValue(name) + onValueSelected(selectedValue) + }, + onDragCancel = { + }, + onDrag = { change, _ -> + offsetX = change.positionChange().x + position = max(0.dp - thumbSize / 2, min(position + offsetX.toDp(), trackWidth - thumbSize / 2)) + change.consumePositionChange() + } + ) + } + ) + + if (legend && steps > 0) { + val tickPositions = + (0..steps).map { Pair(range.start + it.toFloat() / steps * (range.endInclusive - range.start), it) } + tickPositions.forEach { position -> + val tickPosition = getTickPosition(position.first, range, thumbSize) + Column(modifier = Modifier.offset(x = tickPosition.dp).zIndex(0f)) { + Spacer( + modifier = Modifier + .height(trackHeight + tickSize) + .width(1.dp) + .background(Color.Black) + + ) + Text(position.second.toString(), modifier = Modifier.align(Alignment.CenterHorizontally), fontSize = legendFontSize) + } + } + } + } +} + +fun getThumbPosition(value: Float, range: ClosedFloatingPointRange, thumbWidth: Dp, trackWidth: Dp): Dp { + val normalizedValue = (value - range.start) / (range.endInclusive - range.start) + return trackWidth * normalizedValue + thumbWidth / 2 +} + +fun getTickPosition(value: Float, range: ClosedFloatingPointRange, thumbWidth: Dp): Float { + val normalizedValue = (value - range.start) / (range.endInclusive - range.start) + val availableWidth = (range.endInclusive - range.start) + return availableWidth * normalizedValue +} + + +@Composable +fun RoundKnob( + name: String, client: AbstractClient, + range: IntRange, + value: Float, + onValueSelected: (Number) -> Unit = {}, + knobSize: Dp = 48.dp, + strokeWidth: Dp = 4.dp, + knobColor: Color = MaterialTheme.colors.primary, + legendColor: Color = MaterialTheme.colors.onBackground +) { + val knobField = client.getField(name) as ConnectionField + val checkedStateKnob = remember { knobField } + + var rotationAngle by remember { mutableStateOf(calculateRotationAngle(value, range))} + var currValue by remember { mutableStateOf(value) } + var offsetX by remember { mutableStateOf(0f) } + var offsetY by remember { mutableStateOf(0f) } + var centerX by remember { mutableStateOf(0f) } + var centerY by remember { mutableStateOf(0f) } + Box( + contentAlignment = Alignment.Center, + modifier = Modifier.size(knobSize) + ) { + Box(modifier = Modifier.pointerInput(Unit) { + detectDragGestures( + onDragStart = { + }, + onDragEnd = { + var angle = atan2(centerY - offsetY, centerX - offsetX) * (180f / PI).toFloat() - 90 + if (angle < -180) { + angle = (angle + 360) % 360 + } + rotationAngle = (angle).coerceIn(-150f, 150f) + currValue = calculateValue(rotationAngle, range) + + checkedStateKnob.setValue(currValue) + client.sendValue(name) + onValueSelected(currValue) + }, + onDrag = { change, dragAmount -> + offsetX = change.position.x + offsetY = change.position.y + var angle = atan2(centerY - offsetY, centerX - offsetX) * (180f / PI).toFloat() - 90 + if (angle < -180) { + angle = (angle + 360) % 360 + } + rotationAngle = (angle).coerceIn(-150f , 150f) + currValue = calculateValue(rotationAngle, range) + change.consumePositionChange() + } + ) + }) { + Canvas(modifier = Modifier.matchParentSize().onGloballyPositioned { + val windowBounds = it.boundsInWindow() + centerX = windowBounds.size.width / 2f + centerY = windowBounds.size.height / 2f + }) { + drawCircle( + brush = METALLIC_BRUSH, + radius = size.minDimension / 2, + style = Stroke(width = strokeWidth.toPx()) + ) + } + + Canvas( + modifier = Modifier + .size(knobSize) + .rotate(rotationAngle) + ) { + drawLine( + color = knobColor, + start = Offset(x = size.width / 2, y = 0f), + end = Offset(x = size.width / 2, y = size.height / 2), + strokeWidth = strokeWidth.toPx(), + cap = StrokeCap.Round + ) + } + } + + Text( + text = currValue.toString(), + color = legendColor, + style = MaterialTheme.typography.body1, + textAlign = TextAlign.Center, + modifier = Modifier + .align(Alignment.BottomCenter) + .padding(bottom = 8.dp) + ) + } +} + +private fun calculateRotationAngle(value: Float, range: IntRange):Float { + val ratio = (value - range.start) / (range.endInclusive - range.start) + return ratio * 300 - 150 +} + +private fun calculateValue(rotationAngle: Float, range: IntRange): Float { + val ratio = (rotationAngle + 150) / 300 + val value = ratio * (range.endInclusive - range.start) + range.start + return value +} diff --git a/code/cat_visual/src/main/kotlin/lib/visual/Positioning.kt b/code/cat_visual/src/main/kotlin/lib/visual/Positioning.kt new file mode 100644 index 000000000..7f8ae0082 --- /dev/null +++ b/code/cat_visual/src/main/kotlin/lib/visual/Positioning.kt @@ -0,0 +1,32 @@ +package lib.visual + +import androidx.compose.foundation.layout.* +import androidx.compose.runtime.Composable + +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.IntOffset +import androidx.compose.ui.unit.dp +import androidx.compose.ui.zIndex + +@Composable +fun PositionedBox(children: @Composable () -> Unit, x: Int = 0, y:Int = 0, zIndex: Float = 1f) { + Box(modifier = Modifier. + zIndex(zIndex) + .offset {IntOffset(x, y)} + .wrapContentSize()) { + children() + } +} + +@Composable +fun PositionedBox(children: @Composable () -> Unit, x: Float = 0f, y:Float = 0f, zIndex: Float = 1f) { + Box(modifier = Modifier. + zIndex(zIndex) + .offset(x.dp, y.dp) + .wrapContentSize()) { + children() + } +} + + diff --git a/code/cat_visual/src/main/kotlin/lib/visual/colors.kt b/code/cat_visual/src/main/kotlin/lib/visual/colors.kt new file mode 100644 index 000000000..f67d03cf3 --- /dev/null +++ b/code/cat_visual/src/main/kotlin/lib/visual/colors.kt @@ -0,0 +1,51 @@ +package lib.elements + +import androidx.compose.ui.graphics.Brush +import androidx.compose.ui.graphics.Color + + + + +val LIGHT_RADIAL_BRUSH = Brush.radialGradient( + colors = listOf( + Color.Yellow, + Color(0xFFFFA500) + ) +) + +val GREEN_RADIAL_BRUSH = Brush.radialGradient( + colors = listOf( + Color.Gray, + Color.Yellow + ) +) + +val DARK_RADIAL_BRUSH = Brush.radialGradient( + colors = listOf( + Color.DarkGray, + Color.Gray + ) +) + +val LIGHT_HORIZONTAL_BRUSH = Brush.horizontalGradient( + colors = listOf( + Color.Yellow, + Color(0xFFA500FF) + ) +) + +val DARK_HORIZONTAL_BRUSH = Brush.horizontalGradient( + colors = listOf( + Color.Black, + Color.Gray + ) +) + +val METALLIC_BRUSH = Brush.linearGradient( + colors = listOf( + Color.White, + Color.Gray, + Color.DarkGray + ) +) + diff --git a/code/cat_visual/src/main/kotlin/serializer/serialization.kt b/code/cat_visual/src/main/kotlin/serializer/serialization.kt new file mode 100644 index 000000000..9b4923cea --- /dev/null +++ b/code/cat_visual/src/main/kotlin/serializer/serialization.kt @@ -0,0 +1,155 @@ +package serializer + +import kotlinx.serialization.Serializable +import kotlinx.serialization.modules.SerializersModule +import kotlinx.serialization.serializer +import nl.adaptivity.xmlutil.XmlDeclMode +import nl.adaptivity.xmlutil.serialization.XML +import nl.adaptivity.xmlutil.serialization.XmlElement +import nl.adaptivity.xmlutil.serialization.XmlSerialName + +@Serializable +@XmlSerialName("Mapping", "", "") +data class PlainMapping( + val inputs: PlainInputs, + val outputs: PlainOutputs, +) + +@Serializable +@XmlSerialName("Inputs", "", "") +data class PlainInputs( + val inputs: List +) + +@Serializable +@XmlSerialName("Input", "", "") +data class PlainInput( + val name: String, + val type: String, + val host: String, + val port: Int +) + +@Serializable +@XmlSerialName("Outputs", "", "") +data class PlainOutputs( + val outputs: List + +) + +@Serializable +@XmlSerialName("Output", "", "") +data class PlainOutput( + val name: String, + val type: String, + val host: String, + val port: Int +) + + +fun getPlainMapping(modelText: String): PlainMapping { + val module = SerializersModule {} + val xml = XML(module) { + indentString = " " + xmlDeclMode = XmlDeclMode.Minimal + autoPolymorphic = true + } + + val serializer = serializer() + return xml.decodeFromString(serializer, modelText) +} + +@Serializable +@XmlSerialName("Mapping", "", "") +data class Mapping( + val id: String, + val inputs: Inputs, + val outputs: Outputs, +) + +@Serializable +@XmlSerialName("Inputs", "", "") +data class Inputs( + val inputs: List +) + +@Serializable +@XmlSerialName("Input", "", "") +data class Input( + val name: String, + val type: String +) + +@Serializable +@XmlSerialName("Outputs", "", "") +data class Outputs( + val outputs: List +) + +@Serializable +@XmlSerialName("Output", "", "") +data class Output( + val name: String, + val type: String +) + + +fun getMapping(modelText: String): Mapping { + val module = SerializersModule {} + val xml = XML(module) { + indentString = " " + xmlDeclMode = XmlDeclMode.Minimal + autoPolymorphic = true + } + + val serializer = serializer() + return xml.decodeFromString(serializer, modelText) +} + + +@Serializable +@XmlSerialName("Conf", "", "") +data class Conf( + val inputs: ConfInputs, + val outputs: ConfOutputs, +) + +@Serializable +@XmlSerialName("Inputs", "", "") +data class ConfInputs( + val inputs: List +) +@Serializable +@XmlSerialName("Input", "", "") +data class ConfInput( + val type: String, + val host: String, + val port: Int +) + +@Serializable +@XmlSerialName("Outputs", "", "") +data class ConfOutputs( + val outputs: List +) + +@Serializable +@XmlSerialName("Output", "", "") +data class ConfOutput( + val type: String, + val host: String, + val port: Int +) + + +fun getConf(modelText: String): Conf { + val module = SerializersModule {} + val xml = XML(module) { + indentString = " " + xmlDeclMode = XmlDeclMode.Minimal + autoPolymorphic = true + } + + val serializer = serializer() + return xml.decodeFromString(serializer, modelText) +} \ No newline at end of file diff --git a/code/cat_visual/src/test/kotlin/MockBackend.kt b/code/cat_visual/src/test/kotlin/MockBackend.kt new file mode 100644 index 000000000..079444c19 --- /dev/null +++ b/code/cat_visual/src/test/kotlin/MockBackend.kt @@ -0,0 +1,13 @@ +import connection.AbstractClient +import connection.ConnectionFieldRegistry +import connection.field.ConnectionField +import connection.field.TYPE_ID +import serializer.Mapping +import serializer.PlainMapping +import serializer.getMapping +import serializer.getPlainMapping +import java.io.File + +class FieldWithCallback(val field: ConnectionField, val callback: (V) -> Unit) + + diff --git a/code/cat_visual/src/test/kotlin/WaterTankTest.kt b/code/cat_visual/src/test/kotlin/WaterTankTest.kt new file mode 100644 index 000000000..a3559bc1e --- /dev/null +++ b/code/cat_visual/src/test/kotlin/WaterTankTest.kt @@ -0,0 +1,90 @@ +import connection.field.ConnectionField +import kotlin.concurrent.thread + +val client = buildMappingClient("src/main/kotlin/example/WATER_TANK/WATER_TANK.xml", "src/main/kotlin/example/WATER_TANK/WATER_TANK_CONF.xml", mode = "") + + +val TANK_VOLUME = 100 +val MAX_TEMP = 100 + +var isInlet: FieldWithCallback = FieldWithCallback(client.getField("stateInlet") as ConnectionField, + {client.sendValue("stateInlet")}) +var isHeat: FieldWithCallback = FieldWithCallback(client.getField("stateHeat") as ConnectionField, + {client.sendValue("stateHeat")}) +var isOutlet: FieldWithCallback = FieldWithCallback(client.getField("stateOutlet") as ConnectionField, + {client.sendValue("stateOutlet")}) +var lamp1: FieldWithCallback = FieldWithCallback(client.getField("lampIndicator1") as ConnectionField, + {client.sendValue("lampIndicator1")}) +var lamp2: FieldWithCallback = FieldWithCallback(client.getField("lampIndicator2") as ConnectionField, + {client.sendValue("lampIndicator2")}) +var tankIndicator: FieldWithCallback = FieldWithCallback(client.getField("tankIndicator") as ConnectionField, + {client.sendValue("tankIndicator")}) +var outputIndicator: FieldWithCallback = FieldWithCallback(client.getField("outputIndicator") as ConnectionField, + {client.sendValue("outputIndicator")}) +var knob1: FieldWithCallback = FieldWithCallback(client.getField("knob1") as ConnectionField, { + runUpdate() +}) +var knob2: FieldWithCallback = FieldWithCallback(client.getField("knob2") as ConnectionField, { + runUpdate() +}) + + +fun runSimulation(){ + client.retrieveValues(mapOf(Pair("knob1", {knob1.callback(0)}), Pair("knob2", {knob2.callback(0)})), false) +} + +fun runUpdate() { + if (knob1.field.getValue() == 0) { + return + } + if (isInlet.field.getValue() || isHeat.field.getValue() || isOutlet.field.getValue()) { + return + } + isInlet.field.setValue(true) + isInlet.callback(true) + lamp1.field.setValue(true) + lamp1.callback(true) + var currTankState = 0 + while (currTankState < TANK_VOLUME) { + currTankState += knob1.field.getValue() / 2 + tankIndicator.field.setValue(currTankState.toFloat()) + tankIndicator.callback(currTankState.toFloat()) + Thread.sleep( 500) + } + isInlet.field.setValue(false) + isInlet.callback(false) + lamp1.field.setValue(false) + lamp1.callback(false) + isHeat.field.setValue(true) + isHeat.callback(true) + var currTemp = knob2.field.getValue() + while (currTemp < MAX_TEMP) { + currTemp += 10 + outputIndicator.field.setValue(currTemp.toFloat()) + outputIndicator.callback(currTemp.toFloat()) + Thread.sleep(500) + } + isHeat.field.setValue(false) + isHeat.callback(false) + isOutlet.field.setValue(true) + isOutlet.callback(true) + lamp2.field.setValue(true) + lamp2.callback(true) + currTankState = TANK_VOLUME + while (currTankState > 0) { + currTankState -= knob1.field.getValue() / 2 + tankIndicator.field.setValue(currTankState.toFloat()) + tankIndicator.callback(currTankState.toFloat()) + Thread.sleep( 500) + } + isOutlet.field.setValue(false) + isOutlet.callback(false) + lamp2.field.setValue(false) + lamp2.callback(false) + outputIndicator.field.setValue(0f) + outputIndicator.callback(0f) +} + +fun main() { + runSimulation() +} \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index 14f191ebb..979cf2ffc 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,20 +1,21 @@ rootProject.name = "FBME" include( - "code:4diac-integration", - "code:enas", - "code:language", - "code:library", - "code:nxt-integration", - "code:platform", - "code:richediting", - "code:scenes", - "code:smv-debugger", - "code:debugger", +"code:4diac-integration", +"code:enas", +"code:language", +"code:library", +"code:nxt-integration", +"code:platform", +"code:richediting", +"code:scenes", +"code:smv-debugger", +"code:debugger", - "docs", +"docs", - "samples:statistics-plugin", - "samples:sandbox", - "samples:smv-debugger" +"samples:statistics-plugin", +"samples:sandbox", +"samples:smv-debugger", +"cat_visual" ) \ No newline at end of file From 52b98646db3084f5c6e565fabe37327756518c6a Mon Sep 17 00:00:00 2001 From: Valentina Danilova Date: Wed, 24 Jan 2024 19:32:24 +0300 Subject: [PATCH 18/21] bug fixes and identifier changes(WIP) --- .../models/org.fbme.language.build.mps | 5 + .../org.fbme.ide.iec61499.lang.editor.mps | 9 +- .../org.fbme.ide.iec61499.lang.intentions.mps | 2 +- .../models/org.fbme.ide.st.lang.editor.mps | 128 +----------------- .../repository/PlatformDeclarationsScope.kt | 2 +- .../DependentDeclarationGenerator.kt | 15 ++ .../stringify/HMIInterfaceTypeGenerator.kt | 64 ++++++--- .../persistence/Iec61499ModelFactory.kt | 72 +++++----- 8 files changed, 110 insertions(+), 187 deletions(-) diff --git a/code/language/buildsolution/models/org.fbme.language.build.mps b/code/language/buildsolution/models/org.fbme.language.build.mps index 3b28370ae..b318f8383 100644 --- a/code/language/buildsolution/models/org.fbme.language.build.mps +++ b/code/language/buildsolution/models/org.fbme.language.build.mps @@ -417,6 +417,11 @@ + + + + + diff --git a/code/language/languages/org.fbme.ide.iec61499.lang/models/org.fbme.ide.iec61499.lang.editor.mps b/code/language/languages/org.fbme.ide.iec61499.lang/models/org.fbme.ide.iec61499.lang.editor.mps index 537cf030b..543b3e73c 100644 --- a/code/language/languages/org.fbme.ide.iec61499.lang/models/org.fbme.ide.iec61499.lang.editor.mps +++ b/code/language/languages/org.fbme.ide.iec61499.lang/models/org.fbme.ide.iec61499.lang.editor.mps @@ -846,15 +846,8 @@ - + - - - - - - - diff --git a/code/language/languages/org.fbme.ide.iec61499.lang/models/org.fbme.ide.iec61499.lang.intentions.mps b/code/language/languages/org.fbme.ide.iec61499.lang/models/org.fbme.ide.iec61499.lang.intentions.mps index e6a4884b9..81075bdb0 100644 --- a/code/language/languages/org.fbme.ide.iec61499.lang/models/org.fbme.ide.iec61499.lang.intentions.mps +++ b/code/language/languages/org.fbme.ide.iec61499.lang/models/org.fbme.ide.iec61499.lang.intentions.mps @@ -204,7 +204,7 @@ - + diff --git a/code/language/languages/org.fbme.ide.st.lang/models/org.fbme.ide.st.lang.editor.mps b/code/language/languages/org.fbme.ide.st.lang/models/org.fbme.ide.st.lang.editor.mps index 3e6ce0ea7..5a947bc38 100644 --- a/code/language/languages/org.fbme.ide.st.lang/models/org.fbme.ide.st.lang.editor.mps +++ b/code/language/languages/org.fbme.ide.st.lang/models/org.fbme.ide.st.lang.editor.mps @@ -40,9 +40,6 @@ - - - @@ -201,7 +198,6 @@ - @@ -316,7 +312,6 @@ - @@ -417,9 +412,6 @@ - - - @@ -714,7 +706,7 @@ - + @@ -846,12 +838,8 @@ - + - - - - @@ -9716,7 +9704,7 @@ - + @@ -9725,12 +9713,12 @@ - + - + @@ -9886,111 +9874,5 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/code/language/src/main/kotlin/org/fbme/ide/iec61499/repository/PlatformDeclarationsScope.kt b/code/language/src/main/kotlin/org/fbme/ide/iec61499/repository/PlatformDeclarationsScope.kt index ba62b7a53..6e04737b8 100644 --- a/code/language/src/main/kotlin/org/fbme/ide/iec61499/repository/PlatformDeclarationsScope.kt +++ b/code/language/src/main/kotlin/org/fbme/ide/iec61499/repository/PlatformDeclarationsScope.kt @@ -19,7 +19,7 @@ internal class PlatformDeclarationsScope( } override fun findCATBlockTypeDeclaration(identifier: Identifier): CATBlockTypeDeclaration? { - return findNode(identifier)?.let {myRepository.getAdapter(it, CATBlockTypeDeclaration::class.java)} + return findNode(identifier)?.let {repository.getAdapter(it, CATBlockTypeDeclaration::class.java)} } override fun findBasicFBTypeDeclaration(identifier: Identifier): BasicFBTypeDeclaration? { diff --git a/code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/DependentDeclarationGenerator.kt b/code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/DependentDeclarationGenerator.kt index a63070b9f..d66920d59 100644 --- a/code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/DependentDeclarationGenerator.kt +++ b/code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/DependentDeclarationGenerator.kt @@ -21,4 +21,19 @@ class DependentDeclarationGenerator(private val myDeclaration: Declaration, priv return rootElements } + fun getName(): String { + val name = when (myDeclaration) { + is HMIInterfaceTypeDeclaration -> HMIInterfaceTypeGenerator.getDeclarationName(myDeclaration.name) + else -> myDeclaration.name + } + return name + } + + fun getIdentifier(): String { + val name = when (myDeclaration) { + is HMIInterfaceTypeDeclaration -> HMIInterfaceTypeGenerator.getDeclarationName(myDeclaration.identifier.toString()) + else -> myDeclaration.name + } + return name + } } \ No newline at end of file diff --git a/code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/HMIInterfaceTypeGenerator.kt b/code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/HMIInterfaceTypeGenerator.kt index 17ca8c5c2..6224a7243 100644 --- a/code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/HMIInterfaceTypeGenerator.kt +++ b/code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/HMIInterfaceTypeGenerator.kt @@ -9,6 +9,7 @@ import org.fbme.lib.iec61499.parser.Iec61499ConverterConfiguration import org.fbme.lib.iec61499.parser.STConverter import org.fbme.lib.st.STFactory import org.fbme.lib.st.expressions.Expression +import org.fbme.lib.st.expressions.Literal import org.fbme.lib.st.statements.Statement import org.fbme.lib.st.types.DataType import org.fbme.lib.st.types.ElementaryType @@ -21,8 +22,10 @@ class HMIInterfaceTypeGenerator(val declaration: HMIInterfaceTypeDeclaration, va fun generateDependents(): List { val elements = mutableListOf() + val name = getDeclarationName(declaration.name) + val identifier = declaration.identifier.toString() if (declaration.inputParameters.size > 0) { - val outFb = generateDispatchOut(factory, stFactory, declaration.inputParameters, declaration.name) + val outFb = generateDispatchOut(factory, stFactory, declaration.inputParameters, name, identifier) elements.add(outFb) } if (declaration.outputParameters.size > 0) { @@ -30,11 +33,12 @@ class HMIInterfaceTypeGenerator(val declaration: HMIInterfaceTypeDeclaration, va factory, stFactory, declaration.outputParameters, - declaration.name + name, + identifier ) elements.add(inFb) } - val compositeHMI = generateComposite(factory, stFactory, declaration) + val compositeHMI = generateComposite(factory, stFactory, declaration, identifier) elements.add(compositeHMI) return elements } @@ -49,7 +53,7 @@ companion object { ElementaryType.STRING ) - fun generateDispatchOut(factory: IEC61499Factory, stFactory: STFactory, outputVars: List, name: String = ""): FBTypeDeclaration { + fun generateDispatchOut(factory: IEC61499Factory, stFactory: STFactory, outputVars: List, name: String = "", identifier: String = ""): FBTypeDeclaration { val bfb = factory.createBasicFBTypeDeclaration(null) bfb.name = "DISPATCH_OUT_${name}" @@ -59,6 +63,7 @@ companion object { val nameDeclaration = generateParameterDeclaration(factory, "NAME", ElementaryType.STRING, listOf()) val mappingDeclaration = generateParameterDeclaration(factory, "MAPPING", ElementaryType.STRING, listOf()) + mappingDeclaration.initialValue = STConverter.parseLiteral(stFactory, identifier) bfb.inputParameters.add(mappingDeclaration) bfb.outputParameters.add(nameDeclaration) @@ -118,7 +123,7 @@ companion object { } - fun generateDispatchIn(factory: IEC61499Factory, stFactory: STFactory, inputVars: List, name: String = ""): FBTypeDeclaration { + fun generateDispatchIn(factory: IEC61499Factory, stFactory: STFactory, inputVars: List, name: String = "", identifier: String = ""): FBTypeDeclaration { val bfb = factory.createBasicFBTypeDeclaration(null) bfb.name = "DISPATCH_IN_${name}" val startState = factory.createStateDeclaration(null) @@ -130,6 +135,7 @@ companion object { val inConnections = generateTypedConnections(factory, listOf(reqEvent), CONNECTION_TYPES) val nameDeclaration = generateParameterDeclaration(factory, "NAME", ElementaryType.STRING, listOf(reqEvent)) val mappingDeclaration = generateParameterDeclaration(factory, "MAPPING", ElementaryType.STRING, listOf(reqEvent)) + mappingDeclaration.initialValue = STConverter.parseLiteral(stFactory, identifier) bfb.inputParameters.addAll(inConnections) bfb.inputParameters.add(nameDeclaration) bfb.inputParameters.add(mappingDeclaration) @@ -244,9 +250,26 @@ companion object { return STConverter.parseExpression(stFactory, code)!! } - fun generateComposite(factory: IEC61499Factory, stFactory: STFactory, declaration: HMIInterfaceTypeDeclaration): CompositeFBTypeDeclaration { + fun getDeclarationName(name: String): String { + if (name.length < 5) { + return name + } + if (name.endsWith("_HMI")) { + return name.take(name.length - 4) + } + if (name.length < 9) { + return name + } + if (name.endsWith("_HMI_CONF")) { + return name.take(name.length - 9) + } + return name + } + + fun generateComposite(factory: IEC61499Factory, stFactory: STFactory, declaration: HMIInterfaceTypeDeclaration, identifier: String = ""): CompositeFBTypeDeclaration { var cFB = factory.createCompositeFBTypeDeclaration(null) - cFB.name = declaration.name + "_HMI" + val targetBlockName = getDeclarationName(declaration.name) + cFB.name = targetBlockName + "_HMI" declaration.inputParameters.forEach { if (it.name != "MAPPING") { val pD = factory.createParameterDeclaration(null) @@ -270,6 +293,7 @@ companion object { val mappingInput = factory.createParameterDeclaration(null) mappingInput.name = "MAPPING" mappingInput.type = ElementaryType.STRING + mappingInput.initialValue = STConverter.parseLiteral(stFactory, identifier) cFB.inputParameters.add(mappingInput) cFB.inputEvents.add(initEvent) @@ -278,7 +302,7 @@ companion object { cFB.network.functionBlocks.add(generateCommunicationBlock("PUBLISH_1", factory, stFactory)) cFB.network.functionBlocks.add(generateFunctionDeclarationNoParam("JSON_SERIALIZER", factory)) - cFB.network.functionBlocks.add(generateFunctionDeclarationNoParam("DISPATCH_OUT_${declaration.name}", factory)) + cFB.network.functionBlocks.add(generateFunctionDeclarationNoParam("DISPATCH_OUT_$targetBlockName", factory)) // EVENTS GENERATION @@ -298,7 +322,7 @@ companion object { cFB.inputEvents.add(event) val cEDispatch = factory.createFBNetworkConnection(EntryKind.EVENT) cEDispatch.sourceReference.setFQName(event.name) - cEDispatch.targetReference.setFQName("DISPATCH_OUT_${declaration.name}.${event.name}") + cEDispatch.targetReference.setFQName("DISPATCH_OUT_$targetBlockName.${event.name}") cFB.network.eventConnections.add(cEDispatch) } @@ -313,12 +337,12 @@ companion object { .forEach{ val cDDispatch = factory.createFBNetworkConnection(EntryKind.DATA) cDDispatch.sourceReference.setFQName(it.name) - cDDispatch.targetReference.setFQName("DISPATCH_OUT_${declaration.name}.${it.name}") + cDDispatch.targetReference.setFQName("DISPATCH_OUT_$targetBlockName.${it.name}") cFB.network.dataConnections.add(cDDispatch) } val cDNameSerialize = factory.createFBNetworkConnection(EntryKind.DATA) - cDNameSerialize.sourceReference.setFQName("DISPATCH_OUT_${declaration.name}.NAME") + cDNameSerialize.sourceReference.setFQName("DISPATCH_OUT_$targetBlockName.NAME") cDNameSerialize.targetReference.setFQName("JSON_SERIALIZER.NAME") cFB.network.dataConnections.add(cDNameSerialize) @@ -326,11 +350,11 @@ companion object { HMIInterfaceTypeGenerator.CONNECTION_TYPES.forEach { val cEDispatch = factory.createFBNetworkConnection(EntryKind.EVENT) - cEDispatch.sourceReference.setFQName("DISPATCH_OUT_${declaration.name}.IS_${it.name}") + cEDispatch.sourceReference.setFQName("DISPATCH_OUT_$targetBlockName.IS_${it.name}") cEDispatch.targetReference.setFQName("JSON_SERIALIZER.IS_${it.name}") cFB.network.eventConnections.add(cEDispatch) val cDDispatch = factory.createFBNetworkConnection(EntryKind.DATA) - cDDispatch.sourceReference.setFQName("DISPATCH_OUT_${declaration.name}.${it.name}_VALUE") + cDDispatch.sourceReference.setFQName("DISPATCH_OUT_$targetBlockName.${it.name}_VALUE") cDDispatch.targetReference.setFQName("JSON_SERIALIZER.${it.name}_VALUE") cFB.network.dataConnections.add(cDDispatch) } @@ -342,7 +366,7 @@ companion object { cFB.network.functionBlocks.add(generateCommunicationBlock("SUBSCRIBE_1", factory, stFactory, 65012)) cFB.network.functionBlocks.add(generateFunctionDeclarationNoParam("JSON_DESERIALIZER", factory)) - cFB.network.functionBlocks.add(generateFunctionDeclarationNoParam("DISPATCH_IN_${declaration.name}", factory)) + cFB.network.functionBlocks.add(generateFunctionDeclarationNoParam("DISPATCH_IN_$targetBlockName", factory)) // EVENTS GENERATION @@ -358,7 +382,7 @@ companion object { val cEDeserializeDispatch = factory.createFBNetworkConnection(EntryKind.EVENT) cEDeserializeDispatch.sourceReference.setFQName("JSON_DESERIALIZER.RES") - cEDeserializeDispatch.targetReference.setFQName("DISPATCH_IN_${declaration.name}.REQ") + cEDeserializeDispatch.targetReference.setFQName("DISPATCH_IN_$targetBlockName.REQ") cFB.network.eventConnections.add(cEDeserializeDispatch) declaration.outputParameters.forEach { @@ -366,7 +390,7 @@ companion object { cFB.outputEvents.add(event) val cEDispatchRes = factory.createFBNetworkConnection(EntryKind.EVENT) - cEDispatchRes.sourceReference.setFQName("DISPATCH_IN_${declaration.name}.${event.name}") + cEDispatchRes.sourceReference.setFQName("DISPATCH_IN_$targetBlockName.${event.name}") cEDispatchRes.targetReference.setFQName(event.name) cFB.network.eventConnections.add(cEDispatchRes) } @@ -380,17 +404,17 @@ companion object { val cDDeserializeName = factory.createFBNetworkConnection(EntryKind.DATA) cDDeserializeName.sourceReference.setFQName("JSON_DESERIALIZER.NAME") - cDDeserializeName.targetReference.setFQName("DISPATCH_IN_${declaration.name}.NAME") + cDDeserializeName.targetReference.setFQName("DISPATCH_IN_$targetBlockName.NAME") cFB.network.dataConnections.add(cDDeserializeName) val cDMappingDispatch = factory.createFBNetworkConnection(EntryKind.DATA) cDMappingDispatch.sourceReference.setFQName("MAPPING") - cDMappingDispatch.targetReference.setFQName("DISPATCH_IN_${declaration.name}.MAPPING") + cDMappingDispatch.targetReference.setFQName("DISPATCH_IN_$targetBlockName.MAPPING") cFB.network.dataConnections.add(cDMappingDispatch) declaration.outputParameters.forEach { val cEDispatchRes = factory.createFBNetworkConnection(EntryKind.DATA) - cEDispatchRes.sourceReference.setFQName("DISPATCH_IN_${declaration.name}.${it.name}") + cEDispatchRes.sourceReference.setFQName("DISPATCH_IN_$targetBlockName.${it.name}") cEDispatchRes.targetReference.setFQName(it.name) cFB.network.dataConnections.add(cEDispatchRes) } @@ -398,7 +422,7 @@ companion object { HMIInterfaceTypeGenerator.CONNECTION_TYPES.forEach { val cDDispatch = factory.createFBNetworkConnection(EntryKind.DATA) cDDispatch.sourceReference.setFQName("JSON_DESERIALIZER.${it.name}_VALUE") - cDDispatch.targetReference.setFQName("DISPATCH_IN_${declaration.name}.${it.name}_VALUE") + cDDispatch.targetReference.setFQName("DISPATCH_IN_$targetBlockName.${it.name}_VALUE") cFB.network.dataConnections.add(cDDispatch) } } diff --git a/code/platform/src/main/kotlin/org/fbme/ide/platform/persistence/Iec61499ModelFactory.kt b/code/platform/src/main/kotlin/org/fbme/ide/platform/persistence/Iec61499ModelFactory.kt index 933850c7c..3df6479dc 100644 --- a/code/platform/src/main/kotlin/org/fbme/ide/platform/persistence/Iec61499ModelFactory.kt +++ b/code/platform/src/main/kotlin/org/fbme/ide/platform/persistence/Iec61499ModelFactory.kt @@ -274,46 +274,50 @@ class Iec61499ModelFactory : ModelFactory, DataLocationAwareModelFactory { .getComponent(MPSCoreComponents::class.java).moduleRepository val platformRepository = PlatformRepository(repository) - val nodesToDelete = mutableListOf() - val dependents = mutableListOf() - for (rootNode in model.rootNodes) { - if (rootNode.getProperty(SNodeUtil.property_BaseConcept_virtualPackage).orEmpty().endsWith("_dependent")) { -// c.dropReference(it.link) - nodesToDelete.add(rootNode) - continue - } - val owner = PlatformElementsOwner() - val conf = PlatformConverter.STANDARD_CONFIG_FACTORY.createConfiguration(owner) - val declaration = platformRepository.getAdapter(rootNode, Declaration::class.java) - - val els = DependentDeclarationGenerator(declaration, conf).generate() - els.forEach { element -> - val node = (element as PlatformElement).node - node.setProperty(SNodeUtil.property_BaseConcept_virtualPackage, rootNode.getProperty(SNodeUtil.property_BaseConcept_virtualPackage).orEmpty() + ".${rootNode.name}_dependent") - dependents.add(node) - } - } - - LOG.info("Deleting nodes size: {}", nodesToDelete.size) - nodesToDelete.forEach { - model.enterUpdateMode() - model.removeRootNode(it) - it.delete() - model.leaveUpdateMode() - } - LOG.info("Dependents size: {}", dependents.size) - dependents.forEach { - model.enterUpdateMode() - model.addRootNode(it) - model.leaveUpdateMode() - } +// val nodesToDelete = mutableListOf() +// val dependents = mutableListOf() +// for (rootNode in model.rootNodes) { +// if (rootNode.getProperty(SNodeUtil.property_BaseConcept_virtualPackage).orEmpty().endsWith("_dependent")) { +//// c.dropReference(it.link) +// nodesToDelete.add(rootNode) +// continue +// } +// val owner = PlatformElementsOwner() +// val conf = PlatformConverter.STANDARD_CONFIG_FACTORY.createConfiguration(owner) +// val declaration = platformRepository.getAdapter(rootNode, Declaration::class.java) +// +// val dependentGenerator = DependentDeclarationGenerator(declaration, conf) +// val declarationName = dependentGenerator.getName() +// val els = dependentGenerator.generate() +// els.forEach { element -> +// val node = (element as PlatformElement).node +// node.setProperty(SNodeUtil.property_BaseConcept_virtualPackage, rootNode.getProperty(SNodeUtil.property_BaseConcept_virtualPackage).orEmpty() + ".${declarationName}_dependent") +// dependents.add(node) +// } +// } +// +// LOG.info("Deleting nodes size: {}", nodesToDelete.size) +// nodesToDelete.forEach { +// model.enterUpdateMode() +// model.removeRootNode(it) +// it.delete() +// model.leaveUpdateMode() +// } +// LOG.info("Dependents size: {}", dependents.size) +// dependents.forEach { +// model.enterUpdateMode() +// model.addRootNode(it) +// model.leaveUpdateMode() +// } val errors = arrayListOf() // Write nodes to xml files for (rootNode in model.rootNodes) { val document = try { + val conf = StandardIec61499ConverterConfiguration(platformRepository.iec61499Factory, platformRepository.stFactory) + val declaration = platformRepository.getAdapter(rootNode, Declaration::class.java) - RootDeclarationPrinter(declaration).print() + RootDeclarationPrinter(declaration, conf).print() } catch (e: Exception) { errors += PersistenceProblem(SModel.Problem.Kind.Save, e.message, rootNode.name, true) continue From 3b14a59c83040a2924bb4b38cc7df5c32c6ef665 Mon Sep 17 00:00:00 2001 From: "radimir.sorokin" Date: Fri, 26 Jan 2024 17:32:02 -0800 Subject: [PATCH 19/21] update build-bootstrap.xml --- build-bootstrap.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/build-bootstrap.xml b/build-bootstrap.xml index 4f552809e..2416f0bd9 100644 --- a/build-bootstrap.xml +++ b/build-bootstrap.xml @@ -148,6 +148,9 @@ + + + From b88804653545b02732fc55601d7eb6a46e97ba77 Mon Sep 17 00:00:00 2001 From: "radimir.sorokin" Date: Fri, 26 Jan 2024 17:38:45 -0800 Subject: [PATCH 20/21] Configure cat_visual's gradle.build.kts properly --- code/cat_visual/build.gradle.kts | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/code/cat_visual/build.gradle.kts b/code/cat_visual/build.gradle.kts index 7586c8f9e..c92353dac 100644 --- a/code/cat_visual/build.gradle.kts +++ b/code/cat_visual/build.gradle.kts @@ -1,9 +1,8 @@ -import org.jetbrains.compose.compose import org.jetbrains.compose.desktop.application.dsl.TargetFormat import org.jetbrains.kotlin.gradle.tasks.KotlinCompile plugins { - kotlin + kotlin("jvm") version "1.8.0" id("org.jetbrains.compose") version "1.3.1" kotlin("plugin.serialization") version "1.8.0" } @@ -38,12 +37,4 @@ compose.desktop { packageVersion = "1.0.0" } } -} -val compileKotlin: KotlinCompile by tasks -compileKotlin.kotlinOptions { - jvmTarget = "1.8" -} -val compileTestKotlin: KotlinCompile by tasks -compileTestKotlin.kotlinOptions { - jvmTarget = "1.8" } \ No newline at end of file From 3279ecdd432cd97655d10569936e620d639c1df4 Mon Sep 17 00:00:00 2001 From: "radimir.sorokin" Date: Fri, 26 Jan 2024 17:40:09 -0800 Subject: [PATCH 21/21] Update .idea files --- .idea/compiler.xml | 8 ++++++++ .idea/kotlinc.xml | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/.idea/compiler.xml b/.idea/compiler.xml index c8952aa4d..58d13c02c 100644 --- a/.idea/compiler.xml +++ b/.idea/compiler.xml @@ -1,6 +1,14 @@ + + + + + + + + diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml index 7e340a776..9a55c2de1 100644 --- a/.idea/kotlinc.xml +++ b/.idea/kotlinc.xml @@ -1,6 +1,6 @@ - \ No newline at end of file