Exemple #1
0
def _validate_and_strip_checksum(line):
    """Verify the simple 16-bit checksum and remove it from the line.

  Args:
    line: the line to check the checksum of.

  Returns:
    A copy of the line with the checksum stripped out.
  """
    match = _RESPONSE_MATCH.match(line)

    if not match:
        raise lifescan.MissingChecksum(line)

    response, checksum_string = match.groups()

    try:
        checksum_given = int(checksum_string, 16)
        checksum_calculated = _calculate_checksum(bytes(response, 'ascii'))

        if checksum_given != checksum_calculated:
            raise exceptions.InvalidChecksum(checksum_given,
                                             checksum_calculated)
    except ValueError:
        raise exceptions.InvalidChecksum(checksum_given, None)

    return response
    def _read_text_response(self) -> Sequence[bytes]:
        all_lines: List[bytes] = []

        while True:
            line = self._readline()
            if not line.endswith(b"\r\n"):
                raise exceptions.InvalidResponse(
                    f"Corrupted response line: {line!r}")
            all_lines.append(line)

            if line == b"]\r\n":
                break

        if all_lines[0] != b"[\r\n":
            raise exceptions.InvalidResponse(
                f"Unexpected first response line: {all_lines!r}")

        wire_checksum = int(all_lines[-2][:-2], base=16)
        calculated_checksum = _crc8_maxim(b"".join(all_lines[:-2]))

        if wire_checksum != calculated_checksum:
            raise exceptions.InvalidChecksum(wire_checksum,
                                             calculated_checksum)

        return [line[:-2] for line in all_lines[1:-2]]
Exemple #3
0
 def _fetch_device_information(self):
     data = self._send_command('mem')
     res = _parse_result(data)
     self.info_ = res['info']
     self.device_results_ = res['reslog']
     self.device_checksum_ = res['checksum']
     self.device_version_ = self.info_['device_version_']
     self.software_revision_ = self.info_['software_revision_']
     self.device_serialno_ = self.info_['device_serialno_']
     self.device_glucose_unit_ = self.info_['device_glucose_unit_']
     self.device_current_date_time_ = self.info_[
         'device_current_date_time_']
     self.device_nrresults_ = self.info_['device_nrresults_']
     # exclude the last line which is the checksum itself.
     # every  line is ended with a windows end-of-line \r\n
     # except line 6  ends  with a linux   end-of-line \n
     n = self.device_nrresults_
     if n > 0:
         wnl = (ord('\r') + ord('\n')) * (_INFO_SIZE + n
                                          )  # windows end of line
         lnl = ord('\n')  # linux end of line
         ce = self.device_checksum_  # expected
         cg = (sum(ord(c) for c in ''.join(data[:-1])) + wnl + lnl) % (
             2**16)  # gotten
         if ce != cg:
             raise exceptions.InvalidChecksum(ce, cg)
Exemple #4
0
def _verify_checksum(message, expected_checksum_hex):
    """Calculate the simple checksum of the message and compare with expected.

    Args:
      message: (str) message to calculate the checksum of.
      expected_checksum_hex: (str) hexadecimal string representing the checksum
        expected to match the message.

    Raises:
      InvalidChecksum: if the message checksum calculated does not match the one
        received.
    """
    expected_checksum = int(expected_checksum_hex, 16)
    calculated_checksum = sum(ord(c) for c in message)

    if expected_checksum != calculated_checksum:
        raise exceptions.InvalidChecksum(expected_checksum, calculated_checksum)
Exemple #5
0
def _extract_message(register):
    """Parse the message preamble and verify checksums."""
    stx, length = _STRUCT_PREAMBLE.unpack_from(register)
    if stx != _STX:
        raise lifescan.MalformedCommand('invalid STX byte: %02x' % stx)
    if length > _REGISTER_SIZE:
        raise lifescan.MalformedCommand('invalid length: %d > REGISTER_SIZE' %
                                        length)

    # 2 is the length of the checksum, so it should be ignored.
    calculated_checksum = lifescan.crc_ccitt(register[:(length - 2)])

    coda_offset = length - _STRUCT_CODA.size
    etx, encoded_checksum = _STRUCT_CODA.unpack_from(register[coda_offset:])
    if etx != _ETX:
        raise lifescan.MalformedCommand('invalid ETX byte: %02x' % etx)
    if encoded_checksum != calculated_checksum:
        raise exceptions.InvalidChecksum(encoded_checksum, calculated_checksum)

    response = register[_STRUCT_PREAMBLE.size:coda_offset]
    return response
def _verify_checksum(message: AnyStr, expected_checksum_hex: AnyStr) -> None:
    """Calculate the simple checksum of the message and compare with expected.

    Args:
      message: (str) message to calculate the checksum of.
      expected_checksum_hex: hexadecimal string representing the checksum
        expected to match the message.

    Raises:
      InvalidChecksum: if the message checksum calculated does not match the one
        received.
    """
    expected_checksum = int(expected_checksum_hex, 16)
    if isinstance(message, bytes):
        all_bytes = (c for c in message)
    else:
        all_bytes = (ord(c) for c in message)

    calculated_checksum = sum(all_bytes)

    if expected_checksum != calculated_checksum:
        raise exceptions.InvalidChecksum(expected_checksum, calculated_checksum)
