Skip to content

Conversation

zinongli
Copy link
Contributor

@zinongli zinongli commented Jul 29, 2025

What's new

Traverse:

  • Resolves NFC Enhancement: FeliCa Poller Enumerate Through All Service Codes #4134
  • Added felica_poller_state_handler_traverse_system to be among other felica poller states in lib/nfc/protocols/felica.c. It intercepts after activation and auth, before read blocks.
  • The literal tx rx commands are handled by felica_poller_list_service_by_cursor and felica_poller_prepare_tx_buffer_raw in felica_poller_i.c. Very similar logic to other felica poller states.
  • Because of the dynamic nature of the available service codes (newer entries are added with new tag responses and total count is never announced), I sneaked in some helper functions and a struct (DynamicVector). If there are existing solutions I would be happy to switch and not having to create my own.

Block dump:

  • Poller run: Diverge the read_blocks process after detecting whether the tag is Felica Standard or FeliCa Lite. The previous implementation with hardcoded service and blocks number was only applicable to FeliCa Lite. Now after activation the IC type (Standard or Lite or others) will be determined from PMm. From there we direct the poller to go for Standard workflow (traverse system -> dump standard blocks -> success/fail) or Lite workflow (dump lite blocks -> success/fail).
  • Dump blocks state handler: Iterate through all the services readable without auth. Read blocks until exhausting the list (if either staus flag turns non-zero). Save all the dumped blocks into a SimpleArray.
  • Render: Created a new submenu screen similar to DESFire application & file view. User can navigate through the publicly readable services. When they enter each service's screen, a TextBox prints the blocks read.
  • Save: save all the readings into human readable tables. See below for example.
  • Load: Kept backward compatibility for files saved from previous version (i.e. if felica_data_format_version = 1). Because previous implementation treated all the FeliCa tags as FeliCa Lite, if we detect the data format version is one, we temporarily assume the tag to be Lite, proceed to parse and load the same way it was done before.

Check list:

  • poller
  • render
  • save
  • load

This PR is intended for future support for automatic dump of all publicly readable services. Before we dump we need to know what is out there. This is done.

Example dump file from reading a FeliCa Standard:

Filetype: Flipper NFC device
Version: 4
# Device type can be ISO14443-3A, ISO14443-3B, ISO14443-4A, ISO14443-4B, ISO15693-3, FeliCa, NTAG/Ultralight, Mifare Classic, Mifare Plus, Mifare DESFire, SLIX, ST25TB
Device type: FeliCa
# UID is common for all formats
UID: 01 01 01 12 D5 20 F3 28
# FeliCa specific data
Data format version: 2
Manufacture id: 01 01 01 12 D5 20 F3 28
Manufacture parameter: 05 31 43 45 46 82 B7 FF
IC Type: FeliCa Standard RC-S, Japan Transit IC

# Felica Standard specific data
Area found: 9
Area 000: | Code 0000 | Services #000-#000 |
Area 001: | Code 0040 | Services #000-#003 |
Area 002: | Code 00C0 | Services #004-#00B |
Area 003: | Code 0800 | Services #00C-#019 |
Area 004: | Code 0FC0 | Services #01A-#000 |
Area 005: | Code 1000 | Services #01A-#025 |
Area 006: | Code 17C0 | Services #026-#000 |
Area 007: | Code 1800 | Services #026-#031 |
Area 008: | Code 2300 | Services #032-#039 |

