diff --git a/.github/makecode/blocks.png b/.github/makecode/blocks.png
deleted file mode 100644
index ff01e32..0000000
Binary files a/.github/makecode/blocks.png and /dev/null differ
diff --git a/.github/workflows/makecode.yml b/.github/workflows/makecode.yml
deleted file mode 100644
index 1aa354c..0000000
--- a/.github/workflows/makecode.yml
+++ /dev/null
@@ -1,29 +0,0 @@
-name: MakeCode
-
-on: [push]
-
-jobs:
- build:
-
- runs-on: ubuntu-latest
-
- strategy:
- matrix:
- node-version: [8.x]
-
- steps:
- - uses: actions/checkout@v1
- - name: Use Node.js ${{ matrix.node-version }}
- uses: actions/setup-node@v1
- with:
- node-version: ${{ matrix.node-version }}
- - name: npm install
- run: |
- npm install -g pxt
- pxt target microbit
- - name: build
- run: |
- pxt install
- pxt build --cloud
- env:
- CI: true
diff --git a/.github/workflows/maker.yml b/.github/workflows/maker.yml
new file mode 100644
index 0000000..316cc1d
--- /dev/null
+++ b/.github/workflows/maker.yml
@@ -0,0 +1,44 @@
+name: maker
+
+on:
+ push:
+ branches:
+ - master
+ schedule:
+ - cron: '0 0 5,20 * *'
+
+jobs:
+ prepare:
+ runs-on: ubuntu-latest
+ if: "! contains(github.event.head_commit.message, '[skip ci]')"
+ steps:
+ - run: echo "${{ github.event.head_commit.message }}"
+
+ build:
+ needs: prepare
+ runs-on: ubuntu-latest
+
+ strategy:
+ matrix:
+ node-version: [8.x]
+
+ steps:
+ - uses: actions/checkout@v1
+ - name: Use Node.js ${{ matrix.node-version }}
+ uses: actions/setup-node@v1
+ with:
+ node-version: ${{ matrix.node-version }}
+
+ - name: maker pxt.json
+ uses: datamonsters/replace-action@master
+ with:
+ files: 'pxt.json'
+ replacements: 'core=xinabox-cs11,test.ts=dummy.ts'
+ - name: maker compilation
+ run: |
+ npm install -g pxt
+ pxt target maker
+ pxt install
+ pxt build --cloud
+ env:
+ CI: true
diff --git a/.gitignore b/.gitignore
index d2196e7..26c0c1f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,3 @@
-# MakeCode
built
node_modules
yotta_modules
@@ -8,4 +7,9 @@ _site
*.db
*.tgz
.header.json
-.simstate.json
+main.ts
+main.blocks
+Gemfile
+_config.yml
+tsconfig.json
+.vscode
\ No newline at end of file
diff --git a/.vscode/settings.json b/.vscode/settings.json
deleted file mode 100644
index f8106d4..0000000
--- a/.vscode/settings.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "editor.formatOnType": true,
- "files.autoSave": "afterDelay",
- "files.watcherExclude": {
- "**/.git/objects/**": true,
- "**/built/**": true,
- "**/node_modules/**": true,
- "**/yotta_modules/**": true,
- "**/yotta_targets": true,
- "**/pxt_modules/**": true
- },
- "files.associations": {
- "*.blocks": "html",
- "*.jres": "json"
- },
- "search.exclude": {
- "**/built": true,
- "**/node_modules": true,
- "**/yotta_modules": true,
- "**/yotta_targets": true,
- "**/pxt_modules": true
- }
-}
\ No newline at end of file
diff --git a/.vscode/tasks.json b/.vscode/tasks.json
deleted file mode 100644
index 9ee2cf6..0000000
--- a/.vscode/tasks.json
+++ /dev/null
@@ -1,30 +0,0 @@
-
-// A task runner that calls the MakeCode (PXT) compiler
-{
- "version": "2.0.0",
- "tasks": [{
- "label": "pxt deploy",
- "type": "shell",
- "command": "pxt deploy --local",
- "group": "build",
- "problemMatcher": [ "$tsc" ]
- }, {
- "label": "pxt build",
- "type": "shell",
- "command": "pxt build --local",
- "group": "build",
- "problemMatcher": [ "$tsc" ]
- }, {
- "label": "pxt install",
- "type": "shell",
- "command": "pxt install",
- "group": "build",
- "problemMatcher": [ "$tsc" ]
- }, {
- "label": "pxt clean",
- "type": "shell",
- "command": "pxt clean",
- "group": "test",
- "problemMatcher": [ "$tsc" ]
- }]
-}
diff --git a/Gemfile b/Gemfile
deleted file mode 100644
index 91ceacd..0000000
--- a/Gemfile
+++ /dev/null
@@ -1,2 +0,0 @@
-source 'https://rubygems.org'
-gem 'github-pages', group: :jekyll_plugins
\ No newline at end of file
diff --git a/README.md b/README.md
index 6246e5c..3728537 100644
--- a/README.md
+++ b/README.md
@@ -1,31 +1,36 @@
+[![GitHub Issues](https://img.shields.io/github/issues/xinabox/pxt-CS11.svg)](https://github.com/xinabox/pxt-CS11/issues)
+![GitHub Commit](https://img.shields.io/github/last-commit/xinabox/pxt-CS11)
+![Maintained](https://img.shields.io/maintenance/yes/2020)
+![Build status badge](https://github.com/xinabox/pxt-CS11/workflows/maker/badge.svg)
+![Developer](https://img.shields.io/badge/Developer-lb-blue)
-> Open this page at [https://xinabox.github.io/pxt-im01-2/](https://xinabox.github.io/pxt-im01-2/)
+> Open this page at [https://.github.io//](https://.github.io//)
## Use as Extension
This repository can be added as an **extension** in MakeCode.
-* open [https://makecode.microbit.org/](https://makecode.microbit.org/)
+* open []()
* click on **New Project**
* click on **Extensions** under the gearwheel menu
-* search for **https://github.com/xinabox/pxt-im01-2** and import
+* search for **https://github.com/** and import
-## Edit this project ![Build status badge](https://github.com/xinabox/pxt-im01-2/workflows/MakeCode/badge.svg)
+## Edit this project ![Build status badge](https://github.com//workflows/MakeCode/badge.svg)
To edit this repository in MakeCode.
-* open [https://makecode.microbit.org/](https://makecode.microbit.org/)
+* open []()
* click on **Import** then click on **Import URL**
-* paste **https://github.com/xinabox/pxt-im01-2** and click import
+* paste **https://github.com/** and click import
## Blocks preview
This image shows the blocks code from the last commit in master.
This image may take a few minutes to refresh.
-![A rendered view of the blocks](https://github.com/xinabox/pxt-im01-2/raw/master/.github/makecode/blocks.png)
+![A rendered view of the blocks](https://github.com//raw/master/.github/makecode/blocks.png)
#### Metadata (used for search, rendering)
-* for PXT/microbit
+* for PXT/
diff --git a/_config.yml b/_config.yml
deleted file mode 100644
index f56a029..0000000
--- a/_config.yml
+++ /dev/null
@@ -1,8 +0,0 @@
-makecode:
- target: microbit
- platform: microbit
- home_url: https://makecode.microbit.org/
-theme: jekyll-theme-slate
-include:
- - assets
- - README.md
diff --git a/diskio.h b/diskio.h
new file mode 100644
index 0000000..f3b3b5e
--- /dev/null
+++ b/diskio.h
@@ -0,0 +1,38 @@
+#include "ff.h"
+#ifndef _DISKIO_DEFINED
+#define _DISKIO_DEFINED
+
+typedef BYTE DSTATUS;
+
+typedef enum
+{
+ RES_OK = 0,
+ RES_ERROR,
+ RES_WRPRT,
+ RES_NOTRDY,
+ RES_PARERR
+} DRESULT;
+
+DSTATUS disk_initialize(BYTE pdrv);
+DSTATUS disk_status(BYTE pdrv);
+DRESULT disk_read(BYTE pdrv, BYTE *buff, LBA_t sector, UINT count);
+DRESULT disk_write(BYTE pdrv, const BYTE *buff, LBA_t sector, UINT count);
+DRESULT disk_ioctl(BYTE pdrv, BYTE cmd, void *buff);
+
+#define STA_NOINIT 0x01
+
+#define STA_PROTECT 0x04
+
+#define CTRL_SYNC 0
+#define GET_SECTOR_COUNT 1
+#define GET_SECTOR_SIZE 2
+#define GET_BLOCK_SIZE 3
+#define CTRL_TRIM 4
+
+#define CT_MMC 0x01
+#define CT_SD1 0x02
+#define CT_SD2 0x04
+#define CT_SDC (CT_SD1 | CT_SD2)
+#define CT_BLOCK 0x08
+
+#endif
diff --git a/dummy.ts b/dummy.ts
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/dummy.ts
@@ -0,0 +1 @@
+
diff --git a/ff.cpp b/ff.cpp
new file mode 100644
index 0000000..3bb63a4
--- /dev/null
+++ b/ff.cpp
@@ -0,0 +1,1783 @@
+#include "ff.h"
+#include "diskio.h"
+
+#define MAX_DIR 0x200000
+#define MAX_DIR_EX 0x10000000
+#define MAX_FAT12 0xFF5
+#define MAX_FAT16 0xFFF5
+#define MAX_FAT32 0x0FFFFFF5
+
+#define IsLower(c) ((c) >= 'a' && (c) <= 'z')
+#define IsDigit(c) ((c) >= '0' && (c) <= '9')
+
+#define FA_SEEKEND 0x20
+#define FA_MODIFIED 0x40
+
+#define AM_VOL 0x08
+#define AM_LFN 0x0F
+#define AM_MASK 0x3F
+
+#define NSFLAG 11
+
+#define NS_LAST 0x04
+
+#define NS_DOT 0x20
+
+#define NS_NONAME 0x80
+
+#define BS_JmpBoot 0
+
+#define BPB_BytsPerSec 11
+#define BPB_SecPerClus 13
+#define BPB_RsvdSecCnt 14
+#define BPB_NumFATs 16
+#define BPB_RootEntCnt 17
+#define BPB_TotSec16 19
+
+#define BPB_FATSz16 22
+
+#define BPB_TotSec32 32
+
+#define BS_FilSysType 54
+
+#define BS_55AA 510
+
+#define BPB_FATSz32 36
+
+#define BPB_FSVer32 42
+#define BPB_RootClus32 44
+#define BPB_FSInfo32 48
+
+#define BS_FilSysType32 82
+
+#define DIR_Name 0
+#define DIR_Attr 11
+
+#define DIR_CrtTime 14
+#define DIR_LstAccDate 18
+#define DIR_FstClusHI 20
+#define DIR_ModTime 22
+#define DIR_FstClusLO 26
+#define DIR_FileSize 28
+
+#define SZDIRE 32
+#define DDEM 0xE5
+#define RDDEM 0x05
+
+#define FSI_LeadSig 0
+#define FSI_StrucSig 484
+#define FSI_Free_Count 488
+#define FSI_Nxt_Free 492
+
+#define MBR_Table 446
+#define SZ_PTE 16
+
+#define PTE_StLba 8
+
+#define ABORT(fs, res) \
+ { \
+ fp->err = (BYTE)(res); \
+ LEAVE_FF(fs, res); \
+ }
+
+#define LEAVE_FF(fs, res) return res
+
+#define LD2PD(vol) (BYTE)(vol)
+#define LD2PT(vol) 0
+
+#define SS(fs) ((UINT)FF_MAX_SS)
+
+#define GET_FATTIME() ((DWORD)(FF_NORTC_YEAR - 1980) << 25 | (DWORD)FF_NORTC_MON << 21 | (DWORD)FF_NORTC_MDAY << 16)
+
+#define TBL_DC932 \
+ { \
+ 0x81, 0x9F, 0xE0, 0xFC, 0x40, 0x7E, 0x80, 0xFC, 0x00, 0x00 \
+ }
+
+#define MERGE_2STR(a, b) a##b
+#define MKCVTBL(hd, cp) MERGE_2STR(hd, cp)
+
+static FATFS *FatFs[FF_VOLUMES];
+static WORD Fsid;
+
+#define DEF_NAMBUF
+#define INIT_NAMBUF(fs)
+#define FREE_NAMBUF()
+
+static const BYTE DbcTbl[] = MKCVTBL(TBL_DC, FF_CODE_PAGE);
+
+static WORD ld_word(const BYTE *ptr)
+{
+ WORD rv;
+
+ rv = ptr[1];
+ rv = rv << 8 | ptr[0];
+ return rv;
+}
+
+static DWORD ld_dword(const BYTE *ptr)
+{
+ DWORD rv;
+
+ rv = ptr[3];
+ rv = rv << 8 | ptr[2];
+ rv = rv << 8 | ptr[1];
+ rv = rv << 8 | ptr[0];
+ return rv;
+}
+
+#if !FF_FS_READONLY
+static void st_word(BYTE *ptr, WORD val)
+{
+ *ptr++ = (BYTE)val;
+ val >>= 8;
+ *ptr++ = (BYTE)val;
+}
+
+static void st_dword(BYTE *ptr, DWORD val)
+{
+ *ptr++ = (BYTE)val;
+ val >>= 8;
+ *ptr++ = (BYTE)val;
+ val >>= 8;
+ *ptr++ = (BYTE)val;
+ val >>= 8;
+ *ptr++ = (BYTE)val;
+}
+
+#endif
+
+static void mem_cpy(void *dst, const void *src, UINT cnt)
+{
+ BYTE *d = (BYTE *)dst;
+ const BYTE *s = (const BYTE *)src;
+
+ if (cnt != 0)
+ {
+ do
+ {
+ *d++ = *s++;
+ } while (--cnt);
+ }
+}
+
+static void mem_set(void *dst, int val, UINT cnt)
+{
+ BYTE *d = (BYTE *)dst;
+
+ do
+ {
+ *d++ = (BYTE)val;
+ } while (--cnt);
+}
+
+static int mem_cmp(const void *dst, const void *src, UINT cnt)
+{
+ const BYTE *d = (const BYTE *)dst, *s = (const BYTE *)src;
+ int r = 0;
+
+ do
+ {
+ r = *d++ - *s++;
+ } while (--cnt && r == 0);
+
+ return r;
+}
+
+static int chk_chr(const char *str, int chr)
+{
+ while (*str && *str != chr)
+ str++;
+ return *str;
+}
+
+static int dbc_1st(BYTE c)
+{
+ if (c >= DbcTbl[0])
+ {
+ if (c <= DbcTbl[1])
+ return 1;
+ if (c >= DbcTbl[2] && c <= DbcTbl[3])
+ return 1;
+ }
+ return 0;
+}
+
+static int dbc_2nd(BYTE c)
+{
+ if (c >= DbcTbl[4])
+ {
+ if (c <= DbcTbl[5])
+ return 1;
+ if (c >= DbcTbl[6] && c <= DbcTbl[7])
+ return 1;
+ if (c >= DbcTbl[8] && c <= DbcTbl[9])
+ return 1;
+ }
+ return 0;
+}
+
+#if !FF_FS_READONLY
+static FRESULT sync_window(
+ FATFS *fs)
+{
+ FRESULT res = FR_OK;
+
+ if (fs->wflag)
+ {
+ if (disk_write(fs->pdrv, fs->win, fs->winsect, 1) == RES_OK)
+ {
+ fs->wflag = 0;
+ if (fs->winsect - fs->fatbase < fs->fsize)
+ {
+ if (fs->n_fats == 2)
+ disk_write(fs->pdrv, fs->win, fs->winsect + fs->fsize, 1);
+ }
+ }
+ else
+ {
+ res = FR_DISK_ERR;
+ }
+ }
+ return res;
+}
+#endif
+
+static FRESULT move_window(
+ FATFS *fs,
+ LBA_t sect)
+{
+ FRESULT res = FR_OK;
+
+ if (sect != fs->winsect)
+ {
+#if !FF_FS_READONLY
+ res = sync_window(fs);
+#endif
+ if (res == FR_OK)
+ {
+ if (disk_read(fs->pdrv, fs->win, sect, 1) != RES_OK)
+ {
+ sect = (LBA_t)0 - 1;
+ res = FR_DISK_ERR;
+ }
+ fs->winsect = sect;
+ }
+ }
+ return res;
+}
+
+#if !FF_FS_READONLY
+
+static FRESULT sync_fs(
+ FATFS *fs)
+{
+ FRESULT res;
+
+ res = sync_window(fs);
+ if (res == FR_OK)
+ {
+ if (fs->fs_type == FS_FAT32 && fs->fsi_flag == 1)
+ {
+
+ mem_set(fs->win, 0, sizeof fs->win);
+ st_word(fs->win + BS_55AA, 0xAA55);
+ st_dword(fs->win + FSI_LeadSig, 0x41615252);
+ st_dword(fs->win + FSI_StrucSig, 0x61417272);
+ st_dword(fs->win + FSI_Free_Count, fs->free_clst);
+ st_dword(fs->win + FSI_Nxt_Free, fs->last_clst);
+
+ fs->winsect = fs->volbase + 1;
+ disk_write(fs->pdrv, fs->win, fs->winsect, 1);
+ fs->fsi_flag = 0;
+ }
+
+ if (disk_ioctl(fs->pdrv, CTRL_SYNC, 0) != RES_OK)
+ res = FR_DISK_ERR;
+ }
+
+ return res;
+}
+
+#endif
+
+static LBA_t clst2sect(
+ FATFS *fs,
+ DWORD clst)
+{
+ clst -= 2;
+ if (clst >= fs->n_fatent - 2)
+ return 0;
+ return fs->database + (LBA_t)fs->csize * clst;
+}
+
+static DWORD get_fat(
+ FFOBJID *obj,
+ DWORD clst)
+{
+ UINT wc, bc;
+ DWORD val;
+ FATFS *fs = obj->fs;
+
+ if (clst < 2 || clst >= fs->n_fatent)
+ {
+ val = 1;
+ }
+ else
+ {
+ val = 0xFFFFFFFF;
+
+ switch (fs->fs_type)
+ {
+ case FS_FAT32:
+ if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 4))) != FR_OK)
+ break;
+ val = ld_dword(fs->win + clst * 4 % SS(fs)) & 0x0FFFFFFF;
+ break;
+ default:
+ val = 1;
+ }
+ }
+
+ return val;
+}
+
+#if !FF_FS_READONLY
+
+static FRESULT put_fat(
+ FATFS *fs,
+ DWORD clst,
+ DWORD val)
+{
+ UINT bc;
+ BYTE *p;
+ FRESULT res = FR_INT_ERR;
+
+ if (clst >= 2 && clst < fs->n_fatent)
+ {
+ switch (fs->fs_type)
+ {
+ case FS_FAT32:
+ res = move_window(fs, fs->fatbase + (clst / (SS(fs) / 4)));
+ if (res != FR_OK)
+ break;
+ if (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT)
+ {
+ val = (val & 0x0FFFFFFF) | (ld_dword(fs->win + clst * 4 % SS(fs)) & 0xF0000000);
+ }
+ st_dword(fs->win + clst * 4 % SS(fs), val);
+ fs->wflag = 1;
+ break;
+ }
+ }
+ return res;
+}
+
+#endif
+
+#if !FF_FS_READONLY
+
+static FRESULT remove_chain(
+ FFOBJID *obj,
+ DWORD clst,
+ DWORD pclst)
+{
+ FRESULT res = FR_OK;
+ DWORD nxt;
+ FATFS *fs = obj->fs;
+
+ if (clst < 2 || clst >= fs->n_fatent)
+ return FR_INT_ERR;
+
+ if (pclst != 0 && (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT || obj->stat != 2))
+ {
+ res = put_fat(fs, pclst, 0xFFFFFFFF);
+ if (res != FR_OK)
+ return res;
+ }
+
+ do
+ {
+ nxt = get_fat(obj, clst);
+ if (nxt == 0)
+ break;
+ if (nxt == 1)
+ return FR_INT_ERR;
+ if (nxt == 0xFFFFFFFF)
+ return FR_DISK_ERR;
+ if (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT)
+ {
+ res = put_fat(fs, clst, 0);
+ if (res != FR_OK)
+ return res;
+ }
+ if (fs->free_clst < fs->n_fatent - 2)
+ {
+ fs->free_clst++;
+ fs->fsi_flag |= 1;
+ }
+ clst = nxt;
+ } while (clst < fs->n_fatent);
+ return FR_OK;
+}
+
+static DWORD create_chain(
+ FFOBJID *obj,
+ DWORD clst)
+{
+ DWORD cs, ncl, scl;
+ FRESULT res;
+ FATFS *fs = obj->fs;
+
+ if (clst == 0)
+ {
+ scl = fs->last_clst;
+ if (scl == 0 || scl >= fs->n_fatent)
+ scl = 1;
+ }
+ else
+ {
+ cs = get_fat(obj, clst);
+ if (cs < 2)
+ return 1;
+ if (cs == 0xFFFFFFFF)
+ return cs;
+ if (cs < fs->n_fatent)
+ return cs;
+ scl = clst;
+ }
+ if (fs->free_clst == 0)
+ return 0;
+ {
+ ncl = 0;
+ if (scl == clst)
+ {
+ ncl = scl + 1;
+ if (ncl >= fs->n_fatent)
+ ncl = 2;
+ cs = get_fat(obj, ncl);
+ if (cs == 1 || cs == 0xFFFFFFFF)
+ return cs;
+ if (cs != 0)
+ {
+ cs = fs->last_clst;
+ if (cs >= 2 && cs < fs->n_fatent)
+ scl = cs;
+ ncl = 0;
+ }
+ }
+ if (ncl == 0)
+ {
+ ncl = scl;
+ for (;;)
+ {
+ ncl++;
+ if (ncl >= fs->n_fatent)
+ {
+ ncl = 2;
+ if (ncl > scl)
+ return 0;
+ }
+ cs = get_fat(obj, ncl);
+ if (cs == 0)
+ break;
+ if (cs == 1 || cs == 0xFFFFFFFF)
+ return cs;
+ if (ncl == scl)
+ return 0;
+ }
+ }
+ res = put_fat(fs, ncl, 0xFFFFFFFF);
+ if (res == FR_OK && clst != 0)
+ {
+ res = put_fat(fs, clst, ncl);
+ }
+ }
+
+ if (res == FR_OK)
+ {
+ fs->last_clst = ncl;
+ if (fs->free_clst <= fs->n_fatent - 2)
+ fs->free_clst--;
+ fs->fsi_flag |= 1;
+ }
+ else
+ {
+ ncl = (res == FR_DISK_ERR) ? 0xFFFFFFFF : 1;
+ }
+
+ return ncl;
+}
+
+#endif
+
+#if !FF_FS_READONLY
+static FRESULT dir_clear(
+ FATFS *fs,
+ DWORD clst)
+{
+ LBA_t sect;
+ UINT n, szb;
+ BYTE *ibuf;
+
+ if (sync_window(fs) != FR_OK)
+ return FR_DISK_ERR;
+ sect = clst2sect(fs, clst);
+ fs->winsect = sect;
+ mem_set(fs->win, 0, sizeof fs->win);
+ {
+ ibuf = fs->win;
+ szb = 1;
+ for (n = 0; n < fs->csize && disk_write(fs->pdrv, ibuf, sect + n, szb) == RES_OK; n += szb)
+ ;
+ }
+ return (n == fs->csize) ? FR_OK : FR_DISK_ERR;
+}
+#endif
+
+static FRESULT dir_sdi(
+ DIR *dp,
+ DWORD ofs)
+{
+ DWORD csz, clst;
+ FATFS *fs = dp->obj.fs;
+
+ if (ofs >= (DWORD)((FF_FS_EXFAT && fs->fs_type == FS_EXFAT) ? MAX_DIR_EX : MAX_DIR) || ofs % SZDIRE)
+ {
+ return FR_INT_ERR;
+ }
+ dp->dptr = ofs;
+ clst = dp->obj.sclust;
+ if (clst == 0 && fs->fs_type >= FS_FAT32)
+ {
+ clst = (DWORD)fs->dirbase;
+ if (FF_FS_EXFAT)
+ dp->obj.stat = 0;
+ }
+
+ if (clst == 0)
+ {
+ if (ofs / SZDIRE >= fs->n_rootdir)
+ return FR_INT_ERR;
+ dp->sect = fs->dirbase;
+ }
+ else
+ {
+ csz = (DWORD)fs->csize * SS(fs);
+ while (ofs >= csz)
+ {
+ clst = get_fat(&dp->obj, clst);
+ if (clst == 0xFFFFFFFF)
+ return FR_DISK_ERR;
+ if (clst < 2 || clst >= fs->n_fatent)
+ return FR_INT_ERR;
+ ofs -= csz;
+ }
+ dp->sect = clst2sect(fs, clst);
+ }
+ dp->clust = clst;
+ if (dp->sect == 0)
+ return FR_INT_ERR;
+ dp->sect += ofs / SS(fs);
+ dp->dir = fs->win + (ofs % SS(fs));
+
+ return FR_OK;
+}
+
+static FRESULT dir_next(
+ DIR *dp,
+ int stretch)
+{
+ DWORD ofs, clst;
+ FATFS *fs = dp->obj.fs;
+
+ ofs = dp->dptr + SZDIRE;
+ if (ofs >= (DWORD)((FF_FS_EXFAT && fs->fs_type == FS_EXFAT) ? MAX_DIR_EX : MAX_DIR))
+ dp->sect = 0;
+ if (dp->sect == 0)
+ return FR_NO_FILE;
+
+ if (ofs % SS(fs) == 0)
+ {
+ dp->sect++;
+
+ if (dp->clust == 0)
+ {
+ if (ofs / SZDIRE >= fs->n_rootdir)
+ {
+ dp->sect = 0;
+ return FR_NO_FILE;
+ }
+ }
+ else
+ {
+ if ((ofs / SS(fs) & (fs->csize - 1)) == 0)
+ {
+ clst = get_fat(&dp->obj, dp->clust);
+ if (clst <= 1)
+ return FR_INT_ERR;
+ if (clst == 0xFFFFFFFF)
+ return FR_DISK_ERR;
+ if (clst >= fs->n_fatent)
+ {
+ if (!stretch)
+ {
+ dp->sect = 0;
+ return FR_NO_FILE;
+ }
+ clst = create_chain(&dp->obj, dp->clust);
+ if (clst == 0)
+ return FR_DENIED;
+ if (clst == 1)
+ return FR_INT_ERR;
+ if (clst == 0xFFFFFFFF)
+ return FR_DISK_ERR;
+ if (dir_clear(fs, clst) != FR_OK)
+ return FR_DISK_ERR;
+ if (FF_FS_EXFAT)
+ dp->obj.stat |= 4;
+ }
+ dp->clust = clst;
+ dp->sect = clst2sect(fs, clst);
+ }
+ }
+ }
+ dp->dptr = ofs;
+ dp->dir = fs->win + ofs % SS(fs);
+
+ return FR_OK;
+}
+
+#if !FF_FS_READONLY
+
+static FRESULT dir_alloc(
+ DIR *dp,
+ UINT nent)
+{
+ FRESULT res;
+ UINT n;
+ FATFS *fs = dp->obj.fs;
+
+ res = dir_sdi(dp, 0);
+ if (res == FR_OK)
+ {
+ n = 0;
+ do
+ {
+ res = move_window(fs, dp->sect);
+ if (res != FR_OK)
+ break;
+ if (dp->dir[DIR_Name] == DDEM || dp->dir[DIR_Name] == 0)
+ {
+ if (++n == nent)
+ break;
+ }
+ else
+ {
+ n = 0;
+ }
+ res = dir_next(dp, 1);
+ } while (res == FR_OK);
+ }
+
+ if (res == FR_NO_FILE)
+ res = FR_DENIED;
+ return res;
+}
+
+#endif
+
+static DWORD ld_clust(
+ FATFS *fs,
+ const BYTE *dir)
+{
+ DWORD cl;
+
+ cl = ld_word(dir + DIR_FstClusLO);
+ if (fs->fs_type == FS_FAT32)
+ {
+ cl |= (DWORD)ld_word(dir + DIR_FstClusHI) << 16;
+ }
+
+ return cl;
+}
+
+#if !FF_FS_READONLY
+static void st_clust(
+ FATFS *fs,
+ BYTE *dir,
+ DWORD cl)
+{
+ st_word(dir + DIR_FstClusLO, (WORD)cl);
+ if (fs->fs_type == FS_FAT32)
+ {
+ st_word(dir + DIR_FstClusHI, (WORD)(cl >> 16));
+ }
+}
+#endif
+
+#if FF_FS_MINIMIZE <= 1 || FF_FS_RPATH >= 2 || FF_USE_LABEL || FF_FS_EXFAT
+
+#define DIR_READ_FILE(dp) dir_read(dp, 0)
+#define DIR_READ_LABEL(dp) dir_read(dp, 1)
+
+static FRESULT dir_read(
+ DIR *dp,
+ int vol)
+{
+ FRESULT res = FR_NO_FILE;
+ FATFS *fs = dp->obj.fs;
+ BYTE attr, b;
+
+ while (dp->sect)
+ {
+ res = move_window(fs, dp->sect);
+ if (res != FR_OK)
+ break;
+ b = dp->dir[DIR_Name];
+ if (b == 0)
+ {
+ res = FR_NO_FILE;
+ break;
+ }
+ {
+ dp->obj.attr = attr = dp->dir[DIR_Attr] & AM_MASK;
+ if (b != DDEM && b != '.' && attr != AM_LFN && (int)((attr & ~AM_ARC) == AM_VOL) == vol)
+ {
+ break;
+ }
+ }
+ res = dir_next(dp, 0);
+ if (res != FR_OK)
+ break;
+ }
+
+ if (res != FR_OK)
+ dp->sect = 0;
+ return res;
+}
+
+#endif
+
+static FRESULT dir_find(
+ DIR *dp)
+{
+ FRESULT res;
+ FATFS *fs = dp->obj.fs;
+ BYTE c;
+
+ res = dir_sdi(dp, 0);
+ if (res != FR_OK)
+ return res;
+ do
+ {
+ res = move_window(fs, dp->sect);
+ if (res != FR_OK)
+ break;
+ c = dp->dir[DIR_Name];
+ if (c == 0)
+ {
+ res = FR_NO_FILE;
+ break;
+ }
+ dp->obj.attr = dp->dir[DIR_Attr] & AM_MASK;
+ if (!(dp->dir[DIR_Attr] & AM_VOL) && !mem_cmp(dp->dir, dp->fn, 11))
+ break;
+ res = dir_next(dp, 0);
+ } while (res == FR_OK);
+
+ return res;
+}
+
+#if !FF_FS_READONLY
+
+static FRESULT dir_register(
+ DIR *dp)
+{
+ FRESULT res;
+ FATFS *fs = dp->obj.fs;
+
+ res = dir_alloc(dp, 1);
+
+ if (res == FR_OK)
+ {
+ res = move_window(fs, dp->sect);
+ if (res == FR_OK)
+ {
+ mem_set(dp->dir, 0, SZDIRE);
+ mem_cpy(dp->dir + DIR_Name, dp->fn, 11);
+ fs->wflag = 1;
+ }
+ }
+
+ return res;
+}
+
+#endif
+
+#if !FF_FS_READONLY && FF_FS_MINIMIZE == 0
+
+static FRESULT dir_remove(
+ DIR *dp)
+{
+ FRESULT res;
+ FATFS *fs = dp->obj.fs;
+
+ res = move_window(fs, dp->sect);
+ if (res == FR_OK)
+ {
+ dp->dir[DIR_Name] = DDEM;
+ fs->wflag = 1;
+ }
+
+ return res;
+}
+
+#endif
+
+#if FF_FS_MINIMIZE <= 1 || FF_FS_RPATH >= 2
+
+static void get_fileinfo(
+ DIR *dp,
+ FILINFO *fno)
+{
+ UINT si, di;
+ TCHAR c;
+
+ fno->fname[0] = 0;
+ if (dp->sect == 0)
+ return;
+
+ si = di = 0;
+ while (si < 11)
+ {
+ c = (TCHAR)dp->dir[si++];
+ if (c == ' ')
+ continue;
+ if (c == RDDEM)
+ c = DDEM;
+ if (si == 9)
+ fno->fname[di++] = '.';
+ fno->fname[di++] = c;
+ }
+ fno->fname[di] = 0;
+
+ fno->fattrib = dp->dir[DIR_Attr];
+ fno->fsize = ld_dword(dp->dir + DIR_FileSize);
+ fno->ftime = ld_word(dp->dir + DIR_ModTime + 0);
+ fno->fdate = ld_word(dp->dir + DIR_ModTime + 2);
+}
+
+#endif
+
+static FRESULT create_name(
+ DIR *dp,
+ const TCHAR **path)
+{
+ BYTE c, d, *sfn;
+ UINT ni, si, i;
+ const char *p;
+
+ p = *path;
+ sfn = dp->fn;
+ mem_set(sfn, ' ', 11);
+ si = i = 0;
+ ni = 8;
+ for (;;)
+ {
+ c = (BYTE)p[si++];
+ if (c <= ' ')
+ break;
+ if (c == '/' || c == '\\')
+ {
+ while (p[si] == '/' || p[si] == '\\')
+ si++;
+ break;
+ }
+ if (c == '.' || i >= ni)
+ {
+ if (ni == 11 || c != '.')
+ return FR_INVALID_NAME;
+ i = 8;
+ ni = 11;
+ continue;
+ }
+ if (dbc_1st(c))
+ {
+ d = (BYTE)p[si++];
+ if (!dbc_2nd(d) || i >= ni - 1)
+ return FR_INVALID_NAME;
+ sfn[i++] = c;
+ sfn[i++] = d;
+ }
+ else
+ {
+ if (chk_chr("\"*+,:;<=>\?[]|\x7F", c))
+ return FR_INVALID_NAME;
+ if (IsLower(c))
+ c -= 0x20;
+ sfn[i++] = c;
+ }
+ }
+ *path = p + si;
+ if (i == 0)
+ return FR_INVALID_NAME;
+
+ if (sfn[0] == DDEM)
+ sfn[0] = RDDEM;
+ sfn[NSFLAG] = (c <= ' ') ? NS_LAST : 0;
+
+ return FR_OK;
+}
+
+static FRESULT follow_path(
+ DIR *dp,
+ const TCHAR *path)
+{
+ FRESULT res;
+ BYTE ns;
+ FATFS *fs = dp->obj.fs;
+ {
+ while (*path == '/' || *path == '\\')
+ path++;
+ dp->obj.sclust = 0;
+ }
+
+ if ((UINT)*path < ' ')
+ {
+ dp->fn[NSFLAG] = NS_NONAME;
+ res = dir_sdi(dp, 0);
+ }
+ else
+ {
+ for (;;)
+ {
+ res = create_name(dp, &path);
+ if (res != FR_OK)
+ break;
+ res = dir_find(dp);
+ ns = dp->fn[NSFLAG];
+ if (res != FR_OK)
+ {
+ if (res == FR_NO_FILE)
+ {
+ if (FF_FS_RPATH && (ns & NS_DOT))
+ {
+ if (!(ns & NS_LAST))
+ continue;
+ dp->fn[NSFLAG] = NS_NONAME;
+ res = FR_OK;
+ }
+ else
+ {
+ if (!(ns & NS_LAST))
+ res = FR_NO_PATH;
+ }
+ }
+ break;
+ }
+ if (ns & NS_LAST)
+ break;
+
+ if (!(dp->obj.attr & AM_DIR))
+ {
+ res = FR_NO_PATH;
+ break;
+ }
+ {
+ dp->obj.sclust = ld_clust(fs, fs->win + dp->dptr % SS(fs));
+ }
+ }
+ }
+
+ return res;
+}
+
+static int get_ldnumber(
+ const TCHAR **path)
+{
+ const TCHAR *tp, *tt;
+ TCHAR tc;
+ int i, vol = -1;
+
+ tt = tp = *path;
+ if (!tp)
+ return vol;
+ do
+ tc = *tt++;
+ while ((UINT)tc >= (FF_USE_LFN ? ' ' : '!') && tc != ':');
+
+ if (tc == ':')
+ {
+ i = FF_VOLUMES;
+ if (IsDigit(*tp) && tp + 2 == tt)
+ {
+ i = (int)*tp - '0';
+ }
+ if (i < FF_VOLUMES)
+ {
+ vol = i;
+ *path = tt;
+ }
+ return vol;
+ }
+ vol = 0;
+ return vol;
+}
+
+static UINT check_fs(
+ FATFS *fs,
+ LBA_t sect)
+{
+ fs->wflag = 0;
+ fs->winsect = (LBA_t)0 - 1;
+ if (move_window(fs, sect) != FR_OK)
+ return 4;
+
+ if (ld_word(fs->win + BS_55AA) != 0xAA55)
+ return 3;
+
+ if (FF_FS_EXFAT && !mem_cmp(fs->win + BS_JmpBoot, "\xEB\x76\x90"
+ "EXFAT ",
+ 11))
+ return 1;
+
+ if (fs->win[BS_JmpBoot] == 0xE9 || fs->win[BS_JmpBoot] == 0xEB || fs->win[BS_JmpBoot] == 0xE8)
+ {
+ if (!mem_cmp(fs->win + BS_FilSysType, "FAT", 3))
+ return 0;
+ if (!mem_cmp(fs->win + BS_FilSysType32, "FAT32", 5))
+ return 0;
+ }
+ return 2;
+}
+
+static UINT find_volume(
+ FATFS *fs,
+ UINT part)
+{
+ UINT fmt, i;
+ DWORD mbr_pt[4];
+
+ fmt = check_fs(fs, 0);
+ if (fmt != 2 && (fmt >= 3 || part == 0))
+ return fmt;
+
+ if (FF_MULTI_PARTITION && part > 4)
+ return 3;
+ for (i = 0; i < 4; i++)
+ {
+ mbr_pt[i] = ld_dword(fs->win + MBR_Table + i * SZ_PTE + PTE_StLba);
+ }
+ i = part ? part - 1 : 0;
+ do
+ {
+ fmt = mbr_pt[i] ? check_fs(fs, mbr_pt[i]) : 3;
+ } while (part == 0 && fmt >= 2 && ++i < 4);
+ return fmt;
+}
+
+static FRESULT mount_volume(
+ const TCHAR **path,
+ FATFS **rfs,
+ BYTE mode)
+{
+ int vol;
+ DSTATUS stat;
+ LBA_t bsect;
+ DWORD tsect, sysect, fasize, nclst, szbfat;
+ WORD nrsv;
+ FATFS *fs;
+ UINT fmt;
+
+ *rfs = 0;
+ vol = get_ldnumber(path);
+ if (vol < 0)
+ return FR_INVALID_DRIVE;
+
+ fs = FatFs[vol];
+ if (!fs)
+ return FR_NOT_ENABLED;
+ *rfs = fs;
+
+ mode &= (BYTE)~FA_READ;
+ if (fs->fs_type != 0)
+ {
+ stat = disk_status(fs->pdrv);
+ if (!(stat & STA_NOINIT))
+ {
+ if (!FF_FS_READONLY && mode && (stat & STA_PROTECT))
+ {
+ return FR_WRITE_PROTECTED;
+ }
+ return FR_OK;
+ }
+ }
+
+ fs->fs_type = 0;
+ fs->pdrv = LD2PD(vol);
+ stat = disk_initialize(fs->pdrv);
+ if (stat & STA_NOINIT)
+ {
+ return FR_NOT_READY;
+ }
+ if (!FF_FS_READONLY && mode && (stat & STA_PROTECT))
+ {
+ return FR_WRITE_PROTECTED;
+ }
+
+ fmt = find_volume(fs, LD2PT(vol));
+ if (fmt == 4)
+ return FR_DISK_ERR;
+ if (fmt >= 2)
+ return FR_NO_FILESYSTEM;
+ bsect = fs->winsect;
+ {
+ if (ld_word(fs->win + BPB_BytsPerSec) != SS(fs))
+ return FR_NO_FILESYSTEM;
+
+ fasize = ld_word(fs->win + BPB_FATSz16);
+ if (fasize == 0)
+ fasize = ld_dword(fs->win + BPB_FATSz32);
+ fs->fsize = fasize;
+
+ fs->n_fats = fs->win[BPB_NumFATs];
+ if (fs->n_fats != 1 && fs->n_fats != 2)
+ return FR_NO_FILESYSTEM;
+ fasize *= fs->n_fats;
+
+ fs->csize = fs->win[BPB_SecPerClus];
+ if (fs->csize == 0 || (fs->csize & (fs->csize - 1)))
+ return FR_NO_FILESYSTEM;
+
+ fs->n_rootdir = ld_word(fs->win + BPB_RootEntCnt);
+ if (fs->n_rootdir % (SS(fs) / SZDIRE))
+ return FR_NO_FILESYSTEM;
+
+ tsect = ld_word(fs->win + BPB_TotSec16);
+ if (tsect == 0)
+ tsect = ld_dword(fs->win + BPB_TotSec32);
+
+ nrsv = ld_word(fs->win + BPB_RsvdSecCnt);
+ if (nrsv == 0)
+ return FR_NO_FILESYSTEM;
+
+ sysect = nrsv + fasize + fs->n_rootdir / (SS(fs) / SZDIRE);
+ if (tsect < sysect)
+ return FR_NO_FILESYSTEM;
+ nclst = (tsect - sysect) / fs->csize;
+ if (nclst == 0)
+ return FR_NO_FILESYSTEM;
+ fmt = 0;
+ if (nclst <= MAX_FAT32)
+ fmt = FS_FAT32;
+ if (nclst <= MAX_FAT16)
+ fmt = FS_FAT16;
+ if (nclst <= MAX_FAT12)
+ fmt = FS_FAT12;
+ if (fmt == 0)
+ return FR_NO_FILESYSTEM;
+
+ fs->n_fatent = nclst + 2;
+ fs->volbase = bsect;
+ fs->fatbase = bsect + nrsv;
+ fs->database = bsect + sysect;
+ if (fmt == FS_FAT32)
+ {
+ if (ld_word(fs->win + BPB_FSVer32) != 0)
+ return FR_NO_FILESYSTEM;
+ if (fs->n_rootdir != 0)
+ return FR_NO_FILESYSTEM;
+ fs->dirbase = ld_dword(fs->win + BPB_RootClus32);
+ szbfat = fs->n_fatent * 4;
+ }
+ else
+ {
+ if (fs->n_rootdir == 0)
+ return FR_NO_FILESYSTEM;
+ fs->dirbase = fs->fatbase + fasize;
+ szbfat = (fmt == FS_FAT16) ? fs->n_fatent * 2 : fs->n_fatent * 3 / 2 + (fs->n_fatent & 1);
+ }
+ if (fs->fsize < (szbfat + (SS(fs) - 1)) / SS(fs))
+ return FR_NO_FILESYSTEM;
+
+#if !FF_FS_READONLY
+
+ fs->last_clst = fs->free_clst = 0xFFFFFFFF;
+ fs->fsi_flag = 0x80;
+#if (FF_FS_NOFSINFO & 3) != 3
+ if (fmt == FS_FAT32 && ld_word(fs->win + BPB_FSInfo32) == 1 && move_window(fs, bsect + 1) == FR_OK)
+ {
+ fs->fsi_flag = 0;
+ if (ld_word(fs->win + BS_55AA) == 0xAA55 && ld_dword(fs->win + FSI_LeadSig) == 0x41615252 && ld_dword(fs->win + FSI_StrucSig) == 0x61417272)
+ {
+#if (FF_FS_NOFSINFO & 1) == 0
+ fs->free_clst = ld_dword(fs->win + FSI_Free_Count);
+#endif
+#if (FF_FS_NOFSINFO & 2) == 0
+ fs->last_clst = ld_dword(fs->win + FSI_Nxt_Free);
+#endif
+ }
+ }
+#endif
+#endif
+ }
+
+ fs->fs_type = (BYTE)fmt;
+ fs->id = ++Fsid;
+ return FR_OK;
+}
+
+static FRESULT validate(
+ FFOBJID *obj,
+ FATFS **rfs)
+{
+ FRESULT res = FR_INVALID_OBJECT;
+
+ if (obj && obj->fs && obj->fs->fs_type && obj->id == obj->fs->id)
+ {
+ if (!(disk_status(obj->fs->pdrv) & STA_NOINIT))
+ {
+ res = FR_OK;
+ }
+ }
+ *rfs = (res == FR_OK) ? obj->fs : 0;
+ return res;
+}
+
+FRESULT f_mount(
+ FATFS *fs,
+ const TCHAR *path,
+ BYTE opt)
+{
+ FATFS *cfs;
+ int vol;
+ FRESULT res;
+ const TCHAR *rp = path;
+
+ vol = get_ldnumber(&rp);
+ if (vol < 0)
+ return FR_INVALID_DRIVE;
+ cfs = FatFs[vol];
+
+ if (cfs)
+ {
+ cfs->fs_type = 0;
+ }
+
+ if (fs)
+ {
+ fs->fs_type = 0;
+ }
+ FatFs[vol] = fs;
+
+ if (opt == 0)
+ return FR_OK;
+
+ res = mount_volume(&path, &fs, 0);
+ LEAVE_FF(fs, res);
+}
+
+FRESULT f_open(
+ FIL *fp,
+ const TCHAR *path,
+ BYTE mode)
+{
+ FRESULT res;
+ DIR dj;
+ FATFS *fs;
+#if !FF_FS_READONLY
+ DWORD cl, bcs, clst;
+ LBA_t sc;
+ FSIZE_t ofs;
+#endif
+ DEF_NAMBUF
+
+ if (!fp)
+ return FR_INVALID_OBJECT;
+
+ mode &= FF_FS_READONLY ? FA_READ : FA_READ | FA_WRITE | FA_CREATE_ALWAYS | FA_CREATE_NEW | FA_OPEN_ALWAYS | FA_OPEN_APPEND;
+ res = mount_volume(&path, &fs, mode);
+ if (res == FR_OK)
+ {
+ dj.obj.fs = fs;
+ INIT_NAMBUF(fs);
+ res = follow_path(&dj, path);
+ if (res == FR_OK)
+ {
+ if (dj.fn[NSFLAG] & NS_NONAME)
+ {
+ res = FR_INVALID_NAME;
+ }
+ }
+
+ if (mode & (FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW))
+ {
+ if (res != FR_OK)
+ {
+ if (res == FR_NO_FILE)
+ {
+ res = dir_register(&dj);
+ }
+ mode |= FA_CREATE_ALWAYS;
+ }
+ else
+ {
+ if (dj.obj.attr & (AM_RDO | AM_DIR))
+ {
+ res = FR_DENIED;
+ }
+ else
+ {
+ if (mode & FA_CREATE_NEW)
+ res = FR_EXIST;
+ }
+ }
+ if (res == FR_OK && (mode & FA_CREATE_ALWAYS))
+ {
+ {
+
+ cl = ld_clust(fs, dj.dir);
+ st_dword(dj.dir + DIR_CrtTime, GET_FATTIME());
+ dj.dir[DIR_Attr] = AM_ARC;
+ st_clust(fs, dj.dir, 0);
+ st_dword(dj.dir + DIR_FileSize, 0);
+ fs->wflag = 1;
+ if (cl != 0)
+ {
+ sc = fs->winsect;
+ res = remove_chain(&dj.obj, cl, 0);
+ if (res == FR_OK)
+ {
+ res = move_window(fs, sc);
+ fs->last_clst = cl - 1;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ if (res == FR_OK)
+ {
+ if (dj.obj.attr & AM_DIR)
+ {
+ res = FR_NO_FILE;
+ }
+ else
+ {
+ if ((mode & FA_WRITE) && (dj.obj.attr & AM_RDO))
+ {
+ res = FR_DENIED;
+ }
+ }
+ }
+ }
+ if (res == FR_OK)
+ {
+ if (mode & FA_CREATE_ALWAYS)
+ mode |= FA_MODIFIED;
+ fp->dir_sect = fs->winsect;
+ fp->dir_ptr = dj.dir;
+ }
+
+ if (res == FR_OK)
+ {
+ {
+ fp->obj.sclust = ld_clust(fs, dj.dir);
+ fp->obj.objsize = ld_dword(dj.dir + DIR_FileSize);
+ }
+ fp->obj.fs = fs;
+ fp->obj.id = fs->id;
+ fp->flag = mode;
+ fp->err = 0;
+ fp->sect = 0;
+ fp->fptr = 0;
+#if !FF_FS_READONLY
+ if ((mode & FA_SEEKEND) && fp->obj.objsize > 0)
+ {
+ fp->fptr = fp->obj.objsize;
+ bcs = (DWORD)fs->csize * SS(fs);
+ clst = fp->obj.sclust;
+ for (ofs = fp->obj.objsize; res == FR_OK && ofs > bcs; ofs -= bcs)
+ {
+ clst = get_fat(&fp->obj, clst);
+ if (clst <= 1)
+ res = FR_INT_ERR;
+ if (clst == 0xFFFFFFFF)
+ res = FR_DISK_ERR;
+ }
+ fp->clust = clst;
+ if (res == FR_OK && ofs % SS(fs))
+ {
+ sc = clst2sect(fs, clst);
+ if (sc == 0)
+ {
+ res = FR_INT_ERR;
+ }
+ else
+ {
+ fp->sect = sc + (DWORD)(ofs / SS(fs));
+ }
+ }
+ }
+#endif
+ }
+
+ FREE_NAMBUF();
+ }
+
+ if (res != FR_OK)
+ fp->obj.fs = 0;
+
+ LEAVE_FF(fs, res);
+}
+
+FRESULT f_read(
+ FIL *fp,
+ void *buff,
+ UINT btr,
+ UINT *br)
+{
+ FRESULT res;
+ FATFS *fs;
+ DWORD clst;
+ LBA_t sect;
+ FSIZE_t remain;
+ UINT rcnt, cc, csect;
+ BYTE *rbuff = (BYTE *)buff;
+
+ *br = 0;
+ res = validate(&fp->obj, &fs);
+ if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK)
+ LEAVE_FF(fs, res);
+ if (!(fp->flag & FA_READ))
+ LEAVE_FF(fs, FR_DENIED);
+ remain = fp->obj.objsize - fp->fptr;
+ if (btr > remain)
+ btr = (UINT)remain;
+
+ for (; btr;
+ btr -= rcnt, *br += rcnt, rbuff += rcnt, fp->fptr += rcnt)
+ {
+ if (fp->fptr % SS(fs) == 0)
+ {
+ csect = (UINT)(fp->fptr / SS(fs) & (fs->csize - 1));
+ if (csect == 0)
+ {
+ if (fp->fptr == 0)
+ {
+ clst = fp->obj.sclust;
+ }
+ else
+ {
+ {
+ clst = get_fat(&fp->obj, fp->clust);
+ }
+ }
+ if (clst < 2)
+ ABORT(fs, FR_INT_ERR);
+ if (clst == 0xFFFFFFFF)
+ ABORT(fs, FR_DISK_ERR);
+ fp->clust = clst;
+ }
+ sect = clst2sect(fs, fp->clust);
+ if (sect == 0)
+ ABORT(fs, FR_INT_ERR);
+ sect += csect;
+ cc = btr / SS(fs);
+ if (cc > 0)
+ {
+ if (csect + cc > fs->csize)
+ {
+ cc = fs->csize - csect;
+ }
+ if (disk_read(fs->pdrv, rbuff, sect, cc) != RES_OK)
+ ABORT(fs, FR_DISK_ERR);
+#if !FF_FS_READONLY && FF_FS_MINIMIZE <= 2
+ if (fs->wflag && fs->winsect - sect < cc)
+ {
+ mem_cpy(rbuff + ((fs->winsect - sect) * SS(fs)), fs->win, SS(fs));
+ }
+#endif
+ rcnt = SS(fs) * cc;
+ continue;
+ }
+ fp->sect = sect;
+ }
+ rcnt = SS(fs) - (UINT)fp->fptr % SS(fs);
+ if (rcnt > btr)
+ rcnt = btr;
+ if (move_window(fs, fp->sect) != FR_OK)
+ ABORT(fs, FR_DISK_ERR);
+ mem_cpy(rbuff, fs->win + fp->fptr % SS(fs), rcnt);
+ }
+
+ LEAVE_FF(fs, FR_OK);
+}
+
+#if !FF_FS_READONLY
+
+FRESULT f_write(
+ FIL *fp,
+ const void *buff,
+ UINT btw,
+ UINT *bw)
+{
+ FRESULT res;
+ FATFS *fs;
+ DWORD clst;
+ LBA_t sect;
+ UINT wcnt, cc, csect;
+ const BYTE *wbuff = (const BYTE *)buff;
+
+ *bw = 0;
+ res = validate(&fp->obj, &fs);
+ if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK)
+ LEAVE_FF(fs, res);
+ if (!(fp->flag & FA_WRITE))
+ LEAVE_FF(fs, FR_DENIED);
+
+ if ((!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) && (DWORD)(fp->fptr + btw) < (DWORD)fp->fptr)
+ {
+ btw = (UINT)(0xFFFFFFFF - (DWORD)fp->fptr);
+ }
+
+ for (; btw;
+ btw -= wcnt, *bw += wcnt, wbuff += wcnt, fp->fptr += wcnt, fp->obj.objsize = (fp->fptr > fp->obj.objsize) ? fp->fptr : fp->obj.objsize)
+ {
+ if (fp->fptr % SS(fs) == 0)
+ {
+ csect = (UINT)(fp->fptr / SS(fs)) & (fs->csize - 1);
+ if (csect == 0)
+ {
+ if (fp->fptr == 0)
+ {
+ clst = fp->obj.sclust;
+ if (clst == 0)
+ {
+ clst = create_chain(&fp->obj, 0);
+ }
+ }
+ else
+ {
+ {
+ clst = create_chain(&fp->obj, fp->clust);
+ }
+ }
+ if (clst == 0)
+ break;
+ if (clst == 1)
+ ABORT(fs, FR_INT_ERR);
+ if (clst == 0xFFFFFFFF)
+ ABORT(fs, FR_DISK_ERR);
+ fp->clust = clst;
+ if (fp->obj.sclust == 0)
+ fp->obj.sclust = clst;
+ }
+ if (fs->winsect == fp->sect && sync_window(fs) != FR_OK)
+ ABORT(fs, FR_DISK_ERR);
+ sect = clst2sect(fs, fp->clust);
+ if (sect == 0)
+ ABORT(fs, FR_INT_ERR);
+ sect += csect;
+ cc = btw / SS(fs);
+ if (cc > 0)
+ {
+ if (csect + cc > fs->csize)
+ {
+ cc = fs->csize - csect;
+ }
+ if (disk_write(fs->pdrv, wbuff, sect, cc) != RES_OK)
+ ABORT(fs, FR_DISK_ERR);
+#if FF_FS_MINIMIZE <= 2
+ if (fs->winsect - sect < cc)
+ {
+ mem_cpy(fs->win, wbuff + ((fs->winsect - sect) * SS(fs)), SS(fs));
+ fs->wflag = 0;
+ }
+#endif
+ wcnt = SS(fs) * cc;
+ continue;
+ }
+ if (fp->fptr >= fp->obj.objsize)
+ {
+ if (sync_window(fs) != FR_OK)
+ ABORT(fs, FR_DISK_ERR);
+ fs->winsect = sect;
+ }
+ fp->sect = sect;
+ }
+ wcnt = SS(fs) - (UINT)fp->fptr % SS(fs);
+ if (wcnt > btw)
+ wcnt = btw;
+ if (move_window(fs, fp->sect) != FR_OK)
+ ABORT(fs, FR_DISK_ERR);
+ mem_cpy(fs->win + fp->fptr % SS(fs), wbuff, wcnt);
+ fs->wflag = 1;
+ }
+
+ fp->flag |= FA_MODIFIED;
+
+ LEAVE_FF(fs, FR_OK);
+}
+
+FRESULT f_sync(
+ FIL *fp)
+{
+ FRESULT res;
+ FATFS *fs;
+ DWORD tm;
+ BYTE *dir;
+
+ res = validate(&fp->obj, &fs);
+ if (res == FR_OK)
+ {
+ if (fp->flag & FA_MODIFIED)
+ {
+
+ tm = GET_FATTIME();
+ {
+ res = move_window(fs, fp->dir_sect);
+ if (res == FR_OK)
+ {
+ dir = fp->dir_ptr;
+ dir[DIR_Attr] |= AM_ARC;
+ st_clust(fp->obj.fs, dir, fp->obj.sclust);
+ st_dword(dir + DIR_FileSize, (DWORD)fp->obj.objsize);
+ st_dword(dir + DIR_ModTime, tm);
+ st_word(dir + DIR_LstAccDate, 0);
+ fs->wflag = 1;
+ res = sync_fs(fs);
+ fp->flag &= (BYTE)~FA_MODIFIED;
+ }
+ }
+ }
+ }
+
+ LEAVE_FF(fs, res);
+}
+
+#endif
+
+FRESULT f_close(
+ FIL *fp)
+{
+ FRESULT res;
+ FATFS *fs;
+
+#if !FF_FS_READONLY
+ res = f_sync(fp);
+ if (res == FR_OK)
+#endif
+ {
+ res = validate(&fp->obj, &fs);
+ if (res == FR_OK)
+ {
+ fp->obj.fs = 0;
+ }
+ }
+ return res;
+}
+
+FRESULT f_stat(
+ const TCHAR *path,
+ FILINFO *fno)
+{
+ FRESULT res;
+ DIR dj;
+ DEF_NAMBUF
+
+ res = mount_volume(&path, &dj.obj.fs, 0);
+ if (res == FR_OK)
+ {
+ INIT_NAMBUF(dj.obj.fs);
+ res = follow_path(&dj, path);
+ if (res == FR_OK)
+ {
+ if (dj.fn[NSFLAG] & NS_NONAME)
+ {
+ res = FR_INVALID_NAME;
+ }
+ else
+ {
+ if (fno)
+ get_fileinfo(&dj, fno);
+ }
+ }
+ FREE_NAMBUF();
+ }
+
+ LEAVE_FF(dj.obj.fs, res);
+}
+
+FRESULT f_unlink(
+ const TCHAR *path)
+{
+ FRESULT res;
+ DIR dj, sdj;
+ DWORD dclst = 0;
+ FATFS *fs;
+ DEF_NAMBUF
+
+ res = mount_volume(&path, &fs, FA_WRITE);
+ if (res == FR_OK)
+ {
+ dj.obj.fs = fs;
+ INIT_NAMBUF(fs);
+ res = follow_path(&dj, path);
+ if (FF_FS_RPATH && res == FR_OK && (dj.fn[NSFLAG] & NS_DOT))
+ {
+ res = FR_INVALID_NAME;
+ }
+ if (res == FR_OK)
+ {
+ if (dj.fn[NSFLAG] & NS_NONAME)
+ {
+ res = FR_INVALID_NAME;
+ }
+ else
+ {
+ if (dj.obj.attr & AM_RDO)
+ {
+ res = FR_DENIED;
+ }
+ }
+ if (res == FR_OK)
+ {
+ {
+ dclst = ld_clust(fs, dj.dir);
+ }
+ if (dj.obj.attr & AM_DIR)
+ {
+ {
+ sdj.obj.fs = fs;
+ sdj.obj.sclust = dclst;
+ res = dir_sdi(&sdj, 0);
+ if (res == FR_OK)
+ {
+ res = DIR_READ_FILE(&sdj);
+ if (res == FR_OK)
+ res = FR_DENIED;
+ if (res == FR_NO_FILE)
+ res = FR_OK;
+ }
+ }
+ }
+ }
+ if (res == FR_OK)
+ {
+ res = dir_remove(&dj);
+ if (res == FR_OK && dclst != 0)
+ {
+ res = remove_chain(&dj.obj, dclst, 0);
+ }
+ if (res == FR_OK)
+ res = sync_fs(fs);
+ }
+ }
+ FREE_NAMBUF();
+ }
+
+ LEAVE_FF(fs, res);
+}
\ No newline at end of file
diff --git a/ff.h b/ff.h
new file mode 100644
index 0000000..a5483ed
--- /dev/null
+++ b/ff.h
@@ -0,0 +1,173 @@
+#ifndef FF_DEFINED
+#define FF_DEFINED 86606
+
+#include "ffconf.h"
+
+#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__cplusplus)
+#define FF_INTDEF 2
+#include
+typedef unsigned int UINT;
+typedef unsigned char BYTE;
+typedef uint16_t WORD;
+typedef uint32_t DWORD;
+typedef uint64_t QWORD;
+typedef WORD WCHAR;
+#else
+#define FF_INTDEF 1
+typedef unsigned int UINT;
+typedef unsigned char BYTE;
+typedef unsigned short WORD;
+typedef unsigned long DWORD;
+typedef WORD WCHAR;
+#endif
+
+#ifndef _INC_TCHAR
+#define _INC_TCHAR
+
+typedef char TCHAR;
+#define _T(x) x
+#define _TEXT(x) x
+
+#endif
+typedef DWORD FSIZE_t;
+typedef DWORD LBA_t;
+
+typedef struct
+{
+ BYTE fs_type;
+ BYTE pdrv;
+ BYTE n_fats;
+ BYTE wflag;
+ BYTE fsi_flag;
+ WORD id;
+ WORD n_rootdir;
+ WORD csize;
+#if !FF_FS_READONLY
+ DWORD last_clst;
+ DWORD free_clst;
+#endif
+ DWORD n_fatent;
+ DWORD fsize;
+ LBA_t volbase;
+ LBA_t fatbase;
+ LBA_t dirbase;
+ LBA_t database;
+ LBA_t winsect;
+ BYTE win[FF_MAX_SS];
+} FATFS;
+
+typedef struct
+{
+ FATFS *fs;
+ WORD id;
+ BYTE attr;
+ BYTE stat;
+ DWORD sclust;
+ FSIZE_t objsize;
+} FFOBJID;
+
+typedef struct
+{
+ FFOBJID obj;
+ BYTE flag;
+ BYTE err;
+ FSIZE_t fptr;
+ DWORD clust;
+ LBA_t sect;
+#if !FF_FS_READONLY
+ LBA_t dir_sect;
+ BYTE *dir_ptr;
+#endif
+} FIL;
+
+typedef struct
+{
+ FFOBJID obj;
+ DWORD dptr;
+ DWORD clust;
+ LBA_t sect;
+ BYTE *dir;
+ BYTE fn[12];
+} DIR;
+
+typedef struct
+{
+ FSIZE_t fsize;
+ WORD fdate;
+ WORD ftime;
+ BYTE fattrib;
+ TCHAR fname[12 + 1];
+} FILINFO;
+
+typedef struct
+{
+ BYTE fmt;
+ BYTE n_fat;
+ UINT align;
+ UINT n_root;
+ DWORD au_size;
+} MKFS_PARM;
+
+typedef enum
+{
+ FR_OK = 0,
+ FR_DISK_ERR,
+ FR_INT_ERR,
+ FR_NOT_READY,
+ FR_NO_FILE,
+ FR_NO_PATH,
+ FR_INVALID_NAME,
+ FR_DENIED,
+ FR_EXIST,
+ FR_INVALID_OBJECT,
+ FR_WRITE_PROTECTED,
+ FR_INVALID_DRIVE,
+ FR_NOT_ENABLED,
+ FR_NO_FILESYSTEM,
+ FR_MKFS_ABORTED,
+ FR_TIMEOUT,
+ FR_LOCKED,
+ FR_NOT_ENOUGH_CORE,
+ FR_TOO_MANY_OPEN_FILES,
+ FR_INVALID_PARAMETER
+} FRESULT;
+
+FRESULT f_open(FIL *fp, const TCHAR *path, BYTE mode);
+FRESULT f_close(FIL *fp);
+FRESULT f_read(FIL *fp, void *buff, UINT btr, UINT *br);
+FRESULT f_write(FIL *fp, const void *buff, UINT btw, UINT *bw);
+FRESULT f_sync(FIL *fp);
+FRESULT f_unlink(const TCHAR *path);
+FRESULT f_stat(const TCHAR *path, FILINFO *fno);
+FRESULT f_mount(FATFS *fs, const TCHAR *path, BYTE opt);
+
+#define f_size(fp) ((fp)->obj.objsize)
+
+#define FA_READ 0x01
+#define FA_WRITE 0x02
+#define FA_OPEN_EXISTING 0x00
+#define FA_CREATE_NEW 0x04
+#define FA_CREATE_ALWAYS 0x08
+#define FA_OPEN_ALWAYS 0x10
+#define FA_OPEN_APPEND 0x30
+
+#define CREATE_LINKMAP ((FSIZE_t)0 - 1)
+
+#define FM_FAT 0x01
+#define FM_FAT32 0x02
+#define FM_EXFAT 0x04
+#define FM_ANY 0x07
+#define FM_SFD 0x08
+
+#define FS_FAT12 1
+#define FS_FAT16 2
+#define FS_FAT32 3
+#define FS_EXFAT 4
+
+#define AM_RDO 0x01
+#define AM_HID 0x02
+#define AM_SYS 0x04
+#define AM_DIR 0x10
+#define AM_ARC 0x20
+
+#endif
\ No newline at end of file
diff --git a/ffconf.h b/ffconf.h
new file mode 100644
index 0000000..ffdcf00
--- /dev/null
+++ b/ffconf.h
@@ -0,0 +1,14 @@
+#define FFCONF_DEF 86606
+#define FF_FS_READONLY 0
+#define FF_FS_MINIMIZE 0
+#define FF_USE_LABEL 0
+#define FF_CODE_PAGE 932
+#define FF_USE_LFN 0
+#define FF_FS_RPATH 0
+#define FF_VOLUMES 1
+#define FF_MULTI_PARTITION 0
+#define FF_MAX_SS 512
+#define FF_FS_EXFAT 0
+#define FF_NORTC_MON 1
+#define FF_NORTC_MDAY 1
+#define FF_NORTC_YEAR 2019
\ No newline at end of file
diff --git a/icon.png b/icon.png
new file mode 100644
index 0000000..e608636
Binary files /dev/null and b/icon.png differ
diff --git a/im01.cpp b/im01.cpp
new file mode 100644
index 0000000..ba00071
--- /dev/null
+++ b/im01.cpp
@@ -0,0 +1,76 @@
+#include "ff.h"
+#include "diskio.h"
+#include "inttypes.h"
+#include "pxt.h"
+#include "pxtcore.h"
+
+namespace im01
+{
+
+//%
+void _mkdir(String s)
+{
+}
+
+//%
+void _remove(String s)
+{
+ FATFS FatFs;
+ f_mount(&FatFs, "", 0);
+ f_unlink((const char *)s->getUTF8Data());
+}
+
+//%
+bool _file(String s, String v, uint8_t x)
+{
+ FATFS FatFs;
+ f_mount(&FatFs, "", 0);
+ FIL Fil;
+ UINT bw;
+ FRESULT fr;
+ fr = f_open(&Fil, (const char *)s->getUTF8Data(), x);
+ if (fr == FR_OK)
+ {
+ f_write(&Fil, (const char *)v->getUTF8Data(), v->getUTF8Size(), &bw);
+ fr = f_close(&Fil);
+ if (fr == FR_OK && bw == v->getUTF8Size())
+ {
+ return true;
+ }
+ return false;
+ }
+ return false;
+}
+
+//%
+uint32_t _size(String s)
+{
+ FATFS FatFs;
+ f_mount(&FatFs, "", 0);
+ uint32_t lSize = 0;
+ FIL Fil;
+ FRESULT fr;
+ fr = f_open(&Fil, (const char *)s->getUTF8Data(), FA_READ | FA_WRITE);
+ lSize = f_size(&Fil);
+ f_close(&Fil);
+ return lSize;
+}
+
+//%
+bool _exists(String s)
+{
+ FATFS FatFs;
+ f_mount(&FatFs, "", 0);
+ FRESULT fr;
+ FILINFO fno;
+ fr = f_stat((const char *)s->getUTF8Data(), &fno);
+ if (fr == FR_OK)
+ return true;
+ return false;
+}
+
+//%
+String _read(String s)
+{
+}
+} // namespace cs11
\ No newline at end of file
diff --git a/im01.ts b/im01.ts
new file mode 100644
index 0000000..42b9944
--- /dev/null
+++ b/im01.ts
@@ -0,0 +1,131 @@
+//%color=#444444 icon="\uf07b"
+namespace IM01 {
+ let sdFlag = false
+ //%block="IM01 size of file %u"
+ //%u.defl="log.txt"
+ function sizeOfFile(u: string): number {
+ u = truncateStringLength(u)
+ if (sdFlag == false) {
+ createFolder("CS11")
+ sdFlag = true
+ }
+ return size(u)
+ }
+
+ //%block="IM01 remove file"
+ //%u.defl="log.txt"
+ export function removeFile(u: string): void {
+ u = truncateStringLength(u)
+ if (sdFlag == false) {
+ createFolder("CS11")
+ sdFlag = true
+ }
+ remove(u)
+ return
+ }
+
+ //%block="IM01 file %u exists"
+ //%u.defl="log.txt"
+ export function fileExists(u: string): boolean {
+ u = truncateStringLength(u)
+ if (sdFlag == false) {
+ createFolder("CS11")
+ sdFlag = true
+ }
+ return exists(u)
+ }
+
+ //%block="IM01 overwrite file %u with %v"
+ //%u.defl="log.txt"
+ export function overwriteFile(u: string, v: string): void {
+ u = truncateStringLength(u)
+ if (sdFlag == false) {
+ createFolder("CS11")
+ sdFlag = true
+ }
+ file(u, v, 0x02 | 0x08)
+ return
+ }
+
+ //%block="IM01 append file %u with %v"
+ //%u.defl="log.txt"
+ export function appendFile(u: string, v: string): void {
+ u = truncateStringLength(u)
+ if (sdFlag == false) {
+ createFolder("CS11")
+ sdFlag = true
+ }
+ file(u, v, 0x02 | 0x30)
+ return
+ }
+
+ //%block="IM01 append file %u with line %v"
+ //%u.defl="log.txt"
+ export function appendFileLine(u: string, v: string): void {
+ u = truncateStringLength(u)
+ if (sdFlag == false) {
+ createFolder("CS11")
+ sdFlag = true
+ }
+ file(u, v + "\n", 0x02 | 0x30)
+ return
+ }
+
+ //%block="IM01 read file %u"
+ //%u.defl="log.txt"
+ export function readFile(u: string): string {
+ u = truncateStringLength(u)
+ if (sdFlag == false) {
+ createFolder("CS11")
+ sdFlag = true
+ }
+ return file_read(u)
+ }
+
+ //%block="IM01 create folder %u"
+ function createFolder(u: string): void {
+ mkdir(u)
+ return;
+ }
+
+ //%shim=im01::_mkdir
+ function mkdir(u: string): void {
+ return
+ }
+
+ //%shim=im01::_remove
+ function remove(u: string): void {
+ return
+ }
+
+ //%shim=im01::_file
+ function file(u: string, v: string, x: number): boolean {
+ return true
+ }
+
+ //%shim=im01::_size
+ function size(u: string): number {
+ return 1
+ }
+
+ //%shim=im01::_exists
+ function exists(u: string): boolean {
+ return true
+ }
+
+ //%shim=im01::_read
+ function file_read(u: string): string {
+ return ""
+ }
+
+ function truncateStringLength(u: string): string {
+ let i = u.indexOf(".")
+ let ext = u.substr(i, u.length)
+ if (i > 8) {
+ u = u.substr(0, 8) + ext
+ }
+ return u
+ }
+
+
+}
\ No newline at end of file
diff --git a/main.blocks b/main.blocks
deleted file mode 100644
index fd0869b..0000000
--- a/main.blocks
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/main.ts b/main.ts
deleted file mode 100644
index ee54a1b..0000000
--- a/main.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-basic.forever(function () {
-
-})
diff --git a/pxt.json b/pxt.json
index 2163bd2..8f105e4 100644
--- a/pxt.json
+++ b/pxt.json
@@ -1,22 +1,32 @@
{
- "name": "pxt-im01-2",
- "version": "0.0.1",
- "description": "",
+ "name": "CS11",
+ "version": "0.0.8",
+ "description": "XinaBox CS11 SD Card: SD Card functionality.",
+ "license": "MIT",
"dependencies": {
- "core": "*",
- "radio": "*"
+ "core": "*"
},
"files": [
"README.md",
- "main.blocks",
- "main.ts"
+ "main.ts",
+ "sdmm.cpp",
+ "im01.ts",
+ "im01.cpp",
+ "diskio.h",
+ "ff.cpp",
+ "ff.h",
+ "ffconf.h"
],
"testFiles": [
"test.ts"
],
"public": true,
"supportedTargets": [
- "microbit"
+ "maker"
],
- "preferredEditor": "tsprj"
+ "preferredEditor": "blocksprj",
+ "authors": [
+ "Luqmaan Baboo",
+ "Bjarke Gotfredsen"
+ ]
}
diff --git a/sdmm.cpp b/sdmm.cpp
new file mode 100644
index 0000000..5194ab0
--- /dev/null
+++ b/sdmm.cpp
@@ -0,0 +1,544 @@
+#include "ff.h"
+#include "diskio.h"
+
+#include "pxt.h"
+
+
+/*
+ MISO = P14
+ MOSI = P15
+ SCK = P13
+ CS = P16
+*/
+
+
+void DO_INIT()
+{
+
+ uBit.io.P14.setDigitalValue(0);
+}
+
+
+bool DO()
+{
+
+ return uBit.io.P14.getDigitalValue();
+}
+
+void DI_INIT()
+{
+
+ uBit.io.P15.setDigitalValue(0);
+}
+
+void DI_H()
+{
+
+ uBit.io.P15.setDigitalValue(1);
+}
+void DI_L()
+{
+
+ uBit.io.P15.setDigitalValue(0);
+}
+
+void CK_INIT()
+{
+
+ uBit.io.P13.setDigitalValue(0);
+}
+void CK_H()
+{
+
+ uBit.io.P13.setDigitalValue(1);
+}
+void CK_L()
+{
+
+ uBit.io.P13.setDigitalValue(0);
+}
+
+void CS_INIT()
+{
+
+ uBit.io.P16.setDigitalValue(0);
+}
+void CS_H()
+{
+
+ uBit.io.P16.setDigitalValue(1);
+}
+void CS_L()
+{
+
+ uBit.io.P16.setDigitalValue(0);
+}
+
+void dly_us(UINT n)
+{
+ sleep_us(n);
+}
+
+#define CMD0 (0)
+#define CMD1 (1)
+#define ACMD41 (0x80 + 41)
+#define CMD8 (8)
+#define CMD9 (9)
+#define CMD12 (12)
+#define CMD16 (16)
+#define CMD17 (17)
+#define CMD18 (18)
+#define ACMD23 (0x80 + 23)
+#define CMD24 (24)
+#define CMD25 (25)
+#define CMD55 (55)
+#define CMD58 (58)
+
+static DSTATUS Stat = STA_NOINIT;
+
+static BYTE CardType;
+
+static void xmit_mmc(
+ const BYTE *buff,
+ UINT bc)
+{
+ BYTE d;
+
+ do
+ {
+ d = *buff++;
+ if (d & 0x80)
+ DI_H();
+ else
+ DI_L();
+ CK_H();
+ CK_L();
+ if (d & 0x40)
+ DI_H();
+ else
+ DI_L();
+ CK_H();
+ CK_L();
+ if (d & 0x20)
+ DI_H();
+ else
+ DI_L();
+ CK_H();
+ CK_L();
+ if (d & 0x10)
+ DI_H();
+ else
+ DI_L();
+ CK_H();
+ CK_L();
+ if (d & 0x08)
+ DI_H();
+ else
+ DI_L();
+ CK_H();
+ CK_L();
+ if (d & 0x04)
+ DI_H();
+ else
+ DI_L();
+ CK_H();
+ CK_L();
+ if (d & 0x02)
+ DI_H();
+ else
+ DI_L();
+ CK_H();
+ CK_L();
+ if (d & 0x01)
+ DI_H();
+ else
+ DI_L();
+ CK_H();
+ CK_L();
+ } while (--bc);
+}
+
+static void rcvr_mmc(
+ BYTE *buff,
+ UINT bc)
+{
+ BYTE r;
+
+ DI_H();
+
+ do
+ {
+ r = 0;
+ if (DO())
+ r++;
+ CK_H();
+ CK_L();
+ r <<= 1;
+ if (DO())
+ r++;
+ CK_H();
+ CK_L();
+ r <<= 1;
+ if (DO())
+ r++;
+ CK_H();
+ CK_L();
+ r <<= 1;
+ if (DO())
+ r++;
+ CK_H();
+ CK_L();
+ r <<= 1;
+ if (DO())
+ r++;
+ CK_H();
+ CK_L();
+ r <<= 1;
+ if (DO())
+ r++;
+ CK_H();
+ CK_L();
+ r <<= 1;
+ if (DO())
+ r++;
+ CK_H();
+ CK_L();
+ r <<= 1;
+ if (DO())
+ r++;
+ CK_H();
+ CK_L();
+ *buff++ = r;
+ } while (--bc);
+}
+
+static int wait_ready(void)
+{
+ BYTE d;
+ UINT tmr;
+
+ for (tmr = 5000; tmr; tmr--)
+ {
+ rcvr_mmc(&d, 1);
+ if (d == 0xFF)
+ break;
+ dly_us(100);
+ }
+
+ return tmr ? 1 : 0;
+}
+
+void deselect(void)
+{
+ BYTE d;
+
+ CS_H();
+ rcvr_mmc(&d, 1);
+}
+
+static int select(void)
+{
+ BYTE d;
+
+ CS_L();
+ rcvr_mmc(&d, 1);
+ if (wait_ready())
+ return 1;
+
+ deselect();
+ return 0;
+}
+
+static int rcvr_datablock(
+ BYTE *buff,
+ UINT btr)
+{
+ BYTE d[2];
+ UINT tmr;
+
+ for (tmr = 1000; tmr; tmr--)
+ {
+ rcvr_mmc(d, 1);
+ if (d[0] != 0xFF)
+ break;
+ dly_us(100);
+ }
+ if (d[0] != 0xFE)
+ return 0;
+
+ rcvr_mmc(buff, btr);
+ rcvr_mmc(d, 2);
+
+ return 1;
+}
+
+static int xmit_datablock(
+ const BYTE *buff,
+ BYTE token)
+{
+ BYTE d[2];
+
+ if (!wait_ready())
+ return 0;
+
+ d[0] = token;
+ xmit_mmc(d, 1);
+ if (token != 0xFD)
+ {
+ xmit_mmc(buff, 512);
+ rcvr_mmc(d, 2);
+ rcvr_mmc(d, 1);
+ if ((d[0] & 0x1F) != 0x05)
+ return 0;
+ }
+
+ return 1;
+}
+
+static BYTE send_cmd(
+ BYTE cmd,
+ DWORD arg)
+{
+ BYTE n, d, buf[6];
+
+ if (cmd & 0x80)
+ {
+ cmd &= 0x7F;
+ n = send_cmd(CMD55, 0);
+ if (n > 1)
+ return n;
+ }
+
+ if (cmd != CMD12)
+ {
+ deselect();
+ if (!select())
+ return 0xFF;
+ }
+
+ buf[0] = 0x40 | cmd;
+ buf[1] = (BYTE)(arg >> 24);
+ buf[2] = (BYTE)(arg >> 16);
+ buf[3] = (BYTE)(arg >> 8);
+ buf[4] = (BYTE)arg;
+ n = 0x01;
+ if (cmd == CMD0)
+ n = 0x95;
+ if (cmd == CMD8)
+ n = 0x87;
+ buf[5] = n;
+ xmit_mmc(buf, 6);
+
+ if (cmd == CMD12)
+ rcvr_mmc(&d, 1);
+ n = 10;
+ do
+ rcvr_mmc(&d, 1);
+ while ((d & 0x80) && --n);
+
+ return d;
+}
+
+DSTATUS disk_status(
+ BYTE drv)
+{
+ if (drv)
+ return STA_NOINIT;
+
+ return Stat;
+}
+
+DSTATUS disk_initialize(
+ BYTE drv)
+{
+ BYTE n, ty, cmd, buf[4];
+ UINT tmr;
+ DSTATUS s;
+
+ if (drv)
+ return RES_NOTRDY;
+
+ dly_us(10000);
+ CS_INIT();
+ CS_H();
+ CK_INIT();
+ CK_L();
+ DI_INIT();
+ DO_INIT();
+
+ for (n = 10; n; n--)
+ rcvr_mmc(buf, 1);
+
+ ty = 0;
+ if (send_cmd(CMD0, 0) == 1)
+ {
+ if (send_cmd(CMD8, 0x1AA) == 1)
+ {
+ rcvr_mmc(buf, 4);
+ if (buf[2] == 0x01 && buf[3] == 0xAA)
+ {
+ for (tmr = 1000; tmr; tmr--)
+ {
+ if (send_cmd(ACMD41, 1UL << 30) == 0)
+ break;
+ dly_us(1000);
+ }
+ if (tmr && send_cmd(CMD58, 0) == 0)
+ {
+ rcvr_mmc(buf, 4);
+ ty = (buf[0] & 0x40) ? CT_SD2 | CT_BLOCK : CT_SD2;
+ }
+ }
+ }
+ else
+ {
+ if (send_cmd(ACMD41, 0) <= 1)
+ {
+ ty = CT_SD1;
+ cmd = ACMD41;
+ }
+ else
+ {
+ ty = CT_MMC;
+ cmd = CMD1;
+ }
+ for (tmr = 1000; tmr; tmr--)
+ {
+ if (send_cmd(cmd, 0) == 0)
+ break;
+ dly_us(1000);
+ }
+ if (!tmr || send_cmd(CMD16, 512) != 0)
+ ty = 0;
+ }
+ }
+ CardType = ty;
+ s = ty ? 0 : STA_NOINIT;
+ Stat = s;
+
+ deselect();
+
+ return s;
+}
+
+DRESULT disk_read(
+ BYTE drv,
+ BYTE *buff,
+ LBA_t sector,
+ UINT count)
+{
+ BYTE cmd;
+ DWORD sect = (DWORD)sector;
+
+ if (disk_status(drv) & STA_NOINIT)
+ return RES_NOTRDY;
+ if (!(CardType & CT_BLOCK))
+ sect *= 512;
+
+ cmd = count > 1 ? CMD18 : CMD17;
+ if (send_cmd(cmd, sect) == 0)
+ {
+ do
+ {
+ if (!rcvr_datablock(buff, 512))
+ break;
+ buff += 512;
+ } while (--count);
+ if (cmd == CMD18)
+ send_cmd(CMD12, 0);
+ }
+ deselect();
+
+ return count ? RES_ERROR : RES_OK;
+}
+
+DRESULT disk_write(
+ BYTE drv,
+ const BYTE *buff,
+ LBA_t sector,
+ UINT count)
+{
+ DWORD sect = (DWORD)sector;
+
+ if (disk_status(drv) & STA_NOINIT)
+ return RES_NOTRDY;
+ if (!(CardType & CT_BLOCK))
+ sect *= 512;
+
+ if (count == 1)
+ {
+ if ((send_cmd(CMD24, sect) == 0) && xmit_datablock(buff, 0xFE))
+ count = 0;
+ }
+ else
+ {
+ if (CardType & CT_SDC)
+ send_cmd(ACMD23, count);
+ if (send_cmd(CMD25, sect) == 0)
+ {
+ do
+ {
+ if (!xmit_datablock(buff, 0xFC))
+ break;
+ buff += 512;
+ } while (--count);
+ if (!xmit_datablock(0, 0xFD))
+ count = 1;
+ }
+ }
+ deselect();
+
+ return count ? RES_ERROR : RES_OK;
+}
+
+DRESULT disk_ioctl(
+ BYTE drv,
+ BYTE ctrl,
+ void *buff)
+{
+ DRESULT res;
+ BYTE n, csd[16];
+ DWORD cs;
+
+ if (disk_status(drv) & STA_NOINIT)
+ return RES_NOTRDY;
+
+ res = RES_ERROR;
+ switch (ctrl)
+ {
+ case CTRL_SYNC:
+ if (select())
+ res = RES_OK;
+ break;
+
+ case GET_SECTOR_COUNT:
+ if ((send_cmd(CMD9, 0) == 0) && rcvr_datablock(csd, 16))
+ {
+ if ((csd[0] >> 6) == 1)
+ {
+ cs = csd[9] + ((WORD)csd[8] << 8) + ((DWORD)(csd[7] & 63) << 16) + 1;
+ *(LBA_t *)buff = cs << 10;
+ }
+ else
+ {
+ n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2;
+ cs = (csd[8] >> 6) + ((WORD)csd[7] << 2) + ((WORD)(csd[6] & 3) << 10) + 1;
+ *(LBA_t *)buff = cs << (n - 9);
+ }
+ res = RES_OK;
+ }
+ break;
+
+ case GET_BLOCK_SIZE:
+ *(DWORD *)buff = 128;
+ res = RES_OK;
+ break;
+
+ default:
+ res = RES_PARERR;
+ }
+
+ deselect();
+
+ return res;
+}