lpcmanager

Merge of MC9 and MC10

2021-04-12, Edouard Tisserant
41a5e1a761ed
Merge of MC9 and MC10
  • +5 -1
    HostFirmwareUpdater.py
  • +24 -8
    LPCArch.py
  • +0 -16
    LPCBeremiz.py
  • +27 -18
    LPCBus.py
  • +8 -2
    LPCBus/GOT.h
  • +11 -10
    LPCBus/GOT100.h
  • +15 -3
    LPCBus/LHC2_GOT100.h
  • +9 -0
    LPCBus/MC10.h
  • +0 -35
    LPCBus/MC8.c
  • +0 -105
    LPCBus/MC9.c
  • +12 -8
    LPCBus/MC9.h
  • +0 -8
    LPCBus/MC9_Devices_cleanup.c
  • +0 -588
    LPCBus/MC9_Devices_decl.c
  • +0 -42
    LPCBus/MC9_Devices_init.c
  • +0 -19
    LPCBus/MC9_Devices_publish.c
  • +0 -19
    LPCBus/MC9_Devices_retrieve.c
  • +0 -17
    LPCBus/MC9_OnBoard_cleanup.c
  • +0 -170
    LPCBus/MC9_OnBoard_decl.c
  • +0 -55
    LPCBus/MC9_OnBoard_init.c
  • +0 -6
    LPCBus/MC9_OnBoard_publish.c
  • +0 -6
    LPCBus/MC9_OnBoard_retrieve.c
  • +0 -1
    LPCBus/MC9_Right_cleanup.c
  • +0 -12
    LPCBus/MC9_Right_decl.c
  • +0 -26
    LPCBus/MC9_Right_init.c
  • +0 -2
    LPCBus/MC9_Right_publish.c
  • +0 -2
    LPCBus/MC9_Right_retrieve.c
  • +105 -0
    LPCBus/SOM.c
  • +1 -0
    LPCBus/SOM28_Right_cleanup.c
  • +12 -0
    LPCBus/SOM28_Right_decl.c
  • +26 -0
    LPCBus/SOM28_Right_init.c
  • +2 -0
    LPCBus/SOM28_Right_publish.c
  • +2 -0
    LPCBus/SOM28_Right_retrieve.c
  • +8 -0
    LPCBus/SOM_Devices_cleanup.c
  • +588 -0
    LPCBus/SOM_Devices_decl.c
  • +38 -0
    LPCBus/SOM_Devices_init.c
  • +19 -0
    LPCBus/SOM_Devices_publish.c
  • +19 -0
    LPCBus/SOM_Devices_retrieve.c
  • +17 -0
    LPCBus/SOM_OnBoard_cleanup.c
  • +170 -0
    LPCBus/SOM_OnBoard_decl.c
  • +53 -0
    LPCBus/SOM_OnBoard_init.c
  • +6 -0
    LPCBus/SOM_OnBoard_publish.c
  • +6 -0
    LPCBus/SOM_OnBoard_retrieve.c
  • +35 -0
    LPCBus/uC.c
  • +50 -19
    LPCExtension.py
  • +2 -2
    LPCManager.py
  • +4 -1
    LPCModbus.py
  • +24 -2
    LPCProjectController.py
  • +20 -0
    LPCSVGHMI.py
  • +43 -0
    OnChangeFromOptions.py
  • +82 -0
    OptionsParsing.py
  • +9 -0
    SOM6Target/XSD.template
  • +328 -0
    SOM6Target/plc_SOM6_main_retain.c
  • +0 -167
    VariableExporter.py
  • +90 -143
    WampOptionsEditor.py
  • +0 -0
    images/ALARM.png
  • +17 -0
    images/genicons.sh
  • +127 -0
    images/icons.svg
  • --- a/HostFirmwareUpdater.py Wed Jul 29 10:52:37 2020 +0200
    +++ b/HostFirmwareUpdater.py Mon Apr 12 10:01:38 2021 +0200
    @@ -34,6 +34,8 @@
    import os
    import hashlib
    +from LPCArch import GetLPCArch
    +
    UPDATE_SCRIPT_TIMEOUT = 600
    class HostFirmwareUpdater(object):
    @@ -65,7 +67,9 @@
    self._CreateFirmwareImageFileSizeMD5File()
    self._CreateFirmwareImageFileMD5File()
    # start the update script
    - status, textError = self.controller._connector.RunUpdateScript(self.updateType)
    + product_name = GetLPCArch()
    + updateFlashTypeArg = "mmc" if product_name == "MC10" else "ubi"
    + status, textError = self.controller._connector.RunUpdateScript(self.updateType, updateFlashTypeArg)
    if not status :
    raise Exception(textError)
    # The update script is now running: Feeding the update script with firmware image data
    --- a/LPCArch.py Wed Jul 29 10:52:37 2020 +0200
    +++ b/LPCArch.py Mon Apr 12 10:01:38 2021 +0200
    @@ -1,15 +1,31 @@
    #!/usr/bin/env python
    # XXX Where is MC8 ?
    -PLC_GOT_modules = ['GOT', 'GOT_111', 'GOT_131', 'LHC2_GOT_111']
    -PLC_MC9_modules = ['MC9', 'MW1']
    -SOM28_modules = PLC_MC9_modules + PLC_GOT_modules
    +WX_GOT_modules = ['GOT', 'GOT_111', 'GOT_131', 'LHC2_GOT_111']
    +SVG_GOT_modules = ['GOT_012']
    +MC9_modules = ['MC9', 'MW1']
    +SOM28_modules = MC9_modules + WX_GOT_modules
    +SOM6_modules = SVG_GOT_modules
    +
    +product = None
    -arch = None
    +def SetLPCProduct(given):
    + global product
    + product = given
    -def SetLPCArch(given):
    - global arch
    - arch = given
    +def GetLPCProduct():
    + return product
    +
    +def GetLPCSOM():
    + if product in SOM28_modules:
    + return "SOM28"
    + if product in SOM6_modules:
    + return "SOM6"
    def GetLPCArch():
    - return arch
    + if product in SOM28_modules:
    + return "MC9"
    + elif product in SOM6_modules:
    + return "MC10"
    + elif product is "MC8" :
    + return "MC8"
    --- a/LPCBeremiz.py Wed Jul 29 10:52:37 2020 +0200
    +++ b/LPCBeremiz.py Mon Apr 12 10:01:38 2021 +0200
    @@ -3,7 +3,6 @@
    from __future__ import absolute_import
    import wx
    from BeremizIDE import *
    -from VariableExporter import VariableWriter
    # XXX TODO : strip dead code. document.
    @@ -16,15 +15,6 @@
    class LPCBeremiz(Beremiz):
    def _init_coll_FileMenu_Items(self, parent):
    - config = wx.ConfigBase.Get()
    - export = str(config.Read("Exporter"))
    - if export == "":
    - config.Write("Exporter", '0')
    - export = '0'
    - if export == '1':
    - export = True
    - else:
    - export = False
    AppendMenu(parent, help='', id=wx.ID_SAVE,
    kind=wx.ITEM_NORMAL, text=_(u'Save\tCTRL+S'))
    AppendMenu(parent, help='', id=wx.ID_CLOSE,
    @@ -37,10 +27,6 @@
    AppendMenu(parent, help='', id=wx.ID_PRINT,
    kind=wx.ITEM_NORMAL, text=_(u'Print'))
    parent.AppendSeparator()
    - if export:
    - AppendMenu(parent, help='', id=ID_EXPORT,
    - kind=wx.ITEM_NORMAL, text=_(u'Export'))
    - parent.AppendSeparator()
    AppendMenu(parent, help='', id=wx.ID_EXIT,
    kind=wx.ITEM_NORMAL, text=_(u'Quit\tCTRL+Q'))
    @@ -49,8 +35,6 @@
    self.Bind(wx.EVT_MENU, self.OnPageSetupMenu, id=wx.ID_PAGE_SETUP)
    self.Bind(wx.EVT_MENU, self.OnPreviewMenu, id=wx.ID_PREVIEW)
    self.Bind(wx.EVT_MENU, self.OnPrintMenu, id=wx.ID_PRINT)
    - if export:
    - self.Bind(wx.EVT_MENU, lambda event: VariableWriter(self, event, self.CTR.ProjectPath), id=ID_EXPORT)
    self.Bind(wx.EVT_MENU, self.OnQuitMenu, id=wx.ID_EXIT)
    self.AddToMenuToolBar([(wx.ID_SAVE, "save", _(u'Save'), None),
    --- a/LPCBus.py Wed Jul 29 10:52:37 2020 +0200
    +++ b/LPCBus.py Mon Apr 12 10:01:38 2021 +0200
    @@ -3,22 +3,27 @@
    modpath = os.path.split(__file__)[0]
    -from LPCArch import GetLPCArch, SOM28_modules
    +from LPCArch import GetLPCArch, GetLPCProduct, SOM28_modules
    +
    +product = GetLPCProduct()
    arch = GetLPCArch()
    -if arch in SOM28_modules:
    - bus_template_name = "MC9"
    -else:
    - bus_template_name = arch
    -
    LPCBusSourcePath = os.path.join(modpath,"LPCBus")
    def GetLocalCode(fname):
    return open(os.path.join(LPCBusSourcePath,fname)).read()
    -Busses = [ "Right", "On Board", "Devices" ]
    +# busses available per architecture
    +Busses = {"MC8" :[ ("Right", "uC_Right"),
    + ("On Board", "uC_OnBoard"),
    + ("Devices", "uC_Devices")],
    + "MC9" :[ ("Right", "SOM28_Right"),
    + ("On Board", "SOM_OnBoard"),
    + ("Devices", "SOM_Devices")],
    + "MC10" :[("On Board", "SOM_OnBoard"),
    + ("Devices", "SOM_Devices")]}
    -# This matches names of .h files in LPCBus with Arch from LPCArch
    +# This matches names of .h files in LPCBus with product from LPCArch
    headernames = {
    "MC9":"MC9",
    "MW1":"MC9",
    @@ -26,9 +31,13 @@
    "GOT_131":"GOT100",
    "GOT_111":"GOT100",
    "LHC2_GOT_111":"LHC2_GOT100"
    + "GOT_012":"MC10"
    }
    -bus_template_code = { plc:GetLocalCode(plc+".c") for plc in ["MC8", "MC9"] }
    +bus_template_code = { plc: GetLocalCode(
    + {"MC8": "uC",
    + "MC9": "SOM",
    + "MC10": "SOM"}[plc]+".c") for plc in Busses.keys()}
    # This is in case some bus has some special LDFLAGS
    @@ -224,16 +233,16 @@
    "publish_code": "",
    }
    - bus_code = { "MC9:%s"%bus :
    + bus_code = { "%s:%s"%(arch, bus_name) :
    { section :
    - header + GetLocalCode("%s_%s_%s.c"%("MC9",''.join(bus.split()),section))
    + header + GetLocalCode("%s_%s.c"%(bus_template,section))
    for section, header in [
    - ("decl",GetLocalCode("%s.h" % headernames[arch])),
    + ("decl",GetLocalCode("%s.h" % headernames[product])),
    ("init", ""),
    ("retrieve", ""),
    ("publish", ""),
    ("cleanup", "")]}
    - for bus in Busses}
    + for bus_name, bus_template in Busses[arch]}
    for module in GetModuleChildren(self):
    if module["init"] != "":
    @@ -280,7 +289,7 @@
    if var["Publish"] != "":
    code_str["publish_code"] += " " + var["Publish"] % ("*" + var["location"]) + "\n"
    - BusName = bus_template_name + ":" + self.BaseParams.getName()
    + BusName = arch + ":" + self.BaseParams.getName()
    def bcode(section):
    @@ -298,12 +307,12 @@
    "bus_publish_code": bcode("publish"),
    })
    - if bus_template_name not in bus_template_code:
    - raise Exception, "Unknown arch %s. Please use %s"%(
    - bus_template_name,repr(bus_template_code.keys()))
    + if arch not in bus_template_code:
    + raise Exception, "Unknown product %s. Please use %s"%(
    + arch,repr(bus_template_code.keys()))
    Gen_Module_path = os.path.join(buildpath, "Bus_%s.c"%location_str)
    module = open(Gen_Module_path,'w')
    - module.write(bus_template_code[bus_template_name] % code_str)
    + module.write(bus_template_code[arch] % code_str)
    module.close()
    cflags = '"-I%s" "-I%s" -Wno-unused-function'%(
    --- a/LPCBus/GOT.h Wed Jul 29 10:52:37 2020 +0200
    +++ b/LPCBus/GOT.h Mon Apr 12 10:01:38 2021 +0200
    @@ -1,3 +1,9 @@
    -#ifndef RUN_LED_GPIO_1_31
    -#define RUN_LED_GPIO_1_31
    +#ifndef GOT_H
    +#define GOT_H
    +
    +// GPIO_1_31 = 32 + 31 = 63
    +#define RUN_LED_GPIO 63
    +
    +#define LPCBUS_DEVICES_PORT "/dev/ttyAPP1"
    +
    #endif
    --- a/LPCBus/GOT100.h Wed Jul 29 10:52:37 2020 +0200
    +++ b/LPCBus/GOT100.h Mon Apr 12 10:01:38 2021 +0200
    @@ -1,15 +1,16 @@
    -#ifndef RUN_LED_GPIO_1_31
    -#define RUN_LED_GPIO_1_31
    -#endif
    +#ifndef GOT100_H
    +#define GOT100_H
    -#ifndef CAN0_EN_GPIO_0_21
    -#define CAN0_EN_GPIO_0_21
    -#endif
    +// GPIO_1_31 = 32 + 31 = 63
    +#define RUN_LED_GPIO 63
    -#ifndef CAN1_EN_GPIO_0_17
    -#define CAN1_EN_GPIO_0_17
    -#endif
    +// GPIO_0_21
    +#define CAN0_EN_GPIO 21
    -#ifndef ONBOARD_I2C
    +// GPIO_0_17
    +#define CAN1_EN_GPIO 17
    +
    #define ONBOARD_I2C
    +
    +#define LPCBUS_DEVICES_PORT "/dev/ttyAPP1"
    #endif
    --- a/LPCBus/LHC2_GOT100.h Wed Jul 29 10:52:37 2020 +0200
    +++ b/LPCBus/LHC2_GOT100.h Mon Apr 12 10:01:38 2021 +0200
    @@ -1,7 +1,19 @@
    -#include "GOT100.h"
    +#ifndef GOT100_H
    +#define GOT100_H
    +
    +// GPIO_1_31 = 32 + 31 = 63
    +#define RUN_LED_GPIO 63
    -#ifndef GOT100_SMT_BUS
    -#define GOT100_SMT_BUS
    +// GPIO_0_21
    +#define CAN0_EN_GPIO 21
    +
    +// GPIO_0_17
    +#define CAN1_EN_GPIO 17
    +
    +#define ONBOARD_I2C
    +
    +#define LPCBUS_DEVICES_PORT "/dev/ttyAPP3"
    +
    #endif
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/LPCBus/MC10.h Mon Apr 12 10:01:38 2021 +0200
    @@ -0,0 +1,9 @@
    +#ifndef MC10_H
    +#define MC10_H
    +
    +// GPIO_0_0 = 0 + 0 = 0
    +#define RUN_LED_GPIO 0
    +
    +#define LPCBUS_DEVICES_PORT "/dev/ttymxc2"
    +
    +#endif
    --- a/LPCBus/MC8.c Wed Jul 29 10:52:37 2020 +0200
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,35 +0,0 @@
    -/* Code generated by LPCBus confnode */
    -
    -/* LPCBus confnode includes */
    -#include "app_glue.h"
    -#ifdef _WINDOWS_H
    - #include "iec_types.h"
    -#else
    - #include "iec_std_lib.h"
    -#endif
    -
    -%(declare_code)s
    -
    -/* LPCBus confnode user variables definition */
    -%(var_decl)s
    -
    -/* LPCBus confnode functions */
    -int __init_%(location_str)s(int argc,char **argv)
    -{
    -%(init_code)s
    - return 0;
    -}
    -
    -void __cleanup_%(location_str)s(void)
    -{
    -}
    -
    -void __retrieve_%(location_str)s(void)
    -{
    -%(retrieve_code)s
    -}
    -
    -void __publish_%(location_str)s(void)
    -{
    -%(publish_code)s
    -}
    --- a/LPCBus/MC9.c Wed Jul 29 10:52:37 2020 +0200
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,105 +0,0 @@
    -
    -/* Code generated by LPCBus confnode */
    -
    -#ifdef _WINDOWS_H
    - #include "iec_types.h"
    -#else
    - #include "iec_std_lib.h"
    -#endif
    -
    -static inline int16_t getWord(char *buffer)
    -{
    - return ((int16_t)*buffer<<8) + (int16_t)*(buffer+1);
    -}
    -
    -static inline int16_t getWordSwapped(char *buffer)
    -{
    - return (((int16_t)*(buffer+1))<<8) + (int16_t)*buffer;
    -}
    -
    -static inline void setWord(char *buffer, int16_t word)
    -{
    - *buffer = (char)(word>>8);
    - *(buffer+1) = (char)(word);
    -}
    -
    -static inline void setWordSwapped(char *buffer, int16_t word)
    -{
    - *buffer = (char)word;
    - *(buffer+1) = (char)(word>>8);
    -}
    -
    -static inline int8_t getBit(char *buffer, unsigned char bitOffset)
    -{
    - return (*buffer & (0x01 << bitOffset)) && 1;
    -}
    -
    -static inline void setBit(char *buffer, unsigned char bitOffset, int8_t bit)
    -{
    - unsigned char msk = (0x01 << bitOffset);
    - if(bit)
    - *buffer |= msk;
    - else
    - *buffer &= ~msk;
    -}
    -
    -static void setWord16(short *buffer, uint16_t word)
    -{
    - *buffer = (short)word;
    -}
    -
    -static int16_t getWord16(short *buffer)
    -{
    - return((uint16_t)*buffer);
    -}
    -
    -static inline unsigned char getByte(char *buffer)
    -{
    - return((unsigned char)*buffer);
    -}
    -
    -static inline void setByte(char *buffer, unsigned char byte)
    -{
    - *buffer = byte;
    -}
    -
    -typedef struct
    -{
    - unsigned char status; /* Current status of timer - running / expired */
    - uint64_t actValue; /* Actual timer value */
    - uint64_t toValue; /* Timeout value - initialized at startup */
    - uint64_t oldTime; /* Time at previous timer increment; NOTE: if RTIME (unsigned long long) changes type, oldTime has to be adapted */
    -} commTimer;
    -
    -#define TIM_DISABLED 0
    -#define TIM_EN_RUNNING 1
    -#define TIM_EN_EXPIRED 2
    -
    -%(bus_decl)s
    -
    -%(declare_code)s
    -
    -/* LPCBus confnode user variables definition */
    -%(var_decl)s
    -
    -/* LPCBus confnode functions */
    -int __init_%(location_str)s(int argc,char **argv)
    -{
    - %(bus_init_code)s
    - return 0;
    -}
    -
    -void __cleanup_%(location_str)s(void)
    -{
    - %(bus_cleanup_code)s
    -}
    -
    -void __retrieve_%(location_str)s(void)
    -{
    -%(bus_retrieve_code)s
    -}
    -
    -void __publish_%(location_str)s(void)
    -{
    -%(bus_publish_code)s
    -}
    --- a/LPCBus/MC9.h Wed Jul 29 10:52:37 2020 +0200
    +++ b/LPCBus/MC9.h Mon Apr 12 10:01:38 2021 +0200
    @@ -1,11 +1,15 @@
    -#ifndef RUN_LED_GPIO_1_13
    -#define RUN_LED_GPIO_1_13
    -#endif
    +#ifndef MC9_H
    +#define MC9_H
    +
    +// GPIO_1_13 = 32 + 13 = 45
    +#define RUN_LED_GPIO 45
    -#ifndef CAN0_EN_GPIO_0_21
    -#define CAN0_EN_GPIO_0_21
    -#endif
    +// GPIO_0_21
    +#define CAN0_EN_GPIO 21
    -#ifndef CAN1_EN_GPIO_0_17
    -#define CAN1_EN_GPIO_0_17
    +// GPIO_0_17
    +#define CAN1_EN_GPIO 17
    +
    +#define LPCBUS_DEVICES_PORT "/dev/ttyAPP1"
    +
    #endif
    --- a/LPCBus/MC9_Devices_cleanup.c Wed Jul 29 10:52:37 2020 +0200
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,8 +0,0 @@
    -
    -pthread_mutex_lock(&UART_WakeCondLock);
    -
    -UART_task_active = 0;
    -pthread_cond_signal(&UART_WakeCond);
    -pthread_mutex_unlock(&UART_WakeCondLock);
    -pthread_join(UART_task, NULL);
    -closeserial(UART_fd);
    --- a/LPCBus/MC9_Devices_decl.c Wed Jul 29 10:52:37 2020 +0200
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,588 +0,0 @@
    -#include <stdio.h>
    -#include <termios.h>
    -#include <unistd.h>
    -#include <sys/ioctl.h>
    -#include <fcntl.h>
    -#include <sys/select.h>
    -
    -#include <alchemy/task.h>
    -#include <alchemy/mutex.h>
    -#include <alchemy/timer.h>
    -
    -#include "beremiz.h"
    -
    -static struct termios oldterminfo;
    -
    -void closeserial(int fd)
    -{
    - tcsetattr(fd, TCSANOW, &oldterminfo);
    - if (close(fd) < 0)
    - perror("closeserial()");
    -}
    -
    -/*--------------------------- Serial Port handling ---------------------------*/
    -
    -int openserial(char *devicename, unsigned long baudrate)
    -{
    - int fd;
    - struct termios attr;
    - speed_t baud = B115200; /* baud rate */
    -
    - switch(baudrate)
    - {
    - case 19200:
    - baud = B19200;
    - break;
    - case 115200:
    - baud = B115200;
    - break;
    - default:
    - baud = B115200;
    - }
    -
    - if ((fd = open(devicename, O_RDWR)) == -1) {
    - perror("openserial(): open()");
    - return 0;
    - }
    - if (tcgetattr(fd, &oldterminfo) == -1) {
    - perror("openserial(): tcgetattr()");
    - return 0;
    - }
    - attr = oldterminfo;
    - attr.c_oflag = 0;
    - attr.c_iflag = 0;
    - attr.c_lflag = 0;
    -
    - attr.c_cflag = 0;
    - attr.c_cflag |= CREAD;
    - attr.c_cflag |= CLOCAL;
    - attr.c_cflag |= CS8 ; /* 8 bits */
    - /* no parity, 1 stop bit */
    -
    - cfsetspeed(&attr, baud); /* baud rate */
    -
    - if (tcflush(fd, TCIOFLUSH) == -1) {
    - perror("openserial(): tcflush()");
    - return 0;
    - }
    - if (tcsetattr(fd, TCSANOW, &attr) == -1) {
    - perror("initserial(): tcsetattr()");
    - return 0;
    - }
    -
    - return fd;
    -}
    -
    -
    -#define EMPTY 0
    -#define LOCKED 1
    -#define FULL 2
    -
    -#define MAX_UART_DEVICES 32
    -#define UART_BUFSIZE_SHORT 26 /* UART bus read & write buffer size - short buffer for LPC-2 */
    -#define UART_BUFSIZE_LONG 48 /* UART bus read & write buffer size - long buffer for LHC-2 */
    -#define UART_RETRY_NUM 0
    -
    -char uartBufSize = UART_BUFSIZE_SHORT; /* Smarteh uart bus: buffer size */
    -unsigned long uartBaudrate = 19200; /* Smarteh uart bus: baudrate */
    -struct timeval uartTimeout = {0,40000}; /* Smarteh uart bus: timeout */
    -
    -/* Tables containing information about connected devices on UART port
    - (initialized by Composer) */
    -unsigned char uartDev[MAX_UART_DEVICES][2];
    -unsigned char uartDevNum = MAX_UART_DEVICES;
    -
    -/* Buffers for reading data from UART port devices */
    -typedef char uartDevReadBuf_t[MAX_UART_DEVICES][UART_BUFSIZE_LONG];
    -uartDevReadBuf_t uartDevReadBufA;
    -uartDevReadBuf_t uartDevReadBufB;
    -uartDevReadBuf_t *uartDevReadBuf_drv;
    -uartDevReadBuf_t *uartDevReadBuf_plc;
    -/* MC8 compatibility */
    -uartDevReadBuf_t uartDevReadBuf;
    -
    -/* Buffers for writing data to UART port devices */
    -typedef char uartDevWriteBuf_t[MAX_UART_DEVICES][UART_BUFSIZE_LONG];
    -uartDevWriteBuf_t uartDevWriteBufA;
    -uartDevWriteBuf_t uartDevWriteBufB;
    -uartDevWriteBuf_t *uartDevWriteBuf_drv;
    -uartDevWriteBuf_t *uartDevWriteBuf_plc;
    -/* MC8 compatibility */
    -#define uartDevWriteBuf (*uartDevWriteBuf_drv)
    -
    -int uartDevWriteBuf_plc_state;
    -int uartDevReadBuf_plc_state;
    -
    -/* Buffers for communication statuses with UART port devices */
    -/* 2D arrays due to compatibility with Composer (LpcSmartehIDE) */
    -char uartCommErrCntBuf [MAX_UART_DEVICES][1];
    -char uartCommStatusBuf[MAX_UART_DEVICES][1];
    -
    -/* Function interface definition for modules on UART (RS485) bus */
    -typedef unsigned char (*uartPortFunct)(char*, char*, char);
    -/* Table describing module positions on UART (RS485) bus (parsed from Composer data) */
    -uartPortFunct uartPortDevices[MAX_UART_DEVICES] = {NULL};
    -/* Table of timers (one for each position) */
    -static commTimer uartPortTim[MAX_UART_DEVICES];
    -
    -static pthread_t UART_task;
    -static pthread_mutex_t UART_WriteMutex = PTHREAD_MUTEX_INITIALIZER;
    -static pthread_mutex_t UART_ReadMutex = PTHREAD_MUTEX_INITIALIZER;
    -static pthread_mutex_t UART_WakeCondLock = PTHREAD_MUTEX_INITIALIZER;
    -static pthread_cond_t UART_WakeCond = PTHREAD_COND_INITIALIZER;
    -static int UART_WakeCondValue = 0;
    -static int UART_task_active;
    -
    -void* UART_task_proc(void *arg)
    -{
    - static unsigned char i=0;
    - char commStat;
    - uint64_t actTime;
    - static uint64_t lastCommTime=0;
    -
    - struct sched_param param = { .sched_priority = 10 };
    - pthread_setname_np(pthread_self(), "UART_task");
    - pthread_setschedparam(pthread_self(), SCHED_FIFO, &param);
    -
    - while (1){
    - int active;
    - pthread_mutex_lock(&UART_WakeCondLock);
    - active = UART_task_active;
    - while(!UART_WakeCondValue && active){
    - pthread_cond_wait(&UART_WakeCond, &UART_WakeCondLock);
    - active = UART_task_active;
    - }
    -
    - UART_WakeCondValue = 0;
    - pthread_mutex_unlock(&UART_WakeCondLock);
    -
    - if(!active)
    - break;
    -
    - // Communicate only with initialised UART devices
    - if(uartPortDevices[i] != NULL)
    - {
    -
    - // Timers for UART port modules
    - if(uartPortTim[i].status != TIM_DISABLED)
    - {
    - struct timespec time_ref;
    - if(clock_gettime(CLOCK_MONOTONIC, &time_ref)){
    - perror("clock_gettime(time_ref)");
    - }
    - actTime = time_ref.tv_nsec + time_ref.tv_sec * 1000000000LL;
    - uartPortTim[i].actValue = actTime - uartPortTim[i].oldTime;
    -
    - if((uartPortTim[i].actValue < uartPortTim[i].toValue)
    - || (actTime - lastCommTime < 50000000))
    - uartPortTim[i].status = TIM_EN_RUNNING;
    - else {
    - uartPortTim[i].status = TIM_EN_EXPIRED;
    - uartPortTim[i].oldTime = actTime;
    - lastCommTime = actTime;
    - }
    - }
    -
    - // Check timer status
    - if((uartPortTim[i].status == TIM_DISABLED)
    - || (uartPortTim[i].status == TIM_EN_EXPIRED))
    - {
    - if(!pthread_mutex_lock(&UART_WriteMutex)){
    - if(uartDevWriteBuf_plc_state == FULL){
    - uartDevWriteBuf_t *uartDevWriteBuf_tmp;
    - uartDevWriteBuf_tmp = uartDevWriteBuf_plc;
    - uartDevWriteBuf_plc = uartDevWriteBuf_drv;
    - uartDevWriteBuf_drv = uartDevWriteBuf_tmp;
    - uartDevWriteBuf_plc_state = EMPTY;
    - }
    - pthread_mutex_unlock(&UART_WriteMutex);
    - }
    -
    - // Communicate with device
    - commStat = (*uartPortDevices[i])(
    - &uartDevReadBuf[i][0],
    - &uartDevWriteBuf[i][0],
    - uartDev[i][1]);
    -
    - memcpy(uartDevReadBuf_drv, &uartDevReadBuf, sizeof(uartDevReadBuf_t));
    -
    - if(!pthread_mutex_lock(&UART_ReadMutex)){
    - if(uartDevReadBuf_plc_state == EMPTY){
    - uartDevReadBuf_t *uartDevReadBuf_tmp;
    - uartDevReadBuf_tmp = uartDevReadBuf_plc;
    - uartDevReadBuf_plc = uartDevReadBuf_drv;
    - uartDevReadBuf_drv = uartDevReadBuf_tmp;
    - uartDevReadBuf_plc_state = FULL;
    - }
    - pthread_mutex_unlock(&UART_ReadMutex);
    - }
    -
    - // Check communication status:
    - if(commStat == TRUE)
    - {
    - uartCommStatusBuf[i][0] = TRUE;
    - uartCommErrCntBuf[i][0] = 0;
    - }
    - else
    - {
    - if(uartCommErrCntBuf[i][0] < UART_RETRY_NUM)
    - uartCommErrCntBuf[i][0]++;
    - else
    - uartCommStatusBuf[i][0] = FALSE;
    - }
    -
    - // If timer is enabled, reset it's value,
    - // otherwise keep it disabled
    - if(uartPortTim[i].status != TIM_DISABLED)
    - {
    - uartPortTim[i].actValue = 0;
    - uartPortTim[i].status = TIM_EN_RUNNING;
    - }
    - else /* Keep timer disabled */
    - uartPortTim[i].status = TIM_DISABLED;
    -
    - // Procede with next UART device only after
    - // communication with the current one is done
    - if(i < (uartDevNum-1))
    - i++;
    - else /* Go back to the first UART device */
    - i=0;
    - }
    - }
    - else i=0;
    - }
    - return NULL;
    -}
    -
    -#define TAIL_LEN 3 /* Length of data tail in bytes */
    -/**************************************************************************//**
    -* Calculate checksum of a buffer
    -* @param [in] buffer Pointer to buffer
    -* @param [in] bufLen Buffer length
    -* @return Checksum values on buffer locations bufLen-TAIL_LEN &
    -* bufLen-TAIL_LEN+1
    -******************************************************************************/
    -void Checksum(unsigned char *buffer, unsigned char bufLen)
    -{
    - unsigned char i=0, j=0;
    - unsigned char checksum1=0, checksum2=0;
    - unsigned char checksum1Temp=0;
    -
    - for(i=0;i<bufLen-TAIL_LEN;i++)
    - {
    - checksum1Temp=buffer[i];
    - for(j=0;j<8;j++) /* Compute number of '1' of whole buff. */
    - {
    - if((checksum1Temp & 0x01)>0)
    - checksum1++;
    - checksum1Temp = checksum1Temp >> 1;
    - }
    - checksum2 = checksum2 ^ buffer[i]; /* Compute XOR of whole buffer */
    - }
    -
    - buffer[bufLen-TAIL_LEN] = checksum2; /* Write number of '1' to buffer */
    - buffer[bufLen-TAIL_LEN+1] = checksum1; /* Write XOR to buffer */
    -}
    -
    -/**************************************************************************//**
    -* Check if checksum values of received buffer are valid
    -* @param [in] buffer Pointer to buffer
    -* @param [in] bufLen Buffer length
    -* @return TRUE if valid, otherwise FALSE
    -******************************************************************************/
    -unsigned char ChecksumValid(unsigned char *buffer, unsigned char bufLen)
    -{
    - unsigned char i=0, j=0;
    - unsigned char checksum1=0, checksum2=0;
    - unsigned char checksum1Temp=0;
    -
    - for(i=0;i<bufLen-TAIL_LEN;i++)
    - {
    - checksum1Temp = buffer[i];
    - for(j=0;j<8;j++) /* Compute number of '1' of whole buff. */
    - {
    - if((checksum1Temp & 0x01)>0)
    - checksum1++;
    - checksum1Temp = checksum1Temp >> 1; /* Compute XOR of whole buffer */
    - }
    - checksum2 = checksum2 ^ buffer[i];
    - }
    -
    - /* Check if computed checksums are the same as those in buffer (=> no error) */
    - if((checksum2==buffer[bufLen-TAIL_LEN]) && (checksum1==buffer[bufLen-TAIL_LEN+1]))
    - return TRUE;
    - else
    - return FALSE;
    -}
    -
    -static int UART_fd;
    -/*************************************************************************//**
    -* Support for UART modules
    -* @param [in] readBuf Pointer to read buffer (for previously polled UART device!)
    -* @param [out] writeBuf Pointer to write buffer (for current device)
    -* @param [in] address UART device address
    -* @return TRUE if communication was successful, otherwise FALSE
    -*****************************************************************************/
    -unsigned char UARTDevice(char* readBuf, char* writeBuf, char address)
    -{
    - fd_set set;
    - struct timeval timeout;
    - int rv;
    - int count = 0;
    - char tmp[uartBufSize];
    -
    - /* Prepare transmit buffer */
    - memcpy(tmp+1,writeBuf,uartBufSize-TAIL_LEN-1);
    - tmp[0] = 'S';
    - tmp[uartBufSize-TAIL_LEN] = address;
    - Checksum((unsigned char*)tmp+1, uartBufSize);
    -
    - tcflush(UART_fd, TCIOFLUSH);
    -
    - if(write(UART_fd, tmp, uartBufSize) != uartBufSize){
    - goto UARTDevfail;
    - }
    -
    - FD_ZERO(&set); /* clear the set */
    - FD_SET(UART_fd, &set); /* add our file descriptor to the set */
    -
    - timeout.tv_sec = uartTimeout.tv_sec;
    - timeout.tv_usec = uartTimeout.tv_usec;
    -
    - while(count < uartBufSize){
    - rv = select(UART_fd + 1, &set, NULL, NULL, &timeout);
    - if(rv == -1)
    - printf("RS485 select error\n");
    - else if(rv == 0)
    - {
    - //printf("timeout\n");
    - break;
    - }
    - else {
    - int rr = read(UART_fd, tmp + count, uartBufSize - count);
    - if(rr > 0){
    - count += rr;
    - }else{
    - printf("RS485 read error %%d\n",rr);
    - }
    - }
    - }
    -
    - /* Copy received buffer */
    - if((count == uartBufSize) && (tmp[uartBufSize-TAIL_LEN] == address)){
    - if(ChecksumValid((unsigned char*)tmp+1, uartBufSize)){
    - memcpy(readBuf,tmp+1,uartBufSize-TAIL_LEN-1);
    - return(TRUE);
    - }
    - }
    -
    - UARTDevfail:
    - tcflush(UART_fd, TCIOFLUSH);
    - return(FALSE);
    -}
    -
    -/* Macro to transform milliseconds to ns */
    -#define msTOns(ms) (1000000L*ms)
    -
    -void InitUartPortDevices_longBuffer(void)
    -{
    - unsigned char i=0;
    -
    - uartTimeout.tv_sec = 0;
    - uartTimeout.tv_usec = 20000; /* 20 ms timeout */
    -
    - for(i=0;i<MAX_UART_DEVICES;i++)
    - {
    - switch(uartDev[i][1])
    - {
    - case(2): /* MU1 */
    - case(4):
    - case(6):
    - case(8):
    - case(10):
    - case(12):
    - case(14):
    - case(16):
    - case(18):
    - case(20):
    - case(22):
    - case(24):
    - case(26):
    - case(28):
    - case(30):
    - case(32):
    - case(34):
    - case(36):
    - case(38):
    - case(40):
    - case(42):
    - case(44):
    - case(46):
    - case(48):
    - case(66): /* MU2 */
    - case(68):
    - case(70):
    - case(72):
    - case(74): /* MU3 */
    - case(76):
    - case(78):
    - case(80):
    - case(82): /* MU4 */
    - case(84):
    - case(86):
    - case(88):
    - case(90): /* MU5 */
    - case(92):
    - case(94):
    - case(96):
    - case(98): /* MU6 */
    - case(100):
    - case(102):
    - case(104):
    - case(106): /* M4U */
    - case(108):
    - case(110):
    - case(112):
    - case(114): /* TH1 */
    - case(116):
    - case(118):
    - case(120):
    - case(122):
    - case(124):
    - case(126):
    - case(128):
    - case(130):
    - case(132):
    - case(134):
    - case(136):
    - case(138): /* MU7 */
    - case(140):
    - case(142):
    - case(144):
    - case(146): /* MU8 */
    - case(148):
    - case(150):
    - case(152):
    - case(154): /* MU9 */
    - case(156):
    - case(158):
    - case(160):
    - uartPortDevices[i] = &UARTDevice;
    - uartPortTim[i].toValue = msTOns(50); /* 50ms */
    - uartPortTim[i].status = TIM_EN_RUNNING;
    - break;
    - case(240): /* 240-254 are reserved for EEPROM settings */
    - case(242):
    - case(244):
    - case(246):
    - case(248):
    - case(250):
    - case(252):
    - case(254):
    - default:
    - uartPortDevices[i] = NULL; /* "Empty" or unknown module */
    - uartPortTim[i].status = TIM_DISABLED;
    - uartDevNum--; /* Substract unused devices from MAX_UART_DEVICES */
    - break;
    - }
    - }
    -}
    -
    -void InitUartPortDevices_shortBuffer(void)
    -{
    - unsigned char i=0;
    -
    - uartTimeout.tv_sec = 0;
    - uartTimeout.tv_usec = 40000; /* 40 ms timeout */
    -
    - for(i=0;i<MAX_UART_DEVICES;i++)
    - {
    - switch(uartDev[i][1])
    - {
    - case(114): /* U0x */
    - case(116):
    - case(118):
    - case(120):
    - case(122):
    - case(124):
    - case(126):
    - case(128):
    - case(130): /* P01, P02, P01V, P02V */
    - case(132):
    - case(134):
    - case(136):
    - case(138): /* CA1 */
    - case(140):
    - case(142):
    - case(144):
    - case(154): /* CR1 */
    - case(156):
    - case(158):
    - case(160):
    - case(162): /* IR1V */
    - case(164):
    - case(166):
    - case(168):
    - case(178): /* AQ1, SM1, SM5, SM6, SM7 */
    - case(180):
    - case(182):
    - case(184):
    - case(186): /* TH1V */
    - case(188):
    - case(190):
    - case(192):
    - uartPortDevices[i] = &UARTDevice;
    - uartPortTim[i].toValue = msTOns(250); /* 250ms */
    - uartPortTim[i].status = TIM_EN_RUNNING;
    - break;
    - case(146): /* CH1 */
    - case(148):
    - case(150):
    - case(152):
    - uartPortDevices[i] = &UARTDevice;
    - uartPortTim[i].toValue = msTOns(650); /* 650ms */
    - uartPortTim[i].status = TIM_EN_RUNNING;
    - break;
    - case(170): /* ID1, ID2, ID3 */
    - case(172):
    - case(174):
    - case(176):
    - case(194): /* DP1V */
    - case(196):
    - case(198):
    - case(200):
    - case(202): /* DP2V */
    - case(204):
    - case(206):
    - case(208):
    - case(210): /* DT1V */
    - case(212):
    - case(214):
    - case(216):
    - case(218): /* DU1V */
    - case(220):
    - case(222):
    - case(224):
    - case(226): /* WP1 */
    - case(228):
    - case(230):
    - case(232):
    - case(234): /* WP2 */
    - case(236):
    - case(238):
    - case(240):
    - case(242): /* WT1 */
    - case(244):
    - case(246):
    - case(248):
    - uartPortDevices[i] = &UARTDevice;
    - uartPortTim[i].toValue = msTOns(450); /* 450ms */
    - uartPortTim[i].status = TIM_EN_RUNNING;
    - break;
    - default:
    - uartPortDevices[i] = NULL; /* "Empty" or unknown module */
    - uartPortTim[i].status = TIM_DISABLED;
    - break;
    - }
    - }
    -}
    --- a/LPCBus/MC9_Devices_init.c Wed Jul 29 10:52:37 2020 +0200
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,42 +0,0 @@
    -int err;
    -#ifdef GOT100_SMT_BUS
    -char *serialdev = "/dev/ttyAPP3";
    -#else
    -char *serialdev = "/dev/ttyAPP1";
    -#endif
    -
    -uartDevWriteBuf_plc_state = EMPTY;
    -uartDevReadBuf_plc_state = EMPTY;
    -bzero(&uartDev, sizeof(uartDev));
    -
    -bzero(&uartDevReadBufA, sizeof(uartDevReadBuf_t));
    -bzero(&uartDevReadBufB, sizeof(uartDevReadBuf_t));
    -uartDevReadBuf_drv = &uartDevReadBufA;
    -uartDevReadBuf_plc = &uartDevReadBufB;
    -
    -bzero(&uartDevWriteBufA, sizeof(uartDevWriteBuf_t));
    -bzero(&uartDevWriteBufB, sizeof(uartDevWriteBuf_t));
    -uartDevWriteBuf_drv = &uartDevWriteBufA;
    -uartDevWriteBuf_plc = &uartDevWriteBufB;
    -
    -bzero(&uartCommStatusBuf, sizeof(uartCommStatusBuf));
    -bzero(&uartCommErrCntBuf, sizeof(uartCommErrCntBuf));
    -
    -%(init_code)s
    -
    -UART_fd = openserial(serialdev, uartBaudrate); /* uartBaudrate is initialized from Composer */
    -if (!UART_fd) {
    - fprintf(stderr, "Error while initializing %%s.\n", serialdev);
    - return 1;
    -}
    -
    -if(uartBufSize == UART_BUFSIZE_LONG) /* uartBufSize is initialized from Composer */
    - InitUartPortDevices_longBuffer();
    -else
    - InitUartPortDevices_shortBuffer();
    -
    -UART_task_active = 1;
    -
    -if(err = pthread_create(&UART_task, NULL, &UART_task_proc, NULL));
    - return err;
    -
    --- a/LPCBus/MC9_Devices_publish.c Wed Jul 29 10:52:37 2020 +0200
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,19 +0,0 @@
    -if(!pthread_mutex_lock(&UART_WriteMutex)){
    -
    - int prevstate;
    - prevstate=uartDevWriteBuf_plc_state;
    - uartDevWriteBuf_plc_state = LOCKED;
    -
    - pthread_mutex_unlock(&UART_WriteMutex);
    -
    -%(publish_code)s
    -
    - /* unlock plc buffer */
    - uartDevWriteBuf_plc_state = FULL;
    -
    - /* wakeup task */
    - pthread_mutex_lock(&UART_WakeCondLock);
    - UART_WakeCondValue = 1;
    - pthread_cond_signal(&UART_WakeCond);
    - pthread_mutex_unlock(&UART_WakeCondLock);
    -}
    --- a/LPCBus/MC9_Devices_retrieve.c Wed Jul 29 10:52:37 2020 +0200
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,19 +0,0 @@
    -if(!pthread_mutex_lock(&UART_ReadMutex)){
    -
    - int prevstate;
    - if((prevstate=uartDevReadBuf_plc_state) == FULL){
    - uartDevReadBuf_plc_state = LOCKED;
    - }
    -
    - pthread_mutex_unlock(&UART_ReadMutex);
    -
    - if(prevstate == FULL){
    -
    -%(retrieve_code)s
    -
    - /* unlock plc buffer */
    - uartDevReadBuf_plc_state = EMPTY;
    - }else{
    - /* No new data -> no update */
    - }
    -}
    --- a/LPCBus/MC9_OnBoard_cleanup.c Wed Jul 29 10:52:37 2020 +0200
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,17 +0,0 @@
    -#ifdef ONBOARD_I2C
    -if(onboardbusfd!=-1)
    - close(onboardbusfd);
    -#endif /* ONBOARD_I2C */
    -
    -#ifdef CAN0_EN_GPIO_0_21
    -gpio_set_pin_value(CAN0_EN_dev, 1);
    -gpio_close(CAN0_EN_dev);
    -#endif /* CAN0_EN_GPIO_0_21 */
    -
    -#ifdef CAN1_EN_GPIO_0_17
    -gpio_set_pin_value(CAN1_EN_dev, 1);
    -gpio_close(CAN1_EN_dev);
    -#endif /* CAN1_EN_GPIO_0_17 */
    -
    -gpio_set_pin_value(RUN_LED_dev, 1);
    -gpio_close(RUN_LED_dev);
    --- a/LPCBus/MC9_OnBoard_decl.c Wed Jul 29 10:52:37 2020 +0200
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,170 +0,0 @@
    -#include <unistd.h>
    -#include <fcntl.h>
    -#include <rtdm/rtdm.h>
    -#include "beremiz.h"
    -
    -/*------------------------- GPIO -------------------------------------*/
    -/* from armadeus/target/packages/as_devices/c/as_gpio* */
    -
    -//#ifdef DEBUG
    -# define ERROR(fmt, ...) printf(fmt, ##__VA_ARGS__)
    -//#else
    -//# define ERROR(fmt, ...) /*fmt, ##__VA_ARGS__*/
    -//#endif
    -
    -struct gpio_device {
    - int port_num;
    - int pin_file; /* pin file for 2.6.29 interface*/
    -};
    -
    -struct gpio_device *RUN_LED_dev;
    -#ifdef CAN0_EN_GPIO_0_21
    -struct gpio_device *CAN0_EN_dev;
    -#endif /* CAN0_EN_GPIO_0_21 */
    -#ifdef CAN1_EN_GPIO_0_17
    -struct gpio_device *CAN1_EN_dev;
    -#endif /* CAN1_EN_GPIO_0_17 */
    -
    -static int write_file_bool(int fd, int value)
    -{
    - int ret;
    -
    - ret = write(fd, value?"1":"0", 1);
    - if (ret < 0) {
    - ERROR("write error\n");
    - return ret;
    - }
    - if (lseek(fd, 0, SEEK_SET) < 0) {
    - ERROR("lseek error\n");
    - return ret;
    - }
    -
    - return ret;
    -}
    -
    -#define BUFF_SIZE 256
    -static int gpio_set_pin_value(struct gpio_device *aDev, int aValue)
    -{
    - int pin_file = aDev->pin_file;
    - int retval;
    -
    - retval = write_file_bool(pin_file, aValue);
    - if (retval < 0) {
    - ERROR("Can't write value\n");
    - close(pin_file);
    - return -1;
    - }
    -
    - return aValue;
    -}
    -
    -static struct gpio_device *gpio_open(int aGpioNum)
    -{
    - struct gpio_device *dev;
    - int pin_file;
    - int export_file;
    - int gpio_dir_fd;
    - int retval;
    - char buf[BUFF_SIZE];
    - int ret = 0;
    -
    - export_file = open("/sys/class/gpio/export", O_WRONLY);
    - if (export_file < 0) {
    - ERROR("Can't open /sys/class/gpio/export\nBe sure that gpiolib is under your kernel\n");
    - return NULL;
    - }
    -
    - snprintf(buf, BUFF_SIZE, "%%d", aGpioNum);
    - retval = write(export_file, buf, strlen(buf));
    - close(export_file);
    - if (retval < 0) {
    - ERROR("/sys/class/gpio/export can't be written\n");
    - return NULL;
    - }
    -
    - snprintf(buf, BUFF_SIZE, "/sys/class/gpio/gpio%%d/direction", aGpioNum);
    - gpio_dir_fd = open(buf, O_WRONLY);
    - if (gpio_dir_fd < 0) {
    - ERROR("Can't open gpio%%d direction\n", aGpioNum);
    - return NULL;
    - }
    -
    - ret = write(gpio_dir_fd, "out", 3);
    - close(gpio_dir_fd);
    - if (ret < 0){
    - ERROR("Error writing direction\n");
    - return NULL;
    - }
    -
    - snprintf(buf, BUFF_SIZE, "/sys/class/gpio/gpio%%d/value", aGpioNum);
    - pin_file = open(buf, O_RDWR);
    - if (pin_file < 0) {
    - ERROR("Can't export gpio number %%d\n", aGpioNum);
    - return NULL;
    - }
    -
    - dev = malloc(sizeof(struct gpio_device));
    - if (dev == NULL) {
    - ERROR("Can't allocate gpio_device structure\n");
    - close(pin_file);
    - return NULL;
    - }
    -
    - dev->port_num = aGpioNum;
    - dev->pin_file = pin_file;
    -
    - gpio_set_pin_value(dev, 1);
    -
    - return dev;
    -}
    -
    -static int gpio_close(struct gpio_device *aDev)
    -{
    - int unexport_file;
    - char buf[BUFF_SIZE];
    - int retval;
    -
    - if(aDev == NULL){
    - ERROR("device is NULL\n");
    - return -1;
    - }
    -
    - unexport_file = open("/sys/class/gpio/unexport", O_WRONLY);
    - if (unexport_file < 0) {
    - ERROR("Can't open /sys/class/gpio/unexport\nBe sure that gpiolib is under your kernel\n");
    - return -1;
    - }
    -
    - snprintf(buf, BUFF_SIZE, "%%d", aDev->port_num);
    - retval = write(unexport_file, buf, strlen(buf));
    - close(unexport_file);
    - if (retval < 0) {
    - ERROR("/sys/class/gpio/unexport can't be written\n");
    - return -1;
    - }
    -
    - close(aDev->pin_file);
    -
    - return 0;
    -}
    -
    -/* TODO : DELETE !... but keep this until composer stops sending code snippets for mbrtu */
    -typedef enum
    -{
    - MB_PAR_ODD = 0, /**< ODD parity. */
    - MB_PAR_EVEN = 1, /**< Even parity. */
    - MB_PAR_NONE = 2 /**< No parity. */
    -} eMBSerialParity;
    -unsigned long mbBaudRate = 115200; /**< Modbus baud-rate setting: 9600, 19200, 38400, 57600, 115200 */
    -eMBSerialParity mbParity = MB_PAR_NONE; /**< Modbus parity setting: odd, even, none */
    -
    -#ifdef ONBOARD_I2C
    -
    -#include "rt_imx_smt_onboard.h"
    -
    -static readBuf_t onBoardReadBuf;
    -static writeBuf_t onBoardWriteBuf;
    -static busInit_t onBoardBusInit;
    -
    -static int onboardbusfd = -1;
    -#endif /* ONBOARD_I2C */
    --- a/LPCBus/MC9_OnBoard_init.c Wed Jul 29 10:52:37 2020 +0200
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,55 +0,0 @@
    -#define ONBOARDDEVFILENAME "/dev/rtdm/onboard"
    -
    -int err;
    -
    -#ifdef ONBOARD_I2C
    -bzero(&onBoardReadBuf , sizeof(readBuf_t));
    -bzero(&onBoardWriteBuf, sizeof(writeBuf_t));
    -bzero(&onBoardBusInit , sizeof(busInit_t));
    -
    -onBoardBusInit.common_ticktime__ = common_ticktime__;
    -#define onBoardDev (onBoardBusInit.rightI2CMod)
    -#endif /* ONBOARD_I2C */
    -
    -%(init_code)s
    -
    -#ifdef CAN0_EN_GPIO_0_21
    -CAN0_EN_dev = gpio_open(21);
    -gpio_set_pin_value(CAN0_EN_dev, 0);
    -#endif /* CAN0_EN_GPIO_0_21 */
    -#ifdef CAN1_EN_GPIO_0_17
    -CAN1_EN_dev = gpio_open(17);
    -gpio_set_pin_value(CAN1_EN_dev, 0);
    -#endif /* CAN1_EN_GPIO_0_17 */
    -
    -#ifdef ONBOARD_I2C
    -unsigned char i;
    -for(i=0; i<MAX_RIGHT_MODULES; i++) {
    - switch(onBoardDev[i][1]) {
    - case 1:
    - /* OnBoard I2C bus */
    - onboardbusfd = open(ONBOARDDEVFILENAME, 0);
    - if(onboardbusfd < 0) {
    - printf("can't open %%s rtdm device, %%s\n", ONBOARDDEVFILENAME,
    - strerror(-onboardbusfd));
    - return onboardbusfd;
    - }
    - err = ioctl(onboardbusfd, RTSMT_RTIOC_INIT, &onBoardBusInit);
    - if(err) {
    - printf("error while RTSMT_RTIOC_INIT, %%s\n", strerror(-err));
    - close(onboardbusfd);
    - return err;
    - }
    - break;
    - default:
    - break;
    - }
    -}
    -#endif /* ONBOARD_I2C */
    -
    -#if defined RUN_LED_GPIO_1_13
    -RUN_LED_dev = gpio_open(45);
    -#elif defined RUN_LED_GPIO_1_31
    -RUN_LED_dev = gpio_open(63);
    -#endif /* RUN LED GPIO_1_13/GPIO_1_31 */
    -gpio_set_pin_value(RUN_LED_dev, 0);
    --- a/LPCBus/MC9_OnBoard_publish.c Wed Jul 29 10:52:37 2020 +0200
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,6 +0,0 @@
    -%(publish_code)s
    -
    -#ifdef ONBOARD_I2C
    -if(onboardbusfd!=-1)
    - ioctl(onboardbusfd, RTSMT_RTIOC_WRITE, &onBoardWriteBuf);
    -#endif /* ONBOARD_I2C */
    --- a/LPCBus/MC9_OnBoard_retrieve.c Wed Jul 29 10:52:37 2020 +0200
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,6 +0,0 @@
    -#ifdef ONBOARD_I2C
    -if(onboardbusfd!=-1)
    - ioctl(onboardbusfd, RTSMT_RTIOC_READ, &onBoardReadBuf);
    -#endif /* ONBOARD_I2C */
    -
    -%(retrieve_code)s
    --- a/LPCBus/MC9_Right_cleanup.c Wed Jul 29 10:52:37 2020 +0200
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,1 +0,0 @@
    -close(rightbusfd);
    --- a/LPCBus/MC9_Right_decl.c Wed Jul 29 10:52:37 2020 +0200
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,12 +0,0 @@
    -
    -#include <rtdm/rtdm.h>
    -#include "beremiz.h"
    -#include "rt_imx_smt_right.h"
    -
    -static readBuf_t rightReadBuf;
    -static writeBuf_t rightWriteBuf;
    -static busInit_t rightBusInit;
    -
    -static int rightbusfd = -1;
    -
    -/* XXX TODO #include "smarteh.h" */
    --- a/LPCBus/MC9_Right_init.c Wed Jul 29 10:52:37 2020 +0200
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,26 +0,0 @@
    -#define DEVICEFILENAME "/dev/rtdm/rightbus"
    -
    -bzero(&rightReadBuf, sizeof(readBuf_t));
    -bzero(&rightWriteBuf, sizeof(writeBuf_t));
    -bzero(&rightBusInit, sizeof(busInit_t));
    -
    -rightBusInit.common_ticktime__ = common_ticktime__;
    -
    -#define rightI2CMod (rightBusInit.rightI2CMod)
    -%(init_code)s
    -
    -int err;
    -rightbusfd = open( DEVICEFILENAME, 0);
    -if (rightbusfd < 0) {
    - printf("can't open %%s rtdm device, %%s\\n", DEVICEFILENAME,
    - strerror(-rightbusfd));
    - return rightbusfd;
    -}
    -
    -err = ioctl(rightbusfd, RTSMT_RTIOC_INIT, &rightBusInit);
    -if (err) {
    - printf("error while RTSMT_RTIOC_INIT, %%s\\n",
    - strerror(-err));
    - close(rightbusfd);
    - return err;
    -}
    --- a/LPCBus/MC9_Right_publish.c Wed Jul 29 10:52:37 2020 +0200
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,2 +0,0 @@
    -%(publish_code)s
    -ioctl(rightbusfd, RTSMT_RTIOC_WRITE, &rightWriteBuf);
    --- a/LPCBus/MC9_Right_retrieve.c Wed Jul 29 10:52:37 2020 +0200
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,2 +0,0 @@
    -ioctl(rightbusfd, RTSMT_RTIOC_READ, &rightReadBuf);
    -%(retrieve_code)s
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/LPCBus/SOM.c Mon Apr 12 10:01:38 2021 +0200
    @@ -0,0 +1,105 @@
    +
    +/* Code generated by LPCBus confnode */
    +
    +#ifdef _WINDOWS_H
    + #include "iec_types.h"
    +#else
    + #include "iec_std_lib.h"
    +#endif
    +
    +static inline int16_t getWord(char *buffer)
    +{
    + return ((int16_t)*buffer<<8) + (int16_t)*(buffer+1);
    +}
    +
    +static inline int16_t getWordSwapped(char *buffer)
    +{
    + return (((int16_t)*(buffer+1))<<8) + (int16_t)*buffer;
    +}
    +
    +static inline void setWord(char *buffer, int16_t word)
    +{
    + *buffer = (char)(word>>8);
    + *(buffer+1) = (char)(word);
    +}
    +
    +static inline void setWordSwapped(char *buffer, int16_t word)
    +{
    + *buffer = (char)word;
    + *(buffer+1) = (char)(word>>8);
    +}
    +
    +static inline int8_t getBit(char *buffer, unsigned char bitOffset)
    +{
    + return (*buffer & (0x01 << bitOffset)) && 1;
    +}
    +
    +static inline void setBit(char *buffer, unsigned char bitOffset, int8_t bit)
    +{
    + unsigned char msk = (0x01 << bitOffset);
    + if(bit)
    + *buffer |= msk;
    + else
    + *buffer &= ~msk;
    +}
    +
    +static void setWord16(short *buffer, uint16_t word)
    +{
    + *buffer = (short)word;
    +}
    +
    +static int16_t getWord16(short *buffer)
    +{
    + return((uint16_t)*buffer);
    +}
    +
    +static inline unsigned char getByte(char *buffer)
    +{
    + return((unsigned char)*buffer);
    +}
    +
    +static inline void setByte(char *buffer, unsigned char byte)
    +{
    + *buffer = byte;
    +}
    +
    +typedef struct
    +{
    + unsigned char status; /* Current status of timer - running / expired */
    + uint64_t actValue; /* Actual timer value */
    + uint64_t toValue; /* Timeout value - initialized at startup */
    + uint64_t oldTime; /* Time at previous timer increment; NOTE: if RTIME (unsigned long long) changes type, oldTime has to be adapted */
    +} commTimer;
    +
    +#define TIM_DISABLED 0
    +#define TIM_EN_RUNNING 1
    +#define TIM_EN_EXPIRED 2
    +
    +%(bus_decl)s
    +
    +%(declare_code)s
    +
    +/* LPCBus confnode user variables definition */
    +%(var_decl)s
    +
    +/* LPCBus confnode functions */
    +int __init_%(location_str)s(int argc,char **argv)
    +{
    + %(bus_init_code)s
    + return 0;
    +}
    +
    +void __cleanup_%(location_str)s(void)
    +{
    + %(bus_cleanup_code)s
    +}
    +
    +void __retrieve_%(location_str)s(void)
    +{
    +%(bus_retrieve_code)s
    +}
    +
    +void __publish_%(location_str)s(void)
    +{
    +%(bus_publish_code)s
    +}
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/LPCBus/SOM28_Right_cleanup.c Mon Apr 12 10:01:38 2021 +0200
    @@ -0,0 +1,1 @@
    +close(rightbusfd);
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/LPCBus/SOM28_Right_decl.c Mon Apr 12 10:01:38 2021 +0200
    @@ -0,0 +1,12 @@
    +
    +#include <rtdm/rtdm.h>
    +#include "beremiz.h"
    +#include "rt_imx_smt_right.h"
    +
    +static readBuf_t rightReadBuf;
    +static writeBuf_t rightWriteBuf;
    +static busInit_t rightBusInit;
    +
    +static int rightbusfd = -1;
    +
    +/* XXX TODO #include "smarteh.h" */
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/LPCBus/SOM28_Right_init.c Mon Apr 12 10:01:38 2021 +0200
    @@ -0,0 +1,26 @@
    +#define DEVICEFILENAME "/dev/rtdm/rightbus"
    +
    +bzero(&rightReadBuf, sizeof(readBuf_t));
    +bzero(&rightWriteBuf, sizeof(writeBuf_t));
    +bzero(&rightBusInit, sizeof(busInit_t));
    +
    +rightBusInit.common_ticktime__ = common_ticktime__;
    +
    +#define rightI2CMod (rightBusInit.rightI2CMod)
    +%(init_code)s
    +
    +int err;
    +rightbusfd = open( DEVICEFILENAME, 0);
    +if (rightbusfd < 0) {
    + printf("can't open %%s rtdm device, %%s\\n", DEVICEFILENAME,
    + strerror(-rightbusfd));
    + return rightbusfd;
    +}
    +
    +err = ioctl(rightbusfd, RTSMT_RTIOC_INIT, &rightBusInit);
    +if (err) {
    + printf("error while RTSMT_RTIOC_INIT, %%s\\n",
    + strerror(-err));
    + close(rightbusfd);
    + return err;
    +}
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/LPCBus/SOM28_Right_publish.c Mon Apr 12 10:01:38 2021 +0200
    @@ -0,0 +1,2 @@
    +%(publish_code)s
    +ioctl(rightbusfd, RTSMT_RTIOC_WRITE, &rightWriteBuf);
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/LPCBus/SOM28_Right_retrieve.c Mon Apr 12 10:01:38 2021 +0200
    @@ -0,0 +1,2 @@
    +ioctl(rightbusfd, RTSMT_RTIOC_READ, &rightReadBuf);
    +%(retrieve_code)s
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/LPCBus/SOM_Devices_cleanup.c Mon Apr 12 10:01:38 2021 +0200
    @@ -0,0 +1,8 @@
    +
    +pthread_mutex_lock(&UART_WakeCondLock);
    +
    +UART_task_active = 0;
    +pthread_cond_signal(&UART_WakeCond);
    +pthread_mutex_unlock(&UART_WakeCondLock);
    +pthread_join(UART_task, NULL);
    +closeserial(UART_fd);
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/LPCBus/SOM_Devices_decl.c Mon Apr 12 10:01:38 2021 +0200
    @@ -0,0 +1,588 @@
    +#include <stdio.h>
    +#include <termios.h>
    +#include <unistd.h>
    +#include <sys/ioctl.h>
    +#include <fcntl.h>
    +#include <sys/select.h>
    +
    +#include <alchemy/task.h>
    +#include <alchemy/mutex.h>
    +#include <alchemy/timer.h>
    +
    +#include "beremiz.h"
    +
    +static struct termios oldterminfo;
    +
    +void closeserial(int fd)
    +{
    + tcsetattr(fd, TCSANOW, &oldterminfo);
    + if (close(fd) < 0)
    + perror("closeserial()");
    +}
    +
    +/*--------------------------- Serial Port handling ---------------------------*/
    +
    +int openserial(char *devicename, unsigned long baudrate)
    +{
    + int fd;
    + struct termios attr;
    + speed_t baud = B115200; /* baud rate */
    +
    + switch(baudrate)
    + {
    + case 19200:
    + baud = B19200;
    + break;
    + case 115200:
    + baud = B115200;
    + break;
    + default:
    + baud = B115200;
    + }
    +
    + if ((fd = open(devicename, O_RDWR)) == -1) {
    + perror("openserial(): open()");
    + return 0;
    + }
    + if (tcgetattr(fd, &oldterminfo) == -1) {
    + perror("openserial(): tcgetattr()");
    + return 0;
    + }
    + attr = oldterminfo;
    + attr.c_oflag = 0;
    + attr.c_iflag = 0;
    + attr.c_lflag = 0;
    +
    + attr.c_cflag = 0;
    + attr.c_cflag |= CREAD;
    + attr.c_cflag |= CLOCAL;
    + attr.c_cflag |= CS8 ; /* 8 bits */
    + /* no parity, 1 stop bit */
    +
    + cfsetspeed(&attr, baud); /* baud rate */
    +
    + if (tcflush(fd, TCIOFLUSH) == -1) {
    + perror("openserial(): tcflush()");
    + return 0;
    + }
    + if (tcsetattr(fd, TCSANOW, &attr) == -1) {
    + perror("initserial(): tcsetattr()");
    + return 0;
    + }
    +
    + return fd;
    +}
    +
    +
    +#define EMPTY 0
    +#define LOCKED 1
    +#define FULL 2
    +
    +#define MAX_UART_DEVICES 32
    +#define UART_BUFSIZE_SHORT 26 /* UART bus read & write buffer size - short buffer for LPC-2 */
    +#define UART_BUFSIZE_LONG 48 /* UART bus read & write buffer size - long buffer for LHC-2 */
    +#define UART_RETRY_NUM 0
    +
    +char uartBufSize = UART_BUFSIZE_SHORT; /* Smarteh uart bus: buffer size */
    +unsigned long uartBaudrate = 19200; /* Smarteh uart bus: baudrate */
    +struct timeval uartTimeout = {0,40000}; /* Smarteh uart bus: timeout */
    +
    +/* Tables containing information about connected devices on UART port
    + (initialized by Composer) */
    +unsigned char uartDev[MAX_UART_DEVICES][2];
    +unsigned char uartDevNum = MAX_UART_DEVICES;
    +
    +/* Buffers for reading data from UART port devices */
    +typedef char uartDevReadBuf_t[MAX_UART_DEVICES][UART_BUFSIZE_LONG];
    +uartDevReadBuf_t uartDevReadBufA;
    +uartDevReadBuf_t uartDevReadBufB;
    +uartDevReadBuf_t *uartDevReadBuf_drv;
    +uartDevReadBuf_t *uartDevReadBuf_plc;
    +/* MC8 compatibility */
    +uartDevReadBuf_t uartDevReadBuf;
    +
    +/* Buffers for writing data to UART port devices */
    +typedef char uartDevWriteBuf_t[MAX_UART_DEVICES][UART_BUFSIZE_LONG];
    +uartDevWriteBuf_t uartDevWriteBufA;
    +uartDevWriteBuf_t uartDevWriteBufB;
    +uartDevWriteBuf_t *uartDevWriteBuf_drv;
    +uartDevWriteBuf_t *uartDevWriteBuf_plc;
    +/* MC8 compatibility */
    +#define uartDevWriteBuf (*uartDevWriteBuf_drv)
    +
    +int uartDevWriteBuf_plc_state;
    +int uartDevReadBuf_plc_state;
    +
    +/* Buffers for communication statuses with UART port devices */
    +/* 2D arrays due to compatibility with Composer (LpcSmartehIDE) */
    +char uartCommErrCntBuf [MAX_UART_DEVICES][1];
    +char uartCommStatusBuf[MAX_UART_DEVICES][1];
    +
    +/* Function interface definition for modules on UART (RS485) bus */
    +typedef unsigned char (*uartPortFunct)(char*, char*, char);
    +/* Table describing module positions on UART (RS485) bus (parsed from Composer data) */
    +uartPortFunct uartPortDevices[MAX_UART_DEVICES] = {NULL};
    +/* Table of timers (one for each position) */
    +static commTimer uartPortTim[MAX_UART_DEVICES];
    +
    +static pthread_t UART_task;
    +static pthread_mutex_t UART_WriteMutex = PTHREAD_MUTEX_INITIALIZER;
    +static pthread_mutex_t UART_ReadMutex = PTHREAD_MUTEX_INITIALIZER;
    +static pthread_mutex_t UART_WakeCondLock = PTHREAD_MUTEX_INITIALIZER;
    +static pthread_cond_t UART_WakeCond = PTHREAD_COND_INITIALIZER;
    +static int UART_WakeCondValue = 0;
    +static int UART_task_active;
    +
    +void* UART_task_proc(void *arg)
    +{
    + static unsigned char i=0;
    + char commStat;
    + uint64_t actTime;
    + static uint64_t lastCommTime=0;
    +
    + struct sched_param param = { .sched_priority = 10 };
    + pthread_setname_np(pthread_self(), "UART_task");
    + pthread_setschedparam(pthread_self(), SCHED_FIFO, &param);
    +
    + while (1){
    + int active;
    + pthread_mutex_lock(&UART_WakeCondLock);
    + active = UART_task_active;
    + while(!UART_WakeCondValue && active){
    + pthread_cond_wait(&UART_WakeCond, &UART_WakeCondLock);
    + active = UART_task_active;
    + }
    +
    + UART_WakeCondValue = 0;
    + pthread_mutex_unlock(&UART_WakeCondLock);
    +
    + if(!active)
    + break;
    +
    + // Communicate only with initialised UART devices
    + if(uartPortDevices[i] != NULL)
    + {
    +
    + // Timers for UART port modules
    + if(uartPortTim[i].status != TIM_DISABLED)
    + {
    + struct timespec time_ref;
    + if(clock_gettime(CLOCK_MONOTONIC, &time_ref)){
    + perror("clock_gettime(time_ref)");
    + }
    + actTime = time_ref.tv_nsec + time_ref.tv_sec * 1000000000LL;
    + uartPortTim[i].actValue = actTime - uartPortTim[i].oldTime;
    +
    + if((uartPortTim[i].actValue < uartPortTim[i].toValue)
    + || (actTime - lastCommTime < 50000000))
    + uartPortTim[i].status = TIM_EN_RUNNING;
    + else {
    + uartPortTim[i].status = TIM_EN_EXPIRED;
    + uartPortTim[i].oldTime = actTime;
    + lastCommTime = actTime;
    + }
    + }
    +
    + // Check timer status
    + if((uartPortTim[i].status == TIM_DISABLED)
    + || (uartPortTim[i].status == TIM_EN_EXPIRED))
    + {
    + if(!pthread_mutex_lock(&UART_WriteMutex)){
    + if(uartDevWriteBuf_plc_state == FULL){
    + uartDevWriteBuf_t *uartDevWriteBuf_tmp;
    + uartDevWriteBuf_tmp = uartDevWriteBuf_plc;
    + uartDevWriteBuf_plc = uartDevWriteBuf_drv;
    + uartDevWriteBuf_drv = uartDevWriteBuf_tmp;
    + uartDevWriteBuf_plc_state = EMPTY;
    + }
    + pthread_mutex_unlock(&UART_WriteMutex);
    + }
    +
    + // Communicate with device
    + commStat = (*uartPortDevices[i])(
    + &uartDevReadBuf[i][0],
    + &uartDevWriteBuf[i][0],
    + uartDev[i][1]);
    +
    + memcpy(uartDevReadBuf_drv, &uartDevReadBuf, sizeof(uartDevReadBuf_t));
    +
    + if(!pthread_mutex_lock(&UART_ReadMutex)){
    + if(uartDevReadBuf_plc_state == EMPTY){
    + uartDevReadBuf_t *uartDevReadBuf_tmp;
    + uartDevReadBuf_tmp = uartDevReadBuf_plc;
    + uartDevReadBuf_plc = uartDevReadBuf_drv;
    + uartDevReadBuf_drv = uartDevReadBuf_tmp;
    + uartDevReadBuf_plc_state = FULL;
    + }
    + pthread_mutex_unlock(&UART_ReadMutex);
    + }
    +
    + // Check communication status:
    + if(commStat == TRUE)
    + {
    + uartCommStatusBuf[i][0] = TRUE;
    + uartCommErrCntBuf[i][0] = 0;
    + }
    + else
    + {
    + if(uartCommErrCntBuf[i][0] < UART_RETRY_NUM)
    + uartCommErrCntBuf[i][0]++;
    + else
    + uartCommStatusBuf[i][0] = FALSE;
    + }
    +
    + // If timer is enabled, reset it's value,
    + // otherwise keep it disabled
    + if(uartPortTim[i].status != TIM_DISABLED)
    + {
    + uartPortTim[i].actValue = 0;
    + uartPortTim[i].status = TIM_EN_RUNNING;
    + }
    + else /* Keep timer disabled */
    + uartPortTim[i].status = TIM_DISABLED;
    +
    + // Procede with next UART device only after
    + // communication with the current one is done
    + if(i < (uartDevNum-1))
    + i++;
    + else /* Go back to the first UART device */
    + i=0;
    + }
    + }
    + else i=0;
    + }
    + return NULL;
    +}
    +
    +#define TAIL_LEN 3 /* Length of data tail in bytes */
    +/**************************************************************************//**
    +* Calculate checksum of a buffer
    +* @param [in] buffer Pointer to buffer
    +* @param [in] bufLen Buffer length
    +* @return Checksum values on buffer locations bufLen-TAIL_LEN &
    +* bufLen-TAIL_LEN+1
    +******************************************************************************/
    +void Checksum(unsigned char *buffer, unsigned char bufLen)
    +{
    + unsigned char i=0, j=0;
    + unsigned char checksum1=0, checksum2=0;
    + unsigned char checksum1Temp=0;
    +
    + for(i=0;i<bufLen-TAIL_LEN;i++)
    + {
    + checksum1Temp=buffer[i];
    + for(j=0;j<8;j++) /* Compute number of '1' of whole buff. */
    + {
    + if((checksum1Temp & 0x01)>0)
    + checksum1++;
    + checksum1Temp = checksum1Temp >> 1;
    + }
    + checksum2 = checksum2 ^ buffer[i]; /* Compute XOR of whole buffer */
    + }
    +
    + buffer[bufLen-TAIL_LEN] = checksum2; /* Write number of '1' to buffer */
    + buffer[bufLen-TAIL_LEN+1] = checksum1; /* Write XOR to buffer */
    +}
    +
    +/**************************************************************************//**
    +* Check if checksum values of received buffer are valid
    +* @param [in] buffer Pointer to buffer
    +* @param [in] bufLen Buffer length
    +* @return TRUE if valid, otherwise FALSE
    +******************************************************************************/
    +unsigned char ChecksumValid(unsigned char *buffer, unsigned char bufLen)
    +{
    + unsigned char i=0, j=0;
    + unsigned char checksum1=0, checksum2=0;
    + unsigned char checksum1Temp=0;
    +
    + for(i=0;i<bufLen-TAIL_LEN;i++)
    + {
    + checksum1Temp = buffer[i];
    + for(j=0;j<8;j++) /* Compute number of '1' of whole buff. */
    + {
    + if((checksum1Temp & 0x01)>0)
    + checksum1++;
    + checksum1Temp = checksum1Temp >> 1; /* Compute XOR of whole buffer */
    + }
    + checksum2 = checksum2 ^ buffer[i];
    + }
    +
    + /* Check if computed checksums are the same as those in buffer (=> no error) */
    + if((checksum2==buffer[bufLen-TAIL_LEN]) && (checksum1==buffer[bufLen-TAIL_LEN+1]))
    + return TRUE;
    + else
    + return FALSE;
    +}
    +
    +static int UART_fd;
    +/*************************************************************************//**
    +* Support for UART modules
    +* @param [in] readBuf Pointer to read buffer (for previously polled UART device!)
    +* @param [out] writeBuf Pointer to write buffer (for current device)
    +* @param [in] address UART device address
    +* @return TRUE if communication was successful, otherwise FALSE
    +*****************************************************************************/
    +unsigned char UARTDevice(char* readBuf, char* writeBuf, char address)
    +{
    + fd_set set;
    + struct timeval timeout;
    + int rv;
    + int count = 0;
    + char tmp[uartBufSize];
    +
    + /* Prepare transmit buffer */
    + memcpy(tmp+1,writeBuf,uartBufSize-TAIL_LEN-1);
    + tmp[0] = 'S';
    + tmp[uartBufSize-TAIL_LEN] = address;
    + Checksum((unsigned char*)tmp+1, uartBufSize);
    +
    + tcflush(UART_fd, TCIOFLUSH);
    +
    + if(write(UART_fd, tmp, uartBufSize) != uartBufSize){
    + goto UARTDevfail;
    + }
    +
    + FD_ZERO(&set); /* clear the set */
    + FD_SET(UART_fd, &set); /* add our file descriptor to the set */
    +
    + timeout.tv_sec = uartTimeout.tv_sec;
    + timeout.tv_usec = uartTimeout.tv_usec;
    +
    + while(count < uartBufSize){
    + rv = select(UART_fd + 1, &set, NULL, NULL, &timeout);
    + if(rv == -1)
    + printf("RS485 select error\n");
    + else if(rv == 0)
    + {
    + //printf("timeout\n");
    + break;
    + }
    + else {
    + int rr = read(UART_fd, tmp + count, uartBufSize - count);
    + if(rr > 0){
    + count += rr;
    + }else{
    + printf("RS485 read error %%d\n",rr);
    + }
    + }
    + }
    +
    + /* Copy received buffer */
    + if((count == uartBufSize) && (tmp[uartBufSize-TAIL_LEN] == address)){
    + if(ChecksumValid((unsigned char*)tmp+1, uartBufSize)){
    + memcpy(readBuf,tmp+1,uartBufSize-TAIL_LEN-1);
    + return(TRUE);
    + }
    + }
    +
    + UARTDevfail:
    + tcflush(UART_fd, TCIOFLUSH);
    + return(FALSE);
    +}
    +
    +/* Macro to transform milliseconds to ns */
    +#define msTOns(ms) (1000000L*ms)
    +
    +void InitUartPortDevices_longBuffer(void)
    +{
    + unsigned char i=0;
    +
    + uartTimeout.tv_sec = 0;
    + uartTimeout.tv_usec = 20000; /* 20 ms timeout */
    +
    + for(i=0;i<MAX_UART_DEVICES;i++)
    + {
    + switch(uartDev[i][1])
    + {
    + case(2): /* MU1 */
    + case(4):
    + case(6):
    + case(8):
    + case(10):
    + case(12):
    + case(14):
    + case(16):
    + case(18):
    + case(20):
    + case(22):
    + case(24):
    + case(26):
    + case(28):
    + case(30):
    + case(32):
    + case(34):
    + case(36):
    + case(38):
    + case(40):
    + case(42):
    + case(44):
    + case(46):
    + case(48):
    + case(66): /* MU2 */
    + case(68):
    + case(70):
    + case(72):
    + case(74): /* MU3 */
    + case(76):
    + case(78):
    + case(80):
    + case(82): /* MU4 */
    + case(84):
    + case(86):
    + case(88):
    + case(90): /* MU5 */
    + case(92):
    + case(94):
    + case(96):
    + case(98): /* MU6 */
    + case(100):
    + case(102):
    + case(104):
    + case(106): /* M4U */
    + case(108):
    + case(110):
    + case(112):
    + case(114): /* TH1 */
    + case(116):
    + case(118):
    + case(120):
    + case(122):
    + case(124):
    + case(126):
    + case(128):
    + case(130):
    + case(132):
    + case(134):
    + case(136):
    + case(138): /* MU7 */
    + case(140):
    + case(142):
    + case(144):
    + case(146): /* MU8 */
    + case(148):
    + case(150):
    + case(152):
    + case(154): /* MU9 */
    + case(156):
    + case(158):
    + case(160):
    + uartPortDevices[i] = &UARTDevice;
    + uartPortTim[i].toValue = msTOns(50); /* 50ms */
    + uartPortTim[i].status = TIM_EN_RUNNING;
    + break;
    + case(240): /* 240-254 are reserved for EEPROM settings */
    + case(242):
    + case(244):
    + case(246):
    + case(248):
    + case(250):
    + case(252):
    + case(254):
    + default:
    + uartPortDevices[i] = NULL; /* "Empty" or unknown module */
    + uartPortTim[i].status = TIM_DISABLED;
    + uartDevNum--; /* Substract unused devices from MAX_UART_DEVICES */
    + break;
    + }
    + }
    +}
    +
    +void InitUartPortDevices_shortBuffer(void)
    +{
    + unsigned char i=0;
    +
    + uartTimeout.tv_sec = 0;
    + uartTimeout.tv_usec = 40000; /* 40 ms timeout */
    +
    + for(i=0;i<MAX_UART_DEVICES;i++)
    + {
    + switch(uartDev[i][1])
    + {
    + case(114): /* U0x */
    + case(116):
    + case(118):
    + case(120):
    + case(122):
    + case(124):
    + case(126):
    + case(128):
    + case(130): /* P01, P02, P01V, P02V */
    + case(132):
    + case(134):
    + case(136):
    + case(138): /* CA1 */
    + case(140):
    + case(142):
    + case(144):
    + case(154): /* CR1 */
    + case(156):
    + case(158):
    + case(160):
    + case(162): /* IR1V */
    + case(164):
    + case(166):
    + case(168):
    + case(178): /* AQ1, SM1, SM5, SM6, SM7 */
    + case(180):
    + case(182):
    + case(184):
    + case(186): /* TH1V */
    + case(188):
    + case(190):
    + case(192):
    + uartPortDevices[i] = &UARTDevice;
    + uartPortTim[i].toValue = msTOns(250); /* 250ms */
    + uartPortTim[i].status = TIM_EN_RUNNING;
    + break;
    + case(146): /* CH1 */
    + case(148):
    + case(150):
    + case(152):
    + uartPortDevices[i] = &UARTDevice;
    + uartPortTim[i].toValue = msTOns(650); /* 650ms */
    + uartPortTim[i].status = TIM_EN_RUNNING;
    + break;
    + case(170): /* ID1, ID2, ID3 */
    + case(172):
    + case(174):
    + case(176):
    + case(194): /* DP1V */
    + case(196):
    + case(198):
    + case(200):
    + case(202): /* DP2V */
    + case(204):
    + case(206):
    + case(208):
    + case(210): /* DT1V */
    + case(212):
    + case(214):
    + case(216):
    + case(218): /* DU1V */
    + case(220):
    + case(222):
    + case(224):
    + case(226): /* WP1 */
    + case(228):
    + case(230):
    + case(232):
    + case(234): /* WP2 */
    + case(236):
    + case(238):
    + case(240):
    + case(242): /* WT1 */
    + case(244):
    + case(246):
    + case(248):
    + uartPortDevices[i] = &UARTDevice;
    + uartPortTim[i].toValue = msTOns(450); /* 450ms */
    + uartPortTim[i].status = TIM_EN_RUNNING;
    + break;
    + default:
    + uartPortDevices[i] = NULL; /* "Empty" or unknown module */
    + uartPortTim[i].status = TIM_DISABLED;
    + break;
    + }
    + }
    +}
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/LPCBus/SOM_Devices_init.c Mon Apr 12 10:01:38 2021 +0200
    @@ -0,0 +1,38 @@
    +int err;
    +char *serialdev = LPCBUS_DEVICES_PORT;
    +
    +uartDevWriteBuf_plc_state = EMPTY;
    +uartDevReadBuf_plc_state = EMPTY;
    +bzero(&uartDev, sizeof(uartDev));
    +
    +bzero(&uartDevReadBufA, sizeof(uartDevReadBuf_t));
    +bzero(&uartDevReadBufB, sizeof(uartDevReadBuf_t));
    +uartDevReadBuf_drv = &uartDevReadBufA;
    +uartDevReadBuf_plc = &uartDevReadBufB;
    +
    +bzero(&uartDevWriteBufA, sizeof(uartDevWriteBuf_t));
    +bzero(&uartDevWriteBufB, sizeof(uartDevWriteBuf_t));
    +uartDevWriteBuf_drv = &uartDevWriteBufA;
    +uartDevWriteBuf_plc = &uartDevWriteBufB;
    +
    +bzero(&uartCommStatusBuf, sizeof(uartCommStatusBuf));
    +bzero(&uartCommErrCntBuf, sizeof(uartCommErrCntBuf));
    +
    +%(init_code)s
    +
    +UART_fd = openserial(serialdev, uartBaudrate); /* uartBaudrate is initialized from Composer */
    +if (!UART_fd) {
    + fprintf(stderr, "Error while initializing %%s.\n", serialdev);
    + return 1;
    +}
    +
    +if(uartBufSize == UART_BUFSIZE_LONG) /* uartBufSize is initialized from Composer */
    + InitUartPortDevices_longBuffer();
    +else
    + InitUartPortDevices_shortBuffer();
    +
    +UART_task_active = 1;
    +
    +if(err = pthread_create(&UART_task, NULL, &UART_task_proc, NULL));
    + return err;
    +
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/LPCBus/SOM_Devices_publish.c Mon Apr 12 10:01:38 2021 +0200
    @@ -0,0 +1,19 @@
    +if(!pthread_mutex_lock(&UART_WriteMutex)){
    +
    + int prevstate;
    + prevstate=uartDevWriteBuf_plc_state;
    + uartDevWriteBuf_plc_state = LOCKED;
    +
    + pthread_mutex_unlock(&UART_WriteMutex);
    +
    +%(publish_code)s
    +
    + /* unlock plc buffer */
    + uartDevWriteBuf_plc_state = FULL;
    +
    + /* wakeup task */
    + pthread_mutex_lock(&UART_WakeCondLock);
    + UART_WakeCondValue = 1;
    + pthread_cond_signal(&UART_WakeCond);
    + pthread_mutex_unlock(&UART_WakeCondLock);
    +}
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/LPCBus/SOM_Devices_retrieve.c Mon Apr 12 10:01:38 2021 +0200
    @@ -0,0 +1,19 @@
    +if(!pthread_mutex_lock(&UART_ReadMutex)){
    +
    + int prevstate;
    + if((prevstate=uartDevReadBuf_plc_state) == FULL){
    + uartDevReadBuf_plc_state = LOCKED;
    + }
    +
    + pthread_mutex_unlock(&UART_ReadMutex);
    +
    + if(prevstate == FULL){
    +
    +%(retrieve_code)s
    +
    + /* unlock plc buffer */
    + uartDevReadBuf_plc_state = EMPTY;
    + }else{
    + /* No new data -> no update */
    + }
    +}
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/LPCBus/SOM_OnBoard_cleanup.c Mon Apr 12 10:01:38 2021 +0200
    @@ -0,0 +1,17 @@
    +#ifdef ONBOARD_I2C
    +if(onboardbusfd!=-1)
    + close(onboardbusfd);
    +#endif /* ONBOARD_I2C */
    +
    +#ifdef CAN0_EN_GPIO_0_21
    +gpio_set_pin_value(CAN0_EN_dev, 1);
    +gpio_close(CAN0_EN_dev);
    +#endif /* CAN0_EN_GPIO_0_21 */
    +
    +#ifdef CAN1_EN_GPIO_0_17
    +gpio_set_pin_value(CAN1_EN_dev, 1);
    +gpio_close(CAN1_EN_dev);
    +#endif /* CAN1_EN_GPIO_0_17 */
    +
    +gpio_set_pin_value(RUN_LED_dev, 1);
    +gpio_close(RUN_LED_dev);
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/LPCBus/SOM_OnBoard_decl.c Mon Apr 12 10:01:38 2021 +0200
    @@ -0,0 +1,170 @@
    +#include <unistd.h>
    +#include <fcntl.h>
    +#include <rtdm/rtdm.h>
    +#include "beremiz.h"
    +
    +/*------------------------- GPIO -------------------------------------*/
    +/* from armadeus/target/packages/as_devices/c/as_gpio* */
    +
    +//#ifdef DEBUG
    +# define ERROR(fmt, ...) printf(fmt, ##__VA_ARGS__)
    +//#else
    +//# define ERROR(fmt, ...) /*fmt, ##__VA_ARGS__*/
    +//#endif
    +
    +struct gpio_device {
    + int port_num;
    + int pin_file; /* pin file for 2.6.29 interface*/
    +};
    +
    +struct gpio_device *RUN_LED_dev;
    +#ifdef CAN0_EN_GPIO_0_21
    +struct gpio_device *CAN0_EN_dev;
    +#endif /* CAN0_EN_GPIO_0_21 */
    +#ifdef CAN1_EN_GPIO_0_17
    +struct gpio_device *CAN1_EN_dev;
    +#endif /* CAN1_EN_GPIO_0_17 */
    +
    +static int write_file_bool(int fd, int value)
    +{
    + int ret;
    +
    + ret = write(fd, value?"1":"0", 1);
    + if (ret < 0) {
    + ERROR("write error\n");
    + return ret;
    + }
    + if (lseek(fd, 0, SEEK_SET) < 0) {
    + ERROR("lseek error\n");
    + return ret;
    + }
    +
    + return ret;
    +}
    +
    +#define BUFF_SIZE 256
    +static int gpio_set_pin_value(struct gpio_device *aDev, int aValue)
    +{
    + int pin_file = aDev->pin_file;
    + int retval;
    +
    + retval = write_file_bool(pin_file, aValue);
    + if (retval < 0) {
    + ERROR("Can't write value\n");
    + close(pin_file);
    + return -1;
    + }
    +
    + return aValue;
    +}
    +
    +static struct gpio_device *gpio_open(int aGpioNum)
    +{
    + struct gpio_device *dev;
    + int pin_file;
    + int export_file;
    + int gpio_dir_fd;
    + int retval;
    + char buf[BUFF_SIZE];
    + int ret = 0;
    +
    + export_file = open("/sys/class/gpio/export", O_WRONLY);
    + if (export_file < 0) {
    + ERROR("Can't open /sys/class/gpio/export\nBe sure that gpiolib is under your kernel\n");
    + return NULL;
    + }
    +
    + snprintf(buf, BUFF_SIZE, "%%d", aGpioNum);
    + retval = write(export_file, buf, strlen(buf));
    + close(export_file);
    + if (retval < 0) {
    + ERROR("/sys/class/gpio/export can't be written\n");
    + return NULL;
    + }
    +
    + snprintf(buf, BUFF_SIZE, "/sys/class/gpio/gpio%%d/direction", aGpioNum);
    + gpio_dir_fd = open(buf, O_WRONLY);
    + if (gpio_dir_fd < 0) {
    + ERROR("Can't open gpio%%d direction\n", aGpioNum);
    + return NULL;
    + }
    +
    + ret = write(gpio_dir_fd, "out", 3);
    + close(gpio_dir_fd);
    + if (ret < 0){
    + ERROR("Error writing direction\n");
    + return NULL;
    + }
    +
    + snprintf(buf, BUFF_SIZE, "/sys/class/gpio/gpio%%d/value", aGpioNum);
    + pin_file = open(buf, O_RDWR);
    + if (pin_file < 0) {
    + ERROR("Can't export gpio number %%d\n", aGpioNum);
    + return NULL;
    + }
    +
    + dev = malloc(sizeof(struct gpio_device));
    + if (dev == NULL) {
    + ERROR("Can't allocate gpio_device structure\n");
    + close(pin_file);
    + return NULL;
    + }
    +
    + dev->port_num = aGpioNum;
    + dev->pin_file = pin_file;
    +
    + gpio_set_pin_value(dev, 1);
    +
    + return dev;
    +}
    +
    +static int gpio_close(struct gpio_device *aDev)
    +{
    + int unexport_file;
    + char buf[BUFF_SIZE];
    + int retval;
    +
    + if(aDev == NULL){
    + ERROR("device is NULL\n");
    + return -1;
    + }
    +
    + unexport_file = open("/sys/class/gpio/unexport", O_WRONLY);
    + if (unexport_file < 0) {
    + ERROR("Can't open /sys/class/gpio/unexport\nBe sure that gpiolib is under your kernel\n");
    + return -1;
    + }
    +
    + snprintf(buf, BUFF_SIZE, "%%d", aDev->port_num);
    + retval = write(unexport_file, buf, strlen(buf));
    + close(unexport_file);
    + if (retval < 0) {
    + ERROR("/sys/class/gpio/unexport can't be written\n");
    + return -1;
    + }
    +
    + close(aDev->pin_file);
    +
    + return 0;
    +}
    +
    +/* TODO : DELETE !... but keep this until composer stops sending code snippets for mbrtu */
    +typedef enum
    +{
    + MB_PAR_ODD = 0, /**< ODD parity. */
    + MB_PAR_EVEN = 1, /**< Even parity. */
    + MB_PAR_NONE = 2 /**< No parity. */
    +} eMBSerialParity;
    +unsigned long mbBaudRate = 115200; /**< Modbus baud-rate setting: 9600, 19200, 38400, 57600, 115200 */
    +eMBSerialParity mbParity = MB_PAR_NONE; /**< Modbus parity setting: odd, even, none */
    +
    +#ifdef ONBOARD_I2C
    +
    +#include "rt_imx_smt_onboard.h"
    +
    +static readBuf_t onBoardReadBuf;
    +static writeBuf_t onBoardWriteBuf;
    +static busInit_t onBoardBusInit;
    +
    +static int onboardbusfd = -1;
    +#endif /* ONBOARD_I2C */
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/LPCBus/SOM_OnBoard_init.c Mon Apr 12 10:01:38 2021 +0200
    @@ -0,0 +1,53 @@
    +#define ONBOARDDEVFILENAME "/dev/rtdm/onboard"
    +
    +int err;
    +
    +#ifdef ONBOARD_I2C
    +bzero(&onBoardReadBuf , sizeof(readBuf_t));
    +bzero(&onBoardWriteBuf, sizeof(writeBuf_t));
    +bzero(&onBoardBusInit , sizeof(busInit_t));
    +
    +onBoardBusInit.common_ticktime__ = common_ticktime__;
    +#define onBoardDev (onBoardBusInit.rightI2CMod)
    +#endif /* ONBOARD_I2C */
    +
    +%(init_code)s
    +
    +#ifdef CAN0_EN_GPIO
    +CAN0_EN_dev = gpio_open(CAN0_EN_GPIO);
    +gpio_set_pin_value(CAN0_EN_dev, 0);
    +#endif
    +#ifdef CAN1_EN_GPIO
    +CAN1_EN_dev = gpio_open(CAN1_EN_GPIO);
    +gpio_set_pin_value(CAN1_EN_dev, 0);
    +#endif
    +
    +#ifdef ONBOARD_I2C
    +unsigned char i;
    +for(i=0; i<MAX_RIGHT_MODULES; i++) {
    + switch(onBoardDev[i][1]) {
    + case 1:
    + /* OnBoard I2C bus */
    + onboardbusfd = open(ONBOARDDEVFILENAME, 0);
    + if(onboardbusfd < 0) {
    + printf("can't open %%s rtdm device, %%s\n", ONBOARDDEVFILENAME,
    + strerror(-onboardbusfd));
    + return onboardbusfd;
    + }
    + err = ioctl(onboardbusfd, RTSMT_RTIOC_INIT, &onBoardBusInit);
    + if(err) {
    + printf("error while RTSMT_RTIOC_INIT, %%s\n", strerror(-err));
    + close(onboardbusfd);
    + return err;
    + }
    + break;
    + default:
    + break;
    + }
    +}
    +#endif /* ONBOARD_I2C */
    +
    +#if defined RUN_LED_GPIO
    +RUN_LED_dev = gpio_open(RUN_LED_GPIO);
    +gpio_set_pin_value(RUN_LED_dev, 0);
    +#endif
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/LPCBus/SOM_OnBoard_publish.c Mon Apr 12 10:01:38 2021 +0200
    @@ -0,0 +1,6 @@
    +%(publish_code)s
    +
    +#ifdef ONBOARD_I2C
    +if(onboardbusfd!=-1)
    + ioctl(onboardbusfd, RTSMT_RTIOC_WRITE, &onBoardWriteBuf);
    +#endif /* ONBOARD_I2C */
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/LPCBus/SOM_OnBoard_retrieve.c Mon Apr 12 10:01:38 2021 +0200
    @@ -0,0 +1,6 @@
    +#ifdef ONBOARD_I2C
    +if(onboardbusfd!=-1)
    + ioctl(onboardbusfd, RTSMT_RTIOC_READ, &onBoardReadBuf);
    +#endif /* ONBOARD_I2C */
    +
    +%(retrieve_code)s
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/LPCBus/uC.c Mon Apr 12 10:01:38 2021 +0200
    @@ -0,0 +1,35 @@
    +/* Code generated by LPCBus confnode */
    +
    +/* LPCBus confnode includes */
    +#include "app_glue.h"
    +#ifdef _WINDOWS_H
    + #include "iec_types.h"
    +#else
    + #include "iec_std_lib.h"
    +#endif
    +
    +%(declare_code)s
    +
    +/* LPCBus confnode user variables definition */
    +%(var_decl)s
    +
    +/* LPCBus confnode functions */
    +int __init_%(location_str)s(int argc,char **argv)
    +{
    +%(init_code)s
    + return 0;
    +}
    +
    +void __cleanup_%(location_str)s(void)
    +{
    +}
    +
    +void __retrieve_%(location_str)s(void)
    +{
    +%(retrieve_code)s
    +}
    +
    +void __publish_%(location_str)s(void)
    +{
    +%(publish_code)s
    +}
    --- a/LPCExtension.py Wed Jul 29 10:52:37 2020 +0200
    +++ b/LPCExtension.py Mon Apr 12 10:01:38 2021 +0200
    @@ -8,33 +8,39 @@
    import features
    from POULibrary import SimplePOULibraryFactory
    -from LPCArch import arch, PLC_MC9_modules, PLC_GOT_modules
    +from LPCArch import GetLPCProduct, GetLPCSOM, MC9_modules, WX_GOT_modules, SVG_GOT_modules
    # _lpcmanager_path, arch, etc are defined here because
    # globals() of LPCManager.py are passed to extentions
    +wanted_features_names = ["c_ext", "py_ext", "wxglade_hmi"]
    features.libraries=[('Native', 'NativeLib.NativeLibrary', True)]
    def _poulibpath(name):
    return os.path.join(_lpcmanager_path, 'Pous', "pous"+name+".xml")
    -if arch in PLC_MC9_modules:
    +product = GetLPCProduct()
    +if product in MC9_modules + WX_GOT_modules + SVG_GOT_modules:
    features.libraries += [('Python', 'py_ext.PythonLibrary', True),
    ('RTC', SimplePOULibraryFactory(_poulibpath("RTC")), True)]
    -elif arch in PLC_GOT_modules:
    - features.libraries += [('Python', 'py_ext.PythonLibrary', True),
    - ('RTC', SimplePOULibraryFactory(_poulibpath("RTC")), True),
    - ('GOT', SimplePOULibraryFactory(_poulibpath("GOT")), True)]
    -else:
    + if product in WX_GOT_modules:
    + features.libraries += [('GOT', SimplePOULibraryFactory(_poulibpath("GOT")), True)]
    + if product in SVG_GOT_modules:
    + features.libraries += [('SVGHMI', 'LPCSVGHMI.SVGHMILibrary', True)]
    +else: # MC8 ?
    features.libraries += [('LPC', SimplePOULibraryFactory(_poulibpath("LPC")), True)]
    +
    +if product in WX_GOT_modules:
    + wanted_features_names.extend(["wxglade_hmi"])
    +
    #
    # --------- Configuration Tree Nodes (CTN) catalog extension ------------
    #
    _oldcatalog = features.catalog
    catalog_index = dict(zip(zip(*_oldcatalog)[0],_oldcatalog))
    -wanted_beremiz_features = [catalog_index[feature]
    - for feature in ["c_ext", "py_ext", "wxglade_hmi"]]
    +wanted_beremiz_features = [catalog_index[feature]
    + for feature in wanted_features_names]
    features.catalog = wanted_beremiz_features + [
    ('lpchmi', _('Smarteh HMI'), _('Create customized HMI'), 'lpchmi.LPCHMI'),
    ('bacnet', _('Bacnet support'), _('Map located variables over Bacnet'), 'LPCBACnet.RootClass'),
    @@ -42,6 +48,8 @@
    ('LPCBus', _('LPC bus'), _('Support for Smarteh modules'), 'LPCBus.LPCBus'),
    ('CanOpen', _('CANOpen'), _('Support for CANopen'), 'LPCCanFestival.LPCCanOpen')]
    +if product in SVG_GOT_modules:
    + features.catalog += [ catalog_index['svghmi'][:3]+('LPCSVGHMI.SVGHMI',) ]
    #
    # --------- Connectors Extension ------------
    #
    @@ -67,21 +75,22 @@
    import targets
    from LPCtarget import LPC_target
    +som = GetLPCSOM()
    +if som is not None:
    + targets.targets = {product : {
    + "xsd": os.path.join(_lpcmanager_path, som+"target", "XSD"),
    + "class": targets.targets["Xenomai"]["class"],
    + "code": {"plc_"+som+"_main.c": targets.targets["Xenomai"]["code"]["plc_Xenomai_main.c"],
    + "plc_"+som+"_main_retain.c": os.path.join(_lpcmanager_path,
    + som+"target",
    + "plc_"+som+"_main_retain.c")}}}
    +else:
    + raise NotImplemented
    # targets.targets["LPC"] = {"xsd": os.path.join(_lpcmanager_path, "LPCtarget", "XSD"),
    # "class": lambda: LPC_target,
    # "code": {os.path.join(_lpcmanager_path, "LPCtarget", "plc_LPC_main.c")}}
    # targets.toolchains["makefile"] = os.path.join(_lpcmanager_path, "LPCtarget", "XSD_toolchain_makefile")
    -# for arch in SOM28_modules:
    -
    -targets.targets = {arch : {
    - "xsd": os.path.join(_lpcmanager_path, "SOM28target", "XSD"),
    - "class": targets.targets["Xenomai"]["class"],
    - "code": {"plc_SOM28_main.c": targets.targets["Xenomai"]["code"]["plc_Xenomai_main.c"],
    - "plc_SOM28_main_retain.c": os.path.join(_lpcmanager_path,
    - "SOM28target",
    - "plc_SOM28_main_retain.c")}}}
    -
    #
    # --------- Custom columns function Extension ------------
    #
    @@ -92,3 +101,25 @@
    from WxGladeEditor import WxGladeEditor
    WxGladeHMI.EditorType = WxGladeEditor
    PythonEditor.COLUMNS_TYPE = {'Options': WampOptionsCellEditor}
    +
    +
    +#
    +# --------- special OnChange behavior ------------
    +# ----- on load options and OnChange colums fix --------
    +#
    +
    +from py_ext.PythonFileCTNMixin import PythonFileCTNMixin
    +from OnChangeFromOptions import GetVarOnChangeContent, FixOptions
    +PythonFileCTNMixin.GetVarOnChangeContent = GetVarOnChangeContent
    +
    +old_PythonFileCTNMixin__init__ = PythonFileCTNMixin.__init__
    +def PythonFileCTNMixin__init__with_FixOptions(self):
    + old_PythonFileCTNMixin__init__(self)
    + FixOptions(self)
    +
    +PythonFileCTNMixin.__init__ = PythonFileCTNMixin__init__with_FixOptions
    +
    +
    +
    +
    +
    --- a/LPCManager.py Wed Jul 29 10:52:37 2020 +0200
    +++ b/LPCManager.py Mon Apr 12 10:01:38 2021 +0200
    @@ -22,7 +22,7 @@
    # Path of directory containing current python file
    _lpcmanager_path = os.path.split(__file__)[0]
    -from LPCArch import SetLPCArch
    +from LPCArch import SetLPCProduct
    from Beremiz import BeremizIDELauncher
    class LPCManagerLauncher(BeremizIDELauncher):
    @@ -68,7 +68,7 @@
    self.Usage()
    sys.exit()
    self.arch = args[3]
    - SetLPCArch(self.arch)
    + SetLPCProduct(self.arch)
    # overload with exacltly same code, but this is intended.
    # we want extensions to use globals of this module, not Beremiz.py
    --- a/LPCModbus.py Wed Jul 29 10:52:37 2020 +0200
    +++ b/LPCModbus.py Mon Apr 12 10:01:38 2021 +0200
    @@ -3,8 +3,11 @@
    from __future__ import absolute_import
    from modbus.modbus import _ModbusRTUclientPlug, _ModbusRTUslavePlug, RootClass
    +from LPCArch import GetLPCArch
    wrong_uart_name = "ttyS0"
    -good_uart_name = "ttyAPP3"
    +good_uart_name = {"MC9":"ttyAPP3",
    + "MC10":"ttymxc4"}[GetLPCArch()]
    +
    _ModbusRTUclientPlug.XSD = _ModbusRTUclientPlug.XSD.replace(wrong_uart_name,good_uart_name)
    _ModbusRTUslavePlug.XSD = _ModbusRTUslavePlug.XSD.replace(wrong_uart_name,good_uart_name)
    --- a/LPCProjectController.py Wed Jul 29 10:52:37 2020 +0200
    +++ b/LPCProjectController.py Mon Apr 12 10:01:38 2021 +0200
    @@ -11,7 +11,7 @@
    from HostFirmwareUpdater import HostFirmwareUpdater
    from plcopen.types_enums import ComputeConfigurationResourceName
    -from LPCArch import GetLPCArch
    +from LPCArch import GetLPCProduct
    LPCStatusMethods = [
    {"bitmap": "UpdateFw",
    @@ -28,6 +28,14 @@
    LPCMethodsFromStatus["Stopped"]["_UpdateFw"] = True
    LPCMethodsFromStatus["Empty"]["_UpdateFw"] = True
    +ProjectController.ConfNodeMethods += [
    + {
    + "bitmap": "ALARM",
    + "name": _("Manage alarms"),
    + "tooltip": _("Describe and translate alarms"),
    + "method": "_ManageAlarms"
    + },
    +]
    class LPCProjectController(ProjectController):
    StatusMethods = ProjectController.StatusMethods + LPCStatusMethods
    DefaultMethods = LPCDefaultMethods
    @@ -87,7 +95,7 @@
    return result
    def _Transfer(self):
    - product_name = GetLPCArch().lower().replace("_","")
    + product_name = GetLPCProduct().lower().replace("_","")
    if not self._connector.CheckProductID(product_name):
    message = (_("Product ID doesn't match selected target type.\n"))
    dialog = wx.MessageDialog(
    @@ -162,6 +170,20 @@
    return None
    + def _ManageAlarms(self):
    + dlg = wx.SingleChoiceDialog(
    + self.AppFrame,
    + 'Alarms translations', 'Choose a language to edit:',
    + ['TODO'],
    + wx.CHOICEDLG_STYLE)
    +
    + if dlg.ShowModal() == wx.ID_OK:
    + print('You selected: %s\n' % dlg.GetStringSelection())
    + # TODO XXX
    +
    + dlg.Destroy()
    +
    +
    def _UpdateFw(self):
    """
    Method called by user to flash the firmware of the PLC
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/LPCSVGHMI.py Mon Apr 12 10:01:38 2021 +0200
    @@ -0,0 +1,20 @@
    +
    +from svghmi.svghmi import SVGHMI, SVGHMILibrary
    +
    +browser_commandline = 'qt_webenginewidgets_minimal --js-flags="--max_old_space_size=16 --gc_interval=100 --optimize_for_size" --single-process --no-sandbox http://127.0.0.1:{port}/{name}'
    +
    +# set default values so that COG browser is managed by SVGHMI
    +SVGHMI.XSD = """<?xml version="1.0" encoding="utf-8" ?>
    + <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    + <xsd:element name="SVGHMI">
    + <xsd:complexType>
    + <xsd:attribute name="OnStart" type="xsd:string" use="optional" default='"""+browser_commandline+"""'/>
    + <xsd:attribute name="OnStop" type="xsd:string" use="optional" default="killall qt_webenginewidgets_minimal"/>
    + <xsd:attribute name="OnWatchdog" type="xsd:string" use="optional" default="sh -c 'killall qt_webenginewidgets_minimal; sleep 1; """+\
    + browser_commandline.replace('"', '&quot;')+"""'"/>
    + <xsd:attribute name="WatchdogInitial" type="xsd:integer" use="optional" default="30"/>
    + <xsd:attribute name="WatchdogInterval" type="xsd:integer" use="optional" default="5"/>
    + </xsd:complexType>
    + </xsd:element>
    + </xsd:schema>
    + """
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/OnChangeFromOptions.py Mon Apr 12 10:01:38 2021 +0200
    @@ -0,0 +1,43 @@
    +#!/usr/bin/env python
    +# -*- coding: utf-8 -*-
    +
    +from __future__ import absolute_import
    +
    +from OptionsParsing import ParseOptions, GenOptions
    +
    +@staticmethod
    +def GetVarOnChangeContent(var):
    + """
    + Function to overide the way PythonFileCTNMixin access OnChange column when
    + generating python code
    + """
    + opts = ParseOptions(var.getopts())
    + if opts.is_onchange:
    + new_onchange = []
    + for onchangecall in var.getonchange().split(','):
    + onchangecall = onchangecall.strip()
    + if onchangecall:
    + new_onchange.append(onchangecall)
    + if opts.variable_type_selection == 1 : # "Static"
    + new_onchange += ["StoredValue"]
    + elif opts.variable_type_selection == 3 : # "Alarm"
    + new_onchange += ["Alarm"]
    + return ','.join(new_onchange)
    + return var.getonchange()
    +
    +def FixOptions(self):
    + """
    + Function to be called at the end of PythonFileCTNMixin.__init__()
    + """
    + for var in self.CodeFile.variables.variable:
    + onchanges = [
    + onchange.strip() for onchange in var.getonchange().split(',')]
    + opts = ParseOptions(var.getopts())
    +
    + for unwanted in ["Alarm", "StoredValue"]:
    + if unwanted in onchanges:
    + opts.is_onchange = True
    + onchanges.remove(unwanted)
    +
    + var.setonchange(','.join(onchanges))
    + var.setopts(GenOptions(opts))
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/OptionsParsing.py Mon Apr 12 10:01:38 2021 +0200
    @@ -0,0 +1,82 @@
    +#!/usr/bin/env python
    +# -*- coding: utf-8 -*-
    +from __future__ import absolute_import
    +import re
    +
    +VARIABLETYPE = ["None", "Static", "Session", "Alarm"]
    +opt_parser = re.compile(r'(\w+)\s*(?:=\s*"([^"]+)"\s*|=([^\s]+)\s*)?')
    +
    +class OptionsType(dict):
    + def __init__(self):
    + dict.__init__(self,
    + is_onchange = False,
    + is_scada = False,
    + is_static = False,
    + variable_type_selection = 0,
    + unit = None,
    + min = None,
    + max = None,
    + precision = None,
    + subgroup = None,
    + other = None,
    + tags = None)
    + self.__dict__ = self
    +
    +def GenOptions(opts):
    + options = VARIABLETYPE[opts.variable_type_selection]
    + if options == "None":
    + options = ""
    +
    + if opts.is_onchange:
    + options += " onchange"
    +
    + if opts.is_scada:
    + options += " scada"
    +
    + if opts.is_static:
    + options += " static"
    +
    + if opts.min is not None or opts.max is not None:
    + options += ' min=' + str(opts.min if opts.min is not None else 0)
    + options += ' max=' + str(opts.max if opts.min is not None else 0)
    +
    + if opts.precision:
    + options += ' precision=' + str(opts.precision)
    +
    + for name in ['subgroup', 'unit', 'other', 'tags']:
    + content = opts[name]
    + if content is not None:
    + quoting = '"' if ' ' in content else ''
    + options += ' ' + name + '=' + quoting + content + quoting
    +
    + return options
    +
    +def ParseOptions(opts):
    +
    + res = OptionsType()
    +
    + options = re.findall(opt_parser,opts)
    +
    + for key,dblquote_value,smpl_value in options:
    +
    + value = dblquote_value+smpl_value
    + if value == "":
    + if key == "onchange":
    + res.is_onchange = True
    + elif key in VARIABLETYPE[1:]:
    + res.variable_type_selection = VARIABLETYPE.index(key)
    + elif key == "scada":
    + res.is_scada = True
    + elif key == "static":
    + res.is_static = True
    + else:
    + if key in ["precision", "min","max"]:
    + value = int(value)
    +
    + if key in res:
    + res[key] = value
    + else:
    + raise Exception("Unknown key in options")
    + return res
    +
    +
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/SOM6Target/XSD.template Mon Apr 12 10:01:38 2021 +0200
    @@ -0,0 +1,9 @@
    +<xsd:element name="%(target_name)s">
    + <xsd:complexType>
    + <xsd:attribute name="Compiler" type="xsd:string" use="optional" default="$CC"/>
    + <xsd:attribute name="CFLAGS" type="xsd:string" use="optional" default="$CFLAGS"/>
    + <xsd:attribute name="Linker" type="xsd:string" use="optional" default="$CC"/>
    + <xsd:attribute name="LDFLAGS" type="xsd:string" use="optional" default="$LDFLAGS"/>
    + <xsd:attribute name="XenoConfig" type="xsd:string" use="optional"/>
    + </xsd:complexType>
    +</xsd:element>
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/SOM6Target/plc_SOM6_main_retain.c Mon Apr 12 10:01:38 2021 +0200
    @@ -0,0 +1,328 @@
    +#include <alchemy/event.h>
    +#include <alchemy/mutex.h>
    +/*
    +#include <rtdm/rtdm.h>
    +#include <rtdm/spi_apf28_rtdm_ioctl.h>
    +*/
    +#include <xenomai/init.h>
    +
    +/* SPI configurable parameters */
    +/* --------------------------- */
    +/* SPI CLK MODE */
    +#define TEST_SPI_CLK_PHASE RTDM_SPI_CLKPHASE_LOW
    +#define TEST_SPI_CLK_POLARITY RTDM_SPI_CLKPOLARITY_LOW
    +/* Frequency : 5MHz */
    +#define TEST_SPI_SPEED 20000000
    +/* 16 bits per word */
    +#define TEST_SPI_BITS_PER_WORD RTDM_SPI_8BPW
    +/* Chip selects */
    +#define TEST_SPI_CHIPSELECT1 RTDM_SPI_SS0
    +#define TEST_SPI_CHIPSELECT2 RTDM_SPI_SS0
    +/* Use the DMA from transfer > 4 bytes */
    +#define TEST_SPI_DMA_BYTES_MIN 4
    +
    +#define NVRAM_SIZE 0x8000
    +#define IDLEN 4
    +#define CMDSIZE 3
    +#define RETAIN_BUFFER_SIZE (NVRAM_SIZE - IDLEN)
    +
    +static RT_TASK RETAIN_task;
    +static RT_MUTEX RETAIN_Mutex;
    +static RT_EVENT RETAIN_Event;
    +
    +#pragma pack(push,1)
    +/* Data protected by mutex */
    +static struct priv_s {
    + unsigned char cmd[CMDSIZE];
    + struct buf_s {
    + unsigned char id[IDLEN];
    + unsigned char vars[RETAIN_BUFFER_SIZE];
    + } buf;
    +} priv;
    +#pragma pack(pop)
    +
    +static unsigned short actual_size;
    +static int retain_busy = 0;
    +/* 0 : PLC can update. No SPI transmission undergoing
    + 1 : PLC cannot update. SPI transmission undergoing */
    +
    +static int fd_spi;
    +
    +#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
    +
    +static uint8_t rcmd[] = {
    + /* Read, Addresssse */
    + 0x03, 0x00, 0x00,
    +};
    +
    +int SPI_Read(void *buf, unsigned int len){
    +/*
    + int status;
    + int size;
    + unsigned int uint;
    + uint = 1;
    + if (ioctl(fd_spi, RTDM_SPI_LOCK_CS_SET, &uint) < 0) {
    + printf("Failed to lock CS\n");
    + return 0;
    + }
    +
    + status = write(fd_spi, rcmd, ARRAY_SIZE(rcmd));
    + if (status < 0) {
    + fprintf(stderr, "Failed to send read command. ERR : %d\n", status);
    + return 0;
    + }
    +
    + uint = 0;
    + if (ioctl(fd_spi, RTDM_SPI_LOCK_CS_SET, &uint) < 0) {
    + printf("Failed to unlock CS\n");
    + return 0;
    + }
    +
    + size = read(fd_spi, buf, len);
    + if (size != len) {
    + fprintf(stderr, "Failed to read %d bytes on the SPI bus. size : %d\n",
    + len, size);
    + return 0;
    + }
    +
    + return size;
    + */
    + return -EIO;
    +}
    +
    +int SPI_Write(void *buf, unsigned int len){
    + /*
    + int status;
    + status = write(fd_spi, buf, len);
    + if (status < 0) {
    + fprintf(stderr, "Failed to write memory. ERR : %d\n", status);
    + return 0;
    + }
    + return len;
    + */
    + return -EIO;
    +}
    +
    +static void SPI_init(void)
    +{
    +#if 0
    + unsigned long ulong;
    + unsigned int uint;
    +
    + /* Open the SPI RTDM device */
    + if ((fd_spi = open("/dev/rtdm/spi_apf28_rtdm", 0)) < 0) {
    + printf("rt_spi_open error\n");
    + return;
    + }
    +
    + /* Bus configuration */
    +
    + /* Clock phase */
    + uint = TEST_SPI_CLK_PHASE;
    + if (ioctl(fd_spi, RTDM_SPI_CLKPHASE_SET, &uint) < 0) {
    + printf("Failed to configure the clock phase\n");
    + return;
    + }
    + if (ioctl(fd_spi, RTDM_SPI_CLKPHASE_GET, &uint) < 0) {
    + printf("Failed to get the clock phase\n");
    + return;
    + }
    +
    + /* Clock polarity */
    + uint = TEST_SPI_CLK_POLARITY;
    + if (ioctl(fd_spi, RTDM_SPI_CLKPOLARITY_SET, &uint) < 0) {
    + printf("Failed to configure the clock polarity\n");
    + return;
    + }
    + if (ioctl(fd_spi, RTDM_SPI_CLKPOLARITY_GET, &uint) < 0) {
    + printf("Failed to get the clock polarity\n");
    + return;
    + }
    +
    + /* Frequency */
    + ulong = TEST_SPI_SPEED;
    + if (ioctl(fd_spi, RTDM_SPI_FREQ_SET, &ulong) < 0) {
    + printf("Failed to configure the frequency\n");
    + return;
    + }
    + if (ioctl(fd_spi, RTDM_SPI_FREQ_GET, &ulong) < 0) {
    + printf("Failed to get the frequency\n");
    + return;
    + }
    +
    + /* Bits per word */
    + uint = TEST_SPI_BITS_PER_WORD;
    + if (ioctl(fd_spi, RTDM_SPI_BITSPERWORD_SET, &uint) < 0) {
    + printf("Failed to configure the BPW\n");
    + return;
    + }
    + if (ioctl(fd_spi, RTDM_SPI_BITSPERWORD_GET, &uint) < 0) {
    + printf("Failed to get the BPW\n");
    + return;
    + }
    +
    + /* Chipselect */
    + uint = TEST_SPI_CHIPSELECT1;
    + if (ioctl(fd_spi, RTDM_SPI_CHIPSELECT_SET, &uint) < 0) {
    + printf("Failed to configure the chip select\n");
    + return;
    + }
    + if (ioctl(fd_spi, RTDM_SPI_CHIPSELECT_GET, &uint) < 0) {
    + printf("Failed to get the chip select\n");
    + return;
    + }
    +
    + /* DMA usage definition */
    + uint = TEST_SPI_DMA_BYTES_MIN;
    + if (ioctl(fd_spi, RTDM_SPI_DMA_SET, &uint) < 0) {
    + printf("Failed to configure the DMA threshold\n");
    + return;
    + }
    + if (ioctl(fd_spi, RTDM_SPI_DMA_GET, &uint) < 0) {
    + printf("Failed to get the DMA threshold\n");
    + return;
    + }
    +
    + /* Prepare for future write commands */
    + /* Write Command*/
    + priv.cmd[0] = 0x02;
    + /* Write Addresssse */
    + priv.cmd[1] = 0x00;
    + priv.cmd[2] = 0x00;
    +#endif
    +}
    +
    +int NVRAM_Done = 0;
    +
    +void NVRAM_Init(void){
    + int status;
    + /* Set Sequencial access mode */
    + uint8_t mbuf[] = {
    + /* Mode, Sequ */
    + 0x01, 0x40,
    + };
    +
    + // status = write(fd_spi, mbuf, ARRAY_SIZE(mbuf));
    + status = -EIO;
    + if (status < 0) {
    + printf("RETAIN : Failed to change mode. ERR : %d\n", status);
    + // TODO: remove this !!!
    + NVRAM_Done = 1;
    + return;
    + }
    + /* Read the whole NVRAM at start */
    + SPI_Read(&priv.buf, NVRAM_SIZE);
    + NVRAM_Done = 1;
    +}
    +
    +void RETAIN_task_proc(void *arg)
    +{
    + unsigned int msk = 0;
    + NVRAM_Init();
    +
    + while (!rt_event_wait(&RETAIN_Event, 1, &msk, EV_ANY, TM_INFINITE)) {
    + if(rt_mutex_acquire(&RETAIN_Mutex, TM_INFINITE)) return;
    + SPI_Write(&priv, CMDSIZE + actual_size + IDLEN);
    + if(rt_event_clear(&RETAIN_Event, 1, NULL)) return;
    + if(rt_mutex_release(&RETAIN_Mutex)) return;
    + }
    +}
    +
    +void InitRetain(void) /* TODO return error and care */
    +{
    + retain_busy = 0;
    +
    + if(rt_event_create (&RETAIN_Event, "RETAIN_Event", 0, 0))
    + return;
    + if(rt_mutex_create (&RETAIN_Mutex, "RETAIN_Mutex"))
    + return;
    + if(rt_task_create(&RETAIN_task, "RETAIN_task", 0, 50, T_JOINABLE))
    + return;
    +
    + SPI_init(); /*TODO if error */
    +
    + NVRAM_Done = 0;
    +
    + if(rt_task_start(&RETAIN_task, &RETAIN_task_proc, NULL))
    + return;
    +
    + int count = 1000000;
    + while(!NVRAM_Done && count--){
    + usleep(1);
    + }
    + if(!NVRAM_Done){
    + printf("NVRAM init timeout\n");
    + }
    +}
    +
    +void CleanupRetain(void)
    +{
    +
    + rt_task_delete(&RETAIN_task);
    + rt_task_join(&RETAIN_task);
    + rt_mutex_delete(&RETAIN_Mutex);
    + rt_event_delete(&RETAIN_Event);
    +
    +}
    +
    +void ValidateRetainBuffer(void)
    +{
    + if(retain_busy == 0){
    + if(PLC_ID)
    + memcpy(priv.buf.id, PLC_ID, IDLEN);
    + retain_busy = 1;
    + rt_mutex_release(&RETAIN_Mutex);
    + rt_event_signal(&RETAIN_Event, 1);
    + }
    +}
    +
    +void InValidateRetainBuffer(void)
    +{
    + int ret = rt_mutex_acquire(&RETAIN_Mutex, TM_NONBLOCK);
    + if(ret == -EWOULDBLOCK){
    + /* mutex was unavailable */
    + retain_busy = 1;
    + }else if(ret == 0){
    + /* mutex acquired */
    + /* invalidate that buffer */
    + bzero(&priv.buf.id[0], IDLEN);
    + retain_busy = 0;
    + actual_size = 0;
    + }else{
    + /* error */
    + retain_busy = 1;
    + }
    +
    + //printf("invalidate retain\n");
    +}
    +
    +int CheckRetainBuffer(void)
    +{
    + /* compare RETAIN ID buffer with MD5 */
    + /* return true if identical */
    + if(PLC_ID){
    + int res;
    + res = memcmp(&priv.buf.id[0], PLC_ID, IDLEN) == 0;
    + return res;
    + }else{
    + return 0;
    + }
    +}
    +
    +void Retain(unsigned int offset, unsigned int count, void *p)
    +{
    + if(!retain_busy && offset + count < RETAIN_BUFFER_SIZE){
    + /* write in RETAIN buffer at offset*/
    + actual_size = offset + count;
    + memcpy(&priv.buf.vars[offset], p, count);
    + }
    +}
    +
    +void Remind(unsigned int offset, unsigned int count, void *p)
    +{
    + if(!retain_busy && offset + count < RETAIN_BUFFER_SIZE)
    + /* read at offset in RETAIN buffer */
    + memcpy(p, &priv.buf.vars[offset], count);
    +}
    +
    +
    --- a/VariableExporter.py Wed Jul 29 10:52:37 2020 +0200
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,167 +0,0 @@
    -import wx
    -import csv
    -import os
    -
    -def VariableWriter(parent, event, path):
    - FileDialog = wx.FileDialog(parent, "Save CSV file", "", "", "CSV files (*.csv)|*.csv",
    - wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT)
    - if FileDialog.ShowModal() == wx.ID_OK:
    - if FileDialog.GetPath()[-4:] == ".csv":
    - export = FileDialog.GetPath()
    - else:
    - export = FileDialog.GetPath() + ".csv"
    - else:
    - return
    - parent.Controler.logger.write(_("Exporting to " +export+" ...\n"))
    - modbus_list = []
    - modbus_dict = {}
    - setting_list = []
    - command_list = []
    - bit_dict = {}
    - program_name = ""
    - program_type = ""
    - with open(path + "\plc.xml") as infile:
    - for line in infile:
    - if "<pou" in line:
    - start_program = line.find("name")
    - if start_program != -1:
    - end_program = line[start_program:].find(" ")
    - program_name = line[start_program + 6:start_program + end_program - 1]
    - start_type = line.find("pouType")
    - if start_type != -1:
    - end_type = line[start_type:].find("\"")
    - program_type = line[start_type + 9:start_type + end_type + 8]
    - if ":= UINT_TO_WORD(" in line:
    - idx = line.find(":= UINT_TO_WORD(")
    - end = line[idx:].find(")")
    - name = line[idx + len(":= UINT_TO_WORD("):idx + end]
    - space = line.find(" ")
    - target = line[:space]
    - address = target.split("_")[-1]
    - modbus_list.append(name)
    - modbus_dict[name] = [target, address, program_name, program_type]
    - elif ":= WORD_TO_UINT(" in line and not "UINT_TO_WORD" in line:
    - idx = line.find(":= WORD_TO_UINT(")
    - end = line[idx:].find(")")
    - name = line[idx + len(":= WORD_TO_UINT("):idx + end]
    - space = line.find(" ")
    - target = line[:space]
    - address = name.split("_")[-1]
    - setting_list.append([target, "", "", "", "", name, address])
    - elif ":= WORD_TO_BOOL(" in line:
    - idx = line.find(":= WORD_TO_BOOL(")
    - end = line[idx + len(":= WORD_TO_BOOL("):].find(" ")
    - name = line[idx + len(":= WORD_TO_BOOL("):idx + len(":= WORD_TO_BOOL(") + end]
    - target = line[:idx].strip()
    - address = name.split("_")[-1]
    - bit_start = line.find(" N := ")
    - bit_end = line[bit_start:].find(")")
    - bit = line[bit_start + len(" N := "):bit_start + bit_end]
    - command_list.append([target, "", "", "", "", name, address+"."+bit])
    - elif ":= BOOL_TO_WORD(" in line:
    - idx = line.find(":= BOOL_TO_WORD(") + len(":= BOOL_TO_WORD(")
    - if "UINT_TO_BOOL(" in line[idx:]:
    - idx += len("UINT_TO_BOOL")
    - end = line[idx:].find(")")
    - else:
    - end = line[idx:].find(")")
    - name = line[idx:idx+end]
    - if "(*" in line:
    - target_start = len("(*")
    - else:
    - target_start = 0
    - target_end = line.find(" := ")
    - target = line[target_start:target_end].strip()
    - address = target.split("_")[-1]
    - if " N := " in line:
    - bit_start = line.find(" N := ")
    - bit_end = line[bit_start:].find(")")
    - bit = line[bit_start + len(" N := "):bit_start + bit_end]
    - bit_dict[name] = [target, address+"."+bit, program_name, program_type]
    - else:
    - bit_dict[name] = [target, address, program_name, program_type]
    -
    -
    - dir_list = [os.path.join(path, o) for o in os.listdir(path) if os.path.isdir(os.path.join(path, o))]
    -
    - py_directories = []
    - for dir in dir_list:
    - if dir[-6:] == "py_ext":
    - py_directories.append(dir)
    -
    - variables = [
    - ["NAME", "DESCRIPTION", "TYPE", "GROUP", "SUBGROUP", "TYPE OF VARIABLE", "MODBUS NAME", "MODBUS ADDRESS", "PROGRAM NAME",
    - "PROGRAM TYPE"]]
    - for dir in py_directories:
    - variable_list = []
    - with open(dir + "\pyfile.xml") as infile:
    - for line in infile:
    - curr_variable = []
    - idx_name = line.find("name")
    - name = ""
    - if idx_name != -1:
    - end_name = line[idx_name:].find(" ")
    - name = line[idx_name + 6:idx_name + end_name - 1]
    - curr_variable.append(name)
    - idx_desc = line.find("desc")
    - desc = ""
    - if idx_desc != -1:
    - end_desc = line[idx_desc+7:].find("\"")
    - desc = line[idx_desc + 6:idx_desc + 7 + end_desc]
    - if len(curr_variable) > 0:
    - curr_variable.append(desc)
    - idx_type = line.find("type")
    - group = ""
    - type = ""
    - if idx_type != -1:
    - end_type = line[idx_type:].find(" ")
    - type = line[idx_type + 6:idx_type + end_type - 1]
    - group = dir.split("\\")[-1].split("@")[0]
    - if len(curr_variable) > 0:
    - curr_variable.append(type)
    - curr_variable.append(group)
    - idx_opts = line.find("opts")
    - options = []
    - if idx_opts != -1:
    - end_opts = line[idx_opts + 6:].find("\"")
    - opts = line[idx_opts + 6: idx_opts + end_opts + 6]
    - options = opts.split(" ")
    - o_type = ""
    - subgroup = ""
    - for o in options:
    - if o in ["Session", "Alarm", "Static"]:
    - o_type = o
    - if o == "scada":
    - o_type += " " + o
    - if o == "static":
    - o_type += " " + o
    - idx_subgroup = o.find("subgroup")
    - if idx_subgroup != -1:
    - subgroup = o[idx_subgroup + 9:]
    - if len(curr_variable) > 0:
    - curr_variable.append(subgroup)
    - curr_variable.append(o_type)
    - if len(curr_variable) > 0:
    - if name in modbus_list:
    - curr_variable += modbus_dict[name]
    - elif name in bit_dict:
    - curr_variable += bit_dict[name]
    - else:
    - curr_variable += ["", "", "", ""]
    -
    - if curr_variable != []:
    - variables.append(curr_variable)
    - try:
    - with open(export, "wb") as f:
    - writer = csv.writer(f)
    - writer.writerows(variables)
    - writer = csv.writer(f)
    - writer.writerows([""])
    - writer.writerows(setting_list)
    - writer.writerows([""])
    - writer.writerows(command_list)
    - parent.Controler.logger.write(_("Export completed successfully.\n"))
    - except IOError:
    - dialog = wx.MessageDialog(parent, "File is oppened in another program. Please close it before exporting.", style= wx.OK | wx.ICON_EXCLAMATION)
    - dialog.ShowModal()
    - parent.Controler.logger.write_error(_("Export failed.\n"))
    \ No newline at end of file
    --- a/WampOptionsEditor.py Wed Jul 29 10:52:37 2020 +0200
    +++ b/WampOptionsEditor.py Mon Apr 12 10:01:38 2021 +0200
    @@ -1,10 +1,18 @@
    from __future__ import absolute_import
    +import re
    import wx
    import wx.grid
    import controls
    +from collections import namedtuple
    +from OptionsParsing import ParseOptions, VARIABLETYPE, GenOptions, OptionsType
    +
    [ID_OPTIONSWIZARDDIALOG,ID_ONCHANGE,ID_OPTIONSTYPECHOICE,ID_SUBGROUPTEXT,ID_UNITTEXT,ID_VALUECHECKBOX,ID_MINSPIN,ID_MAXSPIN,ID_PRECISIONSPIN, ID_INITIALSPIN,ID_SCADACHECKBOX,ID_OTHERTEXT,ID_DESCRIPTION,ID_STATIC] = [wx.NewId() for _init_ctrls in range(14)]
    -VARIABLETYPE = ["None", "Static", "Session", "Alarm"]
    +
    +
    +excluded_chars = [ord(i) for i in '\n"']
    +sanitizer = "".join([chr(i if i not in excluded_chars else ord(' ')) for i in xrange(256)])
    +eraser = '\r'
    class WampOptionsEditor(wx.Dialog):
    def _init_sizers(self):
    @@ -34,7 +42,6 @@
    self.minValue=wx.StaticText(self, wx.ID_ANY, _("Min value:"))
    self.maxValue=wx.StaticText(self, wx.ID_ANY, _("Max value:"))
    self.PrecisionValue = wx.StaticText(self, wx.ID_ANY, _("Precision:"))
    - self.InitialValue = wx.StaticText(self, wx.ID_ANY, _("Initial:"))
    self.PropertySizer.AddWindow(self.minValue, flag=wx.ALIGN_CENTER_VERTICAL | wx.LEFT, border=15)
    self.PropertySizer.AddWindow(self.MinSpin, flag=wx.GROW)
    @@ -48,12 +55,8 @@
    self.PropertySizer.AddWindow(wx.StaticText(self, wx.ID_ANY, _("Other:")), flag=wx.ALIGN_CENTER_VERTICAL | wx.LEFT, border=15)
    self.PropertySizer.AddWindow(self.OtherText, flag=wx.GROW)
    - self.PropertySizer.AddWindow(self.InitialValue, flag=wx.ALIGN_CENTER_VERTICAL | wx.LEFT, border=15)
    - self.PropertySizer.AddWindow(self.InitialText, flag=wx.GROW)
    -
    - self.PropertySizer.AddWindow(wx.StaticText(self, wx.ID_ANY, _("Description:")), flag=wx.ALIGN_CENTER_VERTICAL | wx.LEFT, border=15)
    - self.PropertySizer.AddWindow(self.DescriptionText, flag=wx.GROW)
    -
    + self.PropertySizer.AddWindow(wx.StaticText(self, wx.ID_ANY, _("Tags:")), flag=wx.ALIGN_CENTER_VERTICAL | wx.LEFT, border=15)
    + self.PropertySizer.AddWindow(self.Tags, flag=wx.GROW)
    self.PropertySizer.AddGrowableCol(1, 1)
    self.MainSizer.AddSizer(self.PropertySizer, flag=wx.GROW | wx.UP | wx.RIGHT, border=15)
    self.ButtonSizer.AddWindow(self.ClearButton)
    @@ -79,13 +82,12 @@
    self.MinSpin = wx.SpinCtrl(parent=self, id=ID_MINSPIN, style=wx.SP_VERTICAL)
    self.MaxSpin = wx.SpinCtrl(parent=self, id=ID_MAXSPIN, style=wx.SP_VERTICAL)
    self.PrecisionSpin = wx.SpinCtrl(parent=self, id=ID_PRECISIONSPIN, style=wx.SP_VERTICAL)
    - self.InitialText = wx.TextCtrl(parent=self, id=ID_INITIALSPIN)
    self.MinSpin.SetRange(-1000000, 1000000)
    self.MaxSpin.SetRange(-1000000, 1000000)
    self.ScadaCheckbox = wx.CheckBox(parent=self, id=ID_SCADACHECKBOX)
    self.StaticCheckbox = wx.CheckBox(parent=self, id=ID_STATIC)
    self.OtherText = wx.TextCtrl(parent=self, id=ID_OTHERTEXT)
    - self.DescriptionText = wx.TextCtrl(parent=self, id=ID_DESCRIPTION, size=(-1, 100), style=wx.TE_MULTILINE | wx.SUNKEN_BORDER)
    + self.Tags = wx.TextCtrl(parent=self, id=ID_DESCRIPTION, size=(-1, 100), style=wx.TE_MULTILINE|wx.SUNKEN_BORDER)
    self.ClearButton = wx.Button(self, wx.ID_CLEAR, _("Clear"))
    self.ButtonSizer = self.CreateButtonSizer(wx.OK|wx.CANCEL)
    self.ValueCheckbox.Bind(wx.EVT_CHECKBOX, self.EnableValue)
    @@ -98,8 +100,6 @@
    self.MinSpin.Enable(False)
    self.MaxSpin.Enable(False)
    self.PrecisionSpin.Enable(False)
    - self.InitialText.Enable(False)
    - self.DescriptionText.Enable(False)
    self.StaticCheckbox.Enable(False)
    self.Bind(wx.EVT_CHOICE, self.Enabler, self.OptionsTypeChoice)
    @@ -108,16 +108,13 @@
    - def __init__(self, parent, opt, desc):
    - self.TypeSelected = 0
    + def __init__(self, parent, opt):
    self.options = opt
    self.value = ""
    - self.Description = ""
    self.OnChange = False
    self._init_ctrls(parent, opt)
    self._init_sizers()
    - self.SetOptions(opt, desc)
    - self.GetOptions()
    + self.SetOptions(opt)
    self.Enabler(None)
    @@ -132,8 +129,6 @@
    self.OnChangeCheckbox.Enable(True)
    self.ValueCheckbox.Enable(True)
    self.PrecisionSpin.Enable(True)
    - self.InitialText.Enable(True)
    - self.DescriptionText.Enable(True)
    else:
    self.ScadaCheckbox.Enable(True)
    self.OtherText.Enable(True)
    @@ -143,8 +138,6 @@
    self.OnChangeCheckbox.Enable(False)
    self.ValueCheckbox.Enable(True)
    self.PrecisionSpin.Enable(True)
    - self.InitialText.Enable(True)
    - self.DescriptionText.Enable(True)
    if self.OptionsTypeChoice.GetSelection() == 3 and self.ScadaCheckbox.GetValue():
    self.StaticCheckbox.Enable(True)
    @@ -171,9 +164,8 @@
    self.MaxSpin.Enable(False)
    self.StaticCheckbox.Enable(False)
    self.PrecisionSpin.SetValue(0)
    - self.InitialText.SetValue("")
    self.OnChangeCheckbox.SetValue(False)
    - self.DescriptionText.SetValue("")
    + self.Tags.SetValue("")
    self.OnChangeCheckbox.Enable(False)
    self.OtherText.Enable(False)
    self.SubgroupText.Enable(False)
    @@ -183,8 +175,7 @@
    self.MinSpin.Enable(False)
    self.MaxSpin.Enable(False)
    self.PrecisionSpin.Enable(False)
    - self.InitialText.Enable(False)
    - self.DescriptionText.Enable(False)
    + self.Tags.Enable(False)
    self.StaticCheckbox.Enable(False)
    def OnTypeChoice(self, event):
    @@ -193,93 +184,65 @@
    def EnableValue(self, event):
    self.MinSpin.Enable(self.ValueCheckbox.GetValue())
    self.MaxSpin.Enable(self.ValueCheckbox.GetValue())
    + event.Skip()
    - def SetOptions(self, opt, desc):
    - opt1 = opt[0]
    - opt2 = opt[1]
    - opt3 = opt[2]
    - optionsTemp = opt1.split(" ")
    - options = []
    - for el in optionsTemp:
    - options.append(el.split("="))
    - for el in options:
    - if len(el) == 1:
    - if el[0] == "":
    - self.OptionsTypeChoice.SetSelection(0)
    - elif el[0] == "Static":
    - self.OptionsTypeChoice.SetSelection(1)
    - elif el[0] == "Session":
    - self.OptionsTypeChoice.SetSelection(2)
    - elif el[0] == "Alarm":
    - self.OptionsTypeChoice.SetSelection(3)
    - if el[0] == "scada":
    - self.ScadaCheckbox.SetValue(True)
    - if el[0] == "static":
    - self.StaticCheckbox.Enable(True)
    - self.StaticCheckbox.SetValue(True)
    - else:
    - if el[0] == "subgroup":
    - self.SubgroupText.SetValue(el[1])
    - elif el[0] == "unit":
    - self.UnitText.SetValue(el[1])
    - elif el[0] == "min":
    - self.ValueCheckbox.SetValue(True)
    - self.MinSpin.SetValue(int(el[1]))
    - self.MinSpin.Enable(True)
    - elif el[0] == "max":
    - self.ValueCheckbox.SetValue(True)
    - self.MaxSpin.SetValue(int(el[1]))
    - self.MaxSpin.Enable(True)
    - elif el[0] == "other":
    - self.OtherText.SetValue(el[1])
    - elif el[0] == "precision":
    - self.PrecisionSpin.SetValue(int(el[1]))
    - if len(opt2)>0:
    - self.OnChangeCheckbox.Enable(True)
    - self.OnChangeCheckbox.SetValue(True)
    - if self.OptionsTypeChoice.GetSelection() == 3 and self.ScadaCheckbox.GetValue():
    - self.StaticCheckbox.Enable(True)
    - if opt3 != "":
    - self.InitialText.SetValue(opt3)
    - self.DescriptionText.SetValue(desc)
    +
    + def SetOptions(self, opts):
    +
    + res = ParseOptions(opts)
    +
    + self.OptionsTypeChoice.SetSelection(res.variable_type_selection)
    + self.OnChangeCheckbox.SetValue(res.is_onchange)
    + self.ScadaCheckbox.SetValue(res.is_scada)
    + self.StaticCheckbox.SetValue(res.is_static)
    +
    + self.StaticCheckbox.Enable(
    + res.is_static or (res.variable_type_selection == 3 and res.is_scada))
    +
    + if res.subgroup is not None:
    + self.SubgroupText.SetValue(res.subgroup)
    + if res.unit is not None:
    + self.UnitText.SetValue(res.unit)
    + if res.min is not None or res.max is not None:
    + self.ValueCheckbox.SetValue(True)
    + self.MinSpin.Enable(True)
    + self.MaxSpin.Enable(True)
    + self.MinSpin.SetValue(res.min if res.min else 0)
    + self.MaxSpin.SetValue(res.max if res.max else 0)
    +
    + if res.other is not None:
    + self.OtherText.SetValue(res.other)
    + if res.precision is not None:
    + self.PrecisionSpin.SetValue(res.precision)
    +
    + if res.tags is not None:
    + self.Tags.SetValue(res.tags)
    def GetOptions(self):
    - self.TypeSelected = self.OptionsTypeChoice.GetSelection()
    - if self.TypeSelected<0:
    - self.TypeSelected = 0
    - options = VARIABLETYPE[self.TypeSelected]
    - if options == "None":
    - options = ""
    - if self.ScadaCheckbox.GetValue():
    - options += " scada"
    - if self.StaticCheckbox.GetValue():
    - options += " static"
    - if self.SubgroupText.GetLineText(0) != "":
    - options += " subgroup=" + self.SubgroupText.GetLineText(0)
    - if self.UnitText.GetLineText(0) != "":
    - options += " unit=" + self.UnitText.GetLineText(0)
    + opts = OptionsType()
    +
    + opts.variable_type_selection = max(self.OptionsTypeChoice.GetSelection(), 0)
    + opts.is_onchange = self.OnChangeCheckbox.GetValue()
    + opts.is_scada = self.ScadaCheckbox.GetValue()
    + opts.is_static = self.StaticCheckbox.GetValue()
    +
    if self.MinSpin.IsEnabled():
    - options += " min=" + str(self.MinSpin.GetValue())
    - options += " max=" + str(self.MaxSpin.GetValue())
    - if self.PrecisionSpin.GetValue() != 0:
    - options += " precision=" + str(self.PrecisionSpin.GetValue())
    - if self.OtherText.GetLineText(0) != "":
    - options += " other=" + self.OtherText.GetLineText(0)
    - if self.OnChangeCheckbox.GetValue():
    - self.OnChange = True
    - else:
    - self.OnChange = False
    - if VARIABLETYPE[self.TypeSelected] == "Alarm":
    - self.value = "Alarm"
    - elif VARIABLETYPE[self.TypeSelected] == "Static":
    - self.value = "StoredValue"
    - else:
    - self.value = ""
    - self.OnChange = True
    - self.Description = self.DescriptionText.GetValue()
    - self.Initial = self.InitialText.GetValue()
    - return options, self.OnChange,self.value, self.Description, self.Initial
    + opts.min = self.MinSpin.GetValue()
    + opts.max = self.MaxSpin.GetValue()
    +
    + opts.precision = self.PrecisionSpin.GetValue()
    +
    + for name, ctrl in [('subgroup', self.SubgroupText),
    + ('unit', self.UnitText),
    + ('other', self.OtherText),
    + ('tags', self.Tags)]:
    + content = ctrl.GetValue().encode('ascii','ignore').translate(sanitizer,eraser)
    + if content:
    + opts[name] = content
    +
    + return GenOptions(opts)
    +
    class WampOptionsCellControl(wx.PyControl):
    @@ -300,7 +263,7 @@
    # create location text control
    self.Options = wx.TextCtrl(self, size=wx.Size(0, -1),
    style=wx.TE_PROCESS_ENTER)
    - self.Options.Bind(wx.EVT_KEY_DOWN, self.OnDurationChar)
    + self.Options.Bind(wx.EVT_KEY_DOWN, self.OnChar)
    main_sizer.AddWindow(self.Options, flag=wx.GROW)
    # create browse button
    @@ -316,16 +279,6 @@
    self.table = table
    self.row = row
    - def OnDurationChar(self, event):
    - keycode = event.GetKeyCode()
    - if keycode in [wx.WXK_RETURN, wx.WXK_TAB]:
    - self.Parent.Parent.ProcessEvent(event)
    - elif keycode == wx.WXK_ESCAPE:
    - self.Duration.SetValue(self.Default)
    - self.Parent.Parent.CloseEditControl()
    - else:
    - event.Skip()
    -
    def SetValue(self, value):
    self.Default = value
    self.Options.SetValue(value)
    @@ -338,19 +291,15 @@
    def OnEditButtonClick(self, event):
    # pop up the Duration Editor dialog
    - options = [self.GetValue(), self.table.GetValueByName(self.row, "OnChange"), self.table.GetValueByName(self.row, "Initial")]
    - desc = self.table.GetValueByName(self.row, "Description")
    - dialog = WampOptionsEditor(self.parent, options, desc)
    + options = self.GetValue()
    + # backward compatibility
    +
    +
    + dialog = WampOptionsEditor(self.parent, options)
    answer = dialog.ShowModal()
    - opt, OnChange, value, description, initial = dialog.GetOptions()
    + opt = dialog.GetOptions()
    if answer == wx.ID_OK:
    self.SetValue(opt)
    - if OnChange:
    - self.table.SetValueByName(self.row, "OnChange", value)
    - else:
    - self.table.SetValueByName(self.row, "OnChange", "")
    - self.table.SetValueByName(self.row, "Description", description)
    - self.table.SetValueByName(self.row, "Initial", str(initial))
    dialog.Destroy()
    @@ -372,7 +321,7 @@
    class WampOptionsCellEditor(wx.grid.PyGridCellEditor):
    '''
    - Grid cell editor that uses DurationCellControl to display an edit button.
    + Grid cell editor that uses WampOptionsCellControl to display an edit button.
    '''
    def __init__(self, table, row, col):
    @@ -396,21 +345,19 @@
    self.CellControl.SetValue(self.table.GetValueByName(self.row, self.colname))
    self.CellControl.SetFocus()
    - def EndEditInternal(self, row, col, grid, old_duration):
    - duration = self.CellControl.GetValue()
    - changed = duration != old_duration
    - if changed:
    - self.table.SetValueByName(row, self.colname, duration)
    - self.CellControl.Disable()
    - return changed
    - if wx.VERSION >= (3, 0, 0):
    - def EndEdit(self, row, col, grid, oldval):
    - return self.EndEditInternal(row, col, grid, oldval)
    - else:
    - def EndEdit(self, row, col, grid):
    - oldval = self.table.GetValueByName(row, self.colname)
    - return self.EndEditInternal(row, col, grid, oldval)
    + def EndEdit(self, row, col, grid, oldval):
    + value = self.CellControl.GetValue()
    + changed = value != oldval
    + if changed:
    + return value
    + else:
    + return None
    +
    + def ApplyEdit(self, row, col, grid):
    + value = self.CellControl.GetValue()
    + self.table.SetValueByName(row, self.colname, value)
    + self.CellControl.Disable()
    def SetSize(self, rect):
    self.CellControl.SetDimensions(rect.x + 1, rect.y,
    Binary file images/ALARM.png has changed
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/images/genicons.sh Mon Apr 12 10:01:38 2021 +0200
    @@ -0,0 +1,17 @@
    +#!/bin/sh
    +
    +INKSCAPE=inkscape
    +
    +for fname in `ls *.svg`; do
    + for i in `cat $fname |grep -o -e '%%[^%]*%%'|sed 's/%//g'`
    + do
    + if [ $i.png -nt $fname ]; then
    + echo "Skip $i"
    + else
    + rm -f $i.png
    + echo "$INKSCAPE" $fname -z -e $i.png -i $i
    + "$INKSCAPE" $fname -z -e $i.png -i $i
    + fi
    + done
    +done
    +
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/images/icons.svg Mon Apr 12 10:01:38 2021 +0200
    @@ -0,0 +1,127 @@
    +<?xml version="1.0" encoding="UTF-8" standalone="no"?>
    +<!-- Created with Inkscape (http://www.inkscape.org/) -->
    +
    +<svg
    + xmlns:dc="http://purl.org/dc/elements/1.1/"
    + xmlns:cc="http://creativecommons.org/ns#"
    + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    + xmlns:svg="http://www.w3.org/2000/svg"
    + xmlns="http://www.w3.org/2000/svg"
    + xmlns:xlink="http://www.w3.org/1999/xlink"
    + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
    + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
    + version="1.0"
    + width="744.09448"
    + height="1052.3622"
    + id="svg2"
    + sodipodi:version="0.32"
    + inkscape:version="0.92.3 (2405546, 2018-03-11)"
    + sodipodi:docname="icons.svg"
    + inkscape:output_extension="org.inkscape.output.svg.inkscape">
    + <metadata
    + id="metadata13810">
    + <rdf:RDF>
    + <cc:Work
    + rdf:about="">
    + <dc:format>image/svg+xml</dc:format>
    + <dc:type
    + rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
    + <dc:title />
    + </cc:Work>
    + </rdf:RDF>
    + </metadata>
    + <sodipodi:namedview
    + inkscape:window-height="836"
    + inkscape:window-width="1800"
    + inkscape:pageshadow="2"
    + inkscape:pageopacity="0"
    + guidetolerance="10.0"
    + gridtolerance="10000"
    + objecttolerance="10.0"
    + borderopacity="1.0"
    + bordercolor="#666666"
    + pagecolor="#ffffff"
    + id="base"
    + showgrid="false"
    + inkscape:zoom="5.6568543"
    + inkscape:cx="380.11858"
    + inkscape:cy="676.83086"
    + inkscape:window-x="0"
    + inkscape:window-y="27"
    + inkscape:current-layer="g46158"
    + showguides="true"
    + inkscape:guide-bbox="true"
    + inkscape:window-maximized="1"
    + inkscape:measure-start="904.956,703.964"
    + inkscape:measure-end="930.144,704.058">
    + <inkscape:grid
    + type="xygrid"
    + id="grid16717"
    + empspacing="5"
    + visible="true"
    + enabled="true"
    + snapvisiblegridlinesonly="true" />
    + </sodipodi:namedview>
    + <text
    + style="font-style:normal;font-weight:normal;font-size:40.12579727px;line-height:0%;font-family:'Bitstream Vera Sans';fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
    + xml:space="preserve"
    + id="text18397"
    + y="54.610374"
    + x="371.85562"><tspan
    + style="text-align:center;text-anchor:middle"
    + id="tspan18399"
    + y="54.610374"
    + x="371.85562">LPCManager icons</tspan></text>
    + <text
    + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:0%;font-family:'Bitstream Vera Sans';-inkscape-font-specification:'Bitstream Vera Sans';text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
    + xml:space="preserve"
    + id="text60407-68-0"
    + y="360.20483"
    + x="365.61026"><tspan
    + y="360.20483"
    + x="365.61026"
    + id="tspan16195-3-3"
    + sodipodi:role="line"
    + style="font-size:12.76000023px;line-height:1.25">%% ALARM %%</tspan></text>
    + <g
    + id="g46158"
    + transform="matrix(1.5,0,0,1.5,-202.5,-195.93108)"
    + style="stroke-width:0.66666669">
    + <rect
    + width="16"
    + height="16"
    + x="405"
    + y="375.86215"
    + id="ALARM"
    + style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:0;fill-rule:evenodd;stroke:none;stroke-width:0.66666669;marker:none;enable-background:accumulate" />
    + <path
    + inkscape:transform-center-y="-1.9795276"
    + inkscape:transform-center-x="-0.011147353"
    + d="m 420.17779,390.02543 -7.17729,0.0865 -7.17828,-0.0479 3.51374,-6.25895 3.63061,-6.19263 3.66355,6.17246 z"
    + inkscape:randomized="0"
    + inkscape:rounded="0"
    + inkscape:flatsided="false"
    + sodipodi:arg2="1.568032"
    + sodipodi:arg1="0.52090978"
    + sodipodi:r2="4.2112961"
    + sodipodi:r1="8.2882175"
    + sodipodi:cy="385.90063"
    + sodipodi:cx="412.98886"
    + sodipodi:sides="3"
    + id="path19290"
    + style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffcc00;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.44444481;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
    + sodipodi:type="star" />
    + <text
    + transform="scale(1.191303,0.839417)"
    + id="text19292"
    + y="463.00879"
    + x="344.19293"
    + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.66666669"
    + xml:space="preserve"><tspan
    + style="font-size:12.4041214px;line-height:1.25;font-family:sans-serif;stroke-width:0.66666669"
    + y="463.00879"
    + x="344.19293"
    + id="tspan19294"
    + sodipodi:role="line">!</tspan></text>
    + </g>
    +</svg>