Service found: 58
Service 000: | Code 0048 | Attrib. 08 | Private | Random | Read/Write |
Service 001: | Code 004A | Attrib. 0A | Private | Random | Read Only  |
Service 002: | Code 0088 | Attrib. 08 | Private | Random | Read/Write |
Service 003: | Code 008B | Attrib. 0B | Public  | Random | Read Only  |
Service 004: | Code 00C8 | Attrib. 08 | Private | Random | Read/Write |
Service 005: | Code 00CA | Attrib. 0A | Private | Random | Read Only  |
Service 006: | Code 00CC | Attrib. 0C | Private | Random | Read/Write |
Service 007: | Code 00CE | Attrib. 0E | Private | Random | Read Only  |
Service 008: | Code 00D0 | Attrib. 10 | Private | Purse  | Direct     |
Service 009: | Code 00D2 | Attrib. 12 | Private | Purse  | Cashback   |
Service 00A: | Code 00D4 | Attrib. 14 | Private | Purse  | Decrement  |
Service 00B: | Code 00D6 | Attrib. 16 | Private | Purse  | Read Only  |
Service 00C: | Code 0810 | Attrib. 10 | Private | Purse  | Direct     |
Service 00D: | Code 0812 | Attrib. 12 | Private | Purse  | Cashback   |
Service 00E: | Code 0816 | Attrib. 16 | Private | Purse  | Read Only  |
Service 00F: | Code 0850 | Attrib. 10 | Private | Purse  | Direct     |
Service 010: | Code 0852 | Attrib. 12 | Private | Purse  | Cashback   |
Service 011: | Code 0856 | Attrib. 16 | Private | Purse  | Read Only  |
Service 012: | Code 0890 | Attrib. 10 | Private | Purse  | Direct     |
Service 013: | Code 0892 | Attrib. 12 | Private | Purse  | Cashback   |
Service 014: | Code 0896 | Attrib. 16 | Private | Purse  | Read Only  |
Service 015: | Code 08C8 | Attrib. 08 | Private | Random | Read/Write |
Service 016: | Code 08CA | Attrib. 0A | Private | Random | Read Only  |
Service 017: | Code 090A | Attrib. 0A | Private | Random | Read Only  |
Service 018: | Code 090C | Attrib. 0C | Private | Random | Read/Write |
Service 019: | Code 090F | Attrib. 0F | Public  | Random | Read Only  |
Service 01A: | Code 1008 | Attrib. 08 | Private | Random | Read/Write |
Service 01B: | Code 100A | Attrib. 0A | Private | Random | Read Only  |
Service 01C: | Code 1048 | Attrib. 08 | Private | Random | Read/Write |
Service 01D: | Code 104A | Attrib. 0A | Private | Random | Read Only  |
Service 01E: | Code 108C | Attrib. 0C | Private | Random | Read/Write |
Service 01F: | Code 108F | Attrib. 0F | Public  | Random | Read Only  |
Service 020: | Code 10C8 | Attrib. 08 | Private | Random | Read/Write |
Service 021: | Code 10CB | Attrib. 0B | Public  | Random | Read Only  |
Service 022: | Code 1108 | Attrib. 08 | Private | Random | Read/Write |
Service 023: | Code 110A | Attrib. 0A | Private | Random | Read Only  |
Service 024: | Code 1148 | Attrib. 08 | Private | Random | Read/Write |
Service 025: | Code 114A | Attrib. 0A | Private | Random | Read Only  |
Service 026: | Code 1808 | Attrib. 08 | Private | Random | Read/Write |
Service 027: | Code 180A | Attrib. 0A | Private | Random | Read Only  |
Service 028: | Code 1848 | Attrib. 08 | Private | Random | Read/Write |
Service 029: | Code 184B | Attrib. 0B | Public  | Random | Read Only  |
Service 02A: | Code 18C8 | Attrib. 08 | Private | Random | Read/Write |
Service 02B: | Code 18CA | Attrib. 0A | Private | Random | Read Only  |
Service 02C: | Code 1908 | Attrib. 08 | Private | Random | Read/Write |
Service 02D: | Code 190A | Attrib. 0A | Private | Random | Read Only  |
Service 02E: | Code 1948 | Attrib. 08 | Private | Random | Read/Write |
Service 02F: | Code 194B | Attrib. 0B | Public  | Random | Read Only  |
Service 030: | Code 1988 | Attrib. 08 | Private | Random | Read/Write |
Service 031: | Code 198B | Attrib. 0B | Public  | Random | Read Only  |
Service 032: | Code 2308 | Attrib. 08 | Private | Random | Read/Write |
Service 033: | Code 230A | Attrib. 0A | Private | Random | Read Only  |
Service 034: | Code 2348 | Attrib. 08 | Private | Random | Read/Write |
Service 035: | Code 234B | Attrib. 0B | Public  | Random | Read Only  |
Service 036: | Code 2388 | Attrib. 08 | Private | Random | Read/Write |
Service 037: | Code 238B | Attrib. 0B | Public  | Random | Read Only  |
Service 038: | Code 23C8 | Attrib. 08 | Private | Random | Read/Write |
Service 039: | Code 23CB | Attrib. 0B | Public  | Random | Read Only  |

