Skip to content

Electronics

Input Device

For my final project the critical component I would need for Spiral 1 is a current sensor. Why? My project will involve the usage of Fuel Cells to convert Hydrogen into a power supply for energy consumption. So I decided to do a little bit of research about current sensor.

Current sensor as the name suggests - measure electric current. There are different ways to measure current and there are different types of current sensors catered to read AC or DC. As such there is a wide variety of current sensing modules out there. This is a summary of the different sensors based on my research

Type Current Transformer Shunt Hall Effect Rogowski Coil
Current AC AC & DC AC & DC AC
How does it work? Converts high current to a lower current by dividing it. The stepped-down/ divided output is sent to ammeters and other instruments for monitoring purposes, as well as to relays and other systems for protection applications in power systems. Detect voltage drop across a precisely calibrated shunt resistor. A shunt resistor is designed with low-resistance resistor to measure electrical current by generating a small, proportional voltage drop. This ensures that the impact on the original circuit is minimal, and the measurement is accurate. Generation of a voltage difference when a current-carrying conductor is placed in a magnetic field. These sensors operate without physical contact, making them ideal where galvanic isolation between the current source and their output is crucial. Rogowski coil measures the rate of change of the magnetic field around a conductor to determine the alternating current. They do not apply to DC applications.
Accuracy High High Medium Low
Range High Low because it requires direct contact Medium Medium
Isolation Yes No Yes Yes
Cost Moderate to High Low to Moderate Moderate Moderate
Application Metering & Billing, Energy Management Systems, etc Ammeters, Battery Management systems, Power supplies etc General-purpose current sensing High-frequency AC current measurement, power quality analysis.

Sources:

Based on the research I think for my first spiral - the most appropriate would be the Shunt sensor. Fuel Cells operate in DC and I would like to an accurate reading as the Fuel Cell supplies power to be used - converted from the Hydrogen Gas.

Current Sensor INA219

The INA219 is a current shunt and power monitor with an I2C- or SMBUS-compatible interface. It monitors:

  • Shunt voltage drop (voltage drop measured across a low-resistance shunt resistor, used to calculate the current flowing through a circuit.)
  • Bus supply voltage (electrical potential difference between the conductors or “buses” in an electrical power distribution system, serving as a common voltage level for multiple circuits and components to connect and operate.)
  • Direct readouts of current in amperes.
  • An additional multiplying register calculates power in watts.

Because it comes in I2C interface(SDA/SCL) straightforward to connect and communicate with microcontrollers. It can handle high side current measuring, up to +26VDC, even though it is powered with 3 or 5V and enables bi-directional current measurements of up to 3.2Amp.

Here is the data sheet

In general this is how the sensor works alt text

Programming

Original Code from here Appropriated for ILI9341 and Xiao ESP32S3 Display

For this program - we will be measuring an LED Diode with a power supply from Elaine-duino. This is the system diagram. alt text As you can see for Vin+ and Vin-, there should be a closed connection for us to fully measure the voltage, current, and power of the load. In the case with this LED Diode, 3V from the Elaine-duino is supplying power to the LED Diode and it closes with Ground Pin.

The complete system diagram with the ILI9341 display looks like this. alt text

#include <Wire.h>
#include <Adafruit_INA219.h>
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_ILI9341.h>

Adafruit_INA219 ina219;

// Define pins for the ILI9341 display
#define TFT_RST A0
#define TFT_DC  A1
#define TFT_CS  D7  // SS
#define TFT_MOSI D10  // MOSI
#define TFT_MISO D9
#define TFT_CLK D8  // SCK
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST);

float current_mA = 0;
float loadvoltage = 0;
float power_mW = 0;

void setup(void) {
  Serial.begin(115200);
  while (!Serial) {
    // will pause Zero, Leonardo, etc until serial console opens
    delay(1);
  }
  uint32_t currentFrequency;

  if (!ina219.begin()) {
    Serial.println("Failed to find INA219 chip");
    while (1) {
      delay(10);
    }
  }

  tft.begin();
  tft.setRotation(3); // Adjust based on your display orientation
  tft.fillScreen(ILI9341_BLACK);

  Serial.println("Measuring voltage and current with INA219 ...");
}

void loop(void) {
  float shuntvoltage = 0;
  float busvoltage = 0;
  current_mA = 0;
  loadvoltage = 0;
  power_mW = 0;

  shuntvoltage = ina219.getShuntVoltage_mV();
  busvoltage = ina219.getBusVoltage_V();
  current_mA = ina219.getCurrent_mA();
  power_mW = ina219.getPower_mW();
  loadvoltage = busvoltage + (shuntvoltage / 1000);

  Serial.print("Load Voltage:  "); Serial.print(loadvoltage); Serial.println(" V");
  Serial.print("Current:       "); Serial.print(current_mA); Serial.println(" mA");
  Serial.print("Power:         "); Serial.print(power_mW); Serial.println(" mW");
  Serial.println("");

  tft.fillScreen(ILI9341_BLACK);
  voltCurrent();
  delay(2000);
  tft.fillScreen(ILI9341_BLACK);
  powerr();
  delay(2000);
}

void voltCurrent() {
  tft.setTextSize(2); // Draw 2X-scale text
  tft.setTextColor(ILI9341_WHITE);
  tft.setCursor(0, 0);            // Start at top-left corner
  tft.print(loadvoltage);
  tft.print("V");
  tft.setCursor(0, 40);            // Adjust cursor position based on text size
  tft.print(current_mA);
  tft.print("mA");
}

void powerr() {
  tft.setTextSize(2); // Draw 2X-scale text
  tft.setTextColor(ILI9341_WHITE);
  tft.setCursor(0, 60);            // Adjust cursor position based on text size
  tft.print(power_mW);
  tft.print("mW");
}

Takeaways

  • As we can see the voltage reading is consistent at around ~3.24V
  • The current reading comes out in a negative value of -34.20 mA. This actually signifies the current direction. A positive value indicates current flowing from the INA219’s Vin+ to Vin-, while a negative value indicates the opposite - current flowing from Vin- to Vin+. However since we have a load in between Vin+ and Vin- (LED), the current will have a negative sign as it flows from the power source (Vin+) to the load (Vin-).
  • The Blue LED Diode consumes 112 mW of Power.

Output Device

My final project requires to use Display as an output - I explored 3 displays which were

  • OLED LCD Display SSD1306, an I2C Display
  • TFT ILI9225, SPI Display
  • TFT ILI9341, SPI Display

128x64 OLED Display SSD1306

OLED Display is made of self-illuminating pixels that emit light when current is passes through. It has no backlight and has superior contrast ratios and true blacks (pixels can completely turn off).

This particular inexpensive OLED Display is easily available and easy to use for starters. It has many Arduino library support. Moreover, it requires less pins to be used compared to other displays due to I2C connection (SDA/SCL). It is compatible with many display libraries - but the most widely used one is the Adafruit GFX Library, the ‘core’ class that all other graphics libraries derive from.

I used the standardised Wokwi animation programming to test out this SSD1306 display is working.

As you can see this code displays a simple eye animation. To get your image displayed you need to convert it intp Bitmap.Use image2cpp tool to convert any images to Bitmap. For more information how to use image2cpp, check out this tutorial

When you convert your image to bitmap code - the image data is stored in a PROGMEM array. PROGMEM is a keyword used to store data in the microcontroller’s program memory (flash memory) instead of RAM. This is because image data, especially for animations, can can quickly fill up the limited RAM space in MCUs. By storing the bitmap code in PROGMEM you keep your RAM available for more function while still having access to the image data.

The animation data can be understood through

  • FRAME_DELAY: This variable defines the delay between animation frames in milliseconds (42ms).
  • FRAME_WIDTH, FRAME_HEIGHT:: This variable defines the width and height of each animation frame (64p x 64p)
  • FRAME_COUNT: This variable defines the total number of frames in the animation (calculated from the size of the frames array).

Wokwi Simulation

Testing out with Elaine’s Devlopment Board (using Xiao ESP32S3) - System Diagram alt text

#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

// Define OLED
#define SCREEN_I2C_ADDR 0x3C // or 0x3C
#define SCREEN_WIDTH 128     // OLED display width, in pixels
#define SCREEN_HEIGHT 64     // OLED display height, in pixels
#define OLED_RST_PIN -1      // Reset pin (-1 if not available)

Adafruit_SSD1306 display(128, 64, &Wire, OLED_RST_PIN);


// OLED Animation: eye
// Code auto-generated by https://wokwi.com/animator, graphics by icons8.com

