package kr.co.sevencore.blefotalib; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.ServiceConnection; import android.os.IBinder; import android.os.RemoteException; import android.util.Log; import android.widget.SimpleExpandableListAdapter; import java.io.File; import java.util.ArrayList; import java.util.HashMap; import kr.co.sevencore.blefotalib.BflCodeList.UploadCode; import kr.co.sevencore.blefotalib.BflCodeList.ServiceIdxCode; import kr.co.sevencore.blefotalib.BflCodeList.CharacteristicFotaIdxCode; import kr.co.sevencore.blefotalib.BflCodeList.CharacteristicDeviceInfoIdxCode; /** * BflFwUploader.java * BLE FOTA Library Firmware Upload. * * 2015 SEVENCORE Co., Ltd. * * @author Jungwoo Park * @version 1.0.0 * @since 2015-04-08 * @see kr.co.sevencore.blefotalib.BflFwUploadService * @see kr.co.sevencore.blefotalib.IBflFwUploadSvc * TODO.. Apply flag value - 00: The BLE device is rebooted by the old firmware, 01: The BLE device is rebooted by the new firmware. */ public class BflFwUploader { private final static String BLE_FOTA_TAG = BflFwUploader.class.getSimpleName(); public IBflFwUploadSvc mBflUploadBinder; // Firmware data upload service AIDL. private Intent mUploadServiceIntent; private String mAddress; // The target device MAC address. private Context mContext; private static String sFirmwareCurrentVersion; // Current target device(BLE server) firmware version. private static String sFirmwareNewVersion; // If another firmware data exists at the target device(BLE server), return firmware version of the target device, private static String sFirmwareVersion; // Selected firmware version at the smart device(BLE client). private static String sFilePath; // Selected firmware data file path. private static int sLeftConnCnt = 0; // Left firmware data count. private static int sSequenceNumber = -1; // Sequence number starts at 0. private static String sFirmwareDataStatus; // Firmware data integrity status. private static String sFirmwareStatus; // Firmware software status. private static byte sFirmwareUpgradeTypeFlag = 0; // Flag 0 : Normal upgrade | Flag 1 : Forced upgrade private static byte sResetFlag = 1; // Flag 0: Not reset | Flag 1: Reset private static String sManufacturerName; // Device manufacturer name. private static String sModelNumber; // Device model number. private static String sSerialNumber; // Device serial number. private static String sExtraData; // Extra data information by read or write characteristic. private static boolean sInitAutoProgressFlag = false; // Initialization for FOTA automation flag. private static boolean sAutoProgressFlag = false; // Firmware upgrade automation flag. private final String NORMAL = "0"; // Firmware data check & status normal status. private final String VALIDATE = "1"; // Firmware data validate status. private final String INVALIDATE = "2"; // Firmware data invalidate status. private final String SUCCESSFUL = "1"; // Firmware status successful status. private final String ABNORMAL_FINISH = "2"; // Firmware status abnormal finish status. private OnUploadSvcInit mUploadSvcInitCallback; // Service initialization result of the firmware upload callback. private OnConnectionState mConnectionCallback; // BLE connection status callback. private OnErrorStateListener mErrorStateCallback; // Error state for connection callback. private OnUpdateGattServiceListener mUpdateGattServiceCallback; // GATT service list adapter callback. private OnDeviceInfoListener mDeviceInfoCallback; // Device and firmware status related information in doing FOTA callback. public BflFwUploader() {} public BflFwUploader(Context context) { mContext = context; } /** * OnUploadSvcInit interface is used to get result of firmware upload service initialization. */ public interface OnUploadSvcInit { /** * Initialization using BLE of the smart device. * * @param initResult true: All of BLE related feature is normal state. * false: Unable to initialize BLE relate feature. */ void onUploadSvcInit(boolean initResult); } /** * OnConnectionState interface is used to get state of connection. * If a main application needs to get state of BLE connection state, * use onConnectionState method. */ public interface OnConnectionState { /** * Get BLE connection state. * * @param state true: connected * false: disconnected. */ void onConnectionState(boolean state); } /** * OnErrorStateListener interface is used to notify error state. * If a main application needs to get the error state of Bluetooth GATT or device information to used for connection, * use onErrorStateListener. */ public interface OnErrorStateListener { /** * Get error state. * * @param state true: Error state. * false: Normal state. */ void onErrorStateListener(boolean state); } /** * OnUpdateGattServiceListener interface is used to get GATT service adapter. * If a main application needs to show service list by expandable list adapter, * use onUpdateGattServiceListener method. */ public interface OnUpdateGattServiceListener { /** * Get GATT service list adapter of the target device. * * @param gattServiceAdapter includes GATT services lists. */ void onUpdateGattServiceListener(SimpleExpandableListAdapter gattServiceAdapter); } /** * OnDeviceInfoListener interface is used to get firmware upgrade progress related data of the target device. * If a main application needs a firmware upgrade progress related information, * use onDeviceInfoListener method. */ public interface OnDeviceInfoListener { /** * Used to get string information data of firmware upgrade progress. * * @param code is a progress identifier of firmware upgrade progress. * @param data is the information related each progress state. */ void onDeviceInfoListener(String code, String data); /** * Used to get integer value of sequence number about firmware upgrade. * * @param code is a progress identifier of firmware upgrade progress. * @param data is the sequence number value. */ void onDataSequenceNumberListener(String code, int data); } /** * Save a callback object to mUploadSvcInitCallback. * * @see kr.co.sevencore.blefotalib.BflFwUploader.OnUploadSvcInit */ public void setOnUploadSvcInit(OnUploadSvcInit callback) { mUploadSvcInitCallback = callback; } /** * Save a callback object to mConnectionCallback. * * @see kr.co.sevencore.blefotalib.BflFwUploader.OnConnectionState */ public void setOnConnectionState(OnConnectionState callback) { mConnectionCallback = callback; } /** * Save a callback object to mErrorStateCallback. * * @see kr.co.sevencore.blefotalib.BflFwUploader.OnErrorStateListener */ public void setOnErrorStateListener(OnErrorStateListener callback) { mErrorStateCallback = callback; } /** * Save a callback object to mUpdateGattServiceCallback. * * @see kr.co.sevencore.blefotalib.BflFwUploader.OnUpdateGattServiceListener */ public void setOnUpdateGattServiceListener(OnUpdateGattServiceListener callback) { mUpdateGattServiceCallback = callback; } /** * Save a callback object to mDeviceInfoCallback. * * @see kr.co.sevencore.blefotalib.BflFwUploader.OnDeviceInfoListener */ public void setOnDeviceInfoListener(OnDeviceInfoListener callback) { mDeviceInfoCallback = callback; } /** * Get the new firmware version information. * * @return The new firmware version information. */ public String getFirmwareVersion() { return sFirmwareVersion; } /** * Get the file path of the firmware data. * * @return The path of firmware data location. */ public String getFilePath() { return sFilePath; } /** * Get the firmware upgrade type. * * @return The firmware upgrade type flag. */ public byte getFirmwareUpgradeType() { return sFirmwareUpgradeTypeFlag; } /** * Set the new firmware version. * * @param version is extracted from the file name to be a new firmware version. */ public void setFirmwareVersion(String version) { sFirmwareVersion = version; } /** * Set the file path of the firmware data. * * @param path is the location of the firmware data. */ public void setFilePath(String path) { sFilePath = path; } /** * Set the firmware upgrade type. * * @param type is firmware upgrade type. */ public void setFirmwareUpgradeType(byte type) { sFirmwareUpgradeTypeFlag = type; } /** * Create an object to implement a service connection interface. * The firmware upload service updates the firmware of the BLE device. * * @see kr.co.sevencore.blefotalib.IBflFwUploadSvc * @see kr.co.sevencore.blefotalib.BflFwUploadService */ private final ServiceConnection mBflUploadSvcConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { mBflUploadBinder = IBflFwUploadSvc.Stub.asInterface(service); boolean initResult = true; try { if (!mBflUploadBinder.initUploader()) { initResult = false; Log.e(BLE_FOTA_TAG, "Unable to initialize Bluetooth."); } try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } if (mUploadSvcInitCallback != null) { mUploadSvcInitCallback.onUploadSvcInit(initResult); } try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } if(mAddress != null) { mBflUploadBinder.connect(mAddress); } else { Log.e(BLE_FOTA_TAG, "Connection creation failed because MAC address value is NULL."); } } catch (RemoteException e) { e.printStackTrace(); } } @Override public void onServiceDisconnected(ComponentName name) { mBflUploadBinder = null; } }; /** * Broadcast receiver of firmware upload service. * Handle various events fired by the Service. * ACTION_GATT_CONNECTED: Connected to a GATT server. * ACTION_GATT_DISCONNECTED: Disconnected from a GATT server. * ACTION_GATT_SERVICES_DISCOVERED: GATT services Discovered. * ACTION_GATT_DATA_AVAILABLE: Update GATT services & characteristics list to be used to do FOTA. * ACTION_DATA_AVAILABLE: Received data from the device. A result of read or notification operations. * ACTION_DATA_WRITABLE: Transmitting data from client device. A result of write operation. * * @see kr.co.sevencore.blefotalib.BflFwUploadService */ private final BroadcastReceiver mBflUploadBroadcastReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { final String action = intent.getAction(); if (action != null) { if (BflFwUploadService.ERROR_LOST_GATT.equals(action)) { if (mErrorStateCallback != null) { mErrorStateCallback.onErrorStateListener(true); } } else if (BflFwUploadService.ERROR_LOST_DEVICE_INFORMATION.equals(action)) { if (mErrorStateCallback != null) { mErrorStateCallback.onErrorStateListener(true); } } else if (BflFwUploadService.ACTION_GATT_CONNECTED.equals(action)) { Log.i(BLE_FOTA_TAG, "The device is connected."); // Update connection state by the callback. if (mConnectionCallback != null) { mConnectionCallback.onConnectionState(true); } } else if (BflFwUploadService.ACTION_GATT_DISCONNECTED.equals(action)) { Log.i(BLE_FOTA_TAG, "The device is disconnected."); initializeValue(); // Update connection state by the callback. if (mConnectionCallback != null) { mConnectionCallback.onConnectionState(false); } } else if (BflFwUploadService.ACTION_GATT_SERVICES_DISCOVERED.equals(action)) { try { // Update GATT services to do FOTA. mBflUploadBinder.updateGatt(); } catch (RemoteException e) { e.printStackTrace(); } } else if (BflFwUploadService.ACTION_GATT_DATA_AVAILABLE.equals(action)) { // Show all the supported services and characteristics on the user interface. if (mUpdateGattServiceCallback != null) { mUpdateGattServiceCallback.onUpdateGattServiceListener( updateGattServicesAdapter( (ArrayList<HashMap<String, String>>) intent.getExtras(). getSerializable(BflFwUploadService.GATT_SERVICE_DATA_AVAILABLE), (ArrayList<ArrayList<HashMap<String, String>>>) intent.getExtras(). getSerializable(BflFwUploadService.GATT_CHARACTERISTIC_DATA_AVAILABLE) ) ); } if (sInitAutoProgressFlag) { // Firmware version characteristic read property execution. executeReadFirmwareCurrentVersion(); } } else if (BflFwUploadService.ACTION_FIRMWARE_CURRENT_VERSION_AVAILABLE.equals(action)) { sFirmwareCurrentVersion = intent.getStringExtra(BflFwUploadService.EXTRA_DATA); // Compare the device firmware version and the server firmware version. Intent versionInfoIntent = new Intent(BflFwVerChecker.ACTION_TARGET_VERSION); versionInfoIntent.putExtra(BflFwVerChecker.VERSION_INFO, sFirmwareCurrentVersion); versionInfoIntent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES); context.sendBroadcast(versionInfoIntent); if (sInitAutoProgressFlag) { // Firmware new version characteristic read property execution. executeReadFirmwareNewVersion(); } if (mDeviceInfoCallback != null) { mDeviceInfoCallback.onDeviceInfoListener( UploadCode.DEVICE_FIRMWARE_CURRENT_VERSION.getCode(), sFirmwareCurrentVersion ); } Log.d(BLE_FOTA_TAG, "Current firmware version: " + sFirmwareCurrentVersion); } else if (BflFwUploadService.ACTION_FIRMWARE_NEW_VERSION_AVAILABLE.equals(action)) { sFirmwareNewVersion = intent.getStringExtra(BflFwUploadService.EXTRA_DATA); final String defaultVersion = "00-00-00"; if (sInitAutoProgressFlag) { // Manufacturer name characteristic read property execution. executeReadManufacturerName(); } // If you want to manage firmware version information // between a new firmware data which is going to be transmitted // and a existing new firmware data which exists on the device, // use below conditional statement. if (sFirmwareNewVersion.equals(defaultVersion)) { if (mDeviceInfoCallback != null) { mDeviceInfoCallback.onDeviceInfoListener( UploadCode.DEVICE_FIRMWARE_NEW_VERSION_EMPTINESS.getCode(), sFirmwareNewVersion ); } } else { if (mDeviceInfoCallback != null) { mDeviceInfoCallback.onDeviceInfoListener( UploadCode.DEVICE_FIRMWARE_NEW_VERSION_EXISTENCE.getCode(), sFirmwareNewVersion ); } } Log.d(BLE_FOTA_TAG, "New firmware version: " + sFirmwareNewVersion); } else if (BflFwUploadService.ACTION_SEQUENCE_NUMBER_AVAILABLE.equals(action)) { if (sAutoProgressFlag && (intent.getStringExtra(BflFwUploadService.EXTRA_DATA) != null)) { sSequenceNumber = Integer.parseInt(intent.getStringExtra(BflFwUploadService.EXTRA_DATA)); // Check the existing file size to resume transmitting the firmware data // or checking firmware data integrity. if (!checkSequence(sFilePath, sSequenceNumber)) { try { mBflUploadBinder.executeWriteFirmwareData( ServiceIdxCode.SERVICE_FIRMWARE_UPGRADE.getCode(), CharacteristicFotaIdxCode.CHARACTERISTIC_FIRMWARE_DATA.getCode(), sFilePath, sSequenceNumber); } catch (RemoteException e) { e.printStackTrace(); } } else { try { mBflUploadBinder.executeWriteChecksumData( ServiceIdxCode.SERVICE_FIRMWARE_UPGRADE.getCode(), CharacteristicFotaIdxCode.CHARACTERISTIC_CHECKSUM_DATA.getCode(), sFilePath); } catch (RemoteException e) { e.printStackTrace(); } } if (mDeviceInfoCallback != null) { mDeviceInfoCallback.onDataSequenceNumberListener( UploadCode.DEVICE_FIRMWARE_AVAILABLE_SEQUENCE_NUMBER.getCode(), sSequenceNumber ); } } Log.d(BLE_FOTA_TAG, "Data sequence number of the device: " + sSequenceNumber); } else if (BflFwUploadService.ACTION_FIRMWARE_DATA_CHECK_AVAILABLE.equals(action)) { if (sAutoProgressFlag && (intent.getStringExtra(BflFwUploadService.EXTRA_DATA) != null)) { sFirmwareDataStatus = intent.getStringExtra(BflFwUploadService.EXTRA_DATA); // Firmware data check flag value - NORMAL: 0, VALIDATE: 1, INVALIDATE: 2 switch (sFirmwareDataStatus) { case NORMAL: if (mDeviceInfoCallback != null) { mDeviceInfoCallback.onDeviceInfoListener( UploadCode.DEVICE_FIRMWARE_DATA_STATUS_NORMAL.getCode(), sFirmwareDataStatus ); } Log.i(BLE_FOTA_TAG, "Firmware data has not been verified yet."); break; case VALIDATE: try { mBflUploadBinder.executeWriteFirmwareUpgradeType( ServiceIdxCode.SERVICE_FIRMWARE_UPGRADE.getCode(), CharacteristicFotaIdxCode.CHARACTERISTIC_FIRMWARE_UPGRADE_TYPE.getCode(), sFirmwareUpgradeTypeFlag ); } catch (RemoteException e) { e.printStackTrace(); } if (mDeviceInfoCallback != null) { mDeviceInfoCallback.onDeviceInfoListener( UploadCode.DEVICE_FIRMWARE_DATA_STATUS_VALID.getCode(), sFirmwareDataStatus ); } Log.i(BLE_FOTA_TAG, "Firmware data validated."); break; case INVALIDATE: sAutoProgressFlag = false; if (mDeviceInfoCallback != null) { mDeviceInfoCallback.onDeviceInfoListener( UploadCode.DEVICE_FIRMWARE_DATA_STATUS_INVALID.getCode(), sFirmwareDataStatus ); } Log.i(BLE_FOTA_TAG, "Firmware data invalidated"); break; } } } else if (BflFwUploadService.ACTION_FIRMWARE_STATUS_AVAILABLE.equals(action)) { if (sAutoProgressFlag && (intent.getStringExtra(BflFwUploadService.EXTRA_DATA) != null)) { sFirmwareStatus = intent.getStringExtra(BflFwUploadService.EXTRA_DATA); // Firmware upgrade status flag value - NORMAL: 0, SUCCESSFUL: 1, ABNORMAL FINISH: 2 switch (sFirmwareStatus) { case NORMAL: if (mDeviceInfoCallback != null) { mDeviceInfoCallback.onDeviceInfoListener( UploadCode.DEVICE_FIRMWARE_STATUS_NORMAL.getCode(), sFirmwareStatus ); } Log.i(BLE_FOTA_TAG, "Upgrade is not over yet."); break; case SUCCESSFUL: try { mBflUploadBinder.executeWriteReset( ServiceIdxCode.SERVICE_FIRMWARE_UPGRADE.getCode(), CharacteristicFotaIdxCode.CHARACTERISTIC_RESET.getCode(), sResetFlag ); Log.i(BLE_FOTA_TAG, "Target device reset now."); } catch (RemoteException e) { e.printStackTrace(); } if (mDeviceInfoCallback != null) { mDeviceInfoCallback.onDeviceInfoListener( UploadCode.DEVICE_FIRMWARE_STATUS_SUCCESSFUL_FINISH.getCode(), sFirmwareStatus ); } Log.i(BLE_FOTA_TAG, "Firmware upgrade finished successfully."); break; case ABNORMAL_FINISH: sAutoProgressFlag = false; if (mDeviceInfoCallback != null) { mDeviceInfoCallback.onDeviceInfoListener( UploadCode.DEVICE_FIRMWARE_STATUS_ABNORMAL_FINISH.getCode(), sFirmwareStatus ); } Log.i(BLE_FOTA_TAG, "Firmware upgrade finished abnormally."); break; } } } else if (BflFwUploadService.ACTION_MANUFACTURER_NAME_AVAILABLE.equals(action)) { sManufacturerName = intent.getStringExtra(BflFwUploadService.EXTRA_DATA); if (sInitAutoProgressFlag) { try { Thread.sleep(700); } catch (InterruptedException e) { e.printStackTrace(); } // Model number characteristic read property execution. executeReadModelNumber(); } if (mDeviceInfoCallback != null) { mDeviceInfoCallback.onDeviceInfoListener( UploadCode.DEVICE_INFORMATION_MANUFACTURER_NAME.getCode(), sManufacturerName ); } } else if (BflFwUploadService.ACTION_MODEL_NUMBER_AVAILABLE.equals(action)) { sModelNumber = intent.getStringExtra(BflFwUploadService.EXTRA_DATA); if (sInitAutoProgressFlag) { try { Thread.sleep(700); } catch (InterruptedException e) { e.printStackTrace(); } // Serial number characteristic read property execution. executeReadSerialNumber(); } if (mDeviceInfoCallback != null) { mDeviceInfoCallback.onDeviceInfoListener( UploadCode.DEVICE_INFORMATION_MODEL_NUMBER.getCode(), sModelNumber ); } } else if (BflFwUploadService.ACTION_SERIAL_NUMBER_AVAILABLE.equals(action)) { sSerialNumber = intent.getStringExtra(BflFwUploadService.EXTRA_DATA); if (mDeviceInfoCallback != null) { mDeviceInfoCallback.onDeviceInfoListener( UploadCode.DEVICE_INFORMATION_SERIAL_NUMBER.getCode(), sSerialNumber ); } } else if (BflFwUploadService.ACTION_DATA_AVAILABLE.equals(action)) { sExtraData = intent.getStringExtra(BflFwUploadService.EXTRA_DATA); if (mDeviceInfoCallback != null) { mDeviceInfoCallback.onDeviceInfoListener( UploadCode.DEVICE_EXTRA_DATA.getCode(), sExtraData ); } Log.d(BLE_FOTA_TAG, "Read extra data: " + sExtraData); } else if (BflFwUploadService.ACTION_FIRMWARE_NEW_VERSION_WRITABLE.equals(action)) { if (sAutoProgressFlag && intent.getStringExtra(BflFwUploadService.EXTRA_DATA) != null) { try { mBflUploadBinder.executeWriteFirmwareData( ServiceIdxCode.SERVICE_FIRMWARE_UPGRADE.getCode(), CharacteristicFotaIdxCode.CHARACTERISTIC_FIRMWARE_DATA.getCode(), sFilePath, sSequenceNumber); Log.d(BLE_FOTA_TAG, "Execute firmware upgrade. Starting firmware data transmission."); } catch (RemoteException e) { e.printStackTrace(); } } Log.d(BLE_FOTA_TAG, "Transmit a new version information to the target device."); } else if (BflFwUploadService.ACTION_FIRMWARE_DATA_WRITABLE.equals(action)) { sLeftConnCnt = Integer.parseInt(intent.getStringExtra(BflFwUploadService.EXTRA_DATA)); if (sAutoProgressFlag && (sLeftConnCnt == 0)) { try { mBflUploadBinder.executeWriteChecksumData( ServiceIdxCode.SERVICE_FIRMWARE_UPGRADE.getCode(), CharacteristicFotaIdxCode.CHARACTERISTIC_CHECKSUM_DATA.getCode(), sFilePath); Log.d(BLE_FOTA_TAG, "Generate & transmit checksum data."); } catch (RemoteException e) { e.printStackTrace(); } } if (mDeviceInfoCallback != null) { mDeviceInfoCallback.onDataSequenceNumberListener( UploadCode.DEVICE_FIRMWARE_DATA_LEFT_COUNT.getCode(), sLeftConnCnt ); } Log.d(BLE_FOTA_TAG, "Left data count: " + sLeftConnCnt); } else if (BflFwUploadService.ACTION_SEQUENCE_NUMBER_WRITABLE.equals(action)) { int writableSequenceNumber = Integer.parseInt(intent.getStringExtra(BflFwUploadService.EXTRA_DATA)); if (mDeviceInfoCallback != null) { mDeviceInfoCallback.onDataSequenceNumberListener( UploadCode.DEVICE_FIRMWARE_WRITABLE_SEQUENCE_NUMBER.getCode(), writableSequenceNumber ); } Log.i(BLE_FOTA_TAG, "Sequence number is " + writableSequenceNumber); } else if (BflFwUploadService.ACTION_CHECKSUM_DATA_WRITABLE.equals(action)) { if (sAutoProgressFlag && (intent.getStringExtra(BflFwUploadService.EXTRA_DATA) != null)) { executeReadFirmwareDataCheck(); } Log.d(BLE_FOTA_TAG, "Transmitting checksum data."); } else if (BflFwUploadService.ACTION_FIRMWARE_UPGRADE_TYPE_WRITABLE.equals(action)) { if (sAutoProgressFlag && (intent.getStringExtra(BflFwUploadService.EXTRA_DATA) != null)) { executeReadFirmwareStatus(); } switch (sFirmwareUpgradeTypeFlag) { case 0: if (mDeviceInfoCallback != null) { mDeviceInfoCallback.onDeviceInfoListener( UploadCode.DEVICE_FIRMWARE_UPGRADE_TYPE_NORMAL.getCode(), "0" ); } break; case 1: if (mDeviceInfoCallback != null) { mDeviceInfoCallback.onDeviceInfoListener( UploadCode.DEVICE_FIRMWARE_UPGRADE_TYPE_FORCED.getCode(), "1" ); } break; } Log.d(BLE_FOTA_TAG, "Firmware update type: " + sFirmwareUpgradeTypeFlag); } else if (BflFwUploadService.ACTION_RESET_WRITABLE.equals(action)) { if (mDeviceInfoCallback != null) { mDeviceInfoCallback.onDeviceInfoListener( UploadCode.DEVICE_FIRMWARE_RESET.getCode(), null ); } Log.d(BLE_FOTA_TAG, "The target device is reset"); } else if (BflFwUploadService.ACTION_DATA_WRITABLE.equals(action)) { if (mDeviceInfoCallback != null) { mDeviceInfoCallback.onDeviceInfoListener( UploadCode.DEVICE_EXTRA_DATA.getCode(), intent.getStringExtra(BflFwUploadService.EXTRA_DATA) ); } } } else { Log.e(BLE_FOTA_TAG, "Firmware uploader broadcast data is NULL."); } } }; /** * BLE FOTA firmware upload service connection. * Create service connection. * * @param address is the device MAC address. * @param initAutoProgress is auto progress setting for initial value. * @see kr.co.sevencore.blefotalib.BflFwUploadService */ public void connectUploadSvc(String address, boolean initAutoProgress) { mAddress = address; sInitAutoProgressFlag = initAutoProgress; mUploadServiceIntent = new Intent(mContext, BflFwUploadService.class); // BLE FOTA Library uses daemon(local) background service using startService method to run independently // & remote service using bindService method to communicate by AIDL. mContext.startService(mUploadServiceIntent); mContext.bindService(mUploadServiceIntent, mBflUploadSvcConnection, mContext.BIND_AUTO_CREATE); } /** * BLE FOTA firmware upload service disconnection. * * @see kr.co.sevencore.blefotalib.BflDeviceScanService * @see kr.co.sevencore.blefotalib.BflUtil */ public void disconnectUploadSvc() { sInitAutoProgressFlag = false; if (BflUtil.isServiceRunning(mContext, BflFwUploadService.class)) { try { mContext.unbindService(mBflUploadSvcConnection); mContext.stopService(mUploadServiceIntent); mBflUploadBinder = null; } catch (Exception e) { e.printStackTrace(); } } } /** * Create connection with the BLE device. * * @param address of the BLE device is used for creating connection. */ public void connect(String address) { if (mBflUploadBinder != null) { try { mBflUploadBinder.connect(address); } catch (RemoteException e) { e.printStackTrace(); } } } /** * Close connection with the BLE device. */ public void disconnect() { if (mBflUploadBinder != null) { try { mBflUploadBinder.disconnect(); } catch (RemoteException e) { e.printStackTrace(); } } } /** * After closing connection by disconnect method, * system resources have to be released properly by close method. */ public void close() { if (mBflUploadBinder != null) { try { mBflUploadBinder.close(); } catch (RemoteException e) { e.printStackTrace(); } } } /** * Register broadcast receiver. * * @param context is gettable from the caller application. * @see kr.co.sevencore.blefotalib.BflFwUploadService */ public void registerBflUploadReceiver(Context context) { context.registerReceiver(mBflUploadBroadcastReceiver, makeGattUpdateIntentFilter()); } /** * Unregister broadcast receiver. * * @see kr.co.sevencore.blefotalib.BflFwDownloadService */ public void unregisterBflUploadReceiver() { try { mContext.unregisterReceiver(mBflUploadBroadcastReceiver); } catch (Exception e) { e.printStackTrace(); } } /** * Set FOTA progress automation flag. * * @param flag is boolean value to be set. */ public void setAutoProgressFlag(boolean flag) { sAutoProgressFlag = flag; } /** * Initialize FOTA progress related values. */ private void initializeValue() { sLeftConnCnt = 0; sSequenceNumber = -1; sFirmwareUpgradeTypeFlag = 0; } /** * Update GATT service adapter. * * @param gattServiceData is services list. * @param gattCharacteristicData is characteristics list. * @return GATT service adapter. * @see kr.co.sevencore.blefotalib.BflFwUploadService */ public SimpleExpandableListAdapter updateGattServicesAdapter( ArrayList<HashMap<String, String>> gattServiceData, ArrayList<ArrayList<HashMap<String, String>>> gattCharacteristicData) { SimpleExpandableListAdapter gattServiceAdapter = new SimpleExpandableListAdapter( mContext, gattServiceData, android.R.layout.simple_expandable_list_item_2, new String[] {BflCodeList.LIST_NAME, BflCodeList.LIST_UUID}, new int[] { android.R.id.text1, android.R.id.text2}, gattCharacteristicData, android.R.layout.simple_expandable_list_item_2, new String[] {BflCodeList.LIST_NAME, BflCodeList.LIST_UUID}, new int[] { android.R.id.text1, android.R.id.text2 } ); return gattServiceAdapter; } /** * Check more data is needed to be transmitted to the target device. * * @param filePath is the location that firmware data stored. * @param sequenceNumber is amount of data going to be transmitted. * @return true: More data is needed to be transmitted. * false: Firmware data transmission finished. */ private boolean checkSequence(String filePath, int sequenceNumber) { File firmwareFile = new File(filePath); long length = firmwareFile.length(); int sequence = sequenceNumber; int sendSize; if (sequence < -1) { sequence += 256; // Used for overflow. } if ((length % BflFwUploadService.PURE_EACH_CONN_DATA_SIZE) != 0) { sendSize = (sequence * BflFwUploadService.EACH_CONN_DATA_SIZE) + ((int) length % BflFwUploadService.PURE_EACH_CONN_DATA_SIZE); } else { sendSize = (sequence + 1) * BflFwUploadService.EACH_CONN_DATA_SIZE; } return (sendSize >= (int) length); } /** * Execute the specific BLE property. * * @param serviceIdx is index of services in adapter. * @param characteristicIdx is index of characteristics in adapter. * @return false: sAutoProgressFlag is disabled or BluetoothGattCharacteristic is null. */ public boolean executeProperty(int serviceIdx, int characteristicIdx) { if (!sAutoProgressFlag) { try { // Return true: onWriteCharacteristic | onReadCharacteristic | setCharacteristicNotification callback. return mBflUploadBinder.checkProperty(serviceIdx, characteristicIdx); } catch (RemoteException e) { e.printStackTrace(); } } return false; } /** * 18FF FOTA service. * 2AF0 Firmware version characteristic. * READ property function of FOTA profile. */ public void executeReadFirmwareCurrentVersion() { try { mBflUploadBinder.executeReadCharacteristic( ServiceIdxCode.SERVICE_FIRMWARE_UPGRADE.getCode(), CharacteristicFotaIdxCode.CHARACTERISTIC_FIRMWARE_VERSION.getCode() ); } catch (RemoteException e) { e.printStackTrace(); } } /** * 18FF FOTA service. * 2AF1 Firmware new version characteristic * READ (| WRITE) property function of FOTA profile. */ public void executeReadFirmwareNewVersion() { try { mBflUploadBinder.executeReadCharacteristic( ServiceIdxCode.SERVICE_FIRMWARE_UPGRADE.getCode(), CharacteristicFotaIdxCode.CHARACTERISTIC_FIRMWARE_NEW_VERSION.getCode() ); } catch (RemoteException e) { e.printStackTrace(); } } /** * 18FF FOTA service. * 2AF3 Sequence number characteristic. * READ property function of FOTA profile. */ public void executeReadSequenceNumber() { try { mBflUploadBinder.executeReadCharacteristic( ServiceIdxCode.SERVICE_FIRMWARE_UPGRADE.getCode(), CharacteristicFotaIdxCode.CHARACTERISTIC_SEQUENCE_NUMBER.getCode() ); } catch (RemoteException e) { e.printStackTrace(); } } /** * 18FF FOTA service. * 2AF6 Firmware data check characteristic. * READ | NOTIFY property of FOTA profile. */ public void executeReadFirmwareDataCheck() { try { mBflUploadBinder.executeReadCharacteristic( ServiceIdxCode.SERVICE_FIRMWARE_UPGRADE.getCode(), CharacteristicFotaIdxCode.CHARACTERISTIC_FIRMWARE_DATA_CHECK.getCode() ); } catch (RemoteException e) { e.printStackTrace(); } } /** * 18FF FOTA service. * 2AF7 Firmware status characteristic. * READ | WRITE property function of FOTA profile. */ public void executeReadFirmwareStatus() { try { mBflUploadBinder.executeReadCharacteristic( ServiceIdxCode.SERVICE_FIRMWARE_UPGRADE.getCode(), CharacteristicFotaIdxCode.CHARACTERISTIC_FIRMWARE_STATUS.getCode() ); } catch (RemoteException e) { e.printStackTrace(); } } /** * 180A Device information which is included service. * 2A29 Manufacturer name characteristic. * READ property function of FOTA profile. */ public void executeReadManufacturerName() { try { mBflUploadBinder.executeReadCharacteristic( ServiceIdxCode.SERVICE_DEVICE_INFO.getCode(), CharacteristicDeviceInfoIdxCode.CHARACTERISTIC_MANUFACTURER_NAME.getCode() ); }catch (RemoteException e) { e.printStackTrace(); } } /** * 180A Device information which is included service. * 2A24 Model number characteristic. * READ property function of FOTA profile. */ public void executeReadModelNumber() { try { mBflUploadBinder.executeReadCharacteristic( ServiceIdxCode.SERVICE_DEVICE_INFO.getCode(), CharacteristicDeviceInfoIdxCode.CHARACTERISTIC_MODEL_NUMBER.getCode() ); } catch (RemoteException e) { e.printStackTrace(); } } /** * 180A Device information which is included service. * 2A25 Serial number characteristic. * READ property function of FOTA profile. */ public void executeReadSerialNumber() { try { mBflUploadBinder.executeReadCharacteristic( ServiceIdxCode.SERVICE_DEVICE_INFO.getCode(), CharacteristicDeviceInfoIdxCode.CHARACTERISTIC_SERIAL_NUMBER.getCode() ); } catch (RemoteException e) { e.printStackTrace(); } } /** * 18FF FOTA service. * 2AF1 Firmware new version characteristic. * (READ |) WRITE property function of FOTA profile. * * @param firmwareVersion is new version information of firmware data which is going to be updated. */ public void executeWriteFirmwareNewVersion(String firmwareVersion) { try { mBflUploadBinder.executeWriteFirmwareNewVersion( ServiceIdxCode.SERVICE_FIRMWARE_UPGRADE.getCode(), CharacteristicFotaIdxCode.CHARACTERISTIC_FIRMWARE_NEW_VERSION.getCode(), firmwareVersion ); } catch (RemoteException e) { e.printStackTrace(); } } /** * 18FF FOTA service. * 2AF2 Firmware data characteristic. * WRITE property function of FOTA profile. * * @param filePath is the location of the new firmware data in the smart device. * @param sequenceNumber is the start location information of the firmware data which is going to be transmitted. */ public void executeFirmwareUpgrade(String filePath, int sequenceNumber) { try { mBflUploadBinder.executeWriteFirmwareData( ServiceIdxCode.SERVICE_FIRMWARE_UPGRADE.getCode(), CharacteristicFotaIdxCode.CHARACTERISTIC_FIRMWARE_DATA.getCode(), filePath, sequenceNumber ); } catch (RemoteException e) { e.printStackTrace(); } } /** * 18FF FOTA service. * 2AF4 Checksum data characteristic. * WRITE property function of FOTA profile. * * @param filePath is the location of the checksum data which is generated from firmware data. */ public void executeWriteChecksumData(String filePath) { try { mBflUploadBinder.executeWriteChecksumData( ServiceIdxCode.SERVICE_FIRMWARE_UPGRADE.getCode(), CharacteristicFotaIdxCode.CHARACTERISTIC_CHECKSUM_DATA.getCode(), filePath ); } catch (RemoteException e) { e.printStackTrace(); } } /** * 18FF FOTA service. * 2AF6 Firmware upgrade type characteristic. * WRITE property function of FOTA profile. * * @param typeFlag is normal or forced upgrade type. */ public void executeWriteFirmwareUpgradeType(byte typeFlag) { try { mBflUploadBinder.executeWriteFirmwareUpgradeType( ServiceIdxCode.SERVICE_FIRMWARE_UPGRADE.getCode(), CharacteristicFotaIdxCode.CHARACTERISTIC_FIRMWARE_UPGRADE_TYPE.getCode(), typeFlag ); } catch (RemoteException e) { e.printStackTrace(); } } /** * 18FF FOTA service. * 2AF8 Reset characteristic. * WRITE property function of FOTA profile. * * @param resetFlag is reset command flag. */ public void executeWriteReset(byte resetFlag) { try { mBflUploadBinder.executeWriteReset( ServiceIdxCode.SERVICE_FIRMWARE_UPGRADE.getCode(), CharacteristicFotaIdxCode.CHARACTERISTIC_RESET.getCode(), resetFlag ); } catch (RemoteException e) { e.printStackTrace(); } } /** * Intent filter for BflFwUploadService. * * ACTION_GATT_CONNECTING: Bluetooth GATT connection creating state. * ACTION_GATT_CONNECTED: Bluetooth GATT connection created state. * ACTION_GATT_DISCONNECTING: Bluetooth GATT connection closing state. * ACTION_GATT_DISCONNECTED: Bluetooth GATT connection closed state. * ACTION_GATT_SERVICES_DISCOVERED: Bluetooth GATT service list discovered. * ACTION_GATT_DATA_AVAILABLE: Bluetooth GATT service list get. * * Read properties of FOTA service. * ACTION_FIRMWARE_CURRENT_VERSION_AVAILABLE: The target device current firmware version information. * ACTION_FIRMWARE_NEW_VERSION_AVAILABLE: The target device new firmware version information to be going to be updated. * ACTION_SEQUENCE_NUMBER_AVAILABLE: The sequence number is used to manage firmware data transmission. * ACTION_FIRMWARE_DATA_CHECK_AVAILABLE: Firmware data integrity information. * ACTION_FIRMWARE_STATUS_AVAILABLE: Firmware status information. * * Read properties of device information service. * ACTION_MANUFACTURER_NAME_AVAILABLE: Manufacturer information. * ACTION_MODEL_NUMBER_AVAILABLE: Model number information. * ACTION_SERIAL_NUMBER_AVAILABLE: Serial number information. * * ACTION_DATA_AVAILABLE: Read data. * * Write properties of FOTA service. * ACTION_FIRMWARE_NEW_VERSION_WRITABLE: Write new firmware version information. * ACTION_FIRMWARE_DATA_WRITABLE: Firmware data transmission. * ACTION_SEQUENCE_NUMBER_WRITABLE: The sequence number is used to manage firmware data transmission. * ACTION_CHECKSUM_DATA_WRITABLE: Checksum data checks integrity of the firmware data. * ACTION_FIRMWARE_UPGRADE_TYPE_WRITABLE: Apply firmware upgrade type. * ACTION_RESET_WRITABLE: The target device reset. * * ACTION_DATA_WRITABLE: Write data. * * @return Intent filter. */ private static IntentFilter makeGattUpdateIntentFilter() { final IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(BflFwUploadService.ERROR_LOST_GATT); intentFilter.addAction(BflFwUploadService.ERROR_LOST_DEVICE_INFORMATION); intentFilter.addAction(BflFwUploadService.ACTION_GATT_CONNECTING); intentFilter.addAction(BflFwUploadService.ACTION_GATT_CONNECTED); intentFilter.addAction(BflFwUploadService.ACTION_GATT_DISCONNECTING); intentFilter.addAction(BflFwUploadService.ACTION_GATT_DISCONNECTED); intentFilter.addAction(BflFwUploadService.ACTION_GATT_SERVICES_DISCOVERED); intentFilter.addAction(BflFwUploadService.ACTION_GATT_DATA_AVAILABLE); // Read properties. intentFilter.addAction(BflFwUploadService.ACTION_FIRMWARE_CURRENT_VERSION_AVAILABLE); intentFilter.addAction(BflFwUploadService.ACTION_FIRMWARE_NEW_VERSION_AVAILABLE); intentFilter.addAction(BflFwUploadService.ACTION_SEQUENCE_NUMBER_AVAILABLE); intentFilter.addAction(BflFwUploadService.ACTION_FIRMWARE_DATA_CHECK_AVAILABLE); intentFilter.addAction(BflFwUploadService.ACTION_FIRMWARE_STATUS_AVAILABLE); intentFilter.addAction(BflFwUploadService.ACTION_MANUFACTURER_NAME_AVAILABLE); intentFilter.addAction(BflFwUploadService.ACTION_MODEL_NUMBER_AVAILABLE); intentFilter.addAction(BflFwUploadService.ACTION_SERIAL_NUMBER_AVAILABLE); intentFilter.addAction(BflFwUploadService.ACTION_DATA_AVAILABLE); // Write properties. intentFilter.addAction(BflFwUploadService.ACTION_FIRMWARE_NEW_VERSION_WRITABLE); intentFilter.addAction(BflFwUploadService.ACTION_FIRMWARE_DATA_WRITABLE); intentFilter.addAction(BflFwUploadService.ACTION_SEQUENCE_NUMBER_WRITABLE); intentFilter.addAction(BflFwUploadService.ACTION_CHECKSUM_DATA_WRITABLE); intentFilter.addAction(BflFwUploadService.ACTION_FIRMWARE_UPGRADE_TYPE_WRITABLE); intentFilter.addAction(BflFwUploadService.ACTION_RESET_WRITABLE); intentFilter.addAction(BflFwUploadService.ACTION_DATA_WRITABLE); return intentFilter; } }