Directory Tree: 
+++ ... are public services
||| ... are private services
- AREA_0000/
|- AREA_0001/
| |- serv_0048
| |- serv_004A
| |- serv_0088
+ +- serv_008B
|- AREA_0003/
| |- serv_00C8
| |- serv_00CA
| |- serv_00CC
| |- serv_00CE
| |- serv_00D0
| |- serv_00D2
| |- serv_00D4
| |- serv_00D6
|- AREA_0020/
| |- serv_0810
| |- serv_0812
| |- serv_0816
| |- serv_0850
| |- serv_0852
| |- serv_0856
| |- serv_0890
| |- serv_0892
| |- serv_0896
| |- serv_08C8
| |- serv_08CA
| |- serv_090A
| |- serv_090C
+ +- serv_090F
|- AREA_003F/
| |- AREA_0040/
| | |- serv_1008
| | |- serv_100A
| | |- serv_1048
| | |- serv_104A
| | |- serv_108C
+ + +- serv_108F
| | |- serv_10C8
+ + +- serv_10CB
| | |- serv_1108
| | |- serv_110A
| | |- serv_1148
| | |- serv_114A
| |- AREA_005F/
| | |- AREA_0060/
| | | |- serv_1808
| | | |- serv_180A
| | | |- serv_1848
+ + + +- serv_184B
| | | |- serv_18C8
| | | |- serv_18CA
| | | |- serv_1908
| | | |- serv_190A
| | | |- serv_1948
+ + + +- serv_194B
| | | |- serv_1988
+ + + +- serv_198B
| | |- AREA_008C/
| | | |- serv_2308
| | | |- serv_230A
| | | |- serv_2348
+ + + +- serv_234B
| | | |- serv_2388
+ + + +- serv_238B
| | | |- serv_23C8
+ + + +- serv_23CB

