everything is now documented

sipo
Ondřej Hruška 7 years ago
parent a44eb5f16a
commit 3784a46951
Signed by: MightyPork
GPG Key ID: 2C5FD5035250423D
  1. 19
      USB/README.TXT
  2. 5
      cortex_handlers.c
  3. 19
      debug.h
  4. 4
      freertos.c
  5. 2
      gex_hooks.h
  6. 2
      stm32_assert.h
  7. 47
      utils/avrlibc.h
  8. 4
      utils/circ_buf.h
  9. 2
      utils/cortex_utils.h
  10. 48
      utils/error.h
  11. 3
      utils/hexdump.h
  12. 6
      utils/ini_parser.h
  13. 9
      utils/ini_writer.h
  14. 4
      utils/macro.h
  15. 6
      utils/malloc_safe.h
  16. 9
      utils/snprintf.h
  17. 1
      utils/stacksmon.c
  18. 22
      utils/stacksmon.h
  19. 10
      utils/str_utils.h
  20. 2
      version.h
  21. 12
      vfs/file_stream.h
  22. 2
      vfs/vfs_manager.c
  23. 96
      vfs/vfs_manager.h
  24. 11
      vfs/vfs_user.c
  25. 112
      vfs/virtual_fs.h

@ -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 ------------------------------------------------------------------*/ /* Includes ------------------------------------------------------------------*/
#include "platform.h" #include "platform.h"

@ -1,6 +1,8 @@
// //
// Created by MightyPork on 2017/11/04. // Created by MightyPork on 2017/11/04.
// //
// Debugging functions
//
#ifndef GEX_DEBUG_H #ifndef GEX_DEBUG_H
#define GEX_DEBUG_H #define GEX_DEBUG_H
@ -12,12 +14,19 @@
#if USE_DEBUG_UART #if USE_DEBUG_UART
/** Externally defined function for writing to the debug UART */
extern void debug_write(const char *buf, uint16_t len); 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))) ; void _DO_PRINTF(const char *format, ...) __attribute__((format(printf,1,2))) ;
/** putsn to debug */
void PUTSN(const char *string, uint16_t len); void PUTSN(const char *string, uint16_t len);
/** puts to debug */
void PUTS(const char *string); void PUTS(const char *string);
/** puts with just a newline */
static inline void PUTNL(void) static inline void PUTNL(void)
{ {
debug_write("\r\n", 2); debug_write("\r\n", 2);
@ -33,6 +42,12 @@ static inline void PUTCHAR(char ch)
debug_write(&ch, 1); 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 { \ #define PRINTF(format, ...) do { \
if (VA_ARG_COUNT(__VA_ARGS__) == 0) { \ if (VA_ARG_COUNT(__VA_ARGS__) == 0) { \
PUTS(format); \ PUTS(format); \
@ -41,6 +56,9 @@ static inline void PUTCHAR(char ch)
} \ } \
} while (0) } while (0)
/**
* Debug printf (with a newline)
*/
#define dbg(format, ...) do { \ #define dbg(format, ...) do { \
if (VA_ARG_COUNT(__VA_ARGS__) == 0) { \ if (VA_ARG_COUNT(__VA_ARGS__) == 0) { \
PUTS(format); \ PUTS(format); \
@ -50,7 +68,6 @@ static inline void PUTCHAR(char ch)
PUTNL(); \ PUTNL(); \
} while (0) } while (0)
#else #else
#define dbg(format, ...) do {} while (0) #define dbg(format, ...) do {} while (0)
#define PRINTF(format, ...) do {} while (0) #define PRINTF(format, ...) do {} while (0)

@ -1,3 +1,7 @@
//
// FreeRTOS setup
//
/** /**
****************************************************************************** ******************************************************************************
* File Name : freertos.c * File Name : freertos.c

@ -1,6 +1,8 @@
// //
// Created by MightyPork on 2017/12/15. // Created by MightyPork on 2017/12/15.
// //
// Callbacks from the top level main() function etc
//
#ifndef GEX_GEX_HOOKS_H #ifndef GEX_GEX_HOOKS_H
#define GEX_GEX_HOOKS_H #define GEX_GEX_HOOKS_H

@ -1,6 +1,8 @@
// //
// Created by MightyPork on 2017/11/20. // Created by MightyPork on 2017/11/20.
// //
// Assert handling with traps
//
#ifndef STM32_ASSERT_H #ifndef STM32_ASSERT_H
#define STM32_ASSERT_H #define STM32_ASSERT_H

@ -1,14 +1,59 @@
// //
// Created by MightyPork on 2017/11/26. // 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 #ifndef GEX_AVRLIBC_H_H
#define 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); 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); 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); 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); unsigned long avr_strtoul(const char *nptr, char **endptr, register int base);
#endif //GEX_AVRLIBC_H_H #endif //GEX_AVRLIBC_H_H

@ -1,3 +1,7 @@
//
// This is a circular buffer implementation borrowed from the DAPLink firmware
//
/** /**
* @file circ_buf.h * @file circ_buf.h
* @brief Implementation of a circular buffer * @brief Implementation of a circular buffer

@ -1,6 +1,8 @@
// //
// Created by MightyPork on 2017/11/26. // Created by MightyPork on 2017/11/26.
// //
// Cortex-M utilities (low level stuff missing from CMSIS)
//
#ifndef GEX_CORTEX_UTILS_H #ifndef GEX_CORTEX_UTILS_H
#define GEX_CORTEX_UTILS_H #define GEX_CORTEX_UTILS_H

@ -1,23 +1,6 @@
/** //
* @file error.h // Error codes and labels. Loosely based on DAPLink, with more codes added.
* @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.
*/
#ifndef ERROR_H #ifndef ERROR_H
#define ERROR_H #define ERROR_H
@ -59,7 +42,10 @@
X(OUT_OF_MEM, "Not enough RAM") \ X(OUT_OF_MEM, "Not enough RAM") \
X(RESOURCE_NOT_AVAILABLE, NULL) X(RESOURCE_NOT_AVAILABLE, NULL)
// Keep in sync with the list error_message
/**
* The return value for all functions with error reporting.
*/
typedef enum { typedef enum {
#define X(name, text) E_##name, #define X(name, text) E_##name,
X_ERROR_CODES X_ERROR_CODES
@ -67,8 +53,6 @@ typedef enum {
ERROR_COUNT ERROR_COUNT
} error_t; } 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 */ /** Check return value and return it if not E_SUCCESS */
#define TRY(call) do { \ #define TRY(call) do { \
@ -77,6 +61,24 @@ const char *error_get_name(error_t error) __attribute__((pure));
if (E_SUCCESS != _rv) return _rv; \ if (E_SUCCESS != _rv) return _rv; \
} while (0) } 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 #ifdef __cplusplus
} }
#endif #endif

