Drawing things
The screensaver feature was nice, but the screensaver could be more entertaining. What if it could display scrolling text, such as "This Rust 4SE02 project will get me a good grade"?
Fortunately, one crate can help you do that: embedded-graphics. Provided you do the proper interfacing with your hardware, this crate will let you draw all kind of shapes, and even display text.
Interfacing with your hardware: the embedded module
You have already decoupled the logical representation of your LED
matrix (the Image type) from the physical one (the Matrix
type). This will make your job easier, as you will only have to
interface the Image type with the embedded-graphics crate: once
you have an Image you can display it on your hardware by putting it
into next_image.
❎ Create an embedded module in your library. This module will
contain anything needed to interface the drawing primitives of the
embedded-graphics crate with your Image type.
First you'll have to choose a pixel representation that
embedded-graphics can use and which is appropriate for your
display. Since you can already display RGB colors with 8 bits data for
each component, the
Rgb888
color type seems appropriate.
❎ Implement From<Rgb888> for your Color type. That will be useful
when drawing on your Image, to build a proper Color value.
Now, you need to implement the
DrawTarget
trait for your Image type. This trait is the one which does the real
drawing. You will only implement the minimal functionality and use the
provided defaults for the rest.
❎ Implement DrawTarget for Image:
- The
Colortype will beRgb888. - You can use
Infallibleas yourErrortype, because drawing into anImagenever fails. - When you implement
draw_iter(), make sure that you only set the pixels whose coordinates belong to the image (xandyboth in0..8). This method can be called with a larger image, for example a large text, and you will only display a portion of it. - If you need to convert a
Rgb888into aColor, do not forget that you can use.into()because you implementedFrom<Rgb888> for Color.
Upgrading the screensaver
You can now use the drawing primitives of embedded-graphics to
create images in your screensaver instead of using gradients.
❎ Modify your screensaver so that it creates intesting images using the drawing primitives.
For example, you could add another local variable in addition to the color index, such as a shape index, and draw a square, a triangle, a circle, and a solid color. Ideally, those color and shape indices would use cycle sizes which are coprime, to maximize the displayed combinations.
When this works, commit and push your code.
Drawing text
The next step is to display scrolling text from the screensaver. Yes, that means forgetting about the shapes that you just designed, they were used to familiarize yourself with the library.
A
Text
object represents some text that can later been drawn into anything
implementing DrawTarget (such as an Image). It uses a character
style, which can be built using
MonoTextStyle::new()
from a font and a color. And the
ibm437 crate provides a great
IBM437_8X8_REGULAR
font which will be perfect for your LED matrix.
The idea is to wait for 60ms (instead of one second) after you have
displayed an image to make some text scroll to the next position if no
new image has been received. To make the text scroll to the left, you
will position it as a negative x offset: since you display pixels
whose x is in 0..8, decreasing the x position of the start of
the text will make it go left.
❎ Modify the screensaver task so that it gets called every
60ms. You need a precise timing if you want the scrolling to be
pleasant.
❎ Modify the screensaver task such that, when it wants to display something:
- A
Textobject is built with a text such as "Hello 4SE02", and placed at anxposition whose value is kept in aoffsetlocal variable. You can use the color you want, or make the color cycle. - The text is drawn into an image coming from the pool, and displayed through
NEXT_IMAGE. - Decrease the
offsetlocal variable, except if the end of the text has reached the0xcoordinate, in which caseoffsetmust be reset to display the text again (find the appropriate value so that it is nice for the eyes). Note: theTextobject has methods to check its bounding box (the smallest rectangle in which it fits).
❎ Modify the screensaver task so that if a new image has been
received on the serial port, the offset of the text is reset so that
next time the screensaver displays something it will start from the
beginning of the text.
Note: you might have to adapt your DrawingText trait implementation for
Image, for example if the text appears upside down.
Make it even prettier if you wish, commit, push.
🦀 Congratulations, you have reached the end of this lab! 🦀