Public blocks read: 105
Block 0000: | Service code 008B | Block index 00 | Data: 00 00 00 00 00 00 00 00 20 00 00 1B 00 00 00 05 |
Block 0001: | Service code 090F | Block index 00 | Data: 16 01 00 05 31 55 D5 02 D6 06 1B 00 00 00 05 00 |
Block 0002: | Service code 090F | Block index 01 | Data: 1D 01 00 02 31 55 01 08 01 07 62 01 00 00 03 00 |
Block 0003: | Service code 090F | Block index 02 | Data: 12 07 00 00 31 55 82 08 00 00 F4 01 00 00 01 00 |
Block 0004: | Service code 090F | Block index 03 | Data: 00 00 00 80 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 0005: | Service code 090F | Block index 04 | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 0006: | Service code 090F | Block index 05 | Data: 00 00 00 80 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 0007: | Service code 090F | Block index 06 | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 0008: | Service code 090F | Block index 07 | Data: 00 00 00 80 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 0009: | Service code 090F | Block index 08 | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 000A: | Service code 090F | Block index 09 | Data: 00 00 00 80 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 000B: | Service code 090F | Block index 0A | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 000C: | Service code 090F | Block index 0B | Data: 00 00 00 80 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 000D: | Service code 090F | Block index 0C | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 000E: | Service code 090F | Block index 0D | Data: 00 00 00 80 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 000F: | Service code 090F | Block index 0E | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 0010: | Service code 090F | Block index 0F | Data: 00 00 00 80 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 0011: | Service code 090F | Block index 10 | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 0012: | Service code 090F | Block index 11 | Data: 00 00 00 80 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 0013: | Service code 090F | Block index 12 | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 0014: | Service code 090F | Block index 13 | Data: 00 00 00 80 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 0015: | Service code 108F | Block index 00 | Data: 20 00 D6 06 20 03 31 55 14 38 47 01 00 00 00 00 |
Block 0016: | Service code 108F | Block index 01 | Data: A0 00 D5 02 91 05 31 55 14 21 92 00 00 00 00 00 |
Block 0017: | Service code 108F | Block index 02 | Data: A0 00 01 08 10 07 31 55 14 14 00 00 00 00 00 00 |
Block 0018: | Service code 10CB | Block index 00 | Data: D5 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 0019: | Service code 10CB | Block index 01 | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 001A: | Service code 184B | Block index 00 | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 001B: | Service code 184B | Block index 01 | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 001C: | Service code 184B | Block index 02 | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 001D: | Service code 184B | Block index 03 | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 001E: | Service code 184B | Block index 04 | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 001F: | Service code 184B | Block index 05 | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 0020: | Service code 184B | Block index 06 | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 0021: | Service code 184B | Block index 07 | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 0022: | Service code 184B | Block index 08 | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 0023: | Service code 184B | Block index 09 | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 0024: | Service code 184B | Block index 0A | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 0025: | Service code 184B | Block index 0B | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 0026: | Service code 184B | Block index 0C | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 0027: | Service code 184B | Block index 0D | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 0028: | Service code 184B | Block index 0E | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 0029: | Service code 184B | Block index 0F | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 002A: | Service code 184B | Block index 10 | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 002B: | Service code 184B | Block index 11 | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 002C: | Service code 184B | Block index 12 | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 002D: | Service code 184B | Block index 13 | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 002E: | Service code 184B | Block index 14 | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 002F: | Service code 184B | Block index 15 | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 0030: | Service code 184B | Block index 16 | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 0031: | Service code 184B | Block index 17 | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 0032: | Service code 184B | Block index 18 | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 0033: | Service code 184B | Block index 19 | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 0034: | Service code 184B | Block index 1A | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 0035: | Service code 184B | Block index 1B | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 0036: | Service code 184B | Block index 1C | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 0037: | Service code 184B | Block index 1D | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 0038: | Service code 184B | Block index 1E | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 0039: | Service code 184B | Block index 1F | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 003A: | Service code 184B | Block index 20 | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 003B: | Service code 184B | Block index 21 | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 003C: | Service code 184B | Block index 22 | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 003D: | Service code 184B | Block index 23 | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 003E: | Service code 194B | Block index 00 | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 003F: | Service code 194B | Block index 01 | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 0040: | Service code 194B | Block index 02 | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 0041: | Service code 194B | Block index 03 | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 0042: | Service code 194B | Block index 04 | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 0043: | Service code 194B | Block index 05 | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 0044: | Service code 194B | Block index 06 | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 0045: | Service code 194B | Block index 07 | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 0046: | Service code 194B | Block index 08 | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 0047: | Service code 194B | Block index 09 | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 0048: | Service code 194B | Block index 0A | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 0049: | Service code 194B | Block index 0B | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 004A: | Service code 194B | Block index 0C | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 004B: | Service code 194B | Block index 0D | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 004C: | Service code 194B | Block index 0E | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 004D: | Service code 194B | Block index 0F | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 004E: | Service code 198B | Block index 00 | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 004F: | Service code 198B | Block index 01 | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 0050: | Service code 198B | Block index 02 | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 0051: | Service code 234B | Block index 00 | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 0052: | Service code 234B | Block index 01 | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 0053: | Service code 234B | Block index 02 | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 0054: | Service code 234B | Block index 03 | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 0055: | Service code 238B | Block index 00 | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 0056: | Service code 238B | Block index 01 | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 0057: | Service code 238B | Block index 02 | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 0058: | Service code 238B | Block index 03 | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 0059: | Service code 238B | Block index 04 | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 005A: | Service code 238B | Block index 05 | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 005B: | Service code 238B | Block index 06 | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 005C: | Service code 238B | Block index 07 | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 005D: | Service code 238B | Block index 08 | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 005E: | Service code 238B | Block index 09 | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 005F: | Service code 238B | Block index 0A | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 0060: | Service code 238B | Block index 0B | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 0061: | Service code 238B | Block index 0C | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 0062: | Service code 238B | Block index 0D | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 0063: | Service code 238B | Block index 0E | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 0064: | Service code 238B | Block index 0F | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 0065: | Service code 23CB | Block index 00 | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 0066: | Service code 23CB | Block index 01 | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 0067: | Service code 23CB | Block index 02 | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
Block 0068: | Service code 23CB | Block index 03 | Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |

Example video of the new rendering for FeliCa Standard (the first tag read) and the backward support for an old file of a Suica (file name was Sui) mistakenly read as FeliCa Lite and got rendered regardless:
https://github.com/user-attachments/assets/40f8b034-1f57-43de-b473-40ed0cae1f09

Reference:
1, 2

My POC on PM3: 1, 2

Thanks for the guidance from @baconwaifu and @dogtopus, and tireless testing by @ry4000.

Verification

FeliCa Standard:

  • Read a FeliCa Standard card.
  • Look at Info -> More
  • Save. Exit app. Re-enter and load. Rendering should be unaffected.