@ -1,6 +1,9 @@
// //
// Created by MightyPork on 2017/12/04. // 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 #ifndef GEX_HEXDUMP_H
#define 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 #ifndef INIPARSE_STREAM_H
#define INIPARSE_STREAM_H #define INIPARSE_STREAM_H
#include "platform.h" #include "platform.h"
// toggleable logging func
#ifdef DEBUG_INI #ifdef DEBUG_INI
#define ini_error(fmt, ...) dbg("! INI err: "#fmt, ##__VA_ARGS__) #define ini_error(fmt, ...) dbg("! INI err: "#fmt, ##__VA_ARGS__)
#else #else

@ -1,12 +1,19 @@
// //
// Created by MightyPork on 2017/12/01. // 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 #ifndef INIWRITER_H
#define INIWRITER_H #define INIWRITER_H
#include "platform.h" #include "platform.h"
/**
* INI writer handle
*/
typedef struct iniwriter_ { typedef struct iniwriter_ {
char *ptr; char *ptr;
uint32_t skip; uint32_t skip;
@ -18,7 +25,7 @@ typedef struct iniwriter_ {
* *
* This buffer is used internally by printf-like iw functions. * This buffer is used internally by printf-like iw functions.
* It can be used to prepare buffer for iw_buff or iw_string, * 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; extern char *iwbuffer;

@ -1,3 +1,7 @@
//
// static assert and general purpose useful macros, borrowed in part from the DAPLink project
//
/** /**
* @file macro.h * @file macro.h
* @brief useful things + Special asserts and macros * @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 #ifndef MALLOC_SAFE_H
#define MALLOC_SAFE_H #define MALLOC_SAFE_H

@ -1,6 +1,8 @@
// //
// Created by MightyPork on 2017/11/09. // Created by MightyPork on 2017/11/09.
// //
// Small sprintf/snprintf implementation, used instead of the newlib one.
//
#ifndef GEX_SNPRINTF_H #ifndef GEX_SNPRINTF_H
#define 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_asprintf(char **ptr, const char *format, ...);
size_t fixup_sprintf(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 VSNPRINTF(...) fixup_vsnprintf(__VA_ARGS__)
#define SNPRINTF(...) fixup_snprintf(__VA_ARGS__) #define SNPRINTF(...) fixup_snprintf(__VA_ARGS__)
#define VASPRINTF(...) fixup_vasprintf(__VA_ARGS__) #define VASPRINTF(...) fixup_vasprintf(__VA_ARGS__)

@ -15,7 +15,6 @@ struct stackhandle {
uint32_t len; uint32_t len;
}; };
#define STACK_NUM 3
static uint32_t nextidx = 0; static uint32_t nextidx = 0;
static struct stackhandle stacks[STACK_NUM]; static struct stackhandle stacks[STACK_NUM];

@ -1,6 +1,8 @@
// //
// Created by MightyPork on 2017/12/04. // 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 #ifndef GEX_STACKSMON_H
#define GEX_STACKSMON_H #define GEX_STACKSMON_H
@ -8,9 +10,29 @@
#include "platform.h" #include "platform.h"
#if USE_STACK_MONITOR #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); void stackmon_check_canaries(void);
/**
* Dump stacks usage table
*/
void stackmon_dump(void); 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); void stackmon_register(const char *description, void *buffer, uint32_t len);
#else #else
#define stackmon_check_canaries() do {} while(0) #define stackmon_check_canaries() do {} while(0)
#define stackmon_dump() do {} while(0) #define stackmon_dump() do {} while(0)

@ -1,3 +1,8 @@
//
// Simple string testing / manipulation functions, mainly used when
// building/parsing the config INI files
//
#ifndef PLATFORSTR_UTILS_H #ifndef PLATFORSTR_UTILS_H
#define 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 nc, const char *c,
uint32_t nd, const char *d); uint32_t nd, const char *d);
/** Convert string to one of two numeric options */
uint32_t str_parse_2(const char *tpl, uint32_t str_parse_2(const char *tpl,
const char *a, uint32_t na, const char *a, uint32_t na,
const char *b, uint32_t nb, const char *b, uint32_t nb,
bool *suc); bool *suc);
/** Convert string to one of three numeric options */
uint32_t str_parse_3(const char *tpl, uint32_t str_parse_3(const char *tpl,
const char *a, uint32_t na, const char *a, uint32_t na,
const char *b, uint32_t nb, const char *b, uint32_t nb,
const char *c, uint32_t nc, const char *c, uint32_t nc,
bool *suc); bool *suc);
/** Convert string to one of four numeric options */
uint32_t str_parse_4(const char *tpl, uint32_t str_parse_4(const char *tpl,
const char *a, uint32_t na, const char *a, uint32_t na,
const char *b, uint32_t nb, const char *b, uint32_t nb,
@ -143,7 +151,7 @@ uint32_t str_parse_4(const char *tpl,
const char *d, uint32_t nd, const char *d, uint32_t nd,
bool *suc); bool *suc);
/** Convert bool to Y or N */ /** Convert bool to a Y or N constant string */
#define str_yn(cond) ((cond) ? ("Y") : ("N")) #define str_yn(cond) ((cond) ? ("Y") : ("N"))
#endif #endif

@ -1,6 +1,8 @@
// //
// Created by MightyPork on 2017/12/08. // Created by MightyPork on 2017/12/08.
// //
// GEX version string
//
#ifndef GEX_VERSION_H #ifndef GEX_VERSION_H
#define GEX_VERSION_H #define GEX_VERSION_H

@ -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 * @file file_stream.h
* @brief Different file stream parsers that are supported * @brief Different file stream parsers that are supported
@ -42,16 +47,19 @@ typedef enum {
STREAM_TYPE_NONE STREAM_TYPE_NONE
} stream_type_t; } 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); 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); 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); 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); error_t stream_write(const uint8_t *data, uint32_t size);
/** Close the open stream */
error_t stream_close(void); error_t stream_close(void);
#ifdef __cplusplus #ifdef __cplusplus

