
Waterfall next, then speed up frequency changes with offsets and reduce delaytime. Sort out 1 pixel error at start/end
305 lines
8.2 KiB
C++
305 lines
8.2 KiB
C++
/*
|
|
* "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;
|
|
}
|