Search in sources :

Example 1 with PebbleInstallable

use of nodomain.freeyourgadget.gadgetbridge.devices.pebble.PebbleInstallable in project Gadgetbridge by Freeyourgadget.

the class PebbleIoThread method run.

@Override
public void run() {
    mIsConnected = connect();
    if (!mIsConnected) {
        if (GBApplication.getGBPrefs().getAutoReconnect() && !mQuit) {
            gbDevice.setState(GBDevice.State.WAITING_FOR_RECONNECT);
            gbDevice.sendDeviceUpdateIntent(getContext());
        }
        return;
    }
    byte[] buffer = new byte[8192];
    enablePebbleKitSupport(true);
    mQuit = false;
    while (!mQuit) {
        try {
            if (mIsInstalling) {
                switch(mInstallState) {
                    case WAIT_SLOT:
                        if (mInstallSlot == -1) {
                            // no slots available
                            finishInstall(true);
                        } else if (mInstallSlot >= 0) {
                            mInstallState = PebbleAppInstallState.START_INSTALL;
                            continue;
                        }
                        break;
                    case START_INSTALL:
                        LOG.info("start installing app binary");
                        PebbleInstallable pi = mPebbleInstallables[mCurrentInstallableIndex];
                        mFis = mPBWReader.getInputStreamFile(pi.getFileName());
                        mCRC = pi.getCRC();
                        mBinarySize = pi.getFileSize();
                        mBytesWritten = 0;
                        writeInstallApp(mPebbleProtocol.encodeUploadStart(pi.getType(), mInstallSlot, mBinarySize, mPBWReader.isLanguage() ? "lang" : null));
                        mAppInstallToken = -1;
                        mInstallState = PebbleAppInstallState.WAIT_TOKEN;
                        break;
                    case WAIT_TOKEN:
                        if (mAppInstallToken != -1) {
                            LOG.info("got token " + mAppInstallToken);
                            mInstallState = PebbleAppInstallState.UPLOAD_CHUNK;
                            continue;
                        }
                        break;
                    case UPLOAD_CHUNK:
                        int bytes = 0;
                        do {
                            int read = mFis.read(buffer, bytes, 2000 - bytes);
                            if (read <= 0)
                                break;
                            bytes += read;
                        } while (bytes < 2000);
                        if (bytes > 0) {
                            GB.updateInstallNotification(getContext().getString(R.string.installing_binary_d_d, (mCurrentInstallableIndex + 1), mPebbleInstallables.length), true, (int) (((float) mBytesWritten / mBinarySize) * 100), getContext());
                            writeInstallApp(mPebbleProtocol.encodeUploadChunk(mAppInstallToken, buffer, bytes));
                            mBytesWritten += bytes;
                            mAppInstallToken = -1;
                            mInstallState = PebbleAppInstallState.WAIT_TOKEN;
                        } else {
                            mInstallState = PebbleAppInstallState.UPLOAD_COMMIT;
                            continue;
                        }
                        break;
                    case UPLOAD_COMMIT:
                        writeInstallApp(mPebbleProtocol.encodeUploadCommit(mAppInstallToken, mCRC));
                        mAppInstallToken = -1;
                        mInstallState = PebbleAppInstallState.WAIT_COMMIT;
                        break;
                    case WAIT_COMMIT:
                        if (mAppInstallToken != -1) {
                            LOG.info("got token " + mAppInstallToken);
                            mInstallState = PebbleAppInstallState.UPLOAD_COMPLETE;
                            continue;
                        }
                        break;
                    case UPLOAD_COMPLETE:
                        writeInstallApp(mPebbleProtocol.encodeUploadComplete(mAppInstallToken));
                        if (++mCurrentInstallableIndex < mPebbleInstallables.length) {
                            mInstallState = PebbleAppInstallState.START_INSTALL;
                        } else {
                            mInstallState = PebbleAppInstallState.APP_REFRESH;
                        }
                        break;
                    case APP_REFRESH:
                        if (mPBWReader.isFirmware()) {
                            writeInstallApp(mPebbleProtocol.encodeInstallFirmwareComplete());
                            finishInstall(false);
                        } else if (mPBWReader.isLanguage() || mPebbleProtocol.mFwMajor >= 3) {
                            // FIXME: don't know yet how to detect success
                            finishInstall(false);
                        } else {
                            writeInstallApp(mPebbleProtocol.encodeAppRefresh(mInstallSlot));
                        }
                        break;
                    default:
                        break;
                }
            }
            if (mIsTCP) {
                mInStream.skip(6);
            }
            int bytes = readWithException(mInStream, buffer, 0, 4);
            while (bytes < 4) {
                bytes += readWithException(mInStream, buffer, bytes, 4 - bytes);
            }
            ByteBuffer buf = ByteBuffer.wrap(buffer);
            buf.order(ByteOrder.BIG_ENDIAN);
            short length = buf.getShort();
            short endpoint = buf.getShort();
            if (length < 0 || length > 8192) {
                LOG.info("invalid length " + length);
                while (mInStream.available() > 0) {
                    // read all
                    readWithException(mInStream, buffer, 0, buffer.length);
                }
                continue;
            }
            bytes = readWithException(mInStream, buffer, 4, length);
            while (bytes < length) {
                bytes += readWithException(mInStream, buffer, bytes + 4, length - bytes);
            }
            if (mIsTCP) {
                mInStream.skip(2);
            }
            GBDeviceEvent[] deviceEvents = mPebbleProtocol.decodeResponse(buffer);
            if (deviceEvents == null) {
                LOG.info("unhandled message to endpoint " + endpoint + " (" + length + " bytes)");
            } else {
                for (GBDeviceEvent deviceEvent : deviceEvents) {
                    if (deviceEvent == null) {
                        continue;
                    }
                    if (!evaluateGBDeviceEventPebble(deviceEvent)) {
                        mPebbleSupport.evaluateGBDeviceEvent(deviceEvent);
                    }
                }
            }
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        } catch (IOException e) {
            if (e.getMessage() != null && (e.getMessage().equals("broken pipe") || e.getMessage().contains("socket closed"))) {
                //FIXME: this does not feel right
                LOG.info(e.getMessage());
                mIsConnected = false;
                int reconnectAttempts = prefs.getInt("pebble_reconnect_attempts", 10);
                if (!mQuit && GBApplication.getGBPrefs().getAutoReconnect() && reconnectAttempts > 0) {
                    gbDevice.setState(GBDevice.State.WAITING_FOR_RECONNECT);
                    gbDevice.sendDeviceUpdateIntent(getContext());
                    int delaySeconds = 1;
                    while (reconnectAttempts-- > 0 && !mQuit && !mIsConnected) {
                        LOG.info("Trying to reconnect (attempts left " + reconnectAttempts + ")");
                        mIsConnected = connect();
                        if (!mIsConnected) {
                            try {
                                Thread.sleep(delaySeconds * 1000);
                            } catch (InterruptedException ignored) {
                            }
                            if (delaySeconds < 64) {
                                delaySeconds *= 2;
                            }
                        }
                    }
                }
                if (!mIsConnected) {
                    mBtSocket = null;
                    LOG.info("Bluetooth socket closed, will quit IO Thread");
                    break;
                }
            }
        }
    }
    mIsConnected = false;
    if (mBtSocket != null) {
        try {
            mBtSocket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        mBtSocket = null;
    }
    enablePebbleKitSupport(false);
    if (mQuit) {
        gbDevice.setState(GBDevice.State.NOT_CONNECTED);
    } else {
        gbDevice.setState(GBDevice.State.WAITING_FOR_RECONNECT);
    }
    gbDevice.sendDeviceUpdateIntent(getContext());
}
Also used : PebbleInstallable(nodomain.freeyourgadget.gadgetbridge.devices.pebble.PebbleInstallable) GBDeviceEvent(nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent) IOException(java.io.IOException) ByteBuffer(java.nio.ByteBuffer)

Aggregations

IOException (java.io.IOException)1 ByteBuffer (java.nio.ByteBuffer)1 GBDeviceEvent (nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent)1 PebbleInstallable (nodomain.freeyourgadget.gadgetbridge.devices.pebble.PebbleInstallable)1