Exemple #7
0
    def get_readings(self) -> Generator[common.AnyReading, None, None]:
        """Iterates over the reading values stored in the glucometer.

        Args:
          unit: The glucose unit to use for the output.

        Yields: A tuple (date, value) of the readings in the glucometer. The
          value is a floating point in the unit specified; if no unit is
          specified, the default unit in the glucometer will be used.

        Raises:
          exceptions.InvalidResponse: if the response does not match what '
          expected.

        """
        data = self._send_command("xmem")

        # The first line is empty, the second is the serial number, the third
        # the version, the fourth the current time, and the fifth the record
        # count.. The last line has a checksum and the end.
        count = int(data[4])
        if count != (len(data) - 6):
            raise exceptions.InvalidResponse("\n".join(data))

        # Extract the checksum from the last line.
        checksum_match = _CHECKSUM_RE.match(data[-1])
        if not checksum_match:
            raise exceptions.InvalidResponse("\n".join(data))

        expected_checksum = int(checksum_match.group("checksum"), 16)
        # exclude the last line in the checksum calculation, as that's the
        # checksum itself. The final \r\n is added separately.
        calculated_checksum = sum(ord(c) for c in "\r\n".join(data[:-1])) + 0xD + 0xA

        if expected_checksum != calculated_checksum:
            raise exceptions.InvalidChecksum(expected_checksum, calculated_checksum)

        for line in data[5:-1]:
            match = _READING_RE.match(line)
            if not match:
                raise exceptions.InvalidResponse(line)

            if match.group("type") != "G":
                logging.warning("Non-glucose readings are not supported, ignoring.")
                continue

            if match.group("reading") == "HI ":
                value = float("inf")
            else:
                value = float(match.group("reading"))

            day = int(match.group("day"))
            month = _MONTH_MATCHES[match.group("month")]
            year = int(match.group("year"))

            hour, minute = map(int, match.group("time").split(":"))

            timestamp = datetime.datetime(year, month, day, hour, minute)

            # The reading, if present, is always in mg/dL even if the glucometer
            # is set to mmol/L.
            yield common.GlucoseReading(timestamp, value)
Exemple #8
0
 def validate_checksum(self):
     expected_checksum = self.checksum
     received_checksum = self._STRUCT.unpack(self.cmd[_IDX_CHECKSUM:])[0]
     if received_checksum != expected_checksum:
         raise exceptions.InvalidChecksum(expected_checksum,
                                          received_checksum)
Exemple #9
0
    def get_readings(self):
        """Iterates over the reading values stored in the glucometer.

    Args:
      unit: The glucose unit to use for the output.

    Yields:
      A tuple (date, value) of the readings in the glucometer. The value is a
      floating point in the unit specified; if no unit is specified, the default
      unit in the glucometer will be used.

    Raises:
      exceptions.InvalidResponse: if the response does not match what expected.
    """
        data = self._send_command('xmem')

        # The first line is empty, the second is the serial number, the third the
        # version, the fourth the current time, and the fifth the record count.. The
        # last line has a checksum and the end.
        count = int(data[4])
        if count != (len(data) - 6):
            raise exceptions.InvalidResponse('\n'.join(data))

        # Extract the checksum from the last line.
        checksum_match = _CHECKSUM_RE.match(data[-1])
        if not checksum_match:
            raise exceptions.InvalidResponse('\n'.join(data))

        expected_checksum = int(checksum_match.group('checksum'), 16)
        # exclude the last line in the checksum calculation, as that's the checksum
        # itself. The final \r\n is added separately.
        calculated_checksum = sum(ord(c)
                                  for c in '\r\n'.join(data[:-1])) + 0xd + 0xa

        if expected_checksum != calculated_checksum:
            raise exceptions.InvalidChecksum(expected_checksum,
                                             calculated_checksum)

        for line in data[5:-1]:
            match = _READING_RE.match(line)
            if not match:
                raise exceptions.InvalidResponse(line)

            if match.group('type') != 'G':
                print('Non-glucose readings are not supported, ignoring.',
                      file=sys.stderr)
                continue

            if match.group('reading') == 'HI ':
                value = float("inf")
            else:
                value = float(match.group('reading'))

            day = int(match.group('day'))
            month = _MONTH_MATCHES[match.group('month')]
            year = int(match.group('year'))

            hour, minute = map(int, match.group('time').split(':'))

            timestamp = datetime.datetime(year, month, day, hour, minute)

            # The reading, if present, is always in mg/dL even if the glucometer is
            # set to mmol/L.
            yield common.Reading(timestamp, value)