private void sendFrame(ShieldFrame frame) {
   if (frame == null) return;
   byte[] frameBytes = frame.getAllFrameAsBytes();
   sendData(frameBytes);
   Log.d("Device " + this.name + ": Frame sent, values: " + frame + ".");
 }
    @Override
    public void run() {
      while (!this.isInterrupted()) {
        try {
          while ((readByteFromSerialBuffer()) != ShieldFrame.START_OF_FRAME) ;
          if (ShieldFrameTimeout != null) ShieldFrameTimeout.stopTimer();
          ShieldFrameTimeout = new TimeOut(1000);
          int tempArduinoLibVersion = readByteFromSerialBuffer();
          byte shieldId = readByteFromSerialBuffer();
          byte instanceId = readByteFromSerialBuffer();
          byte functionId = readByteFromSerialBuffer();
          ShieldFrame frame = new ShieldFrame(shieldId, functionId);
          int argumentsNumber = readByteFromSerialBuffer() & 0xFF;
          int argumentsNumberVerification = (255 - (readByteFromSerialBuffer() & 0xFF));
          if (argumentsNumber != argumentsNumberVerification) {
            Log.d(
                "Device "
                    + OneSheeldDevice.this.name
                    + ": Frame is incorrect, canceling what we've read so far.");
            if (ShieldFrameTimeout != null) ShieldFrameTimeout.stopTimer();
            serialBuffer.clear();
            continue;
          }
          boolean continueRequested = false;
          for (int i = 0; i < argumentsNumber; i++) {
            int length = readByteFromSerialBuffer() & 0xFF;
            int lengthVerification = (255 - (readByteFromSerialBuffer() & 0xFF));
            if (length != lengthVerification || length <= 0) {
              Log.d(
                  "Device "
                      + OneSheeldDevice.this.name
                      + ": Frame is incorrect, canceling what we've read so far.");
              if (ShieldFrameTimeout != null) ShieldFrameTimeout.stopTimer();
              serialBuffer.clear();
              continueRequested = true;
              break;
            }
            byte[] data = new byte[length];
            for (int j = 0; j < length; j++) {
              data[j] = readByteFromSerialBuffer();
            }
            frame.addArgument(data);
          }
          if (continueRequested) continue;
          if ((readByteFromSerialBuffer()) != ShieldFrame.END_OF_FRAME) {
            Log.d(
                "Device "
                    + OneSheeldDevice.this.name
                    + ": Frame is incorrect, canceling what we've read so far.");
            if (ShieldFrameTimeout != null) ShieldFrameTimeout.stopTimer();
            serialBuffer.clear();
            continue;
          }
          if (ShieldFrameTimeout != null) ShieldFrameTimeout.stopTimer();
          if (arduinoLibraryVersion != tempArduinoLibVersion) {
            arduinoLibraryVersion = tempArduinoLibVersion;
            isLibraryVersionQueried = true;
            Log.d(
                "Device "
                    + OneSheeldDevice.this.name
                    + ": Device replied with library version: "
                    + arduinoLibraryVersion
                    + ".");
            onLibraryVersionQueryResponse(arduinoLibraryVersion);
          }

          if (shieldId == CONFIGURATION_SHIELD_ID) {
            if (functionId == LIBRARY_VERSION_RESPONSE) {
            } else if (functionId == IS_HARDWARE_CONNECTED_QUERY) {
              notifyHardwareOfConnection();
            } else if (functionId == IS_CALLBACK_ENTERED) {
              callbackEntered();
            } else if (functionId == IS_CALLBACK_EXITED) {
              callbackExited();
            }
          } else {
            Log.d(
                "Device " + OneSheeldDevice.this.name + ": Frame received, values: " + frame + ".");
            for (OneSheeldDataCallback oneSheeldDataCallback : dataCallbacks) {
              oneSheeldDataCallback.onShieldFrameReceive(frame);
              if (OneSheeldSdk.getKnownShields().contains(shieldId)
                  && OneSheeldSdk.getKnownShields()
                      .getKnownShield(shieldId)
                      .getKnownFunctions()
                      .contains(KnownFunction.getFunctionWithId(functionId)))
                oneSheeldDataCallback.onKnownShieldFrameReceive(
                    OneSheeldSdk.getKnownShields().getKnownShield(shieldId), frame);
            }
          }
        } catch (InterruptedException e) {
          return;
        } catch (ShieldFrameNotComplete e) {
          Log.d(
              "Device "
                  + OneSheeldDevice.this.name
                  + ": Frame wasn't completed in 1 second, canceling what we've read so far.");
          if (ShieldFrameTimeout != null) ShieldFrameTimeout.stopTimer();
          ShieldFrameTimeout = null;
          continue;
        }
      }
    }