From 90f2b4ded345de63fea82b5d53abf257b4c19964 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Fri, 17 Apr 2015 00:57:50 +0200 Subject: [PATCH] Pebble app installation: Use data (filenames, sizes and crc) from manifest.json (Fixes #16) Also remove STM32CRC.java, which had broken tail code, we use the crc from the manifest now. --- .../gadgetbridge/pebble/PBWReader.java | 90 +++++--- .../pebble/PebbleInstallable.java | 31 +++ .../gadgetbridge/pebble/PebbleIoThread.java | 216 +++++++++--------- .../gadgetbridge/pebble/STM32CRC.java | 152 ------------ 4 files changed, 189 insertions(+), 300 deletions(-) create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/pebble/PebbleInstallable.java delete mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/pebble/STM32CRC.java diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/pebble/PBWReader.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/pebble/PBWReader.java index dcce0a2b1..03266c5f7 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/pebble/PBWReader.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/pebble/PBWReader.java @@ -3,6 +3,7 @@ package nodomain.freeyourgadget.gadgetbridge.pebble; import android.content.ContentResolver; import android.content.Context; import android.net.Uri; +import android.util.Log; import org.json.JSONException; import org.json.JSONObject; @@ -19,10 +20,12 @@ import java.util.zip.ZipInputStream; import nodomain.freeyourgadget.gadgetbridge.GBDeviceApp; public class PBWReader { + private static final String TAG = PebbleIoThread.class.getSimpleName(); + private GBDeviceApp app; private final Uri uri; private final ContentResolver cr; - private ArrayList filesToInstall; + private ArrayList pebbleInstallables; public PBWReader(Uri uri, Context context) { this.uri = uri; @@ -37,21 +40,65 @@ public class PBWReader { return; } ZipInputStream zis = new ZipInputStream(fin); - ZipEntry ze = null; - filesToInstall = new ArrayList(); + ZipEntry ze; + pebbleInstallables = new ArrayList(); + byte[] buffer = new byte[1024]; + int count; try { while ((ze = zis.getNextEntry()) != null) { String fileName = ze.getName(); - if (fileName.equals("pebble-app.bin") || fileName.equals("pebble-worker.bin") || fileName.equals("app_resources.pbpack") || fileName.equals("")) { - filesToInstall.add(fileName); // FIXME: do not hardcode filenames above + if (fileName.equals("manifest.json")) { + long bytes = ze.getSize(); + if (bytes > 8192) // that should be too much + break; + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + while ((count = zis.read(buffer)) != -1) { + baos.write(buffer, 0, count); + } + + String jsonString = baos.toString(); + try { + JSONObject json = new JSONObject(jsonString); + JSONObject application = json.getJSONObject("application"); + + String name = application.getString("name"); + int size = application.getInt("size"); + long crc = application.getLong("crc"); + pebbleInstallables.add(new PebbleInstallable(name, size, (int) crc, PebbleProtocol.PUTBYTES_TYPE_BINARY)); + Log.i(TAG, "found app binary to install: " + name); + try { + JSONObject resources = json.getJSONObject("resources"); + name = resources.getString("name"); + size = resources.getInt("size"); + crc = resources.getLong("crc"); + pebbleInstallables.add(new PebbleInstallable(name, size, (int) crc, PebbleProtocol.PUTBYTES_TYPE_RESOURCES)); + Log.i(TAG, "found resources to install: " + name); + } catch (JSONException e) { + // no resources, that is no problem + } + try { + JSONObject worker = json.getJSONObject("worker"); + name = worker.getString("name"); + size = worker.getInt("size"); + crc = worker.getLong("crc"); + pebbleInstallables.add(new PebbleInstallable(name, size, (int) crc, PebbleProtocol.PUTBYTES_TYPE_WORKER)); + Log.i(TAG, "found worker to install: " + name); + } catch (JSONException e) { + // no worker, that is no problem + } + } catch (JSONException e) { + // no application, that is a problem + e.printStackTrace(); + break; + } + } else if (fileName.equals("appinfo.json")) { long bytes = ze.getSize(); if (bytes > 8192) // that should be too much break; ByteArrayOutputStream baos = new ByteArrayOutputStream(); - byte[] buffer = new byte[1024]; - int count; while ((count = zis.read(buffer)) != -1) { baos.write(buffer, 0, count); } @@ -108,33 +155,8 @@ public class PBWReader { return null; } - public int getFileSize(String filename) { - InputStream fin = null; - try { - fin = new BufferedInputStream(cr.openInputStream(uri)); - - } catch (FileNotFoundException e) { - e.printStackTrace(); - return -1; - } - - ZipInputStream zis = new ZipInputStream(fin); - ZipEntry ze = null; - try { - while ((ze = zis.getNextEntry()) != null) { - if (ze.getName().equals(filename)) { - return (int) ze.getSize(); - } - } - zis.close(); - } catch (IOException e) { - e.printStackTrace(); - } - return -1; - } - - public String[] getFilesToInstall() { - return filesToInstall.toArray(new String[filesToInstall.size()]); + public PebbleInstallable[] getPebbleInstallables() { + return pebbleInstallables.toArray(new PebbleInstallable[pebbleInstallables.size()]); } } \ No newline at end of file diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/pebble/PebbleInstallable.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/pebble/PebbleInstallable.java new file mode 100644 index 000000000..6e3ea324a --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/pebble/PebbleInstallable.java @@ -0,0 +1,31 @@ +package nodomain.freeyourgadget.gadgetbridge.pebble; + +public class PebbleInstallable { + final private byte type; + final private int crc; + final private String fileName; + final private int fileSize; + + public PebbleInstallable(String fileName, int fileSize, int crc, byte type) { + this.fileName = fileName; + this.fileSize = fileSize; + this.crc = crc; + this.type = type; + } + + public String getFileName() { + return fileName; + } + + public int getFileSize() { + return fileSize; + } + + public byte getType() { + return type; + } + + public int getCRC() { + return crc; + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/pebble/PebbleIoThread.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/pebble/PebbleIoThread.java index 55e26e61c..30d8a806a 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/pebble/PebbleIoThread.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/pebble/PebbleIoThread.java @@ -48,31 +48,32 @@ public class PebbleIoThread extends GBDeviceIoThread { APP_REFRESH, } - private final PebbleProtocol mmPebbleProtocol; + private final PebbleProtocol mPebbleProtocol; private BluetoothAdapter mBtAdapter = null; private BluetoothSocket mBtSocket = null; - private InputStream mmInStream = null; - private OutputStream mmOutStream = null; - private boolean mmQuit = false; - private boolean mmIsConnected = false; - private boolean mmIsInstalling = false; - private int mmConnectionAttempts = 0; + private InputStream mInStream = null; + private OutputStream mOutStream = null; + private boolean mQuit = false; + private boolean mIsConnected = false; + private boolean mIsInstalling = false; + private int mConnectionAttempts = 0; /* app installation */ - private Uri mmInstallURI = null; - private PBWReader mmPBWReader = null; - private int mmAppInstallToken = -1; - private ZipInputStream mmZis = null; - private STM32CRC mmSTM32CRC = new STM32CRC(); - private PebbleAppInstallState mmInstallState = PebbleAppInstallState.UNKNOWN; - private String[] mmFilesToInstall = null; - private int mmCurrentFileIndex = -1; - private int mmInstallSlot = -1; + private Uri mInstallURI = null; + private PBWReader mPBWReader = null; + private int mAppInstallToken = -1; + private ZipInputStream mZis = null; + private PebbleAppInstallState mInstallState = PebbleAppInstallState.UNKNOWN; + private PebbleInstallable[] mPebbleInstallables = null; + private PebbleInstallable mPebbleInstallable = null; + private int mCurrentInstallableIndex = -1; + private int mInstallSlot = -1; + private int mCRC = -1; public PebbleIoThread(GBDevice gbDevice, GBDeviceProtocol gbDeviceProtocol, BluetoothAdapter btAdapter, Context context) { super(gbDevice, context); - mmPebbleProtocol = (PebbleProtocol) gbDeviceProtocol; + mPebbleProtocol = (PebbleProtocol) gbDeviceProtocol; mBtAdapter = btAdapter; } @@ -83,13 +84,13 @@ public class PebbleIoThread extends GBDeviceIoThread { try { mBtSocket = btDevice.createRfcommSocketToServiceRecord(uuids[0].getUuid()); mBtSocket.connect(); - mmInStream = mBtSocket.getInputStream(); - mmOutStream = mBtSocket.getOutputStream(); + mInStream = mBtSocket.getInputStream(); + mOutStream = mBtSocket.getOutputStream(); } catch (IOException e) { e.printStackTrace(); gbDevice.setState(originalState); - mmInStream = null; - mmOutStream = null; + mInStream = null; + mOutStream = null; mBtSocket = null; return false; } @@ -101,99 +102,85 @@ public class PebbleIoThread extends GBDeviceIoThread { } public void run() { - mmIsConnected = connect(gbDevice.getAddress()); - GB.setReceiversEnableState(mmIsConnected, getContext()); // enable/disable BroadcastReceivers - mmQuit = !mmIsConnected; // quit if not connected + mIsConnected = connect(gbDevice.getAddress()); + GB.setReceiversEnableState(mIsConnected, getContext()); // enable/disable BroadcastReceivers + mQuit = !mIsConnected; // quit if not connected byte[] buffer = new byte[8192]; int bytes; - while (!mmQuit) { + while (!mQuit) { try { - if (mmIsInstalling) { - switch (mmInstallState) { + if (mIsInstalling) { + switch (mInstallState) { case APP_WAIT_SLOT: - if (mmInstallSlot != -1) { + if (mInstallSlot != -1) { GB.updateNotification("starting installation", getContext()); - mmInstallState = PebbleAppInstallState.APP_START_INSTALL; + mInstallState = PebbleAppInstallState.APP_START_INSTALL; continue; } break; case APP_START_INSTALL: Log.i(TAG, "start installing app binary"); - mmSTM32CRC.reset(); - if (mmPBWReader == null) { - mmPBWReader = new PBWReader(mmInstallURI, getContext()); - mmFilesToInstall = mmPBWReader.getFilesToInstall(); - mmCurrentFileIndex = 0; + if (mPBWReader == null) { + mPBWReader = new PBWReader(mInstallURI, getContext()); + mPebbleInstallables = mPBWReader.getPebbleInstallables(); + mCurrentInstallableIndex = 0; } - String fileName = mmFilesToInstall[mmCurrentFileIndex]; - mmZis = mmPBWReader.getInputStreamFile(fileName); - int binarySize = mmPBWReader.getFileSize(fileName); - // FIXME: do not assume type from filename, parse json correctly in PBWReader - byte type = -1; - if (fileName.equals("pebble-app.bin")) { - type = PebbleProtocol.PUTBYTES_TYPE_BINARY; - } else if (fileName.equals("pebble-worker.bin")) { - type = PebbleProtocol.PUTBYTES_TYPE_WORKER; - } else if (fileName.equals("app_resources.pbpack")) { - type = PebbleProtocol.PUTBYTES_TYPE_RESOURCES; - } else { - finishInstall(true); - break; - } - - writeInstallApp(mmPebbleProtocol.encodeUploadStart(type, (byte) mmInstallSlot, binarySize)); - mmInstallState = PebbleAppInstallState.APP_WAIT_TOKEN; + PebbleInstallable pi = mPebbleInstallables[mCurrentInstallableIndex]; + mZis = mPBWReader.getInputStreamFile(pi.getFileName()); + mCRC = pi.getCRC(); + int binarySize = pi.getFileSize(); // TODO: use for progrssbar + writeInstallApp(mPebbleProtocol.encodeUploadStart(pi.getType(), (byte) mInstallSlot, binarySize)); + mInstallState = PebbleAppInstallState.APP_WAIT_TOKEN; break; case APP_WAIT_TOKEN: - if (mmAppInstallToken != -1) { - Log.i(TAG, "got token " + mmAppInstallToken); - mmInstallState = PebbleAppInstallState.APP_UPLOAD_CHUNK; + if (mAppInstallToken != -1) { + Log.i(TAG, "got token " + mAppInstallToken); + mInstallState = PebbleAppInstallState.APP_UPLOAD_CHUNK; continue; } break; case APP_UPLOAD_CHUNK: - bytes = mmZis.read(buffer); + bytes = mZis.read(buffer); if (bytes != -1) { - mmSTM32CRC.addData(buffer, bytes); - writeInstallApp(mmPebbleProtocol.encodeUploadChunk(mmAppInstallToken, buffer, bytes)); - mmAppInstallToken = -1; - mmInstallState = PebbleAppInstallState.APP_WAIT_TOKEN; + writeInstallApp(mPebbleProtocol.encodeUploadChunk(mAppInstallToken, buffer, bytes)); + mAppInstallToken = -1; + mInstallState = PebbleAppInstallState.APP_WAIT_TOKEN; } else { - mmInstallState = PebbleAppInstallState.APP_UPLOAD_COMMIT; + mInstallState = PebbleAppInstallState.APP_UPLOAD_COMMIT; continue; } break; case APP_UPLOAD_COMMIT: - writeInstallApp(mmPebbleProtocol.encodeUploadCommit(mmAppInstallToken, mmSTM32CRC.getResult())); - mmAppInstallToken = -1; - mmInstallState = PebbleAppInstallState.APP_WAIT_COMMMIT; + writeInstallApp(mPebbleProtocol.encodeUploadCommit(mAppInstallToken, mCRC)); + mAppInstallToken = -1; + mInstallState = PebbleAppInstallState.APP_WAIT_COMMMIT; break; case APP_WAIT_COMMMIT: - if (mmAppInstallToken != -1) { - Log.i(TAG, "got token " + mmAppInstallToken); - mmInstallState = PebbleAppInstallState.APP_UPLOAD_COMPLETE; + if (mAppInstallToken != -1) { + Log.i(TAG, "got token " + mAppInstallToken); + mInstallState = PebbleAppInstallState.APP_UPLOAD_COMPLETE; continue; } break; case APP_UPLOAD_COMPLETE: - writeInstallApp(mmPebbleProtocol.encodeUploadComplete(mmAppInstallToken)); - if (++mmCurrentFileIndex < mmFilesToInstall.length) { - mmInstallState = PebbleAppInstallState.APP_START_INSTALL; + writeInstallApp(mPebbleProtocol.encodeUploadComplete(mAppInstallToken)); + if (++mCurrentInstallableIndex < mPebbleInstallables.length) { + mInstallState = PebbleAppInstallState.APP_START_INSTALL; } else { - mmInstallState = PebbleAppInstallState.APP_REFRESH; + mInstallState = PebbleAppInstallState.APP_REFRESH; } break; case APP_REFRESH: - writeInstallApp(mmPebbleProtocol.encodeAppRefresh(mmInstallSlot)); + writeInstallApp(mPebbleProtocol.encodeAppRefresh(mInstallSlot)); break; default: break; } } - bytes = mmInStream.read(buffer, 0, 4); + bytes = mInStream.read(buffer, 0, 4); if (bytes < 4) continue; @@ -203,13 +190,13 @@ public class PebbleIoThread extends GBDeviceIoThread { short endpoint = buf.getShort(); if (length < 0 || length > 8192) { Log.i(TAG, "invalid length " + length); - while (mmInStream.available() > 0) { - mmInStream.read(buffer); // read all + while (mInStream.available() > 0) { + mInStream.read(buffer); // read all } continue; } - bytes = mmInStream.read(buffer, 4, length); + bytes = mInStream.read(buffer, 4, length); if (bytes < length) { try { Thread.sleep(100); @@ -217,23 +204,23 @@ public class PebbleIoThread extends GBDeviceIoThread { e.printStackTrace(); } Log.i(TAG, "Read " + bytes + ", expected " + length + " reading remaining " + (length - bytes)); - int bytes_rest = mmInStream.read(buffer, 4 + bytes, length - bytes); + int bytes_rest = mInStream.read(buffer, 4 + bytes, length - bytes); bytes += bytes_rest; } if (length == 1 && endpoint == PebbleProtocol.ENDPOINT_PHONEVERSION) { Log.i(TAG, "Pebble asked for Phone/App Version - repLYING!"); - write(mmPebbleProtocol.encodePhoneVersion(PebbleProtocol.PHONEVERSION_REMOTE_OS_ANDROID)); - write(mmPebbleProtocol.encodeFirmwareVersionReq()); + write(mPebbleProtocol.encodePhoneVersion(PebbleProtocol.PHONEVERSION_REMOTE_OS_ANDROID)); + write(mPebbleProtocol.encodeFirmwareVersionReq()); // this does not really belong here, but since the pebble only asks for our version once it should do the job SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(getContext()); if (sharedPrefs.getBoolean("datetime_synconconnect", true)) { Log.i(TAG, "syncing time"); - write(mmPebbleProtocol.encodeSetTime(-1)); + write(mPebbleProtocol.encodeSetTime(-1)); } } else if (endpoint != PebbleProtocol.ENDPOINT_DATALOG) { - GBDeviceCommand deviceCmd = mmPebbleProtocol.decodeResponse(buffer); + GBDeviceCommand deviceCmd = mPebbleProtocol.decodeResponse(buffer); if (deviceCmd == null) { Log.i(TAG, "unhandled message to endpoint " + endpoint + " (" + bytes + " bytes)"); } else { @@ -252,23 +239,23 @@ public class PebbleIoThread extends GBDeviceIoThread { gbDevice.sendDeviceUpdateIntent(getContext()); GB.updateNotification("connection lost, trying to reconnect", getContext()); - while (mmConnectionAttempts++ < 10) { - Log.i(TAG, "Trying to reconnect (attempt " + mmConnectionAttempts + ")"); - mmIsConnected = connect(gbDevice.getAddress()); - if (mmIsConnected) + while (mConnectionAttempts++ < 10) { + Log.i(TAG, "Trying to reconnect (attempt " + mConnectionAttempts + ")"); + mIsConnected = connect(gbDevice.getAddress()); + if (mIsConnected) break; } - mmConnectionAttempts = 0; - if (!mmIsConnected) { + mConnectionAttempts = 0; + if (!mIsConnected) { mBtSocket = null; GB.setReceiversEnableState(false, getContext()); Log.i(TAG, "Bluetooth socket closed, will quit IO Thread"); - mmQuit = true; + mQuit = true; } } } } - mmIsConnected = false; + mIsConnected = false; if (mBtSocket != null) { try { mBtSocket.close(); @@ -284,15 +271,16 @@ public class PebbleIoThread extends GBDeviceIoThread { synchronized public void write(byte[] bytes) { // block writes if app installation in in progress - if (mmIsConnected && !mmIsInstalling) { + if (mIsConnected && !mIsInstalling) { try { - mmOutStream.write(bytes); - mmOutStream.flush(); + mOutStream.write(bytes); + mOutStream.flush(); } catch (IOException e) { } } } + // FIXME: this does not belong here in this class, it is supporsed to be generic code private void evaluateGBCommandBundle(GBDeviceCommand deviceCmd) { Context context = getContext(); @@ -352,7 +340,7 @@ public class PebbleIoThread extends GBDeviceIoThread { case SUCCESS: finishInstall(false); // refresh app list - write(mmPebbleProtocol.encodeAppInfoReq()); + write(mPebbleProtocol.encodeAppInfoReq()); break; default: break; @@ -380,17 +368,17 @@ public class PebbleIoThread extends GBDeviceIoThread { } public void setToken(int token) { - mmAppInstallToken = token; + mAppInstallToken = token; } public void setInstallSlot(int slot) { - if (mmIsInstalling) { - mmInstallSlot = slot; + if (mIsInstalling) { + mInstallSlot = slot; } } private void writeInstallApp(byte[] bytes) { - if (!mmIsInstalling) { + if (!mIsInstalling) { return; } int length = bytes.length; @@ -406,24 +394,24 @@ public class PebbleIoThread extends GBDeviceIoThread { Log.i(TAG, new String(hexChars)); */ try { - mmOutStream.write(bytes); - mmOutStream.flush(); + mOutStream.write(bytes); + mOutStream.flush(); } catch (IOException e) { } } public void installApp(Uri uri) { - if (mmIsInstalling) { + if (mIsInstalling) { return; } - write(mmPebbleProtocol.encodeAppInfoReq()); // do this here to get run() out of its blocking read - mmInstallState = PebbleAppInstallState.APP_WAIT_SLOT; - mmInstallURI = uri; - mmIsInstalling = true; + write(mPebbleProtocol.encodeAppInfoReq()); // do this here to get run() out of its blocking read + mInstallState = PebbleAppInstallState.APP_WAIT_SLOT; + mInstallURI = uri; + mIsInstalling = true; } public void finishInstall(boolean hadError) { - if (!mmIsInstalling) { + if (!mIsInstalling) { return; } if (hadError) { @@ -431,21 +419,21 @@ public class PebbleIoThread extends GBDeviceIoThread { } else { GB.updateNotification("installation successful", getContext()); } - mmInstallState = PebbleAppInstallState.UNKNOWN; + mInstallState = PebbleAppInstallState.UNKNOWN; - if (hadError == true && mmAppInstallToken != -1) { - writeInstallApp(mmPebbleProtocol.encodeUploadCancel(mmAppInstallToken)); + if (hadError == true && mAppInstallToken != -1) { + writeInstallApp(mPebbleProtocol.encodeUploadCancel(mAppInstallToken)); } - mmPBWReader = null; - mmIsInstalling = false; - mmZis = null; - mmAppInstallToken = -1; - mmInstallSlot = -1; + mPBWReader = null; + mIsInstalling = false; + mZis = null; + mAppInstallToken = -1; + mInstallSlot = -1; } public void quit() { - mmQuit = true; + mQuit = true; if (mBtSocket != null) { try { mBtSocket.close(); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/pebble/STM32CRC.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/pebble/STM32CRC.java deleted file mode 100644 index 28b83339b..000000000 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/pebble/STM32CRC.java +++ /dev/null @@ -1,152 +0,0 @@ -package nodomain.freeyourgadget.gadgetbridge.pebble; - -import java.nio.ByteBuffer; -import java.nio.ByteOrder; - -/* - * This code was ported to java from the following cpp source file - * https://github.com/smokku/pebble/blob/8f0905197f7cead299c00006ada482095fe9d1a4/daemon/stm32crc.cpp - * (Unofficial Pebble watch support for SailfishOS/Jolla) - */ - -public class STM32CRC { - private int crc; - private byte rem; - private byte buffer[] = {0, 0, 0, 0}; - - private static final int[] crc_table = { - 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, - 0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005, - 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, - 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, - 0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, - 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75, - 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, - 0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd, - 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, - 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, - 0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81, - 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d, - 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, - 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95, - 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, - 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, - 0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae, - 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072, - 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, - 0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca, - 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, - 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, - 0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066, - 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, - 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, - 0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692, - 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, - 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, - 0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e, - 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, - 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, - 0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a, - 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, - 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, - 0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, - 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53, - 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, - 0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b, - 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, - 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, - 0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, - 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b, - 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, - 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3, - 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, - 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, - 0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f, - 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3, - 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, - 0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c, - 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, - 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, - 0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30, - 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec, - 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, - 0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654, - 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, - 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, - 0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18, - 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, - 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, - 0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c, - 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, - 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4, - }; - - public void reset() { - crc = 0xffffffff; - rem = 0; - buffer[0] = 0; - buffer[1] = 0; - buffer[2] = 0; - buffer[3] = 0; - } - - public STM32CRC() { - reset(); - } - - private int calc_crc(int crc, int word) { - crc ^= word; - crc = (crc << 8) ^ crc_table[(crc >>> 24) & 0xFF]; - crc = (crc << 8) ^ crc_table[(crc >>> 24) & 0xFF]; - crc = (crc << 8) ^ crc_table[(crc >>> 24) & 0xFF]; - crc = (crc << 8) ^ crc_table[(crc >>> 24) & 0xFF]; - return crc; - } - - public void addData(byte[] data, int length) { - ByteBuffer buf = ByteBuffer.wrap(data, 0, length); - buf.order(ByteOrder.LITTLE_ENDIAN); - - if (rem > 0) { - for (; rem < 4 && buf.hasRemaining(); ++rem) { - buffer[rem] = buf.get(); - } - - if (rem == 4) { - int word = ((buffer[0] & 0xff)) | - ((buffer[1] & 0xff) << 8) | - ((buffer[2] & 0xff) << 16) | - ((buffer[3] & 0xff) << 24); - crc = calc_crc(crc, word); - buffer[0] = 0; - buffer[1] = 0; - buffer[2] = 0; - buffer[3] = 0; - rem = 0; - } - } - - - while (buf.remaining() >= 4) { - int word = buf.getInt(); - crc = calc_crc(crc, word); - } - - while (buf.hasRemaining()) { - buffer[rem++] = buf.get(); - } - } - - - public int getResult() { - if (rem > 0) { - int word = ((buffer[0] & 0xff)) | - ((buffer[1] & 0xff) << 8) | - ((buffer[2] & 0xff) << 16) | - ((buffer[3] & 0xff) << 24); - return calc_crc(crc, word); - } else { - return crc; - } - } -}