2023-11-03 02:07:06 -07:00
|
|
|
|
|
|
|
|
2023-11-03 16:17:02 -07:00
|
|
|
#include <jni.h>
|
|
|
|
|
2023-11-03 02:07:06 -07:00
|
|
|
// OpenBLT host library
|
|
|
|
#include "openblt.h"
|
|
|
|
|
|
|
|
#include <cstring>
|
|
|
|
|
2023-11-03 16:39:56 -07:00
|
|
|
class Callbacks {
|
|
|
|
public:
|
2023-11-03 19:57:58 -07:00
|
|
|
Callbacks(JNIEnv* env, jobject jCallbacks, const char* phaseName, bool hasProgress)
|
2023-11-03 16:39:56 -07:00
|
|
|
: m_env(env)
|
|
|
|
, m_obj(jCallbacks)
|
2023-11-03 19:38:08 -07:00
|
|
|
, m_class(env->FindClass("com/rusefi/maintenance/OpenbltJni$OpenbltCallbacks"))
|
|
|
|
, m_log(env->GetMethodID(m_class, "log", "(Ljava/lang/String;)V"))
|
2023-11-03 19:57:58 -07:00
|
|
|
, m_phase(env->GetMethodID(m_class, "setPhase", "(Ljava/lang/String;Z)V"))
|
2023-11-03 16:39:56 -07:00
|
|
|
, m_updateProgress(env->GetMethodID(m_class, "updateProgress", "(I)V"))
|
2023-11-03 19:38:08 -07:00
|
|
|
, m_error(env->GetMethodID(m_class, "error", "(Ljava/lang/String;)V"))
|
2023-11-03 16:39:56 -07:00
|
|
|
{
|
2023-11-03 19:57:58 -07:00
|
|
|
phase(phaseName, hasProgress);
|
2023-11-03 16:39:56 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void log(const char* line) {
|
|
|
|
jstring jLine = m_env->NewStringUTF(line);
|
|
|
|
m_env->CallObjectMethod(m_obj, m_error, jLine);
|
|
|
|
m_env->DeleteLocalRef(jLine);
|
|
|
|
}
|
|
|
|
|
|
|
|
void updateProgress(int percent) {
|
|
|
|
m_env->CallIntMethod(m_obj, m_updateProgress, percent);
|
|
|
|
}
|
|
|
|
|
|
|
|
void error(const char* err) {
|
|
|
|
jstring jErr = m_env->NewStringUTF(err);
|
|
|
|
m_env->CallObjectMethod(m_obj, m_error, jErr);
|
|
|
|
m_env->DeleteLocalRef(jErr);
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
JNIEnv* const m_env;
|
|
|
|
jobject const m_obj;
|
|
|
|
|
|
|
|
jclass const m_class;
|
|
|
|
|
|
|
|
jmethodID const m_log;
|
2023-11-03 19:57:58 -07:00
|
|
|
jmethodID const m_phase;
|
2023-11-03 16:39:56 -07:00
|
|
|
jmethodID const m_updateProgress;
|
|
|
|
jmethodID const m_error;
|
2023-11-03 19:57:58 -07:00
|
|
|
|
|
|
|
void phase(const char* name, bool hasProgress) {
|
|
|
|
jstring jName = m_env->NewStringUTF(name);
|
|
|
|
m_env->CallObjectMethod(m_obj, m_phase, jName, hasProgress);
|
|
|
|
m_env->DeleteLocalRef(jName);
|
|
|
|
}
|
2023-11-03 16:39:56 -07:00
|
|
|
};
|
|
|
|
|
2023-11-03 18:17:15 -07:00
|
|
|
extern "C" JNIEXPORT void JNICALL Java_com_rusefi_maintenance_OpenbltJni_loadFirmware(JNIEnv* env, jobject, jstring jFilename, jobject jCallbacks) {
|
2023-11-03 19:57:58 -07:00
|
|
|
Callbacks cb(env, jCallbacks, "Load firmware file", false);
|
2023-11-03 16:39:56 -07:00
|
|
|
|
2023-11-03 16:17:02 -07:00
|
|
|
const char* filename = env->GetStringUTFChars(jFilename, 0);
|
|
|
|
|
2023-11-03 02:07:06 -07:00
|
|
|
BltFirmwareInit(BLT_FIRMWARE_PARSER_SRECORD);
|
|
|
|
|
|
|
|
if (BltFirmwareLoadFromFile(filename, 0) != BLT_RESULT_OK) {
|
2023-11-03 16:39:56 -07:00
|
|
|
cb.error("BltFirmwareLoadFromFile() not OK, failed to load firmware file.");
|
|
|
|
return;
|
2023-11-03 02:07:06 -07:00
|
|
|
}
|
|
|
|
|
2023-11-03 16:39:56 -07:00
|
|
|
env->ReleaseStringUTFChars(jFilename, filename);
|
|
|
|
|
2023-11-03 02:07:06 -07:00
|
|
|
// Check that the file isn't empty
|
|
|
|
if (BltFirmwareGetSegmentCount() == 0) {
|
2023-11-03 16:39:56 -07:00
|
|
|
cb.error("BltFirmwareGetSegmentCount() returned 0");
|
|
|
|
return;
|
2023-11-03 02:07:06 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-11-03 16:17:02 -07:00
|
|
|
static tBltSessionSettingsXcpV10 xcpSettings;
|
|
|
|
static tBltTransportSettingsXcpV10Rs232 transportSettings;
|
|
|
|
static char s_portName[256];
|
2023-11-03 02:07:06 -07:00
|
|
|
|
2023-11-03 18:17:15 -07:00
|
|
|
extern "C" JNIEXPORT void JNICALL Java_com_rusefi_maintenance_OpenbltJni_sessionStart(JNIEnv* env, jobject, jstring jSerialPort, jobject jCallbacks) {
|
2023-11-03 19:57:58 -07:00
|
|
|
Callbacks cb(env, jCallbacks, "Start session", false);
|
2023-11-03 16:39:56 -07:00
|
|
|
|
2023-11-03 02:07:06 -07:00
|
|
|
xcpSettings.timeoutT1 = 1000;
|
|
|
|
xcpSettings.timeoutT3 = 2000;
|
|
|
|
xcpSettings.timeoutT4 = 10000;
|
|
|
|
xcpSettings.timeoutT5 = 1000;
|
|
|
|
xcpSettings.timeoutT6 = 50;
|
|
|
|
xcpSettings.timeoutT7 = 2000;
|
|
|
|
xcpSettings.seedKeyFile = nullptr;
|
|
|
|
xcpSettings.connectMode = 0;
|
|
|
|
|
2023-11-03 16:17:02 -07:00
|
|
|
const char* portName = env->GetStringUTFChars(jSerialPort, 0);
|
2023-11-03 02:07:06 -07:00
|
|
|
strncpy(s_portName, portName, sizeof(s_portName));
|
2023-11-03 16:17:02 -07:00
|
|
|
env->ReleaseStringUTFChars(jSerialPort, portName);
|
|
|
|
|
2023-11-03 02:07:06 -07:00
|
|
|
transportSettings.portName = s_portName;
|
|
|
|
transportSettings.baudrate = 115200;
|
|
|
|
|
|
|
|
BltSessionInit(BLT_SESSION_XCP_V10, &xcpSettings, BLT_TRANSPORT_XCP_V10_RS232, &transportSettings);
|
|
|
|
|
|
|
|
if (BltSessionStart() != BLT_RESULT_OK) {
|
2023-11-03 16:39:56 -07:00
|
|
|
cb.error("BltSessionStart() failed");
|
2023-11-03 02:07:06 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-11-03 18:17:15 -07:00
|
|
|
extern "C" JNIEXPORT void JNICALL Java_com_rusefi_maintenance_OpenbltJni_erase(JNIEnv* env, jobject, jobject jCallbacks) {
|
2023-11-03 19:57:58 -07:00
|
|
|
Callbacks cb(env, jCallbacks, "Erase", true);
|
2023-11-03 16:39:56 -07:00
|
|
|
|
2023-11-03 02:07:06 -07:00
|
|
|
int result = 0;
|
|
|
|
|
|
|
|
uint32_t segmentIdx;
|
|
|
|
uint32_t segmentLen;
|
|
|
|
uint32_t segmentBase;
|
|
|
|
uint8_t const * segmentData;
|
|
|
|
|
|
|
|
/* Erase the memory segments on the target that are covered by the firmwware data. */
|
|
|
|
for (segmentIdx = 0; segmentIdx < BltFirmwareGetSegmentCount(); segmentIdx++)
|
|
|
|
{
|
|
|
|
/* Extract segment info. */
|
|
|
|
segmentData = BltFirmwareGetSegment(segmentIdx, &segmentBase, &segmentLen);
|
|
|
|
/* Sanity check. */
|
|
|
|
// Only continue if sanity check passed.
|
|
|
|
if ((segmentData == nullptr) || (segmentLen == 0))
|
|
|
|
{
|
2023-11-03 21:44:53 -07:00
|
|
|
cb.error("BltFirmwareGetSegment not OK");
|
2023-11-03 02:07:06 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Perform erase operation. */
|
|
|
|
|
|
|
|
/* Perform erase operation in chunks, so that a progress update can be shown
|
|
|
|
* and no erase timeout occurs due to erasing too big of a memory range.
|
|
|
|
*/
|
|
|
|
uint32_t const eraseChunkSize = 32768;
|
|
|
|
uint32_t currentEraseCnt;
|
|
|
|
uint32_t currentEraseBase;
|
|
|
|
uint32_t currentEraseResult;
|
|
|
|
uint32_t stillToEraseCnt;
|
|
|
|
|
|
|
|
stillToEraseCnt = segmentLen;
|
|
|
|
currentEraseBase = segmentBase;
|
|
|
|
while (stillToEraseCnt > 0)
|
|
|
|
{
|
|
|
|
/* Determine chunk size. */
|
|
|
|
if (stillToEraseCnt >= eraseChunkSize)
|
|
|
|
{
|
|
|
|
currentEraseCnt = eraseChunkSize;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
currentEraseCnt = stillToEraseCnt;
|
|
|
|
}
|
|
|
|
/* Erase the next chunk from the target's memory. */
|
|
|
|
currentEraseResult = BltSessionClearMemory(currentEraseBase, currentEraseCnt);
|
|
|
|
if (currentEraseResult != BLT_RESULT_OK)
|
|
|
|
{
|
2023-11-03 21:44:53 -07:00
|
|
|
cb.error("BltSessionClearMemory not OK");
|
2023-11-03 02:07:06 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
/* Update loop variables. */
|
|
|
|
currentEraseBase += currentEraseCnt;
|
|
|
|
stillToEraseCnt -= currentEraseCnt;
|
|
|
|
|
|
|
|
uint8_t progressPct = (uint8_t)(((segmentLen - stillToEraseCnt) * 100ul) / segmentLen);
|
2023-11-03 16:39:56 -07:00
|
|
|
cb.updateProgress(progressPct);
|
2023-11-03 02:07:06 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-11-03 18:17:15 -07:00
|
|
|
extern "C" JNIEXPORT void JNICALL Java_com_rusefi_maintenance_OpenbltJni_program(JNIEnv* env, jobject, jobject jCallbacks) {
|
2023-11-03 19:57:58 -07:00
|
|
|
Callbacks cb(env, jCallbacks, "Program", true);
|
2023-11-03 16:39:56 -07:00
|
|
|
|
2023-11-03 02:07:06 -07:00
|
|
|
uint32_t segmentIdx;
|
|
|
|
uint32_t segmentLen;
|
|
|
|
uint32_t segmentBase;
|
|
|
|
uint8_t const * segmentData;
|
|
|
|
|
2023-11-03 21:44:53 -07:00
|
|
|
int lastPercent = -1;
|
|
|
|
|
2023-11-03 02:07:06 -07:00
|
|
|
/* Program the memory segments on the target with the firmware data. */
|
|
|
|
for (segmentIdx = 0; segmentIdx < BltFirmwareGetSegmentCount(); segmentIdx++)
|
|
|
|
{
|
|
|
|
/* Extract segment info. */
|
|
|
|
segmentData = BltFirmwareGetSegment(segmentIdx, &segmentBase, &segmentLen);
|
|
|
|
|
|
|
|
// Only continue if sanity check passed.
|
|
|
|
if ((segmentData == nullptr) || (segmentLen == 0)) {
|
2023-11-03 19:57:58 -07:00
|
|
|
cb.error("BltFirmwareGetSegment not OK");
|
2023-11-03 02:07:06 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Perform write operation in chunks, so that a progress update can be shown. */
|
|
|
|
uint32_t const writeChunkSize = 256;
|
|
|
|
uint32_t currentWriteCnt;
|
|
|
|
uint32_t currentWriteBase;
|
|
|
|
uint8_t const * currentWriteDataPtr;
|
|
|
|
uint32_t currentWriteResult;
|
|
|
|
uint32_t stillToWriteCnt;
|
|
|
|
|
|
|
|
stillToWriteCnt = segmentLen;
|
|
|
|
currentWriteBase = segmentBase;
|
|
|
|
currentWriteDataPtr = segmentData;
|
|
|
|
while (stillToWriteCnt > 0)
|
|
|
|
{
|
|
|
|
/* Determine chunk size. */
|
|
|
|
if (stillToWriteCnt >= writeChunkSize)
|
|
|
|
{
|
|
|
|
currentWriteCnt = writeChunkSize;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
currentWriteCnt = stillToWriteCnt;
|
|
|
|
}
|
|
|
|
/* Write the next data chunk to the target's memory. */
|
|
|
|
currentWriteResult = BltSessionWriteData(currentWriteBase, currentWriteCnt,
|
|
|
|
currentWriteDataPtr);
|
|
|
|
if (currentWriteResult != BLT_RESULT_OK)
|
|
|
|
{
|
2023-11-03 19:57:58 -07:00
|
|
|
cb.error("BltSessionWriteData not OK");
|
2023-11-03 02:07:06 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Update loop variables. */
|
|
|
|
currentWriteBase += currentWriteCnt;
|
|
|
|
currentWriteDataPtr += currentWriteCnt;
|
|
|
|
stillToWriteCnt -= currentWriteCnt;
|
|
|
|
|
2023-11-03 21:44:53 -07:00
|
|
|
int progressPct = (int)(((segmentLen - stillToWriteCnt) * 100ul) / segmentLen);
|
|
|
|
if (progressPct != lastPercent) {
|
|
|
|
cb.updateProgress(progressPct);
|
|
|
|
}
|
|
|
|
lastPercent = progressPct;
|
2023-11-03 02:07:06 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-11-03 19:57:58 -07:00
|
|
|
extern "C" JNIEXPORT void JNICALL Java_com_rusefi_maintenance_OpenbltJni_stop(JNIEnv* env, jobject, jobject jCallbacks) {
|
|
|
|
Callbacks cb(env, jCallbacks, "Cleanup", false);
|
|
|
|
|
2023-11-03 02:07:06 -07:00
|
|
|
BltSessionStop();
|
|
|
|
BltSessionTerminate();
|
|
|
|
BltFirmwareTerminate();
|
|
|
|
}
|