/----------------------------------------------------------------------------*/
#ifndef _FFCONF
#define _FFCONF 8237 /* Revision ID */
-\r
-\r
+
+
/*---------------------------------------------------------------------------/
/ Function and Buffer Configurations
/----------------------------------------------------------------------------*/
-\r
+
#define _FS_TINY 0 /* 0:Normal or 1:Tiny */
/* When _FS_TINY is set to 1, FatFs uses the sector buffer in the file system
/ object instead of the sector buffer in the individual file object for file
/ data transfer. This reduces memory consumption 512 bytes each file object. */
-\r
-\r
+
+
#define _FS_READONLY 0 /* 0:Read/Write or 1:Read only */
/* Setting _FS_READONLY to 1 defines read only configuration. This removes
/ writing functions, f_write, f_sync, f_unlink, f_mkdir, f_chmod, f_rename,
/ f_truncate and useless f_getfree. */
-\r
-\r
+
+
#define _FS_MINIMIZE 0 /* 0 to 3 */
/* The _FS_MINIMIZE option defines minimization level to remove some functions.
/
/ are removed.
/ 2: f_opendir and f_readdir are removed in addition to 1.
/ 3: f_lseek is removed in addition to 2. */
-\r
-\r
+
+
#define _USE_STRFUNC 1 /* 0:Disable or 1/2:Enable */
/* To enable string functions, set _USE_STRFUNC to 1 or 2. */
-\r
-\r
+
+
#define _USE_MKFS 1 /* 0:Disable or 1:Enable */
/* To enable f_mkfs function, set _USE_MKFS to 1 and set _FS_READONLY to 0 */
-\r
-\r
+
+
#define _USE_FORWARD 0 /* 0:Disable or 1:Enable */
/* To enable f_forward function, set _USE_FORWARD to 1 and set _FS_TINY to 1. */
-\r
-\r
+
+
#define _USE_FASTSEEK 0 /* 0:Disable or 1:Enable */
/* To enable fast seek feature, set _USE_FASTSEEK to 1. */
-\r
-\r
-\r
+
+
+
/*---------------------------------------------------------------------------/
/ Locale and Namespace Configurations
/----------------------------------------------------------------------------*/
-\r
+
#define _CODE_PAGE 1252
/* The _CODE_PAGE specifies the OEM code page to be used on the target system.
/ Incorrect setting of the code page can cause a file open failure.
/ 874 - Thai (OEM, Windows)
/ 1 - ASCII only (Valid for non LFN cfg.)
*/
-\r
-\r
+
+
#define _USE_LFN 1 /* 0 to 3 */
#define _MAX_LFN 255 /* Maximum LFN length to handle (12 to 255) */
/* The _USE_LFN option switches the LFN support.
/ Unicode handling functions ff_convert() and ff_wtoupper() must be added
/ to the project. When enable to use heap, memory control functions
/ ff_memalloc() and ff_memfree() must be added to the project. */
-\r
-\r
+
+
#define _LFN_UNICODE 0 /* 0:ANSI/OEM or 1:Unicode */
/* To switch the character code set on FatFs API to Unicode,
/ enable LFN feature and set _LFN_UNICODE to 1. */
-\r
-\r
+
+
#define _FS_RPATH 0 /* 0 to 2 */
/* The _FS_RPATH option configures relative path feature.
/
/ 2: f_getcwd() is available in addition to 1.
/
/ Note that output of the f_readdir fnction is affected by this option. */
-\r
-\r
-\r
+
+
+
/*---------------------------------------------------------------------------/
/ Physical Drive Configurations
/----------------------------------------------------------------------------*/
-\r
-#define _VOLUMES 1
+
+#define _VOLUMES 2
/* Number of volumes (logical drives) to be used. */
-\r
-\r
+
+
#define _MAX_SS 512 /* 512, 1024, 2048 or 4096 */
/* Maximum sector size to be handled.
/ Always set 512 for memory card and hard disk but a larger value may be
/ required for on-board flash memory, floppy disk and optical disk.
/ When _MAX_SS is larger than 512, it configures FatFs to variable sector size
/ and GET_SECTOR_SIZE command must be implememted to the disk_ioctl function. */
-\r
-\r
+
+
#define _MULTI_PARTITION 0 /* 0:Single partition or 1:Multiple partition */
/* When set to 0, each volume is bound to the same physical drive number and
/ it can mount only first primaly partition. When it is set to 1, each volume
/ is tied to the partitions listed in VolToPart[]. */
-\r
-\r
+
+
#define _USE_ERASE 0 /* 0:Disable or 1:Enable */
/* To enable sector erase feature, set _USE_ERASE to 1. CTRL_ERASE_SECTOR command
/ should be added to the disk_ioctl functio. */
-\r
-\r
-\r
+
+
+
/*---------------------------------------------------------------------------/
/ System Configurations
/----------------------------------------------------------------------------*/
-\r
+
#define _WORD_ACCESS 0 /* 0 or 1 */
/* Set 0 first and it is always compatible with all platforms. The _WORD_ACCESS
/ option defines which access method is used to the word data on the FAT volume.
/ access results incorrect behavior, the _WORD_ACCESS must be set to 0.
/ If it is not the case, the value can also be set to 1 to improve the
/ performance and code size. */
-\r
-\r
+
+
/* A header file that defines sync object types on the O/S, such as
/ windows.h, ucos_ii.h and semphr.h, must be included prior to ff.h. */
-\r
+
#define _FS_REENTRANT 0 /* 0:Disable or 1:Enable */
#define _FS_TIMEOUT 1000 /* Timeout period in unit of time ticks */
#define _SYNC_t HANDLE /* O/S dependent type of sync object. e.g. HANDLE, OS_EVENT*, ID and etc.. */
-\r
+
/* The _FS_REENTRANT option switches the reentrancy (thread safe) of the FatFs module.
/
/ 0: Disable reentrancy. _SYNC_t and _FS_TIMEOUT have no effect.
/ 1: Enable reentrancy. Also user provided synchronization handlers,
/ ff_req_grant, ff_rel_grant, ff_del_syncobj and ff_cre_syncobj
/ function must be added to the project. */
-\r
-\r
+
+
#define _FS_SHARE 0 /* 0:Disable or >=1:Enable */
/* To enable file shareing feature, set _FS_SHARE to 1 or greater. The value
defines how many files can be opened simultaneously. */
-\r
-\r
+
+
#endif /* _FFCONFIG */
#include "StreamOutputPool.h"
#include "ConfigValue.h"
+#include "libs/USBDevice/USBMSD/SDCard.h"
+#include "libs/SDFAT.h"
+
//definitions for lcd
#define LCDWIDTH 128
#define LCDHEIGHT 64
#define reverse_checksum CHECKSUM("reverse")
#define rst_pin_checksum CHECKSUM("rst_pin")
#define a0_pin_checksum CHECKSUM("a0_pin")
+#define sdcd_pin_checksum CHECKSUM("sdcd_pin")
#define red_led_checksum CHECKSUM("red_led_pin")
#define blue_led_checksum CHECKSUM("blue_led_pin")
#define CLAMP(x, low, high) { if ( (x) < (low) ) x = (low); if ( (x) > (high) ) x = (high); } while (0);
#define swap(a, b) { uint8_t t = a; a = b; b = t; }
-ST7565::ST7565(uint8_t variant) {
+ST7565::ST7565(uint8_t variant)
+{
// set the variant
switch(variant) {
case 1:
- is_viki2= true;
- is_mini_viki2= false;
- this->reversed= true;
- this->contrast= 9;
+ is_viki2 = true;
+ is_mini_viki2 = false;
+ this->reversed = true;
+ this->contrast = 9;
break;
case 2:
- is_mini_viki2= true;
- is_viki2= false;
- this->reversed= true;
- this->contrast= 18;
+ is_mini_viki2 = true;
+ is_viki2 = false;
+ this->reversed = true;
+ this->contrast = 18;
break;
default:
// set default for sub variants
- is_viki2= false; // defaults to Wulfnors panel
- is_mini_viki2= false;
- this->reversed= false;
- this->contrast= 9;
+ is_viki2 = false; // defaults to Wulfnors panel
+ is_mini_viki2 = false;
+ this->reversed = false;
+ this->contrast = 9;
break;
}
int spi_channel = THEKERNEL->config->value(panel_checksum, spi_channel_checksum)->by_default(0)->as_number();
PinName mosi;
PinName sclk;
- if(spi_channel == 0){
- mosi= P0_18; sclk= P0_15;
- }else if(spi_channel == 1){
- mosi= P0_9; sclk= P0_7;
- }else{
- mosi= P0_18; sclk= P0_15;
+ if(spi_channel == 0) {
+ mosi = P0_18; sclk = P0_15;
+ } else if(spi_channel == 1) {
+ mosi = P0_9; sclk = P0_7;
+ } else {
+ mosi = P0_18; sclk = P0_15;
}
- this->spi= new mbed::SPI(mosi,NC,sclk);
+ this->spi = new mbed::SPI(mosi, NC, sclk);
this->spi->frequency(THEKERNEL->config->value(panel_checksum, spi_frequency_checksum)->by_default(1000000)->as_number()); //4Mhz freq, can try go a little lower
//chip select
if(!is_viki2 && !is_mini_viki2) {
this->up_pin.from_string(THEKERNEL->config->value( panel_checksum, up_button_pin_checksum )->by_default("nc")->as_string())->as_input();
this->down_pin.from_string(THEKERNEL->config->value( panel_checksum, down_button_pin_checksum )->by_default("nc")->as_string())->as_input();
- }else{
+ } else {
this->up_pin.from_string("nc");
this->down_pin.from_string("nc");
}
this->aux_pin.from_string("nc");
if(is_viki2) {
// the aux pin can be pause or back on a viki2
- string aux_but= THEKERNEL->config->value( panel_checksum, pause_button_pin_checksum )->by_default("nc")->as_string();
+ string aux_but = THEKERNEL->config->value( panel_checksum, pause_button_pin_checksum )->by_default("nc")->as_string();
if(aux_but != "nc") {
this->aux_pin.from_string(aux_but)->as_input();
- this->use_pause= true;
- this->use_back= false;
+ this->use_pause = true;
+ this->use_back = false;
- }else{
- aux_but= THEKERNEL->config->value( panel_checksum, back_button_pin_checksum )->by_default("nc")->as_string();
+ } else {
+ aux_but = THEKERNEL->config->value( panel_checksum, back_button_pin_checksum )->by_default("nc")->as_string();
if(aux_but != "nc") {
this->aux_pin.from_string(aux_but)->as_input();
- this->use_back= true;
- this->use_pause= false;
+ this->use_back = true;
+ this->use_pause = false;
}
}
}
this->blue_led.set(true);
}
+ // external sdcard detect
+ this->sdcd_pin.from_string(THEKERNEL->config->value( panel_checksum, sdcd_pin_checksum )->by_default("nc")->as_string())->as_input();
+
// contrast override
- this->contrast= THEKERNEL->config->value(panel_checksum, contrast_checksum)->by_default(this->contrast)->as_number();
+ this->contrast = THEKERNEL->config->value(panel_checksum, contrast_checksum)->by_default(this->contrast)->as_number();
// reverse display
- this->reversed= THEKERNEL->config->value(panel_checksum, reverse_checksum)->by_default(this->reversed)->as_bool();
+ this->reversed = THEKERNEL->config->value(panel_checksum, reverse_checksum)->by_default(this->reversed)->as_bool();
- framebuffer= (uint8_t *)AHB0.alloc(FB_SIZE); // grab some memory from USB_RAM
+ framebuffer = (uint8_t *)AHB0.alloc(FB_SIZE); // grab some memory from USB_RAM
if(framebuffer == NULL) {
THEKERNEL->streams->printf("Not enough memory available for frame buffer");
}
+ this->sd= nullptr;
+ this->extmounter= nullptr;
}
-ST7565::~ST7565() {
- delete this->spi;
+ST7565::~ST7565()
+{
+ delete this->spi;
AHB0.dealloc(framebuffer);
+ delete this->extmounter;
}
//send commands to lcd
-void ST7565::send_commands(const unsigned char* buf, size_t size){
+void ST7565::send_commands(const unsigned char *buf, size_t size)
+{
cs.set(0);
a0.set(0);
- while(size-- >0){
- spi->write(*buf++);
+ while(size-- > 0) {
+ spi->write(*buf++);
}
cs.set(1);
}
//send data to lcd
-void ST7565::send_data(const unsigned char* buf, size_t size){
+void ST7565::send_data(const unsigned char *buf, size_t size)
+{
cs.set(0);
a0.set(1);
- while(size-- >0){
- spi->write(*buf++);
+ while(size-- > 0) {
+ spi->write(*buf++);
}
cs.set(1);
a0.set(0);
}
//clearing screen
-void ST7565::clear(){
+void ST7565::clear()
+{
memset(framebuffer, 0, FB_SIZE);
- this->tx=0;
- this->ty=0;
+ this->tx = 0;
+ this->ty = 0;
}
-void ST7565::send_pic(const unsigned char* data){
- for (int i=0; i<LCDPAGES; i++)
- {
- set_xy(0, i);
- send_data(data + i*LCDWIDTH, LCDWIDTH);
+void ST7565::send_pic(const unsigned char *data)
+{
+ for (int i = 0; i < LCDPAGES; i++) {
+ set_xy(0, i);
+ send_data(data + i * LCDWIDTH, LCDWIDTH);
}
}
// set column and page number
void ST7565::set_xy(int x, int y)
{
- CLAMP(x, 0, LCDWIDTH-1);
- CLAMP(y, 0, LCDPAGES-1);
+ CLAMP(x, 0, LCDWIDTH - 1);
+ CLAMP(y, 0, LCDPAGES - 1);
unsigned char cmd[3];
cmd[0] = 0xb0 | (y & 0x07);
cmd[1] = 0x10 | (x >> 4);
send_commands(cmd, 3);
}
-void ST7565::setCursor(uint8_t col, uint8_t row){
- this->tx=col*6;
- this->ty=row*8;
+void ST7565::setCursor(uint8_t col, uint8_t row)
+{
+ this->tx = col * 6;
+ this->ty = row * 8;
}
-void ST7565::home(){
- this->tx=0;
- this->ty=0;
+void ST7565::home()
+{
+ this->tx = 0;
+ this->ty = 0;
}
-void ST7565::display(){
- ///nothing
+void ST7565::display()
+{
+ ///nothing
}
-void ST7565::init(){
+void ST7565::init()
+{
const unsigned char init_seq[] = {
- 0x40, //Display start line 0
- (unsigned char)(reversed?0xa0:0xa1), // ADC
- (unsigned char)(reversed?0xc8:0xc0), // COM select
- 0xa6, //Display normal
- 0xa2, //Set Bias 1/9 (Duty 1/65)
- 0x2f, //Booster, Regulator and Follower On
- 0xf8, //Set internal Booster to 4x
- 0x00,
- 0x27, //Contrast set
- 0x81,
- this->contrast, //contrast value
- 0xac, //No indicator
- 0x00,
- 0xaf, //Display on
- };
- //rst.set(0);
- if(this->rst.connected()) rst.set(1);
- send_commands(init_seq, sizeof(init_seq));
- clear();
+ 0x40, //Display start line 0
+ (unsigned char)(reversed ? 0xa0 : 0xa1), // ADC
+ (unsigned char)(reversed ? 0xc8 : 0xc0), // COM select
+ 0xa6, //Display normal
+ 0xa2, //Set Bias 1/9 (Duty 1/65)
+ 0x2f, //Booster, Regulator and Follower On
+ 0xf8, //Set internal Booster to 4x
+ 0x00,
+ 0x27, //Contrast set
+ 0x81,
+ this->contrast, //contrast value
+ 0xac, //No indicator
+ 0x00,
+ 0xaf, //Display on
+ };
+ //rst.set(0);
+ if(this->rst.connected()) rst.set(1);
+ send_commands(init_seq, sizeof(init_seq));
+ clear();
}
-void ST7565::setContrast(uint8_t c){
+void ST7565::setContrast(uint8_t c)
+{
const unsigned char contrast_seq[] = {
- 0x27, //Contrast set
- 0x81,
- c //contrast value
- };
- this->contrast= c;
- send_commands(contrast_seq, sizeof(contrast_seq));
+ 0x27, //Contrast set
+ 0x81,
+ c //contrast value
+ };
+ this->contrast = c;
+ send_commands(contrast_seq, sizeof(contrast_seq));
}
-int ST7565::drawChar(int x, int y, unsigned char c, int color){
- int retVal=-1;
- if(c=='\n'){
- this->ty+=8;
- retVal= -tx;
- }
- if(c=='\r'){
- retVal= -tx;
- }
- else{
- for (uint8_t i =0; i<5; i++ ) {
- if(color==0){
- framebuffer[x + (y/8*128) ] = ~(glcd_font[(c*5)+i]<< y%8);
- if(y+8<63){
- framebuffer[x + ((y+8)/8*128) ] = ~(glcd_font[(c*5)+i] >>(8-(y%8)));
- }
- }
- if(color==1){
- framebuffer[x + ((y)/8*128) ] = glcd_font[(c*5)+i] <<(y%8);
- if(y+8<63){
- framebuffer[x + ((y+8)/8*128) ] = glcd_font[(c*5)+i] >>(8-(y%8));
- }
- }
- x++;
- }
- retVal= 6;
- this->tx+=6;
- }
-
- return retVal;
+int ST7565::drawChar(int x, int y, unsigned char c, int color)
+{
+ int retVal = -1;
+ if(c == '\n') {
+ this->ty += 8;
+ retVal = -tx;
+ }
+ if(c == '\r') {
+ retVal = -tx;
+ } else {
+ for (uint8_t i = 0; i < 5; i++ ) {
+ if(color == 0) {
+ framebuffer[x + (y / 8 * 128) ] = ~(glcd_font[(c * 5) + i] << y % 8);
+ if(y + 8 < 63) {
+ framebuffer[x + ((y + 8) / 8 * 128) ] = ~(glcd_font[(c * 5) + i] >> (8 - (y % 8)));
+ }
+ }
+ if(color == 1) {
+ framebuffer[x + ((y) / 8 * 128) ] = glcd_font[(c * 5) + i] << (y % 8);
+ if(y + 8 < 63) {
+ framebuffer[x + ((y + 8) / 8 * 128) ] = glcd_font[(c * 5) + i] >> (8 - (y % 8));
+ }
+ }
+ x++;
+ }
+ retVal = 6;
+ this->tx += 6;
+ }
+
+ return retVal;
}
//write single char to screen
-void ST7565::write_char(char value){
- drawChar(this->tx, this->ty,value,1);
+void ST7565::write_char(char value)
+{
+ drawChar(this->tx, this->ty, value, 1);
}
-void ST7565::write(const char* line, int len){
+void ST7565::write(const char *line, int len)
+{
for (int i = 0; i < len; ++i) {
- write_char(line[i]);
+ write_char(line[i]);
}
}
-//refreshing screen
-void ST7565::on_refresh(bool now){
+//refreshing screen
+void ST7565::on_refresh(bool now)
+{
static int refresh_counts = 0;
refresh_counts++;
// 10Hz refresh rate
- if(now || refresh_counts % 2 == 0 ){
- send_pic(framebuffer);
- }
+ if(now || refresh_counts % 2 == 0 ) {
+ send_pic(framebuffer);
+ }
}
//reading button state
-uint8_t ST7565::readButtons(void) {
- uint8_t state= 0;
+uint8_t ST7565::readButtons(void)
+{
+ uint8_t state = 0;
state |= (this->click_pin.get() ? BUTTON_SELECT : 0);
if(this->up_pin.connected()) {
state |= (this->up_pin.get() ? BUTTON_UP : 0);
if(this->use_pause) state |= BUTTON_PAUSE;
else if(this->use_back) state |= BUTTON_LEFT;
}
+
+ // sd insert detect, mount sdcard if inserted, unmount if removed
+ if(this->sdcd_pin.connected()) {
+ if(this->extmounter == nullptr && this->sdcd_pin.get()) {
+ mount_external_sd(true);
+ }else if(this->extmounter != nullptr && !this->sdcd_pin.get()){
+ mount_external_sd(false);
+ }
+ }
return state;
}
-int ST7565::readEncoderDelta() {
- static int8_t enc_states[] = {0,-1,1,0,1,0,0,-1,-1,0,0,1,0,1,-1,0};
+int ST7565::readEncoderDelta()
+{
+ static int8_t enc_states[] = {0, -1, 1, 0, 1, 0, 0, -1, -1, 0, 0, 1, 0, 1, -1, 0};
static uint8_t old_AB = 0;
if(this->encoder_a_pin.connected()) {
// mviki
old_AB <<= 2; //remember previous state
old_AB |= ( this->encoder_a_pin.get() + ( this->encoder_b_pin.get() * 2 ) ); //add current state
- return enc_states[(old_AB&0x0f)];
+ return enc_states[(old_AB & 0x0f)];
- }else{
+ } else {
return 0;
}
}
-void ST7565::bltGlyph(int x, int y, int w, int h, const uint8_t *glyph, int span, int x_offset, int y_offset) {
+void ST7565::bltGlyph(int x, int y, int w, int h, const uint8_t *glyph, int span, int x_offset, int y_offset)
+{
if(x_offset == 0 && y_offset == 0 && span == 0) {
// blt the whole thing
renderGlyph(x, y, glyph, w, h);
- }else{
+ } else {
// copy portion of glyph into g where x_offset is left byte aligned
// Note currently the x_offset must be byte aligned
- int n= w/8; // bytes per line to copy
- if(w%8 != 0) n++; // round up to next byte
- uint8_t g[n*h];
- uint8_t *dst= g;
- const uint8_t *src= &glyph[y_offset*span + x_offset/8];
+ int n = w / 8; // bytes per line to copy
+ if(w % 8 != 0) n++; // round up to next byte
+ uint8_t g[n * h];
+ uint8_t *dst = g;
+ const uint8_t *src = &glyph[y_offset * span + x_offset / 8];
for (int i = 0; i < h; ++i) {
memcpy(dst, src, n);
- dst+=n;
- src+= span;
+ dst += n;
+ src += span;
}
renderGlyph(x, y, g, w, h);
}
}
-void ST7565::renderGlyph(int x, int y, const uint8_t *g, int w, int h) {
- CLAMP(x, 0, LCDWIDTH-1);
- CLAMP(y, 0, LCDHEIGHT-1);
+void ST7565::renderGlyph(int x, int y, const uint8_t *g, int w, int h)
+{
+ CLAMP(x, 0, LCDWIDTH - 1);
+ CLAMP(y, 0, LCDHEIGHT - 1);
CLAMP(w, 0, LCDWIDTH - x);
CLAMP(h, 0, LCDHEIGHT - y);
- for(int i=0; i<w; i++){
- for(int j=0; j<h; j++){
- pixel(x+i,y+j,g[(i/8)+ j*((w-1)/8 +1)] & (1<<(7-i%8)));
- }
+ for(int i = 0; i < w; i++) {
+ for(int j = 0; j < h; j++) {
+ pixel(x + i, y + j, g[(i / 8) + j * ((w - 1) / 8 + 1)] & (1 << (7 - i % 8)));
+ }
}
}
void ST7565::pixel(int x, int y, int colour)
{
int page = y / 8;
- unsigned char mask = 1<<(y%8);
- unsigned char *byte = &framebuffer[page*LCDWIDTH + x];
+ unsigned char mask = 1 << (y % 8);
+ unsigned char *byte = &framebuffer[page * LCDWIDTH + x];
if ( colour == 0 )
*byte &= ~mask; // clear pixel
else
}
// cycle the buzzer pin at a certain frequency (hz) for a certain duration (ms)
-void ST7565::buzz(long duration, uint16_t freq) {
+void ST7565::buzz(long duration, uint16_t freq)
+{
if(!this->buzz_pin.connected()) return;
- duration *=1000; //convert from ms to us
+ duration *= 1000; //convert from ms to us
long period = 1000000 / freq; // period in us
long elapsed_time = 0;
while (elapsed_time < duration) {
}
}
-void ST7565::setLed(int led, bool onoff) {
+void ST7565::setLed(int led, bool onoff)
+{
if(!is_viki2) return;
- if(led == LED_HOT){
+ if(led == LED_HOT) {
if(onoff) {
red_led.set(true);
blue_led.set(false);
- }else{
+ } else {
red_led.set(false);
blue_led.set(true);
}
}
}
+
+bool ST7565::mount_external_sd(bool on)
+{
+ // now setup the external sdcard if we have one and mount it
+ if(on) {
+ if(this->sd == nullptr) {
+ size_t n= sizeof(SDCard);
+ void *v = AHB0.alloc(n);
+ memset(v, 0, n); // clear the allocated memory
+ this->sd= new(v) SDCard(P0_18, P0_17, P0_15, P2_8); // allocate object using zeroed memory
+ }
+ delete this->extmounter; // if it was not unmounted before
+ size_t n= sizeof(SDFAT);
+ void *v = AHB0.alloc(n);
+ memset(v, 0, n); // clear the allocated memory
+ this->extmounter= new(v) SDFAT("ext", this->sd);
+ THEKERNEL->streams->printf("External SDcard mounted as /ext, size %d\n", n);
+ }else{
+ delete this->extmounter;
+ this->extmounter= nullptr;
+ THEKERNEL->streams->printf("External SDcard unmounted\n");
+ }
+ return true;
+}