#if defined BOARD_OBP60S3 || defined BOARD_OBP40S3 #include "Pagedata.h" #include "OBP60Extensions.h" #include "ConfigMenu.h" /* Anchor overview with additional associated data This page is in experimental stage so be warned! North is up. Boatdata used DBS - Water depth HDT - Boat heading AWS - Wind strength; Boat not moving so we assume AWS=TWS and AWD=TWD AWD - Wind direction LAT/LON - Boat position, current HDOP - Position error This is the fist page to contain a configuration page with data entry option. Also it will make use of the new alarm function. Data Anchor position lat/lon Depth at anchor position Chain length used Boat position current Depth at boat position Boat heading Wind direction Wind strength Alarm j/n Alarm radius GPS position error Timestamp while dropping anchor Drop / raise function in device OBP40 has to be done inside config mode because of limited number of buttons. */ #define anchor_width 16 #define anchor_height 16 static unsigned char anchor_bits[] = { 0x80, 0x01, 0x40, 0x02, 0x40, 0x02, 0x80, 0x01, 0xf0, 0x0f, 0x80, 0x01, 0x80, 0x01, 0x88, 0x11, 0x8c, 0x31, 0x8e, 0x71, 0x84, 0x21, 0x86, 0x61, 0x86, 0x61, 0xfc, 0x3f, 0xf8, 0x1f, 0x80, 0x01 }; class PageAnchor : public Page { private: GwConfigHandler *config; GwLog *logger; bool simulation = false; bool holdvalues = false; String flashLED; String backlightMode; String lengthformat; int scale = 50; // Radius of display circle in meter bool alarm = false; bool alarm_enabled = false; uint8_t alarm_range; uint8_t chain_length; uint8_t chain; bool anchor_set = false; double anchor_lat; double anchor_lon; double anchor_depth; int anchor_ts; // time stamp anchor dropped char mode = 'N'; // (N)ormal, (C)onfig // ConfigMenu menu; void displayModeNormal(PageData &pageData) { // Boatvalues: DBS, HDT, AWS, AWD, LAT, LON, HDOP GwApi::BoatValue *bv_dbs = pageData.values[0]; // DBS String sval_dbs = formatValue(bv_dbs, *commonData).svalue; String sunit_dbs = formatValue(bv_dbs, *commonData).unit; GwApi::BoatValue *bv_hdt = pageData.values[1]; // HDT String sval_hdt = formatValue(bv_hdt, *commonData).svalue; GwApi::BoatValue *bv_aws = pageData.values[2]; // AWS String sval_aws = formatValue(bv_aws, *commonData).svalue; String sunit_aws = formatValue(bv_aws, *commonData).unit; GwApi::BoatValue *bv_awd = pageData.values[3]; // AWD String sval_awd = formatValue(bv_awd, *commonData).svalue; GwApi::BoatValue *bv_lat = pageData.values[4]; // LAT String sval_lat = formatValue(bv_lat, *commonData).svalue; GwApi::BoatValue *bv_lon = pageData.values[5]; // LON String sval_lon = formatValue(bv_lon, *commonData).svalue; GwApi::BoatValue *bv_hdop = pageData.values[6]; // HDOP String sval_hdop = formatValue(bv_hdop, *commonData).svalue; String sunit_hdop = formatValue(bv_hdop, *commonData).unit; LOG_DEBUG(GwLog::DEBUG,"Drawing at PageAnchor; DBS=%f, HDT=%f, AWS=%f", bv_dbs->value, bv_hdt->value, bv_aws->value); Point c = {200, 150}; // center = anchor position uint16_t r = 125; Point b = {200, 180}; // boat position while dropping anchor const std::vector pts_boat = { // polygon lines {b.x - 5, b.y}, {b.x - 5, b.y - 10}, {b.x, b.y - 16}, {b.x + 5, b.y - 10}, {b.x + 5, b.y} }; //rotatePoints und dann Linien zeichnen // TODO rotate boat according to current heading //drawPoly(rotatePoints(c, pts, RadToDeg(value2)), commonData->fgcolor); drawPoly(pts_boat, commonData->fgcolor); /*size_t polysize = pts_boat.size(); for (size_t i = 0; i < polysize - 1; i++) { getdisplay().drawLine(pts_boat[i].x, pts_boat[i].y, pts_boat[i+1].x, pts_boat[i+1].y, commonData->fgcolor); } // close path getdisplay().drawLine(pts_boat[polysize-1].x, pts_boat[polysize-1].y, pts_boat[0].x, pts_boat[0].y, commonData->fgcolor); */ // Draw wind arrow const std::vector pts_wind = { {c.x, c.y - r + 25}, {c.x - 12, c.y - r - 4}, {c.x, c.y - r + 6}, {c.x + 12, c.y - r - 4} }; if (bv_awd->valid) { fillPoly4(rotatePoints(c, pts_wind, bv_awd->value), commonData->fgcolor); } // Title and corner value headings getdisplay().setTextColor(commonData->fgcolor); getdisplay().setFont(&Ubuntu_Bold12pt8b); getdisplay().setCursor(8, 48); getdisplay().print("Anchor"); getdisplay().setFont(&Ubuntu_Bold10pt8b); getdisplay().setCursor(8, 200); getdisplay().print("Depth"); drawTextRalign(392, 38, "Chain"); drawTextRalign(392, 200, "Wind"); // Units getdisplay().setCursor(8, 272); getdisplay().print(sunit_dbs); drawTextRalign(392, 272, sunit_aws); drawTextRalign(392, 100, lengthformat); // chain unit not implemented // Corner values getdisplay().setFont(&Ubuntu_Bold8pt8b); getdisplay().setCursor(8, 70); getdisplay().print("Alarm: "); getdisplay().print(alarm_enabled ? "On" : "Off"); getdisplay().setCursor(8, 90); getdisplay().print("HDOP"); getdisplay().setCursor(8, 106); if (bv_hdop->valid) { getdisplay().print(round(bv_hdop->value), 0); getdisplay().print(sunit_hdop); } else { getdisplay().print("n/a"); } // Values getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b); // Current chain used getdisplay().setCursor(328, 85); getdisplay().print("27"); // Depth getdisplay().setCursor(8, 250); getdisplay().print(sval_dbs); // Wind getdisplay().setCursor(328, 250); getdisplay().print(sval_aws); getdisplay().drawCircle(c.x, c.y, r, commonData->fgcolor); getdisplay().drawCircle(c.x, c.y, r + 1, commonData->fgcolor); // zoom scale getdisplay().drawLine(c.x + 10, c.y, c.x + r - 4, c.y, commonData->fgcolor); // arrow left getdisplay().drawLine(c.x + 10, c.y, c.x + 16, c.y - 4, commonData->fgcolor); getdisplay().drawLine(c.x + 10, c.y, c.x + 16, c.y + 4, commonData->fgcolor); // arrow right getdisplay().drawLine(c.x + r - 4, c.y, c.x + r - 10, c.y - 4, commonData->fgcolor); getdisplay().drawLine(c.x + r - 4, c.y, c.x + r - 10, c.y + 4, commonData->fgcolor); getdisplay().setFont(&Ubuntu_Bold8pt8b); drawTextCenter(c.x + r / 2, c.y + 8, String(scale) + "m"); // alarm range circle if (alarm_enabled) { // alarm range in meter has to be smaller than the scale in meter // r and r_range are pixel values uint16_t r_range = int(alarm_range * r / scale); LOG_DEBUG(GwLog::LOG,"Drawing at PageAnchor; Alarm range = %d", r_range); getdisplay().drawCircle(c.x, c.y, r_range, commonData->fgcolor); } // draw anchor symbol (as bitmap) getdisplay().drawXBitmap(c.x - anchor_width / 2, c.y - anchor_height / 2, anchor_bits, anchor_width, anchor_height, commonData->fgcolor); } void displayModeConfig() { // LOG_DEBUG(GwLog::LOG,"Drawing at PageAnchor; Mode=%c", mode); getdisplay().setTextColor(commonData->fgcolor); getdisplay().setFont(&Ubuntu_Bold12pt8b); getdisplay().setCursor(8, 48); getdisplay().print("Anchor configuration"); // TODO // show lat/lon for anchor pos // show lat/lon for boat pos // show distance anchor <-> boat } public: PageAnchor(CommonData &common) // : menu("Options", 80, 20) { commonData = &common; config = commonData->config; logger = commonData->logger; logger->logDebug(GwLog::LOG,"Instantiate PageAnchor"); // preload configuration data simulation = config->getBool(config->useSimuData); holdvalues = config->getBool(config->holdvalues); flashLED = config->getString(config->flashLED); backlightMode = config->getString(config->backlight); lengthformat = config->getString(config->lengthFormat); chain_length = config->getInt(config->chainLength); chain = 0; anchor_set = false; alarm_range = 30; /* // Initialize config menu ConfigMenuItem *newitem; menu.setItemDimension(120, 20); newitem = menu.addItem("chain", "Chain out", "int"); newitem->setRange(0, 200, {1, 5, 10}); newitem = menu.addItem("chainmax", "Chain max", "int"); newitem->setRange(0, 200, {1, 5, 10}); newitem = menu.addItem("zoom", "Zoom", "int"); newitem->setRange(0, 200, {1, }); newitem = menu.addItem("range", "Alarm range", "int"); newitem->setRange(0, 200, {1, 5, 10}); // START only for OBP40 newitem = menu.addItem("anchor", "Anchor down", "bool"); newitem = menu.addItem("anchor_lat", "Adjust anchor lat.", "int"); newitem->setRange(0, 200, {1, 5, 10}); newitem = menu.addItem("anchor_lon", "Adjust anchor lon.", "int"); newitem->setRange(0, 200, {1, 5, 10}); // STOP only for OBP40 menu.setItemActive("chain"); */ } void setupKeys(){ Page::setupKeys(); commonData->keydata[0].label = "MODE"; commonData->keydata[1].label = "ALARM"; } int handleKey(int key){ if (key == 1) { // Switch between normal and config mode if (mode == 'N') { mode = 'C'; } else { mode = 'N'; } return 0; } if (key == 2) { // Toggle alarm alarm_enabled = !alarm_enabled; return 0; } if (key == 11) { // Code for keylock commonData->keylock = !commonData->keylock; return 0; } return key; } void displayNew(PageData &pageData){ }; int displayPage(PageData &pageData){ // Logging boat values LOG_DEBUG(GwLog::LOG,"Drawing at PageAnchor; Mode=%c", mode); // Set display in partial refresh mode getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update if (mode == 'N') { displayModeNormal(pageData); } else if (mode == 'C') { displayModeConfig(); } return PAGE_UPDATE; }; }; static Page *createPage(CommonData &common){ return new PageAnchor(common); } /** * with the code below we make this page known to the PageTask * we give it a type (name) that can be selected in the config * we define which function is to be called * and we provide the number of user parameters we expect * this will be number of BoatValue pointers in pageData.values */ PageDescription registerPageAnchor( "Anchor", // Page name createPage, // Action 0, // Number of bus values depends on selection in Web configuration {"DBS", "HDT", "AWS", "AWD", "LAT", "LON", "HDOP"}, // Names of bus values undepends on selection in Web configuration (refer GwBoatData.h) true // Show display header on/off ); #endif