FeliCa Lite:

  • Same as above

Backward compatibility:

  • Load a saved file from previous versoin / current dev branch.
  • Repeat step 2 and 3 from FeliCa Standard.

Checklist (For Reviewer)

  • PR has description of feature/bug or link to Confluence/Jira task
  • Description contains actions to verify feature/bugfix
  • I've built this code, uploaded it to the device and verified feature/bugfix

@zinongli

This comment was marked as outdated.

@zinongli zinongli marked this pull request as ready for review July 29, 2025 22:26
@zinongli zinongli changed the title NFC: FeliCa Service and Area Directory Traverse NFC: FeliCa Standard: Service and Area Directory Traverse Jul 29, 2025
zinongli added 10 commits July 29, 2025 19:26
`parsed` being true is only contingent on whether the header (device type, UID, etc) are correctly read. The detailed data can be absent if saved from previous versions.

Side effects:
1. The data format version number must not increment.
2. Newer sections of dumps must be appended in the end of the file.
Old version was aimed for FeliCa Lite dumping, which doesn't apply to FeliCa standard. Thus they need to be diverged in the poller run workflow.
@hedger
Copy link
Member

hedger commented Sep 25, 2025

@zinongli vector is closer to m-array (ARRAY_DEF).

@zinongli
Copy link
Contributor Author

@zinongli vector is closer to m-array (ARRAY_DEF).

Thanks. I'll try it over the weekend.

@zinongli
Copy link
Contributor Author

I lost to my lack of patience. The switch was easier than I imagined. But I could be wrong. This should be ready for review. I've tested on my end and it works the same as before the switch from dynamic vector to m-array.

Copy link
Member

@hedger hedger left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@zinongli thanks for the improvements. However, there are 2 issues I've noticed:

unit tests fail on FeliCa protocol:
Image
when running emulation of a Suica card dump, NFC Tools reports read error, and in logs there's the following - nvm, also present on dev

473966 [D][FelicaListener] Field On
473998 [D][FelicaListener] Activated
474017 [D][FelicaListener] Activated
474033 [D][FelicaListener] Activated
474056 [D][FelicaListener] Rx Done
474071 [D][FelicaListener] Activated
474081 [D][FelicaListener] Activated
474093 [D][FelicaListener] Activated
474097 [D][FelicaListener] Rx Done
474099 [E][FelicaListener] FeliCa incorrect command
474102 [E][FelicaListener] Processing error:  1

@zinongli
Copy link
Contributor Author

Thanks! I'll look into it.

@zinongli
Copy link
Contributor Author

OK I believe I know where the bug is. The unit test feeds the poller a FelicaData allocated by the listener. I only dealt with the poller and reading workflow in this PR. So the listener allocated the data without properly initializing the simple arrays. I'll fix it.

A partially relevant question: are _poller_sync()s purely made for unit tests? Like "I'll read what I'm emulating"?

@zinongli zinongli requested a review from Skorpionm as a code owner September 30, 2025 13:40
@zinongli
Copy link
Contributor Author

zinongli commented Sep 30, 2025

Was this Manufacturer Code / PMm introduced in #3673 gained from an actual tag or was this dump artificially and randomly generated?
https://github.com/RebornedBrain/flipperzero-firmware/blob/8856ec5de53b1874f10bbc41973773122027833d/applications/debug/unit_tests/resources/unit_tests/nfc/Felica.nfc#L10

My code failed unit test also because this unforeseen IC code 0x4E (the second byte in Manufacturer Code / PMm) was not recorded in any database. Not in pm3 or nullablevoidptr's doc.

If this indeed came from a FeliCa Lite-S I can add it into my workflow switch loop. But from the evidence I have, it seems to me very unlikely to be from an actual Lite-S PMm. Please let me know if you have any recollection of where this dump came from. @RebornedBrain

For the time being, I will edit this dump for unit test to have a documented Lite-S IC code so that the unit test will be directed to the Lite poller workflow. And this PR can pass unit test now.