#define FRAME_DELAY (42)
#define FRAME_WIDTH (64)
#define FRAME_HEIGHT (64)
#define FRAME_COUNT (sizeof(frames) / sizeof(frames[0]))
const byte PROGMEM frames[][512] = {
  {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,248,0,0,0,0,0,1,255,255,128,0,0,0,0,15,255,255,240,0,0,0,0,63,248,31,252,0,0,0,0,255,0,0,255,0,0,0,3,252,0,0,63,192,0,0,7,248,0,0,31,224,0,0,31,184,7,224,29,248,0,0,62,112,15,240,14,124,0,0,124,112,31,248,14,62,0,1,240,96,63,252,6,15,128,3,224,96,63,252,6,7,192,7,192,96,63,252,6,3,224,15,0,96,63,252,6,0,240,30,0,96,63,252,6,0,120,60,0,96,63,252,6,0,60,120,0,112,31,248,14,0,30,120,0,112,31,248,14,0,30,60,0,48,7,224,12,0,60,30,0,56,0,0,28,0,120,15,0,28,0,0,56,0,240,7,128,28,0,0,56,1,224,3,192,14,0,0,112,3,192,0,240,7,0,0,224,15,0,0,120,3,192,3,192,30,0,0,62,1,248,31,128,124,0,0,15,0,255,255,0,240,0,0,7,192,63,252,3,224,0,0,1,240,0,0,15,128,0,0,0,126,0,0,126,0,0,0,0,31,192,3,248,0,0,0,0,7,255,255,224,0,0,0,0,0,255,255,0,0,0,0,0,0,7,224,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
  {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,248,0,0,0,0,0,1,255,255,128,0,0,0,0,15,255,255,240,0,0,0,0,63,248,31,252,0,0,0,0,255,0,0,255,0,0,0,3,252,0,0,63,192,0,0,7,248,0,0,31,224,0,0,31,184,7,224,29,248,0,0,62,112,15,240,14,124,0,0,124,112,31,248,14,62,0,1,240,96,63,252,6,15,128,3,224,96,63,252,6,7,192,7,192,96,63,252,6,3,224,15,0,96,63,252,6,0,240,30,0,96,63,252,6,0,120,60,0,96,63,252,6,0,60,120,0,112,31,248,14,0,30,120,0,112,31,248,14,0,30,60,0,48,7,224,12,0,60,30,0,56,0,0,28,0,120,15,0,28,0,0,56,0,240,7,128,28,0,0,56,1,224,3,192,14,0,0,112,3,192,0,240,7,0,0,224,15,0,0,120,3,192,3,192,30,0,0,62,1,248,31,128,124,0,0,15,0,255,255,0,240,0,0,7,192,63,252,3,224,0,0,1,240,0,0,15,128,0,0,0,126,0,0,126,0,0,0,0,31,192,3,248,0,0,0,0,7,255,255,224,0,0,0,0,0,255,255,0,0,0,0,0,0,7,224,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
  {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,248,0,0,0,0,0,1,255,255,128,0,0,0,0,15,255,255,240,0,0,0,0,63,248,31,252,0,0,0,0,255,0,0,255,0,0,0,3,252,0,0,63,192,0,0,7,248,0,0,31,224,0,0,31,184,7,224,29,248,0,0,62,112,15,240,14,124,0,0,124,112,31,248,14,62,0,1,240,96,63,252,6,15,128,3,224,96,63,252,6,7,192,7,192,96,63,252,6,3,224,15,0,96,63,252,6,0,240,30,0,96,63,252,6,0,120,60,0,96,63,252,6,0,60,120,0,112,31,248,14,0,30,120,0,112,31,248,14,0,30,60,0,48,7,224,12,0,60,30,0,56,0,0,28,0,120,15,0,28,0,0,56,0,240,7,128,28,0,0,56,1,224,3,192,14,0,0,112,3,192,0,240,7,0,0,224,15,0,0,120,3,192,3,192,30,0,0,62,1,248,31,128,124,0,0,15,0,255,255,0,240,0,0,7,192,63,252,3,224,0,0,1,240,0,0,15,128,0,0,0,126,0,0,126,0,0,0,0,31,192,3,248,0,0,0,0,7,255,255,224,0,0,0,0,0,255,255,0,0,0,0,0,0,7,224,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
  {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,248,0,0,0,0,0,1,255,255,128,0,0,0,0,15,255,255,240,0,0,0,0,63,248,31,252,0,0,0,0,255,0,0,255,0,0,0,3,252,0,0,63,192,0,0,7,248,0,0,31,224,0,0,31,184,7,224,29,248,0,0,62,112,15,240,14,124,0,0,124,112,31,248,14,62,0,1,240,96,63,252,6,15,128,3,224,96,63,252,6,7,192,7,192,96,63,252,6,3,224,15,0,96,63,252,6,0,240,30,0,96,63,252,6,0,120,60,0,96,63,252,6,0,60,120,0,112,31,248,14,0,30,120,0,112,31,248,14,0,30,60,0,48,7,224,12,0,60,30,0,56,0,0,28,0,120,15,0,28,0,0,56,0,240,7,128,28,0,0,56,1,224,3,192,14,0,0,112,3,192,0,240,7,0,0,224,15,0,0,120,3,192,3,192,30,0,0,62,1,248,31,128,124,0,0,15,0,255,255,0,240,0,0,7,192,63,252,3,224,0,0,1,240,0,0,15,128,0,0,0,126,0,0,126,0,0,0,0,31,192,3,248,0,0,0,0,7,255,255,224,0,0,0,0,0,255,255,0,0,0,0,0,0,7,224,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
  {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,248,0,0,0,0,0,1,255,255,128,0,0,0,0,15,255,255,240,0,0,0,0,63,255,255,252,0,0,0,0,255,255,255,255,0,0,0,3,255,252,63,255,192,0,0,7,254,0,0,127,224,0,0,31,248,7,224,31,248,0,0,63,240,15,240,15,252,0,0,127,112,31,248,14,254,0,1,252,96,63,252,6,63,128,3,240,96,63,252,6,15,192,7,192,96,63,252,6,7,224,15,128,96,63,252,6,1,240,30,0,96,63,252,6,0,248,60,0,96,63,252,6,0,60,120,0,112,31,248,14,0,30,120,0,112,31,248,14,0,30,60,0,48,7,224,12,0,60,30,0,56,0,0,28,0,120,15,0,28,0,0,56,0,240,7,128,28,0,0,56,1,224,3,192,14,0,0,112,3,192,0,240,7,0,0,224,15,0,0,120,3,192,3,192,30,0,0,62,1,248,31,128,124,0,0,15,0,255,255,0,240,0,0,7,192,63,252,3,224,0,0,1,240,0,0,15,128,0,0,0,126,0,0,126,0,0,0,0,31,192,3,248,0,0,0,0,7,255,255,224,0,0,0,0,0,255,255,0,0,0,0,0,0,7,224,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
  {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,248,0,0,0,0,0,1,255,255,128,0,0,0,0,15,255,255,240,0,0,0,0,63,248,31,252,0,0,0,0,255,0,0,255,0,0,0,3,248,0,0,31,192,0,0,7,224,0,0,7,224,0,0,31,128,0,0,1,248,0,0,62,0,0,0,0,124,0,0,124,3,255,255,192,62,0,1,240,255,255,255,255,15,128,3,231,255,255,255,255,231,192,7,255,240,63,252,15,255,224,15,254,96,63,252,6,127,240,31,240,96,63,252,6,15,248,63,128,96,63,252,6,1,252,124,0,112,31,248,14,0,62,120,0,112,31,248,14,0,30,60,0,48,7,224,12,0,60,30,0,56,0,0,28,0,120,15,0,28,0,0,56,0,240,7,128,28,0,0,56,1,224,3,192,14,0,0,112,3,192,0,240,7,0,0,224,15,0,0,120,3,192,3,192,30,0,0,62,1,248,31,128,124,0,0,15,0,255,255,0,240,0,0,7,192,63,252,3,224,0,0,1,240,0,0,15,128,0,0,0,126,0,0,126,0,0,0,0,31,192,3,248,0,0,0,0,7,255,255,224,0,0,0,0,0,255,255,0,0,0,0,0,0,7,224,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
  {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,248,0,0,0,0,0,1,255,255,128,0,0,0,0,15,255,255,240,0,0,0,0,63,248,31,252,0,0,0,0,255,0,0,255,0,0,0,3,248,0,0,31,192,0,0,7,224,0,0,7,224,0,0,31,128,0,0,1,248,0,0,62,0,0,0,0,124,0,0,124,0,0,0,0,62,0,1,240,0,0,0,0,15,128,3,224,0,0,0,0,7,192,7,128,0,0,0,0,1,224,15,0,0,0,0,0,0,240,30,0,0,0,0,0,0,120,60,0,0,0,0,0,0,60,127,255,255,255,255,255,255,254,127,255,255,255,255,255,255,254,60,0,120,15,240,30,0,60,30,0,56,0,0,28,0,120,15,0,28,0,0,56,0,240,7,128,28,0,0,56,1,224,3,192,14,0,0,112,3,192,0,240,7,0,0,224,15,0,0,120,3,192,3,192,30,0,0,62,1,248,31,128,124,0,0,15,0,255,255,0,240,0,0,7,192,63,252,3,224,0,0,1,240,0,0,15,128,0,0,0,126,0,0,126,0,0,0,0,31,192,3,248,0,0,0,0,7,255,255,224,0,0,0,0,0,255,255,0,0,0,0,0,0,7,224,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
  {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,248,0,0,0,0,0,1,255,255,128,0,0,0,0,15,255,255,240,0,0,0,0,63,248,31,252,0,0,0,0,255,0,0,255,0,0,0,3,248,0,0,31,192,0,0,7,224,0,0,7,224,0,0,31,128,0,0,1,248,0,0,62,0,0,0,0,124,0,0,124,0,0,0,0,62,0,1,240,0,0,0,0,15,128,3,224,0,0,0,0,7,192,7,128,0,0,0,0,1,224,15,0,0,0,0,0,0,240,30,0,0,0,0,0,0,120,60,0,0,0,0,0,0,60,120,0,0,0,0,0,0,30,124,0,0,0,0,0,0,62,63,128,0,0,0,0,1,252,31,240,0,0,0,0,15,248,15,254,0,0,0,0,127,240,7,255,224,0,0,7,255,224,3,207,255,0,0,255,243,192,0,241,255,255,255,255,143,0,0,120,15,255,255,240,30,0,0,62,1,255,255,128,124,0,0,15,0,255,255,0,240,0,0,7,192,63,252,3,224,0,0,1,240,0,0,15,128,0,0,0,126,0,0,126,0,0,0,0,31,192,3,248,0,0,0,0,7,255,255,224,0,0,0,0,0,255,255,0,0,0,0,0,0,7,224,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
  {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,248,0,0,0,0,0,1,255,255,128,0,0,0,0,15,255,255,240,0,0,0,0,63,248,31,252,0,0,0,0,255,0,0,255,0,0,0,3,248,0,0,31,192,0,0,7,224,0,0,7,224,0,0,31,128,0,0,1,248,0,0,62,0,0,0,0,124,0,0,124,0,0,0,0,62,0,1,240,0,0,0,0,15,128,3,224,0,0,0,0,7,192,7,128,0,0,0,0,1,224,15,0,0,0,0,0,0,240,30,0,0,0,0,0,0,120,60,0,0,0,0,0,0,60,120,0,0,0,0,0,0,30,120,0,0,0,0,0,0,30,60,0,0,0,0,0,0,60,31,0,0,0,0,0,0,248,15,128,0,0,0,0,1,240,7,192,0,0,0,0,3,224,3,240,0,0,0,0,15,192,0,252,0,0,0,0,63,0,0,127,0,0,0,0,254,0,0,63,192,0,0,3,252,0,0,15,240,0,0,15,240,0,0,7,254,0,0,127,224,0,0,1,255,224,7,255,128,0,0,0,127,255,255,254,0,0,0,0,31,255,255,248,0,0,0,0,7,255,255,224,0,0,0,0,0,255,255,0,0,0,0,0,0,7,224,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
  {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,248,0,0,0,0,0,1,255,255,128,0,0,0,0,15,255,255,240,0,0,0,0,63,248,31,252,0,0,0,0,255,0,0,255,0,0,0,3,248,0,0,31,192,0,0,7,224,0,0,7,224,0,0,31,128,0,0,1,248,0,0,62,0,0,0,0,124,0,0,124,0,0,0,0,62,0,1,240,0,0,0,0,15,128,3,224,0,0,0,0,7,192,7,128,0,0,0,0,1,224,15,0,0,0,0,0,0,240,30,0,0,0,0,0,0,120,60,0,0,0,0,0,0,60,120,0,0,0,0,0,0,30,120,0,0,0,0,0,0,30,60,0,0,0,0,0,0,60,30,0,0,0,0,0,0,120,15,0,0,0,0,0,0,240,7,128,0,0,0,0,1,224,3,224,0,0,0,0,7,192,1,240,0,0,0,0,15,128,0,248,0,0,0,0,31,0,0,254,0,0,0,0,127,0,0,31,128,0,0,1,248,0,0,7,224,0,0,7,224,0,0,3,248,0,0,31,192,0,0,0,255,0,0,255,0,0,0,0,127,224,7,252,0,0,0,0,127,255,255,252,0,0,0,0,1,255,255,136,0,0,0,0,0,31,248,0,0,0,0,0,0,1,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
  {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,248,0,0,0,0,0,1,255,255,128,0,0,0,0,15,255,255,240,0,0,0,0,63,248,31,252,0,0,0,0,255,0,0,255,0,0,0,3,248,0,0,31,192,0,0,7,224,0,0,7,224,0,0,31,128,0,0,1,248,0,0,62,0,0,0,0,124,0,0,124,0,0,0,0,62,0,1,240,0,0,0,0,15,128,3,224,0,0,0,0,7,192,7,128,0,0,0,0,1,224,15,0,0,0,0,0,0,240,30,0,0,0,0,0,0,120,60,0,0,0,0,0,0,60,120,0,0,0,0,0,0,30,120,0,0,0,0,0,0,30,60,0,0,0,0,0,0,60,30,0,0,0,0,0,0,120,15,0,0,0,0,0,0,240,7,128,0,0,0,0,1,224,3,224,0,0,0,0,7,192,1,240,0,0,0,0,15,128,0,248,0,0,0,0,31,0,1,254,0,0,0,0,127,128,3,223,128,0,0,1,251,192,3,135,224,0,0,7,225,192,0,3,248,0,0,31,192,0,0,0,255,0,0,255,0,0,0,0,127,224,7,252,0,0,0,0,127,255,255,252,0,0,0,0,97,255,255,156,0,0,0,0,224,31,248,12,0,0,0,0,224,1,128,12,0,0,0,0,0,1,128,0,0,0,0,0,0,1,128,0,0,0,0,0,0,1,128,0,0,0,0,0,0,1,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
  {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,248,0,0,0,0,0,1,255,255,128,0,0,0,0,15,255,255,240,0,0,0,0,63,248,31,252,0,0,0,0,255,0,0,255,0,0,0,3,248,0,0,31,192,0,0,7,224,0,0,7,224,0,0,31,128,0,0,1,248,0,0,62,0,0,0,0,124,0,0,124,0,0,0,0,62,0,1,240,0,0,0,0,15,128,3,224,0,0,0,0,7,192,7,128,0,0,0,0,1,224,15,0,0,0,0,0,0,240,30,0,0,0,0,0,0,120,60,0,0,0,0,0,0,60,120,0,0,0,0,0,0,30,120,0,0,0,0,0,0,30,60,0,0,0,0,0,0,60,30,0,0,0,0,0,0,120,15,0,0,0,0,0,0,240,7,128,0,0,0,0,1,224,3,224,0,0,0,0,7,192,1,240,0,0,0,0,15,128,0,248,0,0,0,0,31,0,1,254,0,0,0,0,127,128,3,159,128,0,0,1,249,192,7,135,224,0,0,7,225,224,7,3,248,0,0,31,192,224,14,0,255,0,0,255,0,112,12,0,127,224,7,252,0,48,0,0,127,255,255,252,0,0,0,0,97,255,255,156,0,0,0,0,224,31,248,12,0,0,0,0,224,1,128,14,0,0,0,0,224,1,128,14,0,0,0,0,192,1,128,14,0,0,0,1,192,1,128,6,0,0,0,0,128,1,128,6,0,0,0,0,0,1,128,0,0,0,0,0,0,1,128,0,0,0,0,0,0,1,128,0,0,0,0,0,0,1,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
  {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,248,0,0,0,0,0,1,255,255,128,0,0,0,0,15,255,255,240,0,0,0,0,63,248,31,252,0,0,0,0,255,0,0,255,0,0,0,3,248,0,0,31,192,0,0,7,224,0,0,7,224,0,0,31,128,0,0,1,248,0,0,62,0,0,0,0,124,0,0,124,0,0,0,0,62,0,1,240,0,0,0,0,15,128,3,224,0,0,0,0,7,192,7,128,0,0,0,0,1,224,15,0,0,0,0,0,0,240,30,0,0,0,0,0,0,120,60,0,0,0,0,0,0,60,120,0,0,0,0,0,0,30,120,0,0,0,0,0,0,30,60,0,0,0,0,0,0,60,30,0,0,0,0,0,0,120,15,0,0,0,0,0,0,240,7,128,0,0,0,0,1,224,3,224,0,0,0,0,7,192,1,240,0,0,0,0,15,128,0,248,0,0,0,0,31,0,1,254,0,0,0,0,127,128,3,159,128,0,0,1,249,192,7,135,224,0,0,7,225,224,7,3,248,0,0,31,192,224,14,0,255,0,0,255,0,112,12,0,127,224,7,252,0,48,0,0,127,255,255,252,0,0,0,0,97,255,255,156,0,0,0,0,224,31,248,12,0,0,0,0,224,1,128,14,0,0,0,0,224,1,128,14,0,0,0,0,192,1,128,14,0,0,0,1,192,1,128,6,0,0,0,0,128,1,128,6,0,0,0,0,0,1,128,0,0,0,0,0,0,1,128,0,0,0,0,0,0,1,128,0,0,0,0,0,0,1,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
  {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,248,0,0,0,0,0,1,255,255,128,0,0,0,0,15,255,255,240,0,0,0,0,63,248,31,252,0,0,0,0,255,0,0,255,0,0,0,3,248,0,0,31,192,0,0,7,224,0,0,7,224,0,0,31,128,0,0,1,248,0,0,62,0,0,0,0,124,0,0,124,0,0,0,0,62,0,1,240,0,0,0,0,15,128,3,224,0,0,0,0,7,192,7,128,0,0,0,0,1,224,15,0,0,0,0,0,0,240,30,0,0,0,0,0,0,120,60,0,0,0,0,0,0,60,120,0,0,0,0,0,0,30,120,0,0,0,0,0,0,30,60,0,0,0,0,0,0,60,30,0,0,0,0,0,0,120,15,0,0,0,0,0,0,240,7,128,0,0,0,0,1,224,3,224,0,0,0,0,7,192,1,240,0,0,0,0,15,128,0,248,0,0,0,0,31,0,1,254,0,0,0,0,127,128,3,159,128,0,0,1,249,192,7,135,224,0,0,7,225,224,7,3,248,0,0,31,192,224,14,0,255,0,0,255,0,112,12,0,127,224,7,252,0,48,0,0,127,255,255,252,0,0,0,0,97,255,255,156,0,0,0,0,224,31,248,12,0,0,0,0,224,1,128,14,0,0,0,0,224,1,128,14,0,0,0,0,192,1,128,14,0,0,0,1,192,1,128,6,0,0,0,0,128,1,128,6,0,0,0,0,0,1,128,0,0,0,0,0,0,1,128,0,0,0,0,0,0,1,128,0,0,0,0,0,0,1,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
  {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,248,0,0,0,0,0,1,255,255,128,0,0,0,0,15,255,255,240,0,0,0,0,63,248,31,252,0,0,0,0,255,0,0,255,0,0,0,3,248,0,0,31,192,0,0,7,224,0,0,7,224,0,0,31,128,0,0,1,248,0,0,62,0,0,0,0,124,0,0,124,0,0,0,0,62,0,1,240,0,0,0,0,15,128,3,224,0,0,0,0,7,192,7,128,0,0,0,0,1,224,15,0,0,0,0,0,0,240,30,0,0,0,0,0,0,120,60,0,0,0,0,0,0,60,120,0,0,0,0,0,0,30,120,0,0,0,0,0,0,30,60,0,0,0,0,0,0,60,30,0,0,0,0,0,0,120,15,0,0,0,0,0,0,240,7,128,0,0,0,0,1,224,3,224,0,0,0,0,7,192,1,240,0,0,0,0,15,128,0,248,0,0,0,0,31,0,1,254,0,0,0,0,127,128,3,159,128,0,0,1,249,192,7,135,224,0,0,7,225,224,7,3,248,0,0,31,192,224,14,0,255,0,0,255,0,112,12,0,127,224,7,252,0,48,0,0,127,255,255,252,0,0,0,0,97,255,255,156,0,0,0,0,224,31,248,12,0,0,0,0,224,1,128,14,0,0,0,0,224,1,128,14,0,0,0,0,192,1,128,14,0,0,0,1,192,1,128,6,0,0,0,0,128,1,128,6,0,0,0,0,0,1,128,0,0,0,0,0,0,1,128,0,0,0,0,0,0,1,128,0,0,0,0,0,0,1,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
  {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,248,0,0,0,0,0,1,255,255,128,0,0,0,0,15,255,255,240,0,0,0,0,63,248,31,252,0,0,0,0,255,0,0,255,0,0,0,3,248,0,0,31,192,0,0,7,224,0,0,7,224,0,0,31,128,0,0,1,248,0,0,62,0,0,0,0,124,0,0,124,0,0,0,0,62,0,1,240,0,0,0,0,15,128,3,224,0,0,0,0,7,192,7,128,0,0,0,0,1,224,15,0,0,0,0,0,0,240,30,0,0,0,0,0,0,120,60,0,0,0,0,0,0,60,120,0,0,0,0,0,0,30,120,0,0,0,0,0,0,30,60,0,0,0,0,0,0,60,30,0,0,0,0,0,0,120,15,0,0,0,0,0,0,240,7,128,0,0,0,0,1,224,3,224,0,0,0,0,7,192,1,240,0,0,0,0,15,128,0,248,0,0,0,0,31,0,1,254,0,0,0,0,127,128,3,159,128,0,0,1,249,192,7,135,224,0,0,7,225,224,7,3,248,0,0,31,192,224,14,0,255,0,0,255,0,112,12,0,127,224,7,252,0,48,0,0,127,255,255,252,0,0,0,0,97,255,255,156,0,0,0,0,224,31,248,12,0,0,0,0,224,1,128,14,0,0,0,0,224,1,128,14,0,0,0,0,192,1,128,14,0,0,0,1,192,1,128,6,0,0,0,0,128,1,128,6,0,0,0,0,0,1,128,0,0,0,0,0,0,1,128,0,0,0,0,0,0,1,128,0,0,0,0,0,0,1,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
  {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,248,0,0,0,0,0,1,255,255,128,0,0,0,0,15,255,255,240,0,0,0,0,63,248,31,252,0,0,0,0,255,0,0,255,0,0,0,3,248,0,0,31,192,0,0,7,224,0,0,7,224,0,0,31,128,0,0,1,248,0,0,62,0,0,0,0,124,0,0,124,0,0,0,0,62,0,1,240,0,0,0,0,15,128,3,224,0,0,0,0,7,192,7,128,0,0,0,0,1,224,15,0,0,0,0,0,0,240,30,0,0,0,0,0,0,120,60,0,0,0,0,0,0,60,120,0,0,0,0,0,0,30,120,0,0,0,0,0,0,30,60,0,0,0,0,0,0,60,30,0,0,0,0,0,0,120,15,0,0,0,0,0,0,240,7,128,0,0,0,0,1,224,3,224,0,0,0,0,7,192,1,240,0,0,0,0,15,128,0,248,0,0,0,0,31,0,1,254,0,0,0,0,127,128,3,159,128,0,0,1,249,192,7,135,224,0,0,7,225,224,7,3,248,0,0,31,192,224,14,0,255,0,0,255,0,112,12,0,127,224,7,252,0,48,0,0,127,255,255,252,0,0,0,0,97,255,255,156,0,0,0,0,224,31,248,12,0,0,0,0,224,1,128,14,0,0,0,0,224,1,128,14,0,0,0,0,192,1,128,14,0,0,0,1,192,1,128,6,0,0,0,0,128,1,128,6,0,0,0,0,0,1,128,0,0,0,0,0,0,1,128,0,0,0,0,0,0,1,128,0,0,0,0,0,0,1,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
  {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,248,0,0,0,0,0,1,255,255,128,0,0,0,0,15,255,255,240,0,0,0,0,63,248,31,252,0,0,0,0,255,0,0,255,0,0,0,3,248,0,0,31,192,0,0,7,224,0,0,7,224,0,0,31,128,0,0,1,248,0,0,62,0,0,0,0,124,0,0,124,0,0,0,0,62,0,1,240,0,0,0,0,15,128,3,224,0,0,0,0,7,192,7,128,0,0,0,0,1,224,15,0,0,0,0,0,0,240,30,0,0,0,0,0,0,120,60,0,0,0,0,0,0,60,120,0,0,0,0,0,0,30,120,0,0,0,0,0,0,30,60,0,0,0,0,0,0,60,30,0,0,0,0,0,0,120,15,0,0,0,0,0,0,240,7,128,0,0,0,0,1,224,3,224,0,0,0,0,7,192,1,240,0,0,0,0,15,128,0,248,0,0,0,0,31,0,1,254,0,0,0,0,127,128,3,159,128,0,0,1,249,192,7,135,224,0,0,7,225,224,7,3,248,0,0,31,192,224,14,0,255,0,0,255,0,112,12,0,127,224,7,252,0,48,0,0,127,255,255,252,0,0,0,0,97,255,255,156,0,0,0,0,224,31,248,12,0,0,0,0,224,1,128,14,0,0,0,0,224,1,128,14,0,0,0,0,192,1,128,14,0,0,0,1,192,1,128,6,0,0,0,0,128,1,128,6,0,0,0,0,0,1,128,0,0,0,0,0,0,1,128,0,0,0,0,0,0,1,128,0,0,0,0,0,0,1,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
  {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,248,0,0,0,0,0,1,255,255,128,0,0,0,0,15,255,255,240,0,0,0,0,63,248,31,252,0,0,0,0,255,0,0,255,0,0,0,3,248,0,0,31,192,0,0,7,224,0,0,7,224,0,0,31,128,0,0,1,248,0,0,62,0,0,0,0,124,0,0,124,0,0,0,0,62,0,1,240,0,0,0,0,15,128,3,224,0,0,0,0,7,192,7,128,0,0,0,0,1,224,15,0,0,0,0,0,0,240,30,0,0,0,0,0,0,120,60,0,0,0,0,0,0,60,120,0,0,0,0,0,0,30,120,0,0,0,0,0,0,30,60,0,0,0,0,0,0,60,30,0,0,0,0,0,0,120,15,0,0,0,0,0,0,240,7,128,0,0,0,0,1,224,3,224,0,0,0,0,7,192,1,240,0,0,0,0,15,128,0,248,0,0,0,0,31,0,1,254,0,0,0,0,127,128,3,223,128,0,0,1,251,192,3,135,224,0,0,7,225,192,0,3,248,0,0,31,192,0,0,0,255,0,0,255,0,0,0,0,127,224,7,252,0,0,0,0,127,255,255,252,0,0,0,0,97,255,255,156,0,0,0,0,224,31,248,12,0,0,0,0,224,1,128,12,0,0,0,0,0,1,128,0,0,0,0,0,0,1,128,0,0,0,0,0,0,1,128,0,0,0,0,0,0,1,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
  {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,248,0,0,0,0,0,1,255,255,128,0,0,0,0,15,255,255,240,0,0,0,0,63,248,31,252,0,0,0,0,255,0,0,255,0,0,0,3,248,0,0,31,192,0,0,7,224,0,0,7,224,0,0,31,128,0,0,1,248,0,0,62,0,0,0,0,124,0,0,124,0,0,0,0,62,0,1,240,0,0,0,0,15,128,3,224,0,0,0,0,7,192,7,128,0,0,0,0,1,224,15,0,0,0,0,0,0,240,30,0,0,0,0,0,0,120,60,0,0,0,0,0,0,60,120,0,0,0,0,0,0,30,120,0,0,0,0,0,0,30,60,0,0,0,0,0,0,60,30,0,0,0,0,0,0,120,15,0,0,0,0,0,0,240,7,128,0,0,0,0,1,224,3,224,0,0,0,0,7,192,1,240,0,0,0,0,15,128,0,248,0,0,0,0,31,0,0,254,0,0,0,0,127,0,0,31,128,0,0,1,248,0,0,7,224,0,0,7,224,0,0,3,248,0,0,31,192,0,0,0,255,0,0,255,0,0,0,0,127,224,7,252,0,0,0,0,127,255,255,252,0,0,0,0,1,255,255,136,0,0,0,0,0,31,248,0,0,0,0,0,0,1,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
  {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,248,0,0,0,0,0,1,255,255,128,0,0,0,0,15,255,255,240,0,0,0,0,63,248,31,252,0,0,0,0,255,0,0,255,0,0,0,3,248,0,0,31,192,0,0,7,224,0,0,7,224,0,0,31,128,0,0,1,248,0,0,62,0,0,0,0,124,0,0,124,0,0,0,0,62,0,1,240,0,0,0,0,15,128,3,224,0,0,0,0,7,192,7,128,0,0,0,0,1,224,15,0,0,0,0,0,0,240,30,0,0,0,0,0,0,120,60,0,0,0,0,0,0,60,120,0,0,0,0,0,0,30,120,0,0,0,0,0,0,30,62,0,0,0,0,0,0,124,31,0,0,0,0,0,0,248,15,192,0,0,0,0,3,240,7,240,0,0,0,0,15,224,3,252,0,0,0,0,63,192,0,255,0,0,0,0,255,0,0,127,224,0,0,7,254,0,0,63,252,0,0,63,252,0,0,15,255,224,7,255,240,0,0,7,207,255,255,243,224,0,0,1,240,255,255,15,128,0,0,0,126,0,0,126,0,0,0,0,31,192,3,248,0,0,0,0,7,255,255,224,0,0,0,0,0,255,255,0,0,0,0,0,0,7,224,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
  {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,248,0,0,0,0,0,1,255,255,128,0,0,0,0,15,255,255,240,0,0,0,0,63,248,31,252,0,0,0,0,255,0,0,255,0,0,0,3,248,0,0,31,192,0,0,7,224,0,0,7,224,0,0,31,128,0,0,1,248,0,0,62,0,0,0,0,124,0,0,124,0,0,0,0,62,0,1,240,0,0,0,0,15,128,3,224,0,0,0,0,7,192,7,128,0,0,0,0,1,224,15,0,0,0,0,0,0,240,30,0,0,0,0,0,0,120,60,0,0,0,0,0,0,60,120,0,0,0,0,0,0,62,127,128,0,0,0,0,1,254,63,252,0,0,0,0,63,252,31,255,252,0,0,63,255,248,15,63,255,255,255,255,252,240,7,128,255,255,255,255,1,224,3,192,15,255,255,240,3,192,0,240,7,0,0,224,15,0,0,120,3,192,3,192,30,0,0,62,1,248,31,128,124,0,0,15,0,255,255,0,240,0,0,7,192,63,252,3,224,0,0,1,240,0,0,15,128,0,0,0,126,0,0,126,0,0,0,0,31,192,3,248,0,0,0,0,7,255,255,224,0,0,0,0,0,255,255,0,0,0,0,0,0,7,224,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
  {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,248,0,0,0,0,0,1,255,255,128,0,0,0,0,15,255,255,240,0,0,0,0,63,248,31,252,0,0,0,0,255,0,0,255,0,0,0,3,248,0,0,31,192,0,0,7,224,0,0,7,224,0,0,31,128,0,0,1,248,0,0,62,0,0,0,0,124,0,0,124,0,0,0,0,62,0,1,240,0,0,0,0,15,128,3,224,0,0,0,0,7,192,7,128,0,0,0,0,1,224,15,0,0,255,255,0,0,240,30,127,255,255,255,255,254,120,63,255,255,255,255,255,255,252,127,252,112,31,248,14,63,254,126,0,112,31,248,14,0,126,60,0,48,7,224,12,0,60,30,0,56,0,0,28,0,120,15,0,28,0,0,56,0,240,7,128,28,0,0,56,1,224,3,192,14,0,0,112,3,192,0,240,7,0,0,224,15,0,0,120,3,192,3,192,30,0,0,62,1,248,31,128,124,0,0,15,0,255,255,0,240,0,0,7,192,63,252,3,224,0,0,1,240,0,0,15,128,0,0,0,126,0,0,126,0,0,0,0,31,192,3,248,0,0,0,0,7,255,255,224,0,0,0,0,0,255,255,0,0,0,0,0,0,7,224,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
  {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,248,0,0,0,0,0,1,255,255,128,0,0,0,0,15,255,255,240,0,0,0,0,63,248,31,252,0,0,0,0,255,0,0,255,0,0,0,3,248,0,0,31,192,0,0,7,224,0,0,7,224,0,0,31,128,31,248,1,248,0,0,62,7,255,255,224,124,0,0,124,127,255,255,254,62,0,1,243,255,63,252,255,207,128,3,255,240,63,252,15,255,192,7,255,96,63,252,6,255,224,15,248,96,63,252,6,31,240,31,224,96,63,252,6,7,248,63,0,96,63,252,6,0,252,124,0,112,31,248,14,0,62,120,0,112,31,248,14,0,30,60,0,48,7,224,12,0,60,30,0,56,0,0,28,0,120,15,0,28,0,0,56,0,240,7,128,28,0,0,56,1,224,3,192,14,0,0,112,3,192,0,240,7,0,0,224,15,0,0,120,3,192,3,192,30,0,0,62,1,248,31,128,124,0,0,15,0,255,255,0,240,0,0,7,192,63,252,3,224,0,0,1,240,0,0,15,128,0,0,0,126,0,0,126,0,0,0,0,31,192,3,248,0,0,0,0,7,255,255,224,0,0,0,0,0,255,255,0,0,0,0,0,0,7,224,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
  {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,248,0,0,0,0,0,1,255,255,128,0,0,0,0,15,255,255,240,0,0,0,0,63,255,255,252,0,0,0,0,255,255,255,255,0,0,0,3,255,224,7,255,192,0,0,7,252,0,0,63,224,0,0,31,248,7,224,31,248,0,0,63,240,15,240,15,252,0,0,126,112,31,248,14,126,0,1,252,96,63,252,6,63,128,3,240,96,63,252,6,15,192,7,192,96,63,252,6,3,224,15,128,96,63,252,6,1,240,30,0,96,63,252,6,0,120,60,0,96,63,252,6,0,60,120,0,112,31,248,14,0,30,120,0,112,31,248,14,0,30,60,0,48,7,224,12,0,60,30,0,56,0,0,28,0,120,15,0,28,0,0,56,0,240,7,128,28,0,0,56,1,224,3,192,14,0,0,112,3,192,0,240,7,0,0,224,15,0,0,120,3,192,3,192,30,0,0,62,1,248,31,128,124,0,0,15,0,255,255,0,240,0,0,7,192,63,252,3,224,0,0,1,240,0,0,15,128,0,0,0,126,0,0,126,0,0,0,0,31,192,3,248,0,0,0,0,7,255,255,224,0,0,0,0,0,255,255,0,0,0,0,0,0,7,224,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
  {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,248,0,0,0,0,0,1,255,255,128,0,0,0,0,15,255,255,240,0,0,0,0,63,248,31,252,0,0,0,0,255,0,0,255,0,0,0,3,252,0,0,63,192,0,0,7,248,0,0,31,224,0,0,31,184,7,224,29,248,0,0,62,112,15,240,14,124,0,0,124,112,31,248,14,62,0,1,240,96,63,252,6,15,128,3,224,96,63,252,6,7,192,7,192,96,63,252,6,3,224,15,0,96,63,252,6,0,240,30,0,96,63,252,6,0,120,60,0,96,63,252,6,0,60,120,0,112,31,248,14,0,30,120,0,112,31,248,14,0,30,60,0,48,7,224,12,0,60,30,0,56,0,0,28,0,120,15,0,28,0,0,56,0,240,7,128,28,0,0,56,1,224,3,192,14,0,0,112,3,192,0,240,7,0,0,224,15,0,0,120,3,192,3,192,30,0,0,62,1,248,31,128,124,0,0,15,0,255,255,0,240,0,0,7,192,63,252,3,224,0,0,1,240,0,0,15,128,0,0,0,126,0,0,126,0,0,0,0,31,192,3,248,0,0,0,0,7,255,255,224,0,0,0,0,0,255,255,0,0,0,0,0,0,7,224,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
  {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,248,0,0,0,0,0,1,255,255,128,0,0,0,0,15,255,255,240,0,0,0,0,63,248,31,252,0,0,0,0,255,0,0,255,0,0,0,3,252,0,0,63,192,0,0,7,248,0,0,31,224,0,0,31,184,7,224,29,248,0,0,62,112,15,240,14,124,0,0,124,112,31,248,14,62,0,1,240,96,63,252,6,15,128,3,224,96,63,252,6,7,192,7,192,96,63,252,6,3,224,15,0,96,63,252,6,0,240,30,0,96,63,252,6,0,120,60,0,96,63,252,6,0,60,120,0,112,31,248,14,0,30,120,0,112,31,248,14,0,30,60,0,48,7,224,12,0,60,30,0,56,0,0,28,0,120,15,0,28,0,0,56,0,240,7,128,28,0,0,56,1,224,3,192,14,0,0,112,3,192,0,240,7,0,0,224,15,0,0,120,3,192,3,192,30,0,0,62,1,248,31,128,124,0,0,15,0,255,255,0,240,0,0,7,192,63,252,3,224,0,0,1,240,0,0,15,128,0,0,0,126,0,0,126,0,0,0,0,31,192,3,248,0,0,0,0,7,255,255,224,0,0,0,0,0,255,255,0,0,0,0,0,0,7,224,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
  {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,248,0,0,0,0,0,1,255,255,128,0,0,0,0,15,255,255,240,0,0,0,0,63,248,31,252,0,0,0,0,255,0,0,255,0,0,0,3,252,0,0,63,192,0,0,7,248,0,0,31,224,0,0,31,184,7,224,29,248,0,0,62,112,15,240,14,124,0,0,124,112,31,248,14,62,0,1,240,96,63,252,6,15,128,3,224,96,63,252,6,7,192,7,192,96,63,252,6,3,224,15,0,96,63,252,6,0,240,30,0,96,63,252,6,0,120,60,0,96,63,252,6,0,60,120,0,112,31,248,14,0,30,120,0,112,31,248,14,0,30,60,0,48,7,224,12,0,60,30,0,56,0,0,28,0,120,15,0,28,0,0,56,0,240,7,128,28,0,0,56,1,224,3,192,14,0,0,112,3,192,0,240,7,0,0,224,15,0,0,120,3,192,3,192,30,0,0,62,1,248,31,128,124,0,0,15,0,255,255,0,240,0,0,7,192,63,252,3,224,0,0,1,240,0,0,15,128,0,0,0,126,0,0,126,0,0,0,0,31,192,3,248,0,0,0,0,7,255,255,224,0,0,0,0,0,255,255,0,0,0,0,0,0,7,224,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
};

void setup() {
  display.begin(SSD1306_SWITCHCAPVCC, SCREEN_I2C_ADDR);
}

int frame = 0;
void loop() {
  display.clearDisplay();
  display.drawBitmap(32, 0, frames[frame], FRAME_WIDTH, FRAME_HEIGHT, 1);
  display.display();
  frame = (frame + 1) % FRAME_COUNT;
  // delay(FRAME_DELAY);
}

I2C vs SPI?

The I2C’s display are often chosen because it is good enough for transferring small amounts of data and requires less pin to use. However for my project - I would require a bigger display with colour. Unfortunately I couldn’t find any I2C displays that fit the requirements. The cheap coloured display I could find readily available here in Indonesia are the TFT Displays. They mainly use SPI connections (MISO,MOSI,SCK,SS). As such these displays require more pins. Good thing my custom Elaineduino had enough pins to make sure these TFT displays could be programmed.

2.0” TFT ILI9225 LCD Screen

A thin-film-transistor liquid-crystal display (TFT LCD) is a type of LCD Display that uses thin-film-transistor technology. Each pixel in the display has a tiny transistor that controls the amount of light that passes through it. This allows for much more precise control over the image. TFT displays are considered “active matrix” displays. This means each pixel is controlled by its own transistor, allowing for sharper images and better viewing angles. Most TFT Displays uses the SPI module.

I bought this LCD Screen at first but realised that it has limited libraries compared to other TFT Screens. Please be aware that this particular TFT Display doesn’t support Adafruit GFX Library. The main library to be utilised is the TFT_22_ILI9225.h

Check more about ILI9225 from Arnov Sharma

In his documentation, this was how he used his TFT Display as a shield.

alt text

And so I adapted the pin-outs to Xiao ESP32S3

  • CS = D7. In some forums, D7 was considered the Chip Select/Slave Select pin. However I found any digital pins would work with the Xiao ESP32.
  • RST = A0 Following the analog pin placement.
  • RS = A1 Following the analog pin placement.
  • SDA = D10 The hardware names this pin SDA however the code labels it SDI and reserves it for MOSI. So I adapted to Xiao ESP32’s MOSI pin which is D10
  • CLK = D8 The code suggests an SCK pin. SCK in Xiao ESP32 is D8

System Diagram alt text

Code from Arnov Sharma

#include "SPI.h"
#include "TFT_22_ILI9225.h"
#include "math.h"


#define TFT_RST A0
#define TFT_RS  A1
#define TFT_CS  D7  // SS
#define TFT_SDI D10  // MOSI
#define TFT_CLK D8  // SCK
#define TFT_LED 0   // 0 if wired to +5V directly

#define TFT_BRIGHTNESS 200 // Initial brightness of TFT backlight (optional)

#define ROTATE_ANGLE 10 // Angle in degrees to rotate the triangle

struct _point
{
    int16_t x;
    int16_t y;
};

// Use hardware SPI (faster - on Uno: 13-SCK, 12-MISO, 11-MOSI)
TFT_22_ILI9225 tft = TFT_22_ILI9225(TFT_RST, TFT_RS, TFT_CS, TFT_SDI, TFT_CLK, TFT_LED);

// Variables and constants
_point c1, c2, c3, cc;

// Setup
void setup() {
  tft.begin();

  // Define triangle start coordinates
  c1.x = 30;  c1.y = 30;
  c2.x = 120; c2.y = 80;
  c3.x = 80;  c3.y = 130;

  // Determine the rotation point, i.e. the center of the triangle
  cc = getCoordCentroid(c1, c2, c3);

  tft.clear();
}

// Loop
void loop() {
  // Calculate the number of steps to rotate the triangle a full rotation
  int16_t steps = (int16_t)(360 / ROTATE_ANGLE);

  // Draw solid triangle
  tft.fillTriangle(30, 190, 80, 150, 130, 210, COLOR_BLUE);

  for (int8_t i = 0; i < steps; i++) {
    // Draw triangle
    tft.drawTriangle(c1.x, c1.y, c2.x, c2.y, c3.x, c3.y, COLOR_GREEN);
    // Rotate triangle
    rotateTriangle(c1, c2, c3, cc, ROTATE_ANGLE);
    delay(50);
  }
  delay(5000);
  tft.clear();
}

// Get centroid of triangle
_point getCoordCentroid( _point a, _point b, _point c ) {
  _point o;

  o.x = (int16_t)((a.x + b.x + c.x) / 3);
  o.y = (int16_t)((a.y + b.y + c.y) / 3);

  return o;
}

// Rotate triangle around point r
void rotateTriangle( _point &a, _point &b, _point &c, _point r, int16_t deg ) {

  // Convert degrees to radians
  float angle = (float)deg * 1000 / 57296;

  // Rotate each individual point
  a = rotatePoint( r, angle, a);
  b = rotatePoint( r, angle, b);
  c = rotatePoint( r, angle, c);
}

// Rotate each point p around c
_point rotatePoint( _point c, float angle, _point p ) {
  _point r;

  // 1. translate point back to origin
  // 2. rotate point
  // 3. translate point back

  r.x = cos(angle) * (p.x - c.x) - sin(angle) * (p.y - c.y) + c.x;
  r.y = sin(angle) * (p.x - c.x) + cos(angle) * (p.y - c.y) + c.y;

  return r;
}

TFT ILI9341 2.8” Display

This particular TFT Screen is widely used and has touchscreen capabilities. Adafruit GFX Library supports this display however the library TFT_eSPI is more widely used and works best for 32-bit processor MCUs. Since this library is more popular, there is also a significant amount of people in the community providing widgets and design contribution for the library.

To use this library follow this tutorial. It requires a specific set up.

HOWEVER

I couldn’t get this the eSPI Library to work at all with the Xiao ESP32.... so I just decided to program with the Adafruit GFX Library.

System Diagram alt text

Example Code

Original Code from electronoob adapted for XIAO ESP32S3

/***************************************************
  This is our GFX example for the Adafruit ILI9341 Breakout and Shield
  ----> http://www.adafruit.com/products/1651

  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
 ****************************************************/
#define ILI9341_BLACK       0x0000  ///<   0,   0,   0
#define ILI9341_NAVY        0x000F  ///<   0,   0, 123
#define ILI9341_DARKGREEN   0x03E0  ///<   0, 125,   0
#define ILI9341_DARKCYAN    0x03EF  ///<   0, 125, 123
#define ILI9341_MAROON      0x7800  ///< 123,   0,   0
#define ILI9341_PURPLE      0x780F  ///< 123,   0, 123
#define ILI9341_OLIVE       0x7BE0  ///< 123, 125,   0
#define ILI9341_LIGHTGREY   0xC618  ///< 198, 195, 198
#define ILI9341_DARKGREY    0x7BEF  ///< 123, 125, 123
#define ILI9341_BLUE        0x001F  ///<   0,   0, 255
#define ILI9341_GREEN       0x07E0  ///<   0, 255,   0
#define ILI9341_CYAN        0x07FF  ///<   0, 255, 255
#define ILI9341_RED         0xF800  ///< 255,   0,   0
#define ILI9341_MAGENTA     0xF81F  ///< 255,   0, 255
#define ILI9341_YELLOW      0xFFE0  ///< 255, 255,   0
#define ILI9341_WHITE       0xFFFF  ///< 255, 255, 255
#define ILI9341_ORANGE      0xFD20  ///< 255, 165,   0
#define ILI9341_GREENYELLOW 0xAFE5  ///< 173, 255,  41
#define ILI9341_PINK        0xFC18  ///< 255, 130, 198

#include "SPI.h"
#include "Adafruit_GFX.h"
#include "Adafruit_ILI9341.h"

// For the Adafruit shield, these are the default.
#define TFT_RST A0
#define TFT_DC  A1
#define TFT_CS  D7  // SS
#define TFT_MOSI D10  // MOSI
#define TFT_MISO D9
#define TFT_CLK D8  // SCK

Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_MOSI, TFT_CLK, TFT_RST, TFT_MISO);

void setup() {
  Serial.begin(9600);
  Serial.println("ILI9341 Test!"); 

  tft.begin();

  // read diagnostics (optional but can help debug problems)
  uint8_t x = tft.readcommand8(ILI9341_RDMODE);
  Serial.print("Display Power Mode: 0x"); Serial.println(x, HEX);
  x = tft.readcommand8(ILI9341_RDMADCTL);
  Serial.print("MADCTL Mode: 0x"); Serial.println(x, HEX);
  x = tft.readcommand8(ILI9341_RDPIXFMT);
  Serial.print("Pixel Format: 0x"); Serial.println(x, HEX);
  x = tft.readcommand8(ILI9341_RDIMGFMT);
  Serial.print("Image Format: 0x"); Serial.println(x, HEX);
  x = tft.readcommand8(ILI9341_RDSELFDIAG);
  Serial.print("Self Diagnostic: 0x"); Serial.println(x, HEX); 

void loop(void) {
  tft.fillScreen(ILI9341_NAVY);
  tft.setCursor(0, 0);
  tft.setTextColor(ILI9341_WHITE);  tft.setTextSize(1);
  tft.println("Hello World!");
  tft.setTextColor(ILI9341_YELLOW); tft.setTextSize(2);
  tft.println(1234.56);
  tft.setTextColor(ILI9341_RED);    tft.setTextSize(3);
  tft.println(0xDEADBEEF, HEX);
  tft.println();
  tft.setTextColor(ILI9341_GREEN);
  tft.setTextSize(5);
  tft.println("Groop");
  tft.setTextSize(2);
  tft.println("I implore thee,");
  tft.setTextSize(1);
  tft.println("my foonting turlingdromes.");
  tft.println("And hooptiously drangle me");
  tft.println("with crinkly bindlewurdles,");
  tft.println("Or I will rend thee");
  tft.println("in the gobberwarts");
  tft.println("with my blurglecruncheon,");
  tft.println("see if I don't!");
  delay(5000);

}

unsigned long testFillScreen() {
  unsigned long start = micros();
  tft.fillScreen(ILI9341_BLACK);
  yield();
  tft.fillScreen(ILI9341_RED);
  yield();
  tft.fillScreen(ILI9341_GREEN);
  yield();
  tft.fillScreen(ILI9341_BLUE);
  yield();
  tft.fillScreen(ILI9341_BLACK);
  yield();
  return micros() - start;
}

unsigned long testText() {
  tft.fillScreen(ILI9341_BLACK);
  unsigned long start = micros();
  tft.setCursor(0, 0);
  tft.setTextColor(ILI9341_WHITE);  tft.setTextSize(1);
  tft.println("Hello World!");
  tft.setTextColor(ILI9341_YELLOW); tft.setTextSize(2);
  tft.println(1234.56);
  tft.setTextColor(ILI9341_RED);    tft.setTextSize(3);
  tft.println(0xDEADBEEF, HEX);
  tft.println();
  tft.setTextColor(ILI9341_GREEN);
  tft.setTextSize(5);
  tft.println("Groop");
  tft.setTextSize(2);
  tft.println("I implore thee,");
  tft.setTextSize(1);
  tft.println("my foonting turlingdromes.");
  tft.println("And hooptiously drangle me");
  tft.println("with crinkly bindlewurdles,");
  tft.println("Or I will rend thee");
  tft.println("in the gobberwarts");
  tft.println("with my blurglecruncheon,");
  tft.println("see if I don't!");
  return micros() - start;
}

unsigned long testLines(uint16_t color) {
  unsigned long start, t;
  int           x1, y1, x2, y2,
                w = tft.width(),
                h = tft.height();

  tft.fillScreen(ILI9341_BLACK);
  yield();

  x1 = y1 = 0;
  y2    = h - 1;
  start = micros();
  for(x2=0; x2<w; x2+=6) tft.drawLine(x1, y1, x2, y2, color);
  x2    = w - 1;
  for(y2=0; y2<h; y2+=6) tft.drawLine(x1, y1, x2, y2, color);
  t     = micros() - start; // fillScreen doesn't count against timing

  yield();
  tft.fillScreen(ILI9341_BLACK);
  yield();

  x1    = w - 1;
  y1    = 0;
  y2    = h - 1;
  start = micros();
  for(x2=0; x2<w; x2+=6) tft.drawLine(x1, y1, x2, y2, color);
  x2    = 0;
  for(y2=0; y2<h; y2+=6) tft.drawLine(x1, y1, x2, y2, color);
  t    += micros() - start;

  yield();
  tft.fillScreen(ILI9341_BLACK);
  yield();

  x1    = 0;
  y1    = h - 1;
  y2    = 0;
  start = micros();
  for(x2=0; x2<w; x2+=6) tft.drawLine(x1, y1, x2, y2, color);
  x2    = w - 1;
  for(y2=0; y2<h; y2+=6) tft.drawLine(x1, y1, x2, y2, color);
  t    += micros() - start;

  yield();
  tft.fillScreen(ILI9341_BLACK);
  yield();

  x1    = w - 1;
  y1    = h - 1;
  y2    = 0;
  start = micros();
  for(x2=0; x2<w; x2+=6) tft.drawLine(x1, y1, x2, y2, color);
  x2    = 0;
  for(y2=0; y2<h; y2+=6) tft.drawLine(x1, y1, x2, y2, color);

  yield();
  return micros() - start;
}

unsigned long testFastLines(uint16_t color1, uint16_t color2) {
  unsigned long start;
  int           x, y, w = tft.width(), h = tft.height();

  tft.fillScreen(ILI9341_BLACK);
  start = micros();
  for(y=0; y<h; y+=5) tft.drawFastHLine(0, y, w, color1);
  for(x=0; x<w; x+=5) tft.drawFastVLine(x, 0, h, color2);

  return micros() - start;
}

unsigned long testRects(uint16_t color) {
  unsigned long start;
  int           n, i, i2,
                cx = tft.width()  / 2,
                cy = tft.height() / 2;

  tft.fillScreen(ILI9341_BLACK);
  n     = min(tft.width(), tft.height());
  start = micros();
  for(i=2; i<n; i+=6) {
    i2 = i / 2;
    tft.drawRect(cx-i2, cy-i2, i, i, color);
  }

  return micros() - start;
}

unsigned long testFilledRects(uint16_t color1, uint16_t color2) {
  unsigned long start, t = 0;
  int           n, i, i2,
                cx = tft.width()  / 2 - 1,
                cy = tft.height() / 2 - 1;

  tft.fillScreen(ILI9341_BLACK);
  n = min(tft.width(), tft.height());
  for(i=n; i>0; i-=6) {
    i2    = i / 2;
    start = micros();
    tft.fillRect(cx-i2, cy-i2, i, i, color1);
    t    += micros() - start;
    // Outlines are not included in timing results
    tft.drawRect(cx-i2, cy-i2, i, i, color2);
    yield();
  }

  return t;
}

unsigned long testFilledCircles(uint8_t radius, uint16_t color) {
  unsigned long start;
  int x, y, w = tft.width(), h = tft.height(), r2 = radius * 2;

  tft.fillScreen(ILI9341_BLACK);
  start = micros();
  for(x=radius; x<w; x+=r2) {
    for(y=radius; y<h; y+=r2) {
      tft.fillCircle(x, y, radius, color);
    }
  }

  return micros() - start;
}

unsigned long testCircles(uint8_t radius, uint16_t color) {
  unsigned long start;
  int           x, y, r2 = radius * 2,
                w = tft.width()  + radius,
                h = tft.height() + radius;

  // Screen is not cleared for this one -- this is
  // intentional and does not affect the reported time.
  start = micros();
  for(x=0; x<w; x+=r2) {
    for(y=0; y<h; y+=r2) {
      tft.drawCircle(x, y, radius, color);
    }
  }

  return micros() - start;
}

unsigned long testTriangles() {
  unsigned long start;
  int           n, i, cx = tft.width()  / 2 - 1,
                      cy = tft.height() / 2 - 1;

  tft.fillScreen(ILI9341_BLACK);
  n     = min(cx, cy);
  start = micros();
  for(i=0; i<n; i+=5) {
    tft.drawTriangle(
      cx    , cy - i, // peak
      cx - i, cy + i, // bottom left
      cx + i, cy + i, // bottom right
      tft.color565(i, i, i));
  }

  return micros() - start;
}

unsigned long testFilledTriangles() {
  unsigned long start, t = 0;
  int           i, cx = tft.width()  / 2 - 1,
                   cy = tft.height() / 2 - 1;

  tft.fillScreen(ILI9341_BLACK);
  start = micros();
  for(i=min(cx,cy); i>10; i-=5) {
    start = micros();
    tft.fillTriangle(cx, cy - i, cx - i, cy + i, cx + i, cy + i,
      tft.color565(0, i*10, i*10));
    t += micros() - start;
    tft.drawTriangle(cx, cy - i, cx - i, cy + i, cx + i, cy + i,
      tft.color565(i*10, i*10, 0));
    yield();
  }

  return t;
}

unsigned long testRoundRects() {
  unsigned long start;
  int           w, i, i2,
                cx = tft.width()  / 2 - 1,
                cy = tft.height() / 2 - 1;

  tft.fillScreen(ILI9341_BLACK);
  w     = min(tft.width(), tft.height());
  start = micros();
  for(i=0; i<w; i+=6) {
    i2 = i / 2;
    tft.drawRoundRect(cx-i2, cy-i2, i, i, i/8, tft.color565(i, 0, 0));
  }

  return micros() - start;
}

unsigned long testFilledRoundRects() {
  unsigned long start;
  int           i, i2,
                cx = tft.width()  / 2 - 1,
                cy = tft.height() / 2 - 1;

  tft.fillScreen(ILI9341_BLACK);
  start = micros();
  for(i=min(tft.width(), tft.height()); i>20; i-=6) {
    i2 = i / 2;
    tft.fillRoundRect(cx-i2, cy-i2, i, i, i/8, tft.color565(0, i, 0));
    yield();
  }

  return micros() - start;
}

Simple Menu with Rotary Encoder

Inspired by this video, I adapted the code for ILI9341 with the help of chatgpt. alt text

#include <Adafruit_GFX.h>
#include <Adafruit_ILI9341.h>

// Define pins for the ILI9341 display
#define TFT_RST D4
#define TFT_DC  D5
#define TFT_CS  D3  // SS
#define TFT_MOSI D10  // MOSI
#define TFT_MISO D9
#define TFT_CLK D8  // SCK

// Define pins for the rotary encoder
#define ENCODER_CLK D0
#define ENCODER_DT  D1
#define ENCODER_SW  D2  

Adafruit_ILI9341 display = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST);

int menuitem = 1;
int page = 1;

int volume = 50;
String language[3] = { "EN", "ES", "EL" };
int selectedLanguage = 0;
String difficulty[2] = { "EASY", "HARD" };
int selectedDifficulty = 0;

volatile boolean up = false;
volatile boolean down = false;
volatile boolean middle = false;

volatile int lastClk = HIGH;
unsigned long lastButtonPress = 0;

void setup() {
  pinMode(ENCODER_CLK, INPUT_PULLUP);
  pinMode(ENCODER_DT, INPUT_PULLUP);
  pinMode(ENCODER_SW, INPUT_PULLUP);

  attachInterrupt(digitalPinToInterrupt(ENCODER_CLK), readEncoder, CHANGE);
  attachInterrupt(digitalPinToInterrupt(ENCODER_SW), readButton, FALLING);

  display.begin();
  display.setRotation(4);
  display.fillScreen(ILI9341_BLACK);
  drawMenu();
}

void loop() {
  bool needRedraw = false;

  if (up) {
    up = false;
    if (page == 1) {
      if (menuitem > 1) {
        menuitem--;
      } else {
        menuitem = 3;
      }
      needRedraw = true;
    } else {
      if (menuitem == 1 && volume > 0) {
        volume--;
        needRedraw = true;
      } else if (menuitem == 2 && selectedLanguage > 0) {
        selectedLanguage--;
        needRedraw = true;
      } else if (menuitem == 3 && selectedDifficulty > 0) {
        selectedDifficulty--;
        needRedraw = true;
      }
    }
  }

  if (down) {
    down = false;
    if (page == 1) {
      if (menuitem < 3) {
        menuitem++;
      } else {
        menuitem = 1;
      }
      needRedraw = true;
    } else {
      if (menuitem == 1 && volume < 100) {
        volume++;
        needRedraw = true;
      } else if (menuitem == 2 && selectedLanguage < 2) {
        selectedLanguage++;
        needRedraw = true;
      } else if (menuitem == 3 && selectedDifficulty < 1) {
        selectedDifficulty++;
        needRedraw = true;
      }
    }
  }

  if (middle) {
    middle = false;
    page = (page == 1) ? 2 : 1;
    needRedraw = true;
  }

  if (needRedraw) {
    drawMenu();
  }
}

void drawMenu() {
  display.fillScreen(ILI9341_BLACK);
  display.setTextSize(2);
  display.setTextColor(ILI9341_WHITE);

  if (page == 1) {
    display.setCursor(10, 10);
    display.print("MAIN MENU");

    display.setCursor(10, 40);
    display.setTextColor(menuitem == 1 ? ILI9341_YELLOW : ILI9341_WHITE);
    display.print("Volume");

    display.setCursor(10, 70);
    display.setTextColor(menuitem == 2 ? ILI9341_YELLOW : ILI9341_WHITE);
    display.print("Language");

    display.setCursor(10, 100);
    display.setTextColor(menuitem == 3 ? ILI9341_YELLOW : ILI9341_WHITE);
    display.print("Difficulty");
  } else if (page == 2) {
    display.setCursor(10, 10);
    if (menuitem == 1) {
      display.print("Volume");
      display.setCursor(10, 40);
      display.print(volume);
    } else if (menuitem == 2) {
      display.print("Language");
      display.setCursor(10, 40);
      display.print(language[selectedLanguage]);
    } else if (menuitem == 3) {
      display.print("Difficulty");
      display.setCursor(10, 40);
      display.print(difficulty[selectedDifficulty]);
    }
  }
}

void readEncoder() {
  int clkValue = digitalRead(ENCODER_CLK);
  if (clkValue != lastClk) {
    if (digitalRead(ENCODER_DT) != clkValue) {
      down = true;
    } else {
      up = true;
    }
  }
  lastClk = clkValue;
}

void readButton() {
  unsigned long currentTime = millis();
  if (currentTime - lastButtonPress > 200) { // debounce time
    middle = true;
    lastButtonPress = currentTime;
  }
}

Final Project - System Diagram

Based on my eplorations I have decided that the TFT ILI9341 would be the screen that I required for my final project. This is my finalised system diagram intended for the final project.

alt text

Electronics Design and Production

I started with this aspect first because for system integration I want to minimise as much wiring as possible. This will also affect how the enclosure would look like and since I want to make a compact handheld device - it is important that we start from what’s within.

As I was testing out my input and output devices during those weeks, I realised that there were too many wiring, and system integration wise this was just not it.

Knowing that the TFT ILI9341 Display is designed to be used as a shield for the Arduino UNO microcontrollers, I decided to design my board with that feature in mind. I decided to mainly have female headers on my board and that the components would sit in place directly on to the headers.

This was my initial sketch for the electronic design. alt text

Once I have laid out the components and the wiring - I made the schematic, designed the sketch in Kicad and produced it.

alt text alt text alt text

For my pcb production, I was using the same settings as my electronic production week - Rico and Henk suggested that I used 4 offset instead of 2 for this board. The production took abit of time to prepare because I was using a used v-bit and had to figure out the offset height in our finicky CNC Milling Machine. I tried offseting from 0.3mm all the way to 0.01 to figure out the optimum offset.

alt text alt text

Since 0.3mm wasn’t cutting through, I made an offset of 0.4mm - as a way of airpassing..... but turns out the machine instead started cutting the board - and cut was deeper than I expected. I didn’t know if I wanted to laugh or cry because it felt like all the preparation I did was a waste.

alt text

I made a mistake with the screw hole...... if you want to use a M3 screw… make sure that your screw diameter is at least 3.2mm and also I just happened to forget offseting the board when I had to drill the holes. alt text

It looked like my board may be a problem… but when I got to stuffing and my board worked! alt text

However there was a problem.... Initially I wanted to use a wire to in between the rotary encoder and the female header input, but Rico told me that it wouldn’t be ideal. I had to frankenstein my board in order to make sure I can get the rotary encoder to be plugged. alt text alt text alt text

The rotary encoder also had to be modified. It will be impossible for me to have original orientation plugged in with the default header that it comes with. So I desoldered the header pin and customised the rotary encoder to plug directly onto the board. alt text alt text