Merge pull request #447 from EdgeTX/2.4

Merge from 2.4 branch
This commit is contained in:
richardclli
2021-07-14 10:41:13 +08:00
committed by GitHub
33 changed files with 1011 additions and 165 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 803 B

+5 -5
View File
@@ -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);
-3
View File
@@ -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)
+1
View File
@@ -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
+2
View File
@@ -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,
+38 -9
View File
@@ -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
+33 -9
View File
@@ -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_
+2 -2
View File
@@ -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));
+3 -3
View File
@@ -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));
},
+4 -3
View File
@@ -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();
+16 -24
View File
@@ -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();
+26 -5
View File
@@ -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());
+9 -1
View File
@@ -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
};
+17 -10
View File
@@ -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));
+5 -5
View File
@@ -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);
+2 -2
View File
@@ -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;
+435
View File
@@ -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();
}
+126
View File
@@ -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();
+1 -4
View File
@@ -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();
+5 -27
View File
@@ -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
View File
@@ -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();
}
}
+1
View File
@@ -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()
-5
View File
@@ -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
+230 -39
View File
@@ -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);
}
}
+4 -2
View File
@@ -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;
+1 -1
View File
@@ -21,7 +21,7 @@
#include "opentx.h"
#include "touch_driver.h"
static bool touchEventOccured;
volatile static bool touchEventOccured;
#define FT6x06_MAX_INSTANCE 1
@@ -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);