/*
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.stm32;
import org.cirqwizard.serial.ExecutionException;
import org.cirqwizard.serial.SerialException;
import org.cirqwizard.serial.SerialInterface;
import java.io.IOException;
public class STM32BootLoaderInterface
{
private static final int CMD_INIT = 0x7F;
private static final int CMD_GET_VERSION = 0x01;
private static final int CMD_EXTENDED_ERASE = 0x44;
private static final int CMD_GET_ID = 0x02;
private static final int CMD_WRITE_FLASH = 0x31;
private static final int CMD_WRITE_UNPROTECT = 0x73;
private static final int CMD_READ_FLASH = 0x11;
private static final int ACK = 0x79;
private static final int CMD_GO = 0x21;
private static final int NACK = 0x1F;
SerialInterface serialInterface;
public STM32BootLoaderInterface(SerialInterface serialInterface)
{
this.serialInterface = serialInterface;
}
public void reset() throws SerialException, ExecutionException
{
try
{
serialInterface.send("$$$reset\r\n", 2000);
Thread.sleep(1000);
}
catch (InterruptedException e)
{
// Interrupted. That's fine
}
}
public void initBootloader() throws BootloaderException
{
try
{
serialInterface.setBootloaderMode(true);
serialInterface.write(CMD_INIT);
int response = serialInterface.readByte();
if (response != ACK && response != NACK)
throw new BootloaderException("Unexpected response received: " + response);
}
catch (Exception e)
{
throw new BootloaderException(e);
}
}
public void switchOffBootloader() throws SerialException
{
try
{
serialInterface.setBootloaderMode(false);
}
catch (SerialException e)
{
throw new SerialException(e);
}
}
private void sendCommand(int command) throws BootloaderException
{
try
{
serialInterface.write(command);
serialInterface.write(~command);
}
catch (IOException e)
{
throw new BootloaderException(e);
}
}
private void sendPacket(byte[] packet) throws BootloaderException
{
try
{
int checksum = 0;
serialInterface.write(packet);
for (int i = 0; i < packet.length; i++)
checksum ^= packet[i];
serialInterface.write(checksum);
}
catch (IOException e)
{
throw new BootloaderException(e);
}
}
private void sendAddress(int address) throws BootloaderException
{
byte[] b = new byte[4];
b[0] = (byte)(address >> 24);
b[1] = (byte)((address >> 16) & 0xFF);
b[2] = (byte)((address >> 8) & 0xFF);
b[3] = (byte)(address & 0xFF);
sendPacket(b);
}
public int getChipId() throws BootloaderException
{
try
{
sendCommand(CMD_GET_ID);
if (serialInterface.readByte() != ACK)
throw new BootloaderException("Command not acknowledged");
if (serialInterface.readByte() != 1)
throw new BootloaderException("Unexpected response");
int id = (serialInterface.readByte() << 8) | serialInterface.readByte();
if (serialInterface.readByte() != ACK)
throw new BootloaderException("Command not acknowledged");
return id;
}
catch (IOException e)
{
throw new BootloaderException(e);
}
}
public int getVersion() throws BootloaderException
{
try
{
sendCommand(CMD_GET_VERSION);
if (serialInterface.readByte() != ACK)
throw new BootloaderException("Command not acknowledged");
int version = serialInterface.readByte();
serialInterface.readByte();
serialInterface.readByte();
if (serialInterface.readByte() != ACK)
throw new BootloaderException("Command not acknowledged");
return version;
}
catch (IOException e)
{
throw new BootloaderException(e);
}
}
public void unprotectWrite() throws BootloaderException
{
try
{
sendCommand(CMD_WRITE_UNPROTECT);
if (serialInterface.readByte() != ACK)
throw new BootloaderException("Command not acknowledged");
if (serialInterface.readByte() != ACK)
throw new BootloaderException("Command not acknowledged");
}
catch (IOException e)
{
throw new BootloaderException(e);
}
}
public void eraseFlash() throws BootloaderException
{
try
{
sendCommand(CMD_EXTENDED_ERASE);
if (serialInterface.readByte() != ACK)
throw new BootloaderException("Command not acknowledged");
serialInterface.write(0xFF);
serialInterface.write(0xFF);
serialInterface.write(0x00);
if (serialInterface.readByte() != ACK)
throw new BootloaderException("Command not acknowledged");
}
catch (IOException e)
{
throw new BootloaderException(e);
}
}
public void restartController() throws BootloaderException
{
try
{
sendCommand(CMD_GO);
if (serialInterface.readByte() != ACK)
throw new BootloaderException("Command not acknowledged");
sendAddress(0x08000000);
if (serialInterface.readByte() != ACK)
throw new BootloaderException("Command not acknowledged");
}
catch (IOException e)
{
throw new BootloaderException(e);
}
}
public void writeSector(byte[] bin, int offset) throws BootloaderException
{
try
{
sendCommand(CMD_WRITE_FLASH);
if (serialInterface.readByte() != ACK)
throw new BootloaderException("Command not acknowledged");
sendAddress(0x08000000 + offset);
if (serialInterface.readByte() != ACK)
throw new BootloaderException("Command not acknowledged");
int bytesToWrite = Math.min(bin.length - offset, 256);
byte[] b = new byte[bytesToWrite + 1];
b[0] = (byte)(bytesToWrite - 1);
System.arraycopy(bin, offset, b, 1, bytesToWrite);
sendPacket(b);
if (serialInterface.readByte() != ACK)
throw new BootloaderException("Command not acknowledged");
}
catch (IOException e)
{
throw new BootloaderException(e);
}
}
}