Skip to content

Commit 27f3b26

Browse files
authored
Merge pull request #691 from flit/refactor/magic_files
Refactor magic file handling
2 parents 6fbcdb5 + 262b777 commit 27f3b26

File tree

2 files changed

+196
-41
lines changed

2 files changed

+196
-41
lines changed

source/daplink/drag-n-drop/vfs_user.c

Lines changed: 135 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* @brief Implementation of vfs_user.h
44
*
55
* DAPLink Interface Firmware
6-
* Copyright (c) 2009-2019, ARM Limited, All Rights Reserved
6+
* Copyright (c) 2009-2020, ARM Limited, All Rights Reserved
77
* SPDX-License-Identifier: Apache-2.0
88
*
99
* Licensed under the Apache License, Version 2.0 (the "License"); you may
@@ -23,6 +23,7 @@
2323
#include "ctype.h"
2424
#include "string.h"
2525

26+
#include "vfs_user.h"
2627
#include "vfs_manager.h"
2728
#include "macro.h"
2829
#include "error.h"
@@ -40,6 +41,35 @@
4041
// device. This is to accomodate for hex file programming.
4142
static const uint32_t disc_size = MB(64);
4243

44+
//! @brief Constants for magic action or config files.
45+
//!
46+
//! The "magic files" are files with a special name that if created on the USB MSC volume, will
47+
//! cause an event. There are two classes of magic files: action files and config files. The former
48+
//! causes a given action to take place, while the latter changes a persistent configuration setting
49+
//! to a predetermined value.
50+
//!
51+
//! See #s_magic_file_info for the mapping of filenames to these enums.
52+
typedef enum _magic_file {
53+
kDAPLinkModeActionFile, //!< Switch between interface and bootloader.
54+
kTestAssertActionFile, //!< Force an assertion for testing.
55+
kRefreshActionFile, //!< Force a remount.
56+
kEraseActionFile, //!< Erase the target flash.
57+
kAutoResetConfigFile, //!< Enable reset after flash.
58+
kHardResetConfigFile, //!< Disable reset after flash.
59+
kAutomationOnConfigFile, //!< Enable automation.
60+
kAutomationOffConfigFile, //!< Disable automation.
61+
kOverflowOnConfigFile, //!< Enable UART overflow reporting.
62+
kOverflowOffConfigFile, //!< Disable UART overflow reporting.
63+
kMSDOnConfigFile, //!< Enable USB MSC. Uh....
64+
kMSDOffConfigFile, //!< Disable USB MSC.
65+
} magic_file_t;
66+
67+
//! @brief Mapping from filename string to magic file enum.
68+
typedef struct _magic_file_info {
69+
const char *name; //!< Name of the magic file, must be in 8.3 format.
70+
magic_file_t which; //!< Enum for the file.
71+
} magic_file_info_t;
72+
4373
static const char mbed_redirect_file[] =
4474
"<!doctype html>\r\n"
4575
"<!-- mbed Platform Website and Authentication Shortcut -->\r\n"
@@ -60,6 +90,22 @@ static const char error_type_prefix[] = "type: ";
6090

6191
static const vfs_filename_t assert_file = "ASSERT TXT";
6292

93+
//! @brief Table of magic files and their names.
94+
static const magic_file_info_t s_magic_file_info[] = {
95+
{ daplink_mode_file_name, kDAPLinkModeActionFile },
96+
{ "ASSERT ACT", kTestAssertActionFile },
97+
{ "REFRESH ACT", kRefreshActionFile },
98+
{ "ERASE ACT", kEraseActionFile },
99+
{ "AUTO_RSTCFG", kAutoResetConfigFile },
100+
{ "HARD_RSTCFG", kHardResetConfigFile },
101+
{ "AUTO_ON CFG", kAutomationOnConfigFile },
102+
{ "AUTO_OFFCFG", kAutomationOffConfigFile },
103+
{ "OVFL_ON CFG", kOverflowOnConfigFile },
104+
{ "OVFL_OFFCFG", kOverflowOffConfigFile },
105+
{ "MSD_ON CFG", kMSDOnConfigFile },
106+
{ "MSD_OFF CFG", kMSDOffConfigFile },
107+
};
108+
63109
static uint8_t file_buffer[VFS_SECTOR_SIZE];
64110
static char assert_buf[64 + 1];
65111
static uint16_t assert_line;
@@ -123,9 +169,28 @@ void vfs_user_build_filesystem()
123169
}
124170
}
125171

