/* * 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" #include #include #include #include #if defined(RTCLOCK) #include #endif #if defined WIN32 || !defined __GNUC__ #include #define mkdir(s, f) _mkdir(s) #endif #if defined(SIMU_DISKIO) FILE * diskImage = 0; #endif #if defined(SIMU_AUDIO) && defined(CPUARM) #include #endif 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; uint16_t dummyport16; const char *eepromFile = NULL; FILE *fp = NULL; int g_snapshot_idx = 0; #if defined(CPUSTM32) uint32_t Peri1_frequency, Peri2_frequency; GPIO_TypeDef gpioa, gpiob, gpioc, gpiod, gpioe, gpiof, gpiog, gpioh, gpioi, gpioj; TIM_TypeDef tim1, tim2, tim3, tim4, tim5, tim6, tim7, tim8, tim9, tim10; RCC_TypeDef rcc; DMA_Stream_TypeDef dma2_stream2, dma2_stream6; DMA_TypeDef dma2; USART_TypeDef Usart0, Usart1, Usart2, Usart3, Usart4; #elif defined(CPUARM) Pio Pioa, Piob, Pioc; Pwm pwm; Twi Twio; Usart Usart0; Dacc dacc; Adc Adc0; #endif #if defined(EEPROM_RLC) extern uint16_t eeprom_pointer; extern uint8_t * eeprom_buffer_data; #else uint32_t eeprom_pointer; uint8_t * eeprom_buffer_data; volatile int32_t eeprom_buffer_size; bool eeprom_read_operation; #define EESIZE_SIMU (128*4096) // TODO why here? #endif #if !defined(EESIZE_SIMU) #define EESIZE_SIMU EESIZE #endif #if defined(SDCARD) && !defined(SKIP_FATFS_DECLARATION) char simuSdDirectory[1024] = ""; #endif uint8_t eeprom[EESIZE_SIMU]; sem_t *eeprom_write_sem; void simuInit() { for (int i = 0; i <= 17; i++) { simuSetSwitch(i, 0); simuSetKey(i, false); // a little dirty, but setting keys that don't exist is perfectly OK here } } #define NEG_CASE(sw_or_key, pin, mask) \ case sw_or_key: \ if ((int)state > 0) pin &= ~(mask); else pin |= (mask); \ break; #define POS_CASE(sw_or_key, pin, mask) \ case sw_or_key: \ if ((int)state > 0) pin |= (mask); else pin &= ~(mask); \ break; #if defined(CPUARM) #if defined(PCBTARANIS) && !defined(REV9E) #define SWITCH_CASE NEG_CASE #else #define SWITCH_CASE POS_CASE #endif #define SWITCH_3_CASE(swtch, pin1, pin2, mask1, mask2) \ case swtch: \ if ((int)state < 0) pin1 &= ~(mask1); else pin1 |= (mask1); \ if ((int)state > 0) pin2 &= ~(mask2); else pin2 |= (mask2); \ break; #define KEY_CASE NEG_CASE #define TRIM_CASE NEG_CASE #else #if defined(PCBMEGA2560) #define SWITCH_CASE POS_CASE #else #define SWITCH_CASE NEG_CASE #endif #define SWITCH_3_CASE(swtch, pin1, pin2, mask1, mask2) \ case swtch: \ if ((int)state >= 0) pin1 &= ~(mask1); else pin1 |= (mask1); \ if ((int)state <= 0) pin2 &= ~(mask2); else pin2 |= (mask2); \ break; #define KEY_CASE POS_CASE #define TRIM_CASE KEY_CASE #endif void simuSetKey(uint8_t key, bool state) { // TRACE("simuSetKey(%d, %d)", key, state); switch (key) { KEY_CASE(KEY_MENU, KEYS_GPIO_REG_MENU, KEYS_GPIO_PIN_MENU) KEY_CASE(KEY_EXIT, KEYS_GPIO_REG_EXIT, KEYS_GPIO_PIN_EXIT) #if defined(PCBHORUS) KEY_CASE(KEY_ENTER, KEYS_GPIO_REG_ENTER, KEYS_GPIO_PIN_ENTER) KEY_CASE(KEY_RIGHT, KEYS_GPIO_REG_RIGHT, KEYS_GPIO_PIN_RIGHT) KEY_CASE(KEY_LEFT, KEYS_GPIO_REG_LEFT, KEYS_GPIO_PIN_LEFT) KEY_CASE(KEY_UP, KEYS_GPIO_REG_UP, KEYS_GPIO_PIN_UP) KEY_CASE(KEY_DOWN, KEYS_GPIO_REG_DOWN, KEYS_GPIO_PIN_DOWN) #elif defined(PCBTARANIS) || defined(PCBFLAMENCO) KEY_CASE(KEY_ENTER, KEYS_GPIO_REG_ENTER, KEYS_GPIO_PIN_ENTER) KEY_CASE(KEY_PAGE, KEYS_GPIO_REG_PAGE, KEYS_GPIO_PIN_PAGE) KEY_CASE(KEY_MINUS, KEYS_GPIO_REG_MINUS, KEYS_GPIO_PIN_MINUS) KEY_CASE(KEY_PLUS, KEYS_GPIO_REG_PLUS, KEYS_GPIO_PIN_PLUS) #else KEY_CASE(KEY_RIGHT, KEYS_GPIO_REG_RIGHT, KEYS_GPIO_PIN_RIGHT) KEY_CASE(KEY_LEFT, KEYS_GPIO_REG_LEFT, KEYS_GPIO_PIN_LEFT) KEY_CASE(KEY_UP, KEYS_GPIO_REG_UP, KEYS_GPIO_PIN_UP) KEY_CASE(KEY_DOWN, KEYS_GPIO_REG_DOWN, KEYS_GPIO_PIN_DOWN) #endif #if defined(PCBSKY9X) && !defined(REVX) KEY_CASE(BTN_REa, PIOB->PIO_PDSR, 0x40) #elif defined(PCBGRUVIN9X) || defined(PCBMEGA2560) KEY_CASE(BTN_REa, pind, 0x20) #elif defined(ROTARY_ENCODER_NAVIGATION) KEY_CASE(BTN_REa, RotEncoder, 0x20) #endif } } void simuSetTrim(uint8_t trim, bool state) { // TRACE("trim=%d state=%d", trim, state); switch (trim) { TRIM_CASE(0, TRIMS_GPIO_REG_LHL, TRIMS_GPIO_PIN_LHL) TRIM_CASE(1, TRIMS_GPIO_REG_LHR, TRIMS_GPIO_PIN_LHR) TRIM_CASE(2, TRIMS_GPIO_REG_LVD, TRIMS_GPIO_PIN_LVD) TRIM_CASE(3, TRIMS_GPIO_REG_LVU, TRIMS_GPIO_PIN_LVU) TRIM_CASE(4, TRIMS_GPIO_REG_RVD, TRIMS_GPIO_PIN_RVD) TRIM_CASE(5, TRIMS_GPIO_REG_RVU, TRIMS_GPIO_PIN_RVU) TRIM_CASE(6, TRIMS_GPIO_REG_RHL, TRIMS_GPIO_PIN_RHL) TRIM_CASE(7, TRIMS_GPIO_REG_RHR, TRIMS_GPIO_PIN_RHR) #if defined(HORUS) TRIM_CASE(8, TRIMS_GPIO_REG_LSU, TRIMS_GPIO_PIN_LSU) TRIM_CASE(9, TRIMS_GPIO_REG_LSD, TRIMS_GPIO_PIN_RVU) TRIM_CASE(10, TRIMS_GPIO_REG_RSU, TRIMS_GPIO_PIN_RHL) TRIM_CASE(11, TRIMS_GPIO_REG_RSD, TRIMS_GPIO_PIN_RHR) #endif } } // TODO use a better numbering to allow google tests to work on Taranis void simuSetSwitch(uint8_t swtch, int8_t state) { // TRACE("simuSetSwitch(%d, %d)", swtch, state); switch (swtch) { #if defined(PCBFLAMENCO) // SWITCH_3_CASE(0, SWITCHES_GPIO_REG_A_L, SWITCHES_GPIO_REG_A_H, SWITCHES_GPIO_PIN_A_L, SWITCHES_GPIO_PIN_A_H) // SWITCH_CASE(1, SWITCHES_GPIO_REG_B, SWITCHES_GPIO_PIN_B) // SWITCH_3_CASE(2, SWITCHES_GPIO_REG_C_L, SWITCHES_GPIO_REG_C_H, SWITCHES_GPIO_PIN_C_L, SWITCHES_GPIO_PIN_C_H) // SWITCH_3_CASE(3, SWITCHES_GPIO_REG_D_L, SWITCHES_GPIO_REG_D_H, SWITCHES_GPIO_PIN_D_L, SWITCHES_GPIO_PIN_D_H) // SWITCH_CASE(4, SWITCHES_GPIO_REG_E, SWITCHES_GPIO_PIN_E) // SWITCH_3_CASE(5, SWITCHES_GPIO_REG_F_H, SWITCHES_GPIO_REG_F_L, SWITCHES_GPIO_PIN_F_H, SWITCHES_GPIO_PIN_F_L) #elif defined(PCBTARANIS) || defined(PCBHORUS) SWITCH_3_CASE(0, SWITCHES_GPIO_REG_A_L, SWITCHES_GPIO_REG_A_H, SWITCHES_GPIO_PIN_A_L, SWITCHES_GPIO_PIN_A_H) SWITCH_3_CASE(1, SWITCHES_GPIO_REG_B_L, SWITCHES_GPIO_REG_B_H, SWITCHES_GPIO_PIN_B_L, SWITCHES_GPIO_PIN_B_H) SWITCH_3_CASE(2, SWITCHES_GPIO_REG_C_L, SWITCHES_GPIO_REG_C_H, SWITCHES_GPIO_PIN_C_L, SWITCHES_GPIO_PIN_C_H) SWITCH_3_CASE(3, SWITCHES_GPIO_REG_D_L, SWITCHES_GPIO_REG_D_H, SWITCHES_GPIO_PIN_D_L, SWITCHES_GPIO_PIN_D_H) SWITCH_3_CASE(4, SWITCHES_GPIO_REG_E_L, SWITCHES_GPIO_REG_E_H, SWITCHES_GPIO_PIN_E_L, SWITCHES_GPIO_PIN_E_H) SWITCH_CASE(5, SWITCHES_GPIO_REG_F, SWITCHES_GPIO_PIN_F) SWITCH_3_CASE(6, SWITCHES_GPIO_REG_G_L, SWITCHES_GPIO_REG_G_H, SWITCHES_GPIO_PIN_G_L, SWITCHES_GPIO_PIN_G_H) SWITCH_CASE(7, SWITCHES_GPIO_REG_H, SWITCHES_GPIO_PIN_H) #if defined(REV9E) SWITCH_3_CASE(8, SWITCHES_GPIO_REG_I_L, SWITCHES_GPIO_REG_I_H, SWITCHES_GPIO_PIN_I_L, SWITCHES_GPIO_PIN_I_H) SWITCH_3_CASE(9, SWITCHES_GPIO_REG_J_L, SWITCHES_GPIO_REG_J_H, SWITCHES_GPIO_PIN_J_L, SWITCHES_GPIO_PIN_J_H) SWITCH_3_CASE(10, SWITCHES_GPIO_REG_K_L, SWITCHES_GPIO_REG_K_H, SWITCHES_GPIO_PIN_K_L, SWITCHES_GPIO_PIN_K_H) SWITCH_3_CASE(11, SWITCHES_GPIO_REG_L_L, SWITCHES_GPIO_REG_L_H, SWITCHES_GPIO_PIN_L_L, SWITCHES_GPIO_PIN_L_H) SWITCH_3_CASE(12, SWITCHES_GPIO_REG_M_L, SWITCHES_GPIO_REG_M_H, SWITCHES_GPIO_PIN_M_L, SWITCHES_GPIO_PIN_M_H) SWITCH_3_CASE(13, SWITCHES_GPIO_REG_N_L, SWITCHES_GPIO_REG_N_H, SWITCHES_GPIO_PIN_N_L, SWITCHES_GPIO_PIN_N_H) SWITCH_3_CASE(14, SWITCHES_GPIO_REG_O_L, SWITCHES_GPIO_REG_O_H, SWITCHES_GPIO_PIN_O_L, SWITCHES_GPIO_PIN_O_H) SWITCH_3_CASE(15, SWITCHES_GPIO_REG_P_L, SWITCHES_GPIO_REG_P_H, SWITCHES_GPIO_PIN_P_L, SWITCHES_GPIO_PIN_P_H) SWITCH_3_CASE(16, SWITCHES_GPIO_REG_Q_L, SWITCHES_GPIO_REG_Q_H, SWITCHES_GPIO_PIN_Q_L, SWITCHES_GPIO_PIN_Q_H) SWITCH_3_CASE(17, SWITCHES_GPIO_REG_R_L, SWITCHES_GPIO_REG_R_H, SWITCHES_GPIO_PIN_R_L, SWITCHES_GPIO_PIN_R_H) #endif #elif defined(PCBSKY9X) SWITCH_CASE(0, PIOC->PIO_PDSR, 1<<20) SWITCH_CASE(1, PIOA->PIO_PDSR, 1<<15) SWITCH_CASE(2, PIOC->PIO_PDSR, 1<<31) SWITCH_3_CASE(3, PIOC->PIO_PDSR, PIOC->PIO_PDSR, 0x00004000, 0x00000800) SWITCH_CASE(4, PIOA->PIO_PDSR, 1<<2) SWITCH_CASE(5, PIOC->PIO_PDSR, 1<<16) SWITCH_CASE(6, PIOC->PIO_PDSR, 1<<8) #elif defined(PCBGRUVIN9X) SWITCH_CASE(0, ping, 1< 0); if (fp) { if (fwrite(eeprom_buffer_data, 1, 1, fp) != 1) perror("error in fwrite"); #if !defined(CPUARM) sleep(5/*ms*/); #endif } else { memcpy(&eeprom[eeprom_pointer], eeprom_buffer_data, 1); } eeprom_pointer++; eeprom_buffer_data++; if (fp && eeprom_buffer_size == 1) { fflush(fp); } } #if defined(CPUARM) } Spi_complete = 1; #endif } return 0; } #endif uint8_t main_thread_running = 0; char * main_thread_error = NULL; extern void opentxStart(); void *main_thread(void *) { #ifdef SIMU_EXCEPTIONS signal(SIGFPE, sig); signal(SIGSEGV, sig); try { #endif #if defined(PCBHORUS) lcdColorsInit(); #endif #if defined(CPUARM) stackPaint(); #endif s_current_protocol[0] = 255; menuLevel = 0; menuHandlers[0] = menuMainView; menuHandlers[1] = menuModelSelect; storageReadAll(); // load general setup and selected model #if defined(SIMU_DISKIO) f_mount(&g_FATFS_Obj, "", 1); // call sdGetFreeSectors() now because f_getfree() takes a long time first time it's called sdGetFreeSectors(); #endif #if defined(CPUARM) && defined(SDCARD) referenceSystemAudioFiles(); #endif if (g_eeGeneral.backlightMode != e_backlight_mode_off) backlightOn(); // on Tx start turn the light on if (main_thread_running == 1) { opentxStart(); } s_current_protocol[0] = 0; #if defined(PCBFLAMENCO) menuEntryTime = get_tmr10ms() - 200; #endif while (main_thread_running) { #if defined(CPUARM) doMixerCalculations(); #if defined(FRSKY) || defined(MAVLINK) telemetryWakeup(); #endif checkTrims(); #endif perMain(); sleep(10/*ms*/); } #if defined(LUA) luaClose(); #endif #ifdef SIMU_EXCEPTIONS } catch (...) { main_thread_running = 0; } #endif #if defined(SIMU_DISKIO) if (diskImage) { fclose(diskImage); } #endif return NULL; } #if defined WIN32 || !defined __GNUC__ #define chdir _chdir #define getcwd _getcwd #endif pthread_t main_thread_pid; void StartMainThread(bool tests) { #if defined(SDCARD) if (strlen(simuSdDirectory) == 0) getcwd(simuSdDirectory, 1024); #endif #if defined(CPUARM) pthread_mutex_init(&mixerMutex, NULL); pthread_mutex_init(&audioMutex, NULL); #endif /* g_tmr10ms must be non-zero otherwise some SF functions (that use this timer as a marker when it was last executed) will be executed twice on startup. Normal radio does not see this issue because g_tmr10ms is already a big number before the first call to the Special Functions. Not so in the simulator. There is another issue, some other function static variables depend on this value. If simulator is started multiple times in one Companion session, they are set to their initial values only first time the simulator is started. Therefore g_tmr10ms must also be set to non-zero value only the first time, then it must be left alone to continue from the previous simulator session value. See the issue #2446 */ if (g_tmr10ms == 0) { g_tmr10ms = 1; } #if defined(RTCLOCK) g_rtcTime = time(0); #endif main_thread_running = (tests ? 1 : 2); pthread_create(&main_thread_pid, NULL, &main_thread, NULL); } void StopMainThread() { main_thread_running = 0; pthread_join(main_thread_pid, NULL); } #if defined(CPUARM) struct SimulatorAudio { int volumeGain; int currentVolume; uint16_t leftoverData[AUDIO_BUFFER_SIZE]; int leftoverLen; bool threadRunning; pthread_t threadPid; } simuAudio; bool dacQueue(AudioBuffer *buffer) { return false; } void setVolume(uint8_t volume) { } void setScaledVolume(uint8_t volume) { simuAudio.currentVolume = min((volumeScale[min(volume, VOLUME_LEVEL_MAX)] * simuAudio.volumeGain) / 10, 127); // TRACE("setVolume(): in: %u, out: %u", volume, simuAudio.currentVolume); } #endif #if defined(SIMU_AUDIO) && defined(CPUARM) void copyBuffer(uint8_t * dest, uint16_t * buff, unsigned int samples) { for(unsigned int i=0; i= nextBuffer->size*2) { copyBuffer(stream, nextBuffer->data, nextBuffer->size); stream += nextBuffer->size*2; len -= nextBuffer->size*2; // putchar('+'); } else { //partial copyBuffer(stream, nextBuffer->data, len/2); simuAudio.leftoverLen = (nextBuffer->size-len/2); memcpy(simuAudio.leftoverData, &nextBuffer->data[len/2], simuAudio.leftoverLen*2); len = 0; // putchar('p'); break; } } else { break; } } } //fill the rest of buffer with silence if (len > 0) { SDL_memset(stream, 0x8000, len); // make sure this is silence. // putchar('.'); } } void * audioThread(void *) { /* Checking here if SDL audio was initialized is wrong, because the SDL_CloseAudio() de-initializes it. if ( !SDL_WasInit(SDL_INIT_AUDIO) ) { fprintf(stderr, "ERROR: couldn't initialize SDL audio support\n"); return 0; } */ SDL_AudioSpec wanted, have; /* Set the audio format */ wanted.freq = AUDIO_SAMPLE_RATE; wanted.format = AUDIO_S16SYS; wanted.channels = 1; /* 1 = mono, 2 = stereo */ wanted.samples = AUDIO_BUFFER_SIZE*2; /* Good low-latency value for callback */ wanted.callback = fillAudioBuffer; wanted.userdata = NULL; /* SDL_OpenAudio() internally calls SDL_InitSubSystem(SDL_INIT_AUDIO), which initializes SDL Audio subsystem if necessary */ if ( SDL_OpenAudio(&wanted, &have) < 0 ) { fprintf(stderr, "Couldn't open audio: %s\n", SDL_GetError()); return 0; } SDL_PauseAudio(0); while (simuAudio.threadRunning) { audioQueue.wakeup(); sleep(1); } SDL_CloseAudio(); return 0; } void StartAudioThread(int volumeGain) { simuAudio.leftoverLen = 0; simuAudio.threadRunning = true; simuAudio.volumeGain = volumeGain; setScaledVolume(VOLUME_LEVEL_DEF); pthread_attr_t attr; pthread_attr_init(&attr); struct sched_param sp; sp.sched_priority = SCHED_RR; pthread_attr_setschedparam(&attr, &sp); pthread_create(&simuAudio.threadPid, &attr, &audioThread, NULL); return; } void StopAudioThread() { simuAudio.threadRunning = false; pthread_join(simuAudio.threadPid, NULL); } #endif // #if defined(SIMU_AUDIO) && defined(CPUARM) pthread_t eeprom_thread_pid; void StartEepromThread(const char *filename) { eepromFile = filename; if (eepromFile) { fp = fopen(eepromFile, "rb+"); if (!fp) fp = fopen(eepromFile, "wb+"); if (!fp) perror("error in fopen"); } #ifdef __APPLE__ eeprom_write_sem = sem_open("eepromsem", O_CREAT, S_IRUSR | S_IWUSR, 0); #else eeprom_write_sem = (sem_t *)malloc(sizeof(sem_t)); sem_init(eeprom_write_sem, 0, 0); #endif #if !defined(PCBTARANIS) && !defined(PCBHORUS) eeprom_thread_running = true; assert(!pthread_create(&eeprom_thread_pid, NULL, &eeprom_write_function, NULL)); #endif } void StopEepromThread() { #if !defined(PCBTARANIS) && !defined(PCBFLAMENCO) && !defined(PCBHORUS) eeprom_thread_running = false; sem_post(eeprom_write_sem); pthread_join(eeprom_thread_pid, NULL); #endif #ifdef __APPLE__ //TODO free semaphore eeprom_write_sem #else sem_destroy(eeprom_write_sem); free(eeprom_write_sem); #endif if (fp) fclose(fp); } void eepromReadBlock (uint8_t * pointer_ram, uint32_t pointer_eeprom, uint32_t size) { assert(size); if (fp) { // TRACE("EEPROM read (pos=%d, size=%d)", pointer_eeprom, size); if (fseek(fp, (long)pointer_eeprom, SEEK_SET)==-1) perror("error in fseek"); if (fread(pointer_ram, size, 1, fp) <= 0) perror("error in fread"); } else { memcpy(pointer_ram, &eeprom[(uint64_t)pointer_eeprom], size); } } #if defined(PCBTARANIS) || defined(PCBFLAMENCO) void eepromWriteBlock(uint8_t * pointer_ram, uint32_t pointer_eeprom, uint32_t size) { assert(size); if (fp) { // TRACE("EEPROM write (pos=%d, size=%d)", pointer_eeprom, size); if (fseek(fp, (long)pointer_eeprom, SEEK_SET)==-1) perror("error in fseek"); if (fwrite(pointer_ram, size, 1, fp) <= 0) perror("error in fwrite"); } else { memcpy(&eeprom[(uint64_t)pointer_eeprom], pointer_ram, size); } } #endif uint16_t stackAvailable() { return 500; } #if 0 static void EeFsDump(){ for(int i=0; i #if !defined WIN32 #include #endif } #include "ff.h" #if defined WIN32 || !defined __GNUC__ #include #include #endif #include #include #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 filemap_t; filemap_t fileMap; char *findTrueFileName(const char *path) { TRACE("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("\tfound in map: %s", result); return result; } else { //find file //add to map #if defined WIN32 || !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("\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("comparing with: %s", ffd.cFileName); if (!strcasecmp(fileName.c_str(), ffd.cFileName)) { strcpy(result, dirName.c_str()); strcat(result, ffd.cFileName); TRACE("\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("\tsearching for: %s", fileName.c_str()); for (;;) { struct simu::dirent * res = simu::readdir(dir); if (res == 0) break; #if defined(__APPLE__) 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("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("\tfound: %s", res->d_name); fileMap.insert(filemap_t:: value_type(path, result)); simu::closedir(dir); return result; } } } simu::closedir(dir); } #endif } TRACE("\tnot found"); strcpy(result, path); return result; } FRESULT f_stat (const TCHAR * name, FILINFO *) { char *path = convertSimuPath(name); char * realPath = findTrueFileName(path); struct stat tmp; if (stat(realPath, &tmp)) { TRACE("f_stat(%s) = error %d (%s)", path, errno, strerror(errno)); return FR_INVALID_NAME; } else { TRACE("f_stat(%s) = OK", path); 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); if (!(flag & FA_WRITE)) { struct stat tmp; if (stat(realPath, &tmp)) { TRACE("f_open(%s) = INVALID_NAME", path); return FR_INVALID_NAME; } fil->fsize = tmp.st_size; fil->fptr = 0; } fil->fs = (FATFS*)fopen(realPath, (flag & FA_WRITE) ? ((flag & FA_CREATE_ALWAYS) ? "wb+" : "ab+") : "rb+"); fil->fptr = 0; if (fil->fs) { TRACE("f_open(%s, %x) = %p (FIL %p)", path, flag, fil->fs, fil); return FR_OK; } TRACE("f_open(%s) = error %d (%s)", path, errno, strerror(errno)); return FR_INVALID_NAME; } FRESULT f_read (FIL* fil, void* data, UINT size, UINT* read) { if (fil && fil->fs) { *read = fread(data, 1, size, (FILE*)fil->fs); fil->fptr += *read; // TRACE("fread(%p) %u, %u", fil->fs, size, *read); } return FR_OK; } FRESULT f_write (FIL* fil, const void* data, UINT size, UINT* written) { if (fil && fil->fs) { *written = fwrite(data, 1, size, (FILE*)fil->fs); fil->fptr += size; // TRACE("fwrite(%p) %u, %u", fil->fs, size, *written); } return FR_OK; } FRESULT f_lseek (FIL* fil, DWORD offset) { if (fil && fil->fs) fseek((FILE*)fil->fs, offset, SEEK_SET); fil->fptr = offset; return FR_OK; } UINT f_size(FIL* fil) { if (fil && fil->fs) { long curr = ftell((FILE*)fil->fs); fseek((FILE*)fil->fs, 0, SEEK_END); long size = ftell((FILE*)fil->fs); fseek((FILE*)fil->fs, curr, SEEK_SET); TRACE("f_size(%p) %u", fil->fs, size); return size; } return 0; } FRESULT f_close (FIL * fil) { assert(fil); TRACE("f_close(%p) (FIL:%p)", fil->fs, fil); if (fil->fs) { fclose((FILE*)fil->fs); fil->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->fs = (FATFS *)simu::opendir(path); if ( rep->fs ) { TRACE("f_opendir(%s) = OK", path); return FR_OK; } TRACE("f_opendir(%s) = error %d (%s)", path, errno, strerror(errno)); return FR_NO_PATH; } FRESULT f_closedir (DIR * rep) { TRACE("f_closedir(%p)", rep); simu::closedir((simu::DIR *)rep->fs); return FR_OK; } FRESULT f_readdir (DIR * rep, FILINFO * fil) { if (!rep->fs) return FR_NO_FILE; simu::dirent * ent = simu::readdir((simu::DIR *)rep->fs); if (!ent) return FR_NO_FILE; #if defined(WIN32) || !defined(__GNUC__) || defined(__APPLE__) fil->fattrib = (ent->d_type == DT_DIR ? AM_DIR : 0); #else if (ent->d_type == simu::DT_UNKNOWN) { 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, 13); memset(fil->lfname, 0, SD_SCREEN_FILE_LENGTH); strncpy(fil->fname, ent->d_name, 13-1); strcpy(fil->lfname, ent->d_name); // TRACE("f_readdir(): %s", fil->fname); return FR_OK; } FRESULT f_mkfs (const TCHAR * path, BYTE, UINT) { TRACE("Format SD..."); return FR_OK; } FRESULT f_mkdir (const TCHAR * name) { char * path = convertSimuPath(name); if (mkdir(path, 0777)) { TRACE("mkdir(%s) = error %d (%s)", path, errno, strerror(errno)); return FR_INVALID_NAME; } else { TRACE("mkdir(%s) = OK", path); return FR_OK; } return FR_OK; } FRESULT f_unlink (const TCHAR * name) { char * path = convertSimuPath(name); if (unlink(path)) { TRACE("f_unlink(%s) = error %d (%s)", path, errno, strerror(errno)); return FR_INVALID_NAME; } else { TRACE("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("f_rename(%s, %s) = error %d (%s)", old, path, errno, strerror(errno)); return FR_INVALID_NAME; } TRACE("f_rename(%s, %s) = OK", old, path); return FR_OK; } int f_putc (TCHAR c, FIL * fil) { if (fil && fil->fs) fwrite(&c, 1, 1, (FILE*)fil->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->fs) vfprintf((FILE*)fil->fs, format, arglist); va_end(arglist); return 0; } FRESULT f_getcwd (TCHAR *path, UINT sz_path) { char cwd[1024]; if (!getcwd(cwd, 1024)) { TRACE("f_getcwd() = getcwd() error %d (%s)", errno, strerror(errno)); strcpy(path, "."); return FR_NO_PATH; } if (strlen(cwd) < strlen(simuSdDirectory)) { TRACE("f_getcwd() = logic error strlen(cwd) < strlen(simuSdDirectory): cwd: \"%s\", simuSdDirectory: \"%s\"", cwd, simuSdDirectory); strcpy(path, "."); return FR_NO_PATH; } // remove simuSdDirectory from the cwd strcpy(path, cwd + strlen(simuSdDirectory)); TRACE("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(SDCARD) && !defined(SKIP_FATFS_DECLARATION) && !defined(SIMU_DISKIO) #if defined(SIMU_DISKIO) #include "FatFs/diskio.h" #include #include #if defined(CPUARM) FATFS g_FATFS_Obj = { 0}; #endif int ff_cre_syncobj (BYTE vol, _SYNC_t* sobj) /* Create a sync object */ { return 1; } int ff_req_grant (_SYNC_t sobj) /* Lock sync object */ { return 1; } void ff_rel_grant (_SYNC_t sobj) /* Unlock sync object */ { } int ff_del_syncobj (_SYNC_t sobj) /* Delete a sync object */ { 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("disk_status() called %d times", noDiskStatus); noDiskStatus = 0; } } DSTATUS disk_initialize (BYTE pdrv) { traceDiskStatus(); TRACE("disk_initialize(%u)", pdrv); diskImage = fopen("sdcard.image", "r+"); return diskImage ? (DSTATUS)0 : (DSTATUS)STA_NODISK; } DSTATUS disk_status (BYTE pdrv) { ++noDiskStatus; // TRACE("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("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("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("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("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("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; } uint32_t sdIsHC() { return sdGetSize() > 2000000; } uint32_t sdGetSpeed() { return 330000; } #endif // #if defined(SIMU_DISKIO) bool simuLcdRefresh = true; display_t simuLcdBuf[DISPLAY_BUFFER_SIZE]; #if !defined(PCBFLAMENCO) && !defined(PCBHORUS) void lcdSetRefVolt(uint8_t val) { } #endif void adcPrepareBandgap() { } #if defined(PCBTARANIS) void lcdOff() { } #endif void lcdRefresh() { #if defined(PCBFLAMENCO) TW8823_SendScreen(); #endif memcpy(simuLcdBuf, displayBuf, sizeof(simuLcdBuf)); simuLcdRefresh = true; } void telemetryPortInit() { } #if !defined(PCBFLAMENCO) display_t simuLcdBackupBuf[DISPLAY_BUFFER_SIZE]; void lcdStoreBackupBuffer() { memcpy(simuLcdBackupBuf, displayBuf, sizeof(simuLcdBackupBuf)); } int lcdRestoreBackupBuffer() { memcpy(displayBuf, simuLcdBackupBuf, sizeof(displayBuf)); return 1; } #endif #if defined(PWR_BUTTON_DELAY) uint32_t pwrPressed() { return false; } #elif defined(PCBTARANIS) || defined(PCBFLAMENCO) || defined(PCBHORUS) uint32_t pwrCheck() { return true; } #endif #if defined(PCBTARANIS) || defined(PCBFLAMENCO) || defined(PCBHORUS) void pwrInit() { } void pwrOff() { } int usbPlugged() { return false; } void USART_DeInit(USART_TypeDef* ) { } ErrorStatus RTC_SetTime(uint32_t RTC_Format, RTC_TimeTypeDef* RTC_TimeStruct) { return SUCCESS; } ErrorStatus RTC_SetDate(uint32_t RTC_Format, RTC_DateTypeDef* RTC_DateStruct) { return SUCCESS; } void RTC_GetTime(uint32_t RTC_Format, RTC_TimeTypeDef* RTC_TimeStruct) { } void RTC_GetDate(uint32_t RTC_Format, RTC_DateTypeDef* RTC_DateStruct) { } void RTC_TimeStructInit(RTC_TimeTypeDef* RTC_TimeStruct) { } void RTC_DateStructInit(RTC_DateTypeDef* RTC_DateStruct) { } void PWR_BackupAccessCmd(FunctionalState NewState) { } void RCC_RTCCLKConfig(uint32_t RCC_RTCCLKSource) { } void RCC_APB1PeriphClockCmd(uint32_t RCC_APB1Periph, FunctionalState NewState) { } void RCC_RTCCLKCmd(FunctionalState NewState) { } ErrorStatus RTC_Init(RTC_InitTypeDef* RTC_InitStruct) { return SUCCESS; } void USART_SendData(USART_TypeDef* USARTx, uint16_t Data) { } FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG) { return SET; } void GPIO_PinAFConfig(GPIO_TypeDef* GPIOx, uint16_t GPIO_PinSource, uint8_t GPIO_AF) { } void USART_Init(USART_TypeDef* USARTx, USART_InitTypeDef* USART_InitStruct) { } void USART_Cmd(USART_TypeDef* USARTx, FunctionalState NewState) { } void USART_ITConfig(USART_TypeDef* USARTx, uint16_t USART_IT, FunctionalState NewState) { } void RCC_PLLI2SConfig(uint32_t PLLI2SN, uint32_t PLLI2SR) { } void RCC_PLLI2SCmd(FunctionalState NewState) { } void RCC_I2SCLKConfig(uint32_t RCC_I2SCLKSource) { } void SPI_I2S_DeInit(SPI_TypeDef* SPIx) { } void I2S_Init(SPI_TypeDef* SPIx, I2S_InitTypeDef* I2S_InitStruct) { } void I2S_Cmd(SPI_TypeDef* SPIx, FunctionalState NewState) { } void SPI_I2S_ITConfig(SPI_TypeDef* SPIx, uint8_t SPI_I2S_IT, FunctionalState NewState) { } void RCC_LSEConfig(uint8_t RCC_LSE) { } FlagStatus RCC_GetFlagStatus(uint8_t RCC_FLAG) { return RESET; } ErrorStatus RTC_WaitForSynchro(void) { return SUCCESS; } void unlockFlash() { } void lockFlash() { } void writeFlash(uint32_t *address, uint32_t *buffer) { SIMU_SLEEP(100); } uint32_t isBootloaderStart(const void *block) { return 1; } #if defined(REVPLUS) void turnBacklightOn(uint8_t level, uint8_t color) { TIM4->CCR4 = (100-level)*color; TIM4->CCR2 = (100-level)*(100-color); } void turnBacklightOff(void) { TIM4->CCR4 = 0; TIM4->CCR2 = 0; } #endif #endif // #if defined(PCBTARANIS) #if defined(PCBFLAMENCO) void i2cWriteTW8823(unsigned char, unsigned char) { } uint8_t i2cReadBQ24195(uint8_t) { return 0; } void i2cWriteBQ24195(uint8_t, uint8_t) { } #endif void serialPrintf(const char * format, ...) { } void serialCrlf() { } void serialPutc(char c) { } uint16_t stackSize() { return 0; } int32_t getVolume() { return 0; }