package de.uniluebeck.itm.wsn.drivers.telosb;
import com.google.inject.Inject;
import de.uniluebeck.itm.wsn.drivers.core.exception.FlashEraseFailedException;
import de.uniluebeck.itm.wsn.drivers.core.exception.FlashProgramFailedException;
import de.uniluebeck.itm.wsn.drivers.core.serialport.SerialPortConnection;
import de.uniluebeck.itm.wsn.drivers.core.serialport.SerialPortConnection.SerialPortMode;
import de.uniluebeck.itm.wsn.drivers.core.serialport.SerialPortProgrammingModeInterceptor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class TelosbProgrammingModeInterceptor extends SerialPortProgrammingModeInterceptor {
private static final Logger LOG = LoggerFactory.getLogger(TelosbProgrammingModeInterceptor.class);
@Inject
private BSLTelosb bsl;
@Inject
private SerialPortConnection connection;
@Override
public void enterProgrammingMode() throws Exception {
connection.setSerialPortMode(SerialPortMode.PROGRAM);
// invoke boot loader
startBootLoader(bsl);
// perform mass erase to reset the password to default password
resetPassword(bsl);
// read boot loader version
int bslVersion = readBSLVersion(bsl);
// check if patch is required
if (bslVersion <= 0x0110) {
throw new FlashProgramFailedException("Current BSL version is 1.1 or below, patch is required");
}
// change baud rate to 38000
if (bslVersion >= 0x0160 && !bsl.changeBaudRate(BSLTelosb.BaudRate.Baud38000)) {
LOG.warn("Could not change the baud rate, keeping initial baud rate of 9600.");
}
}
@Override
public void leaveProgrammingMode() throws Exception {
LOG.trace("Leaving programming mode...");
connection.setSerialPortMode(SerialPortMode.NORMAL);
LOG.trace("Programming mode left");
}
private void startBootLoader(BSLTelosb bsl) throws FlashProgramFailedException {
LOG.trace("Starting boot loader...");
if (!bsl.invokeBSL()) {
throw new FlashProgramFailedException("Failed to start boot loader.");
}
}
private void resetPassword(BSLTelosb bsl) throws Exception {
LOG.trace("Erasing flash memory...");
bsl.sendBSLCommand(BSLTelosb.CMD_MASSERASE, 0xFF00, 0xA506, null, false);
final byte[] reply = bsl.receiveBSLReply();
if ((reply[0] & 0xff) == BSLTelosb.DATA_NACK) {
throw new FlashEraseFailedException("Failed to perform mass erase, NACK received.");
} else if (reply.length > 1) {
throw new FlashEraseFailedException("Failed to perform mass erase, reply length unexpected.");
}
// send default password
LOG.trace("Transmitting password...");
if (!bsl.transmitPassword(null, false)) {
throw new FlashProgramFailedException("Failed to transmit password, received NACK.");
}
}
private int readBSLVersion(BSLTelosb bsl) throws Exception {
LOG.trace("Reading BSL version...");
bsl.sendBSLCommand(BSLTelosb.CMD_RXBSLVERSION, 0, 0, null, false);
byte[] reply = bsl.receiveBSLReply();
if (reply.length != 16) {
String replyString = "";
for (int i = 0; i < reply.length; i++) {
replyString += String.format(" 0x%02x ", reply[i]);
}
throw new FlashProgramFailedException(
"Unable to read BSL version, reply length is unexpected: " + replyString
);
}
int deviceId = (((reply[0] & 0xFF) << 8) | (reply[1] & 0xFF));
int bslVersion = (((reply[10] & 0xFF) << 8) | (reply[11] & 0xFF));
if (LOG.isTraceEnabled()) {
LOG.trace(String.format("Current bsl version: %02x.%02x, device id: 0x%04x",
((bslVersion >> 8) & 0xFF),
(bslVersion & 0xFF),
deviceId
)
);
}
return bslVersion;
}
}