|
27 | 27 | """
|
28 | 28 |
|
29 | 29 | import time
|
| 30 | +import struct |
30 | 31 | from digitalio import Direction
|
31 | 32 | from micropython import const
|
32 | 33 |
|
@@ -501,6 +502,101 @@ def mifare_classic_write_block(
|
501 | 502 | )
|
502 | 503 | return response[0] == 0x0
|
503 | 504 |
|
| 505 | + def mifare_classic_sub_value_block(self, block_number: int, amount: int) -> bool: |
| 506 | + """Decrease the balance of a value block. Block number should be the block |
| 507 | + to change and amount should be an integer up to a maximum of 2147483647. |
| 508 | + If the value block is successfully updated then True is returned, |
| 509 | + otherwise False is returned. |
| 510 | + """ |
| 511 | + params = [0x01, MIFARE_CMD_DECREMENT, block_number & 0xFF] |
| 512 | + params.extend(list(amount.to_bytes(4, "little"))) |
| 513 | + |
| 514 | + response = self.call_function( |
| 515 | + _COMMAND_INDATAEXCHANGE, params=params, response_length=1 |
| 516 | + ) |
| 517 | + if response[0] != 0x00: |
| 518 | + return False |
| 519 | + |
| 520 | + response = self.call_function( |
| 521 | + _COMMAND_INDATAEXCHANGE, |
| 522 | + params=[0x01, MIFARE_CMD_TRANSFER, block_number & 0xFF], |
| 523 | + response_length=1, |
| 524 | + ) |
| 525 | + |
| 526 | + return response[0] == 0x00 |
| 527 | + |
| 528 | + def mifare_classic_add_value_block(self, block_number: int, amount: int) -> bool: |
| 529 | + """Increase the balance of a value block. Block number should be the block |
| 530 | + to change and amount should be an integer up to a maximum of 2147483647. |
| 531 | + If the value block is successfully updated then True is returned, |
| 532 | + otherwise False is returned. |
| 533 | + """ |
| 534 | + params = [0x01, MIFARE_CMD_INCREMENT, block_number & 0xFF] |
| 535 | + params.extend(list(amount.to_bytes(4, "little"))) |
| 536 | + |
| 537 | + response = self.call_function( |
| 538 | + _COMMAND_INDATAEXCHANGE, params=params, response_length=1 |
| 539 | + ) |
| 540 | + if response[0] != 0x00: |
| 541 | + return False |
| 542 | + |
| 543 | + response = self.call_function( |
| 544 | + _COMMAND_INDATAEXCHANGE, |
| 545 | + params=[0x01, MIFARE_CMD_TRANSFER, block_number & 0xFF], |
| 546 | + response_length=1, |
| 547 | + ) |
| 548 | + |
| 549 | + return response[0] == 0x00 |
| 550 | + |
| 551 | + def mifare_classic_get_value_block(self, block_number: int) -> int: |
| 552 | + """Read the contents of a value block and return a integer representing the |
| 553 | + current balance. Block number should be the block to read. |
| 554 | + """ |
| 555 | + block = self.mifare_classic_read_block(block_number=block_number) |
| 556 | + if block is None: |
| 557 | + return None |
| 558 | + |
| 559 | + value = block[0:4] |
| 560 | + value_inverted = block[4:8] |
| 561 | + value_backup = block[8:12] |
| 562 | + if value != value_backup: |
| 563 | + raise RuntimeError( |
| 564 | + "Value block bytes 0-3 do not match 8-11: " |
| 565 | + + "".join("%02x" % b for b in block) |
| 566 | + ) |
| 567 | + if value_inverted != bytearray(map((lambda x: x ^ 0xFF), value)): |
| 568 | + raise RuntimeError( |
| 569 | + "Inverted value block bytes 4-7 not valid: " |
| 570 | + + "".join("%02x" % b for b in block) |
| 571 | + ) |
| 572 | + |
| 573 | + return struct.unpack("<i", value)[0] |
| 574 | + |
| 575 | + def mifare_classic_fmt_value_block( |
| 576 | + self, block_number: int, initial_value: int, address_block: int = 0 |
| 577 | + ) -> bool: |
| 578 | + """Formats a block on the card so it is suitable for use as a value block. |
| 579 | + Block number should be the block to use. Initial value should be an integer |
| 580 | + up to a maximum of 2147483647. Address block is optional and can be used |
| 581 | + as part of backup management. |
| 582 | + """ |
| 583 | + data = bytearray() |
| 584 | + initial_value = initial_value.to_bytes(4, "little") |
| 585 | + # Value |
| 586 | + data.extend(initial_value) |
| 587 | + # Inverted value |
| 588 | + data.extend(bytearray(map((lambda x: x ^ 0xFF), initial_value))) |
| 589 | + # Duplicate of value |
| 590 | + data.extend(initial_value) |
| 591 | + |
| 592 | + # Address |
| 593 | + address_block = address_block.to_bytes(1, "little")[0] |
| 594 | + data.extend( |
| 595 | + [address_block, address_block ^ 0xFF, address_block, address_block ^ 0xFF] |
| 596 | + ) |
| 597 | + |
| 598 | + return self.mifare_classic_write_block(block_number, data) |
| 599 | + |
504 | 600 | def ntag2xx_write_block(self, block_number: int, data: ReadableBuffer) -> bool:
|
505 | 601 | """Write a block of data to the card. Block number should be the block
|
506 | 602 | to write and data should be a byte array of length 4 with the data to
|
|
0 commit comments