/*
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License version 3 as published by
the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.cirqwizard.fx.misc;
import javafx.scene.layout.VBox;
import org.cirqwizard.fx.ScreenController;
import org.cirqwizard.logging.LoggerFactory;
import org.cirqwizard.serial.SerialInterface;
import org.cirqwizard.stm32.STM32BootLoaderInterface;
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.concurrent.Service;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.Parent;
import javafx.scene.control.*;
import javafx.stage.FileChooser;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
public class Firmware extends ScreenController implements Initializable
{
@FXML private TextField selectedFile;
@FXML private ProgressBar flashProgress;
@FXML private Button flashButton;
@FXML private CheckBox emergencyReflashCheckbox;
@FXML private Label flashStatusLabel;
@FXML private Label firmwareVersion;
@FXML private VBox fileSelectionBox;
@FXML private VBox progressBarBox;
private static final String ERROR_CLASS_NAME = "error-message";
@Override
protected String getFxmlName()
{
return "Firmware.fxml";
}
@Override
protected String getName()
{
return "Firmware";
}
@Override
public void refresh()
{
selectedFile.setText("");
firmwareVersion.setText("");
flashButton.setDisable(true);
flashStatusLabel.textProperty().unbind();
flashProgress.progressProperty().unbind();
flashProgress.setProgress(0);
fileSelectionBox.setVisible(true);
progressBarBox.setVisible(false);
String currentFirmware = null;
if (getMainApplication().getCNCController() != null)
currentFirmware = getMainApplication().getCNCController().getFirmwareVersion();
if (currentFirmware != null)
firmwareVersion.setText("Current firmware: " + currentFirmware);
else
firmwareVersion.setText("Current firmware: could not get firmware version.");
}
@Override
public void initialize(URL url, ResourceBundle resourceBundle)
{
selectedFile.textProperty().addListener((v, oldV, newV) -> flashButton.setDisable(newV == null || newV.trim().isEmpty()));
}
public void selectFile()
{
FileChooser chooser = new FileChooser();
FileChooser.ExtensionFilter filter = new FileChooser.ExtensionFilter("Firmware files", "*.bin");
chooser.getExtensionFilters().add(filter);
File file = chooser.showOpenDialog(null);
if (file != null)
selectedFile.setText(file.getAbsolutePath());
}
private void setErrorMessage(String message)
{
if (!flashStatusLabel.getStyleClass().contains(ERROR_CLASS_NAME))
flashStatusLabel.getStyleClass().add(ERROR_CLASS_NAME);
flashStatusLabel.setText(message);
}
private void setInfoMessage(String message)
{
if (flashStatusLabel.getStyleClass().contains(ERROR_CLASS_NAME))
flashStatusLabel.getStyleClass().remove(ERROR_CLASS_NAME);
flashStatusLabel.setText(message);
}
public void flash()
{
flashProgress.setVisible(true);
fileSelectionBox.setVisible(false);
progressBarBox.setVisible(true);
flashStatusLabel.setText("");
if (selectedFile.getText().isEmpty())
{
setErrorMessage("Error! No file selected");
return;
}
try
{
FileInputStream inputStream;
inputStream = new FileInputStream(selectedFile.getText());
byte[] bin = new byte[inputStream.available()];
inputStream.read(bin);
setInfoMessage("File opened successfully");
SerialInterface serialInterface = getMainApplication().getSerialInterface();
STM32BootLoaderInterface bootloader = new STM32BootLoaderInterface(serialInterface);
if (!emergencyReflashCheckbox.isSelected())
bootloader.reset();
SerialWriter serialWriter = new SerialWriter(bootloader,bin);
serialWriter.start();
flashProgress.progressProperty().bind(serialWriter.progressProperty());
}
catch (FileNotFoundException e)
{
flashStatusLabel.setText("Error! File not found.");
}
catch (IOException e)
{
flashStatusLabel.setText("Error! Can't read file.");
}
catch (Exception e)
{
LoggerFactory.logException("Could not flash firmware", e);
flashStatusLabel.setText("Error during flashing. Could not flash firmware.");
flashProgress.setVisible(false);
}
}
public class SerialWriter extends Service
{
private byte[] bin;
private STM32BootLoaderInterface bootloader;
public SerialWriter(STM32BootLoaderInterface bootloader, byte[] bin)
{
this.bootloader = bootloader;
this.bin = bin;
}
@Override
protected Task createTask()
{
flashProgress.setVisible(true);
return new SerialWriterTask();
}
private void setStatus(final String msg)
{
Platform.runLater(() -> setInfoMessage(msg));
}
public class SerialWriterTask extends Task
{
@Override
protected Object call() throws Exception
{
try
{
bootloader.initBootloader();
setStatus("Erasing flash...");
bootloader.eraseFlash();
setStatus("Erased. Writing data...");
flashButton.setDisable(false);
for (int i = 0; i < bin.length; i += 256)
{
bootloader.writeSector(bin, i);
updateProgress(i , bin.length);
}
bootloader.restartController();
bootloader.switchOffBootloader();
setStatus("Flash OK.");
}
catch (Exception e)
{
Platform.runLater(() ->
{
setErrorMessage("Communication error");
flashProgress.setVisible(false);
});
LoggerFactory.logException("Communication error:", e);
}
return null;
}
}
}
}