everything is now documented
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
USB support is implemented using the STM32 USB Device library.
|
||||
|
||||
The library is copied into the core project to make customizations easier to maintain
|
||||
across different ports. The USBD library supports all versions of the HAL and LL.
|
||||
|
||||
GEX uses USB classes CDC/ACM and MSC/SCSI.
|
||||
The two classes are combined into a composite class with association descriptors.
|
||||
|
||||
USB interrupts are processed by the USBD library and endpoint callbacks in the composite
|
||||
class are fired. To avoid race conditions (and because DAPlink did it the same way), the
|
||||
events are notified to the USB thread (TaskMain) which calls endpoint handlers in the
|
||||
corresponding class drivers.
|
||||
|
||||
VFS is handled synchronously on the main thread. CDC messages (TinyFrame data) are queued
|
||||
and processed by the message queue thread. This makes it possible to query hardware
|
||||
(e.g. slow USART or NeoPixel) without stalling the USB communication. This arrangement
|
||||
also makes it possible to wait on a binary semaphore when sending data back to host. The
|
||||
semaphore is set from the CDC TxComplete callback and taken by the TinyFrame write
|
||||
function, serving as a form of flow control.
|
||||
@@ -1,3 +1,8 @@
|
||||
//
|
||||
// Some FreeRTOS / CortexM callbacks are implemented here
|
||||
// (moved from the top level project for easier maintenance)
|
||||
//
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
|
||||
#include "platform.h"
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
//
|
||||
// Created by MightyPork on 2017/11/04.
|
||||
//
|
||||
// Debugging functions
|
||||
//
|
||||
|
||||
#ifndef GEX_DEBUG_H
|
||||
#define GEX_DEBUG_H
|
||||
@@ -12,12 +14,19 @@
|
||||
|
||||
#if USE_DEBUG_UART
|
||||
|
||||
/** Externally defined function for writing to the debug UART */
|
||||
extern void debug_write(const char *buf, uint16_t len);
|
||||
|
||||
/** Debug printf, used in the macros below */
|
||||
void _DO_PRINTF(const char *format, ...) __attribute__((format(printf,1,2))) ;
|
||||
|
||||
/** putsn to debug */
|
||||
void PUTSN(const char *string, uint16_t len);
|
||||
|
||||
/** puts to debug */
|
||||
void PUTS(const char *string);
|
||||
|
||||
/** puts with just a newline */
|
||||
static inline void PUTNL(void)
|
||||
{
|
||||
debug_write("\r\n", 2);
|
||||
@@ -33,6 +42,12 @@ static inline void PUTCHAR(char ch)
|
||||
debug_write(&ch, 1);
|
||||
}
|
||||
|
||||
// NOTE: Those macros use puts instead of printf if the format is the only arg.
|
||||
// this saves ROM and stack overhead
|
||||
|
||||
/**
|
||||
* Debug printf
|
||||
*/
|
||||
#define PRINTF(format, ...) do { \
|
||||
if (VA_ARG_COUNT(__VA_ARGS__) == 0) { \
|
||||
PUTS(format); \
|
||||
@@ -41,6 +56,9 @@ static inline void PUTCHAR(char ch)
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* Debug printf (with a newline)
|
||||
*/
|
||||
#define dbg(format, ...) do { \
|
||||
if (VA_ARG_COUNT(__VA_ARGS__) == 0) { \
|
||||
PUTS(format); \
|
||||
@@ -50,14 +68,13 @@ static inline void PUTCHAR(char ch)
|
||||
PUTNL(); \
|
||||
} while (0)
|
||||
|
||||
|
||||
#else
|
||||
#define dbg(format, ...) do {} while (0)
|
||||
#define PRINTF(format, ...) do {} while (0)
|
||||
#define PUTSN(string, len) do {} while (0)
|
||||
#define PUTS(string) do {} while (0)
|
||||
#define PUTNL() do {} while (0)
|
||||
#define PUTCHAR(ch) do {} while (0)
|
||||
#define dbg(format, ...) do {} while (0)
|
||||
#define PRINTF(format, ...) do {} while (0)
|
||||
#define PUTSN(string, len) do {} while (0)
|
||||
#define PUTS(string) do {} while (0)
|
||||
#define PUTNL() do {} while (0)
|
||||
#define PUTCHAR(ch) do {} while (0)
|
||||
#endif
|
||||
|
||||
#endif //GEX_DEBUG_H
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
//
|
||||
// FreeRTOS setup
|
||||
//
|
||||
|
||||
/**
|
||||
******************************************************************************
|
||||
* File Name : freertos.c
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
//
|
||||
// Created by MightyPork on 2017/12/15.
|
||||
//
|
||||
// Callbacks from the top level main() function etc
|
||||
//
|
||||
|
||||
#ifndef GEX_GEX_HOOKS_H
|
||||
#define GEX_GEX_HOOKS_H
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
//
|
||||
// Created by MightyPork on 2017/11/20.
|
||||
//
|
||||
// Assert handling with traps
|
||||
//
|
||||
|
||||
#ifndef STM32_ASSERT_H
|
||||
#define STM32_ASSERT_H
|
||||
|
||||
+46
-1
@@ -1,14 +1,59 @@
|
||||
//
|
||||
// Created by MightyPork on 2017/11/26.
|
||||
//
|
||||
// Those are low memory footprint implementations of some stdlib functions
|
||||
// taken from the AVR libc. They are used instead of newlib versions.
|
||||
//
|
||||
|
||||
#ifndef GEX_AVRLIBC_H_H
|
||||
#define GEX_AVRLIBC_H_H
|
||||
|
||||
/**
|
||||
* atoi() - parse decimal int from ASCII
|
||||
*
|
||||
* @param p - string
|
||||
* @return int, 0 on failure
|
||||
*/
|
||||
int avr_atoi(const char *p);
|
||||
long avr_strtol(const char *nptr, char **endptr, register int base);
|
||||
|
||||
/**
|
||||
* atol() - parse decimal long int from ASCII
|
||||
*
|
||||
* @param p - string
|
||||
* @return int, 0 on failure
|
||||
*/
|
||||
long avr_atol(const char *p);
|
||||
|
||||
/**
|
||||
* strtol() - parse integer number form string.
|
||||
* this is internally called by atol and atoi
|
||||
*
|
||||
* 0x is allowed for bases 0 and 16
|
||||
*
|
||||
* @param nptr - string to parse
|
||||
* @param endptr - NULL or pointer to string where the end will be stored (first bad char)
|
||||
* @param base - base 2, 10, 16.... 0 for auto
|
||||
* @return the number
|
||||
*/
|
||||
long avr_strtol(const char *nptr, char **endptr, register int base);
|
||||
|
||||
/**
|
||||
* Parse double from ASCII
|
||||
*
|
||||
* @param nptr - string to parse
|
||||
* @param endptr - NULL or pointer to string where the end will be stored (first bad char)
|
||||
* @return the number
|
||||
*/
|
||||
double avr_strtod (const char * nptr, char ** endptr);
|
||||
|
||||
/**
|
||||
* like strtol(), but unsigned (and hence higher max value)
|
||||
*
|
||||
* @param nptr - string to parse
|
||||
* @param endptr - NULL or pointer to string where the end will be stored (first bad char)
|
||||
* @param base - base 2, 10, 16.... 0 for auto
|
||||
* @return the number
|
||||
*/
|
||||
unsigned long avr_strtoul(const char *nptr, char **endptr, register int base);
|
||||
|
||||
#endif //GEX_AVRLIBC_H_H
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
//
|
||||
// This is a circular buffer implementation borrowed from the DAPLink firmware
|
||||
//
|
||||
|
||||
/**
|
||||
* @file circ_buf.h
|
||||
* @brief Implementation of a circular buffer
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
//
|
||||
// Created by MightyPork on 2017/11/26.
|
||||
//
|
||||
// Cortex-M utilities (low level stuff missing from CMSIS)
|
||||
//
|
||||
|
||||
#ifndef GEX_CORTEX_UTILS_H
|
||||
#define GEX_CORTEX_UTILS_H
|
||||
|
||||
+25
-23
@@ -1,23 +1,6 @@
|
||||
/**
|
||||
* @file error.h
|
||||
* @brief collection of known errors and accessor for the friendly string
|
||||
*
|
||||
* DAPLink Interface Firmware
|
||||
* Copyright (c) 2009-2016, ARM Limited, All Rights Reserved
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// Error codes and labels. Loosely based on DAPLink, with more codes added.
|
||||
//
|
||||
|
||||
#ifndef ERROR_H
|
||||
#define ERROR_H
|
||||
@@ -59,7 +42,10 @@
|
||||
X(OUT_OF_MEM, "Not enough RAM") \
|
||||
X(RESOURCE_NOT_AVAILABLE, NULL)
|
||||
|
||||
// Keep in sync with the list error_message
|
||||
|
||||
/**
|
||||
* The return value for all functions with error reporting.
|
||||
*/
|
||||
typedef enum {
|
||||
#define X(name, text) E_##name,
|
||||
X_ERROR_CODES
|
||||
@@ -67,8 +53,6 @@ typedef enum {
|
||||
ERROR_COUNT
|
||||
} error_t;
|
||||
|
||||
const char *error_get_message(error_t error) __attribute__((pure));
|
||||
const char *error_get_name(error_t error) __attribute__((pure));
|
||||
|
||||
/** Check return value and return it if not E_SUCCESS */
|
||||
#define TRY(call) do { \
|
||||
@@ -77,6 +61,24 @@ const char *error_get_name(error_t error) __attribute__((pure));
|
||||
if (E_SUCCESS != _rv) return _rv; \
|
||||
} while (0)
|
||||
|
||||
|
||||
/**
|
||||
* Get a user-friendly message from a E_* enum value
|
||||
*
|
||||
* @param error - E_* value
|
||||
* @return string, error name or description
|
||||
*/
|
||||
const char *error_get_message(error_t error) __attribute__((pure));
|
||||
|
||||
|
||||
/**
|
||||
* Get error name from a E_* enum value
|
||||
*
|
||||
* @param error - E_* value
|
||||
* @return string, error name
|
||||
*/
|
||||
const char *error_get_name(error_t error) __attribute__((pure));
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
//
|
||||
// Created by MightyPork on 2017/12/04.
|
||||
//
|
||||
// Memory dumping utility from: https://stackoverflow.com/a/7776146/2180189
|
||||
// Prints bytes in the usual hexdump format (as HEX and ASCII)
|
||||
//
|
||||
|
||||
#ifndef GEX_HEXDUMP_H
|
||||
#define GEX_HEXDUMP_H
|
||||
|
||||
@@ -1,8 +1,14 @@
|
||||
//
|
||||
// INI file parser with a FSM generated by Ragel. This was originally written for ESPTerm
|
||||
// Used to extract sections, keys and values from user-provided settings file
|
||||
//
|
||||
|
||||
#ifndef INIPARSE_STREAM_H
|
||||
#define INIPARSE_STREAM_H
|
||||
|
||||
#include "platform.h"
|
||||
|
||||
// toggleable logging func
|
||||
#ifdef DEBUG_INI
|
||||
#define ini_error(fmt, ...) dbg("! INI err: "#fmt, ##__VA_ARGS__)
|
||||
#else
|
||||
|
||||
+8
-1
@@ -1,12 +1,19 @@
|
||||
//
|
||||
// Created by MightyPork on 2017/12/01.
|
||||
//
|
||||
// Utility for generating a INI file with support for extracting individual sectors
|
||||
// and measuring total length without buffering. This is used to build the INI files
|
||||
// for the VFS and config.
|
||||
//
|
||||
|
||||
#ifndef INIWRITER_H
|
||||
#define INIWRITER_H
|
||||
|
||||
#include "platform.h"
|
||||
|
||||
/**
|
||||
* INI writer handle
|
||||
*/
|
||||
typedef struct iniwriter_ {
|
||||
char *ptr;
|
||||
uint32_t skip;
|
||||
@@ -18,7 +25,7 @@ typedef struct iniwriter_ {
|
||||
*
|
||||
* This buffer is used internally by printf-like iw functions.
|
||||
* It can be used to prepare buffer for iw_buff or iw_string,
|
||||
* but must not be used for %s substitutions in iw_* functions.
|
||||
* but must NOT be used for %s substitutions in iw_* functions.
|
||||
*/
|
||||
extern char *iwbuffer;
|
||||
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
//
|
||||
// static assert and general purpose useful macros, borrowed in part from the DAPLink project
|
||||
//
|
||||
|
||||
/**
|
||||
* @file macro.h
|
||||
* @brief useful things + Special asserts and macros
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
//
|
||||
// Safe malloc with error file:line logging, using the FreeRTOS-provided malloc facility
|
||||
// The custom malloc implementation is safer than the poorly documented hacks provided by
|
||||
// newlib, written primarily for the desktop rather than embedded.
|
||||
//
|
||||
|
||||
#ifndef MALLOC_SAFE_H
|
||||
#define MALLOC_SAFE_H
|
||||
|
||||
|
||||
+2
-7
@@ -1,6 +1,8 @@
|
||||
//
|
||||
// Created by MightyPork on 2017/11/09.
|
||||
//
|
||||
// Small sprintf/snprintf implementation, used instead of the newlib one.
|
||||
//
|
||||
|
||||
#ifndef GEX_SNPRINTF_H
|
||||
#define GEX_SNPRINTF_H
|
||||
@@ -15,13 +17,6 @@ size_t fixup_vasprintf(char **ptr, const char *format, va_list ap);
|
||||
size_t fixup_asprintf(char **ptr, const char *format, ...);
|
||||
size_t fixup_sprintf(char *ptr, const char *format, ...);
|
||||
|
||||
// Trap for using newlib functions
|
||||
//#define vsnprintf fuck1
|
||||
//#define snprintf fuck2
|
||||
//#define vasprintf fuck3
|
||||
//#define asprintf fuck4
|
||||
//#define sprintf fuck5
|
||||
|
||||
#define VSNPRINTF(...) fixup_vsnprintf(__VA_ARGS__)
|
||||
#define SNPRINTF(...) fixup_snprintf(__VA_ARGS__)
|
||||
#define VASPRINTF(...) fixup_vasprintf(__VA_ARGS__)
|
||||
|
||||
@@ -15,7 +15,6 @@ struct stackhandle {
|
||||
uint32_t len;
|
||||
};
|
||||
|
||||
#define STACK_NUM 3
|
||||
static uint32_t nextidx = 0;
|
||||
static struct stackhandle stacks[STACK_NUM];
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
//
|
||||
// Created by MightyPork on 2017/12/04.
|
||||
//
|
||||
// Utility for monitoring usage levels of FreeRTOS stacks and printing it in a nice table
|
||||
//
|
||||
|
||||
#ifndef GEX_STACKSMON_H
|
||||
#define GEX_STACKSMON_H
|
||||
@@ -8,9 +10,29 @@
|
||||
#include "platform.h"
|
||||
|
||||
#if USE_STACK_MONITOR
|
||||
|
||||
/** Number of tracked stacks, max */
|
||||
#define STACK_NUM 3
|
||||
|
||||
/**
|
||||
* Check canaries and trap if they're dead
|
||||
*/
|
||||
void stackmon_check_canaries(void);
|
||||
|
||||
/**
|
||||
* Dump stacks usage table
|
||||
*/
|
||||
void stackmon_dump(void);
|
||||
|
||||
/**
|
||||
* Register a stack to be monitored
|
||||
*
|
||||
* @param description - stack name
|
||||
* @param buffer - stack buffer
|
||||
* @param len - stack size in bytes
|
||||
*/
|
||||
void stackmon_register(const char *description, void *buffer, uint32_t len);
|
||||
|
||||
#else
|
||||
#define stackmon_check_canaries() do {} while(0)
|
||||
#define stackmon_dump() do {} while(0)
|
||||
|
||||
+9
-1
@@ -1,3 +1,8 @@
|
||||
//
|
||||
// Simple string testing / manipulation functions, mainly used when
|
||||
// building/parsing the config INI files
|
||||
//
|
||||
|
||||
#ifndef PLATFORSTR_UTILS_H
|
||||
#define PLATFORSTR_UTILS_H
|
||||
|
||||
@@ -125,17 +130,20 @@ const char *str_4(uint32_t n,
|
||||
uint32_t nc, const char *c,
|
||||
uint32_t nd, const char *d);
|
||||
|
||||
/** Convert string to one of two numeric options */
|
||||
uint32_t str_parse_2(const char *tpl,
|
||||
const char *a, uint32_t na,
|
||||
const char *b, uint32_t nb,
|
||||
bool *suc);
|
||||
|
||||
/** Convert string to one of three numeric options */
|
||||
uint32_t str_parse_3(const char *tpl,
|
||||
const char *a, uint32_t na,
|
||||
const char *b, uint32_t nb,
|
||||
const char *c, uint32_t nc,
|
||||
bool *suc);
|
||||
|
||||
/** Convert string to one of four numeric options */
|
||||
uint32_t str_parse_4(const char *tpl,
|
||||
const char *a, uint32_t na,
|
||||
const char *b, uint32_t nb,
|
||||
@@ -143,7 +151,7 @@ uint32_t str_parse_4(const char *tpl,
|
||||
const char *d, uint32_t nd,
|
||||
bool *suc);
|
||||
|
||||
/** Convert bool to Y or N */
|
||||
/** Convert bool to a Y or N constant string */
|
||||
#define str_yn(cond) ((cond) ? ("Y") : ("N"))
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
//
|
||||
// Created by MightyPork on 2017/12/08.
|
||||
//
|
||||
// GEX version string
|
||||
//
|
||||
|
||||
#ifndef GEX_VERSION_H
|
||||
#define GEX_VERSION_H
|
||||
|
||||
+10
-2
@@ -1,3 +1,8 @@
|
||||
//
|
||||
// File streams, this was used in DAPLink to capture and flash the firmware update image.
|
||||
// Here we detect only the settings INI files, which start by two hash symbols.
|
||||
//
|
||||
|
||||
/**
|
||||
* @file file_stream.h
|
||||
* @brief Different file stream parsers that are supported
|
||||
@@ -42,16 +47,19 @@ typedef enum {
|
||||
STREAM_TYPE_NONE
|
||||
} stream_type_t;
|
||||
|
||||
// Stateless function to identify a filestream by its contents
|
||||
/** Stateless function to identify a filestream by its contents */
|
||||
stream_type_t stream_start_identify(const uint8_t *data, uint32_t size);
|
||||
|
||||
// Stateless function to identify a filestream by its name
|
||||
/** Stateless function to identify a filestream by its name */
|
||||
stream_type_t stream_type_from_name(const vfs_filename_t filename);
|
||||
|
||||
/** Open a stream (only one can be open at all times) */
|
||||
error_t stream_open(stream_type_t stream_type);
|
||||
|
||||
/** Write some data to an open stream */
|
||||
error_t stream_write(const uint8_t *data, uint32_t size);
|
||||
|
||||
/** Close the open stream */
|
||||
error_t stream_close(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
+1
-1
@@ -328,7 +328,7 @@ void vfs_if_usbd_msc_read_sect(uint32_t sector, uint8_t *buf, uint32_t num_of_se
|
||||
vfs_read(sector, buf, num_of_sectors);
|
||||
}
|
||||
|
||||
void vfs_if_usbd_msc_write_sect(uint32_t sector, uint8_t *buf, uint32_t num_of_sectors)
|
||||
void vfs_if_usbd_msc_write_sect(uint32_t sector, const uint8_t *buf, uint32_t num_of_sectors)
|
||||
{
|
||||
sync_assert_usb_thread();
|
||||
vfs_printf("\033[32mWRITE @ %d, len %d\033[0m", (int)sector, (int)num_of_sectors);
|
||||
|
||||
+78
-18
@@ -1,3 +1,10 @@
|
||||
//
|
||||
// The main VFS state machine, mostly based on DAPLink
|
||||
//
|
||||
// TODO many errors were originally written to a FAIL.TXT file for the user to see,
|
||||
// those are now caught by assert_param(0) and crash the whole system. This is not ideal.
|
||||
//
|
||||
|
||||
/**
|
||||
* @file vfs_manager.h
|
||||
* @brief Methods that build and manipulate a virtual file system
|
||||
@@ -29,61 +36,114 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Flag that we're plugged into Windows.
|
||||
* This is detected by characteristic writes of some system metadata store (which we discard)
|
||||
*/
|
||||
extern bool vfs_is_windows;
|
||||
|
||||
/* Callable from anywhere */
|
||||
|
||||
// Enable or disable the virtual filesystem
|
||||
/** Enable or disable the virtual filesystem */
|
||||
void vfs_mngr_fs_enable(bool enabled);
|
||||
|
||||
// Remount the virtual filesystem
|
||||
/**
|
||||
* Remount the virtual filesystem
|
||||
*
|
||||
* @param force_full - use media ready toggle instead of just notifying of modified data
|
||||
* (this should be more reliable, but can also be more intrusive)
|
||||
*/
|
||||
void vfs_mngr_fs_remount(bool force_full);
|
||||
|
||||
|
||||
/* Callable only from the thread running the virtual fs */
|
||||
|
||||
// Initialize the VFS manager
|
||||
// Must be called after USB has been initialized (usbd_init())
|
||||
// Notes: Must only be called from the thread runnning USB
|
||||
/**
|
||||
* Initialize the VFS manager
|
||||
* Must be called after USB has been initialized (usbd_init())
|
||||
*
|
||||
* @note Must only be called from the thread runnning USB
|
||||
* @param enabled
|
||||
*/
|
||||
void vfs_mngr_init(bool enabled);
|
||||
|
||||
// Run the vfs manager state machine
|
||||
// Notes: Must only be called from the thread runnning USB
|
||||
|
||||
/**
|
||||
* Run the vfs manager state machine
|
||||
*
|
||||
* @note Must only be called from the thread runnning USB
|
||||
* @param elapsed_ms
|
||||
*/
|
||||
void vfs_mngr_periodic(uint32_t elapsed_ms);
|
||||
|
||||
// Return the status of the last transfer or E_SUCCESS
|
||||
// if none have been performed yet
|
||||
/**
|
||||
* Return the status of the last transfer or E_SUCCESS
|
||||
* if none have been performed yet
|
||||
*
|
||||
* @return success
|
||||
*/
|
||||
error_t vfs_mngr_get_transfer_status(void);
|
||||
|
||||
|
||||
/* Use functions */
|
||||
|
||||
// Build the filesystem by calling vfs_init and then adding files with vfs_create_file
|
||||
/**
|
||||
* Build the filesystem by calling vfs_init and then adding files with vfs_create_file
|
||||
*/
|
||||
void vfs_user_build_filesystem(void);
|
||||
|
||||
// Called when a file on the filesystem changes
|
||||
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);
|
||||
/**
|
||||
* Called when a file on the filesystem changes
|
||||
*
|
||||
* @param filename - name of the changed file
|
||||
* @param change - type of change
|
||||
* @param file - data pointer (?)
|
||||
* @param new_file_data - new data pointer (?)
|
||||
*/
|
||||
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);
|
||||
|
||||
// Called when VFS is disconnecting
|
||||
/**
|
||||
* Called when VFS is disconnecting
|
||||
*/
|
||||
void vfs_user_disconnecting(void);
|
||||
|
||||
|
||||
|
||||
// --- interface ---
|
||||
|
||||
/**
|
||||
* Initialize, call form the MSC init callback
|
||||
*/
|
||||
void vfs_if_usbd_msc_init(void);
|
||||
|
||||
/**
|
||||
* MSC wants to read a sector
|
||||
*
|
||||
* @param sector - first sector number
|
||||
* @param buf - destination
|
||||
* @param num_of_sectors - length
|
||||
*/
|
||||
void vfs_if_usbd_msc_read_sect(uint32_t sector, uint8_t *buf, uint32_t num_of_sectors);
|
||||
void vfs_if_usbd_msc_write_sect(uint32_t sector, uint8_t *buf, uint32_t num_of_sectors);
|
||||
|
||||
/**
|
||||
* MSC wants to write a sector
|
||||
*
|
||||
* @param sector - first sector number
|
||||
* @param buf - data
|
||||
* @param num_of_sectors - length
|
||||
*/
|
||||
void vfs_if_usbd_msc_write_sect(uint32_t sector, const uint8_t *buf, uint32_t num_of_sectors);
|
||||
|
||||
typedef struct {
|
||||
uint32_t MemorySize;
|
||||
uint16_t BlockSize;
|
||||
uint32_t BlockGroup; // LUN?
|
||||
uint32_t BlockGroup; // LUN
|
||||
uint32_t BlockCount;
|
||||
// uint8_t *BlockBuf; // apparently unused :thaenkin:
|
||||
bool MediaReady;
|
||||
bool MediaChanged;
|
||||
} vfs_info_t;
|
||||
|
||||
/** VFS info struct - some are used by SCSI/MSC */
|
||||
extern volatile vfs_info_t vfs_info;
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
//
|
||||
// Here are defined the files and handlers
|
||||
//
|
||||
|
||||
/**
|
||||
* @file vfs_user.c
|
||||
* @brief Implementation of vfs_user.h
|
||||
@@ -27,6 +31,7 @@
|
||||
|
||||
const vfs_filename_t daplink_drive_name = VFS_DRIVE_NAME;
|
||||
|
||||
|
||||
static uint32_t read_iw_sector(uint32_t sector_offset, uint8_t *data, uint32_t num_sectors, void (*handler)(IniWriter *))
|
||||
{
|
||||
const uint32_t avail = num_sectors*VFS_SECTOR_SIZE;
|
||||
@@ -38,6 +43,7 @@ static uint32_t read_iw_sector(uint32_t sector_offset, uint8_t *data, uint32_t n
|
||||
return avail - iw.count;
|
||||
}
|
||||
|
||||
|
||||
// File callback to be used with vfs_add_file to return file contents
|
||||
static uint32_t read_file_units_ini(uint32_t sector_offset, uint8_t *data, uint32_t num_sectors)
|
||||
{
|
||||
@@ -45,18 +51,21 @@ static uint32_t read_file_units_ini(uint32_t sector_offset, uint8_t *data, uint3
|
||||
return read_iw_sector(sector_offset, data, num_sectors, settings_build_units_ini);
|
||||
}
|
||||
|
||||
|
||||
static uint32_t read_file_system_ini(uint32_t sector_offset, uint8_t *data, uint32_t num_sectors)
|
||||
{
|
||||
vfs_printf("Read SYSTEM.INI");
|
||||
return read_iw_sector(sector_offset, data, num_sectors, settings_build_system_ini);
|
||||
}
|
||||
|
||||
|
||||
static uint32_t read_file_pinout_txt(uint32_t sector_offset, uint8_t *data, uint32_t num_sectors)
|
||||
{
|
||||
vfs_printf("Read PINOUT.TXT");
|
||||
return read_iw_sector(sector_offset, data, num_sectors, settings_build_pinout_txt);
|
||||
}
|
||||
|
||||
|
||||
void vfs_user_build_filesystem(void)
|
||||
{
|
||||
dbg("Rebuilding VFS...");
|
||||
@@ -69,6 +78,7 @@ void vfs_user_build_filesystem(void)
|
||||
vfs_create_file("PINOUT TXT", read_file_pinout_txt, NULL, iw_measure_total(settings_build_pinout_txt));
|
||||
}
|
||||
|
||||
|
||||
// Callback to handle changes to the root directory. Should be used with vfs_set_file_change_callback
|
||||
void vfs_user_file_change_handler(const vfs_filename_t filename,
|
||||
vfs_file_change_t change,
|
||||
@@ -98,6 +108,7 @@ void vfs_user_file_change_handler(const vfs_filename_t filename,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void vfs_user_disconnecting(void)
|
||||
{
|
||||
// maybe reset...
|
||||
|
||||
+92
-20
@@ -1,3 +1,8 @@
|
||||
//
|
||||
// The guts of the virtual FAT16 are implemented here.
|
||||
// This is taken from DAPLink and some memory-wasting bits are commented out or removed.
|
||||
//
|
||||
|
||||
/**
|
||||
* @file virtual_fs.h
|
||||
* @brief FAT 12/16 filesystem handling
|
||||
@@ -28,6 +33,7 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Toggleable debug funcs
|
||||
#if DEBUG_VFS
|
||||
#define vfs_printf(...) do { dbg(__VA_ARGS__); } while(0)
|
||||
#define vfs_printf_nonl(...) do { PRINTF(__VA_ARGS__); } while(0)
|
||||
@@ -48,6 +54,7 @@ extern "C" {
|
||||
#define VFS_MAX_FILES 16
|
||||
#define VFS_DISK_SIZE MB(32)
|
||||
|
||||
/** Filename typedef */
|
||||
typedef char vfs_filename_t[11];
|
||||
|
||||
typedef enum {
|
||||
@@ -69,51 +76,116 @@ typedef enum {
|
||||
notification will also occur*/
|
||||
} vfs_file_change_t;
|
||||
|
||||
/** File typedef */
|
||||
typedef void *vfs_file_t;
|
||||
|
||||
/** Sector struct typedef */
|
||||
typedef uint32_t vfs_sector_t;
|
||||
|
||||
// Callback for when data is written to a file on the virtual filesystem
|
||||
/**
|
||||
* Callback for when data is written to a file on the virtual filesystem
|
||||
*/
|
||||
typedef void (*vfs_write_cb_t)(uint32_t sector_offset, const uint8_t *data, uint32_t num_sectors);
|
||||
// Callback for when data is ready from the virtual filesystem
|
||||
|
||||
/**
|
||||
* Callback for when data is ready from the virtual filesystem
|
||||
*/
|
||||
typedef uint32_t (*vfs_read_cb_t)(uint32_t sector_offset, uint8_t *data, uint32_t num_sectors);
|
||||
// Callback for when a file's attributes are changed on the virtual filesystem. Note that the 'file' parameter
|
||||
// can be saved and compared to other files to see if they are referencing the same object. The
|
||||
// same cannot be done with new_file_data since it points to a temporary buffer.
|
||||
|
||||
/**
|
||||
* Callback for when a file's attributes are changed on the virtual filesystem.
|
||||
* Note that the 'file' parameter can be saved and compared to other files to see if
|
||||
* they are referencing the same object. The same cannot be done with new_file_data
|
||||
* since it points to a temporary buffer.
|
||||
*/
|
||||
typedef void (*vfs_file_change_cb_t)(const vfs_filename_t filename, vfs_file_change_t change,
|
||||
vfs_file_t file, vfs_file_t new_file_data);
|
||||
|
||||
// Initialize the filesystem with the given size and name
|
||||
/**
|
||||
* Initialize the filesystem with the given size and name
|
||||
*
|
||||
* @param drive_name
|
||||
* @param disk_size
|
||||
*/
|
||||
void vfs_init(const vfs_filename_t drive_name, uint32_t disk_size);
|
||||
|
||||
// Get the total size of the virtual filesystem
|
||||
/**
|
||||
* Get the total size of the virtual filesystem
|
||||
*/
|
||||
uint32_t vfs_get_total_size(void);
|
||||
|
||||
// Add a file to the virtual FS and return a handle to this file.
|
||||
// This must be called before vfs_read or vfs_write are called.
|
||||
// Adding a new file after vfs_read or vfs_write have been called results in undefined behavior.
|
||||
vfs_file_t vfs_create_file(const vfs_filename_t filename, vfs_read_cb_t read_cb, vfs_write_cb_t write_cb, uint32_t len);
|
||||
/**
|
||||
* Add a file to the virtual FS and return a handle to this file.
|
||||
* This must be called before vfs_read or vfs_write are called.
|
||||
* Adding a new file after vfs_read or vfs_write have been called results in undefined behavior.
|
||||
*
|
||||
* @param filename
|
||||
* @param read_cb
|
||||
* @param write_cb
|
||||
* @param len
|
||||
* @return
|
||||
*/
|
||||
vfs_file_t vfs_create_file(const vfs_filename_t filename,
|
||||
vfs_read_cb_t read_cb, vfs_write_cb_t write_cb,
|
||||
uint32_t len);
|
||||
|
||||
// Set the attributes of a file
|
||||
/**
|
||||
* Set the attributes of a file
|
||||
*
|
||||
* @param file
|
||||
* @param attr
|
||||
*/
|
||||
void vfs_file_set_attr(vfs_file_t file, vfs_file_attr_bit_t attr);
|
||||
|
||||
// Get the starting sector of this file.
|
||||
// NOTE - If the file size is 0 there is no starting
|
||||
// sector so VFS_INVALID_SECTOR will be returned.
|
||||
/**
|
||||
* Get the starting sector of this file.
|
||||
* NOTE - If the file size is 0 there is no starting
|
||||
* sector so VFS_INVALID_SECTOR will be returned.
|
||||
*
|
||||
* @param file
|
||||
* @return
|
||||
*/
|
||||
vfs_sector_t vfs_file_get_start_sector(vfs_file_t file);
|
||||
|
||||
// Get the size of the file.
|
||||
/**
|
||||
* Get the size of the file.
|
||||
*
|
||||
* @param file
|
||||
* @return
|
||||
*/
|
||||
uint32_t vfs_file_get_size(vfs_file_t file);
|
||||
|
||||
// Get the attributes of a file
|
||||
/**
|
||||
* Get the attributes of a file
|
||||
*
|
||||
* @param file
|
||||
* @return
|
||||
*/
|
||||
vfs_file_attr_bit_t vfs_file_get_attr(vfs_file_t file);
|
||||
|
||||
// Set the callback when a file is created, deleted or has atributes changed.
|
||||
/**
|
||||
* Set the callback when a file is created, deleted or has atributes changed.
|
||||
*
|
||||
* @param cb
|
||||
*/
|
||||
void vfs_set_file_change_callback(vfs_file_change_cb_t cb);
|
||||
|
||||
// Read one or more sectors from the virtual filesystem
|
||||
/**
|
||||
* Read one or more sectors from the virtual filesystem
|
||||
*
|
||||
* @param sector
|
||||
* @param buf
|
||||
* @param num_of_sectors
|
||||
*/
|
||||
void vfs_read(uint32_t sector, uint8_t *buf, uint32_t num_of_sectors);
|
||||
|
||||
// Write one or more sectors to the virtual filesystem
|
||||
/**
|
||||
* Write one or more sectors to the virtual filesystem
|
||||
*
|
||||
* @param sector
|
||||
* @param buf
|
||||
* @param num_of_sectors
|
||||
*/
|
||||
void vfs_write(uint32_t sector, const uint8_t *buf, uint32_t num_of_sectors);
|
||||
|
||||
bool vfs_find_file(uint32_t start_sector, vfs_filename_t *destFilename, vfs_file_t **destFile);
|
||||
|
||||
Reference in New Issue
Block a user