172+
// Default file change hook.
173+
__WEAK bool vfs_user_file_change_handler_hook(const vfs_filename_t filename, vfs_file_change_t change,
174+
vfs_file_t file, vfs_file_t new_file_data)
175+
{
176+
return false;
177+
}
178+
179+
// Default magic file hook.
180+
__WEAK bool vfs_user_magic_file_hook(const vfs_filename_t filename, bool *do_remount)
181+
{
182+
return false;
183+
}
184+
126185
// Callback to handle changes to the root directory. Should be used with vfs_set_file_change_callback
127186
void vfs_user_file_change_handler(const vfs_filename_t filename, vfs_file_change_t change, vfs_file_t file, vfs_file_t new_file_data)
128187
{
188+
// Call file changed hook. If it returns true, then it handled the request and we have nothing
189+
// more to do.
190+
if (vfs_user_file_change_handler_hook(filename, change, file, new_file_data)) {
191+
return;
192+
}
193+
129194
// Allow settings to be changed if automation mode is
130195
// enabled or if the user is holding the reset button
131196
bool btn_pressed = gpio_get_reset_btn();
@@ -138,52 +203,81 @@ void vfs_user_file_change_handler(const vfs_filename_t filename, vfs_file_change
138203
// Unused
139204
}
140205

141-
if (VFS_FILE_CREATED == change) {
142-
if (!memcmp(filename, daplink_mode_file_name, sizeof(vfs_filename_t))) {
143-
if (daplink_is_interface()) {
144-
config_ram_set_hold_in_bl(true);
145-
} else {
146-
// Do nothing - bootloader will go to interface by default
206+
else if (VFS_FILE_CREATED == change) {
207+
bool do_remount = true; // Almost all magic files cause a remount.
208+
int32_t which_magic_file = -1;
209+
210+
// Let the hook examine the filename. If it returned false then look for the standard
211+
// magic files.
212+
if (!vfs_user_magic_file_hook(filename, &do_remount)) {
213+
// Compare the new file's name to our table of magic filenames.
214+
for (int32_t i = 0; i < ARRAY_SIZE(s_magic_file_info); ++i) {
215+
if (!memcmp(filename, s_magic_file_info[i].name, sizeof(vfs_filename_t))) {
216+
which_magic_file = i;
217+
}
147218
}
148219

149-
vfs_mngr_fs_remount();
150-
} else if (!memcmp(filename, "AUTO_RSTCFG", sizeof(vfs_filename_t))) {
151-
config_set_auto_rst(true);
152-
vfs_mngr_fs_remount();
153-
} else if (!memcmp(filename, "HARD_RSTCFG", sizeof(vfs_filename_t))) {
154-
config_set_auto_rst(false);
155-
vfs_mngr_fs_remount();
156-
} else if (!memcmp(filename, "ASSERT ACT", sizeof(vfs_filename_t))) {
157-
// Test asserts
158-
util_assert(0);
159-
} else if (!memcmp(filename, "REFRESH ACT", sizeof(vfs_filename_t))) {
160-
// Remount to update the drive
161-
vfs_mngr_fs_remount();
162-
} else if (!memcmp(filename, "AUTO_ON CFG", sizeof(vfs_filename_t))) {
163-
config_set_automation_allowed(true);
164-
vfs_mngr_fs_remount();
165-
} else if (!memcmp(filename, "AUTO_OFFCFG", sizeof(vfs_filename_t))) {
166-
config_set_automation_allowed(false);
167-
vfs_mngr_fs_remount();
168-
} else if (!memcmp(filename, "ERASE ACT", sizeof(vfs_filename_t))) {
169-
erase_target();
170-
vfs_mngr_fs_remount();
171-
} else if (!memcmp(filename, "OVFL_ON CFG", sizeof(vfs_filename_t))) {
172-
config_set_overflow_detect(true);
173-
vfs_mngr_fs_remount();
174-
} else if (!memcmp(filename, "OVFL_OFFCFG", sizeof(vfs_filename_t))) {
175-
config_set_overflow_detect(false);
176-
vfs_mngr_fs_remount();
177-
} else if (!memcmp(filename, "MSD_ON ACT", sizeof(vfs_filename_t))) {
178-
config_ram_set_disable_msd(false);
179-
vfs_mngr_fs_remount();
180-
} else if (!memcmp(filename, "MSD_OFF ACT", sizeof(vfs_filename_t))) {
181-
config_ram_set_disable_msd(true);
220+
// Check if we matched a magic filename and handle it.
221+
if (which_magic_file != -1) {
222+
switch (which_magic_file) {
223+
case kDAPLinkModeActionFile:
224+
if (daplink_is_interface()) {
225+
config_ram_set_hold_in_bl(true);
226+
} else {
227+
// Do nothing - bootloader will go to interface by default
228+
}
229+
break;
230+
case kTestAssertActionFile:
231+
// Test asserts
232+
util_assert(0);
233+
do_remount = false;
234+
break;
235+
case kRefreshActionFile:
236+
// Remount to update the drive
237+
break;
238+
case kEraseActionFile:
239+
erase_target();
240+
break;
241+
case kAutoResetConfigFile:
242+
config_set_auto_rst(true);
243+
break;
244+
case kHardResetConfigFile:
245+
config_set_auto_rst(false);
246+
break;
247+
case kAutomationOnConfigFile:
248+
config_set_automation_allowed(true);
249+
break;
250+
case kAutomationOffConfigFile:
251+
config_set_automation_allowed(false);
252+
break;
253+
case kOverflowOnConfigFile:
254+
config_set_overflow_detect(true);
255+
break;
256+
case kOverflowOffConfigFile:
257+
config_set_overflow_detect(false);
258+
break;
259+
case kMSDOnConfigFile:
260+
config_ram_set_disable_msd(false);
261+
break;
262+
case kMSDOffConfigFile:
263+
config_ram_set_disable_msd(true);
264+
break;
265+
default:
266+
util_assert(false);
267+
}
268+
}
269+
else {
270+
do_remount = false;
271+
}
272+
}
273+
274+
// Remount if requested.
275+
if (do_remount) {
182276
vfs_mngr_fs_remount();
183277
}
184278
}
185279

186-
if (VFS_FILE_DELETED == change) {
280+
else if (VFS_FILE_DELETED == change) {
187281
if (!memcmp(filename, assert_file, sizeof(vfs_filename_t))) {
188282
// Clear assert and remount to update the drive
189283
util_assert_clear();
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/**
2+
* @file vfs_user.h
3+
* @brief VFS user files header.
4+
*
5+
* DAPLink Interface Firmware
6+
* Copyright (c) 2020, ARM Limited, All Rights Reserved
7+
* SPDX-License-Identifier: Apache-2.0
8+
*
9+
* Licensed under the Apache License, Version 2.0 (the "License"); you may
10+
* not use this file except in compliance with the License.
11+
* You may obtain a copy of the License at
12+
*
13+
* http://www.apache.org/licenses/LICENSE-2.0
14+
*
15+
* Unless required by applicable law or agreed to in writing, software
16+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
17+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18+
* See the License for the specific language governing permissions and
19+
* limitations under the License.
20+
*/
21+
22+
#ifndef VFS_USER_H
23+
#define VFS_USER_H
24+
25+
#include <stdbool.h>
26+
#include "virtual_fs.h"
27+
28+
#ifdef __cplusplus
29+
extern "C" {
30+
#endif
31+
32+
//! @brief Hook for file changes in root directory.
33+
//!
34+
//! @param filename Name of the file that has changed.
35+
//! @param change Type of change.
36+
//! @param file
37+
//! @param new_file_data Data being written to the file if _change_ is #VFS_FILE_CHANGED.
38+
//! @retval true The hook handled the change notification, the caller should do nothing else.
39+
//! @retval false The hook did nothing, continue with normal behaviour.
40+
bool vfs_user_file_change_handler_hook(const vfs_filename_t filename,
41+
vfs_file_change_t change, vfs_file_t file, vfs_file_t new_file_data);
42+
43+
//! @brief Hook for magic files.
44+
//!
45+
//! This hook is intended to simplify checking for magic files. In addition to allowing support for
46+
//! new magic files, you can also change the behaviour of or disable standard magic files.
47+
//!
48+
//! @param filename Name of the file that was created.
49+
//! @param[out] do_remount Whether the caller should remount the MSD volume. Only applies if true
50+
//! is returned. The default is true, so if the hook does not modify this parameter and returns
51+
//! true, a remount is performed.
52+
//! @retval true The hook handled the specified file. A remount will be performed if requested,
53+
//! but otherwise no other standard behaviour is applied.
54+
//! @retval false The hook did not handle the file; continue with canonical behaviour.
55+
bool vfs_user_magic_file_hook(const vfs_filename_t filename, bool *do_remount);
56+
57+
#ifdef __cplusplus
58+
}
59+
#endif
60+
61+
#endif // VFS_USER_H

0 commit comments

Comments
 (0)