mirror of
https://github.com/opentx/opentx.git
synced 2025-07-23 16:25:16 +03:00
Projectkk2glider/simu tmp sd path (#4231)
* Re #4224: Introduced settingsPath and use std::string for paths in simpgmspace. * Re #4224: Relevant parts of simpgmspace.cpp moved into simufatfs.cpp and simudisk.cpp * Removed "/" from "mask_monitor_logsw.png" * Re #4224: findTrueFileName() refactoring * Faster gtests (less waiting for eeprom operations to finish) * Re #4224: Radio settings and models directories now taken from alternate path (if set) [simu] * Fixes #3322: together with previous changes to the SD browser this prevents the simulator from browsing higher than SD card root path. * f_chdir() debug traces
This commit is contained in:
parent
bedaa505a2
commit
f7543e3220
12 changed files with 840 additions and 706 deletions
|
@ -64,7 +64,7 @@ class SimulatorInterface
|
||||||
|
|
||||||
virtual ~SimulatorInterface() {};
|
virtual ~SimulatorInterface() {};
|
||||||
|
|
||||||
virtual void setSdPath(const QString &sdPath) { };
|
virtual void setSdPath(const QString & sdPath = "", const QString & settingsPath = "") { };
|
||||||
|
|
||||||
virtual void setVolumeGain(int value) { };
|
virtual void setVolumeGain(int value) { };
|
||||||
|
|
||||||
|
|
|
@ -130,7 +130,7 @@ class DefaultTheme: public Theme
|
||||||
loadMenuIcon(ICON_MONITOR_CHANNELS2, "mask_monitor_channels2.png");
|
loadMenuIcon(ICON_MONITOR_CHANNELS2, "mask_monitor_channels2.png");
|
||||||
loadMenuIcon(ICON_MONITOR_CHANNELS3, "mask_monitor_channels3.png");
|
loadMenuIcon(ICON_MONITOR_CHANNELS3, "mask_monitor_channels3.png");
|
||||||
loadMenuIcon(ICON_MONITOR_CHANNELS4, "mask_monitor_channels4.png");
|
loadMenuIcon(ICON_MONITOR_CHANNELS4, "mask_monitor_channels4.png");
|
||||||
loadMenuIcon(ICON_MONITOR_LOGICAL_SWITCHES, "/mask_monitor_logsw.png");
|
loadMenuIcon(ICON_MONITOR_LOGICAL_SWITCHES, "mask_monitor_logsw.png");
|
||||||
|
|
||||||
BitmapBuffer * background = BitmapBuffer::loadMask(getThemePath("mask_currentmenu_bg.png"));
|
BitmapBuffer * background = BitmapBuffer::loadMask(getThemePath("mask_currentmenu_bg.png"));
|
||||||
BitmapBuffer * shadow = BitmapBuffer::loadMask(getThemePath("mask_currentmenu_shadow.png"));
|
BitmapBuffer * shadow = BitmapBuffer::loadMask(getThemePath("mask_currentmenu_shadow.png"));
|
||||||
|
|
|
@ -131,7 +131,9 @@ Open9xSim::~Open9xSim()
|
||||||
{
|
{
|
||||||
StopSimu();
|
StopSimu();
|
||||||
StopAudioThread();
|
StopAudioThread();
|
||||||
|
#if defined(EEPROM)
|
||||||
StopEepromThread();
|
StopEepromThread();
|
||||||
|
#endif
|
||||||
|
|
||||||
delete bmp;
|
delete bmp;
|
||||||
delete sliders[0];
|
delete sliders[0];
|
||||||
|
@ -548,9 +550,11 @@ int main(int argc,char **argv)
|
||||||
|
|
||||||
simuInit();
|
simuInit();
|
||||||
|
|
||||||
|
#if defined(EEPROM)
|
||||||
StartEepromThread(argc >= 2 ? argv[1] : "eeprom.bin");
|
StartEepromThread(argc >= 2 ? argv[1] : "eeprom.bin");
|
||||||
|
#endif
|
||||||
StartAudioThread();
|
StartAudioThread();
|
||||||
StartSimu();
|
StartSimu(false, argc >= 3 ? argv[2] : 0, argc >= 4 ? argv[3] : 0);
|
||||||
|
|
||||||
return application.run();
|
return application.run();
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,8 @@ set(SIMU_SRC
|
||||||
${SIMU_SRC}
|
${SIMU_SRC}
|
||||||
simpgmspace.cpp
|
simpgmspace.cpp
|
||||||
simueeprom.cpp
|
simueeprom.cpp
|
||||||
|
simufatfs.cpp
|
||||||
|
simudisk.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
add_definitions(-DSIMU)
|
add_definitions(-DSIMU)
|
||||||
|
|
|
@ -58,12 +58,10 @@ OpenTxSimulator::OpenTxSimulator()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenTxSimulator::setSdPath(const QString &sdPath)
|
void OpenTxSimulator::setSdPath(const QString & sdPath, const QString & settingsPath)
|
||||||
{
|
{
|
||||||
#if defined(SDCARD)
|
simuSdDirectory = sdPath;
|
||||||
strncpy(simuSdDirectory, sdPath.toLatin1().constData(), sizeof(simuSdDirectory)-1);
|
simuSettingsDirectory = settingsPath;
|
||||||
simuSdDirectory[sizeof(simuSdDirectory)-1] = '\0';
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenTxSimulator::setVolumeGain(int value)
|
void OpenTxSimulator::setVolumeGain(int value)
|
||||||
|
@ -106,7 +104,7 @@ void OpenTxSimulator::start(const char * filename, bool tests)
|
||||||
|
|
||||||
StartEepromThread(filename);
|
StartEepromThread(filename);
|
||||||
StartAudioThread(volumeGain);
|
StartAudioThread(volumeGain);
|
||||||
StartSimu(tests);
|
StartSimu(tests, simuSdDirectory.toLatin1().constData(), simuSettingsDirectory.toLatin1().constData());
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenTxSimulator::stop()
|
void OpenTxSimulator::stop()
|
||||||
|
|
|
@ -29,12 +29,14 @@ class DLLEXPORT OpenTxSimulator : public SimulatorInterface {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int volumeGain;
|
int volumeGain;
|
||||||
|
QString simuSdDirectory;
|
||||||
|
QString simuSettingsDirectory;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
OpenTxSimulator();
|
OpenTxSimulator();
|
||||||
|
|
||||||
virtual void setSdPath(const QString &sdPath);
|
virtual void setSdPath(const QString & sdPath = "", const QString & settingsPath = "");
|
||||||
|
|
||||||
virtual void setVolumeGain(int value);
|
virtual void setVolumeGain(int value);
|
||||||
|
|
||||||
|
|
|
@ -20,9 +20,8 @@
|
||||||
|
|
||||||
#include "opentx.h"
|
#include "opentx.h"
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <sys/stat.h>
|
#include <string>
|
||||||
|
|
||||||
#if !defined _MSC_VER || defined __GNUC__
|
#if !defined _MSC_VER || defined __GNUC__
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
|
@ -36,17 +35,6 @@
|
||||||
#include <SDL.h>
|
#include <SDL.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(TRACE_SIMPGMSPACE)
|
|
||||||
#undef TRACE_SIMPGMSPACE
|
|
||||||
#define TRACE_SIMPGMSPACE TRACE
|
|
||||||
#else
|
|
||||||
#define TRACE_SIMPGMSPACE(...)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(SDCARD) && !defined(SKIP_FATFS_DECLARATION) && !defined(SIMU_DISKIO)
|
|
||||||
#define SIMU_USE_SDCARD
|
|
||||||
#endif
|
|
||||||
|
|
||||||
uint8_t MCUCSR, MCUSR, MCUCR;
|
uint8_t MCUCSR, MCUSR, MCUCR;
|
||||||
volatile uint8_t pina=0xff, pinb=0xff, pinc=0xff, pind, pine=0xff, pinf=0xff, ping=0xff, pinh=0xff, pinj=0, pinl=0;
|
volatile uint8_t pina=0xff, pinb=0xff, pinc=0xff, pind, pine=0xff, pinf=0xff, ping=0xff, pinh=0xff, pinj=0, pinl=0;
|
||||||
uint8_t portb, portc, porth=0, dummyport;
|
uint8_t portb, portc, porth=0, dummyport;
|
||||||
|
@ -77,10 +65,6 @@ Dacc dacc;
|
||||||
Adc Adc0;
|
Adc Adc0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(SIMU_USE_SDCARD)
|
|
||||||
char simuSdDirectory[1024] = "";
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void lcdInit()
|
void lcdInit()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -305,18 +289,14 @@ void simuSetSwitch(uint8_t swtch, int8_t state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void StartSimu(bool tests)
|
void StartSimu(bool tests, const char * sdPath, const char * settingsPath)
|
||||||
{
|
{
|
||||||
s_current_protocol[0] = 255;
|
s_current_protocol[0] = 255;
|
||||||
menuLevel = 0;
|
menuLevel = 0;
|
||||||
|
|
||||||
main_thread_running = (tests ? 1 : 2); // TODO rename to simu_run_mode with #define
|
main_thread_running = (tests ? 1 : 2); // TODO rename to simu_run_mode with #define
|
||||||
|
|
||||||
#if defined(SIMU_USE_SDCARD)
|
simuFatfsSetPaths(sdPath, settingsPath);
|
||||||
if (strlen(simuSdDirectory) == 0) {
|
|
||||||
f_getcwd(simuSdDirectory, 1024);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
g_tmr10ms must be non-zero otherwise some SF functions (that use this timer as a marker when it was last executed)
|
g_tmr10ms must be non-zero otherwise some SF functions (that use this timer as a marker when it was last executed)
|
||||||
|
@ -522,675 +502,6 @@ uint16_t stackAvailable()
|
||||||
return 500;
|
return 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(SIMU_USE_SDCARD)
|
|
||||||
#if defined(_MSC_VER) || !defined(__GNUC__)
|
|
||||||
#include <direct.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <sys/utime.h>
|
|
||||||
#define mkdir(s, f) _mkdir(s)
|
|
||||||
#else
|
|
||||||
#include <utime.h>
|
|
||||||
#endif
|
|
||||||
#include "ff.h"
|
|
||||||
#include <map>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
namespace simu {
|
|
||||||
#include <dirent.h>
|
|
||||||
#if !defined(_MSC_VER)
|
|
||||||
#include <libgen.h>
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(CPUARM)
|
|
||||||
FATFS g_FATFS_Obj;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
char * convertSimuPath(const char *path)
|
|
||||||
{
|
|
||||||
static char result[1024];
|
|
||||||
if (((path[0] == '/') || (path[0] == '\\')) && (strcmp(simuSdDirectory, "/") != 0))
|
|
||||||
sprintf(result, "%s%s", simuSdDirectory, path);
|
|
||||||
else
|
|
||||||
strcpy(result, path);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef std::map<std::string, std::string> filemap_t;
|
|
||||||
|
|
||||||
filemap_t fileMap;
|
|
||||||
|
|
||||||
char *findTrueFileName(const char *path)
|
|
||||||
{
|
|
||||||
// TRACE_SIMPGMSPACE("findTrueFileName(%s)", path);
|
|
||||||
static char result[1024];
|
|
||||||
filemap_t::iterator i = fileMap.find(path);
|
|
||||||
if (i != fileMap.end()) {
|
|
||||||
strcpy(result, i->second.c_str());
|
|
||||||
// TRACE_SIMPGMSPACE("\tfound in map: %s", result);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
//find file
|
|
||||||
//add to map
|
|
||||||
#if defined _MSC_VER || !defined __GNUC__
|
|
||||||
char drive[_MAX_DRIVE];
|
|
||||||
char dir[_MAX_DIR];
|
|
||||||
char fname[_MAX_FNAME];
|
|
||||||
char ext[_MAX_EXT];
|
|
||||||
_splitpath(path, drive, dir, fname, ext);
|
|
||||||
std::string fileName = std::string(fname) + std::string(ext);
|
|
||||||
std::string dirName = std::string(drive) + std::string(dir);
|
|
||||||
std::string searchName = dirName + "*";
|
|
||||||
// TRACE_SIMPGMSPACE("\tsearching for: %s", fileName.c_str());
|
|
||||||
WIN32_FIND_DATA ffd;
|
|
||||||
HANDLE hFind = FindFirstFile(searchName.c_str(), &ffd);
|
|
||||||
if (INVALID_HANDLE_VALUE != hFind) {
|
|
||||||
do {
|
|
||||||
if (!(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
|
|
||||||
//TRACE_SIMPGMSPACE("comparing with: %s", ffd.cFileName);
|
|
||||||
if (!strcasecmp(fileName.c_str(), ffd.cFileName)) {
|
|
||||||
strcpy(result, dirName.c_str());
|
|
||||||
strcat(result, ffd.cFileName);
|
|
||||||
TRACE_SIMPGMSPACE("\tfound: %s", ffd.cFileName);
|
|
||||||
fileMap.insert(filemap_t:: value_type(path, result));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
while (FindNextFile(hFind, &ffd) != 0);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
strcpy(result, path);
|
|
||||||
std::string fileName = simu::basename(result);
|
|
||||||
strcpy(result, path);
|
|
||||||
std::string dirName = simu::dirname(result);
|
|
||||||
simu::DIR * dir = simu::opendir(dirName.c_str());
|
|
||||||
if (dir) {
|
|
||||||
// TRACE_SIMPGMSPACE("\tsearching for: %s", fileName.c_str());
|
|
||||||
for (;;) {
|
|
||||||
struct simu::dirent * res = simu::readdir(dir);
|
|
||||||
if (res == 0) break;
|
|
||||||
#if defined(WIN32) || defined(__APPLE__) || defined(__FreeBSD__)
|
|
||||||
if ((res->d_type == DT_REG) || (res->d_type == DT_LNK)) {
|
|
||||||
#else
|
|
||||||
if ((res->d_type == simu::DT_REG) || (res->d_type == simu::DT_LNK)) {
|
|
||||||
#endif
|
|
||||||
// TRACE_SIMPGMSPACE("comparing with: %s", res->d_name);
|
|
||||||
if (!strcasecmp(fileName.c_str(), res->d_name)) {
|
|
||||||
strcpy(result, dirName.c_str());
|
|
||||||
strcat(result, "/");
|
|
||||||
strcat(result, res->d_name);
|
|
||||||
// TRACE_SIMPGMSPACE("\tfound: %s", res->d_name);
|
|
||||||
fileMap.insert(filemap_t:: value_type(path, result));
|
|
||||||
simu::closedir(dir);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
simu::closedir(dir);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
// TRACE_SIMPGMSPACE("\tnot found");
|
|
||||||
strcpy(result, path);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
FRESULT f_stat (const TCHAR * name, FILINFO *fno)
|
|
||||||
{
|
|
||||||
char *path = convertSimuPath(name);
|
|
||||||
char * realPath = findTrueFileName(path);
|
|
||||||
struct stat tmp;
|
|
||||||
if (stat(realPath, &tmp)) {
|
|
||||||
TRACE_SIMPGMSPACE("f_stat(%s) = error %d (%s)", path, errno, strerror(errno));
|
|
||||||
return FR_INVALID_NAME;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
TRACE_SIMPGMSPACE("f_stat(%s) = OK", path);
|
|
||||||
if (fno) {
|
|
||||||
fno->fattrib = (tmp.st_mode & S_IFDIR) ? AM_DIR : 0;
|
|
||||||
// convert to FatFs fdate/ftime
|
|
||||||
struct tm *ltime = localtime(&tmp.st_mtime);
|
|
||||||
fno->fdate = ((ltime->tm_year - 80) << 9) | ((ltime->tm_mon + 1) << 5) | ltime->tm_mday;
|
|
||||||
fno->ftime = (ltime->tm_hour << 11) | (ltime->tm_min << 5) | (ltime->tm_sec / 2);
|
|
||||||
fno->fsize = (DWORD)tmp.st_size;
|
|
||||||
}
|
|
||||||
return FR_OK;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
FRESULT f_mount (FATFS* ,const TCHAR*, BYTE opt)
|
|
||||||
{
|
|
||||||
return FR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
FRESULT f_open (FIL * fil, const TCHAR *name, BYTE flag)
|
|
||||||
{
|
|
||||||
char * path = convertSimuPath(name);
|
|
||||||
char * realPath = findTrueFileName(path);
|
|
||||||
fil->obj.fs = 0;
|
|
||||||
if (!(flag & FA_WRITE)) {
|
|
||||||
struct stat tmp;
|
|
||||||
if (stat(realPath, &tmp)) {
|
|
||||||
TRACE_SIMPGMSPACE("f_open(%s) = INVALID_NAME (FIL %p)", path, fil);
|
|
||||||
return FR_INVALID_NAME;
|
|
||||||
}
|
|
||||||
fil->obj.objsize = tmp.st_size;
|
|
||||||
fil->fptr = 0;
|
|
||||||
}
|
|
||||||
fil->obj.fs = (FATFS*)fopen(realPath, (flag & FA_WRITE) ? ((flag & FA_CREATE_ALWAYS) ? "wb+" : "ab+") : "rb+");
|
|
||||||
fil->fptr = 0;
|
|
||||||
if (fil->obj.fs) {
|
|
||||||
TRACE_SIMPGMSPACE("f_open(%s, %x) = %p (FIL %p)", path, flag, fil->obj.fs, fil);
|
|
||||||
return FR_OK;
|
|
||||||
}
|
|
||||||
TRACE_SIMPGMSPACE("f_open(%s) = error %d (%s) (FIL %p)", path, errno, strerror(errno), fil);
|
|
||||||
return FR_INVALID_NAME;
|
|
||||||
}
|
|
||||||
|
|
||||||
FRESULT f_read (FIL* fil, void* data, UINT size, UINT* read)
|
|
||||||
{
|
|
||||||
if (fil && fil->obj.fs) {
|
|
||||||
*read = fread(data, 1, size, (FILE*)fil->obj.fs);
|
|
||||||
fil->fptr += *read;
|
|
||||||
// TRACE_SIMPGMSPACE("fread(%p) %u, %u", fil->obj.fs, size, *read);
|
|
||||||
}
|
|
||||||
return FR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
FRESULT f_write (FIL* fil, const void* data, UINT size, UINT* written)
|
|
||||||
{
|
|
||||||
if (fil && fil->obj.fs) {
|
|
||||||
*written = fwrite(data, 1, size, (FILE*)fil->obj.fs);
|
|
||||||
fil->fptr += size;
|
|
||||||
// TRACE_SIMPGMSPACE("fwrite(%p) %u, %u", fil->obj.fs, size, *written);
|
|
||||||
}
|
|
||||||
return FR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
TCHAR * f_gets (TCHAR* buff, int len, FIL* fil)
|
|
||||||
{
|
|
||||||
if (fil && fil->obj.fs) {
|
|
||||||
buff = fgets(buff, len, (FILE*)fil->obj.fs);
|
|
||||||
if (buff != NULL) {
|
|
||||||
fil->fptr = *buff;
|
|
||||||
}
|
|
||||||
// TRACE_SIMPGMSPACE("fgets(%p) %u, %s", fil->obj.fs, len, buff);
|
|
||||||
}
|
|
||||||
return buff;
|
|
||||||
}
|
|
||||||
|
|
||||||
FRESULT f_lseek (FIL* fil, DWORD offset)
|
|
||||||
{
|
|
||||||
if (fil && fil->obj.fs) fseek((FILE*)fil->obj.fs, offset, SEEK_SET);
|
|
||||||
fil->fptr = offset;
|
|
||||||
return FR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
UINT f_size(FIL* fil)
|
|
||||||
{
|
|
||||||
if (fil && fil->obj.fs) {
|
|
||||||
long curr = ftell((FILE*)fil->obj.fs);
|
|
||||||
fseek((FILE*)fil->obj.fs, 0, SEEK_END);
|
|
||||||
long size = ftell((FILE*)fil->obj.fs);
|
|
||||||
fseek((FILE*)fil->obj.fs, curr, SEEK_SET);
|
|
||||||
TRACE_SIMPGMSPACE("f_size(%p) %u", fil->obj.fs, size);
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
FRESULT f_close (FIL * fil)
|
|
||||||
{
|
|
||||||
TRACE_SIMPGMSPACE("f_close(%p) (FIL:%p)", fil->obj.fs, fil);
|
|
||||||
if (fil->obj.fs) {
|
|
||||||
fclose((FILE*)fil->obj.fs);
|
|
||||||
fil->obj.fs = NULL;
|
|
||||||
}
|
|
||||||
return FR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
FRESULT f_chdir (const TCHAR *name)
|
|
||||||
{
|
|
||||||
chdir(convertSimuPath(name));
|
|
||||||
return FR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
FRESULT f_opendir (DIR * rep, const TCHAR * name)
|
|
||||||
{
|
|
||||||
char *path = convertSimuPath(name);
|
|
||||||
rep->obj.fs = (FATFS *)simu::opendir(path);
|
|
||||||
if ( rep->obj.fs ) {
|
|
||||||
TRACE_SIMPGMSPACE("f_opendir(%s) = OK", path);
|
|
||||||
return FR_OK;
|
|
||||||
}
|
|
||||||
TRACE_SIMPGMSPACE("f_opendir(%s) = error %d (%s)", path, errno, strerror(errno));
|
|
||||||
return FR_NO_PATH;
|
|
||||||
}
|
|
||||||
|
|
||||||
FRESULT f_closedir (DIR * rep)
|
|
||||||
{
|
|
||||||
TRACE_SIMPGMSPACE("f_closedir(%p)", rep);
|
|
||||||
if (rep->obj.fs) simu::closedir((simu::DIR *)rep->obj.fs);
|
|
||||||
return FR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
FRESULT f_readdir (DIR * rep, FILINFO * fil)
|
|
||||||
{
|
|
||||||
simu::dirent * ent;
|
|
||||||
if (!rep->obj.fs) return FR_NO_FILE;
|
|
||||||
for(;;) {
|
|
||||||
ent = simu::readdir((simu::DIR *)rep->obj.fs);
|
|
||||||
if (!ent) return FR_NO_FILE;
|
|
||||||
if (strcmp(ent->d_name, ".") && strcmp(ent->d_name, "..") ) break;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(WIN32) || !defined(__GNUC__) || defined(__APPLE__) || defined(__FreeBSD__)
|
|
||||||
fil->fattrib = (ent->d_type == DT_DIR ? AM_DIR : 0);
|
|
||||||
#else
|
|
||||||
if (ent->d_type == simu::DT_UNKNOWN || ent->d_type == simu::DT_LNK) {
|
|
||||||
fil->fattrib = 0;
|
|
||||||
struct stat buf;
|
|
||||||
if (stat(ent->d_name, &buf) == 0) {
|
|
||||||
fil->fattrib = (S_ISDIR(buf.st_mode) ? AM_DIR : 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
fil->fattrib = (ent->d_type == simu::DT_DIR ? AM_DIR : 0);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
memset(fil->fname, 0, SD_SCREEN_FILE_LENGTH);
|
|
||||||
strcpy(fil->fname, ent->d_name);
|
|
||||||
// TRACE_SIMPGMSPACE("f_readdir(): %s", fil->fname);
|
|
||||||
return FR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
FRESULT f_mkfs (const TCHAR* path, BYTE opt, DWORD au, void* work, UINT len)
|
|
||||||
{
|
|
||||||
TRACE_SIMPGMSPACE("Format SD...");
|
|
||||||
return FR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
FRESULT f_mkdir (const TCHAR * name)
|
|
||||||
{
|
|
||||||
char * path = convertSimuPath(name);
|
|
||||||
#if defined(WIN32) && defined(__GNUC__)
|
|
||||||
if (mkdir(path)) {
|
|
||||||
#else
|
|
||||||
if (mkdir(path, 0777)) {
|
|
||||||
#endif
|
|
||||||
TRACE_SIMPGMSPACE("mkdir(%s) = error %d (%s)", path, errno, strerror(errno));
|
|
||||||
return FR_INVALID_NAME;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
TRACE_SIMPGMSPACE("mkdir(%s) = OK", path);
|
|
||||||
return FR_OK;
|
|
||||||
}
|
|
||||||
return FR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
FRESULT f_unlink (const TCHAR * name)
|
|
||||||
{
|
|
||||||
char * path = convertSimuPath(name);
|
|
||||||
if (unlink(path)) {
|
|
||||||
TRACE_SIMPGMSPACE("f_unlink(%s) = error %d (%s)", path, errno, strerror(errno));
|
|
||||||
return FR_INVALID_NAME;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
TRACE_SIMPGMSPACE("f_unlink(%s) = OK", path);
|
|
||||||
return FR_OK;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
FRESULT f_rename(const TCHAR *oldname, const TCHAR *newname)
|
|
||||||
{
|
|
||||||
char old[1024];
|
|
||||||
strcpy(old, convertSimuPath(oldname));
|
|
||||||
char * path = convertSimuPath(newname);
|
|
||||||
|
|
||||||
if (rename(old, path) < 0) {
|
|
||||||
TRACE_SIMPGMSPACE("f_rename(%s, %s) = error %d (%s)", old, path, errno, strerror(errno));
|
|
||||||
return FR_INVALID_NAME;
|
|
||||||
}
|
|
||||||
TRACE_SIMPGMSPACE("f_rename(%s, %s) = OK", old, path);
|
|
||||||
return FR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
FRESULT f_utime(const TCHAR* path, const FILINFO* fno)
|
|
||||||
{
|
|
||||||
if (fno == NULL)
|
|
||||||
return FR_INVALID_PARAMETER;
|
|
||||||
|
|
||||||
char *simpath = convertSimuPath(path);
|
|
||||||
char *realPath = findTrueFileName(simpath);
|
|
||||||
struct utimbuf newTimes;
|
|
||||||
struct tm ltime;
|
|
||||||
|
|
||||||
// convert from FatFs fdate/ftime
|
|
||||||
ltime.tm_year = ((fno->fdate >> 9) & 0x7F) + 80;
|
|
||||||
ltime.tm_mon = ((fno->fdate >> 5) & 0xF) - 1;
|
|
||||||
ltime.tm_mday = (fno->fdate & 0x1F);
|
|
||||||
ltime.tm_hour = ((fno->ftime >> 11) & 0x1F);
|
|
||||||
ltime.tm_min = ((fno->ftime >> 5) & 0x3F);
|
|
||||||
ltime.tm_sec = (fno->ftime & 0x1F) * 2;
|
|
||||||
ltime.tm_isdst = -1; // force mktime() to check dst
|
|
||||||
|
|
||||||
newTimes.modtime = mktime(<ime);
|
|
||||||
newTimes.actime = newTimes.modtime;
|
|
||||||
|
|
||||||
if (utime(realPath, &newTimes)) {
|
|
||||||
TRACE_SIMPGMSPACE("f_utime(%s) = error %d (%s)", simpath, errno, strerror(errno));
|
|
||||||
return FR_DENIED;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
TRACE_SIMPGMSPACE("f_utime(%s) set mtime = %s", simpath, ctime(&newTimes.modtime));
|
|
||||||
return FR_OK;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int f_putc (TCHAR c, FIL * fil)
|
|
||||||
{
|
|
||||||
if (fil && fil->obj.fs) fwrite(&c, 1, 1, (FILE*)fil->obj.fs);
|
|
||||||
return FR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
int f_puts (const TCHAR * str, FIL * fil)
|
|
||||||
{
|
|
||||||
int n;
|
|
||||||
for (n = 0; *str; str++, n++) {
|
|
||||||
if (f_putc(*str, fil) == EOF) return EOF;
|
|
||||||
}
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
int f_printf (FIL *fil, const TCHAR * format, ...)
|
|
||||||
{
|
|
||||||
va_list arglist;
|
|
||||||
va_start(arglist, format);
|
|
||||||
if (fil && fil->obj.fs) vfprintf((FILE*)fil->obj.fs, format, arglist);
|
|
||||||
va_end(arglist);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
FRESULT f_getcwd (TCHAR *path, UINT sz_path)
|
|
||||||
{
|
|
||||||
char cwd[1024];
|
|
||||||
size_t sdlen = strlen(simuSdDirectory);
|
|
||||||
if (!getcwd(cwd, 1024)) {
|
|
||||||
TRACE_SIMPGMSPACE("f_getcwd() = getcwd() error %d (%s)", errno, strerror(errno));
|
|
||||||
strcpy(path, ".");
|
|
||||||
return FR_NO_PATH;
|
|
||||||
}
|
|
||||||
size_t cwdlen = strlen(cwd);
|
|
||||||
|
|
||||||
if (cwdlen < sdlen) {
|
|
||||||
TRACE_SIMPGMSPACE("f_getcwd() = logic error strlen(cwd) < strlen(simuSdDirectory): cwd: \"%s\", simuSdDirectory: \"%s\"", cwd, simuSdDirectory);
|
|
||||||
strcpy(path, ".");
|
|
||||||
return FR_NO_PATH;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sz_path < (cwdlen - sdlen)) {
|
|
||||||
//TRACE_SIMPGMSPACE("f_getcwd(): buffer too short");
|
|
||||||
return FR_NOT_ENOUGH_CORE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove simuSdDirectory from the cwd
|
|
||||||
strcpy(path, cwd + sdlen);
|
|
||||||
|
|
||||||
if (path[0] == '\0') {
|
|
||||||
strcpy(path, "/"); // fix for the root directory
|
|
||||||
}
|
|
||||||
|
|
||||||
TRACE_SIMPGMSPACE("f_getcwd() = %s", path);
|
|
||||||
return FR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
FRESULT f_getfree (const TCHAR* path, DWORD* nclst, FATFS** fatfs)
|
|
||||||
{
|
|
||||||
// just fake that we always have some clusters free
|
|
||||||
*nclst = 10;
|
|
||||||
return FR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(PCBSKY9X)
|
|
||||||
int32_t Card_state = SD_ST_MOUNTED;
|
|
||||||
uint32_t Card_CSD[4]; // TODO elsewhere
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // #if defined(SIMU_USE_SDCARD)
|
|
||||||
|
|
||||||
|
|
||||||
#if defined(SIMU_DISKIO)
|
|
||||||
#include "FatFs/diskio.h"
|
|
||||||
#include <time.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#if defined(CPUARM)
|
|
||||||
FATFS g_FATFS_Obj = { 0};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
pthread_mutex_t ioMutex;
|
|
||||||
|
|
||||||
int ff_cre_syncobj (BYTE vol, _SYNC_t* sobj) /* Create a sync object */
|
|
||||||
{
|
|
||||||
pthread_mutex_init(&ioMutex, 0);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ff_req_grant (_SYNC_t sobj) /* Lock sync object */
|
|
||||||
{
|
|
||||||
pthread_mutex_lock(&ioMutex);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ff_rel_grant (_SYNC_t sobj) /* Unlock sync object */
|
|
||||||
{
|
|
||||||
pthread_mutex_unlock(&ioMutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
int ff_del_syncobj (_SYNC_t sobj) /* Delete a sync object */
|
|
||||||
{
|
|
||||||
pthread_mutex_destroy(&ioMutex);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
DWORD get_fattime (void)
|
|
||||||
{
|
|
||||||
time_t tim = time(0);
|
|
||||||
const struct tm * t = gmtime(&tim);
|
|
||||||
|
|
||||||
/* Pack date and time into a DWORD variable */
|
|
||||||
return ((DWORD)(t->tm_year - 80) << 25)
|
|
||||||
| ((uint32_t)(t->tm_mon+1) << 21)
|
|
||||||
| ((uint32_t)t->tm_mday << 16)
|
|
||||||
| ((uint32_t)t->tm_hour << 11)
|
|
||||||
| ((uint32_t)t->tm_min << 5)
|
|
||||||
| ((uint32_t)t->tm_sec >> 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int noDiskStatus = 0;
|
|
||||||
|
|
||||||
void traceDiskStatus()
|
|
||||||
{
|
|
||||||
if (noDiskStatus > 0) {
|
|
||||||
TRACE_SIMPGMSPACE("disk_status() called %d times", noDiskStatus);
|
|
||||||
noDiskStatus = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DSTATUS disk_initialize (BYTE pdrv)
|
|
||||||
{
|
|
||||||
traceDiskStatus();
|
|
||||||
TRACE_SIMPGMSPACE("disk_initialize(%u)", pdrv);
|
|
||||||
diskImage = fopen("sdcard.image", "r+");
|
|
||||||
return diskImage ? (DSTATUS)0 : (DSTATUS)STA_NODISK;
|
|
||||||
}
|
|
||||||
|
|
||||||
DSTATUS disk_status (BYTE pdrv)
|
|
||||||
{
|
|
||||||
++noDiskStatus;
|
|
||||||
// TRACE_SIMPGMSPACE("disk_status(%u)", pdrv);
|
|
||||||
return (DSTATUS)0;
|
|
||||||
}
|
|
||||||
|
|
||||||
DRESULT __disk_read (BYTE pdrv, BYTE* buff, DWORD sector, UINT count)
|
|
||||||
{
|
|
||||||
if (diskImage == 0) return RES_NOTRDY;
|
|
||||||
traceDiskStatus();
|
|
||||||
TRACE_SIMPGMSPACE("disk_read(%u, %p, %u, %u)", pdrv, buff, sector, count);
|
|
||||||
fseek(diskImage, sector*512, SEEK_SET);
|
|
||||||
fread(buff, count, 512, diskImage);
|
|
||||||
return RES_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
DRESULT __disk_write (BYTE pdrv, const BYTE* buff, DWORD sector, UINT count)
|
|
||||||
{
|
|
||||||
if (diskImage == 0) return RES_NOTRDY;
|
|
||||||
traceDiskStatus();
|
|
||||||
TRACE_SIMPGMSPACE("disk_write(%u, %p, %u, %u)", pdrv, buff, sector, count);
|
|
||||||
fseek(diskImage, sector*512, SEEK_SET);
|
|
||||||
fwrite(buff, count, 512, diskImage);
|
|
||||||
return RES_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff)
|
|
||||||
{
|
|
||||||
if (diskImage == 0) return RES_NOTRDY;
|
|
||||||
traceDiskStatus();
|
|
||||||
TRACE_SIMPGMSPACE("disk_ioctl(%u, %u, %p)", pdrv, cmd, buff);
|
|
||||||
if (pdrv) return RES_PARERR;
|
|
||||||
|
|
||||||
DRESULT res;
|
|
||||||
BYTE *ptr = (BYTE *)buff;
|
|
||||||
|
|
||||||
if (cmd == CTRL_POWER) {
|
|
||||||
switch (*ptr) {
|
|
||||||
case 0: /* Sub control code == 0 (POWER_OFF) */
|
|
||||||
res = RES_OK;
|
|
||||||
break;
|
|
||||||
case 1: /* Sub control code == 1 (POWER_ON) */
|
|
||||||
res = RES_OK;
|
|
||||||
break;
|
|
||||||
case 2: /* Sub control code == 2 (POWER_GET) */
|
|
||||||
*(ptr+1) = (BYTE)1; /* fake powered */
|
|
||||||
res = RES_OK;
|
|
||||||
break;
|
|
||||||
default :
|
|
||||||
res = RES_PARERR;
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch(cmd) {
|
|
||||||
/* Generic command (Used by FatFs) */
|
|
||||||
case CTRL_SYNC : /* Complete pending write process (needed at _FS_READONLY == 0) */
|
|
||||||
break;
|
|
||||||
|
|
||||||
case GET_SECTOR_COUNT: /* Get media size (needed at _USE_MKFS == 1) */
|
|
||||||
{
|
|
||||||
struct stat buf;
|
|
||||||
if (stat("sdcard.image", &buf) == 0) {
|
|
||||||
DWORD noSectors = buf.st_size / 512;
|
|
||||||
*(DWORD*)buff = noSectors;
|
|
||||||
TRACE_SIMPGMSPACE("disk_ioctl(GET_SECTOR_COUNT) = %u", noSectors);
|
|
||||||
return RES_OK;
|
|
||||||
}
|
|
||||||
return RES_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
case GET_SECTOR_SIZE: /* Get sector size (needed at _MAX_SS != _MIN_SS) */
|
|
||||||
TRACE_SIMPGMSPACE("disk_ioctl(GET_SECTOR_SIZE) = 512");
|
|
||||||
*(WORD*)buff = 512;
|
|
||||||
res = RES_OK;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case GET_BLOCK_SIZE : /* Get erase block size (needed at _USE_MKFS == 1) */
|
|
||||||
*(WORD*)buff = 512 * 4;
|
|
||||||
res = RES_OK;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CTRL_TRIM : /* Inform device that the data on the block of sectors is no longer used (needed at _USE_TRIM == 1) */
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* Generic command (Not used by FatFs) */
|
|
||||||
case CTRL_LOCK : /* Lock/Unlock media removal */
|
|
||||||
case CTRL_EJECT: /* Eject media */
|
|
||||||
case CTRL_FORMAT: /* Create physical format on the media */
|
|
||||||
return RES_PARERR;
|
|
||||||
|
|
||||||
|
|
||||||
/* MMC/SDC specific ioctl command */
|
|
||||||
// case MMC_GET_TYPE 10 /* Get card type */
|
|
||||||
// case MMC_GET_CSD 11 /* Get CSD */
|
|
||||||
// case MMC_GET_CID 12 /* Get CID */
|
|
||||||
// case MMC_GET_OCR 13 /* Get OCR */
|
|
||||||
// case MMC_GET_SDSTAT 14 /* Get SD status */
|
|
||||||
|
|
||||||
/* ATA/CF specific ioctl command */
|
|
||||||
// case ATA_GET_REV 20 /* Get F/W revision */
|
|
||||||
// case ATA_GET_MODEL 21 /* Get model name */
|
|
||||||
// case ATA_GET_SN 22 /* Get serial number */
|
|
||||||
default:
|
|
||||||
return RES_PARERR;
|
|
||||||
}
|
|
||||||
return RES_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
void sdInit(void)
|
|
||||||
{
|
|
||||||
// ioMutex = CoCreateMutex();
|
|
||||||
// if (ioMutex >= CFG_MAX_MUTEX ) {
|
|
||||||
// // sd error
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
|
|
||||||
if (f_mount(&g_FATFS_Obj, "", 1) == FR_OK) {
|
|
||||||
// call sdGetFreeSectors() now because f_getfree() takes a long time first time it's called
|
|
||||||
sdGetFreeSectors();
|
|
||||||
|
|
||||||
#if defined(LOG_TELEMETRY)
|
|
||||||
f_open(&g_telemetryFile, LOGS_PATH "/telemetry.log", FA_OPEN_ALWAYS | FA_WRITE);
|
|
||||||
if (f_size(&g_telemetryFile) > 0) {
|
|
||||||
f_lseek(&g_telemetryFile, f_size(&g_telemetryFile)); // append
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
TRACE_SIMPGMSPACE("f_mount() failed");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void sdDone()
|
|
||||||
{
|
|
||||||
if (sdMounted()) {
|
|
||||||
audioQueue.stopSD();
|
|
||||||
#if defined(LOG_TELEMETRY)
|
|
||||||
f_close(&g_telemetryFile);
|
|
||||||
#endif
|
|
||||||
f_mount(NULL, "", 0); // unmount SD
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t sdMounted()
|
|
||||||
{
|
|
||||||
return g_FATFS_Obj.fs_type != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t sdIsHC()
|
|
||||||
{
|
|
||||||
return sdGetSize() > 2000000;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t sdGetSpeed()
|
|
||||||
{
|
|
||||||
return 330000;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // #if defined(SIMU_DISKIO)
|
|
||||||
|
|
||||||
bool simuLcdRefresh = true;
|
bool simuLcdRefresh = true;
|
||||||
display_t simuLcdBuf[DISPLAY_BUFFER_SIZE];
|
display_t simuLcdBuf[DISPLAY_BUFFER_SIZE];
|
||||||
|
|
||||||
|
|
|
@ -372,7 +372,7 @@ void simuSetKey(uint8_t key, bool state);
|
||||||
void simuSetTrim(uint8_t trim, bool state);
|
void simuSetTrim(uint8_t trim, bool state);
|
||||||
void simuSetSwitch(uint8_t swtch, int8_t state);
|
void simuSetSwitch(uint8_t swtch, int8_t state);
|
||||||
|
|
||||||
void StartSimu(bool tests=true);
|
void StartSimu(bool tests=true, const char * sdPath = 0, const char * settingsPath = 0);
|
||||||
void StopSimu();
|
void StopSimu();
|
||||||
|
|
||||||
void StartEepromThread(const char *filename="eeprom.bin");
|
void StartEepromThread(const char *filename="eeprom.bin");
|
||||||
|
@ -467,8 +467,8 @@ inline void NVIC_Init(NVIC_InitTypeDef *) { }
|
||||||
inline void delay_01us(int dummy) { }
|
inline void delay_01us(int dummy) { }
|
||||||
#define configure_pins(...)
|
#define configure_pins(...)
|
||||||
|
|
||||||
#if defined(SDCARD)
|
#if defined(SDCARD) && !defined(SKIP_FATFS_DECLARATION) && !defined(SIMU_DISKIO)
|
||||||
extern char simuSdDirectory[1024];
|
#define SIMU_USE_SDCARD
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define sdMountPoll()
|
#define sdMountPoll()
|
||||||
|
@ -478,4 +478,17 @@ extern char simuSdDirectory[1024];
|
||||||
#define sdMounted() (true)
|
#define sdMounted() (true)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(SIMU_USE_SDCARD)
|
||||||
|
void simuFatfsSetPaths(const char * sdPath, const char * settingsPath);
|
||||||
|
#else
|
||||||
|
#define simuFatfsSetPaths(...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(TRACE_SIMPGMSPACE)
|
||||||
|
#undef TRACE_SIMPGMSPACE
|
||||||
|
#define TRACE_SIMPGMSPACE TRACE
|
||||||
|
#else
|
||||||
|
#define TRACE_SIMPGMSPACE(...)
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif // _SIMPGMSPACE_H_
|
#endif // _SIMPGMSPACE_H_
|
||||||
|
|
245
radio/src/targets/simu/simudisk.cpp
Normal file
245
radio/src/targets/simu/simudisk.cpp
Normal file
|
@ -0,0 +1,245 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) OpenTX
|
||||||
|
*
|
||||||
|
* Based on code named
|
||||||
|
* th9x - http://code.google.com/p/th9x
|
||||||
|
* er9x - http://code.google.com/p/er9x
|
||||||
|
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||||
|
*
|
||||||
|
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if defined(SIMU_DISKIO)
|
||||||
|
#include "FatFs/diskio.h"
|
||||||
|
#include <time.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
FATFS g_FATFS_Obj = {0};
|
||||||
|
|
||||||
|
pthread_mutex_t ioMutex;
|
||||||
|
|
||||||
|
int ff_cre_syncobj (BYTE vol, _SYNC_t* sobj) /* Create a sync object */
|
||||||
|
{
|
||||||
|
pthread_mutex_init(&ioMutex, 0);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ff_req_grant (_SYNC_t sobj) /* Lock sync object */
|
||||||
|
{
|
||||||
|
pthread_mutex_lock(&ioMutex);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ff_rel_grant (_SYNC_t sobj) /* Unlock sync object */
|
||||||
|
{
|
||||||
|
pthread_mutex_unlock(&ioMutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ff_del_syncobj (_SYNC_t sobj) /* Delete a sync object */
|
||||||
|
{
|
||||||
|
pthread_mutex_destroy(&ioMutex);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD get_fattime (void)
|
||||||
|
{
|
||||||
|
time_t tim = time(0);
|
||||||
|
const struct tm * t = gmtime(&tim);
|
||||||
|
|
||||||
|
/* Pack date and time into a DWORD variable */
|
||||||
|
return ((DWORD)(t->tm_year - 80) << 25)
|
||||||
|
| ((uint32_t)(t->tm_mon+1) << 21)
|
||||||
|
| ((uint32_t)t->tm_mday << 16)
|
||||||
|
| ((uint32_t)t->tm_hour << 11)
|
||||||
|
| ((uint32_t)t->tm_min << 5)
|
||||||
|
| ((uint32_t)t->tm_sec >> 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int noDiskStatus = 0;
|
||||||
|
|
||||||
|
void traceDiskStatus()
|
||||||
|
{
|
||||||
|
if (noDiskStatus > 0) {
|
||||||
|
TRACE_SIMPGMSPACE("disk_status() called %d times", noDiskStatus);
|
||||||
|
noDiskStatus = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DSTATUS disk_initialize (BYTE pdrv)
|
||||||
|
{
|
||||||
|
traceDiskStatus();
|
||||||
|
TRACE_SIMPGMSPACE("disk_initialize(%u)", pdrv);
|
||||||
|
diskImage = fopen("sdcard.image", "r+");
|
||||||
|
return diskImage ? (DSTATUS)0 : (DSTATUS)STA_NODISK;
|
||||||
|
}
|
||||||
|
|
||||||
|
DSTATUS disk_status (BYTE pdrv)
|
||||||
|
{
|
||||||
|
++noDiskStatus;
|
||||||
|
// TRACE_SIMPGMSPACE("disk_status(%u)", pdrv);
|
||||||
|
return (DSTATUS)0;
|
||||||
|
}
|
||||||
|
|
||||||
|
DRESULT __disk_read (BYTE pdrv, BYTE* buff, DWORD sector, UINT count)
|
||||||
|
{
|
||||||
|
if (diskImage == 0) return RES_NOTRDY;
|
||||||
|
traceDiskStatus();
|
||||||
|
TRACE_SIMPGMSPACE("disk_read(%u, %p, %u, %u)", pdrv, buff, sector, count);
|
||||||
|
fseek(diskImage, sector*512, SEEK_SET);
|
||||||
|
fread(buff, count, 512, diskImage);
|
||||||
|
return RES_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
DRESULT __disk_write (BYTE pdrv, const BYTE* buff, DWORD sector, UINT count)
|
||||||
|
{
|
||||||
|
if (diskImage == 0) return RES_NOTRDY;
|
||||||
|
traceDiskStatus();
|
||||||
|
TRACE_SIMPGMSPACE("disk_write(%u, %p, %u, %u)", pdrv, buff, sector, count);
|
||||||
|
fseek(diskImage, sector*512, SEEK_SET);
|
||||||
|
fwrite(buff, count, 512, diskImage);
|
||||||
|
return RES_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff)
|
||||||
|
{
|
||||||
|
if (diskImage == 0) return RES_NOTRDY;
|
||||||
|
traceDiskStatus();
|
||||||
|
TRACE_SIMPGMSPACE("disk_ioctl(%u, %u, %p)", pdrv, cmd, buff);
|
||||||
|
if (pdrv) return RES_PARERR;
|
||||||
|
|
||||||
|
DRESULT res;
|
||||||
|
BYTE *ptr = (BYTE *)buff;
|
||||||
|
|
||||||
|
if (cmd == CTRL_POWER) {
|
||||||
|
switch (*ptr) {
|
||||||
|
case 0: /* Sub control code == 0 (POWER_OFF) */
|
||||||
|
res = RES_OK;
|
||||||
|
break;
|
||||||
|
case 1: /* Sub control code == 1 (POWER_ON) */
|
||||||
|
res = RES_OK;
|
||||||
|
break;
|
||||||
|
case 2: /* Sub control code == 2 (POWER_GET) */
|
||||||
|
*(ptr+1) = (BYTE)1; /* fake powered */
|
||||||
|
res = RES_OK;
|
||||||
|
break;
|
||||||
|
default :
|
||||||
|
res = RES_PARERR;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(cmd) {
|
||||||
|
/* Generic command (Used by FatFs) */
|
||||||
|
case CTRL_SYNC : /* Complete pending write process (needed at _FS_READONLY == 0) */
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GET_SECTOR_COUNT: /* Get media size (needed at _USE_MKFS == 1) */
|
||||||
|
{
|
||||||
|
struct stat buf;
|
||||||
|
if (stat("sdcard.image", &buf) == 0) {
|
||||||
|
DWORD noSectors = buf.st_size / 512;
|
||||||
|
*(DWORD*)buff = noSectors;
|
||||||
|
TRACE_SIMPGMSPACE("disk_ioctl(GET_SECTOR_COUNT) = %u", noSectors);
|
||||||
|
return RES_OK;
|
||||||
|
}
|
||||||
|
return RES_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
case GET_SECTOR_SIZE: /* Get sector size (needed at _MAX_SS != _MIN_SS) */
|
||||||
|
TRACE_SIMPGMSPACE("disk_ioctl(GET_SECTOR_SIZE) = 512");
|
||||||
|
*(WORD*)buff = 512;
|
||||||
|
res = RES_OK;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GET_BLOCK_SIZE : /* Get erase block size (needed at _USE_MKFS == 1) */
|
||||||
|
*(WORD*)buff = 512 * 4;
|
||||||
|
res = RES_OK;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CTRL_TRIM : /* Inform device that the data on the block of sectors is no longer used (needed at _USE_TRIM == 1) */
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Generic command (Not used by FatFs) */
|
||||||
|
case CTRL_LOCK : /* Lock/Unlock media removal */
|
||||||
|
case CTRL_EJECT: /* Eject media */
|
||||||
|
case CTRL_FORMAT: /* Create physical format on the media */
|
||||||
|
return RES_PARERR;
|
||||||
|
|
||||||
|
|
||||||
|
/* MMC/SDC specific ioctl command */
|
||||||
|
// case MMC_GET_TYPE 10 /* Get card type */
|
||||||
|
// case MMC_GET_CSD 11 /* Get CSD */
|
||||||
|
// case MMC_GET_CID 12 /* Get CID */
|
||||||
|
// case MMC_GET_OCR 13 /* Get OCR */
|
||||||
|
// case MMC_GET_SDSTAT 14 /* Get SD status */
|
||||||
|
|
||||||
|
/* ATA/CF specific ioctl command */
|
||||||
|
// case ATA_GET_REV 20 /* Get F/W revision */
|
||||||
|
// case ATA_GET_MODEL 21 /* Get model name */
|
||||||
|
// case ATA_GET_SN 22 /* Get serial number */
|
||||||
|
default:
|
||||||
|
return RES_PARERR;
|
||||||
|
}
|
||||||
|
return RES_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sdInit(void)
|
||||||
|
{
|
||||||
|
// ioMutex = CoCreateMutex();
|
||||||
|
// if (ioMutex >= CFG_MAX_MUTEX ) {
|
||||||
|
// // sd error
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
|
||||||
|
if (f_mount(&g_FATFS_Obj, "", 1) == FR_OK) {
|
||||||
|
// call sdGetFreeSectors() now because f_getfree() takes a long time first time it's called
|
||||||
|
sdGetFreeSectors();
|
||||||
|
|
||||||
|
#if defined(LOG_TELEMETRY)
|
||||||
|
f_open(&g_telemetryFile, LOGS_PATH "/telemetry.log", FA_OPEN_ALWAYS | FA_WRITE);
|
||||||
|
if (f_size(&g_telemetryFile) > 0) {
|
||||||
|
f_lseek(&g_telemetryFile, f_size(&g_telemetryFile)); // append
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
TRACE_SIMPGMSPACE("f_mount() failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void sdDone()
|
||||||
|
{
|
||||||
|
if (sdMounted()) {
|
||||||
|
audioQueue.stopSD();
|
||||||
|
#if defined(LOG_TELEMETRY)
|
||||||
|
f_close(&g_telemetryFile);
|
||||||
|
#endif
|
||||||
|
f_mount(NULL, "", 0); // unmount SD
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t sdMounted()
|
||||||
|
{
|
||||||
|
return g_FATFS_Obj.fs_type != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t sdIsHC()
|
||||||
|
{
|
||||||
|
return sdGetSize() > 2000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t sdGetSpeed()
|
||||||
|
{
|
||||||
|
return 330000;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // #if defined(SIMU_DISKIO)
|
|
@ -134,7 +134,11 @@ void eepromWriteBlock(uint8_t * buffer, size_t address, size_t size)
|
||||||
eepromStartWrite(buffer, address, size);
|
eepromStartWrite(buffer, address, size);
|
||||||
|
|
||||||
while (!eepromIsTransferComplete()) {
|
while (!eepromIsTransferComplete()) {
|
||||||
|
#if defined(GTESTS)
|
||||||
|
sleep(0/*ms*/);
|
||||||
|
#else
|
||||||
sleep(1/*ms*/);
|
sleep(1/*ms*/);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
554
radio/src/targets/simu/simufatfs.cpp
Normal file
554
radio/src/targets/simu/simufatfs.cpp
Normal file
|
@ -0,0 +1,554 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) OpenTX
|
||||||
|
*
|
||||||
|
* Based on code named
|
||||||
|
* th9x - http://code.google.com/p/th9x
|
||||||
|
* er9x - http://code.google.com/p/er9x
|
||||||
|
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||||
|
*
|
||||||
|
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "opentx.h"
|
||||||
|
|
||||||
|
#if defined _MSC_VER || !defined (__GNUC__)
|
||||||
|
#define WINDOWS_BUILD
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(SIMU_USE_SDCARD)
|
||||||
|
#if defined(WINDOWS_BUILD)
|
||||||
|
#include <direct.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/utime.h>
|
||||||
|
#define mkdir(s, f) _mkdir(s)
|
||||||
|
#else
|
||||||
|
#include <utime.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include "ff.h"
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace simu {
|
||||||
|
#include <dirent.h>
|
||||||
|
#if !defined(_MSC_VER)
|
||||||
|
#include <libgen.h>
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string simuSdDirectory; // path to the root of the SD card image
|
||||||
|
std::string simuSettingsDirectory; // path to the root of the models and settings (only for the radios that use SD for model storage)
|
||||||
|
|
||||||
|
bool isPathDelimiter(char delimiter)
|
||||||
|
{
|
||||||
|
return (delimiter == '/' || delimiter == '\\');
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string removeTrailingPathDelimiter(const char * path)
|
||||||
|
{
|
||||||
|
std::string result = path;
|
||||||
|
while (!result.empty() && isPathDelimiter(result.back())) {
|
||||||
|
result.pop_back();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void simuFatfsSetPaths(const char * sdPath, const char * settingsPath)
|
||||||
|
{
|
||||||
|
if (sdPath) {
|
||||||
|
simuSdDirectory = removeTrailingPathDelimiter(sdPath);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
char buff[1024];
|
||||||
|
f_getcwd(buff, sizeof(buff)-1);
|
||||||
|
simuSdDirectory = removeTrailingPathDelimiter(buff);
|
||||||
|
}
|
||||||
|
if (settingsPath) {
|
||||||
|
simuSettingsDirectory = removeTrailingPathDelimiter(settingsPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool startsWith(const char *path, const char * start)
|
||||||
|
{
|
||||||
|
return strncasecmp(path, start, strlen(start)) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string convertToSimuPath(const char *path)
|
||||||
|
{
|
||||||
|
std::string result;
|
||||||
|
if (isPathDelimiter(path[0])) {
|
||||||
|
if (!simuSettingsDirectory.empty() && (startsWith(path, "/MODELS") || startsWith(path, "/RADIO"))) {
|
||||||
|
result = simuSettingsDirectory + std::string(path);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
result = simuSdDirectory + std::string(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
result = std::string(path);
|
||||||
|
}
|
||||||
|
TRACE("convertToSimuPath(): %s -> %s", path, result.c_str());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string convertFromSimuPath(const char *path)
|
||||||
|
{
|
||||||
|
std::string result;
|
||||||
|
if (startsWith(path, simuSdDirectory.c_str())) {
|
||||||
|
result = std::string(path).substr(simuSdDirectory.length(), std::string::npos);
|
||||||
|
if (result.empty()) {
|
||||||
|
result = "/";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
result = std::string(path);
|
||||||
|
if (!result.empty() && !isPathDelimiter(result[0])) {
|
||||||
|
result = "/" + result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TRACE("convertFromSimuPath(): %s -> %s", path, result.c_str());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef std::map<std::string, std::string> filemap_t;
|
||||||
|
|
||||||
|
filemap_t fileMap;
|
||||||
|
|
||||||
|
void splitPath(const std::string & path, std::string & dir, std::string & name)
|
||||||
|
{
|
||||||
|
#if defined(WINDOWS_BUILD)
|
||||||
|
char drive[_MAX_DRIVE];
|
||||||
|
char dir[_MAX_DIR];
|
||||||
|
char fname[_MAX_FNAME];
|
||||||
|
char ext[_MAX_EXT];
|
||||||
|
_splitpath(path.c_str(), drive, dir, fname, ext);
|
||||||
|
name = std::string(fname) + std::string(ext);
|
||||||
|
dir = std::string(drive) + std::string(dir);
|
||||||
|
std::string searchName = dirName + "*";
|
||||||
|
#else
|
||||||
|
char * buff = new char[path.length()+1];
|
||||||
|
strcpy(buff, path.c_str());
|
||||||
|
name = simu::basename(buff);
|
||||||
|
strcpy(buff, path.c_str());
|
||||||
|
dir = simu::dirname(buff);
|
||||||
|
delete[] buff;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool isFile(const std::string & fullName, unsigned char d_type)
|
||||||
|
{
|
||||||
|
#if defined(WIN32) || defined(__APPLE__) || defined(__FreeBSD__)
|
||||||
|
#define REGULAR_FILE DT_REG
|
||||||
|
#define SYMBOLIC_LINK DT_LNK
|
||||||
|
#else
|
||||||
|
#define REGULAR_FILE simu::DT_REG
|
||||||
|
#define SYMBOLIC_LINK simu::DT_LNK
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (d_type == REGULAR_FILE) return true;
|
||||||
|
if (d_type == SYMBOLIC_LINK) {
|
||||||
|
struct stat tmp;
|
||||||
|
if (stat(fullName.c_str(), &tmp) == 0) {
|
||||||
|
// TRACE_SIMPGMSPACE("\tsymlik: %s is %s", fullName.c_str(), (tmp.st_mode & S_IFREG) ? "file" : "other");
|
||||||
|
if (tmp.st_mode & S_IFREG) return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> listDirectoryFiles(const std::string & dirName)
|
||||||
|
{
|
||||||
|
std::vector<std::string> result;
|
||||||
|
|
||||||
|
#if defined (WINDOWS_BUILD)
|
||||||
|
std::string searchName = dirName + "*";
|
||||||
|
// TRACE_SIMPGMSPACE("\tsearching for: %s", fileName.c_str());
|
||||||
|
WIN32_FIND_DATA ffd;
|
||||||
|
HANDLE hFind = FindFirstFile(searchName.c_str(), &ffd);
|
||||||
|
if (INVALID_HANDLE_VALUE != hFind) {
|
||||||
|
do {
|
||||||
|
if (!(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
|
||||||
|
//TRACE_SIMPGMSPACE("comparing with: %s", ffd.cFileName);
|
||||||
|
if (!strcasecmp(fileName.c_str(), ffd.cFileName)) {
|
||||||
|
std::string fullName = dirName + std::string(ffd.cFileName);
|
||||||
|
// TRACE_SIMPGMSPACE("listDirectoryFiles(): %s", fullName.c_str());
|
||||||
|
result.push_back(fullName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (FindNextFile(hFind, &ffd) != 0);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
simu::DIR * dir = simu::opendir(dirName.c_str());
|
||||||
|
if (dir) {
|
||||||
|
struct simu::dirent * res;
|
||||||
|
while ((res = simu::readdir(dir)) != 0) {
|
||||||
|
std::string fullName = dirName + "/" + std::string(res->d_name);
|
||||||
|
if (isFile(fullName, res->d_type)) {
|
||||||
|
// TRACE_SIMPGMSPACE("listDirectoryFiles(): %s", fullName.c_str());
|
||||||
|
result.push_back(fullName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
simu::closedir(dir);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string findTrueFileName(const std::string & path)
|
||||||
|
{
|
||||||
|
TRACE_SIMPGMSPACE("findTrueFileName(%s)", path.c_str());
|
||||||
|
std::string result;
|
||||||
|
filemap_t::iterator i = fileMap.find(path);
|
||||||
|
if (i != fileMap.end()) {
|
||||||
|
result = i->second;
|
||||||
|
TRACE_SIMPGMSPACE("\tfound in map: %s", result.c_str());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
//find file and add to map
|
||||||
|
std::string dirName;
|
||||||
|
std::string fileName;
|
||||||
|
splitPath(path, dirName, fileName);
|
||||||
|
std::vector<std::string> files = listDirectoryFiles(dirName);
|
||||||
|
for(unsigned int i=0; i<files.size(); ++i) {
|
||||||
|
if (!strcasecmp(files[i].c_str(), path.c_str())) {
|
||||||
|
TRACE_SIMPGMSPACE("\tfound: %s", files[i].c_str());
|
||||||
|
fileMap.insert(filemap_t::value_type(path, files[i]));
|
||||||
|
return files[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TRACE_SIMPGMSPACE("\tnot found");
|
||||||
|
return std::string(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
FRESULT f_stat (const TCHAR * name, FILINFO *fno)
|
||||||
|
{
|
||||||
|
std::string path = convertToSimuPath(name);
|
||||||
|
std::string realPath = findTrueFileName(path);
|
||||||
|
struct stat tmp;
|
||||||
|
if (stat(realPath.c_str(), &tmp)) {
|
||||||
|
TRACE_SIMPGMSPACE("f_stat(%s) = error %d (%s)", path.c_str(), errno, strerror(errno));
|
||||||
|
return FR_INVALID_NAME;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
TRACE_SIMPGMSPACE("f_stat(%s) = OK", path.c_str());
|
||||||
|
if (fno) {
|
||||||
|
fno->fattrib = (tmp.st_mode & S_IFDIR) ? AM_DIR : 0;
|
||||||
|
// convert to FatFs fdate/ftime
|
||||||
|
struct tm *ltime = localtime(&tmp.st_mtime);
|
||||||
|
fno->fdate = ((ltime->tm_year - 80) << 9) | ((ltime->tm_mon + 1) << 5) | ltime->tm_mday;
|
||||||
|
fno->ftime = (ltime->tm_hour << 11) | (ltime->tm_min << 5) | (ltime->tm_sec / 2);
|
||||||
|
fno->fsize = (DWORD)tmp.st_size;
|
||||||
|
}
|
||||||
|
return FR_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FRESULT f_mount (FATFS* ,const TCHAR*, BYTE opt)
|
||||||
|
{
|
||||||
|
return FR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
FRESULT f_open (FIL * fil, const TCHAR *name, BYTE flag)
|
||||||
|
{
|
||||||
|
std::string path = convertToSimuPath(name);
|
||||||
|
std::string realPath = findTrueFileName(path);
|
||||||
|
fil->obj.fs = 0;
|
||||||
|
if (!(flag & FA_WRITE)) {
|
||||||
|
struct stat tmp;
|
||||||
|
if (stat(realPath.c_str(), &tmp)) {
|
||||||
|
TRACE_SIMPGMSPACE("f_open(%s) = INVALID_NAME (FIL %p)", path.c_str(), fil);
|
||||||
|
return FR_INVALID_NAME;
|
||||||
|
}
|
||||||
|
fil->obj.objsize = tmp.st_size;
|
||||||
|
fil->fptr = 0;
|
||||||
|
}
|
||||||
|
fil->obj.fs = (FATFS*)fopen(realPath.c_str(), (flag & FA_WRITE) ? ((flag & FA_CREATE_ALWAYS) ? "wb+" : "ab+") : "rb+");
|
||||||
|
fil->fptr = 0;
|
||||||
|
if (fil->obj.fs) {
|
||||||
|
TRACE_SIMPGMSPACE("f_open(%s, %x) = %p (FIL %p)", path.c_str(), flag, fil->obj.fs, fil);
|
||||||
|
return FR_OK;
|
||||||
|
}
|
||||||
|
TRACE_SIMPGMSPACE("f_open(%s) = error %d (%s) (FIL %p)", path.c_str(), errno, strerror(errno), fil);
|
||||||
|
return FR_INVALID_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
FRESULT f_read (FIL* fil, void* data, UINT size, UINT* read)
|
||||||
|
{
|
||||||
|
if (fil && fil->obj.fs) {
|
||||||
|
*read = fread(data, 1, size, (FILE*)fil->obj.fs);
|
||||||
|
fil->fptr += *read;
|
||||||
|
// TRACE_SIMPGMSPACE("fread(%p) %u, %u", fil->obj.fs, size, *read);
|
||||||
|
}
|
||||||
|
return FR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
FRESULT f_write (FIL* fil, const void* data, UINT size, UINT* written)
|
||||||
|
{
|
||||||
|
if (fil && fil->obj.fs) {
|
||||||
|
*written = fwrite(data, 1, size, (FILE*)fil->obj.fs);
|
||||||
|
fil->fptr += size;
|
||||||
|
// TRACE_SIMPGMSPACE("fwrite(%p) %u, %u", fil->obj.fs, size, *written);
|
||||||
|
}
|
||||||
|
return FR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
TCHAR * f_gets (TCHAR* buff, int len, FIL* fil)
|
||||||
|
{
|
||||||
|
if (fil && fil->obj.fs) {
|
||||||
|
buff = fgets(buff, len, (FILE*)fil->obj.fs);
|
||||||
|
if (buff != NULL) {
|
||||||
|
fil->fptr = *buff;
|
||||||
|
}
|
||||||
|
// TRACE_SIMPGMSPACE("fgets(%p) %u, %s", fil->obj.fs, len, buff);
|
||||||
|
}
|
||||||
|
return buff;
|
||||||
|
}
|
||||||
|
|
||||||
|
FRESULT f_lseek (FIL* fil, DWORD offset)
|
||||||
|
{
|
||||||
|
if (fil && fil->obj.fs) fseek((FILE*)fil->obj.fs, offset, SEEK_SET);
|
||||||
|
fil->fptr = offset;
|
||||||
|
return FR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT f_size(FIL* fil)
|
||||||
|
{
|
||||||
|
if (fil && fil->obj.fs) {
|
||||||
|
long curr = ftell((FILE*)fil->obj.fs);
|
||||||
|
fseek((FILE*)fil->obj.fs, 0, SEEK_END);
|
||||||
|
long size = ftell((FILE*)fil->obj.fs);
|
||||||
|
fseek((FILE*)fil->obj.fs, curr, SEEK_SET);
|
||||||
|
TRACE_SIMPGMSPACE("f_size(%p) %u", fil->obj.fs, size);
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
FRESULT f_close (FIL * fil)
|
||||||
|
{
|
||||||
|
TRACE_SIMPGMSPACE("f_close(%p) (FIL:%p)", fil->obj.fs, fil);
|
||||||
|
if (fil->obj.fs) {
|
||||||
|
fclose((FILE*)fil->obj.fs);
|
||||||
|
fil->obj.fs = NULL;
|
||||||
|
}
|
||||||
|
return FR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
FRESULT f_chdir (const TCHAR *name)
|
||||||
|
{
|
||||||
|
std::string path = convertToSimuPath(name);
|
||||||
|
if (chdir(path.c_str())) {
|
||||||
|
TRACE_SIMPGMSPACE("f_chdir(%s) = error %d (%s)", path.c_str(), errno, strerror(errno));
|
||||||
|
return FR_NO_PATH;
|
||||||
|
}
|
||||||
|
TRACE_SIMPGMSPACE("f_chdir(%s)", path.c_str());
|
||||||
|
return FR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
FRESULT f_opendir (DIR * rep, const TCHAR * name)
|
||||||
|
{
|
||||||
|
std::string path = convertToSimuPath(name);
|
||||||
|
rep->obj.fs = (FATFS *)simu::opendir(path.c_str());
|
||||||
|
if (rep->obj.fs) {
|
||||||
|
TRACE_SIMPGMSPACE("f_opendir(%s) = OK", path.c_str());
|
||||||
|
return FR_OK;
|
||||||
|
}
|
||||||
|
TRACE_SIMPGMSPACE("f_opendir(%s) = error %d (%s)", path.c_str(), errno, strerror(errno));
|
||||||
|
return FR_NO_PATH;
|
||||||
|
}
|
||||||
|
|
||||||
|
FRESULT f_closedir (DIR * rep)
|
||||||
|
{
|
||||||
|
TRACE_SIMPGMSPACE("f_closedir(%p)", rep);
|
||||||
|
if (rep->obj.fs) simu::closedir((simu::DIR *)rep->obj.fs);
|
||||||
|
return FR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
FRESULT f_readdir (DIR * rep, FILINFO * fil)
|
||||||
|
{
|
||||||
|
simu::dirent * ent;
|
||||||
|
if (!rep->obj.fs) return FR_NO_FILE;
|
||||||
|
for(;;) {
|
||||||
|
ent = simu::readdir((simu::DIR *)rep->obj.fs);
|
||||||
|
if (!ent) return FR_NO_FILE;
|
||||||
|
if (strcmp(ent->d_name, ".") && strcmp(ent->d_name, "..") ) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(WIN32) || !defined(__GNUC__) || defined(__APPLE__) || defined(__FreeBSD__)
|
||||||
|
fil->fattrib = (ent->d_type == DT_DIR ? AM_DIR : 0);
|
||||||
|
#else
|
||||||
|
if (ent->d_type == simu::DT_UNKNOWN || ent->d_type == simu::DT_LNK) {
|
||||||
|
fil->fattrib = 0;
|
||||||
|
struct stat buf;
|
||||||
|
if (stat(ent->d_name, &buf) == 0) {
|
||||||
|
fil->fattrib = (S_ISDIR(buf.st_mode) ? AM_DIR : 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fil->fattrib = (ent->d_type == simu::DT_DIR ? AM_DIR : 0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
memset(fil->fname, 0, SD_SCREEN_FILE_LENGTH);
|
||||||
|
strcpy(fil->fname, ent->d_name);
|
||||||
|
// TRACE_SIMPGMSPACE("f_readdir(): %s", fil->fname);
|
||||||
|
return FR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
FRESULT f_mkfs (const TCHAR* path, BYTE opt, DWORD au, void* work, UINT len)
|
||||||
|
{
|
||||||
|
TRACE_SIMPGMSPACE("Format SD...");
|
||||||
|
return FR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
FRESULT f_mkdir (const TCHAR * name)
|
||||||
|
{
|
||||||
|
std::string path = convertToSimuPath(name);
|
||||||
|
#if defined(WIN32) && defined(__GNUC__)
|
||||||
|
if (mkdir(path.c_str())) {
|
||||||
|
#else
|
||||||
|
if (mkdir(path.c_str(), 0777)) {
|
||||||
|
#endif
|
||||||
|
TRACE_SIMPGMSPACE("mkdir(%s) = error %d (%s)", path.c_str(), errno, strerror(errno));
|
||||||
|
return FR_INVALID_NAME;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
TRACE_SIMPGMSPACE("mkdir(%s) = OK", path.c_str());
|
||||||
|
return FR_OK;
|
||||||
|
}
|
||||||
|
return FR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
FRESULT f_unlink (const TCHAR * name)
|
||||||
|
{
|
||||||
|
std::string path = convertToSimuPath(name);
|
||||||
|
if (unlink(path.c_str())) {
|
||||||
|
TRACE_SIMPGMSPACE("f_unlink(%s) = error %d (%s)", path.c_str(), errno, strerror(errno));
|
||||||
|
return FR_INVALID_NAME;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
TRACE_SIMPGMSPACE("f_unlink(%s) = OK", path.c_str());
|
||||||
|
return FR_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FRESULT f_rename(const TCHAR *oldname, const TCHAR *newname)
|
||||||
|
{
|
||||||
|
std::string old = convertToSimuPath(oldname);
|
||||||
|
std::string path = convertToSimuPath(newname);
|
||||||
|
|
||||||
|
if (rename(old.c_str(), path.c_str()) < 0) {
|
||||||
|
TRACE_SIMPGMSPACE("f_rename(%s, %s) = error %d (%s)", old.c_str(), path.c_str(), errno, strerror(errno));
|
||||||
|
return FR_INVALID_NAME;
|
||||||
|
}
|
||||||
|
TRACE_SIMPGMSPACE("f_rename(%s, %s) = OK", old.c_str(), path.c_str());
|
||||||
|
return FR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
FRESULT f_utime(const TCHAR* path, const FILINFO* fno)
|
||||||
|
{
|
||||||
|
if (fno == NULL)
|
||||||
|
return FR_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
std::string simpath = convertToSimuPath(path);
|
||||||
|
std::string realPath = findTrueFileName(simpath);
|
||||||
|
struct utimbuf newTimes;
|
||||||
|
struct tm ltime;
|
||||||
|
|
||||||
|
// convert from FatFs fdate/ftime
|
||||||
|
ltime.tm_year = ((fno->fdate >> 9) & 0x7F) + 80;
|
||||||
|
ltime.tm_mon = ((fno->fdate >> 5) & 0xF) - 1;
|
||||||
|
ltime.tm_mday = (fno->fdate & 0x1F);
|
||||||
|
ltime.tm_hour = ((fno->ftime >> 11) & 0x1F);
|
||||||
|
ltime.tm_min = ((fno->ftime >> 5) & 0x3F);
|
||||||
|
ltime.tm_sec = (fno->ftime & 0x1F) * 2;
|
||||||
|
ltime.tm_isdst = -1; // force mktime() to check dst
|
||||||
|
|
||||||
|
newTimes.modtime = mktime(<ime);
|
||||||
|
newTimes.actime = newTimes.modtime;
|
||||||
|
|
||||||
|
if (utime(realPath.c_str(), &newTimes)) {
|
||||||
|
TRACE_SIMPGMSPACE("f_utime(%s) = error %d (%s)", simpath.c_str(), errno, strerror(errno));
|
||||||
|
return FR_DENIED;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
TRACE_SIMPGMSPACE("f_utime(%s) set mtime = %s", simpath.c_str(), ctime(&newTimes.modtime));
|
||||||
|
return FR_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int f_putc (TCHAR c, FIL * fil)
|
||||||
|
{
|
||||||
|
if (fil && fil->obj.fs) fwrite(&c, 1, 1, (FILE*)fil->obj.fs);
|
||||||
|
return FR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int f_puts (const TCHAR * str, FIL * fil)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
for (n = 0; *str; str++, n++) {
|
||||||
|
if (f_putc(*str, fil) == EOF) return EOF;
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
int f_printf (FIL *fil, const TCHAR * format, ...)
|
||||||
|
{
|
||||||
|
va_list arglist;
|
||||||
|
va_start(arglist, format);
|
||||||
|
if (fil && fil->obj.fs) vfprintf((FILE*)fil->obj.fs, format, arglist);
|
||||||
|
va_end(arglist);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
FRESULT f_getcwd (TCHAR *path, UINT sz_path)
|
||||||
|
{
|
||||||
|
char cwd[1024];
|
||||||
|
if (!getcwd(cwd, 1024)) {
|
||||||
|
TRACE_SIMPGMSPACE("f_getcwd() = getcwd() error %d (%s)", errno, strerror(errno));
|
||||||
|
strcpy(path, ".");
|
||||||
|
return FR_NO_PATH;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string result = convertFromSimuPath(cwd);
|
||||||
|
if (result.length() > sz_path) {
|
||||||
|
//TRACE_SIMPGMSPACE("f_getcwd(): buffer too short");
|
||||||
|
return FR_NOT_ENOUGH_CORE;
|
||||||
|
}
|
||||||
|
|
||||||
|
strcpy(path, result.c_str());
|
||||||
|
TRACE_SIMPGMSPACE("f_getcwd() = %s", path);
|
||||||
|
return FR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
FRESULT f_getfree (const TCHAR* path, DWORD* nclst, FATFS** fatfs)
|
||||||
|
{
|
||||||
|
// just fake that we always have some clusters free
|
||||||
|
*nclst = 10;
|
||||||
|
return FR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(PCBSKY9X)
|
||||||
|
int32_t Card_state = SD_ST_MOUNTED;
|
||||||
|
uint32_t Card_CSD[4]; // TODO elsewhere
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // #if defined(SIMU_USE_SDCARD)
|
|
@ -7,6 +7,7 @@ if(GTEST_INCDIR AND GTEST_SRCDIR AND Qt5Widgets_FOUND)
|
||||||
add_library(gtests-lib STATIC EXCLUDE_FROM_ALL ${GTEST_SRCDIR}/src/gtest-all.cc )
|
add_library(gtests-lib STATIC EXCLUDE_FROM_ALL ${GTEST_SRCDIR}/src/gtest-all.cc )
|
||||||
target_include_directories(gtests-lib PUBLIC ${GTEST_INCDIR} ${GTEST_INCDIR}/gtest ${GTEST_SRCDIR})
|
target_include_directories(gtests-lib PUBLIC ${GTEST_INCDIR} ${GTEST_INCDIR}/gtest ${GTEST_SRCDIR})
|
||||||
add_definitions(-DSIMU)
|
add_definitions(-DSIMU)
|
||||||
|
add_definitions(-DGTESTS)
|
||||||
set(TESTS_PATH ${RADIO_SRC_DIRECTORY})
|
set(TESTS_PATH ${RADIO_SRC_DIRECTORY})
|
||||||
configure_file(${RADIO_SRC_DIRECTORY}/tests/location.h.in ${CMAKE_CURRENT_BINARY_DIR}/location.h @ONLY)
|
configure_file(${RADIO_SRC_DIRECTORY}/tests/location.h.in ${CMAKE_CURRENT_BINARY_DIR}/location.h @ONLY)
|
||||||
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
||||||
|
@ -36,7 +37,7 @@ if(GTEST_INCDIR AND GTEST_SRCDIR AND Qt5Widgets_FOUND)
|
||||||
|
|
||||||
use_cxx11() # ensure gnu++11 in CXX_FLAGS with CMake < 3.1
|
use_cxx11() # ensure gnu++11 in CXX_FLAGS with CMake < 3.1
|
||||||
|
|
||||||
add_executable(gtests EXCLUDE_FROM_ALL ${TEST_SRC_FILES} ${CMAKE_CURRENT_SOURCE_DIR}/location.h ${RADIO_SRC} ../targets/simu/simpgmspace.cpp ../targets/simu/simueeprom.cpp)
|
add_executable(gtests EXCLUDE_FROM_ALL ${TEST_SRC_FILES} ${CMAKE_CURRENT_SOURCE_DIR}/location.h ${RADIO_SRC} ../targets/simu/simpgmspace.cpp ../targets/simu/simueeprom.cpp ../targets/simu/simufatfs.cpp)
|
||||||
qt5_use_modules(gtests Core Widgets)
|
qt5_use_modules(gtests Core Widgets)
|
||||||
add_dependencies(gtests ${FIRMWARE_DEPENDENCIES} gtests-lib)
|
add_dependencies(gtests ${FIRMWARE_DEPENDENCIES} gtests-lib)
|
||||||
target_link_libraries(gtests gtests-lib pthread)
|
target_link_libraries(gtests gtests-lib pthread)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue