George Sykes ELEC2645 project

Dependencies:   mbed

https://os.mbed.com/media/uploads/el18gs/pixil-frame-0.png

GHOST HUNTER

In a world of ghostly horrors there is much money to be made in underground ghost fighting rings. You've managed to get hold of a Ghostbuster, a special piece of equipment that allows you to catch, train and fight ghosts.

Instructions

Below you will find the instructions for the game. Please note that due to COVID-19 a large part of the game (fighting ghosts) could not be added as it would have required access to a second gamepad which i could not acquire.

Welcome screen

When first started you will be presented with a welcome screen

  • Pot 1 to adjust the contrast on the screen
  • Press A to continue.

Main menu

You have three options, catch ghosts (add ghosts to your inventory), inventory (sell ghosts) or settings(adjust the games settings).

  • Press X and B to move the selection up and down respectively
  • Press A to enter the selected submenu

Catch Ghost

Will now be presented with two challenges. In the first you need to find a ghost, in the second you catch it. Theses stages will start automatically.

Find ghost

Rotate the gamepad on its roll and pitch axis until all the LED's turn on. The ones on the left indicate roll and the right pitch.

  • Rotate the gamepad on it roll and pitch to light up the LED's

Catch ghost

Return the gamepad to a comfortable position and use the joystick to move the crosshairs onto the ghost sprite. When ready press the A button to catch the ghost. You will be told what kind of ghost you have captured and it will be added to your inventory.

  • Press A to catch the ghost
  • Move the joystick to move the crosshairs

Inventory

The inventory allows you to view your ghosts and sell them.

  • Use Pot 1 to scroll through the ghosts
  • Pot 2 to scroll up and down the details of the individual ghosts
  • Press X to prepare to sell a ghost and press again to confirm, if you don't press again the sale screen will disappear after 5 seconds
  • Press Start to return to the main menu

Settings

This menu allows you to adjust some of the settings of the game.

  • Press X to go up one option
  • Press B to go down one option
  • Press A to enter the selected submenu
  • Press Start to return to the main menu

Contrast

Set the contrast of the LCD screen, the contrast will adjust on this screen so you can see the effect (contrast is bounded between 0.4 and 0.6).

  • Pot 1 to increase or decrease the contrast
  • Press A to set the contrast

Button Delay

Set the minimum time between button presses; if this is too low the game will detect two button presses when there was only one, too high and the buttons will seem unresponsive. So as to ensure these issues do not occur while changing the setting button X temporarily operates on the new delay but none of the others will until A is pressed.

  • Pot 1 to increase or decrease the delay
  • Press X to test the new delay, this will toggle the small circle to be filled in or unfilled
  • Press A to save the setting
Committer:
el18gs
Date:
Tue May 26 13:37:32 2020 +0000
Revision:
17:3ebcf7bba112
Parent:
1:8d14be858ca0
Final Submission. I have read and agreed with Statement of Academic Integrity.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
el18gs 1:8d14be858ca0 1 #include "mbed.h"
el18gs 1:8d14be858ca0 2 #include "N5110.h"
el18gs 1:8d14be858ca0 3
el18gs 1:8d14be858ca0 4 // overloaded constructor includes power pin - LCD Vcc connected to GPIO pin
el18gs 1:8d14be858ca0 5 // this constructor works fine with LPC1768 - enough current sourced from GPIO
el18gs 1:8d14be858ca0 6 // to power LCD. Doesn't work well with K64F.
el18gs 1:8d14be858ca0 7 N5110::N5110(PinName const pwrPin,
el18gs 1:8d14be858ca0 8 PinName const scePin,
el18gs 1:8d14be858ca0 9 PinName const rstPin,
el18gs 1:8d14be858ca0 10 PinName const dcPin,
el18gs 1:8d14be858ca0 11 PinName const mosiPin,
el18gs 1:8d14be858ca0 12 PinName const sclkPin,
el18gs 1:8d14be858ca0 13 PinName const ledPin)
el18gs 1:8d14be858ca0 14 :
el18gs 1:8d14be858ca0 15 _spi(new SPI(mosiPin,NC,sclkPin)), // create new SPI instance and initialise
el18gs 1:8d14be858ca0 16 _led(new DigitalOut(ledPin)),
el18gs 1:8d14be858ca0 17 _pwr(new DigitalOut(pwrPin)),
el18gs 1:8d14be858ca0 18 _sce(new DigitalOut(scePin)),
el18gs 1:8d14be858ca0 19 _rst(new DigitalOut(rstPin)),
el18gs 1:8d14be858ca0 20 _dc(new DigitalOut(dcPin))
el18gs 1:8d14be858ca0 21 {}
el18gs 1:8d14be858ca0 22
el18gs 1:8d14be858ca0 23 // overloaded constructor does not include power pin - LCD Vcc must be tied to +3V3
el18gs 1:8d14be858ca0 24 // Best to use this with K64F as the GPIO hasn't sufficient output current to reliably
el18gs 1:8d14be858ca0 25 // drive the LCD.
el18gs 1:8d14be858ca0 26 N5110::N5110(PinName const scePin,
el18gs 1:8d14be858ca0 27 PinName const rstPin,
el18gs 1:8d14be858ca0 28 PinName const dcPin,
el18gs 1:8d14be858ca0 29 PinName const mosiPin,
el18gs 1:8d14be858ca0 30 PinName const sclkPin,
el18gs 1:8d14be858ca0 31 PinName const ledPin)
el18gs 1:8d14be858ca0 32 :
el18gs 1:8d14be858ca0 33 _spi(new SPI(mosiPin,NC,sclkPin)), // create new SPI instance and initialise
el18gs 1:8d14be858ca0 34 _led(new DigitalOut(ledPin)),
el18gs 1:8d14be858ca0 35 _pwr(NULL), // pwr not needed so null it to be safe
el18gs 1:8d14be858ca0 36 _sce(new DigitalOut(scePin)),
el18gs 1:8d14be858ca0 37 _rst(new DigitalOut(rstPin)),
el18gs 1:8d14be858ca0 38 _dc(new DigitalOut(dcPin))
el18gs 1:8d14be858ca0 39 {}
el18gs 1:8d14be858ca0 40 // Second overload contructor uses the New Gamepad (Rev 2.1) pin mappings
el18gs 1:8d14be858ca0 41 N5110::N5110()
el18gs 1:8d14be858ca0 42 :
el18gs 1:8d14be858ca0 43 _spi(new SPI(PTD2,NC,PTD1)), // create new SPI instance and initialise
el18gs 1:8d14be858ca0 44 _led(new DigitalOut(PTB23)),
el18gs 1:8d14be858ca0 45 _pwr(NULL), // pwr not needed so null it to be safe
el18gs 1:8d14be858ca0 46 _sce(new DigitalOut(PTB19)),
el18gs 1:8d14be858ca0 47 _rst(new DigitalOut(PTC1)),
el18gs 1:8d14be858ca0 48 _dc(new DigitalOut(PTB18))
el18gs 1:8d14be858ca0 49 {}
el18gs 1:8d14be858ca0 50
el18gs 1:8d14be858ca0 51 N5110::~N5110()
el18gs 1:8d14be858ca0 52 {
el18gs 1:8d14be858ca0 53 delete _spi;
el18gs 1:8d14be858ca0 54
el18gs 1:8d14be858ca0 55 if(_pwr) {
el18gs 1:8d14be858ca0 56 delete _pwr;
el18gs 1:8d14be858ca0 57 }
el18gs 1:8d14be858ca0 58
el18gs 1:8d14be858ca0 59 delete _led;
el18gs 1:8d14be858ca0 60 delete _sce;
el18gs 1:8d14be858ca0 61 delete _rst;
el18gs 1:8d14be858ca0 62 delete _dc;
el18gs 1:8d14be858ca0 63 }
el18gs 1:8d14be858ca0 64
el18gs 1:8d14be858ca0 65 // initialise function - powers up and sends the initialisation commands
el18gs 1:8d14be858ca0 66 void N5110::init()
el18gs 1:8d14be858ca0 67 {
el18gs 1:8d14be858ca0 68 turnOn(); // power up
el18gs 1:8d14be858ca0 69 reset(); // reset LCD - must be done within 100 ms
el18gs 1:8d14be858ca0 70 initSPI();
el18gs 1:8d14be858ca0 71
el18gs 1:8d14be858ca0 72 backLightOn();
el18gs 1:8d14be858ca0 73 setContrast(0.55); // this may need tuning (say 0.4 to 0.6)
el18gs 1:8d14be858ca0 74 setBias(3); // datasheet - 48:1 mux - don't mess with if you don't know what you're doing! (0 to 7)
el18gs 1:8d14be858ca0 75 setTempCoefficient(0); // datasheet - may need increasing (range 0 to 3) at very low temperatures
el18gs 1:8d14be858ca0 76 normalMode(); // normal video mode by default
el18gs 1:8d14be858ca0 77
el18gs 1:8d14be858ca0 78 clearRAM(); // RAM is undefined at power-up so clear to be sure
el18gs 1:8d14be858ca0 79 clear(); // clear buffer
el18gs 1:8d14be858ca0 80 }
el18gs 1:8d14be858ca0 81
el18gs 1:8d14be858ca0 82 // sets normal video mode (black on white)
el18gs 1:8d14be858ca0 83 void N5110::normalMode()
el18gs 1:8d14be858ca0 84 {
el18gs 1:8d14be858ca0 85 sendCommand(0b00100000); // basic instruction
el18gs 1:8d14be858ca0 86 sendCommand(0b00001100); // normal video mode- datasheet
el18gs 1:8d14be858ca0 87 }
el18gs 1:8d14be858ca0 88
el18gs 1:8d14be858ca0 89 // sets normal video mode (white on black)
el18gs 1:8d14be858ca0 90 void N5110::inverseMode()
el18gs 1:8d14be858ca0 91 {
el18gs 1:8d14be858ca0 92 sendCommand(0b00100000); // basic instruction
el18gs 1:8d14be858ca0 93 sendCommand(0b00001101); // inverse video mode - datasheet
el18gs 1:8d14be858ca0 94 }
el18gs 1:8d14be858ca0 95
el18gs 1:8d14be858ca0 96 // function to power up the LCD and backlight - only works when using GPIO to power
el18gs 1:8d14be858ca0 97 void N5110::turnOn()
el18gs 1:8d14be858ca0 98 {
el18gs 1:8d14be858ca0 99 if (_pwr != NULL) {
el18gs 1:8d14be858ca0 100 _pwr->write(1); // apply power
el18gs 1:8d14be858ca0 101 }
el18gs 1:8d14be858ca0 102 }
el18gs 1:8d14be858ca0 103
el18gs 1:8d14be858ca0 104 // function to power down LCD
el18gs 1:8d14be858ca0 105 void N5110::turnOff()
el18gs 1:8d14be858ca0 106 {
el18gs 1:8d14be858ca0 107 clear(); // clear buffer
el18gs 1:8d14be858ca0 108 refresh();
el18gs 1:8d14be858ca0 109 backLightOff(); // turn backlight off
el18gs 1:8d14be858ca0 110 clearRAM(); // clear RAM to ensure specified current consumption
el18gs 1:8d14be858ca0 111 // send command to ensure we are in basic mode
el18gs 1:8d14be858ca0 112
el18gs 1:8d14be858ca0 113 sendCommand(0b00100000); // basic mode
el18gs 1:8d14be858ca0 114 sendCommand(0b00001000); // clear display
el18gs 1:8d14be858ca0 115 sendCommand(0b00100001); // extended mode
el18gs 1:8d14be858ca0 116 sendCommand(0b00100100); // power down
el18gs 1:8d14be858ca0 117
el18gs 1:8d14be858ca0 118 // if we are powering the LCD using the GPIO then make it low to turn off
el18gs 1:8d14be858ca0 119 if (_pwr != NULL) {
el18gs 1:8d14be858ca0 120 wait_ms(10); // small delay and then turn off the power pin
el18gs 1:8d14be858ca0 121 _pwr->write(0); // turn off power
el18gs 1:8d14be858ca0 122 }
el18gs 1:8d14be858ca0 123
el18gs 1:8d14be858ca0 124 }
el18gs 1:8d14be858ca0 125
el18gs 1:8d14be858ca0 126 // function to change LED backlight brightness
el18gs 1:8d14be858ca0 127 void N5110::backLightOn()
el18gs 1:8d14be858ca0 128 {
el18gs 1:8d14be858ca0 129 _led->write(1);
el18gs 1:8d14be858ca0 130 }
el18gs 1:8d14be858ca0 131
el18gs 1:8d14be858ca0 132 // function to change LED backlight brightness
el18gs 1:8d14be858ca0 133 void N5110::backLightOff()
el18gs 1:8d14be858ca0 134 {
el18gs 1:8d14be858ca0 135 _led->write(0);
el18gs 1:8d14be858ca0 136 }
el18gs 1:8d14be858ca0 137
el18gs 1:8d14be858ca0 138 void N5110::setContrast(float contrast) {
el18gs 1:8d14be858ca0 139
el18gs 1:8d14be858ca0 140 // enforce limits
el18gs 1:8d14be858ca0 141 if (contrast > 1.0f)
el18gs 1:8d14be858ca0 142 contrast = 1.0f;
el18gs 1:8d14be858ca0 143 else if (contrast < 0.0f)
el18gs 1:8d14be858ca0 144 contrast = 0.0;
el18gs 1:8d14be858ca0 145
el18gs 1:8d14be858ca0 146 // convert to char in range 0 to 127 (i.e. 6 bits)
el18gs 1:8d14be858ca0 147 char ic = char(contrast*127.0f);
el18gs 1:8d14be858ca0 148
el18gs 1:8d14be858ca0 149 sendCommand(0b00100001); // extended instruction set
el18gs 1:8d14be858ca0 150 sendCommand(0b10000000 | ic); // set Vop (which controls contrast)
el18gs 1:8d14be858ca0 151 sendCommand(0b00100000); // back to basic instruction set
el18gs 1:8d14be858ca0 152 }
el18gs 1:8d14be858ca0 153
el18gs 1:8d14be858ca0 154 void N5110::setTempCoefficient(char tc) {
el18gs 1:8d14be858ca0 155
el18gs 1:8d14be858ca0 156 // enforce limits
el18gs 1:8d14be858ca0 157 if (tc>3) {
el18gs 1:8d14be858ca0 158 tc=3;
el18gs 1:8d14be858ca0 159 }
el18gs 1:8d14be858ca0 160
el18gs 1:8d14be858ca0 161 // temperature coefficient may need increasing at low temperatures
el18gs 1:8d14be858ca0 162
el18gs 1:8d14be858ca0 163 sendCommand(0b00100001); // extended instruction set
el18gs 1:8d14be858ca0 164 sendCommand(0b00000100 | tc);
el18gs 1:8d14be858ca0 165 sendCommand(0b00100000); // back to basic instruction set
el18gs 1:8d14be858ca0 166 }
el18gs 1:8d14be858ca0 167
el18gs 1:8d14be858ca0 168 void N5110::setBias(char bias) {
el18gs 1:8d14be858ca0 169
el18gs 1:8d14be858ca0 170 // from data sheet
el18gs 1:8d14be858ca0 171 // bias mux rate
el18gs 1:8d14be858ca0 172 // 0 1:100
el18gs 1:8d14be858ca0 173 // 1 1:80
el18gs 1:8d14be858ca0 174 // 2 1:65
el18gs 1:8d14be858ca0 175 // 3 1:48 (default)
el18gs 1:8d14be858ca0 176 // 4 1:40/1:34
el18gs 1:8d14be858ca0 177 // 5 1:24
el18gs 1:8d14be858ca0 178 // 6 1:18/1:16
el18gs 1:8d14be858ca0 179 // 7 1:10/1:9/1:8
el18gs 1:8d14be858ca0 180
el18gs 1:8d14be858ca0 181 // enforce limits
el18gs 1:8d14be858ca0 182 if (bias>7) {
el18gs 1:8d14be858ca0 183 bias=7;
el18gs 1:8d14be858ca0 184 }
el18gs 1:8d14be858ca0 185
el18gs 1:8d14be858ca0 186 sendCommand(0b00100001); // extended mode instruction
el18gs 1:8d14be858ca0 187 sendCommand(0b00010000 | bias);
el18gs 1:8d14be858ca0 188 sendCommand(0b00100000); // end of extended mode instruction
el18gs 1:8d14be858ca0 189 }
el18gs 1:8d14be858ca0 190
el18gs 1:8d14be858ca0 191 // pulse the active low reset line
el18gs 1:8d14be858ca0 192 void N5110::reset()
el18gs 1:8d14be858ca0 193 {
el18gs 1:8d14be858ca0 194 _rst->write(0); // reset the LCD
el18gs 1:8d14be858ca0 195 _rst->write(1);
el18gs 1:8d14be858ca0 196 }
el18gs 1:8d14be858ca0 197
el18gs 1:8d14be858ca0 198 // function to initialise SPI peripheral
el18gs 1:8d14be858ca0 199 void N5110::initSPI()
el18gs 1:8d14be858ca0 200 {
el18gs 1:8d14be858ca0 201 _spi->format(8,1); // 8 bits, Mode 1 - polarity 0, phase 1 - base value of clock is 0, data captured on falling edge/propagated on rising edge
el18gs 1:8d14be858ca0 202 _spi->frequency(4000000); // maximum of screen is 4 MHz
el18gs 1:8d14be858ca0 203 }
el18gs 1:8d14be858ca0 204
el18gs 1:8d14be858ca0 205 // send a command to the display
el18gs 1:8d14be858ca0 206 void N5110::sendCommand(unsigned char command)
el18gs 1:8d14be858ca0 207 {
el18gs 1:8d14be858ca0 208 _dc->write(0); // set DC low for command
el18gs 1:8d14be858ca0 209 _sce->write(0); // set CE low to begin frame
el18gs 1:8d14be858ca0 210 _spi->write(command); // send command
el18gs 1:8d14be858ca0 211 _dc->write(1); // turn back to data by default
el18gs 1:8d14be858ca0 212 _sce->write(1); // set CE high to end frame (expected for transmission of single byte)
el18gs 1:8d14be858ca0 213 }
el18gs 1:8d14be858ca0 214
el18gs 1:8d14be858ca0 215 // send data to the display at the current XY address
el18gs 1:8d14be858ca0 216 // dc is set to 1 (i.e. data) after sending a command and so should
el18gs 1:8d14be858ca0 217 // be the default mode.
el18gs 1:8d14be858ca0 218 void N5110::sendData(unsigned char data)
el18gs 1:8d14be858ca0 219 {
el18gs 1:8d14be858ca0 220 _sce->write(0); // set CE low to begin frame
el18gs 1:8d14be858ca0 221 _spi->write(data);
el18gs 1:8d14be858ca0 222 _sce->write(1); // set CE high to end frame (expected for transmission of single byte)
el18gs 1:8d14be858ca0 223 }
el18gs 1:8d14be858ca0 224
el18gs 1:8d14be858ca0 225 // this function writes 0 to the 504 bytes to clear the RAM
el18gs 1:8d14be858ca0 226 void N5110::clearRAM()
el18gs 1:8d14be858ca0 227 {
el18gs 1:8d14be858ca0 228 _sce->write(0); //set CE low to begin frame
el18gs 1:8d14be858ca0 229 for(int i = 0; i < WIDTH * HEIGHT; i++) { // 48 x 84 bits = 504 bytes
el18gs 1:8d14be858ca0 230 _spi->write(0x00); // send 0's
el18gs 1:8d14be858ca0 231 }
el18gs 1:8d14be858ca0 232 _sce->write(1); // set CE high to end frame
el18gs 1:8d14be858ca0 233 }
el18gs 1:8d14be858ca0 234
el18gs 1:8d14be858ca0 235 // function to set the XY address in RAM for subsequenct data write
el18gs 1:8d14be858ca0 236 void N5110::setXYAddress(unsigned int const x,
el18gs 1:8d14be858ca0 237 unsigned int const y)
el18gs 1:8d14be858ca0 238 {
el18gs 1:8d14be858ca0 239 if (x<WIDTH && y<HEIGHT) { // check within range
el18gs 1:8d14be858ca0 240 sendCommand(0b00100000); // basic instruction
el18gs 1:8d14be858ca0 241 sendCommand(0b10000000 | x); // send addresses to display with relevant mask
el18gs 1:8d14be858ca0 242 sendCommand(0b01000000 | y);
el18gs 1:8d14be858ca0 243 }
el18gs 1:8d14be858ca0 244 }
el18gs 1:8d14be858ca0 245
el18gs 1:8d14be858ca0 246 // These functions are used to set, clear and get the value of pixels in the display
el18gs 1:8d14be858ca0 247 // Pixels are addressed in the range of 0 to 47 (y) and 0 to 83 (x). The refresh()
el18gs 1:8d14be858ca0 248 // function must be called after set and clear in order to update the display
el18gs 1:8d14be858ca0 249 void N5110::setPixel(unsigned int const x,
el18gs 1:8d14be858ca0 250 unsigned int const y,
el18gs 1:8d14be858ca0 251 bool const state)
el18gs 1:8d14be858ca0 252 {
el18gs 1:8d14be858ca0 253 if (x<WIDTH && y<HEIGHT) { // check within range
el18gs 1:8d14be858ca0 254 // calculate bank and shift 1 to required position in the data byte
el18gs 1:8d14be858ca0 255 if(state) buffer[x][y/8] |= (1 << y%8);
el18gs 1:8d14be858ca0 256 else buffer[x][y/8] &= ~(1 << y%8);
el18gs 1:8d14be858ca0 257 }
el18gs 1:8d14be858ca0 258 }
el18gs 1:8d14be858ca0 259
el18gs 1:8d14be858ca0 260 void N5110::clearPixel(unsigned int const x,
el18gs 1:8d14be858ca0 261 unsigned int const y)
el18gs 1:8d14be858ca0 262 {
el18gs 1:8d14be858ca0 263 if (x<WIDTH && y<HEIGHT) { // check within range
el18gs 1:8d14be858ca0 264 // calculate bank and shift 1 to required position (using bit clear)
el18gs 1:8d14be858ca0 265 buffer[x][y/8] &= ~(1 << y%8);
el18gs 1:8d14be858ca0 266 }
el18gs 1:8d14be858ca0 267 }
el18gs 1:8d14be858ca0 268
el18gs 1:8d14be858ca0 269 int N5110::getPixel(unsigned int const x,
el18gs 1:8d14be858ca0 270 unsigned int const y) const
el18gs 1:8d14be858ca0 271 {
el18gs 1:8d14be858ca0 272 if (x<WIDTH && y<HEIGHT) { // check within range
el18gs 1:8d14be858ca0 273 // return relevant bank and mask required bit
el18gs 1:8d14be858ca0 274
el18gs 1:8d14be858ca0 275 int pixel = (int) buffer[x][y/8] & (1 << y%8);
el18gs 1:8d14be858ca0 276
el18gs 1:8d14be858ca0 277 if (pixel)
el18gs 1:8d14be858ca0 278 return 1;
el18gs 1:8d14be858ca0 279 else
el18gs 1:8d14be858ca0 280 return 0;
el18gs 1:8d14be858ca0 281 }
el18gs 1:8d14be858ca0 282
el18gs 1:8d14be858ca0 283 return 0;
el18gs 1:8d14be858ca0 284
el18gs 1:8d14be858ca0 285 }
el18gs 1:8d14be858ca0 286
el18gs 1:8d14be858ca0 287 // function to refresh the display
el18gs 1:8d14be858ca0 288 void N5110::refresh()
el18gs 1:8d14be858ca0 289 {
el18gs 1:8d14be858ca0 290 setXYAddress(0,0); // important to set address back to 0,0 before refreshing display
el18gs 1:8d14be858ca0 291 // address auto increments after printing string, so buffer[0][0] will not coincide
el18gs 1:8d14be858ca0 292 // with top-left pixel after priting string
el18gs 1:8d14be858ca0 293
el18gs 1:8d14be858ca0 294 _sce->write(0); //set CE low to begin frame
el18gs 1:8d14be858ca0 295
el18gs 1:8d14be858ca0 296 for(int j = 0; j < BANKS; j++) { // be careful to use correct order (j,i) for horizontal addressing
el18gs 1:8d14be858ca0 297 for(int i = 0; i < WIDTH; i++) {
el18gs 1:8d14be858ca0 298 _spi->write(buffer[i][j]); // send buffer
el18gs 1:8d14be858ca0 299 }
el18gs 1:8d14be858ca0 300 }
el18gs 1:8d14be858ca0 301 _sce->write(1); // set CE high to end frame
el18gs 1:8d14be858ca0 302
el18gs 1:8d14be858ca0 303 }
el18gs 1:8d14be858ca0 304
el18gs 1:8d14be858ca0 305 // fills the buffer with random bytes. Can be used to test the display.
el18gs 1:8d14be858ca0 306 // The rand() function isn't seeded so it probably creates the same pattern everytime
el18gs 1:8d14be858ca0 307 void N5110::randomiseBuffer()
el18gs 1:8d14be858ca0 308 {
el18gs 1:8d14be858ca0 309 int i,j;
el18gs 1:8d14be858ca0 310 for(j = 0; j < BANKS; j++) { // be careful to use correct order (j,i) for horizontal addressing
el18gs 1:8d14be858ca0 311 for(i = 0; i < WIDTH; i++) {
el18gs 1:8d14be858ca0 312 buffer[i][j] = rand()%256; // generate random byte
el18gs 1:8d14be858ca0 313 }
el18gs 1:8d14be858ca0 314 }
el18gs 1:8d14be858ca0 315
el18gs 1:8d14be858ca0 316 }
el18gs 1:8d14be858ca0 317
el18gs 1:8d14be858ca0 318 // function to print 5x7 font
el18gs 1:8d14be858ca0 319 void N5110::printChar(char const c,
el18gs 1:8d14be858ca0 320 unsigned int const x,
el18gs 1:8d14be858ca0 321 unsigned int const y)
el18gs 1:8d14be858ca0 322 {
el18gs 1:8d14be858ca0 323 if (y<BANKS) { // check if printing in range of y banks
el18gs 1:8d14be858ca0 324
el18gs 1:8d14be858ca0 325 for (int i = 0; i < 5 ; i++ ) {
el18gs 1:8d14be858ca0 326 int pixel_x = x+i;
el18gs 1:8d14be858ca0 327 if (pixel_x > WIDTH-1) // ensure pixel isn't outside the buffer size (0 - 83)
el18gs 1:8d14be858ca0 328 break;
el18gs 1:8d14be858ca0 329 buffer[pixel_x][y] = font5x7[(c - 32)*5 + i];
el18gs 1:8d14be858ca0 330 // array is offset by 32 relative to ASCII, each character is 5 pixels wide
el18gs 1:8d14be858ca0 331 }
el18gs 1:8d14be858ca0 332
el18gs 1:8d14be858ca0 333 }
el18gs 1:8d14be858ca0 334 }
el18gs 1:8d14be858ca0 335
el18gs 1:8d14be858ca0 336 // function to print string at specified position
el18gs 1:8d14be858ca0 337 void N5110::printString(const char *str,
el18gs 1:8d14be858ca0 338 unsigned int const x,
el18gs 1:8d14be858ca0 339 unsigned int const y)
el18gs 1:8d14be858ca0 340 {
el18gs 1:8d14be858ca0 341 if (y<BANKS) { // check if printing in range of y banks
el18gs 1:8d14be858ca0 342
el18gs 1:8d14be858ca0 343 int n = 0 ; // counter for number of characters in string
el18gs 1:8d14be858ca0 344 // loop through string and print character
el18gs 1:8d14be858ca0 345 while(*str) {
el18gs 1:8d14be858ca0 346
el18gs 1:8d14be858ca0 347 // writes the character bitmap data to the buffer, so that
el18gs 1:8d14be858ca0 348 // text and pixels can be displayed at the same time
el18gs 1:8d14be858ca0 349 for (int i = 0; i < 5 ; i++ ) {
el18gs 1:8d14be858ca0 350 int pixel_x = x+i+n*6;
el18gs 1:8d14be858ca0 351 if (pixel_x > WIDTH-1) // ensure pixel isn't outside the buffer size (0 - 83)
el18gs 1:8d14be858ca0 352 break;
el18gs 1:8d14be858ca0 353 buffer[pixel_x][y] = font5x7[(*str - 32)*5 + i];
el18gs 1:8d14be858ca0 354 }
el18gs 1:8d14be858ca0 355 str++; // go to next character in string
el18gs 1:8d14be858ca0 356 n++; // increment index
el18gs 1:8d14be858ca0 357 }
el18gs 1:8d14be858ca0 358 }
el18gs 1:8d14be858ca0 359 }
el18gs 1:8d14be858ca0 360
el18gs 1:8d14be858ca0 361 // function to clear the screen buffer
el18gs 1:8d14be858ca0 362 void N5110::clear()
el18gs 1:8d14be858ca0 363 {
el18gs 1:8d14be858ca0 364 memset(buffer,0,sizeof(buffer));
el18gs 1:8d14be858ca0 365 }
el18gs 1:8d14be858ca0 366
el18gs 1:8d14be858ca0 367 // function to plot array on display
el18gs 1:8d14be858ca0 368 void N5110::plotArray(float const array[])
el18gs 1:8d14be858ca0 369 {
el18gs 1:8d14be858ca0 370 for (int i=0; i<WIDTH; i++) { // loop through array
el18gs 1:8d14be858ca0 371 // elements are normalised from 0.0 to 1.0, so multiply
el18gs 1:8d14be858ca0 372 // by 47 to convert to pixel range, and subtract from 47
el18gs 1:8d14be858ca0 373 // since top-left is 0,0 in the display geometry
el18gs 1:8d14be858ca0 374 setPixel(i,47 - int(array[i]*47.0f),true);
el18gs 1:8d14be858ca0 375 }
el18gs 1:8d14be858ca0 376
el18gs 1:8d14be858ca0 377 }
el18gs 1:8d14be858ca0 378
el18gs 1:8d14be858ca0 379 // function to draw circle
el18gs 1:8d14be858ca0 380 void N5110:: drawCircle(unsigned int const x0,
el18gs 1:8d14be858ca0 381 unsigned int const y0,
el18gs 1:8d14be858ca0 382 unsigned int const radius,
el18gs 1:8d14be858ca0 383 FillType const fill)
el18gs 1:8d14be858ca0 384 {
el18gs 1:8d14be858ca0 385 // from http://en.wikipedia.org/wiki/Midpoint_circle_algorithm
el18gs 1:8d14be858ca0 386 int x = radius;
el18gs 1:8d14be858ca0 387 int y = 0;
el18gs 1:8d14be858ca0 388 int radiusError = 1-x;
el18gs 1:8d14be858ca0 389
el18gs 1:8d14be858ca0 390 while(x >= y) {
el18gs 1:8d14be858ca0 391
el18gs 1:8d14be858ca0 392 // if transparent, just draw outline
el18gs 1:8d14be858ca0 393 if (fill == FILL_TRANSPARENT) {
el18gs 1:8d14be858ca0 394 setPixel( x + x0, y + y0,true);
el18gs 1:8d14be858ca0 395 setPixel(-x + x0, y + y0,true);
el18gs 1:8d14be858ca0 396 setPixel( y + x0, x + y0,true);
el18gs 1:8d14be858ca0 397 setPixel(-y + x0, x + y0,true);
el18gs 1:8d14be858ca0 398 setPixel(-y + x0, -x + y0,true);
el18gs 1:8d14be858ca0 399 setPixel( y + x0, -x + y0,true);
el18gs 1:8d14be858ca0 400 setPixel( x + x0, -y + y0,true);
el18gs 1:8d14be858ca0 401 setPixel(-x + x0, -y + y0,true);
el18gs 1:8d14be858ca0 402 } else { // drawing filled circle, so draw lines between points at same y value
el18gs 1:8d14be858ca0 403
el18gs 1:8d14be858ca0 404 int type = (fill==FILL_BLACK) ? 1:0; // black or white fill
el18gs 1:8d14be858ca0 405
el18gs 1:8d14be858ca0 406 drawLine(x+x0,y+y0,-x+x0,y+y0,type);
el18gs 1:8d14be858ca0 407 drawLine(y+x0,x+y0,-y+x0,x+y0,type);
el18gs 1:8d14be858ca0 408 drawLine(y+x0,-x+y0,-y+x0,-x+y0,type);
el18gs 1:8d14be858ca0 409 drawLine(x+x0,-y+y0,-x+x0,-y+y0,type);
el18gs 1:8d14be858ca0 410 }
el18gs 1:8d14be858ca0 411
el18gs 1:8d14be858ca0 412 y++;
el18gs 1:8d14be858ca0 413 if (radiusError<0) {
el18gs 1:8d14be858ca0 414 radiusError += 2 * y + 1;
el18gs 1:8d14be858ca0 415 } else {
el18gs 1:8d14be858ca0 416 x--;
el18gs 1:8d14be858ca0 417 radiusError += 2 * (y - x) + 1;
el18gs 1:8d14be858ca0 418 }
el18gs 1:8d14be858ca0 419 }
el18gs 1:8d14be858ca0 420
el18gs 1:8d14be858ca0 421 }
el18gs 1:8d14be858ca0 422
el18gs 1:8d14be858ca0 423 void N5110::drawLine(unsigned int const x0,
el18gs 1:8d14be858ca0 424 unsigned int const y0,
el18gs 1:8d14be858ca0 425 unsigned int const x1,
el18gs 1:8d14be858ca0 426 unsigned int const y1,
el18gs 1:8d14be858ca0 427 unsigned int const type)
el18gs 1:8d14be858ca0 428 {
el18gs 1:8d14be858ca0 429 // Note that the ranges can be negative so we have to turn the input values
el18gs 1:8d14be858ca0 430 // into signed integers first
el18gs 1:8d14be858ca0 431 int const y_range = static_cast<int>(y1) - static_cast<int>(y0);
el18gs 1:8d14be858ca0 432 int const x_range = static_cast<int>(x1) - static_cast<int>(x0);
el18gs 1:8d14be858ca0 433
el18gs 1:8d14be858ca0 434 // if dotted line, set step to 2, else step is 1
el18gs 1:8d14be858ca0 435 unsigned int const step = (type==2) ? 2:1;
el18gs 1:8d14be858ca0 436
el18gs 1:8d14be858ca0 437 // make sure we loop over the largest range to get the most pixels on the display
el18gs 1:8d14be858ca0 438 // for instance, if drawing a vertical line (x_range = 0), we need to loop down the y pixels
el18gs 1:8d14be858ca0 439 // or else we'll only end up with 1 pixel in the x column
el18gs 1:8d14be858ca0 440 if ( abs(x_range) > abs(y_range) ) {
el18gs 1:8d14be858ca0 441
el18gs 1:8d14be858ca0 442 // ensure we loop from smallest to largest or else for-loop won't run as expected
el18gs 1:8d14be858ca0 443 unsigned int const start = x_range > 0 ? x0:x1;
el18gs 1:8d14be858ca0 444 unsigned int const stop = x_range > 0 ? x1:x0;
el18gs 1:8d14be858ca0 445
el18gs 1:8d14be858ca0 446 // loop between x pixels
el18gs 1:8d14be858ca0 447 for (unsigned int x = start; x<= stop ; x+=step) {
el18gs 1:8d14be858ca0 448 // do linear interpolation
el18gs 1:8d14be858ca0 449 int const dx = static_cast<int>(x)-static_cast<int>(x0);
el18gs 1:8d14be858ca0 450 unsigned int const y = y0 + y_range * dx / x_range;
el18gs 1:8d14be858ca0 451
el18gs 1:8d14be858ca0 452 // If the line type is '0', this will clear the pixel
el18gs 1:8d14be858ca0 453 // If it is '1' or '2', the pixel will be set
el18gs 1:8d14be858ca0 454 setPixel(x,y, type);
el18gs 1:8d14be858ca0 455 }
el18gs 1:8d14be858ca0 456 } else {
el18gs 1:8d14be858ca0 457
el18gs 1:8d14be858ca0 458 // ensure we loop from smallest to largest or else for-loop won't run as expected
el18gs 1:8d14be858ca0 459 unsigned int const start = y_range > 0 ? y0:y1;
el18gs 1:8d14be858ca0 460 unsigned int const stop = y_range > 0 ? y1:y0;
el18gs 1:8d14be858ca0 461
el18gs 1:8d14be858ca0 462 for (unsigned int y = start; y<= stop ; y+=step) {
el18gs 1:8d14be858ca0 463 // do linear interpolation
el18gs 1:8d14be858ca0 464 int const dy = static_cast<int>(y)-static_cast<int>(y0);
el18gs 1:8d14be858ca0 465 unsigned int const x = x0 + x_range * dy / y_range;
el18gs 1:8d14be858ca0 466
el18gs 1:8d14be858ca0 467 // If the line type is '0', this will clear the pixel
el18gs 1:8d14be858ca0 468 // If it is '1' or '2', the pixel will be set
el18gs 1:8d14be858ca0 469 setPixel(x,y, type);
el18gs 1:8d14be858ca0 470 }
el18gs 1:8d14be858ca0 471 }
el18gs 1:8d14be858ca0 472
el18gs 1:8d14be858ca0 473 }
el18gs 1:8d14be858ca0 474
el18gs 1:8d14be858ca0 475 void N5110::drawRect(unsigned int const x0,
el18gs 1:8d14be858ca0 476 unsigned int const y0,
el18gs 1:8d14be858ca0 477 unsigned int const width,
el18gs 1:8d14be858ca0 478 unsigned int const height,
el18gs 1:8d14be858ca0 479 FillType const fill)
el18gs 1:8d14be858ca0 480 {
el18gs 1:8d14be858ca0 481 if (fill == FILL_TRANSPARENT) { // transparent, just outline
el18gs 1:8d14be858ca0 482 drawLine(x0,y0,x0+(width-1),y0,1); // top
el18gs 1:8d14be858ca0 483 drawLine(x0,y0+(height-1),x0+(width-1),y0+(height-1),1); // bottom
el18gs 1:8d14be858ca0 484 drawLine(x0,y0,x0,y0+(height-1),1); // left
el18gs 1:8d14be858ca0 485 drawLine(x0+(width-1),y0,x0+(width-1),y0+(height-1),1); // right
el18gs 1:8d14be858ca0 486 } else { // filled rectangle
el18gs 1:8d14be858ca0 487 int type = (fill==FILL_BLACK) ? 1:0; // black or white fill
el18gs 1:8d14be858ca0 488 for (int y = y0; y<y0+height; y++) { // loop through rows of rectangle
el18gs 1:8d14be858ca0 489 drawLine(x0,y,x0+(width-1),y,type); // draw line across screen
el18gs 1:8d14be858ca0 490 }
el18gs 1:8d14be858ca0 491 }
el18gs 1:8d14be858ca0 492 }
el18gs 1:8d14be858ca0 493
el18gs 1:8d14be858ca0 494 void N5110::drawSprite(int x0,
el18gs 1:8d14be858ca0 495 int y0,
el18gs 1:8d14be858ca0 496 int nrows,
el18gs 1:8d14be858ca0 497 int ncols,
el18gs 1:8d14be858ca0 498 int *sprite)
el18gs 1:8d14be858ca0 499 {
el18gs 1:8d14be858ca0 500 for (int i = 0; i < nrows; i++) {
el18gs 1:8d14be858ca0 501 for (int j = 0 ; j < ncols ; j++) {
el18gs 1:8d14be858ca0 502
el18gs 1:8d14be858ca0 503 int pixel = *((sprite+i*ncols)+j);
el18gs 1:8d14be858ca0 504 setPixel(x0+j,y0+i, pixel);
el18gs 1:8d14be858ca0 505 }
el18gs 1:8d14be858ca0 506 }
el18gs 1:8d14be858ca0 507 }