Code:
#include <IRremote.h>
#include <MemoryFree.h>
#include <IrCommons.h>
#include <Enums.h>
#include <Commons.h>
#include <RadioBlock.h>
#include <EEPROM.h>
#include <IrCommands.h>
#include <RfCommons.h>
#include <mac.h>
#include <Weapon.h>
#include <Adafruit_GFX.h> // Core graphics library
#include <Teensy3_ST7735.h>
#include <SPI.h>
#define NEW_LINE_SIZE 13
#define COLUMN_SIZE 88
#define DEBUG
#define DEBUG_FINE
byte brightness = 0;
Commons commons;
Teensy3_ST7735 tft(14, 20, 7);
RadioBlockSerialInterface radioBlock(5,4,3,2);
Weapon weapon(radioBlock, commons);
RfCommons rfCommons(radioBlock);
IrCommons irCommons;
int message[20];
void setup(void) {
Serial.begin(9600);
weapon.init();
irCommons.init();
tft.initR(INITR_REDTAB); // initialize a ST7735R chip, red tab
tft.fillScreen(ST7735_BLACK);
tft.setTextWrap(false);
tft.setRotation(3);
tft.setTextSize(1);
tft.setCursor(0, 0);
tft.setTextColor(ST7735_WHITE);
drawHealth();
drawHeat();
drawHits();
drawKills();
drawAccuracy();
drawSpawns();
drawRange();
drawTeam();
drawBattle();
drawObject();
drawStatus();
drawTime();
}
void loop() {
irCommons.listen(weapon);
rfCommons.listen(weapon);
weapon.doWork();
if (weapon.shooting) {
message[COMMAND_POSITION] = HIT_TAKEN;
message[VALUE_POSITION] = weapon.damage;
message[TEAM_POSITION] = weapon.team;
message[PLAYERID_POSITION] = 0;
message[BATTLEGROUP_POSITION] = weapon.battleGroup;
irCommons.executeCommand(message, 5);
}
updateHealth();
updateHeat();
updateTeam();
updateStatus();
updateTime();
}
void drawStatus() {
tft.setCursor(0, 5 * NEW_LINE_SIZE);
tft.print("Status");
tft.print(":");
tft.println(weapon.getStatusDescription());
}
byte previousStatus = weapon.status;
void updateStatus() {
if (previousStatus != weapon.status) {
previousStatus = weapon.status;
tft.fillRect(42, 5 * NEW_LINE_SIZE, 36, 7, ST7735_BLACK);
//tft.drawRect(42, 5 * NEW_LINE_SIZE, 36, 7, ST7735_WHITE);
tft.setCursor(42, 5 * NEW_LINE_SIZE);
tft.print(weapon.getStatusDescription());
}
}
void testStatus() {
weapon.status = PLAYER_ALIVE;
updateStatus();
// delay(500);
weapon.status = PLAYER_DEAD;
updateStatus();
// delay(500);
weapon.status = GAME_OVER;
updateStatus();
// delay(500);
weapon.status = PLAYER_PAUSED;
updateStatus();
// delay(500);
}
void drawTime() {
tft.setCursor(COLUMN_SIZE, 5 * NEW_LINE_SIZE);
tft.print("00:15:00");
}
byte previousHours = weapon.getHours();
byte previousMinutes = weapon.getMinutes();
byte previousSeconds = weapon.getSeconds();
void updateTime() {
//hours
if (previousHours != weapon.getHours()) {
previousHours = weapon.getHours();
//tft.fillRect(42, 5 * NEW_LINE_SIZE, 36, 7, ST7735_BLACK);
//tft.drawRect(COLUMN_SIZE, 5 * NEW_LINE_SIZE, 12, 7, ST7735_WHITE);
tft.fillRect(COLUMN_SIZE, 5 * NEW_LINE_SIZE, 12, 7, ST7735_BLACK);
tft.setCursor(COLUMN_SIZE, 5 * NEW_LINE_SIZE);
byte localHours = weapon.getHours();
if (localHours < 10) {
tft.print("0");
}
tft.print(localHours);
}
//minutes
if (previousMinutes != weapon.getMinutes()) {
previousMinutes = weapon.getMinutes();
//tft.drawRect(COLUMN_SIZE + 18, 5 * NEW_LINE_SIZE, 12, 7, ST7735_WHITE);
tft.fillRect(COLUMN_SIZE + 18, 5 * NEW_LINE_SIZE, 12, 7, ST7735_BLACK);
tft.setCursor(COLUMN_SIZE + 18, 5 * NEW_LINE_SIZE);
byte localMinutes = weapon.getMinutes();
if (localMinutes < 10) {
tft.print("0");
}
tft.print(localMinutes);
}
//seconds
if (previousSeconds != weapon.getSeconds()) {
previousSeconds = weapon.getSeconds();
//tft.drawRect(COLUMN_SIZE + 36, 5 * NEW_LINE_SIZE, 12, 7, ST7735_WHITE);
tft.fillRect(COLUMN_SIZE + 36, 5 * NEW_LINE_SIZE, 12, 7, ST7735_BLACK);
tft.setCursor(COLUMN_SIZE + 36, 5 * NEW_LINE_SIZE);
byte localSeconds = weapon.getSeconds();
if (localSeconds < 10) {
tft.print("0");
}
tft.print(localSeconds);
}
//tft.setCursor(42, 5 * NEW_LINE_SIZE);
//tft.print(weapon.getStatusDescription());
}
void testTime() {
updateTime();
}
void drawBattle() {
tft.setCursor(0, 4 * NEW_LINE_SIZE);
tft.print("Battle");
tft.print(":");
tft.print(weapon.battleGroup);
}
byte previousBattleGroup = weapon.battleGroup;
void updateBattle() {
if (previousBattleGroup != weapon.battleGroup) {
previousBattleGroup = weapon.battleGroup;
tft.fillRect(42, 4 * NEW_LINE_SIZE, 18, 7, ST7735_BLACK);
//tft.drawRect(42, 4 * NEW_LINE_SIZE, 18, 7, ST7735_WHITE);
tft.setCursor(42, 4 * NEW_LINE_SIZE);
tft.print(weapon.battleGroup);
}
}
void testBattle() {
for (int i = 0; i < 256; i++) {
weapon.battleGroup = i;
updateBattle();
delay(10);
}
}
void drawObject() {
tft.setCursor(COLUMN_SIZE, 4 * NEW_LINE_SIZE);
tft.print("Object");
tft.print(":");
tft.print(weapon.getObjectives());
}
void updateObject() {
tft.fillRect(COLUMN_SIZE + 42, 4 * NEW_LINE_SIZE, 30, 7, ST7735_BLACK);
//tft.drawRect(COLUMN_SIZE + 42, 4 * NEW_LINE_SIZE, 30, 7, ST7735_WHITE);
tft.setCursor(COLUMN_SIZE + 42, 4 * NEW_LINE_SIZE);
tft.print(weapon.getObjectives());
}
void testObject() {
for (int i = 0; i < 65000; i++) {
weapon.objectives = i;
updateObject();
delay(10);
}
}
void drawRange() {
tft.setCursor(0, 3 * NEW_LINE_SIZE);
tft.print("Range");
tft.print(":");
tft.print(weapon.getRange());
}
void updateRange() {
tft.fillRect(36, 3 * NEW_LINE_SIZE, 36, 7, ST7735_BLACK);
//tft.drawRect(36, 3 * NEW_LINE_SIZE, 36, 7, ST7735_WHITE);
tft.setCursor(36, 3 * NEW_LINE_SIZE);
tft.print(weapon.getRange());
}
void testRange() {
weapon.range = SHORT_RANGE;
updateRange();
delay(500);
weapon.range = MEDIUM_RANGE;
updateRange();
delay(500);
weapon.range = LONG_RANGE;
updateRange();
delay(500);
}
void drawTeam() {
tft.setCursor(COLUMN_SIZE, 3 * NEW_LINE_SIZE);
tft.print("Team");
tft.print(":");
tft.println(weapon.getTeamDescription());
}
byte previousTeam = weapon.team;
void updateTeam() {
if (previousTeam != weapon.team) {
previousTeam = weapon.team;
tft.fillRect(COLUMN_SIZE + 30, 3 * NEW_LINE_SIZE, 36, 7, ST7735_BLACK);
//tft.drawRect(COLUMN_SIZE + 30, 3 * NEW_LINE_SIZE, 36, 7, ST7735_WHITE);
tft.setCursor(COLUMN_SIZE + 30, 3 * NEW_LINE_SIZE);
tft.print(weapon.getTeamDescription());
}
}
void testTeam() {
weapon.team = TEAM_RED;
updateTeam();
delay(500);
weapon.team = TEAM_BLUE;
updateTeam();
delay(500);
weapon.team = TEAM_GREEN;
updateTeam();
delay(500);
weapon.team = TEAM_PURPLE;
updateTeam();
delay(500);
weapon.team = TEAM_ORANGE;
updateTeam();
delay(500);
weapon.team = TEAM_YELLOW;
updateTeam();
delay(500);
weapon.team = TEAM_FREE_FOR_ALL;
updateTeam();
delay(500);
weapon.team = NONE;
updateTeam();
delay(500);
}
void drawAccuracy() {
tft.setCursor(0, 2 * NEW_LINE_SIZE);
tft.print("Accuracy");
tft.print(":");
tft.print(weapon.getAccuracy());
tft.print("%");
}
void updateAccuracy() {
tft.fillRect(54, 2 * NEW_LINE_SIZE, 17, 7, ST7735_BLACK);
//tft.drawRect(54, 2 * NEW_LINE_SIZE, 17, 7, ST7735_WHITE);
if (weapon.getAccuracy() < 10) {
tft.setCursor(66, 2 * NEW_LINE_SIZE);
} else if (weapon.getAccuracy() < 100) {
tft.setCursor(60, 2 * NEW_LINE_SIZE);
} else {
tft.setCursor(54, 2 * NEW_LINE_SIZE);
}
tft.print(weapon.getAccuracy());
}
void testAccuracy() {
for (int i = 0; i < 500; i++) {
weapon.accuracy = i;
updateAccuracy();
delay(10);
}
}
void drawSpawns() {
tft.setCursor(COLUMN_SIZE, 2 * NEW_LINE_SIZE);
tft.print("Spawns");
tft.print(":");
tft.print(weapon.getSpawns());
}
void updateSpawns() {
tft.fillRect(COLUMN_SIZE + 42, 2 * NEW_LINE_SIZE, 30, 7, ST7735_BLACK);
//tft.drawRect(COLUMN_SIZE + 42, 2 * NEW_LINE_SIZE, 30, 7, ST7735_WHITE);
tft.setCursor(COLUMN_SIZE + 42, 2 * NEW_LINE_SIZE);
tft.print(weapon.spawns);
}
void testSpawns() {
for (int i = 0; i < 500; i++) {
weapon.spawns = i;
updateSpawns();
delay(15);
}
}
void drawHits() {
tft.setCursor(0, 1 * NEW_LINE_SIZE);
tft.print("Hits");
tft.print(":");
tft.print(weapon.getHits());
}
void updateHits() {
tft.fillRect(30, 1 * NEW_LINE_SIZE, 30, 7, ST7735_BLACK);
//tft.drawRect(30, 1 * NEW_LINE_SIZE, 30, 7, ST7735_WHITE);
tft.setCursor(30, 1 * NEW_LINE_SIZE);
tft.print(weapon.hits);
}
void drawKills() {
tft.setCursor(COLUMN_SIZE, 1 * NEW_LINE_SIZE);
tft.print("Kills");
tft.print(":");
tft.println(weapon.getKills());
}
void updateKills() {
tft.fillRect(COLUMN_SIZE + 36, 1 * NEW_LINE_SIZE, 30, 7, ST7735_BLACK);
//tft.drawRect(COLUMN_SIZE + 36, 1 * NEW_LINE_SIZE, 30, 7, ST7735_WHITE);
tft.setCursor(COLUMN_SIZE + 36, 1 * NEW_LINE_SIZE);
tft.print(weapon.getKills());
}
void testKills() {
for (int i = 0; i < 500; i++) {
weapon.kills = i;
updateKills();
delay(5);
}
}
void drawHealth() {
tft.setCursor(0, 0);
tft.setTextColor(ST7735_WHITE);
tft.print("HP");
tft.print(":");
tft.print(weapon.getHealth());
tft.print("/");
tft.print(weapon.getMaxHealth());
tft.println("");
}
byte previousHealth = weapon.health;
void updateHealth() {
if (previousHealth != weapon.health){
previousHealth = weapon.health;
tft.fillRect(18, 0, 5, 8, ST7735_BLACK);
if (weapon.health < 10) {
tft.setCursor(18, 0);
} else if (weapon.health < 100) {
tft.setCursor(24, 0);
} else {
tft.setCursor(18, 0);
}
tft.print(weapon.health);
}
}
void updateMaxHealth() {
tft.fillRect(42, 0, 17, 8, ST7735_BLACK);
//tft.drawRect(COLUMN_SIZE + 46, 0, 17, 8, ST7735_WHITE);
tft.setCursor(42, 0);
tft.print(weapon.maxHealth);
}
//HEAT
void drawHeat() {
tft.setCursor(COLUMN_SIZE, 0);
tft.print("Heat");
tft.print(": ");
tft.print(weapon.getAmmo());
tft.print("/");
tft.println(weapon.getMaxAmmo());
}
byte previousHeat = weapon.ammo;
void updateHeat() {
if (previousHeat != weapon.ammo) {
previousHeat = weapon.ammo;
if (weapon.ammo < 10) {
tft.fillRect(COLUMN_SIZE + 30, 0, 12, 8, ST7735_BLACK);
tft.setCursor(COLUMN_SIZE + 36, 0);
} else if (weapon.ammo < 100) {
tft.fillRect(COLUMN_SIZE + 30, 0, 12, 8, ST7735_BLACK);
tft.setCursor(COLUMN_SIZE + 30, 0);
} else {
tft.setCursor(COLUMN_SIZE + 30, 0);
}
tft.print(weapon.ammo);
}
}
void testHeat() {
for (int i = 0; i < 500; i++) {
weapon.ammo = i;
updateHeat();
delay(100);
}
}
//MAX HEAT
void updateMaxHeat() {
tft.fillRect(COLUMN_SIZE + 54, 0, 17, 8, ST7735_BLACK);
//tft.drawRect(COLUMN_SIZE + 54, 0, 17, 8, ST7735_WHITE);
tft.setCursor(COLUMN_SIZE + 54, 0);
tft.print(weapon.maxAmmo);
}
void testMaxHeat() {
for (int i = 0; i < 120; i++) {
weapon.maxAmmo = i;
updateMaxHeat();
delay(100);
}
}
void updateAssistedKills() {
tft.fillRect(47, 32, 25, 7, ST7735_BLACK);
//tft.drawRect(47, 32, 25, 7, ST7735_WHITE);
tft.setCursor(47, 32);
tft.print(weapon.assistedKills);
}
void testHealth() {
for (int i = 0; i < 101; i++) {
weapon.health = i;
updateHealth();
delay(10);
}
}
void testMaxHealth() {
for (int i = 0; i < 101; i++) {
weapon.maxHealth = i;
updateMaxHealth();
delay(10);
}
}
void testHits() {
for (int i = 0; i < 65000; i++) {
weapon.hits = i;
updateHits();
delay(10);
}
}
Code:
/***************************************************
This is an example sketch for the Adafruit 1.8" SPI display.
This library works with the Adafruit 1.8" TFT Breakout w/SD card
----> http://www.adafruit.com/products/358
as well as Adafruit raw 1.8" TFT display
----> http://www.adafruit.com/products/618
Check out the links above for our tutorials and wiring diagrams
These displays use SPI to communicate, 4 or 5 pins are required to
interface (RST is optional)
Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!
Written by Limor Fried/Ladyada for Adafruit Industries.
MIT license, all text above must be included in any redistribution
****************************************************/
#include <Teensy3_ST7735.h>
#include <SPI.h>
#include <SD.h>
// TFT display and SD card will share the hardware SPI interface.
// Hardware SPI pins are specific to the Arduino board type and
// cannot be remapped to alternate pins. For Arduino Uno,
// Duemilanove, etc., pin 11 = MOSI, pin 12 = MISO, pin 13 = SCK.
#define SD_CS 4 // Chip select line for SD card
#define TFT_CS 10 // Chip select line for TFT display
#define TFT_DC 9 // Data/command line for TFT
#define TFT_RST 8 // Reset line for TFT (or connect to +5V)
//Adafruit_ST7735 tft = Adafruit_ST7735(14, 20, 7);
Teensy3_ST7735 tft(14, 20, 7);
void setup(void) {
Serial.begin(9600);
// Our supplier changed the 1.8" display slightly after Jan 10, 2012
// so that the alignment of the TFT had to be shifted by a few pixels
// this just means the init code is slightly different. Check the
// color of the tab to see which init code to try. If the display is
// cut off or has extra 'random' pixels on the top & left, try the
// other option!
// If you are seeing red and green color inversion, use Black Tab
// If your TFT's plastic wrap has a Black Tab, use the following:
tft.initR(INITR_REDTAB); // initialize a ST7735S chip, black tab
// If your TFT's plastic wrap has a Red Tab, use the following:
//tft.initR(INITR_REDTAB); // initialize a ST7735R chip, red tab
// If your TFT's plastic wrap has a Green Tab, use the following:
//tft.initR(INITR_GREENTAB); // initialize a ST7735R chip, green tab
}
void loop() {
delay(10000);
Serial.print("Initializing SD card...");
if (!SD.begin(19)) {
Serial.println("failed!");
return;
}
Serial.println("OK!");
bmpDraw("parrot.bmp", 0, 0);
}
// This function opens a Windows Bitmap (BMP) file and
// displays it at the given coordinates. It's sped up
// by reading many pixels worth of data at a time
// (rather than pixel by pixel). Increasing the buffer
// size takes more of the Arduino's precious RAM but
// makes loading a little faster. 20 pixels seems a
// good balance.
#define BUFFPIXEL 20
void bmpDraw(char *filename, uint8_t x, uint8_t y) {
File bmpFile;
int bmpWidth, bmpHeight; // W+H in pixels
uint8_t bmpDepth; // Bit depth (currently must be 24)
uint32_t bmpImageoffset; // Start of image data in file
uint32_t rowSize; // Not always = bmpWidth; may have padding
uint8_t sdbuffer[3*BUFFPIXEL]; // pixel buffer (R+G+B per pixel)
uint8_t buffidx = sizeof(sdbuffer); // Current position in sdbuffer
boolean goodBmp = false; // Set to true on valid header parse
boolean flip = true; // BMP is stored bottom-to-top
int w, h, row, col;
uint8_t r, g, b;
uint32_t pos = 0, startTime = millis();
if((x >= tft.width()) || (y >= tft.height())) return;
Serial.println();
Serial.print("Loading image '");
Serial.print(filename);
Serial.println('\'');
// Open requested file on SD card
if ((bmpFile = SD.open(filename)) == NULL) {
Serial.print("File not found");
return;
}
// Parse BMP header
if(read16(bmpFile) == 0x4D42) { // BMP signature
Serial.print("File size: "); Serial.println(read32(bmpFile));
(void)read32(bmpFile); // Read & ignore creator bytes
bmpImageoffset = read32(bmpFile); // Start of image data
Serial.print("Image Offset: "); Serial.println(bmpImageoffset, DEC);
// Read DIB header
Serial.print("Header size: "); Serial.println(read32(bmpFile));
bmpWidth = read32(bmpFile);
bmpHeight = read32(bmpFile);
if(read16(bmpFile) == 1) { // # planes -- must be '1'
bmpDepth = read16(bmpFile); // bits per pixel
Serial.print("Bit Depth: "); Serial.println(bmpDepth);
if((bmpDepth == 24) && (read32(bmpFile) == 0)) { // 0 = uncompressed
goodBmp = true; // Supported BMP format -- proceed!
Serial.print("Image size: ");
Serial.print(bmpWidth);
Serial.print('x');
Serial.println(bmpHeight);
// BMP rows are padded (if needed) to 4-byte boundary
rowSize = (bmpWidth * 3 + 3) & ~3;
// If bmpHeight is negative, image is in top-down order.
// This is not canon but has been observed in the wild.
if(bmpHeight < 0) {
bmpHeight = -bmpHeight;
flip = false;
}
// Crop area to be loaded
w = bmpWidth;
h = bmpHeight;
if((x+w-1) >= tft.width()) w = tft.width() - x;
if((y+h-1) >= tft.height()) h = tft.height() - y;
// Set TFT address window to clipped image bounds
tft.setAddrWindow(x, y, x+w-1, y+h-1);
for (row=0; row<h; row++) { // For each scanline...
// Seek to start of scan line. It might seem labor-
// intensive to be doing this on every line, but this
// method covers a lot of gritty details like cropping
// and scanline padding. Also, the seek only takes
// place if the file position actually needs to change
// (avoids a lot of cluster math in SD library).
if(flip) // Bitmap is stored bottom-to-top order (normal BMP)
pos = bmpImageoffset + (bmpHeight - 1 - row) * rowSize;
else // Bitmap is stored top-to-bottom
pos = bmpImageoffset + row * rowSize;
if(bmpFile.position() != pos) { // Need seek?
bmpFile.seek(pos);
buffidx = sizeof(sdbuffer); // Force buffer reload
}
for (col=0; col<w; col++) { // For each pixel...
// Time to read more pixel data?
if (buffidx >= sizeof(sdbuffer)) { // Indeed
bmpFile.read(sdbuffer, sizeof(sdbuffer));
buffidx = 0; // Set index to beginning
}
// Convert pixel from BMP to TFT format, push to display
b = sdbuffer[buffidx++];
g = sdbuffer[buffidx++];
r = sdbuffer[buffidx++];
tft.pushColor(tft.Color565(r,g,b));
} // end pixel
} // end scanline
Serial.print("Loaded in ");
Serial.print(millis() - startTime);
Serial.println(" ms");
} // end goodBmp
}
}
bmpFile.close();
if(!goodBmp) Serial.println("BMP format not recognized.");
}
// These read 16- and 32-bit types from the SD card file.
// BMP data is stored little-endian, Arduino is little-endian too.
// May need to reverse subscript order if porting elsewhere.
uint16_t read16(File f) {
uint16_t result;
((uint8_t *)&result)[0] = f.read(); // LSB
((uint8_t *)&result)[1] = f.read(); // MSB
return result;
}
uint32_t read32(File f) {
uint32_t result;
((uint8_t *)&result)[0] = f.read(); // LSB
((uint8_t *)&result)[1] = f.read();
((uint8_t *)&result)[2] = f.read();
((uint8_t *)&result)[3] = f.read(); // MSB
return result;
}