def getPacket(self): """ Adds start token, header and CRC to payload. Escapes bytes. """ # Construct the packet for CRC calculation packet = [] packet.append(self.protocolMajor) packet.append(self.protocolMinor) packet.append(int(self.messageType)) packet += self.payload # Calculate the CRC of the packet packetCrc = crc16ccitt(packet) # Append the CRC to the base packet to escape the entire thing packet += Conversion.uint16_to_uint8_array(packetCrc) # Prepend the size field. sizeField = len(packet) packet = Conversion.uint16_to_uint8_array(sizeField) + packet # Escape everything except the start token packet = self.escapeCharacters(packet) # Prepend the start token. packet = [START_TOKEN] + packet return packet
def decrypt(self, data: int) -> bytes: data = Conversion.uint32_to_uint16_reversed_array(data) data = bytes(Conversion.uint16_array_to_uint8_array(data)) blocksize = self.blocksize key = self.key rounds = self.rounds w = blocksize // 2 b = blocksize // 8 expanded_key = _expand_key(key, w, rounds) index = b chunk = data[:index] out = [] while chunk: decrypted_chunk = _decrypt_block(chunk, expanded_key, blocksize, rounds) chunk = data[index:index + b] # Read in blocksize number of bytes if not chunk: decrypted_chunk = decrypted_chunk.rstrip(b"\x00") index += b out.append(decrypted_chunk) result = b"".join(out) result = Conversion.uint8_array_to_uint16_array(result) result = Conversion.uint16_reversed_array_to_uint32(result) return result
def encrypt(self, data: int) -> int: # alteration to accept numbers instead of bytes data = Conversion.uint32_to_uint16_reversed_array(data) data = bytes(Conversion.uint16_array_to_uint8_array(data)) blocksize = self.blocksize key = self.key rounds = self.rounds w = blocksize // 2 b = blocksize // 8 expanded_key = _expand_key(key, w, rounds) index = b chunk = data[:index] out = [] while chunk: chunk = chunk.ljust( b, b"\x00") # padding with 0 bytes if not large enough encrypted_chunk = _encrypt_block(chunk, expanded_key, blocksize, rounds) out.append(encrypted_chunk) chunk = data[index:index + b] # Read in blocksize number of bytes index += b result = b"".join(out) result = Conversion.uint8_array_to_uint16_array(result) result = Conversion.uint16_reversed_array_to_uint32(result) return result
def getIBeaconConfigIdPacket(id, timestamp, interval): data = [] data.append(id) data += Conversion.uint32_to_uint8_array(timestamp) data += Conversion.uint16_to_uint8_array(interval) return ControlPacket( ControlType.SET_IBEACON_CONFIG_ID).loadByteArray(data).serialize()
def serialize(self): arr = [] arr.append(self.presenceType.value) arr += Conversion.uint64_to_uint8_array(self.getMask(self.locationIds)) arr += Conversion.uint32_to_uint8_array(self.delayInSeconds) return arr
def obtainTimestamp(fullTimeStamp, lsb): timestampBytes = Conversion.uint32_to_uint8_array(int(fullTimeStamp)) lsbBytes = Conversion.uint16_to_uint8_array(lsb) restoredTimestamp = Conversion.uint8_array_to_uint32( [lsbBytes[0], lsbBytes[1], timestampBytes[2], timestampBytes[3]]) return restoredTimestamp
def __init__(self, payload): if len(payload) < self.packetSize: print("ERROR: INVALID PAYLOAD LENGTH", len(payload), payload) return self.timestampCounter = Conversion.uint8_array_to_uint32(payload[0:4]) self.samples = [] for i in range(4, self.packetSize, self.sampleSize): self.samples.append(Conversion.uint8_array_to_int16(payload[i:i+self.sampleSize]))
def getPacket(self): # TODO: make use of the base class, now there is a double implementation of the control packet. arr = [SUPPORTED_PROTOCOL_VERSION] arr += Conversion.uint16_to_uint8_array(self.type) arr += Conversion.uint16_to_uint8_array( self.length + 6 ) # the + 2 is for the stateType uint16, +2 for the id, +2 for persistenceMode and reserved arr += self.payload # this is the state type arr += Conversion.uint16_to_uint8_array(self.id) arr.append(self.persistenceMode) arr.append(0) return arr
def _verifyDecryption(decrypted, validationKey): # the conversion to uint32 only takes the first 4 bytes if Conversion.uint8_array_to_uint32( decrypted) == Conversion.uint8_array_to_uint32(validationKey): # remove checksum from decryption and return payload result = [0] * (len(decrypted) - SESSION_KEY_LENGTH) for i in range(0, len(result)): result[i] = decrypted[i + SESSION_KEY_LENGTH] return result else: raise CrownstoneBleException( EncryptionError.ENCRYPTION_VALIDATION_FAILED, "Failed to validate result, Could not decrypt")
def process(self): """ Process a buffer. Check CRC, and emit a uart packet. Buffer starts after size header, and includes wrapper header and tail (CRC). Return: processing success """ # Check size bufferSize = len(self.buffer) wrapperSize = WRAPPER_HEADER_SIZE + CRC_SIZE if bufferSize < wrapperSize: _LOGGER.warning("Buffer too small") return False # Get the buffer between size field and CRC: baseBuffer = self.buffer[0 : bufferSize - CRC_SIZE] # Check CRC calculatedCrc = crc16ccitt(baseBuffer) sourceCrc = Conversion.uint8_array_to_uint16(self.buffer[bufferSize - CRC_SIZE : ]) if calculatedCrc != sourceCrc: _LOGGER.warning("Failed CRC: {0} != {1} (data: {2})".format(calculatedCrc, sourceCrc, baseBuffer)) UartEventBus.emit(DevTopics.uartNoise, "crc mismatch") return False wrapperPacket = UartWrapperPacket() if wrapperPacket.parse(baseBuffer): UartEventBus.emit(SystemTopics.uartNewPackage, wrapperPacket) return True
def getPacket(self): packet = [SUPPORTED_PROTOCOL_VERSION] packet += Conversion.uint16_to_uint8_array(self.type) packet += self.lengthAsUint8Array packet += self.payload return packet
async def getUptime(self): """ Get the uptime of the crownstone in seconds. """ controlPacket = ControlPacket(ControlType.GET_UPTIME).getPacket() result = await self._writeControlAndGetResult(controlPacket) if result.resultCode != ResultValue.SUCCESS: raise CrownstoneException(CrownstoneError.RESULT_NOT_SUCCESS, "Result: " + str(result.resultCode)) return Conversion.uint8_array_to_uint32(result.payload)
def getPacket(self): arr = [] arr.append(self.timeType.value) arr += Conversion.int32_to_uint8_array(self.offset) return arr
def getSetupPacket(crownstoneId: int, sphereId: int, adminKey, memberKey, basicKey, serviceDataKey, localizationKey, meshDeviceKey, meshAppKey, meshNetworkKey, ibeaconUUID: str, ibeaconMajor: int, ibeaconMinor: int): """ :param crownstoneId: uint8 number :param sphereId: uint8 number :param adminKey: byteString (no conversion required) :param memberKey: byteString (no conversion required) :param basicKey: byteString (no conversion required) :param serviceDataKey: byteString (no conversion required) :param localizationKey: byteString (no conversion required) :param meshDeviceKey: byteString (no conversion required) :param meshAppKey: byteString (no conversion required) :param meshNetworkKey: byteString (no conversion required) :param ibeaconUUID: string (ie. "1843423e-e175-4af0-a2e4-31e32f729a8a") :param ibeaconMajor: uint16 number :param ibeaconMinor: uint16 number :return: """ data = [] data.append(crownstoneId) data.append(sphereId) data += list(adminKey) data += list(memberKey) data += list(basicKey) data += list(serviceDataKey) data += list(localizationKey) MDKey = meshDeviceKey if type(meshDeviceKey) is str: MDKey = Conversion.ascii_or_hex_string_to_16_byte_array( meshDeviceKey) data += list(MDKey) data += list(meshAppKey) data += list(meshNetworkKey) data += Conversion.ibeaconUUIDString_to_reversed_uint8_array( ibeaconUUID) data += Conversion.uint16_to_uint8_array(ibeaconMajor) data += Conversion.uint16_to_uint8_array(ibeaconMinor) return ControlPacket(ControlType.SETUP).loadByteArray(data).serialize()
def getPacket(self): # Header: 1B device ID, 2B opcode # construct the basePacket, which is used for CRC calculation uartMsg = [] uartMsg += Conversion.uint16_to_uint8_array(self.opCode) uartMsg += self.payload return uartMsg
def add(self, byte): self.rawBuffer.append(byte) # An escape shouldn't be followed by a special byte. if self.escapingNextByte and (byte is START_TOKEN or byte is ESCAPE_TOKEN): _LOGGER.warning("Received special byte after escape token.") self.reset(True) return # Activate on start token. if byte is START_TOKEN: if self.active: _LOGGER.warning("Received multiple start tokens.") self.reset(True) else: # Reset to be sure. self.reset() self.active = True return if not self.active: # Since the start token was not received, we discard this byte. self.reset(True) return # Escape next byte on escape token. if byte is ESCAPE_TOKEN: self.escapingNextByte = True return if self.escapingNextByte: byte ^= BIT_FLIP_MASK self.escapingNextByte = False self.buffer.append(byte) bufferSize = len(self.buffer) if self.sizeToRead == 0: # We didn't parse the size yet. if bufferSize == SIZE_HEADER_SIZE: # Now we know the remaining size to read self.sizeToRead = Conversion.uint8_array_to_uint16(self.buffer) # Size to read shouldn't be 0. if self.sizeToRead == 0: self.reset(True) return self.buffer = [] return elif bufferSize >= self.sizeToRead: processSuccessful = self.process() self.reset(not processSuccessful) return
def __init__(self, payload, channelIndex): if len(payload) < self.packetSize: print("ERROR: INVALID PAYLOAD LENGTH", len(payload), payload) return self.channelIndex = channelIndex self.pin = payload[0] self.range = Conversion.uint8_array_to_uint32(payload[1:1 + 4]) self.refPin = payload[5]
def add(self, byte): # An escape shouldn't be followed by a special byte. if self.escapingNextByte and (byte is START_TOKEN or byte is ESCAPE_TOKEN): _LOGGER.warning("Special byte after escape token") UartEventBus.emit(DevTopics.uartNoise, "special byte after escape token") self.reset() return # Activate on start token. if byte is START_TOKEN: if self.active: _LOGGER.warning("MULTIPLE START TOKENS") _LOGGER.debug( f"Multiple start tokens: sizeToRead={self.sizeToRead} bufLen={len(self.buffer)} buffer={self.buffer}" ) UartEventBus.emit(DevTopics.uartNoise, "multiple start token") self.reset() self.active = True return if not self.active: return # Escape next byte on escape token. if byte is ESCAPE_TOKEN: self.escapingNextByte = True return if self.escapingNextByte: byte ^= BIT_FLIP_MASK self.escapingNextByte = False self.buffer.append(byte) bufferSize = len(self.buffer) if self.sizeToRead == 0: # We didn't parse the size yet. if bufferSize == SIZE_HEADER_SIZE: # Now we know the remaining size to read self.sizeToRead = Conversion.uint8_array_to_uint16(self.buffer) # Size to read shouldn't be 0. if self.sizeToRead == 0: self.reset() return self.buffer = [] return elif bufferSize >= self.sizeToRead: self.process() self.reset() return
def __init__(self, byte): self.type = AdvType.CROWNSTONE_FLAGS bitmaskArray = Conversion.uint8_to_bit_array(byte) self.dimmerReady = bitmaskArray[0] self.dimmingAllowed = bitmaskArray[1] self.hasError = bitmaskArray[2] self.switchLocked = bitmaskArray[3] self.timeIsSet = bitmaskArray[4] self.switchCraftEnabled = bitmaskArray[5] self.tapToToggleEnabled = bitmaskArray[6] self.behaviourOverridden = bitmaskArray[7]
def __init__(self, bitMask): self.type = AdvType.CROWNSTONE_ERRORS self.bitMask = bitMask bitArray = Conversion.uint32_to_bit_array_reversed(bitMask) self.overCurrent = bitArray[31 - 0] self.overCurrentDimmer = bitArray[31 - 1] self.temperatureChip = bitArray[31 - 2] self.temperatureDimmer = bitArray[31 - 3] self.dimmerOnFailure = bitArray[31 - 4] self.dimmerOffFailure = bitArray[31 - 5]
def __init__(self, byte): self.type = AdvType.ALTERNATIVE_STATE bitmaskArray = Conversion.uint8_to_bit_array(byte) self.uartAlive = bitmaskArray[0] self.uartAliveEncrypted = bitmaskArray[1] self.uartEncryptionRequiredByCrownstone = bitmaskArray[2] self.uartEncryptionRequiredByHub = bitmaskArray[3] self.hubHasBeenSetUp = bitmaskArray[4] self.hubHasInternet = bitmaskArray[5] self.hubHasError = bitmaskArray[6] self.timeIsSet = bitmaskArray[7]
def test_add_contains(): """ Checks if _add(0), _add(1), ..., _add(max_items), _contains(0), _contains(1), ..., _contains(max_items), does what it 's supposed to do. A load factor is incorporated since cuckoo filters will not fit their theoretical max load. """ # Settings for this test max_buckets_log2 = 7 nests_per_bucket = 4 load_factor = 0.75 filter = CuckooFilter(max_buckets_log2, nests_per_bucket) # setup test variables max_items = filter.fingerprintcount() num_items_to_test = int(max_items * load_factor) fails = 0 # Add a lot of integers for i in range(num_items_to_test): i_as_uint8_list = Conversion.uint32_to_uint8_array(i) if not filter.add(i_as_uint8_list): fails += 1 assert fails == 0, "Add failed" fails = 0 # check if they ended up in the filter for i in range(num_items_to_test): i_as_uint8_list = Conversion.uint32_to_uint8_array(i) if not filter.contains(i_as_uint8_list): fails += 1 assert fails == 0, "Contains failed" fails = 0
def loadKeys(self, adminKey, memberKey, basicKey, serviceDataKey, localizationKey, meshApplicationKey, meshNetworkKey): self.adminKey = Conversion.ascii_or_hex_string_to_16_byte_array( adminKey) self.memberKey = Conversion.ascii_or_hex_string_to_16_byte_array( memberKey) self.basicKey = Conversion.ascii_or_hex_string_to_16_byte_array( basicKey) self.serviceDataKey = Conversion.ascii_or_hex_string_to_16_byte_array( serviceDataKey) self.localizationKey = Conversion.ascii_or_hex_string_to_16_byte_array( localizationKey) self.meshApplicationKey = Conversion.ascii_or_hex_string_to_16_byte_array( meshApplicationKey) self.meshNetworkKey = Conversion.ascii_or_hex_string_to_16_byte_array( meshNetworkKey) self.initializedKeys = True self.determineUserLevel()
def __init__(self, payload): if len(payload) < 1: print("ERROR: INVALID PAYLOAD LENGTH", len(payload), payload) return self.channels = [] index = 0 self.amountOfChannels = payload[index] index += 1 self.packetSize = self.amountOfChannels * self.channelSize + 1 + 4 # 4 for sampling period, 1 for count if len(payload) < self.packetSize: print("ERROR: INVALID PAYLOAD LENGTH", len(payload), payload) return for i in range(0, self.amountOfChannels): self.channels.append( AdcChannelPacket(payload[index:index + self.channelSize], i)) index += self.channelSize self.samplingPeriod = Conversion.uint8_array_to_uint32( payload[index:index + 4])
def process(self): """ Process a buffer. Check CRC, and emit a uart packet. Buffer starts after size header, and includes wrapper header and tail (CRC). """ # Check size bufferSize = len(self.buffer) wrapperSize = WRAPPER_HEADER_SIZE + CRC_SIZE if bufferSize < wrapperSize: _LOGGER.warning("Buffer too small") UartEventBus.emit(DevTopics.uartNoise, "buffer too small") return # Get the buffer between size field and CRC: baseBuffer = self.buffer[0:bufferSize - CRC_SIZE] # Check CRC calculatedCrc = crc16ccitt(baseBuffer) sourceCrc = Conversion.uint8_array_to_uint16(self.buffer[bufferSize - CRC_SIZE:]) if calculatedCrc != sourceCrc: _LOGGER.warning("Failed CRC") _LOGGER.debug( f"Failed CRC: sourceCrc={sourceCrc} calculatedCrc={calculatedCrc} bufSize={len(self.buffer)} buffer={self.buffer}" ) UartEventBus.emit(DevTopics.uartNoise, "crc mismatch") return wrapperPacket = UartWrapperPacket() if wrapperPacket.parse(baseBuffer): UartEventBus.emit(SystemTopics.uartNewPackage, wrapperPacket)
def write_uint16(outfile, val): for byt in Conversion.uint16_to_uint8_array(val): write_uint8(outfile, byt)
def __init__(self, byte): self.type = AdvType.MICROAPP_FLAGS bitmaskArray = Conversion.uint8_to_bit_array(byte) self.behaviourEnabled = bitmaskArray[0]
def getFloat(self): """ Get a float from the current position, and advance the position. """ return Conversion.uint8_array_to_float(self._request(4))
def getUInt64(self): """ Get a uint64 from the current position, and advance the position. """ return Conversion.uint8_array_to_uint64(self._request(8))
def getInt32(self): """ Get an int32 from the current position, and advance the position. """ return Conversion.uint8_array_to_int32(self._request(4))