|
5 | 5 | #include <furi_hal_nfc.h>
|
6 | 6 |
|
7 | 7 | #define FELICA_LISTENER_MAX_BUFFER_SIZE (128)
|
| 8 | +#define FELICA_LISTENER_CMD_POLLING (0x00U) |
| 9 | +#define FELICA_LISTENER_RESPONSE_POLLING (0x01U) |
8 | 10 | #define FELICA_LISTENER_RESPONSE_CODE_READ (0x07)
|
9 | 11 | #define FELICA_LISTENER_RESPONSE_CODE_WRITE (0x09)
|
10 | 12 |
|
| 13 | +#define FELICA_LISTENER_REQUEST_NONE (0x00U) |
| 14 | +#define FELICA_LISTENER_REQUEST_SYSTEM_CODE (0x01U) |
| 15 | +#define FELICA_LISTENER_REQUEST_PERFORMANCE (0x02U) |
| 16 | + |
| 17 | +#define FELICA_LISTENER_SYSTEM_CODE_NDEF (__builtin_bswap16(0x12FCU)) |
| 18 | +#define FELICA_LISTENER_SYSTEM_CODE_LITES (__builtin_bswap16(0x88B4U)) |
| 19 | + |
| 20 | +#define FELICA_LISTENER_PERFORMANCE_VALUE (__builtin_bswap16(0x0083U)) |
| 21 | + |
11 | 22 | #define TAG "FelicaListener"
|
12 | 23 |
|
13 | 24 | FelicaListener* felica_listener_alloc(Nfc* nfc, FelicaData* data) {
|
@@ -151,6 +162,70 @@ static FelicaError felica_listener_process_request(
|
151 | 162 | }
|
152 | 163 | }
|
153 | 164 |
|
| 165 | +static void felica_listener_populate_polling_response_header( |
| 166 | + FelicaListener* instance, |
| 167 | + FelicaListenerPollingResponseHeader* resp) { |
| 168 | + resp->idm = instance->data->idm; |
| 169 | + resp->pmm = instance->data->pmm; |
| 170 | + resp->response_code = FELICA_LISTENER_RESPONSE_POLLING; |
| 171 | +} |
| 172 | + |
| 173 | +static bool felica_listener_check_system_code( |
| 174 | + const FelicaListenerGenericRequest* const generic_request, |
| 175 | + uint16_t code) { |
| 176 | + return ( |
| 177 | + generic_request->polling.system_code == code || |
| 178 | + generic_request->polling.system_code == (code | 0x00FFU) || |
| 179 | + generic_request->polling.system_code == (code | 0xFF00U)); |
| 180 | +} |
| 181 | + |
| 182 | +static uint16_t felica_listener_get_response_system_code( |
| 183 | + FelicaListener* instance, |
| 184 | + const FelicaListenerGenericRequest* const generic_request) { |
| 185 | + uint16_t resp_system_code = FELICA_SYSTEM_CODE_CODE; |
| 186 | + if(felica_listener_check_system_code(generic_request, FELICA_LISTENER_SYSTEM_CODE_NDEF) && |
| 187 | + instance->data->data.fs.mc.data[FELICA_MC_SYS_OP] == 1) { |
| 188 | + // NDEF |
| 189 | + resp_system_code = FELICA_LISTENER_SYSTEM_CODE_NDEF; |
| 190 | + } else if(felica_listener_check_system_code( |
| 191 | + generic_request, FELICA_LISTENER_SYSTEM_CODE_LITES)) { |
| 192 | + // Lite-S |
| 193 | + resp_system_code = FELICA_LISTENER_SYSTEM_CODE_LITES; |
| 194 | + } |
| 195 | + return resp_system_code; |
| 196 | +} |
| 197 | + |
| 198 | +static FelicaError felica_listener_process_system_code( |
| 199 | + FelicaListener* instance, |
| 200 | + const FelicaListenerGenericRequest* const generic_request) { |
| 201 | + FelicaError result = FelicaErrorFeatureUnsupported; |
| 202 | + do { |
| 203 | + uint16_t resp_system_code = |
| 204 | + felica_listener_get_response_system_code(instance, generic_request); |
| 205 | + if(resp_system_code == FELICA_SYSTEM_CODE_CODE) break; |
| 206 | + |
| 207 | + FelicaListenerPollingResponse* resp = malloc(sizeof(FelicaListenerPollingResponse)); |
| 208 | + felica_listener_populate_polling_response_header(instance, &resp->header); |
| 209 | + |
| 210 | + resp->header.length = sizeof(FelicaListenerPollingResponse); |
| 211 | + if(generic_request->polling.request_code == FELICA_LISTENER_REQUEST_SYSTEM_CODE) { |
| 212 | + resp->optional_request_data = resp_system_code; |
| 213 | + } else if(generic_request->polling.request_code == FELICA_LISTENER_REQUEST_PERFORMANCE) { |
| 214 | + resp->optional_request_data = FELICA_LISTENER_PERFORMANCE_VALUE; |
| 215 | + } else { |
| 216 | + resp->header.length = sizeof(FelicaListenerPollingResponseHeader); |
| 217 | + } |
| 218 | + |
| 219 | + bit_buffer_reset(instance->tx_buffer); |
| 220 | + bit_buffer_append_bytes(instance->tx_buffer, (uint8_t*)resp, resp->header.length); |
| 221 | + free(resp); |
| 222 | + |
| 223 | + result = felica_listener_frame_exchange(instance, instance->tx_buffer); |
| 224 | + } while(false); |
| 225 | + |
| 226 | + return result; |
| 227 | +} |
| 228 | + |
154 | 229 | NfcCommand felica_listener_run(NfcGenericEvent event, void* context) {
|
155 | 230 | furi_assert(context);
|
156 | 231 | furi_assert(event.protocol == NfcProtocolInvalid);
|
@@ -187,7 +262,23 @@ NfcCommand felica_listener_run(NfcGenericEvent event, void* context) {
|
187 | 262 | break;
|
188 | 263 | }
|
189 | 264 |
|
190 |
| - if(!felica_listener_check_idm(instance, &request->header.idm)) { |
| 265 | + if(request->header.code == FELICA_LISTENER_CMD_POLLING) { |
| 266 | + // Will always respond at Time Slot 0 for now. |
| 267 | + nfc_felica_listener_timer_anticol_start(instance->nfc, 0); |
| 268 | + if(request->polling.system_code != FELICA_SYSTEM_CODE_CODE) { |
| 269 | + FelicaError error = felica_listener_process_system_code(instance, request); |
| 270 | + if(error == FelicaErrorFeatureUnsupported) { |
| 271 | + command = NfcCommandReset; |
| 272 | + } else if(error != FelicaErrorNone) { |
| 273 | + FURI_LOG_E( |
| 274 | + TAG, "Error when handling Polling with System Code: %2X", error); |
| 275 | + } |
| 276 | + break; |
| 277 | + } else { |
| 278 | + FURI_LOG_E(TAG, "Hardware Polling command leaking through"); |
| 279 | + break; |
| 280 | + } |
| 281 | + } else if(!felica_listener_check_idm(instance, &request->header.idm)) { |
191 | 282 | FURI_LOG_E(TAG, "Wrong IDm");
|
192 | 283 | break;
|
193 | 284 | }
|
|
0 commit comments