Skip to content

Commit 70fc88f

Browse files
authored
Merge branch 'dev' into skorp/subghz_fix_rpc
2 parents e15a56c + 4a58930 commit 70fc88f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

64 files changed

+424
-123
lines changed

applications/debug/ccid_test/ccid_test_app.c

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ void ccid_test_app_free(CcidTestApp* app) {
105105
furi_record_close(RECORD_GUI);
106106
app->gui = NULL;
107107

108-
free(app->iso7816_handler);
108+
iso7816_handler_free(app->iso7816_handler);
109109

110110
// Free rest
111111
free(app);
@@ -121,8 +121,7 @@ int32_t ccid_test_app(void* p) {
121121
furi_hal_usb_unlock();
122122

123123
furi_check(furi_hal_usb_set_config(&usb_ccid, &app->ccid_cfg) == true);
124-
furi_hal_usb_ccid_set_callbacks(
125-
(CcidCallbacks*)&app->iso7816_handler->ccid_callbacks, app->iso7816_handler);
124+
iso7816_handler_set_usb_ccid_callbacks();
126125
furi_hal_usb_ccid_insert_smartcard();
127126

128127
//handle button events
@@ -142,7 +141,7 @@ int32_t ccid_test_app(void* p) {
142141
}
143142

144143
//tear down USB
145-
furi_hal_usb_ccid_set_callbacks(NULL, NULL);
144+
iso7816_handler_reset_usb_ccid_callbacks();
146145
furi_hal_usb_set_config(usb_mode_prev, NULL);
147146

148147
//teardown view

applications/debug/ccid_test/iso7816/iso7816_handler.c

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,17 @@
66
#include <furi.h>
77
#include <furi_hal.h>
88

9+
#include "iso7816_handler.h"
10+
911
#include "iso7816_t0_apdu.h"
1012
#include "iso7816_atr.h"
11-
#include "iso7816_handler.h"
1213
#include "iso7816_response.h"
1314

15+
static Iso7816Handler* iso7816_handler;
16+
static CcidCallbacks* ccid_callbacks;
17+
static uint8_t* command_apdu_buffer;
18+
static uint8_t* response_apdu_buffer;
19+
1420
void iso7816_icc_power_on_callback(uint8_t* atr_data, uint32_t* atr_data_len, void* context) {
1521
furi_check(context);
1622

@@ -40,12 +46,11 @@ void iso7816_xfr_datablock_callback(
4046

4147
Iso7816Handler* handler = (Iso7816Handler*)context;
4248

43-
ISO7816_Response_APDU* response_apdu = (ISO7816_Response_APDU*)&handler->response_apdu_buffer;
44-
45-
ISO7816_Command_APDU* command_apdu = (ISO7816_Command_APDU*)&handler->command_apdu_buffer;
49+
ISO7816_Response_APDU* response_apdu = (ISO7816_Response_APDU*)response_apdu_buffer;
50+
ISO7816_Command_APDU* command_apdu = (ISO7816_Command_APDU*)command_apdu_buffer;
4651

4752
uint8_t result = iso7816_read_command_apdu(
48-
command_apdu, pc_to_reader_datablock, pc_to_reader_datablock_len);
53+
command_apdu, pc_to_reader_datablock, pc_to_reader_datablock_len, CCID_SHORT_APDU_SIZE);
4954

5055
if(result == ISO7816_READ_COMMAND_APDU_OK) {
5156
handler->iso7816_process_command(command_apdu, response_apdu);
@@ -61,8 +66,31 @@ void iso7816_xfr_datablock_callback(
6166
}
6267

6368
Iso7816Handler* iso7816_handler_alloc() {
64-
Iso7816Handler* handler = malloc(sizeof(Iso7816Handler));
65-
handler->ccid_callbacks.icc_power_on_callback = iso7816_icc_power_on_callback;
66-
handler->ccid_callbacks.xfr_datablock_callback = iso7816_xfr_datablock_callback;
67-
return handler;
69+
iso7816_handler = malloc(sizeof(Iso7816Handler));
70+
71+
command_apdu_buffer = malloc(sizeof(ISO7816_Command_APDU) + CCID_SHORT_APDU_SIZE);
72+
response_apdu_buffer = malloc(sizeof(ISO7816_Response_APDU) + CCID_SHORT_APDU_SIZE);
73+
74+
ccid_callbacks = malloc(sizeof(CcidCallbacks));
75+
ccid_callbacks->icc_power_on_callback = iso7816_icc_power_on_callback;
76+
ccid_callbacks->xfr_datablock_callback = iso7816_xfr_datablock_callback;
77+
78+
return iso7816_handler;
79+
}
80+
81+
void iso7816_handler_set_usb_ccid_callbacks() {
82+
furi_hal_usb_ccid_set_callbacks(ccid_callbacks, iso7816_handler);
83+
}
84+
85+
void iso7816_handler_reset_usb_ccid_callbacks() {
86+
furi_hal_usb_ccid_set_callbacks(NULL, NULL);
87+
}
88+
89+
void iso7816_handler_free(Iso7816Handler* handler) {
90+
free(ccid_callbacks);
91+
92+
free(command_apdu_buffer);
93+
free(response_apdu_buffer);
94+
95+
free(handler);
6896
}

applications/debug/ccid_test/iso7816/iso7816_handler.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@
55
#include "iso7816_t0_apdu.h"
66

77
typedef struct {
8-
CcidCallbacks ccid_callbacks;
98
void (*iso7816_answer_to_reset)(Iso7816Atr* atr);
109
void (*iso7816_process_command)(
1110
const ISO7816_Command_APDU* command,
1211
ISO7816_Response_APDU* response);
13-
14-
uint8_t command_apdu_buffer[sizeof(ISO7816_Command_APDU) + CCID_SHORT_APDU_SIZE];
15-
uint8_t response_apdu_buffer[sizeof(ISO7816_Response_APDU) + CCID_SHORT_APDU_SIZE];
1612
} Iso7816Handler;
1713

1814
Iso7816Handler* iso7816_handler_alloc();
15+
16+
void iso7816_handler_free(Iso7816Handler* handler);
17+
void iso7816_handler_set_usb_ccid_callbacks();
18+
void iso7816_handler_reset_usb_ccid_callbacks();

applications/debug/ccid_test/iso7816/iso7816_t0_apdu.c

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,48 @@
11
/* Implements rudimentary iso7816-3 support for APDU (T=0) */
22
#include <stdint.h>
33
#include <string.h>
4-
#include <furi.h>
5-
#include <furi_hal.h>
64
#include "iso7816_t0_apdu.h"
75

8-
//reads dataBuffer with dataLen size, translate it into a ISO7816_Command_APDU type
6+
//reads pc_to_reader_datablock_len with pc_to_reader_datablock_len size, translate it into a ISO7816_Command_APDU type
97
//extra data will be pointed to commandDataBuffer
108
uint8_t iso7816_read_command_apdu(
119
ISO7816_Command_APDU* command,
12-
const uint8_t* dataBuffer,
13-
uint32_t dataLen) {
14-
command->CLA = dataBuffer[0];
15-
command->INS = dataBuffer[1];
16-
command->P1 = dataBuffer[2];
17-
command->P2 = dataBuffer[3];
10+
const uint8_t* pc_to_reader_datablock,
11+
uint32_t pc_to_reader_datablock_len,
12+
uint32_t max_apdu_size) {
13+
command->CLA = pc_to_reader_datablock[0];
14+
command->INS = pc_to_reader_datablock[1];
15+
command->P1 = pc_to_reader_datablock[2];
16+
command->P2 = pc_to_reader_datablock[3];
1817

19-
if(dataLen == 4) {
18+
if(pc_to_reader_datablock_len == 4) {
2019
command->Lc = 0;
2120
command->Le = 0;
2221
command->LePresent = false;
2322

2423
return ISO7816_READ_COMMAND_APDU_OK;
25-
} else if(dataLen == 5) {
24+
} else if(pc_to_reader_datablock_len == 5) {
2625
//short le
2726

2827
command->Lc = 0;
29-
command->Le = dataBuffer[4];
28+
command->Le = pc_to_reader_datablock[4];
3029
command->LePresent = true;
3130

3231
return ISO7816_READ_COMMAND_APDU_OK;
33-
} else if(dataLen > 5 && dataBuffer[4] != 0x00) {
32+
} else if(pc_to_reader_datablock_len > 5 && pc_to_reader_datablock[4] != 0x00) {
3433
//short lc
3534

36-
command->Lc = dataBuffer[4];
37-
if(command->Lc > 0 && command->Lc < CCID_SHORT_APDU_SIZE) { //-V560
38-
memcpy(command->Data, &dataBuffer[5], command->Lc);
35+
command->Lc = pc_to_reader_datablock[4];
36+
if(command->Lc > 0 && command->Lc < max_apdu_size) { //-V560
37+
memcpy(command->Data, &pc_to_reader_datablock[5], command->Lc);
3938

4039
//does it have a short le too?
41-
if(dataLen == (uint32_t)(command->Lc + 5)) {
40+
if(pc_to_reader_datablock_len == (uint32_t)(command->Lc + 5)) {
4241
command->Le = 0;
4342
command->LePresent = false;
4443
return ISO7816_READ_COMMAND_APDU_OK;
45-
} else if(dataLen == (uint32_t)(command->Lc + 6)) {
46-
command->Le = dataBuffer[dataLen - 1];
44+
} else if(pc_to_reader_datablock_len == (uint32_t)(command->Lc + 6)) {
45+
command->Le = pc_to_reader_datablock[pc_to_reader_datablock_len - 1];
4746
command->LePresent = true;
4847

4948
return ISO7816_READ_COMMAND_APDU_OK;

applications/debug/ccid_test/iso7816/iso7816_t0_apdu.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ typedef struct {
3434
uint8_t iso7816_read_command_apdu(
3535
ISO7816_Command_APDU* command,
3636
const uint8_t* pc_to_reader_datablock,
37-
uint32_t pc_to_reader_datablock_len);
37+
uint32_t pc_to_reader_datablock_len,
38+
uint32_t max_apdu_size);
3839
void iso7816_write_response_apdu(
3940
const ISO7816_Response_APDU* response,
4041
uint8_t* reader_to_pc_datablock,

applications/debug/expansion_test/expansion_test.c

Lines changed: 55 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,27 @@
66
* 13 -> 16 (USART TX to LPUART RX)
77
* 14 -> 15 (USART RX to LPUART TX)
88
*
9+
* Optional: Connect an LED with an appropriate series resistor
10+
* between pins 1 and 8. It will always be on if the device is
11+
* connected to USB power, so unplug it before running the app.
12+
*
913
* What this application does:
1014
*
1115
* - Enables module support and emulates the module on a single device
1216
* (hence the above connection),
1317
* - Connects to the expansion module service, sets baud rate,
18+
* - Enables OTG (5V) on GPIO via plain expansion protocol,
19+
* - Waits 5 cycles of idle loop (1 second),
1420
* - Starts the RPC session,
21+
* - Disables OTG (5V) on GPIO via RPC messages,
22+
* - Waits 5 cycles of idle loop (1 second),
1523
* - Creates a directory at `/ext/ExpansionTest` and writes a file
1624
* named `test.txt` under it,
1725
* - Plays an audiovisual alert (sound and blinking display),
18-
* - Waits 10 cycles of idle loop,
26+
* - Enables OTG (5V) on GPIO via RPC messages,
27+
* - Waits 5 cycles of idle loop (1 second),
1928
* - Stops the RPC session,
20-
* - Waits another 10 cycles of idle loop,
29+
* - Disables OTG (5V) on GPIO via plain expansion protocol,
2130
* - Exits (plays a sound if any of the above steps failed).
2231
*/
2332
#include <furi.h>
@@ -302,6 +311,22 @@ static bool expansion_test_app_handshake(ExpansionTestApp* instance) {
302311
return success;
303312
}
304313

314+
static bool expansion_test_app_enable_otg(ExpansionTestApp* instance, bool enable) {
315+
bool success = false;
316+
317+
do {
318+
const ExpansionFrameControlCommand command = enable ?
319+
ExpansionFrameControlCommandEnableOtg :
320+
ExpansionFrameControlCommandDisableOtg;
321+
if(!expansion_test_app_send_control_request(instance, command)) break;
322+
if(!expansion_test_app_receive_frame(instance, &instance->frame)) break;
323+
if(!expansion_test_app_is_success_response(&instance->frame)) break;
324+
success = true;
325+
} while(false);
326+
327+
return success;
328+
}
329+
305330
static bool expansion_test_app_start_rpc(ExpansionTestApp* instance) {
306331
bool success = false;
307332

@@ -396,6 +421,27 @@ static bool expansion_test_app_rpc_alert(ExpansionTestApp* instance) {
396421
return success;
397422
}
398423

424+
static bool expansion_test_app_rpc_enable_otg(ExpansionTestApp* instance, bool enable) {
425+
bool success = false;
426+
427+
instance->msg.command_id++;
428+
instance->msg.command_status = PB_CommandStatus_OK;
429+
instance->msg.which_content = PB_Main_gpio_set_otg_mode_tag;
430+
instance->msg.content.gpio_set_otg_mode.mode = enable ? PB_Gpio_GpioOtgMode_ON :
431+
PB_Gpio_GpioOtgMode_OFF;
432+
instance->msg.has_next = false;
433+
434+
do {
435+
if(!expansion_test_app_send_rpc_request(instance, &instance->msg)) break;
436+
if(!expansion_test_app_receive_rpc_request(instance, &instance->msg)) break;
437+
if(instance->msg.which_content != PB_Main_empty_tag) break;
438+
if(instance->msg.command_status != PB_CommandStatus_OK) break;
439+
success = true;
440+
} while(false);
441+
442+
return success;
443+
}
444+
399445
static bool expansion_test_app_idle(ExpansionTestApp* instance, uint32_t num_cycles) {
400446
uint32_t num_cycles_done;
401447
for(num_cycles_done = 0; num_cycles_done < num_cycles; ++num_cycles_done) {
@@ -434,13 +480,18 @@ int32_t expansion_test_app(void* p) {
434480
if(!expansion_test_app_send_presence(instance)) break;
435481
if(!expansion_test_app_wait_ready(instance)) break;
436482
if(!expansion_test_app_handshake(instance)) break;
483+
if(!expansion_test_app_enable_otg(instance, true)) break;
484+
if(!expansion_test_app_idle(instance, 5)) break;
437485
if(!expansion_test_app_start_rpc(instance)) break;
486+
if(!expansion_test_app_rpc_enable_otg(instance, false)) break;
487+
if(!expansion_test_app_idle(instance, 5)) break;
438488
if(!expansion_test_app_rpc_mkdir(instance)) break;
439489
if(!expansion_test_app_rpc_write(instance)) break;
440490
if(!expansion_test_app_rpc_alert(instance)) break;
441-
if(!expansion_test_app_idle(instance, 10)) break;
491+
if(!expansion_test_app_rpc_enable_otg(instance, true)) break;
492+
if(!expansion_test_app_idle(instance, 5)) break;
442493
if(!expansion_test_app_stop_rpc(instance)) break;
443-
if(!expansion_test_app_idle(instance, 10)) break;
494+
if(!expansion_test_app_enable_otg(instance, false)) break;
444495
success = true;
445496
} while(false);
446497

applications/examples/example_number_input/scenes/example_number_input_scene_show_number.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,7 @@ static void example_number_input_scene_update_view(void* context) {
1313

1414
dialog_ex_set_header(dialog_ex, "The number is", 64, 0, AlignCenter, AlignTop);
1515

16-
static char buffer[12]; //needs static for extended lifetime
17-
16+
char buffer[12] = {};
1817
snprintf(buffer, sizeof(buffer), "%ld", app->current_number);
1918
dialog_ex_set_text(dialog_ex, buffer, 64, 29, AlignCenter, AlignCenter);
2019

applications/services/expansion/expansion_protocol.h

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,28 @@ typedef enum {
6464
* @brief Enumeration of suported control commands.
6565
*/
6666
typedef enum {
67-
ExpansionFrameControlCommandStartRpc = 0x00, /**< Start an RPC session. */
68-
ExpansionFrameControlCommandStopRpc = 0x01, /**< Stop an open RPC session. */
67+
/** @brief Start an RPC session.
68+
*
69+
* Must only be used while the RPC session is NOT active.
70+
*/
71+
ExpansionFrameControlCommandStartRpc = 0x00,
72+
/** @brief Stop an open RPC session.
73+
*
74+
* Must only be used while the RPC session IS active.
75+
*/
76+
ExpansionFrameControlCommandStopRpc = 0x01,
77+
/** @brief Enable OTG (5V) on external GPIO.
78+
*
79+
* Must only be used while the RPC session is NOT active,
80+
* otherwise OTG is to be controlled via RPC messages.
81+
*/
82+
ExpansionFrameControlCommandEnableOtg = 0x02,
83+
/** @brief Disable OTG (5V) on external GPIO.
84+
*
85+
* Must only be used while the RPC session is NOT active,
86+
* otherwise OTG is to be controlled via RPC messages.
87+
*/
88+
ExpansionFrameControlCommandDisableOtg = 0x03,
6989
} ExpansionFrameControlCommand;
7090

7191
#pragma pack(push, 1)

applications/services/expansion/expansion_worker.c

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -245,9 +245,18 @@ static bool expansion_worker_handle_state_connected(
245245

246246
do {
247247
if(rx_frame->header.type == ExpansionFrameTypeControl) {
248-
if(rx_frame->content.control.command != ExpansionFrameControlCommandStartRpc) break;
249-
instance->state = ExpansionWorkerStateRpcActive;
250-
if(!expansion_worker_rpc_session_open(instance)) break;
248+
const uint8_t command = rx_frame->content.control.command;
249+
if(command == ExpansionFrameControlCommandStartRpc) {
250+
if(!expansion_worker_rpc_session_open(instance)) break;
251+
instance->state = ExpansionWorkerStateRpcActive;
252+
} else if(command == ExpansionFrameControlCommandEnableOtg) {
253+
furi_hal_power_enable_otg();
254+
} else if(command == ExpansionFrameControlCommandDisableOtg) {
255+
furi_hal_power_disable_otg();
256+
} else {
257+
break;
258+
}
259+
251260
if(!expansion_worker_send_status_response(instance, ExpansionFrameErrorNone)) break;
252261

253262
} else if(rx_frame->header.type == ExpansionFrameTypeHeartbeat) {
@@ -279,9 +288,14 @@ static bool expansion_worker_handle_state_rpc_active(
279288
if(size_consumed != rx_frame->content.data.size) break;
280289

281290
} else if(rx_frame->header.type == ExpansionFrameTypeControl) {
282-
if(rx_frame->content.control.command != ExpansionFrameControlCommandStopRpc) break;
283-
instance->state = ExpansionWorkerStateConnected;
284-
expansion_worker_rpc_session_close(instance);
291+
const uint8_t command = rx_frame->content.control.command;
292+
if(command == ExpansionFrameControlCommandStopRpc) {
293+
instance->state = ExpansionWorkerStateConnected;
294+
expansion_worker_rpc_session_close(instance);
295+
} else {
296+
break;
297+
}
298+
285299
if(!expansion_worker_send_status_response(instance, ExpansionFrameErrorNone)) break;
286300

287301
} else if(rx_frame->header.type == ExpansionFrameTypeStatus) {

0 commit comments

Comments
 (0)