Merge pull request #725 from opentx/bsongis/Issue713_more_custom_functions

Bsongis/issue713 more custom functions
This commit is contained in:
Andre Bernet
2014-02-25 19:00:01 +01:00
19 changed files with 418 additions and 231 deletions
+2 -2
View File
@@ -74,7 +74,7 @@ const uint8_t modn12x3[4][4]= {
#define C9X_MAX_ENCODERS 2
#define C9X_NUM_CHNOUT 32 // number of real output channels
#define C9X_NUM_CSW 32 // number of custom switches
#define C9X_MAX_CUSTOM_FUNCTIONS 32 // number of functions assigned to switches
#define C9X_MAX_CUSTOM_FUNCTIONS 64 // number of functions assigned to switches
#define C9X_NUM_MODULES 2
#define STK_RUD 1
@@ -856,7 +856,7 @@ class ModuleData {
void clear() { memset(this, 0, sizeof(ModuleData)); }
};
#define C9X_MAX_SCRIPTS 3
#define C9X_MAX_SCRIPTS 7
#define C9X_MAX_SCRIPT_INPUTS 10
class ScriptData {
public:
@@ -20,7 +20,7 @@
#define MAX_CHANNELS(board, version) (IS_ARM(board) ? 32 : 16)
#define MAX_EXPOS(board, version) (IS_ARM(board) ? ((IS_TARANIS(board) && version >= 216) ? 64 : 32) : (IS_DBLRAM(board, version) ? 16 : 14))
#define MAX_CUSTOM_SWITCHES(board, version) (IS_ARM(board) ? 32 : (IS_DBLEEPROM(board, version) ? 15 : 12))
#define MAX_CUSTOM_FUNCTIONS(board, version) (IS_ARM(board) ? 32 : (IS_DBLEEPROM(board, version) ? 24 : 16))
#define MAX_CUSTOM_FUNCTIONS(board, version) (IS_ARM(board) ? (version >= 216 ? 64 : 32) : (IS_DBLEEPROM(board, version) ? 24 : 16))
#define MAX_CURVES(board, version) (IS_ARM(board) ? ((IS_TARANIS(board) && version >= 216) ? 32 : 16) : O9X_MAX_CURVES)
#define MAX_GVARS(board, version) ((IS_ARM(board) && version >= 216) ? 9 : 5)
@@ -164,7 +164,7 @@ class SourcesConversionTable: public ConversionTable {
if (IS_TARANIS(board) && version >= 216) {
for (int i=0; i<32; i++)
addConversion(RawSource(SOURCE_TYPE_VIRTUAL_INPUT, i), val++);
for (int i=0; i<3; i++) {
for (int i=0; i<7; i++) {
for (int j=0; j<6; j++) {
addConversion(RawSource(SOURCE_TYPE_LUA_INPUT, i*16+j), val++);
}
@@ -1429,7 +1429,9 @@ class ArmCustomFunctionField: public TransformedField {
internalField.Append(new SwitchField<8>(fn.swtch, board, version));
internalField.Append(new ConversionField< UnsignedField<8> >((unsigned int &)fn.func, &functionsConversionTable, "Function", ::QObject::tr("OpenTX on this board doesn't accept this function")));
if (IS_TARANIS(board))
if (IS_TARANIS(board) && version >= 216)
internalField.Append(new CharField<8>(_param, false));
else if (IS_TARANIS(board))
internalField.Append(new CharField<10>(_param, false));
else
internalField.Append(new CharField<6>(_param, false));
@@ -2208,7 +2210,7 @@ Open9xModelDataNew::Open9xModelDataNew(ModelData & modelData, BoardEnum board, u
}
if (IS_TARANIS(board) && version >= 216) {
for (int i=0; i<3; i++) {
for (int i=0; i<7; i++) {
ScriptData & script = modelData.scriptData[i];
internalField.Append(new ZCharField<10>(script.filename));
internalField.Append(new ZCharField<10>(script.name));
@@ -517,7 +517,7 @@ int OpenTxInterface::getCapability(const Capability capability)
return (IS_TARANIS(board) ? 22 : 9);
case CustomFunctions:
if (IS_ARM(board))
return 32;
return 64;
else if (board==BOARD_GRUVIN9X||board==BOARD_M128)
return 24;
else
@@ -550,7 +550,7 @@ int OpenTxInterface::getCapability(const Capability capability)
case VoicesAsNumbers:
return (IS_ARM(board) ? 0 : 1);
case VoicesMaxLength:
return (IS_ARM(board) ? (IS_TARANIS(board) ? 10 : 6) : 0);
return (IS_ARM(board) ? (IS_TARANIS(board) ? 8 : 6) : 0);
case MultiLangVoice:
return (IS_ARM(board) ? 1 : 0);
case SoundPitch:
+207 -85
View File
@@ -117,132 +117,260 @@ const char * audioFilenames[] = {
};
uint64_t sdAvailableSystemAudioFiles = 0;
uint8_t sdAvailablePhaseAudioFiles[MAX_PHASES] = { 0 };
uint8_t sdAvailableMixerAudioFiles[MAX_MIXERS] = { 0 };
uint32_t sdAvailablePhaseAudioFiles = 0;
uint64_t sdAvailableSwitchAudioFiles = 0;
uint64_t sdAvailableLogicalSwitchAudioFiles = 0;
void refreshSystemAudioFiles()
#define MASK_SYSTEM_AUDIO_FILE(index) ((uint64_t)1 << index)
#define MASK_PHASE_AUDIO_FILE(index, event) ((uint32_t)1 << (2*index+event))
#define MASK_SWITCH_AUDIO_FILE(index) ((uint64_t)1 << index)
#define MASK_LOGICAL_SWITCH_AUDIO_FILE(index, event) ((uint64_t)1 << (2*index+event))
bool isFileAvailable(const char * filename)
{
FILINFO info;
#if _USE_LFN
TCHAR lfn[_MAX_LFN + 1];
info.lfname = lfn;
info.lfsize = sizeof(lfn);
#endif
return f_stat(filename, &info) == FR_OK;
}
char filename[32] = SYSTEM_SOUNDS_PATH "/";
strncpy(filename+SOUNDS_PATH_LNG_OFS, currentLanguagePack->id, 2);
char * getAudioPath(char * path)
{
strcpy(path, SOUNDS_PATH "/");
strncpy(path+SOUNDS_PATH_LNG_OFS, currentLanguagePack->id, 2);
return path + sizeof(SOUNDS_PATH);
}
char * getSystemAudioPath(char * path)
{
char * str = getAudioPath(path);
strcpy(str, SYSTEM_SUBDIR "/");
return str + sizeof(SYSTEM_SUBDIR);
}
void getSystemAudioFile(char * filename, int index)
{
char * str = getSystemAudioPath(filename);
strcpy(str, audioFilenames[index]);
strcat(str, SOUNDS_EXT);
}
void referenceSystemAudioFiles()
{
char path[AUDIO_FILENAME_MAXLEN+1];
FILINFO fno;
DIR dir;
char *fn; /* This function is assuming non-Unicode cfg. */
TCHAR lfn[_MAX_LFN + 1];
fno.lfname = lfn;
fno.lfsize = sizeof(lfn);
uint64_t availableAudioFiles = 0;
assert(sizeof(audioFilenames)==AU_FRSKY_FIRST*sizeof(char *));
assert(sizeof(sdAvailableSystemAudioFiles)*8 >= AU_FRSKY_FIRST);
uint64_t availableAudioFiles = 0;
char * filename = getSystemAudioPath(path);
*(filename-1) = '\0';
for (uint32_t i=0; i<AU_FRSKY_FIRST; i++) {
strcpy(filename+sizeof(SYSTEM_SOUNDS_PATH), audioFilenames[i]);
strcat(filename+sizeof(SYSTEM_SOUNDS_PATH), SOUNDS_EXT);
if (f_stat(filename, &info) == FR_OK)
availableAudioFiles |= ((uint64_t)1 << i);
FRESULT res = f_opendir(&dir, path); /* Open the directory */
if (res == FR_OK) {
for (;;) {
res = f_readdir(&dir, &fno); /* Read a directory item */
if (res != FR_OK || fno.fname[0] == 0) break; /* Break on error or end of dir */
fn = *fno.lfname ? fno.lfname : fno.fname;
uint8_t len = strlen(fn);
// Eliminates directories / non wav files
if (len < 5 || strcasecmp(fn+len-4, SOUNDS_EXT) || (fno.fattrib & AM_DIR)) continue;
for (int i=0; i<AU_FRSKY_FIRST; i++) {
getSystemAudioFile(path, i);
if (!strcmp(filename, fn)) {
availableAudioFiles |= MASK_SYSTEM_AUDIO_FILE(i);
break;
}
}
}
}
sdAvailableSystemAudioFiles = availableAudioFiles;
}
const char * suffixes[] = { "-OFF", "-ON", /*"-BG", */NULL };
const char * suffixes[] = { "-off", "-on" };
inline uint8_t getAvailableFiles(char *prefix, FILINFO &info, char *filename)
char * getModelPath(char * path)
{
uint8_t result = 0;
for (uint8_t i=0; suffixes[i]; i++) {
strcpy(prefix, suffixes[i]);
strcat(prefix, SOUNDS_EXT);
if (f_stat(filename, &info) == FR_OK)
result |= ((uint8_t)1 << i);
}
strcpy(path, SOUNDS_PATH "/");
strncpy(path+SOUNDS_PATH_LNG_OFS, currentLanguagePack->id, 2);
char * result = strcat_modelname(path+sizeof(SOUNDS_PATH), g_eeGeneral.currModel);
*result++ = '/';
*result = '\0';
return result;
}
void refreshModelAudioFiles()
void getPhaseAudioFile(char * filename, int index, unsigned int event)
{
FILINFO info;
char * str = getModelPath(filename);
char * tmp = strcat_phasename(str, index);
strcpy(tmp, suffixes[event]);
strcat(tmp, SOUNDS_EXT);
}
void getSwitchAudioFile(char * filename, int index)
{
char * str = getModelPath(filename);
int len = STR_VSWITCHES[0];
strncpy(str, &STR_VSWITCHES[1+len*index], len);
str += len-1;
if (*str == '\300') {
strcpy(str, "-up");
str += 3;
}
else if (*str == '-') {
strcpy(str, "-mid");
str += 4;
}
else if (*str == '\301') {
strcpy(str, "-down");
str += 5;
}
else {
str += 1;
}
strcat(str, SOUNDS_EXT);
}
void getLogicalSwitchAudioFile(char * filename, int index, unsigned int event)
{
char * str = getModelPath(filename);
int len = STR_VSWITCHES[0];
strncpy(str, &STR_VSWITCHES[1+len*(index+SWSRC_FIRST_CSW-1)], len);
str += len;
strcpy(str, suffixes[event]);
strcat(str, SOUNDS_EXT);
}
void referenceModelAudioFiles()
{
char path[AUDIO_FILENAME_MAXLEN+1];
FILINFO fno;
DIR dir;
char *fn; /* This function is assuming non-Unicode cfg. */
TCHAR lfn[_MAX_LFN + 1];
info.lfname = lfn;
info.lfsize = sizeof(lfn);
fno.lfname = lfn;
fno.lfsize = sizeof(lfn);
char filename[AUDIO_FILENAME_MAXLEN+1] = SOUNDS_PATH "/";
strncpy(filename+SOUNDS_PATH_LNG_OFS, currentLanguagePack->id, 2);
if (sdMounted()) {
char *buf = strcat_modelname(&filename[sizeof(SOUNDS_PATH)], g_eeGeneral.currModel);
*buf++ = '/';
sdAvailablePhaseAudioFiles = 0;
sdAvailableSwitchAudioFiles = 0;
sdAvailableLogicalSwitchAudioFiles = 0;
for (uint32_t i=0; i<MAX_PHASES; i++) {
char *tmp = strcat_phasename(buf, i);
sdAvailablePhaseAudioFiles[i] = (tmp != buf ? getAvailableFiles(strcat_phasename(buf, i), info, filename) : 0);
char * filename = getModelPath(path);
*(filename-1) = '\0';
FRESULT res = f_opendir(&dir, path); /* Open the directory */
if (res == FR_OK) {
for (;;) {
res = f_readdir(&dir, &fno); /* Read a directory item */
if (res != FR_OK || fno.fname[0] == 0) break; /* Break on error or end of dir */
fn = *fno.lfname ? fno.lfname : fno.fname;
uint8_t len = strlen(fn);
bool found = false;
// Eliminates directories / non wav files
if (len < 5 || strcasecmp(fn+len-4, SOUNDS_EXT) || (fno.fattrib & AM_DIR)) continue;
// Phases Audio Files <phasename>-[on|off].wav
for (int i=0; i<MAX_PHASES && !found; i++) {
for (int event=0; event<2; event++) {
getPhaseAudioFile(path, i, event);
if (!strcmp(filename, fn)) {
sdAvailablePhaseAudioFiles |= MASK_PHASE_AUDIO_FILE(i, event);
found = true;
break;
}
}
}
// Switches Audio Files <switchname>-[up|mid|down].wav
for (int i=0; i<SWSRC_LAST_SWITCH+NUM_XPOTS*POTS_POS_COUNT && !found; i++) {
getSwitchAudioFile(path, i);
if (!strcmp(filename, fn)) {
sdAvailableSwitchAudioFiles |= MASK_SWITCH_AUDIO_FILE(i);
found = true;
}
}
// Logical Switches Audio Files <switchname>-[on|off].wav
for (int i=0; i<NUM_CSW && !found; i++) {
for (int event=0; event<2; event++) {
getLogicalSwitchAudioFile(path, i, event);
if (!strcmp(filename, fn)) {
sdAvailableLogicalSwitchAudioFiles |= MASK_LOGICAL_SWITCH_AUDIO_FILE(i, event);
found = true;
break;
}
}
}
}
/* for (uint32_t i=0; i<MAX_MIXERS; i++) {
char *tmp = strcat_mixername_nodefault(buf, i);
sdAvailableMixerAudioFiles[i] = (tmp != buf ? getAvailableFiles(tmp, info, filename) : 0);
} */
}
}
bool isAudioFileAvailable(uint32_t i, char * filename)
bool isAudioFileReferenced(uint32_t i, char * filename)
{
uint8_t category = (i >> 24);
uint8_t index = (i >> 16) & 0xFF;
uint8_t event = i & 0xFF;
#if 0
printf("isAudioFileAvailable(%08x)\n", i); fflush(stdout);
printf("isAudioFileReferenced(%08x)\n", i); fflush(stdout);
#endif
if (category == SYSTEM_AUDIO_CATEGORY) {
if (sdAvailableSystemAudioFiles & ((uint64_t)1 << event)) {
strcpy(filename, SYSTEM_SOUNDS_PATH "/");
strncpy(filename+SOUNDS_PATH_LNG_OFS, currentLanguagePack->id, 2);
strcpy(filename+sizeof(SYSTEM_SOUNDS_PATH), audioFilenames[i]);
strcat(filename+sizeof(SYSTEM_SOUNDS_PATH), SOUNDS_EXT);
if (sdAvailableSystemAudioFiles & MASK_SYSTEM_AUDIO_FILE(event)) {
getSystemAudioFile(filename, event);
return true;
}
}
else if (category == PHASE_AUDIO_CATEGORY) {
if (sdAvailablePhaseAudioFiles[index] & ((uint32_t)1 << event)) {
strcpy(filename, SOUNDS_PATH "/");
strncpy(filename+SOUNDS_PATH_LNG_OFS, currentLanguagePack->id, 2);
char *str = strcat_modelname(filename+sizeof(SOUNDS_PATH), g_eeGeneral.currModel);
*str++ = '/';
char * tmp = strcat_phasename(str, index);
if (tmp != str) {
strcpy(tmp, suffixes[event]);
strcat(tmp, SOUNDS_EXT);
return true;
}
if (sdAvailablePhaseAudioFiles & MASK_PHASE_AUDIO_FILE(index, event)) {
getPhaseAudioFile(filename, index, event);
return true;
}
}
else if (category == MIXER_AUDIO_CATEGORY) {
if (sdAvailableMixerAudioFiles[index] & ((uint32_t)1 << event)) {
strcpy(filename, SOUNDS_PATH "/");
strncpy(filename+SOUNDS_PATH_LNG_OFS, currentLanguagePack->id, 2);
char *str = strcat_modelname(filename+sizeof(SOUNDS_PATH), g_eeGeneral.currModel);
*str++ = '/';
char * tmp = strcat_mixername(str, index);
if (tmp != str) {
strcpy(tmp, suffixes[event]);
strcat(tmp, SOUNDS_EXT);
return true;
}
else if (category == SWITCH_AUDIO_CATEGORY) {
if (sdAvailableSwitchAudioFiles & MASK_SWITCH_AUDIO_FILE(index)) {
getSwitchAudioFile(filename, index);
return true;
}
}
else if (category == LOGICAL_SWITCH_AUDIO_CATEGORY) {
if (sdAvailableLogicalSwitchAudioFiles & MASK_LOGICAL_SWITCH_AUDIO_FILE(index, event)) {
getLogicalSwitchAudioFile(filename, index, event);
return true;
}
}
return false;
}
tmr10ms_t timeAutomaticPromptsSilence = 0;
void playModelEvent(uint8_t category, uint8_t index, uint8_t event)
{
char filename[AUDIO_FILENAME_MAXLEN+1];
if ((get_tmr10ms()-timeAutomaticPromptsSilence > 50) && isAudioFileReferenced((category << 24) + (index << 16) + event, filename)) {
audioQueue.playFile(filename);
}
}
#else
#define isAudioFileAvailable(i, f) false
#define isAudioFileReferenced(i, f) false
#endif
// TODO should be generated and in flash rather than in ram
int16_t alawTable[256];
int16_t ulawTable[256];
@@ -757,10 +885,6 @@ void AudioQueue::reset()
void audioEvent(uint8_t e, uint16_t f)
{
#if defined(SDCARD)
char filename[AUDIO_FILENAME_MAXLEN+1];
#endif
#if defined(HAPTIC)
haptic.event(e); //do this before audio to help sync timings
#endif
@@ -773,7 +897,8 @@ void audioEvent(uint8_t e, uint16_t f)
if (g_eeGeneral.beepMode>0 || (g_eeGeneral.beepMode==0 && e>=AU_TRIM_MOVE) || (g_eeGeneral.beepMode>=-1 && e<=AU_ERROR)) {
#if defined(SDCARD)
if (e < AU_FRSKY_FIRST && isAudioFileAvailable(e, filename)) {
char filename[AUDIO_FILENAME_MAXLEN+1];
if (e < AU_FRSKY_FIRST && isAudioFileReferenced(e, filename)) {
audioQueue.playFile(filename);
}
else
@@ -982,16 +1107,13 @@ void audioEvent(uint8_t e, uint16_t f)
void pushPrompt(uint16_t prompt, uint8_t id)
{
#if defined(SDCARD)
char filename[] = SYSTEM_SOUNDS_PATH "/0000" SOUNDS_EXT;
strncpy(filename+SOUNDS_PATH_LNG_OFS, currentLanguagePack->id, 2);
char filename[AUDIO_FILENAME_MAXLEN+1];
char * str = getSystemAudioPath(filename);
strcpy(str, "0000" SOUNDS_EXT);
for (int8_t i=3; i>=0; i--) {
filename[sizeof(SYSTEM_SOUNDS_PATH)+i] = '0' + (prompt%10);
str[i] = '0' + (prompt%10);
prompt /= 10;
}
audioQueue.playFile(filename, 0, id);
#endif
}
+29 -13
View File
@@ -277,16 +277,21 @@ void audioStart();
#define AUDIO_HEARTBEAT()
#define SYSTEM_AUDIO_CATEGORY 0
#define MODEL_AUDIO_CATEGORY 1
#define PHASE_AUDIO_CATEGORY 2
#define MIXER_AUDIO_CATEGORY 3
enum AutomaticPromptsCategories {
SYSTEM_AUDIO_CATEGORY,
MODEL_AUDIO_CATEGORY,
PHASE_AUDIO_CATEGORY,
SWITCH_AUDIO_CATEGORY,
LOGICAL_SWITCH_AUDIO_CATEGORY,
};
#define AUDIO_EVENT_OFF 0
#define AUDIO_EVENT_ON 1
#define AUDIO_EVENT_BG 2
enum AutomaticPromptsEvents {
AUDIO_EVENT_OFF,
AUDIO_EVENT_ON,
AUDIO_EVENT_MID,
};
extern void pushPrompt(uint16_t prompt, uint8_t id=0);
void pushPrompt(uint16_t prompt, uint8_t id=0);
#define I18N_PLAY_FUNCTION(lng, x, ...) void lng ## _ ## x(__VA_ARGS__, uint8_t id)
#define PLAY_FUNCTION(x, ...) void x(__VA_ARGS__, uint8_t id)
@@ -300,15 +305,26 @@ extern void pushPrompt(uint16_t prompt, uint8_t id=0);
#define AUDIO_RESET() audioQueue.reset()
#if defined(SDCARD)
#define PLAY_PHASE_OFF(phase) do { char filename[AUDIO_FILENAME_MAXLEN+1]; if (isAudioFileAvailable((PHASE_AUDIO_CATEGORY << 24) + (phase << 16) + AUDIO_EVENT_OFF, filename)) audioQueue.playFile(filename); } while (0)
#define PLAY_PHASE_ON(phase) do { char filename[AUDIO_FILENAME_MAXLEN+1]; if (isAudioFileAvailable((PHASE_AUDIO_CATEGORY << 24) + (phase << 16) + AUDIO_EVENT_ON, filename)) audioQueue.playFile(filename); } while (0)
extern tmr10ms_t timeAutomaticPromptsSilence;
void playModelEvent(uint8_t category, uint8_t index, uint8_t event=0);
#define PLAY_PHASE_OFF(phase) playModelEvent(PHASE_AUDIO_CATEGORY, phase, AUDIO_EVENT_OFF)
#define PLAY_PHASE_ON(phase) playModelEvent(PHASE_AUDIO_CATEGORY, phase, AUDIO_EVENT_ON)
#define PLAY_SWITCH_MOVED(sw) playModelEvent(SWITCH_AUDIO_CATEGORY, sw)
#define PLAY_LOGICAL_SWITCH_OFF(sw) playModelEvent(LOGICAL_SWITCH_AUDIO_CATEGORY, sw, AUDIO_EVENT_OFF)
#define PLAY_LOGICAL_SWITCH_ON(sw) playModelEvent(LOGICAL_SWITCH_AUDIO_CATEGORY, sw, AUDIO_EVENT_ON)
#define SKIP_AUTOMATIC_PROMPTS() timeAutomaticPromptsSilence = get_tmr10ms()
#else
#define PLAY_PHASE_OFF(phase)
#define PLAY_PHASE_ON(phase)
#define PLAY_SWITCH_MOVED(sw)
#define PLAY_LOGICAL_SWITCH_OFF(sw)
#define PLAY_LOGICAL_SWITCH_ON(sw)
#define SKIP_AUTOMATIC_PROMPTS()
#endif
extern void refreshSystemAudioFiles();
extern void refreshModelAudioFiles();
extern bool isAudioFileAvailable(uint32_t i, char * filename);
void referenceSystemAudioFiles();
void referenceModelAudioFiles();
bool isAudioFileReferenced(uint32_t i, char * filename/*at least AUDIO_FILENAME_MAXLEN+1 long*/);
#endif
+4
View File
@@ -157,5 +157,9 @@ void audioDefevent(uint8_t e);
#define PLAY_PHASE_OFF(phase)
#define PLAY_PHASE_ON(phase)
#define PLAY_SWITCH_MOVED(sw)
#define PLAY_LOGICAL_SWITCH_OFF(sw)
#define PLAY_LOGICAL_SWITCH_ON(sw)
#define SKIP_AUTOMATIC_PROMPTS()
#endif
+4
View File
@@ -102,6 +102,10 @@ void beep(uint8_t val);
#define PLAY_PHASE_OFF(phase)
#define PLAY_PHASE_ON(phase)
#define PLAY_SWITCH_MOVED(sw)
#define PLAY_LOGICAL_SWITCH_OFF(sw)
#define PLAY_LOGICAL_SWITCH_ON(sw)
#define SKIP_AUTOMATIC_PROMPTS()
#endif
#if !defined(CPUARM)
+3 -3
View File
@@ -144,7 +144,7 @@ PACK(typedef struct {
int8_t swtch;
uint8_t func;
PACK(union {
char name[LEN_CFN_NAME];
char name[10];
struct {
int16_t val;
int16_t ext1;
@@ -193,7 +193,7 @@ PACK(typedef struct {
int8_t points[NUM_POINTS];
LogicalSwitchData_v215 customSw[NUM_CSW];
CustomFnData_v215 funcSw[NUM_CFN];
CustomFnData_v215 funcSw[32];
SwashRingData swashR;
PhaseData_v215 phaseData[MAX_PHASES];
@@ -593,7 +593,7 @@ void ConvertModel_215_to_216(ModelData &model)
}
if (fn.func == FUNC_PLAY_TRACK || fn.func == FUNC_BACKGND_MUSIC) {
memcpy(fn.play.name, oldModel.funcSw[i].param.name, LEN_CFN_NAME);
memcpy(fn.play.name, oldModel.funcSw[i].param.name, 8);
}
else {
fn.all.val = oldModel.funcSw[i].param.composite.val;
+1 -1
View File
@@ -404,7 +404,7 @@ void eeLoadModel(uint8_t id)
#endif
#if defined(CPUARM) && defined(SDCARD)
refreshModelAudioFiles();
referenceModelAudioFiles();
#endif
LOAD_MODEL_BITMAP();
+1 -1
View File
@@ -978,7 +978,7 @@ void eeLoadModel(uint8_t id)
#endif
#if defined(CPUARM) && defined(SDCARD)
refreshModelAudioFiles();
referenceModelAudioFiles();
#endif
LOAD_MODEL_BITMAP();
+3 -3
View File
@@ -5139,8 +5139,8 @@ void onModelCustomScriptMenu(const char *result)
ScriptData &sd = g_model.scriptsData[s_currIdx];
if (result == STR_UPDATE_LIST) {
if (!listSdFiles(SCRIPTS_PATH, MIXES_EXT, sizeof(sd.file), NULL)) {
POPUP_WARNING(STR_NO_BITMAPS_ON_SD);
if (!listSdFiles(SCRIPTS_PATH, SCRIPTS_EXT, sizeof(sd.file), NULL)) {
POPUP_WARNING(STR_NO_SCRIPTS_ON_SD);
s_menu_flags = 0;
}
}
@@ -5187,7 +5187,7 @@ void menuModelCustomScriptOne(uint8_t event)
lcd_putsiAtt(SCRIPT_ONE_2ND_COLUMN_POS, y, STR_VCSWFUNC, 0, attr);
if (attr && event==EVT_KEY_BREAK(KEY_ENTER) && !READ_ONLY()) {
s_editMode = 0;
if (listSdFiles(SCRIPTS_PATH, MIXES_EXT, sizeof(sd.file), sd.file, LIST_NONE_SD_FILE)) {
if (listSdFiles(SCRIPTS_PATH, SCRIPTS_EXT, sizeof(sd.file), sd.file, LIST_NONE_SD_FILE)) {
menuHandler = onModelCustomScriptMenu;
}
else {
+2 -2
View File
@@ -935,10 +935,10 @@ void luaLoadModelScript(uint8_t index)
sid.state = SCRIPT_NOFILE;
if (ZEXIST(sd.file)) {
char filename[sizeof(SCRIPTS_PATH)+sizeof(sd.file)+sizeof(MIXES_EXT)] = SCRIPTS_PATH "/";
char filename[sizeof(SCRIPTS_PATH)+sizeof(sd.file)+sizeof(SCRIPTS_EXT)] = SCRIPTS_PATH "/";
strncpy(filename+sizeof(SCRIPTS_PATH), sd.file, sizeof(sd.file));
filename[sizeof(SCRIPTS_PATH)+sizeof(sd.file)] = '\0';
strcat(filename+sizeof(SCRIPTS_PATH), MIXES_EXT);
strcat(filename+sizeof(SCRIPTS_PATH), SCRIPTS_EXT);
luaLoad(filename, sid);
}
}
+6 -5
View File
@@ -74,8 +74,8 @@
#define MAX_MIXERS 64
#define MAX_EXPOS 64
#define NUM_CSW 32 // number of custom switches
#define NUM_CFN 32 // number of functions assigned to switches
#define MAX_SCRIPTS 3
#define NUM_CFN 64 // number of functions assigned to switches
#define MAX_SCRIPTS 7
#define MAX_INPUTS 32
#elif defined(CPUARM)
#define MAX_MODELS 60
@@ -84,7 +84,7 @@
#define MAX_MIXERS 64
#define MAX_EXPOS 32
#define NUM_CSW 32 // number of custom switches
#define NUM_CFN 32 // number of functions assigned to switches
#define NUM_CFN 64 // number of functions assigned to switches
#elif defined(CPUM2560) || defined(CPUM2561)
#define MAX_MODELS 30
#define NUM_CHNOUT 16 // number of real output channels CH1-CH16
@@ -323,8 +323,9 @@ enum BacklightMode {
#define SPLASH_MODE uint8_t splashMode:1; uint8_t spare4:2
#endif
#if defined(PCBTARANIS)
#define POTS_POS_COUNT 6
#if defined(PCBTARANIS)
PACK(typedef struct {
uint8_t count;
uint8_t steps[POTS_POS_COUNT-1];
@@ -822,7 +823,7 @@ enum AdjustGvarFunctionParam {
#if defined(CPUARM)
#if defined(PCBTARANIS)
#define LEN_CFN_NAME 10
#define LEN_CFN_NAME 8
#else
#define LEN_CFN_NAME 6
#endif
+139 -100
View File
@@ -1314,7 +1314,6 @@ getvalue_t getValue(uint8_t i)
volatile GETSWITCH_RECURSIVE_TYPE s_last_switch_used = 0;
volatile GETSWITCH_RECURSIVE_TYPE s_last_switch_value = 0;
/* recursive function. stack as of today (16/03/2012) grows by 8bytes at each call, which is ok! */
#if defined(CPUARM)
uint32_t cswDelays[NUM_CSW];
@@ -1327,27 +1326,66 @@ tmr10ms_t switchesMidposStart[6] = { 0 };
uint32_t switchesPos = 0;
tmr10ms_t potsLastposStart[NUM_XPOTS];
uint8_t potsPos[NUM_XPOTS];
uint32_t check2PosSwitchPosition(EnumKeys sw)
{
uint32_t result;
uint32_t index;
if (switchState(sw))
index = sw - SW_SA0;
else
index = sw - SW_SA0 + 1;
result = (1 << index);
if (!(switchesPos & result)) {
PLAY_SWITCH_MOVED(index);
}
return result;
}
#define DELAY_SWITCH_3POS 10/*100ms*/
#define CHECK_2POS(sw) newPos |= (switchState(sw ## 0) ? (1 << (sw ## 0 - SW_SA0)) : (1 << (sw ## 0 - SW_SA0 + 1)))
#define CHECK_3POS(idx, sw) if (switchState(sw ## 0)) { \
newPos |= (1 << (sw ## 0 - SW_SA0)); \
switchesMidposStart[idx] = 0; \
} \
else if (switchState(sw ## 2)) { \
newPos |= (1 << (sw ## 0 - SW_SA0 + 2)); \
switchesMidposStart[idx] = 0; \
} \
else if ((switchesPos & (1 << (sw ## 0 - SW_SA0 + 1))) || (switchesMidposStart[idx] && (tmr10ms_t)(get_tmr10ms() - switchesMidposStart[idx]) > DELAY_SWITCH_3POS)) { \
newPos |= (1 << (sw ## 0 - SW_SA0 + 1)); \
switchesMidposStart[idx] = 0; \
} \
else { \
if (!switchesMidposStart[idx]) { \
switchesMidposStart[idx] = get_tmr10ms(); \
} \
newPos |= (switchesPos & (0x7 << (sw ## 0 - SW_SA0))); \
}
void getSwitchesPosition()
uint32_t check3PosSwitchPosition(uint8_t idx, EnumKeys sw, bool startup)
{
uint32_t result;
uint32_t index;
if (switchState(sw)) {
index = sw - SW_SA0;
result = (1 << index);
switchesMidposStart[idx] = 0;
}
else if (switchState(EnumKeys(sw+2))) {
index = sw - SW_SA0 + 2;
result = (1 << index);
switchesMidposStart[idx] = 0;
}
else if (startup || (switchesPos & (1 << (sw - SW_SA0 + 1))) || (switchesMidposStart[idx] && (tmr10ms_t)(get_tmr10ms() - switchesMidposStart[idx]) > DELAY_SWITCH_3POS)) {
index = sw - SW_SA0 + 1;
result = (1 << index);
switchesMidposStart[idx] = 0;
}
else {
index = sw - SW_SA0 + 1;
if (!switchesMidposStart[idx]) {
switchesMidposStart[idx] = get_tmr10ms();
}
result = (switchesPos & (0x7 << (sw - SW_SA0)));
}
if (!(switchesPos & result)) {
PLAY_SWITCH_MOVED(index);
}
return result;
}
#define CHECK_2POS(sw) newPos |= check2PosSwitchPosition(sw ## 0)
#define CHECK_3POS(idx, sw) newPos |= check3PosSwitchPosition(idx, sw ## 0, startup)
void getSwitchesPosition(bool startup)
{
uint32_t newPos = 0;
CHECK_3POS(0, SW_SA);
@@ -1366,13 +1404,17 @@ void getSwitchesPosition()
if (calib->count>0 && calib->count<POTS_POS_COUNT) {
uint8_t pos = anaIn(POT1+i) / (2*RESX/calib->count);
uint8_t previousPos = potsPos[i] >> 4;
uint8_t previousStoredPos = potsPos[i] & 0x0F;
if (pos != previousPos) {
potsLastposStart[i] = get_tmr10ms();
potsPos[i] = (pos << 4) | (potsPos[i] & 0x0f);
potsPos[i] = (pos << 4) | previousStoredPos;
}
else if ((tmr10ms_t)(get_tmr10ms() - potsLastposStart[i]) > DELAY_SWITCH_3POS) {
else if (startup || (tmr10ms_t)(get_tmr10ms() - potsLastposStart[i]) > DELAY_SWITCH_3POS) {
potsLastposStart[i] = 0;
potsPos[i] = (pos << 4) | (pos);
potsPos[i] = (pos << 4) | pos;
if (previousStoredPos != pos) {
PLAY_SWITCH_MOVED(SWSRC_LAST_SWITCH+i*POTS_POS_COUNT+pos);
}
}
}
}
@@ -1381,16 +1423,14 @@ void getSwitchesPosition()
#define SWITCH_POSITION(sw) (switchesPos & (1<<(sw)))
#define POT_POSITION(sw) ((potsPos[(sw)/POTS_POS_COUNT] & 0x0f) == ((sw) % POTS_POS_COUNT))
#else
#define getSwitchesPosition()
#define getSwitchesPosition(...)
#define SWITCH_POSITION(idx) switchState((EnumKeys)(SW_BASE+(idx)))
#endif
int16_t csLastValue[NUM_CSW];
#define CS_LAST_VALUE_INIT -32768
// param swtch may be (negativ sign ignored)
// 0 --> no source
// 1 .. 9 (or max switches) --> returns switch value including 3pos
// others internal switches etc.
/* recursive function. stack as of today (16/03/2012) grows by 8bytes at each call, which is ok! */
bool getSwitch(int8_t swtch)
{
bool result;
@@ -1610,10 +1650,14 @@ bool getSwitch(int8_t swtch)
}
#endif
if (result)
if (result) {
if (!(s_last_switch_value&mask)) PLAY_LOGICAL_SWITCH_ON(cs_idx);
s_last_switch_value |= mask;
else
}
else {
if (s_last_switch_value&mask) PLAY_LOGICAL_SWITCH_OFF(cs_idx);
s_last_switch_value &= ~mask;
}
}
}
@@ -1644,53 +1688,24 @@ int8_t getMovedSwitch()
}
}
#else
// saves about 50 bytes flash
// return delivers 1 to 3 for ID1 to ID3
// 4..8 for all other switches if changed to true
// -4..-8 for all other switches if changed to false
// 9 for Trainer switch if changed to true; Change to false is ignored
swstate_t mask=0x80;
swstate_t mask = 0x80;
for (uint8_t i=NUM_PSWITCH; i>1; i--) {
bool prev;
// mask= (1<<(i-2));
prev=(switches_states & mask);
prev = (switches_states & mask);
// don't use getSwitch here to always get the proper value, even getSwitch manipulates
// bool next = getSwitch(i);
bool next = switchState((EnumKeys)(SW_BASE+i-1));
if (prev!=next) {
if (((i<NUM_PSWITCH) && (i>3)) || next==true)
result = next ? i : -i;
if ((i<=3) && (result==0)) result=1;
switches_states ^= mask;
}
mask>>=1;
} //endfor
/*
for (uint8_t i=NUM_PSWITCH; i>0; i--) {
bool prev;
swstate_t mask = 0;
if (i <= 3) {
prev = ((switches_states & 0x03) == (i-1));
}
else {
mask = (1<<(i-2));
prev = (switches_states & mask);
}
// don't use getSwitch here to always get the proper value, because getSwitch manipulates
// bool next = getSwitch(i);
bool next = switchState((EnumKeys)(SW_BASE+i-1));
if (prev != next) {
if (i!=NUM_PSWITCH || next==true)
if (((i<NUM_PSWITCH) && (i>3)) || next==true)
result = next ? i : -i;
if (mask)
switches_states ^= mask;
else {
switches_states = (switches_states & 0xFC) | (i-1);
}
if (i<=3 && result==0) result = 1;
switches_states ^= mask;
}
} //endfor */
mask >>= 1;
}
#endif
if ((tmr10ms_t)(get_tmr10ms() - s_move_last_time) > 10)
@@ -2303,6 +2318,8 @@ void checkAll()
#endif
clearKeyEvents();
SKIP_AUTOMATIC_PROMPTS();
}
#if defined(MODULE_ALWAYS_SEND_PULSES)
@@ -2351,30 +2368,39 @@ void checkTHR()
if (g_model.disableThrottleWarning) return;
getADC();
evalInputs(e_perout_mode_notrainer); // let do evalInputs do the job
int16_t v = calibratedStick[thrchn];
if (v<=(THRCHK_DEADBAND-1024)) return; // prevent warning if throttle input OK
// first - display warning; also deletes inputs if any have been before
MESSAGE(STR_THROTTLEWARN, STR_THROTTLENOTIDLE, STR_PRESSANYKEYTOSKIP, AU_THROTTLE_ALERT);
while (1) {
SIMU_SLEEP(1);
getADC();
while (1) {
SIMU_SLEEP(1);
evalInputs(e_perout_mode_notrainer); // let do evalInputs do the job
v = calibratedStick[thrchn];
if (pwrCheck()==e_power_off || keyDown() || v<=(THRCHK_DEADBAND-1024))
break;
getADC();
evalInputs(e_perout_mode_notrainer); // let do evalInputs do the job
v = calibratedStick[thrchn];
if (pwrCheck()==e_power_off || keyDown() || v<=(THRCHK_DEADBAND-1024))
break;
checkBacklight();
wdt_reset();
}//endwhile
checkBacklight();
wdt_reset();
}
#endif
}
void checkAlarm() // added by Gohst
{
if (g_eeGeneral.disableAlarmWarning) return;
if (IS_SOUND_OFF()) ALERT(STR_ALARMSWARN, STR_ALARMSDISABLED, AU_ERROR);
if (g_eeGeneral.disableAlarmWarning)
return;
if (IS_SOUND_OFF())
ALERT(STR_ALARMSWARN, STR_ALARMSDISABLED, AU_ERROR);
}
void checkSwitches()
@@ -2405,19 +2431,21 @@ void checkSwitches()
for (uint8_t i=0; i<NUM_SWITCHES-1; i++) {
if (!(g_model.nSwToWarn & (1<<i))) {
swstate_t mask = (0x03 << (i*2));
if(!((states & mask) == (switches_states & mask)))
if (!((states & mask) == (switches_states & mask))) {
warn = true;
}
}
}
uint8_t potMode = g_model.nPotsToWarn >> 6;
if(potMode) {
if (potMode) {
perOut(e_perout_mode_normal, 0);
bad_pots = 0;
for (uint8_t i=0; i<NUM_POTS; i++)
if(!(g_model.nPotsToWarn & (1 << i)) && (abs(g_model.potPosition[i] - (getValue(MIXSRC_FIRST_POT+i) >> 3)) > 2)) {
warn = true;
bad_pots |= (1<<i);
}
for (uint8_t i=0; i<NUM_POTS; i++) {
if (!(g_model.nPotsToWarn & (1 << i)) && (abs(g_model.potPosition[i] - (getValue(MIXSRC_FIRST_POT+i) >> 3)) > 2)) {
warn = true;
bad_pots |= (1<<i);
}
}
}
#else
for (uint8_t i=0; i<NUM_SWITCHES-1; i++) {
@@ -2447,7 +2475,7 @@ void checkSwitches()
if ((last_bad_switches != switches_states) || (last_bad_pots != bad_pots)) {
MESSAGE(STR_SWITCHWARN, NULL, STR_PRESSANYKEYTOSKIP, ((last_bad_switches == 0xff) || (last_bad_pots == 0xff)) ? AU_SWITCH_ALERT : AU_NONE);
for (uint8_t i=0; i<NUM_SWITCHES-1; i++) {
if(!(g_model.nSwToWarn & (1<<i))) {
if (!(g_model.nSwToWarn & (1<<i))) {
swstate_t mask = (0x03 << (i*2));
uint8_t attr = ((states & mask) == (switches_states & mask)) ? 0 : INVERS;
char c = "\300-\301"[(states & mask) >> (i*2)];
@@ -2455,7 +2483,7 @@ void checkSwitches()
lcd_putcAtt(60+i*(2*FW+FW/2)+FW, 4*FH+3, c, attr);
}
}
if(potMode) {
if (potMode) {
for (uint8_t i=0; i<NUM_POTS; i++) {
if (!(g_model.nPotsToWarn & (1 << i))) {
uint8_t flags = 0;
@@ -2465,8 +2493,8 @@ void checkSwitches()
case 1:
lcd_putc(60+i*(5*FW)+2*FW+2, 6*FH-2, g_model.potPosition[i] > (getValue(MIXSRC_FIRST_POT+i) >> 3) ? 126 : 127);
break;
case 2:
case 3:
case 2:
case 3:
lcd_putc(60+i*(5*FW)+2*FW+2, 6*FH-2, g_model.potPosition[i] > (getValue(MIXSRC_FIRST_POT+i) >> 3) ? '\300' : '\301');
break;
}
@@ -2484,11 +2512,11 @@ void checkSwitches()
for (uint8_t i=0; i<NUM_SWITCHES-1; i++) {
uint8_t attr;
if (i == 0)
attr = ((states & 0x03) != (switches_states & 0x03)) ? INVERS : 0;
attr = ((states & 0x03) != (switches_states & 0x03)) ? INVERS : 0;
else
attr = (states & (1 << (i+1))) == (switches_states & (1 << (i+1))) ? 0 : INVERS;
if(!(g_model.nSwToWarn & (1<<i)))
putsSwitches(x, 5*FH, (i>0?(i+3):(states&0x3)+1), attr);
attr = (states & (1 << (i+1))) == (switches_states & (1 << (i+1))) ? 0 : INVERS;
if (!(g_model.nSwToWarn & (1<<i)))
putsSwitches(x, 5*FH, (i>0?(i+3):(states&0x3)+1), attr);
x += 3*FW+FW/2;
}
#endif
@@ -2947,11 +2975,14 @@ void resetAll()
#if defined(FRSKY)
resetTelemetry();
#endif
for (uint8_t i=0; i<NUM_CSW; i++)
for (uint8_t i=0; i<NUM_CSW; i++) {
csLastValue[i] = CS_LAST_VALUE_INIT;
}
s_last_switch_value = 0;
SKIP_AUTOMATIC_PROMPTS();
RESET_THR_TRACE();
}
@@ -3345,7 +3376,7 @@ void evalFunctions()
if (active || IS_PLAY_BOTH_FUNC(CFN_FUNC(sd))) {
switch(CFN_FUNC(sd)) {
switch (CFN_FUNC(sd)) {
case FUNC_SAFETY_CHANNEL:
safetyCh[CFN_CH_INDEX(sd)] = CFN_PARAM(sd);
@@ -3954,17 +3985,25 @@ void doMixerCalculations()
PORTH |= 0x40; // PORTH:6 LOW->HIGH signals start of mixer interrupt
#endif
static tmr10ms_t lastTMR;
static tmr10ms_t lastTMR = 0;
tmr10ms_t tmr10ms = get_tmr10ms();
uint8_t tick10ms = (tmr10ms >= lastTMR ? tmr10ms - lastTMR : 1); // handle tick10ms overrun
//@@@ open.20.fsguruh: correct overflow handling costs a lot of code; happens only each 11 min;
uint8_t tick10ms = (tmr10ms >= lastTMR ? tmr10ms - lastTMR : 1);
// handle tick10ms overrun
// correct overflow handling costs a lot of code; happens only each 11 min;
// therefore forget the exact calculation and use only 1 instead; good compromise
#if !defined(CPUARM)
lastTMR = tmr10ms;
#endif
getADC();
getSwitchesPosition();
getSwitchesPosition(lastTMR == 0);
#if defined(CPUARM)
lastTMR = tmr10ms;
#endif
#if defined(PCBSKY9X) && !defined(REVA) && !defined(SIMU)
Current_analogue = (Current_analogue*31 + s_anaFilt[8] ) >> 5 ;
+1 -2
View File
@@ -1639,8 +1639,7 @@ uint8_t zlen(const char *str, uint8_t size);
bool zexist(const char *str, uint8_t size);
char * strcat_zchar(char * dest, char * name, uint8_t size, const char *defaultName, uint8_t defaultNameSize, uint8_t defaultIdx);
#define strcat_modelname(dest, idx) strcat_zchar(dest, modelHeaders[idx].name, LEN_MODEL_NAME, STR_MODEL, PSIZE(TR_MODEL), idx+1)
#define strcat_phasename(dest, idx) strcat_zchar(dest, g_model.phaseData[idx].name, LEN_FP_NAME, NULL, 0, 0)
#define strcat_mixername(dest, idx) strcat_zchar(dest, g_model.mixData[idx].name, LEN_EXPOMIX_NAME, NULL, 0, 0)
#define strcat_phasename(dest, idx) strcat_zchar(dest, g_model.phaseData[idx].name, LEN_FP_NAME, STR_FP, PSIZE(TR_FP), idx+1)
#define ZLEN(s) zlen(s, sizeof(s))
#define ZEXIST(s) zexist(s, sizeof(s))
#endif
+1 -2
View File
@@ -44,7 +44,7 @@
#define LOGS_PATH ROOT_PATH "LOGS" // no trailing slash = important
#define SOUNDS_PATH ROOT_PATH "SOUNDS/en" // no trailing slash = important
#define SOUNDS_PATH_LNG_OFS (sizeof(SOUNDS_PATH)-3)
#define SYSTEM_SOUNDS_PATH SOUNDS_PATH "/SYSTEM" // no trailing slash = important
#define SYSTEM_SUBDIR "SYSTEM" // no trailing slash = important
#define BITMAPS_PATH ROOT_PATH "BMP"
#define SCRIPTS_PATH ROOT_PATH "SCRIPTS"
@@ -53,7 +53,6 @@
#define SOUNDS_EXT ".wav"
#define BITMAPS_EXT ".bmp"
#define SCRIPTS_EXT ".lua"
#define MIXES_EXT ".mix"
#define TEXT_EXT ".txt"
extern FATFS g_FATFS_Obj;
+4 -3
View File
@@ -300,7 +300,7 @@ void *main_thread(void *)
eeReadAll(); // load general setup and selected model
#if defined(CPUARM) && defined(SDCARD)
refreshSystemAudioFiles();
referenceSystemAudioFiles();
#endif
if (g_eeGeneral.backlightMode != e_backlight_mode_off) backlightOn(); // on Tx start turn the light on
@@ -473,9 +473,10 @@ char *convertSimuPath(const char *path)
FRESULT f_stat (const TCHAR * name, FILINFO *)
{
char *path = convertSimuPath(name);
struct stat tmp;
// printf("f_stat(%s)\n", path); fflush(stdout);
return stat(convertSimuPath(name), &tmp) ? FR_INVALID_NAME : FR_OK;
TRACE("f_stat(%s)", path);
return stat(path, &tmp) ? FR_INVALID_NAME : FR_OK;
}
FRESULT f_mount (BYTE, FATFS*)
+2 -2
View File
@@ -1014,7 +1014,7 @@ void sdMountPoll()
case SD_ST_DATA:
if (!usbPlugged() && f_mount(0, &g_FATFS_Obj) == FR_OK) {
refreshSystemAudioFiles();
referenceSystemAudioFiles();
Card_state = SD_ST_MOUNTED;
}
break;
@@ -1082,7 +1082,7 @@ void sdInit()
Card_state = SD_ST_DATA;
if (f_mount(0, &g_FATFS_Obj) == FR_OK) {
refreshSystemAudioFiles();
referenceSystemAudioFiles();
Card_state = SD_ST_MOUNTED;
}
+1 -1
View File
@@ -969,7 +969,7 @@ FIL g_telemetryFile = {0};
void sdInit()
{
if (f_mount(0, &g_FATFS_Obj) == FR_OK) {
refreshSystemAudioFiles();
referenceSystemAudioFiles();
#if defined(DEBUG)
f_open(&g_telemetryFile, LOGS_PATH "/sport.log", FA_OPEN_ALWAYS | FA_WRITE);