/* * "Marker.cpp" Contains the code for the "Marker" class functions */ #include "marker.h" // Class definition /* * There are two constructors; the first simply creates an uninitialized * object, and the second one fills in the address of the display object, * the address of the marker's sprite and sets the marker's number. The * "Init" function actually does the work. */ Marker::Marker () {} // Create an uninitialized object Marker::Marker ( TFT_eSprite* spr, uint8_t marker ) { Init ( spr, marker ); } /* * The "Init" function does all the work of the real constructor but can also * be called to initialized a previously uninitialized object. */ void Marker::Init ( TFT_eSprite* spr, uint8_t marker ) { /* * Create our "sprite" and set it up. The actual sprites are created in the main * program. It would make more sense to creat them in here, but I haven't figured * out how to do that without causing crashes or other goofy behaviors. */ _sprite = spr; // Pointer to our sprite object _sprite->setAttribute ( PSRAM_ENABLE, false ); // Don't use PSRAM on the WROVERs _sprite->createSprite ( MARKER_SPRITE_WIDTH, MARKER_SPRITE_HEIGHT ); // Set the size /* * Set some default conditions for the time being: */ _index = marker - 1; // Save marker number _enabled = false; // Turn it off for now _status = 0; // White, disabled & invisible _x = 0; // No real position yet _y = 0; _frequency = 0; // Don't know the frequency _mode = MKR_PEAK; // Assume peak frequency mode /* * Set the pivot point for the marker - this is the point used when pushing */ _sprite->setPivot ( X_MARKER_OFFSET, Y_MARKER_OFFSET ); } /* * "Paint" Remembers the "x"and "y" coordinates and sends the marker to the display. * Note x and y are relative to the target sprite */ void Marker::Paint ( TFT_eSprite *target, uint16_t x, uint16_t y ) { if ( _enabled ) { _x = x + 1; // Remember location _y = y; target->setPivot ( _x, _y ); // Set pivot point in target. // Push rotated checks the bounds of // the target sprite _sprite->pushRotated ( target, 0, BLACK ); // Send the sprite to the target sprite } else // Not enabled return; // Do nothing } /* * Set or retreive the mode for the marker. */ void Marker::Mode ( uint8_t mode ) { _mode = mode; // Simple enough! } uint8_t Marker::Mode () { return _mode; // Also simple! } /* * The next three functions set or clear the "_enabled" indicator. There are two * versions of "Enable"; the first simply marks the marker as enabled and the * second enables the marker and sets the mode all at once. * * "Toggle" toggles the enabled/disabled status. * * These functions also manipulate the "MKR_ACTIVE" bit in the "_status" byte. */ void Marker::Enable () // Enable it { _enabled = true; _status |= MKR_ACTIVE; // In the "_status" byte also } void Marker::Enable ( uint8_t mode ) // Enable & set mode all at once { Mode ( mode ); // Set the mode Enable (); // and enable the marker } void Marker::Disable () // Disable it { _enabled = false; _status &= ~MKR_ACTIVE; // In the "_status" byte also } void Marker::Toggle () // Toggle enabled/disabled status { _enabled = !_enabled; _status ^= MKR_ACTIVE; // In the "_status" byte also } /* * "isEnabled" returns "true" if the marker is enabled; "false" if not. */ bool Marker::isEnabled () // Request enabled/disabled status { return _enabled; } /* * Set or get the marker's current frequency. */ void Marker::Frequency ( uint32_t freq ) // Set the marker's frequency { _frequency = freq; } uint32_t Marker::Frequency () // Get the frequency { return _frequency; } uint8_t Marker::Index () // Get marker's index { return _index; } /* * This version of "Status" simply returns the current "_status" byte, which is updated * whenever a new color for the marker is specified or the enabled/disabled changes. */ uint8_t Marker::Status () // Return the "_status" byte { return _status; } /* * This version of "Status" is used to set the "_status" byte. Note, that we don't * check for a legitimate color choice here as the expectation is that this capability * is only used by the main program when the marker statuses saved in flash memory * are recalled at startup. */ void Marker::Status ( uint8_t status) // Set the status byte { _color = _colors[status & MKR_COLOR]; Color ( _color ); if ( status & MKR_ACTIVE ) // Enable it? Enable (); // Yes, do it else // Otherwise Disable (); // Turn it off } /* * This version of "Color" (do I need an alternate version named "Colour" for the * Brits?) simply returns the 16 bit color assigned to the marker. */ uint16_t Marker::Color () // Returns the marker's color { return _color; } /* * This version of "Color" is used by the serial command handler and the touch screen * menu system to specify the color for the marker. * * There are only six colors allowed. The number is based on the fact that the touch * screen menu can only display that many choices at once. The legal colors are defined * in the "_colors" array in the header file. * * The function checks to see if the specified color is in the list and if so, not only * sets the "_color" variable, but also updates the "_status" byte. */ bool Marker::Color ( uint16_t color ) // Sets the marker's color { /* * The "markerBitmap" shows where in the "sprite" the pixels should be of * the specified color (1) and where the background color (0) should be used. * * Using the bitmap, we build the "sprite" using the specified color. */ const uint8_t markerBitmap[] = { 0xFE, 0xEE, 0xCE, 0xEE, 0xEE, 0xEE, 0xC6, 0x7C, 0X38, 0x10, // Marker 1 0xFE, 0xC6, 0xBA, 0xFA, 0xC6, 0xBE, 0x82, 0x7C, 0x38, 0x10, // Marker 2 0xFE, 0xC6, 0xBA, 0xE6, 0xFA, 0xBA, 0xC6, 0x7C, 0x38, 0x10, // Marker 3 0xFE, 0xF6, 0xE6, 0xD6, 0xB6, 0xB6, 0x82, 0x74, 0x38, 0x10, // Marker 4 }; int line; // Which horizontal line we're painting int column; // and which column int colorIx; // Loop index uint8_t bits; // One byte from the marker definition bool returnCode = false; // Assume bad color specification /* * The first thing we do is to compare the requested color to the legitimate ones * and if we don't find a match, return a "false" indication. */ for ( colorIx = 0; colorIx < MKR_COLOR_COUNT; colorIx++ ) if ( color == _colors[colorIx] ) // Found a match? { returnCode = true; // Set good return code break; // No need to look further } if ( !returnCode ) // If no match found return false; // Return "false" _color = color; // It's a legal color, so save it _status = _status & ~MKR_COLOR; // Clear the previous color _status = _status | colorIx; // Set the new one /* * Next, we re-paint our sprite in the new color. */ for ( line = 0; line < MARKER_HEIGHT; line++ ) // Paint one line at a time { bits = markerBitmap[_index * MARKER_HEIGHT + line]; // Get bitmap of the next line for ( column = 0; column < MARKER_WIDTH; column++ ) // horizontally left to right { if ( bits & 0x80 ) // Next pixel turned on? _sprite->drawPixel ( column, line, SwapBytes ( _color )); // Yes, use specified color else _sprite->drawPixel ( column, line, BACKGROUND );// Use display background color bits <<= 1; // Shift the bitmap byte one place left } } return true; // Good return code } /* * "SwapBytes" was added in Version 2.9. Bodmer did something in the TFT_eSPI library * (version 2.2.5 and later) that makes it necessary to swap the bytes in the color * word when using rotated sprites (as we do here). */ uint16_t Marker::SwapBytes ( uint16_t color) { uint16_t low = ( color & 0x00FF ) << 8; uint16_t high = ( color & 0xFF00 ) >> 8; uint16_t swap = low | high; return swap; }