if(felica_event->type == FelicaPollerEventTypeReady ||
felica_event->type == FelicaPollerEventTypeIncomplete) {
felica_copy(&poller_context->data, felica_poller->data);
felica_copy(poller_context->data.data, felica_poller->data);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This nested data structure was intended to mimic how it was handled in MfUltralight's poller sync since we need proper allocation for FelicaData

@RebornedBrain
Copy link
Contributor

Was this Manufacturer Code / PMm introduced in #3673 gained from an actual tag or was this dump artificially and randomly generated? https://github.com/RebornedBrain/flipperzero-firmware/blob/8856ec5de53b1874f10bbc41973773122027833d/applications/debug/unit_tests/resources/unit_tests/nfc/Felica.nfc#L10

My code failed unit test also because this unforeseen IC code 0x4E (the second byte in Manufacturer Code / PMm) was not recorded in any database. Not in pm3 or nullablevoidptr's doc.

If this indeed came from a FeliCa Lite-S I can add it into my workflow switch loop. But from the evidence I have, it seems to me very unlikely to be from an actual Lite-S PMm. Please let me know if you have any recollection of where this dump came from. @RebornedBrain

For the time being, I will edit this dump for unit test to have a documented Lite-S IC code so that the unit test will be directed to the Lite poller workflow. And this PR can pass unit test now.

Hi, I've checked the dump, and looks like you're right, PMm is wrong. I was able to find the card, which I used while implementing Felica Lite-S, here it is:

Filetype: Flipper NFC device
Version: 4
# Device type can be ISO14443-3A, ISO14443-3B, ISO14443-4A, ISO14443-4B, ISO15693-3, FeliCa, NTAG/Ultralight, Mifare Classic, Mifare Plus, Mifare DESFire, SLIX, ST25TB
Device type: FeliCa
# UID is common for all formats
UID: 01 2E 55 21 B3 0B A8 96
# FeliCa specific data
Data format version: 1
Manufacture id: 01 2E 55 21 B3 0B A8 96
Manufacture parameter: 00 F1 00 00 00 01 43 00
Blocks total: 28
Blocks read: 25
Block 0: 00 00 80 00 A5 BD 21 83 64 67 19 4D CE 7D 3B AA 1D 34
Block 1: 01 B1 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Block 2: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Block 3: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Block 4: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Block 5: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Block 6: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Block 7: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Block 8: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Block 9: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Block 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Block 11: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Block 12: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Block 13: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Block 14: 00 00 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
Block 15: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Block 16: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Block 17: 00 00 01 2E 55 21 B3 0B A8 96 57 4E 10 2A 94 16 BC 8E
Block 18: 00 00 01 2E 55 21 B3 0B A8 96 00 F1 00 00 00 01 43 00
Block 19: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Block 20: 00 00 88 B4 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Block 21: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Block 22: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Block 23: 00 00 FF FF FF 00 FF 00 02 00 00 00 00 00 00 00 00 00
Block 24: 00 00 26 FE FF 00 00 00 00 00 00 00 00 00 00 00 00 00
Block 25: 01 B2 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Block 26: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Block 27: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

As you can see it has those 57 4E 10 2A 94 16 BC 8E but in block 17, so it is DFC, not IDm/PMm which is block 18 according to spec. As far as I remember, when I implemented Felica it firstly had a bug when it missed one sector, then I've fixed it, but it could be very possible that this test dump was made before, or created as copy-paste or smth like that.
So @zinongli feel free to adjust test dump. Thanks for finding that 👍

@zinongli
Copy link
Contributor Author

Thanks @RebornedBrain !
I'll edit the PMm and leave the rest untouched.

Copy link
Member

@hedger hedger left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @zinongli @RebornedBrain - LGTM now. Hope with this new functionality we'll be able to bring more exciting FeliCa features and parsers.

@zinongli
Copy link
Contributor Author

zinongli commented Oct 1, 2025

Thanks a lot! By the way some of the SubGhz fixes got carried over hahaha

@hedger
Copy link
Member

hedger commented Oct 1, 2025

@zinongli I took liberty to push some static analysis fixes to your branch - they affect your code too, check them out (nothing major)

@zinongli
Copy link
Contributor Author

zinongli commented Oct 1, 2025

Oh of course, thanks for fixing them!

@hedger hedger added NFC NFC-related New Feature Contains an IMPLEMENTATION of a new feature labels Oct 1, 2025
@hedger hedger merged commit 85b6b2b into flipperdevices:dev Oct 1, 2025
10 of 11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
New Feature Contains an IMPLEMENTATION of a new feature NFC NFC-related
Projects
None yet
Development

Successfully merging this pull request may close these issues.

NFC Enhancement: FeliCa Poller Enumerate Through All Service Codes
4 participants