from __future__ import absolute_import
from ProjectController import ProjectController
from FirmwareUpdateDialog import FirmwareUpdateDialog
from HostFirmwareUpdater import HostFirmwareUpdater
from plcopen.types_enums import ComputeConfigurationResourceName
from LPCArch import GetLPCProductDesc
"tooltip": _("Update the PLC firmware"),
LPCDefaultMethods = ProjectController.DefaultMethods.copy()
LPCDefaultMethods["_UpdateFw"]=False
LPCMethodsFromStatus = ProjectController.MethodsFromStatus.copy()
LPCMethodsFromStatus["Started"]["_UpdateFw"] = True
LPCMethodsFromStatus["Stopped"]["_UpdateFw"] = True
LPCMethodsFromStatus["Empty"]["_UpdateFw"] = True
ProjectController.ConfNodeMethods += [
"name": _("Manage alarms"),
"tooltip": _("Describe and translate alarms"),
"method": "_ManageAlarms"
class LPCProjectController(ProjectController):
StatusMethods = ProjectController.StatusMethods + LPCStatusMethods
DefaultMethods = LPCDefaultMethods
MethodsFromStatus = LPCMethodsFromStatus
def __init__(self, frame, logger, buildpath, arch):
self.OrigBuildPath = buildpath
ProjectController.__init__(self, frame, logger)
# Firmware update running status
self.firmwareUpadateIsRunning = False
def GetProjectName(self):
Beremiz uses project directory name as project name
In LPCManager, project name is given as PLCOpen project name
and is passed at startup by SetProjectProperties command
return self.Project.getname()
Zip project files for use in xEye
output_file_path = opj(ops(self._getBuildPath())[0],
self.GetProjectName() + ".xEye")
zf = zipfile.ZipFile(output_file_path, mode='w',
compression=zipfile.ZIP_DEFLATED)
for extrafilespath in [self._getExtraFilesPath(),
self._getProjectFilesPath()]:
dirname = ops(extrafilespath)[-1]
for name in os.listdir(extrafilespath):
zf.write(opj(extrafilespath, str(name)), opj(dirname, str(name)), zipfile.ZIP_DEFLATED)
zf.write(self._builder.bin_path, self._builder.bin)
zf.write(opj(self._getBuildPath(), 'lastbuildPLC.md5'), 'lastbuildPLC.md5')
self.logger.write(_("xEye export file created at: %s\n") % output_file_path)
AutoSave before regular build, and zip for xEye after
if self.ProjectTestModified():
self.AppFrame.RefreshAfterSave()
result = ProjectController._Build(self)
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(
self.AppFrame, message, _("Error"), wx.OK | wx.ICON_ERROR)
return ProjectController._Transfer(self)
def SetProjectName(self, name):
return self.Project.setname(name)
def SetOnlineMode(self, mode, path=None):
# SetOnlineMode is only for MC8
# Update a PLCOpenEditor Pou variable location
def UpdateProjectVariableLocation(self, old_leading, new_leading):
self.Project.updateElementAddress(old_leading, new_leading)
# Update a PLCOpenEditor Pou variable name
def UpdateProjectVariableName(self, old_name, new_name):
self.Project.updateElementName(old_name, new_name)
def RemoveProjectVariableByAddress(self, address):
self.Project.removeVariableByAddress(address)
def RemoveProjectVariableByFilter(self, leading):
self.Project.removeVariableByFilter(leading)
def AddProjectDefaultConfiguration(self, config_name="config", res_name="resource1"):
ProjectController.AddProjectDefaultConfiguration(self, config_name, res_name)
self.SetEditedResourceInfos(
ComputeConfigurationResourceName(config_name, res_name),
def LoadProject(self, ProjectPath, BuildPath=None):
Create plcopen project if plc.xml not found,
so that original LoadProject doesn't make errors.
After regular load, add CanOpen nodes if not already there,
and eventualy save project again.
TargetType is forced to MC9.
plc_file = os.path.join(ProjectPath, "plc.xml")
if not os.path.isfile(plc_file):
self.NewProject(ProjectPath, BuildPath)
ProjectController.LoadProject(self, ProjectPath, BuildPath)
if GetLPCProductDesc().get("CAN", True):
canopen_child = self.GetChildByName("CanOpen")
if canopen_child is None:
canopen = self.CTNAddChild("CanOpen", "CanOpen", 0)
self.SetParamsAttribute('BeremizRoot.TargetType', self.arch)
if self.CTNTestModified():
self.RefreshConfNodesBlockLists()
dlg = wx.SingleChoiceDialog(
'Alarms translations', 'Choose a language to edit:',
if dlg.ShowModal() == wx.ID_OK:
print('You selected: %s\n' % dlg.GetStringSelection())
Method called by user to flash the firmware of the PLC
if self.firmwareUpadateIsRunning == True:
self.logger.write_error(_("Firmware update is already running!\n"))
self.firmwareUpadateIsRunning = True
self.logger.write(_("Firmware update started\n"))
# Launch the firmware selection dialog
dialog = FirmwareUpdateDialog(self.AppFrame)
answer = dialog.ShowModal()
imageFilePath = dialog.GetFirmwareImageFile()
updateType = dialog.GetFirmwareUpdateType()
chunksSize = dialog.GetChunksSize()
if answer == wx.ID_CANCEL:
self.logger.write_error(_("Firmware update canceled!\n"))
self.firmwareUpadateIsRunning = False
if imageFilePath == None or imageFilePath == "":
self.logger.write_error(_("No firmware image file selected!\n"))
self.logger.write_error(_("Firmware update canceled!\n"))
self.firmwareUpadateIsRunning = False
self.logger.write(_("Firmware image file: %s\n") % imageFilePath)
self.logger.write(_("Firmware update type: Linux kernel image\n"))
self.logger.write(_("Firmware update type: Linux DTB image\n"))
self.logger.write(_("Firmware update type: Root file system image\n"))
self.logger.write_error(_("Unknown firmware update type!\n"))
self.logger.write_error(_("Firmware update canceled!\n"))
self.firmwareUpadateIsRunning = False
if chunksSize < 1024 or chunksSize > 1024 * 1024:
self.logger.write_error(_("Bad chunks size : %d KiB!\n") % chunksSize)
self.logger.write_error(_("Firmware update canceled!\n"))
self.firmwareUpadateIsRunning = False
self.logger.write(_("Chunks size : %d KiB\n") % chunksSize)
# Last confirmation before firmware update
answer = wx.MessageBox(_('Are you sure to launch the firmware update for the selected PLC?'),
_('Firmware Update'), wx.YES_NO | wx.CENTRE | wx.NO_DEFAULT,
self.logger.write_error(_("Firmware update canceled!\n"))
self.firmwareUpadateIsRunning = False
# do we still have a connection ?
if self._connector is None:
self.logger.write_error(_("Firmware update canceled because connection lost!\n"))
self.firmwareUpadateIsRunning = False
dlg = wx.ProgressDialog(_("Firmware update"),
_("Updating firmware, please wait."),
# Lauch the firmaware update on the remote PLC
updater = HostFirmwareUpdater(self, imageFilePath, updateType, chunksSize, dlg)
self.logger.write_error(str(e) + "\n")
self.logger.write_error(_("Firmware update failed!\n"))
if not dlg.WasCancelled():
dlg.Update(100, _("Firmware update failed!\n(%s)"%str(e)))
self.firmwareUpadateIsRunning = False
answer = wx.MessageBox(_('Firmware update requires rebooting and reconnecting to complete. Reboot PLC now?'),
_('Firmware Update'), wx.YES_NO | wx.CENTRE | wx.NO_DEFAULT,
self.logger.write(_("Rebooting PLC...\n"))
wx.MessageBox(_('Do not poweroff the device while it is rebooting. Wait until you can connect again to ensure update succeeded.'),
_('WARNING'), wx.OK | wx.CENTRE | wx.NO_DEFAULT,