@ -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); 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(); sync_assert_usb_thread();
vfs_printf("\033[32mWRITE @ %d, len %d\033[0m", (int)sector, (int)num_of_sectors); vfs_printf("\033[32mWRITE @ %d, len %d\033[0m", (int)sector, (int)num_of_sectors);

@ -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 * @file vfs_manager.h
* @brief Methods that build and manipulate a virtual file system * @brief Methods that build and manipulate a virtual file system
@ -29,61 +36,114 @@
extern "C" { extern "C" {
#endif #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; extern bool vfs_is_windows;
/* Callable from anywhere */ /* Callable from anywhere */
// Enable or disable the virtual filesystem /** Enable or disable the virtual filesystem */
void vfs_mngr_fs_enable(bool enabled); 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); void vfs_mngr_fs_remount(bool force_full);
/* Callable only from the thread running the virtual fs */ /* Callable only from the thread running the virtual fs */
// Initialize the VFS manager /**
// Must be called after USB has been initialized (usbd_init()) * Initialize the VFS manager
// Notes: Must only be called from the thread runnning USB * 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); 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); 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); error_t vfs_mngr_get_transfer_status(void);
/* Use functions */ /* 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); 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); void vfs_user_disconnecting(void);
// --- interface --- // --- interface ---
/**
* Initialize, call form the MSC init callback
*/
void vfs_if_usbd_msc_init(void); 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_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 { typedef struct {
uint32_t MemorySize; uint32_t MemorySize;
uint16_t BlockSize; uint16_t BlockSize;
uint32_t BlockGroup; // LUN? uint32_t BlockGroup; // LUN
uint32_t BlockCount; uint32_t BlockCount;
// uint8_t *BlockBuf; // apparently unused :thaenkin:
bool MediaReady; bool MediaReady;
bool MediaChanged; bool MediaChanged;
} vfs_info_t; } vfs_info_t;
/** VFS info struct - some are used by SCSI/MSC */
extern volatile vfs_info_t vfs_info; extern volatile vfs_info_t vfs_info;
#ifdef __cplusplus #ifdef __cplusplus

@ -1,3 +1,7 @@
//
// Here are defined the files and handlers
//
/** /**
* @file vfs_user.c * @file vfs_user.c
* @brief Implementation of vfs_user.h * @brief Implementation of vfs_user.h
@ -27,6 +31,7 @@
const vfs_filename_t daplink_drive_name = VFS_DRIVE_NAME; 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 *)) 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; 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; return avail - iw.count;
} }
// File callback to be used with vfs_add_file to return file contents // 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) 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); 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) static uint32_t read_file_system_ini(uint32_t sector_offset, uint8_t *data, uint32_t num_sectors)
{ {
vfs_printf("Read SYSTEM.INI"); vfs_printf("Read SYSTEM.INI");
return read_iw_sector(sector_offset, data, num_sectors, settings_build_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) static uint32_t read_file_pinout_txt(uint32_t sector_offset, uint8_t *data, uint32_t num_sectors)
{ {
vfs_printf("Read PINOUT.TXT"); vfs_printf("Read PINOUT.TXT");
return read_iw_sector(sector_offset, data, num_sectors, settings_build_pinout_txt); return read_iw_sector(sector_offset, data, num_sectors, settings_build_pinout_txt);
} }
void vfs_user_build_filesystem(void) void vfs_user_build_filesystem(void)
{ {
dbg("Rebuilding VFS..."); 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)); 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 // 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, void vfs_user_file_change_handler(const vfs_filename_t filename,
vfs_file_change_t change, 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) void vfs_user_disconnecting(void)
{ {
// maybe reset... // maybe reset...

@ -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 * @file virtual_fs.h
* @brief FAT 12/16 filesystem handling * @brief FAT 12/16 filesystem handling
@ -28,6 +33,7 @@
extern "C" { extern "C" {
#endif #endif
// Toggleable debug funcs
#if DEBUG_VFS #if DEBUG_VFS
#define vfs_printf(...) do { dbg(__VA_ARGS__); } while(0) #define vfs_printf(...) do { dbg(__VA_ARGS__); } while(0)
#define vfs_printf_nonl(...) do { PRINTF(__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_MAX_FILES 16
#define VFS_DISK_SIZE MB(32) #define VFS_DISK_SIZE MB(32)
/** Filename typedef */
typedef char vfs_filename_t[11]; typedef char vfs_filename_t[11];
typedef enum { typedef enum {
@ -69,51 +76,116 @@ typedef enum {
notification will also occur*/ notification will also occur*/
} vfs_file_change_t; } vfs_file_change_t;
/** File typedef */
typedef void *vfs_file_t; typedef void *vfs_file_t;
/** Sector struct typedef */
typedef uint32_t vfs_sector_t; 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); 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); 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, 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); 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); 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); 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. * Add a file to the virtual FS and return a handle to this file.
// Adding a new file after vfs_read or vfs_write have been called results in undefined behavior. * This must be called before vfs_read or vfs_write are called.
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); * 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); 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 * Get the starting sector of this file.
// sector so VFS_INVALID_SECTOR will be returned. * 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); 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); 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); 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); 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); 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); 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); bool vfs_find_file(uint32_t start_sector, vfs_filename_t *destFilename, vfs_file_t **destFile);

Loading…
Cancel
Save