Binary file not shown.
|
After Width: | Height: | Size: 1.3 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 803 B |
+5
-5
@@ -26,31 +26,31 @@
|
||||
#define dumpPrintf(...) serialPrintf(__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#if defined(DEBUG) || defined(CLI)
|
||||
uint8_t dumpPosition;
|
||||
|
||||
void dumpStart(unsigned int size)
|
||||
static void dumpStart(unsigned int size)
|
||||
{
|
||||
dumpPrintf("DUMP %d bytes ...\n\r", size);
|
||||
dumpPosition = 0;
|
||||
}
|
||||
|
||||
void dumpBody(const void *data, unsigned int size)
|
||||
static void dumpBody(const void *data, unsigned int size)
|
||||
{
|
||||
for (unsigned int i=0; i<size; i++) {
|
||||
dumpPrintf("%.2X ", ((uint8_t *)data)[i]);
|
||||
dumpPosition++;
|
||||
if ((dumpPosition & (32-1)) == 0) {
|
||||
if ((dumpPosition & 31) == 0) {
|
||||
dumpPrintf(CRLF);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void dumpEnd()
|
||||
static void dumpEnd()
|
||||
{
|
||||
dumpPrintf(CRLF);
|
||||
}
|
||||
|
||||
#if defined(DEBUG) || defined(CLI)
|
||||
void dump(const void * data, unsigned int size)
|
||||
{
|
||||
dumpStart(size);
|
||||
|
||||
@@ -22,9 +22,6 @@
|
||||
#define _DUMP_H_
|
||||
|
||||
#if defined(DEBUG) || defined(CLI)
|
||||
void dumpStart(unsigned int size);
|
||||
void dumpBody(const void * data, unsigned int size);
|
||||
void dumpEnd();
|
||||
void dump(const void * data, unsigned int size);
|
||||
#else
|
||||
#define dump(data, size)
|
||||
|
||||
@@ -62,6 +62,7 @@ set(GUI_SRC
|
||||
view_channels.cpp
|
||||
view_logical_switches.cpp
|
||||
view_statistics.cpp
|
||||
view_text.cpp
|
||||
menu_screen.cpp
|
||||
screen_setup.cpp
|
||||
switch_warn_dialog.cpp
|
||||
|
||||
@@ -54,6 +54,8 @@ enum MenuIcons {
|
||||
ICON_MODEL_SPECIAL_FUNCTIONS,
|
||||
ICON_MODEL_LUA_SCRIPTS,
|
||||
ICON_MODEL_TELEMETRY,
|
||||
ICON_MODEL_SELECT,
|
||||
ICON_MODEL_SELECT_CATEGORY,
|
||||
ICON_THEME,
|
||||
ICON_THEME_SETUP,
|
||||
ICON_THEME_VIEW1,
|
||||
|
||||
@@ -21,10 +21,38 @@
|
||||
#include "static.h"
|
||||
|
||||
MessageDialog::MessageDialog(Window* parent, const char* title,
|
||||
const char* message, const char* info,
|
||||
const int lineHeight,
|
||||
const WindowFlags windowFlags,
|
||||
const LcdFlags textFlags) :
|
||||
const char* message, const char* info) :
|
||||
Dialog(parent, title, {50, 73, LCD_W - 100, LCD_H - 146})
|
||||
{
|
||||
messageWidget = new StaticText(
|
||||
this,
|
||||
{0, coord_t(height() - PAGE_LINE_HEIGHT) / 2, width(), PAGE_LINE_HEIGHT},
|
||||
message, 0, CENTERED);
|
||||
|
||||
infoWidget = new StaticText(this,
|
||||
{0, 30 + coord_t(height() - PAGE_LINE_HEIGHT) / 2,
|
||||
width(), PAGE_LINE_HEIGHT},
|
||||
info, 0, CENTERED);
|
||||
setCloseWhenClickOutside(true);
|
||||
setFocus();
|
||||
}
|
||||
|
||||
#if defined(HARDWARE_KEYS)
|
||||
void MessageDialog::onEvent(event_t event)
|
||||
{
|
||||
TRACE_WINDOWS("%s received event 0x%X", getWindowDebugString().c_str(),
|
||||
event);
|
||||
|
||||
if (event == EVT_KEY_BREAK(KEY_EXIT) || event == EVT_KEY_BREAK(KEY_ENTER)) {
|
||||
deleteLater();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
DynamicMessageDialog::DynamicMessageDialog(
|
||||
Window* parent, const char* title, std::function<std::string()> textHandler,
|
||||
const char* message, const int lineHeight,
|
||||
const LcdFlags textFlags) :
|
||||
Dialog(parent, title, {50, 73, LCD_W - 100, LCD_H - 146})
|
||||
{
|
||||
setWindowFlags(windowFlags);
|
||||
@@ -34,21 +62,22 @@ MessageDialog::MessageDialog(Window* parent, const char* title,
|
||||
{0, coord_t(height() - PAGE_LINE_HEIGHT) / 2, width(), PAGE_LINE_HEIGHT},
|
||||
message, 0, CENTERED);
|
||||
|
||||
infoWidget = new StaticText(
|
||||
infoWidget = new DynamicText(
|
||||
this,
|
||||
{0, 30 + coord_t(height() - PAGE_LINE_HEIGHT) / 2, width(), lineHeight},
|
||||
info, 0, textFlags);
|
||||
textHandler, textFlags);
|
||||
setCloseWhenClickOutside(true);
|
||||
setFocus();
|
||||
}
|
||||
|
||||
#if defined(HARDWARE_KEYS)
|
||||
void MessageDialog::onEvent(event_t event)
|
||||
void DynamicMessageDialog::onEvent(event_t event)
|
||||
{
|
||||
TRACE_WINDOWS("%s received event 0x%X", getWindowDebugString().c_str(), event);
|
||||
TRACE_WINDOWS("%s received event 0x%X", getWindowDebugString().c_str(),
|
||||
event);
|
||||
|
||||
if (event == EVT_KEY_BREAK(KEY_EXIT) || event == EVT_KEY_BREAK(KEY_ENTER)) {
|
||||
deleteLater();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
@@ -23,23 +23,46 @@
|
||||
#include "dialog.h"
|
||||
#include "static.h"
|
||||
|
||||
class MessageDialog : public Dialog
|
||||
class MessageDialog: public Dialog {
|
||||
public:
|
||||
MessageDialog(Window * parent, const char * title, const char * message, const char * info = "");
|
||||
|
||||
void setInfoText(std::string text)
|
||||
{
|
||||
infoWidget->setText(std::move(text));
|
||||
}
|
||||
|
||||
protected:
|
||||
StaticText * messageWidget;
|
||||
StaticText * infoWidget;
|
||||
|
||||
#if defined(DEBUG_WINDOWS)
|
||||
std::string getName() const override
|
||||
{
|
||||
return "MessageDialog";
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(HARDWARE_KEYS)
|
||||
void onEvent(event_t event) override;
|
||||
#endif
|
||||
};
|
||||
|
||||
class DynamicMessageDialog : public Dialog
|
||||
{
|
||||
public:
|
||||
MessageDialog(Window* parent, const char* title, const char* message,
|
||||
const char* info = "", const int lineHeight = PAGE_LINE_HEIGHT,
|
||||
const WindowFlags windowFlags = 0,
|
||||
DynamicMessageDialog(Window* parent, const char* title,
|
||||
std::function<std::string()> textHandler, const char* message = "", const int lineHeight = PAGE_LINE_HEIGHT,
|
||||
const LcdFlags textFlags = CENTERED);
|
||||
// Attn.: FONT(XXL) is not supported by MessageDialog
|
||||
// Attn.: FONT(XXL) is not supported by DynamicMessageDialog
|
||||
|
||||
void setInfoText(std::string text) { infoWidget->setText(std::move(text)); }
|
||||
|
||||
protected:
|
||||
StaticText* messageWidget;
|
||||
StaticText* infoWidget;
|
||||
LcdFlags textFlags;
|
||||
DynamicText* infoWidget;
|
||||
|
||||
#if defined(DEBUG_WINDOWS)
|
||||
std::string getName() const override { return "MessageDialog"; }
|
||||
std::string getName() const override { return "DynamicMessageDialog"; }
|
||||
#endif
|
||||
|
||||
#if defined(HARDWARE_KEYS)
|
||||
@@ -47,4 +70,5 @@ class MessageDialog : public Dialog
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
#endif // _MESSAGE_DIALOG_H_
|
||||
|
||||
@@ -284,12 +284,12 @@ class InputEditWindow : public Page
|
||||
|
||||
// Flight modes
|
||||
new StaticText(window, grid.getLabelSlot(), STR_FLMODE);
|
||||
for (uint8_t i=0; i<MAX_FLIGHT_MODES; i++) {
|
||||
for (uint32_t i=0; i<MAX_FLIGHT_MODES; i++) {
|
||||
char fm[2] = { char('0' + i), '\0'};
|
||||
if (i > 0 && (i % 4) == 0)
|
||||
grid.nextLine();
|
||||
new TextButton(window, grid.getFieldSlot(4, i % 4), fm,
|
||||
[=]() -> uint8_t {
|
||||
[=]() -> uint32_t {
|
||||
BFBIT_FLIP(line->flightModes, bfBit<uint32_t>(i));
|
||||
SET_DIRTY();
|
||||
return !(bfSingleBitGet(line->flightModes, i));
|
||||
|
||||
@@ -136,13 +136,13 @@ class MixEditWindow : public Page
|
||||
|
||||
// Flight modes
|
||||
new StaticText(window, grid.getLabelSlot(), STR_FLMODE);
|
||||
for (uint8_t i = 0; i < MAX_FLIGHT_MODES; i++) {
|
||||
for (uint32_t i = 0; i < MAX_FLIGHT_MODES; i++) {
|
||||
char fm[2] = {char('0' + i), '\0'};
|
||||
if (i > 0 && (i % 4) == 0) grid.nextLine();
|
||||
new TextButton(
|
||||
window, grid.getFieldSlot(4, i % 4), fm,
|
||||
[=]() -> uint8_t {
|
||||
BFBIT_FLIP(mix->flightModes, bfBit<uint8_t>(i));
|
||||
[=]() -> uint32_t {
|
||||
BFBIT_FLIP(mix->flightModes, bfBit<uint32_t>(i));
|
||||
SET_DIRTY();
|
||||
return !(bfSingleBitGet(mix->flightModes, i));
|
||||
},
|
||||
|
||||
@@ -244,6 +244,7 @@ class ModelCategoryPageBody : public FormWindow
|
||||
storageCheck(true);
|
||||
|
||||
modelslist.setCurrentModel(model);
|
||||
modelslist.setCurrentCategory(category);
|
||||
update();
|
||||
});
|
||||
}
|
||||
@@ -271,7 +272,7 @@ class ModelCategoryPageBody : public FormWindow
|
||||
.c_str(),
|
||||
[=] {
|
||||
modelslist.removeModel(category, model);
|
||||
update(index < category->size() - 1 ? index : index - 1);
|
||||
update(index < (int)category->size() - 1 ? index : index - 1);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -353,7 +354,7 @@ class ModelCategoryPage : public PageTab
|
||||
{
|
||||
public:
|
||||
explicit ModelCategoryPage(ModelsCategory *category) :
|
||||
PageTab(category->name, ICON_MODEL), category(category)
|
||||
PageTab(category->name, ICON_MODEL_SELECT_CATEGORY), category(category)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -369,7 +370,7 @@ class ModelCategoryPage : public PageTab
|
||||
};
|
||||
|
||||
ModelSelectMenu::ModelSelectMenu():
|
||||
TabsGroup(ICON_MODEL)
|
||||
TabsGroup(ICON_MODEL_SELECT)
|
||||
{
|
||||
modelslist.load();
|
||||
|
||||
|
||||
@@ -41,26 +41,6 @@ std::string switchWarninglabel(swsrc_t index)
|
||||
1);
|
||||
}
|
||||
|
||||
class RssiDialog : public MessageDialog
|
||||
{
|
||||
public:
|
||||
RssiDialog(Window* parent, const char* title, const char* message,
|
||||
const char* info = "", const int lineHeight = PAGE_LINE_HEIGHT,
|
||||
const WindowFlags windowFlags = 0,
|
||||
const LcdFlags textFlags = CENTERED) :
|
||||
MessageDialog(parent, title, message, info, lineHeight, windowFlags,
|
||||
textFlags)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void checkEvents()
|
||||
{
|
||||
char buf[10];
|
||||
sprintf(buf, "%d", (int)TELEMETRY_RSSI());
|
||||
setInfoText(buf);
|
||||
MessageDialog::checkEvents();
|
||||
}
|
||||
};
|
||||
|
||||
class ChannelFailsafeBargraph: public Window {
|
||||
public:
|
||||
@@ -644,6 +624,7 @@ class ModuleWindow : public FormGroup {
|
||||
}
|
||||
#if defined(MULTIMODULE)
|
||||
else if (isModuleMultimodule(moduleIdx)) {
|
||||
Choice * mmSubProtocol = nullptr;
|
||||
grid.nextLine();
|
||||
new StaticText(this, grid.getLabelSlot(true), STR_RF_PROTOCOL);
|
||||
|
||||
@@ -653,6 +634,8 @@ class ModuleWindow : public FormGroup {
|
||||
GET_DEFAULT(multiRfProto),
|
||||
[=](int32_t newValue) {
|
||||
g_model.moduleData[moduleIdx].setMultiProtocol(newValue);
|
||||
g_model.moduleData[moduleIdx].subType = 0;
|
||||
if (mmSubProtocol != nullptr) mmSubProtocol->invalidate();
|
||||
resetMultiProtocolsOptions(moduleIdx);
|
||||
SET_DIRTY();
|
||||
update();
|
||||
@@ -662,7 +645,7 @@ class ModuleWindow : public FormGroup {
|
||||
// Subtype (D16, DSMX,...)
|
||||
const mm_protocol_definition * pdef = getMultiProtocolDefinition(g_model.moduleData[moduleIdx].getMultiProtocol());
|
||||
if (pdef->maxSubtype > 0)
|
||||
new Choice(this, grid.getFieldSlot(2, 1), pdef->subTypeString, 0, pdef->maxSubtype,GET_SET_DEFAULT(g_model.moduleData[moduleIdx].subType));
|
||||
mmSubProtocol = new Choice(this, grid.getFieldSlot(2, 1), pdef->subTypeString, 0, pdef->maxSubtype,GET_SET_DEFAULT(g_model.moduleData[moduleIdx].subType));
|
||||
grid.nextLine();
|
||||
|
||||
// Multimodule status
|
||||
@@ -868,8 +851,14 @@ class ModuleWindow : public FormGroup {
|
||||
}
|
||||
else {
|
||||
moduleState[moduleIdx].mode = MODULE_MODE_RANGECHECK;
|
||||
auto rssiDialog = new RssiDialog(
|
||||
this, "Range Test", "RSSI:", "", 50, REFRESH_ALWAYS,
|
||||
auto rssiDialog = new DynamicMessageDialog(
|
||||
this, "Range Test",
|
||||
[=]() {
|
||||
char buf[16];
|
||||
sprintf(buf, "%d db", (int)TELEMETRY_RSSI());
|
||||
return std::string(buf);
|
||||
},
|
||||
"RSSI:", 50,
|
||||
DEFAULT_COLOR | CENTERED | FONT(BOLD) | FONT(XL));
|
||||
rssiDialog->setCloseHandler([this]() {
|
||||
rangeButton->check(false);
|
||||
@@ -1023,6 +1012,8 @@ void onBindMenu(const char * result)
|
||||
|
||||
const char * STR_TIMER_MODES[] = {"OFF", "ON", "Start", "Throttle", "Throttle %", "Throttle Start"};
|
||||
|
||||
const char MODEL_NAME_EXTRA_CHARS[] = "_-.,:;<=>";
|
||||
|
||||
void ModelSetupPage::build(FormWindow * window)
|
||||
{
|
||||
FormGridLayout grid;
|
||||
@@ -1030,7 +1021,8 @@ void ModelSetupPage::build(FormWindow * window)
|
||||
|
||||
// Model name
|
||||
new StaticText(window, grid.getLabelSlot(), STR_MODELNAME);
|
||||
auto text = new RadioTextEdit(window, grid.getFieldSlot(), g_model.header.name, sizeof(g_model.header.name));
|
||||
auto text = new RadioTextEdit(window, grid.getFieldSlot(), g_model.header.name, sizeof(g_model.header.name),
|
||||
0, MODEL_NAME_EXTRA_CHARS);
|
||||
text->setChangeHandler([=] {
|
||||
modelslist.load();
|
||||
auto model = modelslist.getCurrentModel();
|
||||
|
||||
@@ -552,13 +552,34 @@ void ModelTelemetryPage::build(FormWindow * window, int8_t focusSensorIndex)
|
||||
});
|
||||
grid.nextLine();
|
||||
new StaticText(window, grid.getLabelSlot(true), STR_RANGE);
|
||||
new NumberEdit(window, grid.getFieldSlot(2, 0), -7, 7, GET_SET_WITH_OFFSET(g_model.varioData.min, -10));
|
||||
new NumberEdit(window, grid.getFieldSlot(2, 1), -7, 7, GET_SET_WITH_OFFSET(g_model.varioData.max, 10));
|
||||
|
||||
auto vMin = new NumberEdit(window, grid.getFieldSlot(2, 0), -17, 17,
|
||||
GET_SET_WITH_OFFSET(g_model.varioData.min, -10));
|
||||
vMin->setAvailableHandler(
|
||||
[](int val) { return val < g_model.varioData.max + 10; });
|
||||
|
||||
auto vMax = new NumberEdit(window, grid.getFieldSlot(2, 1), -17, 17,
|
||||
GET_SET_WITH_OFFSET(g_model.varioData.max, 10));
|
||||
vMax->setAvailableHandler(
|
||||
[](int val) { return g_model.varioData.min - 10 < val; });
|
||||
|
||||
grid.nextLine();
|
||||
new StaticText(window, grid.getLabelSlot(true), STR_CENTER);
|
||||
new NumberEdit(window, grid.getFieldSlot(3, 0), -7, 7, GET_SET_WITH_OFFSET(g_model.varioData.min, -5), 0, PREC1);
|
||||
new NumberEdit(window, grid.getFieldSlot(3, 1), -7, 7, GET_SET_WITH_OFFSET(g_model.varioData.max, 5), 0, PREC1);
|
||||
new Choice(window, grid.getFieldSlot(3, 2), STR_VVARIOCENTER, 0, 1, GET_SET_DEFAULT(g_model.varioData.centerSilent));
|
||||
|
||||
auto cMin = new NumberEdit(
|
||||
window, grid.getFieldSlot(3, 0), -15, 15,
|
||||
GET_SET_WITH_OFFSET(g_model.varioData.centerMin, -5), 0, PREC1);
|
||||
cMin->setAvailableHandler(
|
||||
[](int val) { return val < g_model.varioData.centerMax + 5; });
|
||||
|
||||
auto cMax = new NumberEdit(
|
||||
window, grid.getFieldSlot(3, 1), -15, 15,
|
||||
GET_SET_WITH_OFFSET(g_model.varioData.centerMax, 5), 0, PREC1);
|
||||
cMax->setAvailableHandler(
|
||||
[](int val) { return g_model.varioData.centerMin - 5 < val; });
|
||||
|
||||
new Choice(window, grid.getFieldSlot(3, 2), STR_VVARIOCENTER, 0, 1,
|
||||
GET_SET_DEFAULT(g_model.varioData.centerSilent));
|
||||
grid.nextLine();
|
||||
|
||||
window->setInnerHeight(grid.getWindowHeight());
|
||||
|
||||
@@ -49,7 +49,7 @@ class RadioAnalogsDiagsWindow: public Window {
|
||||
}
|
||||
|
||||
#if defined(HARDWARE_TOUCH)
|
||||
constexpr coord_t y = MENU_CONTENT_TOP + 6 * FH;
|
||||
constexpr coord_t y = MENU_CONTENT_TOP + 5 * FH;
|
||||
|
||||
if (touchState.event != TE_NONE && touchState.event != TE_SLIDE_END) {
|
||||
coord_t x = dc->drawText(MENUS_MARGIN_LEFT, y, STR_TOUCH_PANEL);
|
||||
@@ -59,6 +59,14 @@ class RadioAnalogsDiagsWindow: public Window {
|
||||
dc->drawLine(touchState.x - 10, touchState.y - 8 - parent->top(), touchState.x + 10, touchState.y + 8 - parent->top(), SOLID, 0);
|
||||
dc->drawLine(touchState.x - 10, touchState.y + 8 - parent->top(), touchState.x + 10, touchState.y - 8- parent->top(), SOLID, 0);
|
||||
}
|
||||
#if !defined(SIMU)
|
||||
constexpr coord_t y1 = MENU_CONTENT_TOP + 6 * FH;
|
||||
coord_t x1 = MENUS_MARGIN_LEFT;
|
||||
x1 = dc->drawText(x1, y1, "Touch GT911 FW ver:") + 8;
|
||||
x1 = dc->drawNumber(x1, y1, touchGT911fwver, LEFT, 4) + 16;
|
||||
x1 = dc->drawText(x1, y1, "TSI2CEvents:") + 4;
|
||||
dc->drawNumber(x1, y1, touchGT911hiccups, LEFT, 5);
|
||||
#endif
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "io/bootloader_flash.h"
|
||||
#include "standalone_lua.h"
|
||||
#include "sdcard.h"
|
||||
#include "view_text.h"
|
||||
|
||||
class FileNameEditWindow : public Page
|
||||
{
|
||||
@@ -232,15 +233,15 @@ void RadioSdManagerPage::build(FormWindow * window)
|
||||
|
||||
if (res != FR_OK || fno.fname[0] == 0)
|
||||
break; // Break on error or end of dir
|
||||
if (strlen(fno.fname) > SD_SCREEN_FILE_LENGTH)
|
||||
if (strlen((const char*)fno.fname) > SD_SCREEN_FILE_LENGTH)
|
||||
continue;
|
||||
if (fno.fname[0] == '.' && fno.fname[1] != '.')
|
||||
continue; // Ignore hidden files under UNIX, but not ..
|
||||
|
||||
if (fno.fattrib & AM_DIR) {
|
||||
directories.push_back(fno.fname);
|
||||
directories.push_back((char*)fno.fname);
|
||||
} else {
|
||||
files.push_back(fno.fname);
|
||||
files.push_back((char*)fno.fname);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -251,7 +252,7 @@ void RadioSdManagerPage::build(FormWindow * window)
|
||||
for (auto name: directories) {
|
||||
auto b = new TextButton(window, grid.getLabelSlot(), name, [=]() -> uint8_t {
|
||||
std::string fullpath = currentPath + "/" + name;
|
||||
f_chdir(fullpath.c_str());
|
||||
f_chdir((TCHAR*)fullpath.c_str());
|
||||
window->clear();
|
||||
build(window);
|
||||
return 0;
|
||||
@@ -303,11 +304,18 @@ void RadioSdManagerPage::build(FormWindow * window)
|
||||
// else if (isExtensionMatching(ext, BITMAPS_EXT)) {
|
||||
// // TODO
|
||||
// }
|
||||
// else if (!strcasecmp(ext, TEXT_EXT)) {
|
||||
// menu->addLine(STR_VIEW_TEXT, [=]() {
|
||||
// // TODO
|
||||
// });
|
||||
// }
|
||||
else if (!strcasecmp(ext, TEXT_EXT)) {
|
||||
menu->addLine(STR_VIEW_TEXT, [=]() {
|
||||
static char lfn[FF_MAX_LFN + 1]; // TODO optimize that!
|
||||
f_getcwd((TCHAR *)lfn, FF_MAX_LFN);
|
||||
|
||||
auto textView = new ViewTextWindow(lfn, name);
|
||||
textView->setCloseHandler([=]() {
|
||||
//window->clear();
|
||||
rebuild(window);
|
||||
});
|
||||
});
|
||||
}
|
||||
if (!READ_ONLY() && !strcasecmp(ext, FIRMWARE_EXT)) {
|
||||
if (isBootloader(name.data())) {
|
||||
menu->addLine(STR_FLASH_BOOTLOADER, [=]() {
|
||||
@@ -378,7 +386,6 @@ void RadioSdManagerPage::build(FormWindow * window)
|
||||
//window->clear();
|
||||
rebuild(window);
|
||||
});
|
||||
// rebuild(window); });
|
||||
});
|
||||
menu->addLine(STR_DELETE_FILE, [=]() {
|
||||
f_unlink((const TCHAR*)getFullPath(name));
|
||||
|
||||
@@ -27,8 +27,8 @@
|
||||
class ModelTextEdit: public TextEdit
|
||||
{
|
||||
public:
|
||||
ModelTextEdit(Window * parent, const rect_t & rect, char * value, uint8_t length, LcdFlags windowFlags = 0):
|
||||
TextEdit(parent, rect, value, length, windowFlags)
|
||||
ModelTextEdit(Window * parent, const rect_t & rect, char * value, uint8_t length, LcdFlags windowFlags = 0, const char * extra_chars = nullptr):
|
||||
TextEdit(parent, rect, value, length, windowFlags, extra_chars)
|
||||
{
|
||||
setChangeHandler([](){
|
||||
storageDirty(EE_MODEL);
|
||||
@@ -39,11 +39,11 @@ class ModelTextEdit: public TextEdit
|
||||
class RadioTextEdit: public TextEdit
|
||||
{
|
||||
public:
|
||||
RadioTextEdit(Window * parent, const rect_t & rect, char * value, uint8_t length, LcdFlags windowFlags = 0):
|
||||
TextEdit(parent, rect, value, length, windowFlags)
|
||||
RadioTextEdit(Window * parent, const rect_t & rect, char * value, uint8_t length, LcdFlags windowFlags = 0, const char * extra_chars = nullptr):
|
||||
TextEdit(parent, rect, value, length, windowFlags, extra_chars)
|
||||
{
|
||||
setChangeHandler([](){
|
||||
storageDirty(EE_GENERAL);
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -61,6 +61,12 @@ const uint8_t mask_model_special_functions[] = {
|
||||
const uint8_t mask_model_telemetry[] = {
|
||||
#include "mask_model_telemetry.lbm"
|
||||
};
|
||||
const uint8_t mask_menu_model_select[] = {
|
||||
#include "mask_menu_model_select.lbm" //TODO: someone may want to make proper icon
|
||||
};
|
||||
const uint8_t mask_model_select_category[] = {
|
||||
#include "mask_model_select_category.lbm" //TODO: someone should make proper icon
|
||||
};
|
||||
const uint8_t mask_monitor[] = {
|
||||
#include "mask_monitor.lbm"
|
||||
};
|
||||
|
||||
@@ -150,6 +150,8 @@ class Theme480: public OpenTxTheme
|
||||
loadMenuIcon(ICON_MODEL_SPECIAL_FUNCTIONS, mask_model_special_functions);
|
||||
loadMenuIcon(ICON_MODEL_LUA_SCRIPTS, mask_model_lua_scripts);
|
||||
loadMenuIcon(ICON_MODEL_TELEMETRY, mask_model_telemetry);
|
||||
loadMenuIcon(ICON_MODEL_SELECT, mask_menu_model_select);
|
||||
loadMenuIcon(ICON_MODEL_SELECT_CATEGORY, mask_model_select_category);
|
||||
loadMenuIcon(ICON_STATS, mask_menu_stats);
|
||||
loadMenuIcon(ICON_STATS_THROTTLE_GRAPH, mask_stats_throttle_graph);
|
||||
loadMenuIcon(ICON_STATS_TIMERS, mask_stats_timers);
|
||||
|
||||
@@ -52,7 +52,7 @@ ViewMainMenu::ViewMainMenu(Window* parent) :
|
||||
// "Tasks", 0, FOCUS_COLOR | FONT(XL) | CENTERED);
|
||||
// pos += title->height() + PAGE_LINE_SPACING;
|
||||
|
||||
carousel->addButton(ICON_MODEL, "Select\nModel", [=]() -> uint8_t {
|
||||
carousel->addButton(ICON_MODEL_SELECT, "Select\nModel", [=]() -> uint8_t {
|
||||
deleteLater();
|
||||
new ModelSelectMenu();
|
||||
return 0;
|
||||
@@ -64,7 +64,7 @@ ViewMainMenu::ViewMainMenu(Window* parent) :
|
||||
return 0;
|
||||
});
|
||||
|
||||
carousel->addButton(ICON_RADIO_TOOLS, "Model\nSettings", [=]() -> uint8_t {
|
||||
carousel->addButton(ICON_MODEL, "Model\nSettings", [=]() -> uint8_t {
|
||||
deleteLater();
|
||||
new ModelMenu();
|
||||
return 0;
|
||||
|
||||
@@ -0,0 +1,435 @@
|
||||
/*
|
||||
* Copyright (C) EdgeTX
|
||||
*
|
||||
* 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 "view_text.h"
|
||||
|
||||
#include "gridlayout.h"
|
||||
#include "menu.h"
|
||||
#include "opentx.h"
|
||||
#include "sdcard.h"
|
||||
|
||||
#define CASE_EVT_KEY_NEXT_LINE \
|
||||
case EVT_ROTARY_RIGHT: \
|
||||
case EVT_KEY_BREAK(KEY_PGDN)
|
||||
// case EVT_KEY_BREAK(KEY_DOWN)
|
||||
|
||||
#define CASE_EVT_KEY_PREVIOUS_LINE \
|
||||
case EVT_ROTARY_LEFT: \
|
||||
case EVT_KEY_BREAK(KEY_PGUP): \
|
||||
case EVT_KEY_BREAK(KEY_UP)
|
||||
|
||||
#define CASE_EVT_START \
|
||||
case EVT_ENTRY: \
|
||||
case EVT_KEY_BREAK(KEY_ENTER): \
|
||||
case EVT_KEY_BREAK(KEY_TELEM)
|
||||
|
||||
void ViewTextWindow::extractNameSansExt()
|
||||
{
|
||||
uint8_t nameLength;
|
||||
uint8_t extLength;
|
||||
|
||||
const char *ext =
|
||||
getFileExtension(name.data(), 0, 0, &nameLength, &extLength);
|
||||
extension = std::string(ext);
|
||||
if (nameLength > TEXT_FILENAME_MAXLEN) nameLength = TEXT_FILENAME_MAXLEN;
|
||||
|
||||
nameLength -= extLength;
|
||||
name.substr(nameLength);
|
||||
}
|
||||
|
||||
#if READ_FILE_BY_LINE
|
||||
void ViewTextWindow::buildBody(Window *window)
|
||||
{
|
||||
GridLayout grid(window);
|
||||
grid.spacer();
|
||||
int i;
|
||||
|
||||
// assume average characte is 10 pixels wide, round the string length to tens.
|
||||
// Font is not fixed width, so this is for the worst case...
|
||||
const int maxLineLength = int(floor(window->width() / 10 / 10)) * 10 - 2;
|
||||
window->setFocus();
|
||||
|
||||
FIL file;
|
||||
if (FR_OK !=
|
||||
f_open(&file, (TCHAR *)fullPath.c_str(), FA_OPEN_EXISTING | FA_READ)) {
|
||||
return;
|
||||
}
|
||||
readCount = 0;
|
||||
longestLine = 0;
|
||||
lastLine = false;
|
||||
for (i = 0; i < TEXT_FILE_MAXSIZE && !lastLine; i++) {
|
||||
lastLine =
|
||||
sdReadTextLine(&file, reusableBuffer.viewText.lines[0], maxLineLength);
|
||||
|
||||
new StaticText(window, grid.getSlot(), reusableBuffer.viewText.lines[0]);
|
||||
grid.nextLine();
|
||||
}
|
||||
|
||||
f_close(&file);
|
||||
|
||||
window->setInnerWidth((longestLine + 4) * 10);
|
||||
window->setInnerHeight(grid.getWindowHeight());
|
||||
}
|
||||
|
||||
void ViewTextWindow::checkEvents()
|
||||
{
|
||||
if (&body == Window::focusWindow) {
|
||||
const int step = PAGE_LINE_HEIGHT + PAGE_LINE_SPACING;
|
||||
coord_t currentPos = body.getScrollPositionY();
|
||||
coord_t deltaY;
|
||||
event_t event = getWindowEvent();
|
||||
|
||||
if (event == EVT_ROTARY_LEFT || event == EVT_ROTARY_RIGHT) {
|
||||
deltaY = ROTARY_ENCODER_SPEED() * step;
|
||||
} else {
|
||||
deltaY = step;
|
||||
}
|
||||
|
||||
switch (event) {
|
||||
CASE_EVT_KEY_NEXT_LINE:
|
||||
currentPos += deltaY;
|
||||
break;
|
||||
|
||||
CASE_EVT_KEY_PREVIOUS_LINE:
|
||||
currentPos -= deltaY;
|
||||
break;
|
||||
|
||||
default:
|
||||
Page::onEvent(event);
|
||||
return;
|
||||
}
|
||||
body.setScrollPositionY(currentPos);
|
||||
}
|
||||
Page::checkEvents();
|
||||
}
|
||||
|
||||
bool ViewTextWindow::sdReadTextLine(FIL *file, char line[],
|
||||
const uint8_t maxLineLength)
|
||||
{
|
||||
char c;
|
||||
unsigned int sz;
|
||||
uint8_t line_length = 0;
|
||||
uint8_t escape = 0;
|
||||
char escape_chars[4] = {0};
|
||||
int current_line = 0;
|
||||
|
||||
memclear(line, maxLineLength + 1);
|
||||
line[line_length++] = 0x20;
|
||||
|
||||
for (uint8_t i = 0; i < maxLineLength && readCount < (int)TEXT_FILE_MAXSIZE;
|
||||
++i) {
|
||||
if ((f_read(file, &c, 1, &sz) != FR_OK || !sz) &&
|
||||
line_length < maxLineLength) {
|
||||
return true;
|
||||
}
|
||||
readCount++;
|
||||
|
||||
if (c == '\n') {
|
||||
++current_line;
|
||||
escape = 0;
|
||||
return false;
|
||||
} else if (c != '\r') {
|
||||
if (c == '\\' && escape == 0) {
|
||||
escape = 1;
|
||||
continue;
|
||||
} else if (c != '\\' && escape > 0 && escape < sizeof(escape_chars)) {
|
||||
escape_chars[escape - 1] = c;
|
||||
if (escape == 2 && !strncmp(escape_chars, "up", 2)) {
|
||||
c = CHAR_UP;
|
||||
} else if (escape == 2 && !strncmp(escape_chars, "dn", 2)) {
|
||||
c = CHAR_DOWN;
|
||||
} else if (escape == 3) {
|
||||
int val = atoi(escape_chars);
|
||||
if (val >= 200 && val < 225) {
|
||||
c = '\200' + val - 200;
|
||||
}
|
||||
} else {
|
||||
escape++;
|
||||
continue;
|
||||
}
|
||||
} else if (c == '~') {
|
||||
c = 'z' + 1;
|
||||
} else if (c == '\t') {
|
||||
c = 0x1D; // tab
|
||||
}
|
||||
escape = 0;
|
||||
line[line_length++] = c;
|
||||
if (longestLine < line_length) longestLine = line_length;
|
||||
}
|
||||
}
|
||||
if (c != '\n') {
|
||||
current_line += 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
|
||||
void ViewTextWindow::buildBody(Window *window)
|
||||
{
|
||||
GridLayout grid(window);
|
||||
grid.spacer();
|
||||
int i;
|
||||
|
||||
// assume average characte is 10 pixels wide, round the string length to tens.
|
||||
// Font is not fixed width, so this is for the worst case...
|
||||
maxLineLength = int(floor(window->width() / 10 / 10)) * 10 - 2;
|
||||
maxScreenLines = window->height() / (PAGE_LINE_HEIGHT + PAGE_LINE_SPACING);
|
||||
window->setFocus();
|
||||
readLinesCount = 0;
|
||||
lastLoadedLine = 0;
|
||||
|
||||
lines = new char*[maxScreenLines];
|
||||
for(i = 0 ; i < maxScreenLines; i++)
|
||||
{
|
||||
lines[i] = new char[maxLineLength + 1];
|
||||
memclear(lines[i], maxLineLength + 1);
|
||||
}
|
||||
|
||||
longestLine = 0;
|
||||
loadFirstScreen();
|
||||
|
||||
if(isInSetup == true)
|
||||
{
|
||||
textBottom = false;
|
||||
while(!textBottom)
|
||||
{
|
||||
sdReadTextFileBlock(fullPath.c_str(), readLinesCount);
|
||||
textVerticalOffset += 10;
|
||||
}
|
||||
maxPos = (maxLines - maxScreenLines) * (PAGE_LINE_HEIGHT + PAGE_LINE_SPACING);
|
||||
if(maxPos < body.getRect().h) maxPos = body.getRect().h;
|
||||
}
|
||||
|
||||
isInSetup = false;
|
||||
loadFirstScreen();
|
||||
|
||||
for (i = 0; i < maxScreenLines; i++) {
|
||||
new DynamicText(window, grid.getSlot(), [=]() {
|
||||
std::string str = (lines[i][0]) ? std::string(lines[i]) : std::string(" ");
|
||||
return std::string(str);
|
||||
});
|
||||
grid.nextLine();
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(HARDWARE_TOUCH)
|
||||
bool ViewTextWindow::onTouchSlide(coord_t x, coord_t y, coord_t startX,
|
||||
coord_t startY, coord_t slideX,
|
||||
coord_t slideY)
|
||||
{
|
||||
if (&body == Window::focusWindow) {
|
||||
const int step = PAGE_LINE_HEIGHT + PAGE_LINE_SPACING;
|
||||
int deltaY = -slideY;
|
||||
int lineStep = deltaY / step;
|
||||
|
||||
textVerticalOffset += lineStep;
|
||||
if (textVerticalOffset < 0) textVerticalOffset = 0;
|
||||
|
||||
// if (textBottom && lineStep > 0) textVerticalOffset -= lineStep;
|
||||
if(textVerticalOffset > maxLines) textVerticalOffset = maxLines;
|
||||
sdReadTextFileBlock(fullPath.c_str(), readLinesCount);
|
||||
}
|
||||
return Page::onTouchSlide(x, y, startX, startY, slideX, slideY);
|
||||
}
|
||||
#endif
|
||||
|
||||
void ViewTextWindow::checkEvents()
|
||||
{
|
||||
if (&body == Window::focusWindow) {
|
||||
const int step = PAGE_LINE_HEIGHT + PAGE_LINE_SPACING;
|
||||
coord_t deltaY;
|
||||
event_t event = getWindowEvent();
|
||||
|
||||
if (event == EVT_ROTARY_LEFT || event == EVT_ROTARY_RIGHT) {
|
||||
deltaY = ROTARY_ENCODER_SPEED() * step;
|
||||
} else {
|
||||
deltaY = step;
|
||||
}
|
||||
|
||||
int lineStep = deltaY / step;
|
||||
if(lineStep > (maxScreenLines >> 1)) lineStep = maxScreenLines >> 1;
|
||||
/*
|
||||
if(event) {
|
||||
sprintf(lines[0], "Received event %d", event);
|
||||
if(!readLinesCount)
|
||||
readLinesCount = 1;
|
||||
Page::onEvent(event);
|
||||
return;
|
||||
}
|
||||
*/
|
||||
switch (event) {
|
||||
CASE_EVT_START:
|
||||
textVerticalOffset = 0;
|
||||
readLinesCount = 0;
|
||||
sdReadTextFileBlock(fullPath.c_str(), readLinesCount);
|
||||
break;
|
||||
|
||||
CASE_EVT_KEY_NEXT_LINE:
|
||||
if(textBottom && textVerticalOffset) //(textVerticalOffset + maxScreenLines - 1 >= readLinesCount)
|
||||
break;
|
||||
else {
|
||||
textVerticalOffset += lineStep;
|
||||
if(textVerticalOffset > maxLines) textVerticalOffset = maxLines;
|
||||
}
|
||||
sdReadTextFileBlock(fullPath.c_str(), readLinesCount);
|
||||
break;
|
||||
|
||||
CASE_EVT_KEY_PREVIOUS_LINE:
|
||||
if (textVerticalOffset == 0)
|
||||
break;
|
||||
else {
|
||||
textVerticalOffset -= lineStep;
|
||||
if(textVerticalOffset < 0) textVerticalOffset = 0;
|
||||
}
|
||||
|
||||
sdReadTextFileBlock(fullPath.c_str(), readLinesCount);
|
||||
break;
|
||||
|
||||
default:
|
||||
Page::onEvent(event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
Page::checkEvents();
|
||||
}
|
||||
|
||||
void ViewTextWindow::loadFirstScreen()
|
||||
{
|
||||
textVerticalOffset = 0;
|
||||
readLinesCount = 0;
|
||||
sdReadTextFileBlock(fullPath.c_str(), readLinesCount);
|
||||
}
|
||||
|
||||
void ViewTextWindow::sdReadTextFileBlock(const char *filename, int &lines_count)
|
||||
{
|
||||
FIL file;
|
||||
int result;
|
||||
char c;
|
||||
unsigned int sz = 0;
|
||||
int line_length = 1;
|
||||
uint8_t escape = 0;
|
||||
char escape_chars[4] = {0};
|
||||
int current_line = 0;
|
||||
textBottom = false;
|
||||
|
||||
for(int i = 0; i < maxScreenLines; i++) {
|
||||
memclear(lines[i], maxLineLength + 1);
|
||||
lines[i][0] = ' ';
|
||||
}
|
||||
|
||||
result = f_open(&file, (TCHAR *)filename, FA_OPEN_EXISTING | FA_READ);
|
||||
if (result == FR_OK) {
|
||||
for (int i = 0; i < TEXT_FILE_MAXSIZE &&
|
||||
f_read(&file, &c, 1, &sz) == FR_OK && sz == 1 &&
|
||||
(lines_count == 0 ||
|
||||
current_line - textVerticalOffset < maxScreenLines);
|
||||
i++) {
|
||||
if (c == '\n' || line_length >= maxLineLength) {
|
||||
++current_line;
|
||||
line_length = 1;
|
||||
escape = 0;
|
||||
}
|
||||
if (c != '\r' && c != '\n' && current_line >= textVerticalOffset &&
|
||||
current_line - textVerticalOffset < maxScreenLines &&
|
||||
line_length < maxLineLength) {
|
||||
if (c == '\\' && escape == 0) {
|
||||
escape = 1;
|
||||
continue;
|
||||
} else if (c != '\\' && escape > 0 && escape < sizeof(escape_chars)) {
|
||||
escape_chars[escape - 1] = c;
|
||||
if (escape == 2 && !strncmp(escape_chars, "up", 2)) {
|
||||
c = CHAR_UP;
|
||||
} else if (escape == 2 && !strncmp(escape_chars, "dn", 2)) {
|
||||
c = CHAR_DOWN;
|
||||
} else if (escape == 3) {
|
||||
int val = atoi(escape_chars);
|
||||
if (val >= 200 && val < 225) {
|
||||
c = '\200' + val - 200;
|
||||
}
|
||||
} else {
|
||||
escape++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (c == '~') {
|
||||
c = 'z' + 1;
|
||||
} else if (c == '\t') {
|
||||
c = 0x1D; // tab
|
||||
}
|
||||
escape = 0;
|
||||
|
||||
lines[current_line - textVerticalOffset][line_length++] = c;
|
||||
if (longestLine < line_length) longestLine = line_length;
|
||||
} else if(current_line < textVerticalOffset) {
|
||||
++line_length;
|
||||
}
|
||||
}
|
||||
if (c != '\n') {
|
||||
++current_line;
|
||||
}
|
||||
|
||||
if (f_eof(&file)) {
|
||||
textBottom = true;
|
||||
if (isInSetup) maxLines = current_line;
|
||||
}
|
||||
|
||||
f_close(&file);
|
||||
}
|
||||
|
||||
if(lastLoadedLine < textVerticalOffset)
|
||||
lastLoadedLine = textVerticalOffset;
|
||||
|
||||
if (lines_count == 0) {
|
||||
lines_count = current_line;
|
||||
}
|
||||
}
|
||||
|
||||
void ViewTextWindow::drawVerticalScrollbar(BitmapBuffer *dc)
|
||||
{
|
||||
int readPos = textVerticalOffset * (PAGE_LINE_HEIGHT + PAGE_LINE_SPACING);
|
||||
|
||||
if(readPos < header.getRect().h << 1) readPos = header.getRect().h << 1;
|
||||
|
||||
coord_t yofs = divRoundClosest(body.getRect().h * readPos, maxPos);
|
||||
coord_t yhgt = divRoundClosest(body.getRect().h * body.getRect().h, maxPos);
|
||||
if (yhgt < 15) yhgt = 15;
|
||||
if (yhgt + yofs > maxPos) yhgt = maxPos - yofs;
|
||||
dc->drawSolidFilledRect(body.getRect().w - SCROLLBAR_WIDTH, yofs,
|
||||
SCROLLBAR_WIDTH, yhgt, SCROLLBAR_COLOR);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#include "datastructs.h"
|
||||
|
||||
void readModelNotes()
|
||||
{
|
||||
LED_ERROR_BEGIN();
|
||||
|
||||
std::string modelNotesName(g_model.header.name);
|
||||
modelNotesName.append(TEXT_EXT);
|
||||
const char buf[] = {MODELS_PATH};
|
||||
f_chdir((TCHAR*)buf);
|
||||
new ViewTextWindow(std::string(buf), modelNotesName, ICON_MODEL);
|
||||
|
||||
LED_ERROR_END();
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Copyright (C) EdgeTX
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "page.h"
|
||||
#include "static.h"
|
||||
#include "lcd.h"
|
||||
#include "menus.h"
|
||||
#include "ff.h"
|
||||
|
||||
#define READ_FILE_BY_LINE 0
|
||||
|
||||
constexpr uint16_t TEXT_FILE_MAXSIZE = 20480;
|
||||
|
||||
class ViewTextWindow : public Page
|
||||
{
|
||||
public:
|
||||
ViewTextWindow(const std::string iPath, const std::string iName, unsigned int icon = ICON_RADIO_SD_MANAGER) :
|
||||
Page(icon),
|
||||
path(std::move(iPath)),
|
||||
name(std::move(iName)),
|
||||
icon(icon)
|
||||
{
|
||||
fullPath = path + std::string("/") + name;
|
||||
extractNameSansExt();
|
||||
lines = nullptr;
|
||||
lastLoadedLine = 0;
|
||||
maxPos = 0;
|
||||
maxLines = 0;
|
||||
isInSetup = true;
|
||||
//body.setWindowFlags(FORWARD_SCROLL);
|
||||
header.setWindowFlags(NO_SCROLLBAR);
|
||||
|
||||
buildHeader(&header);
|
||||
buildBody(&body);
|
||||
};
|
||||
|
||||
#if READ_FILE_BY_LINE
|
||||
bool sdReadTextLine(FIL* file, char lines[],
|
||||
const uint8_t lineLength = LCD_COLS);
|
||||
#else
|
||||
void sdReadTextFileBlock(const char * filename, int& lines_count);
|
||||
void loadFirstScreen(void);
|
||||
#if defined(HARDWARE_TOUCH)
|
||||
bool onTouchSlide(coord_t x, coord_t y, coord_t startX, coord_t startY, coord_t slideX, coord_t slideY) override;
|
||||
#endif
|
||||
void drawVerticalScrollbar(BitmapBuffer * dc);
|
||||
|
||||
~ViewTextWindow()
|
||||
{
|
||||
if(lines != nullptr) {
|
||||
for(int i = 0; i < maxScreenLines; i++)
|
||||
{
|
||||
delete[] lines[i];
|
||||
}
|
||||
delete[] lines;
|
||||
}
|
||||
}
|
||||
|
||||
void paint(BitmapBuffer* dc)
|
||||
{
|
||||
Page::paint(dc);
|
||||
drawVerticalScrollbar(dc);
|
||||
}
|
||||
#endif
|
||||
virtual void checkEvents();
|
||||
|
||||
#if defined(DEBUG_WINDOWS)
|
||||
std::string getName() const override { return "ViewTextWindow"; };
|
||||
#endif
|
||||
|
||||
protected:
|
||||
std::string path;
|
||||
std::string name;
|
||||
std::string fullPath;
|
||||
std::string extension;
|
||||
unsigned int icon;
|
||||
|
||||
bool lastLine;
|
||||
uint16_t readCount;
|
||||
int longestLine;
|
||||
|
||||
#if !READ_FILE_BY_LINE
|
||||
char** lines = nullptr;
|
||||
//char lines[15][80];
|
||||
int maxScreenLines;
|
||||
int maxLineLength;
|
||||
int textVerticalOffset;
|
||||
int readLinesCount;
|
||||
int lastLoadedLine;
|
||||
int maxPos;
|
||||
int maxLines;
|
||||
bool textBottom;
|
||||
bool isInSetup;
|
||||
#endif
|
||||
|
||||
void extractNameSansExt(void);
|
||||
void buildBody(Window *window);
|
||||
void buildHeader(Window *window)
|
||||
{
|
||||
new StaticText(window,
|
||||
{PAGE_TITLE_LEFT, PAGE_TITLE_TOP + 10,
|
||||
LCD_W - PAGE_TITLE_LEFT, PAGE_LINE_HEIGHT},
|
||||
name, 0, MENU_HIGHLIGHT_COLOR);
|
||||
};
|
||||
};
|
||||
|
||||
void readModelNotes();
|
||||
@@ -26,6 +26,7 @@
|
||||
// #include "shutdown_animation.h"
|
||||
#include "radio_calibration.h"
|
||||
#include "view_main.h"
|
||||
#include "view_text.h"
|
||||
#endif
|
||||
|
||||
#if defined(PCBSKY9X)
|
||||
@@ -749,13 +750,9 @@ void checkAll()
|
||||
disableVBatBridge();
|
||||
#endif
|
||||
|
||||
#if defined(COLORLCD)
|
||||
#warning "Model notes missing"
|
||||
#else
|
||||
if (g_model.displayChecklist && modelHasNotes()) {
|
||||
readModelNotes();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(MULTIMODULE)
|
||||
checkMultiLowPower();
|
||||
|
||||
@@ -347,7 +347,7 @@ bool setupPulsesExternalModule(uint8_t protocol)
|
||||
case PROTOCOL_CHANNELS_PXX2_LOWSPEED:
|
||||
extmodulePulsesData.pxx2.setupFrame(EXTERNAL_MODULE);
|
||||
#if defined(PCBSKY9X)
|
||||
sheduleNextMixerCalculation(EXTERNAL_MODULE, PXX2_NO_HEARTBEAT_PERIOD);
|
||||
scheduleNextMixerCalculation(EXTERNAL_MODULE, PXX2_NO_HEARTBEAT_PERIOD);
|
||||
#endif
|
||||
return true;
|
||||
#endif
|
||||
@@ -457,12 +457,9 @@ static void enablePulsesInternalModule(uint8_t protocol)
|
||||
case PROTOCOL_CHANNELS_PXX1_PULSES:
|
||||
intmodulePxx1PulsesStart();
|
||||
#if defined(INTMODULE_HEARTBEAT)
|
||||
// use backup trigger (1 ms later)
|
||||
init_intmodule_heartbeat();
|
||||
mixerSchedulerSetPeriod(INTERNAL_MODULE, INTMODULE_PXX1_SERIAL_PERIOD + 1000/*us*/);
|
||||
#else
|
||||
mixerSchedulerSetPeriod(INTERNAL_MODULE, INTMODULE_PXX1_SERIAL_PERIOD);
|
||||
#endif
|
||||
mixerSchedulerSetPeriod(INTERNAL_MODULE, INTMODULE_PXX1_SERIAL_PERIOD);
|
||||
break;
|
||||
#endif
|
||||
|
||||
@@ -470,12 +467,9 @@ static void enablePulsesInternalModule(uint8_t protocol)
|
||||
case PROTOCOL_CHANNELS_PXX1_SERIAL:
|
||||
intmodulePxx1SerialStart();
|
||||
#if defined(INTMODULE_HEARTBEAT)
|
||||
// use backup trigger (1 ms later)
|
||||
init_intmodule_heartbeat();
|
||||
mixerSchedulerSetPeriod(INTERNAL_MODULE, INTMODULE_PXX1_SERIAL_PERIOD + 1000/*us*/);
|
||||
#else
|
||||
mixerSchedulerSetPeriod(INTERNAL_MODULE, INTMODULE_PXX1_SERIAL_PERIOD);
|
||||
#endif
|
||||
mixerSchedulerSetPeriod(INTERNAL_MODULE, INTMODULE_PXX1_SERIAL_PERIOD);
|
||||
break;
|
||||
#endif
|
||||
|
||||
@@ -487,10 +481,8 @@ static void enablePulsesInternalModule(uint8_t protocol)
|
||||
#if defined(INTMODULE_HEARTBEAT)
|
||||
// use backup trigger (1 ms later)
|
||||
init_intmodule_heartbeat();
|
||||
mixerSchedulerSetPeriod(INTERNAL_MODULE, PXX2_MAX_HEARTBEAT_PERIOD);
|
||||
#else
|
||||
mixerSchedulerSetPeriod(INTERNAL_MODULE, PXX2_NO_HEARTBEAT_PERIOD);
|
||||
#endif
|
||||
mixerSchedulerSetPeriod(INTERNAL_MODULE, PXX2_PERIOD);
|
||||
break;
|
||||
#endif
|
||||
|
||||
@@ -522,12 +514,6 @@ bool setupPulsesInternalModule(uint8_t protocol)
|
||||
#if defined(HARDWARE_INTERNAL_MODULE) && defined(PXX1) && !defined(INTMODULE_USART)
|
||||
case PROTOCOL_CHANNELS_PXX1_PULSES:
|
||||
intmodulePulsesData.pxx.setupFrame(INTERNAL_MODULE);
|
||||
#if defined(INTMODULE_HEARTBEAT)
|
||||
mixerSchedulerResetTimer();
|
||||
mixerSchedulerSetPeriod(INTERNAL_MODULE, INTMODULE_PXX1_SERIAL_PERIOD + 1000 /* backup */);
|
||||
#else
|
||||
mixerSchedulerSetPeriod(INTERNAL_MODULE, INTMODULE_PXX1_SERIAL_PERIOD);
|
||||
#endif
|
||||
return true;
|
||||
#endif
|
||||
|
||||
@@ -545,12 +531,7 @@ bool setupPulsesInternalModule(uint8_t protocol)
|
||||
mixerSchedulerSetPeriod(INTERNAL_MODULE, PXX2_TOOLS_PERIOD);
|
||||
}
|
||||
else {
|
||||
#if defined(INTMODULE_HEARTBEAT)
|
||||
mixerSchedulerResetTimer();
|
||||
mixerSchedulerSetPeriod(INTERNAL_MODULE, PXX2_MAX_HEARTBEAT_PERIOD);
|
||||
#else
|
||||
mixerSchedulerSetPeriod(INTERNAL_MODULE, PXX2_NO_HEARTBEAT_PERIOD);
|
||||
#endif
|
||||
mixerSchedulerSetPeriod(INTERNAL_MODULE, PXX2_PERIOD);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -559,8 +540,6 @@ bool setupPulsesInternalModule(uint8_t protocol)
|
||||
#if defined(PCBTARANIS) && defined(INTERNAL_MODULE_PPM)
|
||||
case PROTOCOL_CHANNELS_PPM:
|
||||
setupPulsesPPMInternalModule();
|
||||
// probably useless, as the interval did not change since "enable" function
|
||||
mixerSchedulerSetPeriod(INTERNAL_MODULE, PPM_PERIOD(INTERNAL_MODULE));
|
||||
return true;
|
||||
#endif
|
||||
|
||||
@@ -572,7 +551,6 @@ bool setupPulsesInternalModule(uint8_t protocol)
|
||||
#endif
|
||||
|
||||
default:
|
||||
//mixerSchedulerSetPeriod(INTERNAL_MODULE, 10000 /*us*/); // used for USB sim for example
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
+18
-3
@@ -30,7 +30,12 @@
|
||||
#define PXX2_LOWSPEED_BAUDRATE 230400
|
||||
#define PXX2_HIGHSPEED_BAUDRATE 450000
|
||||
#define PXX2_NO_HEARTBEAT_PERIOD 4000/*us*/
|
||||
#define PXX2_MAX_HEARTBEAT_PERIOD (7000 + 1000)/*us 7ms frame rate + 1ms heartbeat backup*/
|
||||
#define PXX2_MAX_HEARTBEAT_PERIOD (9000 + 1000)/*us longest period (isrm/accst) + 1ms heartbeat backup*/
|
||||
#if defined(INTMODULE_HEARTBEAT)
|
||||
#define PXX2_PERIOD PXX2_MAX_HEARTBEAT_PERIOD
|
||||
#else
|
||||
#define PXX2_PERIOD PXX2_NO_HEARTBEAT_PERIOD
|
||||
#endif
|
||||
#define PXX2_TOOLS_PERIOD 1000/*us*/
|
||||
#define PXX2_FRAME_MAXLENGTH 64
|
||||
|
||||
@@ -40,10 +45,20 @@
|
||||
|
||||
#if defined(PXX_FREQUENCY_HIGH)
|
||||
#define INTMODULE_PXX1_SERIAL_BAUDRATE 450000
|
||||
#define INTMODULE_PXX1_SERIAL_PERIOD 4000/*us*/
|
||||
#if defined(INTMODULE_HEARTBEAT)
|
||||
// use backup trigger (1 ms later)
|
||||
#define INTMODULE_PXX1_SERIAL_PERIOD (4000 + 1000)/*us*/
|
||||
#else
|
||||
#define INTMODULE_PXX1_SERIAL_PERIOD 4000/*us*/
|
||||
#endif
|
||||
#else
|
||||
#define INTMODULE_PXX1_SERIAL_BAUDRATE 115200
|
||||
#define INTMODULE_PXX1_SERIAL_PERIOD 9000/*us*/
|
||||
#if defined(INTMODULE_HEARTBEAT)
|
||||
// use backup trigger (1 ms later)
|
||||
#define INTMODULE_PXX1_SERIAL_PERIOD (9000 + 1000)/*us*/
|
||||
#else
|
||||
#define INTMODULE_PXX1_SERIAL_PERIOD 9000/*us*/
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Used by the Sky9x family boards
|
||||
|
||||
@@ -79,6 +79,7 @@ void check_intmodule_heartbeat()
|
||||
#endif
|
||||
EXTI_ClearITPendingBit(INTMODULE_HEARTBEAT_EXTI_LINE);
|
||||
|
||||
mixerSchedulerResetTimer();
|
||||
mixerSchedulerISRTrigger();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -183,6 +183,7 @@ endif()
|
||||
|
||||
if(FLYSKY_HALL_STICKS)
|
||||
add_definitions(-DFLYSKY_HALL_STICKS)
|
||||
add_definitions(-DFLYSKY_HALL_STICKS_REVERSE)
|
||||
set(AUX_SERIAL OFF)
|
||||
set(FLYSKY_HALL_STICKS_DRIVER flyskyHallStick_driver.cpp)
|
||||
endif()
|
||||
|
||||
@@ -758,10 +758,6 @@
|
||||
|
||||
// Flysky Hall Stick
|
||||
#if defined(FLYSKY_HALL_STICKS)
|
||||
#if defined (RADIO_TX16S)
|
||||
#define FLYSKY_HALL_STICKS_REVERSE
|
||||
#endif
|
||||
|
||||
#define FLYSKY_HALL_SERIAL_USART UART4
|
||||
#define FLYSKY_HALL_SERIAL_GPIO GPIOA
|
||||
#define FLYSKY_HALL_DMA_Channel DMA_Channel_4
|
||||
@@ -784,7 +780,6 @@
|
||||
|
||||
#define FLYSKY_HALL_RX_DMA_Stream_IRQHandler DMA1_Stream2_IRQHandler
|
||||
#define FLYSKY_HALL_TX_DMA_Stream_IRQHandler DMA1_Stream4_IRQHandler
|
||||
|
||||
#endif
|
||||
|
||||
// Internal Module
|
||||
|
||||
@@ -39,9 +39,9 @@ const uint8_t TOUCH_GT911_Cfg[] = {
|
||||
0x50, // 0x8053 Screen touch level
|
||||
0x3C, // 0x8054 Screen touch leave
|
||||
0x03, // 0x8055 Low power control
|
||||
0x05, // 0x8056 Refresh rate
|
||||
0x00, // 0x8057 X threshold
|
||||
0x00, // 0x8058 Y threshold
|
||||
0x0F, // 0x8056 Refresh rate
|
||||
0x01, // 0x8057 X threshold
|
||||
0x01, // 0x8058 Y threshold
|
||||
0x00, // 0x8059 Reserved
|
||||
0x00, // 0x805A Reserved
|
||||
0x00, // 0x805B Space (top, bottom)
|
||||
@@ -230,9 +230,9 @@ const uint8_t TOUCH_GT911_Cfg[] =
|
||||
0x5A, // 0x8053 Screen touch level
|
||||
0x3C, // 0x8054 Screen touch leave
|
||||
0x03, // 0x8055 Low power control
|
||||
0x05, // 0x8056 Refresh rate
|
||||
0x00, // 0x8057 X threshold
|
||||
0x00, // 0x8058 Y threshold
|
||||
0x0F, // 0x8056 Refresh rate
|
||||
0x01, // 0x8057 X threshold
|
||||
0x01, // 0x8058 Y threshold
|
||||
0x00, // 0x8059 Reserved
|
||||
0x00, // 0x805A Reserved
|
||||
0x11, // 0x805B Space (top, bottom)
|
||||
@@ -403,9 +403,11 @@ const uint8_t TOUCH_GT911_Cfg[] =
|
||||
|
||||
#endif
|
||||
|
||||
uint8_t touchGT911Flag = 0;
|
||||
uint8_t touchEventOccured = 0;
|
||||
bool touchGT911Flag = false;
|
||||
volatile static bool touchEventOccured = false;
|
||||
struct TouchData touchData;
|
||||
uint16_t touchGT911fwver = 0;
|
||||
uint32_t touchGT911hiccups = 0;
|
||||
|
||||
static void TOUCH_AF_ExtiStop(void)
|
||||
{
|
||||
@@ -415,7 +417,7 @@ static void TOUCH_AF_ExtiStop(void)
|
||||
EXTI_StructInit(&EXTI_InitStructure);
|
||||
EXTI_InitStructure.EXTI_Line = TOUCH_INT_EXTI_LINE1;
|
||||
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
|
||||
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling;
|
||||
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
|
||||
EXTI_InitStructure.EXTI_LineCmd = DISABLE;
|
||||
EXTI_Init(&EXTI_InitStructure);
|
||||
|
||||
@@ -436,7 +438,7 @@ static void TOUCH_AF_ExtiConfig(void)
|
||||
EXTI_StructInit(&EXTI_InitStructure);
|
||||
EXTI_InitStructure.EXTI_Line = TOUCH_INT_EXTI_LINE1;
|
||||
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
|
||||
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling;
|
||||
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
|
||||
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
|
||||
EXTI_Init(&EXTI_InitStructure);
|
||||
|
||||
@@ -484,6 +486,8 @@ void TOUCH_AF_INT_Change(void)
|
||||
|
||||
void I2C_Init()
|
||||
{
|
||||
TRACE("I2C Init");
|
||||
|
||||
I2C_DeInit(I2C);
|
||||
|
||||
GPIO_InitTypeDef GPIO_InitStructure;
|
||||
@@ -508,6 +512,15 @@ void I2C_Init()
|
||||
GPIO_Init(I2C_GPIO, &GPIO_InitStructure);
|
||||
}
|
||||
|
||||
bool I2C_WaitFlag(uint32_t flag)
|
||||
{
|
||||
uint32_t timeout = I2C_TIMEOUT_MAX;
|
||||
while (!I2C_GetFlagStatus(I2C, flag)) {
|
||||
if ((timeout--) == 0) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool I2C_WaitEvent(uint32_t event)
|
||||
{
|
||||
uint32_t timeout = I2C_TIMEOUT_MAX;
|
||||
@@ -529,33 +542,55 @@ bool I2C_WaitEventCleared(uint32_t event)
|
||||
uint8_t I2C_GT911_WriteRegister(uint16_t reg, uint8_t * buf, uint8_t len)
|
||||
{
|
||||
if (!I2C_WaitEventCleared(I2C_FLAG_BUSY))
|
||||
{
|
||||
TRACE("I2C WRITE ERROR: busy timeout");
|
||||
return false;
|
||||
}
|
||||
|
||||
I2C_GenerateSTART(I2C, ENABLE);
|
||||
if (!I2C_WaitEvent(I2C_EVENT_MASTER_MODE_SELECT))
|
||||
{
|
||||
TRACE("I2C WRITE ERROR: could not issue start");
|
||||
return false;
|
||||
}
|
||||
|
||||
I2C_Send7bitAddress(I2C, GT_CMD_WR, I2C_Direction_Transmitter);
|
||||
if (!I2C_WaitEvent(I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
|
||||
{
|
||||
TRACE("I2C WRITE ERROR: could not send device address");
|
||||
return false;
|
||||
}
|
||||
|
||||
I2C_SendData(I2C, (uint8_t)((reg & 0xFF00) >> 8));
|
||||
if (!I2C_WaitEvent(I2C_EVENT_MASTER_BYTE_TRANSMITTING))
|
||||
{
|
||||
TRACE("I2C WRITE ERROR: could not send register high address");
|
||||
return false;
|
||||
}
|
||||
|
||||
I2C_SendData(I2C, (uint8_t)(reg & 0x00FF));
|
||||
if (!I2C_WaitEvent(I2C_EVENT_MASTER_BYTE_TRANSMITTING))
|
||||
{
|
||||
TRACE("I2C WRITE ERROR: could not send register low address");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* While there is data to be written */
|
||||
while (len--) {
|
||||
I2C_SendData(I2C, *buf);
|
||||
if (!I2C_WaitEvent(I2C_EVENT_MASTER_BYTE_TRANSMITTING))
|
||||
{
|
||||
TRACE("I2C WRITE ERROR: could not send data with %u bytes remaining", len+1 );
|
||||
return false;
|
||||
}
|
||||
buf++;
|
||||
}
|
||||
|
||||
if (!I2C_WaitEvent(I2C_EVENT_MASTER_BYTE_TRANSMITTED))
|
||||
{
|
||||
TRACE("I2C WRITE ERROR: waiting for BTF failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
I2C_GenerateSTOP(I2C, ENABLE);
|
||||
return true;
|
||||
@@ -564,67 +599,184 @@ uint8_t I2C_GT911_WriteRegister(uint16_t reg, uint8_t * buf, uint8_t len)
|
||||
bool I2C_GT911_ReadRegister(u16 reg, uint8_t * buf, uint8_t len)
|
||||
{
|
||||
if (!I2C_WaitEventCleared(I2C_FLAG_BUSY))
|
||||
{
|
||||
TRACE("I2C READ ERROR: busy timeout");
|
||||
return false;
|
||||
}
|
||||
|
||||
I2C_GenerateSTART(I2C, ENABLE);
|
||||
if (!I2C_WaitEvent(I2C_EVENT_MASTER_MODE_SELECT))
|
||||
{
|
||||
TRACE("I2C READ ERROR: could not issue first step start");
|
||||
return false;
|
||||
}
|
||||
|
||||
I2C_Send7bitAddress(I2C, GT_CMD_WR, I2C_Direction_Transmitter);
|
||||
if (!I2C_WaitEvent(I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
|
||||
{
|
||||
TRACE("I2C READ ERROR: could not send first step device address");
|
||||
return false;
|
||||
}
|
||||
|
||||
I2C_SendData(I2C, (uint8_t)((reg & 0xFF00) >> 8));
|
||||
if (!I2C_WaitEvent(I2C_EVENT_MASTER_BYTE_TRANSMITTING))
|
||||
{
|
||||
TRACE("I2C READ ERROR: could not send register high address");
|
||||
return false;
|
||||
}
|
||||
|
||||
I2C_SendData(I2C, (uint8_t)(reg & 0x00FF));
|
||||
if (!I2C_WaitEvent(I2C_EVENT_MASTER_BYTE_TRANSMITTED))
|
||||
{
|
||||
TRACE("I2C READ ERROR: could not send register low address");
|
||||
return false;
|
||||
}
|
||||
|
||||
// According to GP911 data sheet, repeated start is not listed, so we do full stop.
|
||||
// See chapter 6.1.c, page 12, diagram for reading data
|
||||
I2C_GenerateSTOP(I2C, ENABLE);
|
||||
if (!I2C_WaitEventCleared(I2C_FLAG_BUSY))
|
||||
{
|
||||
TRACE("I2C READ ERROR: timeout waiting for first stop");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Enable Acknowledgement, clear POS flag
|
||||
I2C_AcknowledgeConfig(I2C, ENABLE);
|
||||
I2C_NACKPositionConfig(I2C, I2C_NACKPosition_Current);
|
||||
|
||||
I2C_GenerateSTART(I2C, ENABLE);
|
||||
if (!I2C_WaitEvent(I2C_EVENT_MASTER_MODE_SELECT))
|
||||
{
|
||||
TRACE("I2C READ ERROR: could not issue second step start");
|
||||
return false;
|
||||
}
|
||||
|
||||
I2C_Send7bitAddress(I2C, GT_CMD_RD, I2C_Direction_Receiver);
|
||||
if (!I2C_WaitEvent(I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED))
|
||||
{
|
||||
TRACE("I2C READ ERROR: could not send second step device address");
|
||||
return false;
|
||||
|
||||
if (len > 1) {
|
||||
I2C_AcknowledgeConfig(I2C, ENABLE);
|
||||
}
|
||||
|
||||
while (len) {
|
||||
if (len == 1) {
|
||||
I2C_AcknowledgeConfig(I2C, DISABLE);
|
||||
}
|
||||
if (!I2C_WaitEvent(I2C_EVENT_MASTER_BYTE_RECEIVED))
|
||||
if (len == 1) {
|
||||
// Clear Ack bit
|
||||
I2C_AcknowledgeConfig(I2C, DISABLE);
|
||||
|
||||
// EV6_1 -- must be atomic -- Clear ADDR, generate STOP
|
||||
__disable_irq();
|
||||
(void) I2C->SR2;
|
||||
I2C_GenerateSTOP(I2C,ENABLE);
|
||||
__enable_irq();
|
||||
|
||||
// Receive data EV7
|
||||
if(!I2C_WaitFlag(I2C_FLAG_RXNE)) {
|
||||
TRACE("I2C READ ERROR: timeout waiting for RxNE");
|
||||
I2C_Init();
|
||||
return false;
|
||||
}
|
||||
|
||||
*buf++ = I2C_ReceiveData(I2C);
|
||||
len--;
|
||||
}
|
||||
else if (len == 2) {
|
||||
|
||||
// Set POS flag
|
||||
I2C_NACKPositionConfig(I2C, I2C_NACKPosition_Next);
|
||||
|
||||
// EV6_1 -- must be atomic and in this order
|
||||
__disable_irq();
|
||||
(void) I2C->SR2; // Clear ADDR flag
|
||||
I2C_AcknowledgeConfig(I2C, DISABLE); // Clear Ack bit
|
||||
__enable_irq();
|
||||
|
||||
// EV7_3 -- Wait for BTF, program stop, read data twice
|
||||
if (!I2C_WaitFlag(I2C_FLAG_BTF)) {
|
||||
TRACE("I2C READ ERROR: timeout waiting for BTF");
|
||||
I2C_Init();
|
||||
return false;
|
||||
}
|
||||
|
||||
__disable_irq();
|
||||
I2C_GenerateSTOP(I2C,ENABLE);
|
||||
*buf++ = I2C->DR;
|
||||
__enable_irq();
|
||||
|
||||
*buf++ = I2C->DR;
|
||||
}
|
||||
else {
|
||||
|
||||
(void) I2C->SR2; // Clear ADDR flag
|
||||
while (len-- != 3) {
|
||||
// EV7 -- cannot guarantee 1 transfer completion time, wait for BTF
|
||||
// instead of RXNE
|
||||
if (!I2C_WaitFlag(I2C_FLAG_BTF)) {
|
||||
TRACE("I2C READ ERROR: timeout waiting for BTF");
|
||||
I2C_Init();
|
||||
return false;
|
||||
}
|
||||
|
||||
*buf++ = I2C_ReceiveData(I2C);
|
||||
}
|
||||
|
||||
// Data N-2 in DR, data N-1 in shift register,
|
||||
// SCL stretched low until data N-2 is read
|
||||
if (!I2C_WaitFlag(I2C_FLAG_BTF)) {
|
||||
TRACE("I2C READ ERROR: timeout waiting for BTF");
|
||||
I2C_Init();
|
||||
return false;
|
||||
}
|
||||
|
||||
I2C_AcknowledgeConfig(I2C, DISABLE); // clear ack bit
|
||||
*buf++ = I2C_ReceiveData(I2C); // receive byte N-2
|
||||
|
||||
// Wait for BTF, program stop, read data twice
|
||||
if (!I2C_WaitFlag(I2C_FLAG_BTF)) {
|
||||
TRACE("I2C READ ERROR: timeout waiting for BTF");
|
||||
I2C_Init();
|
||||
return false;
|
||||
}
|
||||
|
||||
__disable_irq();
|
||||
I2C_GenerateSTOP(I2C,ENABLE);
|
||||
*buf++ = I2C->DR;
|
||||
__enable_irq();
|
||||
|
||||
*buf++ = I2C->DR;
|
||||
}
|
||||
|
||||
I2C_GenerateSTOP(I2C, ENABLE);
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8_t I2C_GT911_SendConfig(uint8_t mode)
|
||||
bool I2C_GT911_SendConfig(void)
|
||||
{
|
||||
uint8_t buf[2];
|
||||
uint8_t i = 0;
|
||||
buf[0] = 0;
|
||||
buf[1] = mode;
|
||||
buf[1] = 1;
|
||||
bool bResult = true;
|
||||
|
||||
for (i = 0; i < sizeof(TOUCH_GT911_Cfg); i++)
|
||||
buf[0] += TOUCH_GT911_Cfg[i];//check sum
|
||||
|
||||
buf[0] = (~buf[0]) + 1;
|
||||
I2C_GT911_WriteRegister(GT_CFGS_REG, (uint8_t *) TOUCH_GT911_Cfg, sizeof(TOUCH_GT911_Cfg));//
|
||||
I2C_GT911_WriteRegister(GT_CHECK_REG, buf, 2);//write checksum
|
||||
return 0;
|
||||
if (!I2C_GT911_WriteRegister(GT_CFGS_REG, (uint8_t *) TOUCH_GT911_Cfg, sizeof(TOUCH_GT911_Cfg)))
|
||||
{
|
||||
TRACE("GT911 ERROR: write config failed");
|
||||
bResult = false;
|
||||
}
|
||||
|
||||
if (!I2C_GT911_WriteRegister(GT_CHECK_REG, buf, 2)) //write checksum
|
||||
{
|
||||
TRACE("GT911 ERROR: write config checksum failed");
|
||||
bResult = false;
|
||||
}
|
||||
return bResult;
|
||||
}
|
||||
|
||||
void touchPanelDeInit(void)
|
||||
{
|
||||
TOUCH_AF_ExtiStop();
|
||||
touchGT911Flag = false;
|
||||
}
|
||||
|
||||
bool touchPanelInit(void)
|
||||
@@ -656,29 +808,55 @@ bool touchPanelInit(void)
|
||||
delay_ms(50);
|
||||
|
||||
TRACE("Reading Touch registry");
|
||||
I2C_GT911_ReadRegister(GT_PID_REG, tmp, 4);
|
||||
if (!I2C_GT911_ReadRegister(GT_PID_REG, tmp, 4))
|
||||
{
|
||||
TRACE("GT911 ERROR: Product ID read failed");
|
||||
}
|
||||
|
||||
if (strcmp((char *) tmp, "911") == 0) //ID==9147
|
||||
{
|
||||
TRACE("GT911 chip detected");
|
||||
tmp[0] = 0X02;
|
||||
I2C_GT911_WriteRegister(GT_CTRL_REG, tmp, 1);
|
||||
I2C_GT911_ReadRegister(GT_CFGS_REG, tmp, 1);
|
||||
if (!I2C_GT911_WriteRegister(GT_CTRL_REG, tmp, 1))
|
||||
{
|
||||
TRACE("GT911 ERROR: write to control register failed");
|
||||
}
|
||||
if (!I2C_GT911_ReadRegister(GT_CFGS_REG, tmp, 1))
|
||||
{
|
||||
TRACE("GT911 ERROR: configuration register read failed");
|
||||
}
|
||||
|
||||
TRACE("Chip config Ver:%x\r\n", tmp[0]);
|
||||
if (tmp[0] < GT911_CFG_NUMER) //Config ver
|
||||
TRACE("Chip config Ver:%x", tmp[0]);
|
||||
if (tmp[0] <= GT911_CFG_NUMER) //Config ver
|
||||
{
|
||||
TRACE("Sending new config %d", GT911_CFG_NUMER);
|
||||
I2C_GT911_SendConfig(1);
|
||||
if (!I2C_GT911_SendConfig())
|
||||
{
|
||||
TRACE("GT911 ERROR: sending configration failed");
|
||||
}
|
||||
}
|
||||
|
||||
if (!I2C_GT911_ReadRegister(GT911_FIRMWARE_VERSION_REG, tmp, 2))
|
||||
{
|
||||
TRACE("GT911 ERROR: reading firmware version failed");
|
||||
}
|
||||
else
|
||||
{
|
||||
touchGT911fwver = (tmp[1] << 8) + tmp[0];
|
||||
TRACE("GT911 FW version: %u", touchGT911fwver);
|
||||
}
|
||||
|
||||
delay_ms(10);
|
||||
tmp[0] = 0X00;
|
||||
I2C_GT911_WriteRegister(GT_CTRL_REG, tmp, 1); //end reset
|
||||
if (!I2C_GT911_WriteRegister(GT_CTRL_REG, tmp, 1)) //end reset
|
||||
{
|
||||
TRACE("GT911 ERROR: write to control register failed");
|
||||
}
|
||||
touchGT911Flag = true;
|
||||
|
||||
TOUCH_AF_ExtiConfig();
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
TRACE("GT911 chip NOT FOUND");
|
||||
@@ -686,6 +864,7 @@ bool touchPanelInit(void)
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(SIMU) || defined(SEMIHOSTING) || defined(DEBUG)
|
||||
static const char* event2str(uint8_t ev)
|
||||
{
|
||||
switch(ev){
|
||||
@@ -703,20 +882,25 @@ static const char* event2str(uint8_t ev)
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void touchPanelRead()
|
||||
{
|
||||
uint8_t state = 0;
|
||||
|
||||
if (!touchEventOccured)
|
||||
return;
|
||||
// if (!touchEventOccured)
|
||||
// return;
|
||||
|
||||
touchEventOccured = 0;
|
||||
// touchEventOccured = false;
|
||||
|
||||
uint32_t startReadStatus = RTOS_GET_MS();
|
||||
do {
|
||||
if (!I2C_GT911_ReadRegister(GT911_READ_XY_REG, &state, 1)) {
|
||||
TRACE("GT911 I2C read error");
|
||||
//ledRed();
|
||||
touchGT911hiccups++;
|
||||
TRACE("GT911 I2C read XY error");
|
||||
touchPanelDeInit();
|
||||
touchPanelInit();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -734,7 +918,11 @@ void touchPanelRead()
|
||||
if (pointsCount > 0 && pointsCount <= GT911_MAX_TP) {
|
||||
if (!I2C_GT911_ReadRegister(GT911_READ_XY_REG + 1, touchData.data,
|
||||
pointsCount * sizeof(TouchPoint))) {
|
||||
TRACE("GT911 I2C read error");
|
||||
//ledRed();
|
||||
touchGT911hiccups++;
|
||||
TRACE("GT911 I2C data read error");
|
||||
touchPanelDeInit();
|
||||
touchPanelInit();
|
||||
return;
|
||||
}
|
||||
if (touchState.event == TE_NONE || touchState.event == TE_UP ||
|
||||
@@ -765,7 +953,10 @@ void touchPanelRead()
|
||||
}
|
||||
|
||||
uint8_t zero = 0;
|
||||
I2C_GT911_WriteRegister(GT911_READ_XY_REG, &zero, 1);
|
||||
if (!I2C_GT911_WriteRegister(GT911_READ_XY_REG, &zero, 1))
|
||||
{
|
||||
TRACE("GT911 ERROR: clearing XY register failed");
|
||||
}
|
||||
|
||||
TRACE("touch event = %s", event2str(touchState.event));
|
||||
}
|
||||
@@ -777,7 +968,7 @@ extern "C" void TOUCH_INT_EXTI_IRQHandler1(void)
|
||||
// on touch turn the light on
|
||||
resetBacklightTimeout();
|
||||
}
|
||||
touchEventOccured = 1;
|
||||
touchEventOccured = true;
|
||||
EXTI_ClearITPendingBit(TOUCH_INT_EXTI_LINE1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,13 +22,15 @@
|
||||
|
||||
#define HAS_TOUCH_PANEL() touchGT911Flag == true
|
||||
|
||||
extern uint8_t touchGT911Flag;
|
||||
extern bool touchGT911Flag;
|
||||
extern uint16_t touchGT911fwver;
|
||||
extern uint32_t touchGT911hiccups;
|
||||
extern bool touchPanelInit();
|
||||
|
||||
void touchPanelRead();
|
||||
bool touchPanelEventOccured();
|
||||
|
||||
#define GT911_TIMEOUT 20 // 20ms
|
||||
#define GT911_TIMEOUT 3 // 3ms
|
||||
|
||||
#define GT911_MAX_TP 5
|
||||
#define GT911_CFG_NUMER 0x6C
|
||||
|
||||
@@ -128,6 +128,8 @@ void adcInit()
|
||||
ADC_DMA_Stream->NDTR = 2;
|
||||
ADC_DMA_Stream->FCR = DMA_SxFCR_DMDIS | DMA_SxFCR_FTH_0;
|
||||
|
||||
ADC->CCR = ADC_CCR_VBATE; // Enable RTC coin cell sampling bridge
|
||||
|
||||
ADC1->CR1 = ADC_CR1_SCAN;
|
||||
ADC1->CR2 = ADC_CR2_ADON | ADC_CR2_DMA | ADC_CR2_DDS;
|
||||
ADC1->SQR1 = (1 - 1) << 20;
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
#include "opentx.h"
|
||||
#include "touch_driver.h"
|
||||
|
||||
static bool touchEventOccured;
|
||||
volatile static bool touchEventOccured;
|
||||
|
||||
#define FT6x06_MAX_INSTANCE 1
|
||||
|
||||
|
||||
Vendored
+15
-2
@@ -29,6 +29,19 @@
|
||||
#include "usb_core.h"
|
||||
#include "usb_bsp.h"
|
||||
|
||||
// taken from https://github.com/ARMmbed/mbed-os/blob/master/cmsis/TARGET_CORTEX_M/cmsis_compiler.h
|
||||
#ifndef __PACKED_STRUCT
|
||||
#define __PACKED_STRUCT struct __attribute__((packed))
|
||||
#endif
|
||||
#ifndef __UNALIGNED_UINT32_WRITE
|
||||
__PACKED_STRUCT T_UINT32_WRITE { uint32_t v; };
|
||||
#define __UNALIGNED_UINT32_WRITE(addr, val) (void)((((struct T_UINT32_WRITE *)(void *)(addr))->v) = (val))
|
||||
#endif
|
||||
#ifndef __UNALIGNED_UINT32_READ
|
||||
__PACKED_STRUCT T_UINT32_READ { uint32_t v; };
|
||||
#define __UNALIGNED_UINT32_READ(addr) (((const struct T_UINT32_READ *)(const void *)(addr))->v)
|
||||
#endif
|
||||
|
||||
|
||||
/** @addtogroup USB_OTG_DRIVER
|
||||
* @{
|
||||
@@ -180,7 +193,7 @@ USB_OTG_STS USB_OTG_WritePacket(USB_OTG_CORE_HANDLE *pdev,
|
||||
fifo = pdev->regs.DFIFO[ch_ep_num];
|
||||
for (i = 0; i < count32b; i++)
|
||||
{
|
||||
USB_OTG_WRITE_REG32( fifo, *((uint32_t *)src) );
|
||||
USB_OTG_WRITE_REG32( fifo, __UNALIGNED_UINT32_READ(src) );
|
||||
src+=4;
|
||||
}
|
||||
}
|
||||
@@ -206,7 +219,7 @@ void *USB_OTG_ReadPacket(USB_OTG_CORE_HANDLE *pdev,
|
||||
|
||||
for( i = 0; i < count32b; i++)
|
||||
{
|
||||
*(uint32_t *)dest = USB_OTG_READ_REG32(fifo);
|
||||
__UNALIGNED_UINT32_WRITE(dest, USB_OTG_READ_REG32(fifo));
|
||||
dest += 4 ;
|
||||
}
|
||||
return ((void *)dest);
|
||||
|
||||
Vendored
+1
-1
Submodule radio/src/thirdparty/libopenui updated: 05067daa62...014e87b9fc
Reference in New Issue
Block a user