First Commit

This commit is contained in:
MindCreeper03
2025-02-27 19:31:50 +01:00
parent bcbb6aff9a
commit e490df1715
2470 changed files with 1479965 additions and 0 deletions

View File

@@ -0,0 +1,8 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
"version": "0.2.0",
"configurations": [
]
}

View File

@@ -0,0 +1,549 @@
#include <Arduino.h>
#include <Adafruit_SCD30.h>
#include <Adafruit_BME280.h>
#include "RTClib.h"
#include <Wire.h>
#include <U8g2lib.h>
#include <SPI.h>
#include <TFT_eSPI.h>
#include <SD.h>
#include <ESP32Time.h>
#include <WiFi.h>
#include <time.h>
#define INTERNAL_RTC_OFFSET 3600
#define X_OFFSET 3
#define BAUDRATE 57600
#define DATAPOINTS_ON_SCREEN 288
#define SCREEN_WIDTH 320
#define SCREEN_HEIGHT 240
#define FONT_SIZE 2
#define FONT_SIZE_LEGEND 1
#define CS_SD 5
#define CO2_COLOR TFT_BLUE
#define TEMP_COLOR TFT_RED
#define HUM_COLOR TFT_GREEN
#define CENTER_X SCREEN_WIDTH / 2 + 20
#define MODE_SWITCH 35 // 8
#define FORCE_REDRAW 34 // 11
#define SET_RTC 32 // 10
RTC_DS3231 rtc;
U8G2_SH1106_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/U8X8_PIN_NONE);
Adafruit_SCD30 scd30; //I2C
Adafruit_BME280 bme; // I2C
TFT_eSPI tft = TFT_eSPI();
File g_myFile;
ESP32Time rtc_internal(INTERNAL_RTC_OFFSET);
struct datapoint {
String time;
float temperature;
float humidity;
int co2;
};
String g_fileName = "";
const char* ssid = "Obi W(L)an Kenobi";
const char* password = "YTI2YWJjMjk3ZTUx";
const char* ntpServer = "de.pool.ntp.org";
const long gmtOffset_sec = 3600;
const int dayLightOffset_sec = 0;
datapoint ga_graphed_data[DATAPOINTS_ON_SCREEN];
int g_graphedIndex = 0;
String g_timeYear, g_timeMonth, g_timeDay, g_timeHour, g_timeMinute, g_timeSecond, g_timeStamp, g_date, g_time_hms, g_co2Data, g_humidData, g_tempData, g_timeDow, g_path, g_DataPoint;
datapoint g_currentData = { "", 0, 0, 0 };
int g_screenSelect = 0;
bool g_screenChangeFlag, g_modeSwitchActive, g_triggeredLogging, g_debounceSerialOut, g_debounceForceReDraw, g_debounceRTCSet, g_rtcError, g_debounceRtcError, g_IndexMisMatchReDraw, g_WiFiConnected;
int theoreticalIndex(datapoint point) {
return point.time.substring(11, 13).toInt() * 12 + floor(point.time.substring(14, 16).toInt() / 5);
}
void setRTC() {
bool gotString = false;
char inChar;
u8g2.clearDisplay();
u8g2.clearBuffer();
u8g2.drawStr(X_OFFSET, 10, "Setting Time via Serial");
u8g2.sendBuffer();
int year, month, day, hour, minute, second;
int j = 0;
int data[20];
while (!gotString) {
if (Serial.available()) {
inChar = Serial.read();
data[j] = char(inChar) - '0';
j += 1;
if (inChar == 'x') {
gotString = true;
}
}
}
Serial.println();
for (int i = 0; i < 20; i++) Serial.print(data[i]);
year = data[0] * 10 + data[1] + 2000;
// now month
month = data[2] * 10 + data[3];
// now date
day = data[4] * 10 + data[5];
// now hour
hour = data[6] * 10 + data[7];
// now minute
minute = data[8] * 10 + data[9];
// now second
second = data[10] * 10 + data[11];
rtc.adjust(DateTime(year, month, day, hour, minute, second));
Serial.println("Current Time: " + String(rtc.now().year()) + "-" + String(rtc.now().month()) + "-" + String(rtc.now().day()) + "--" + String(rtc.now().hour()) + ":" + String(rtc.now().minute()) + ":" + String(rtc.now().second()));
g_IndexMisMatchReDraw = true;
}
datapoint StrToDataPoint(String text) {
int StringCount = 0;
String strs[5];
while (text.length() > 0) {
int index = text.indexOf(';');
if (index == -1) {
strs[StringCount++] = text;
break;
} else {
strs[StringCount++] = text.substring(0, index);
text = text.substring(index + 1);
}
}
datapoint data = { strs[0], strs[1].toFloat(), strs[2].toFloat(), strs[3].toInt() };
return data;
}
void drawGraph(float data[288], int points, int type) {
float offset = 0;
int color = 0;
float scale = 0;
int max_y = 220;
int min_y = 20;
int last_y;
float raw_y;
int y;
points = min(points, 288);
switch (type) {
case 0: //co2
color = CO2_COLOR;
offset = -300;
scale = 0.22;
break;
case 1: //temp
color = TEMP_COLOR;
offset = -15;
scale = 10;
break;
case 2: //humidity
color = HUM_COLOR;
offset = 0;
scale = 2;
break;
}
for (int i = 0; i < points; i++) {
raw_y = floor((float(data[i]) + offset) * scale);
y = min(float(max_y), max_y - max(float(min_y), raw_y));
if (i) {
last_y = min(float(max_y), max_y - max(float(min_y), floor((float(data[i - 1]) + offset) * scale)));
} else {
last_y = y;
}
int x = i + 30;
if (i % 5 == 0) {
//Serial.println("Printed Pixel to X: "+String(x)+"; Y: "+String(y));
//Serial.println("Debug Data: Data Value: "+String(data[i]+offset)+"; Y-Raw: "+String(raw_y)+"; Scale: "+String(scale));
}
last_y = max(last_y, 20);
if (y < 20) {
tft.drawLine(x, 20, x, last_y, TFT_RED);
} else {
tft.drawLine(x, y, x, last_y, color);
}
}
}
void checkforData() {
int data;
g_graphedIndex = 0;
String dataString = "";
int StringCount = 0;
String strs[288];
datapoint point;
int new_index;
getTime();
g_myFile = SD.open(g_fileName.c_str());
if (!g_myFile) {
Serial.println("File read of " + g_fileName + " failed. returning to normal program routine");
return;
}
while (g_myFile.available()) {
data = g_myFile.read();
dataString += char(data);
//Serial.print(char(data));
if (dataString.endsWith("\n")) {
strs[StringCount++] = dataString;
//Serial.println(dataString);
dataString = "";
}
//ga_graphed_data[g_graphedIndex] = StrToDataPoint(data);
//g_graphedIndex++;
}
for (int i = 0; i < StringCount; i++) {
point = StrToDataPoint(strs[i]);
new_index = theoreticalIndex(point);
if (new_index > 288) {
Serial.println("Clock error ig");
new_index = 288;
}
if (new_index != g_graphedIndex) {
Serial.println("New Index: " + String(new_index) + " Graphed Index was: " + String(g_graphedIndex));
Serial.println("Indexing Error: Correcting Index");
g_graphedIndex = new_index;
}
//Serial.println(g_graphedIndex);
ga_graphed_data[g_graphedIndex] = point;
//Serial.println(strs[i]);
g_graphedIndex++;
}
g_myFile.close();
new_index = theoreticalIndex(g_currentData);
if (new_index > g_graphedIndex) {
g_graphedIndex = new_index;
Serial.println("Corrected Index");
}
Serial.println("Imported " + String(max(StringCount - 1, 0)) + " of " + String(new_index) + " Datapoints");
}
void synchTime(bool WiFiConnected) {
DateTime now = rtc.now();
if (WiFiConnected) {
configTime(gmtOffset_sec, dayLightOffset_sec, ntpServer);
struct tm timeinfo;
if (!getLocalTime(&timeinfo)) {
Serial.println("failed to get current time! Updating internal rtc from DS3231");
synchTime(false);
return;
}
Serial.println("Current time:");
Serial.println(&timeinfo, "%A, %B %d %Y %H:%M:%S");
if (getLocalTime(&timeinfo)) {
rtc_internal.setTimeStruct(timeinfo);
int now_hour;
if(rtc_internal.getHour(true)>0){
now_hour = rtc_internal.getHour(true)-1;
}
else{
now_hour = 23;
}
rtc.adjust(DateTime(rtc_internal.getYear(), rtc_internal.getMonth()+1, rtc_internal.getDay()-1, now_hour, rtc_internal.getMinute(), rtc_internal.getSecond()));
}
} else {
Serial.println("Updating internal rtc from DS3231");
int now_hour;
if(now.hour()>0){
now_hour = now.hour()-1;
}
else{
now_hour = 23;
}
rtc_internal.setTime(now.second(), now.minute(), now_hour, now.day(), now.month(), now.year()); //potential issue here
Serial.println(rtc_internal.getDateTime());
}
Serial.println("Synchronised Clocks");
}
void setup() {
// put your setup code here, to run once:
Serial.begin(BAUDRATE);
delay(5000);
while (!Serial) { ; };
Serial.flush();
if (!SD.begin(CS_SD)) {
Serial.println("Init of SD failed");
}
else{
Serial.println("SD Card initialised");
}
pinMode(MODE_SWITCH, INPUT);
pinMode(FORCE_REDRAW, INPUT);
pinMode(SET_RTC, INPUT);
Wire.begin();
tft.init();
tft.setRotation(1);
tft.fillScreen(TFT_BLACK);
tft.setTextColor(TFT_WHITE, TFT_BLACK);
u8g2.begin();
u8g2.clearDisplay();
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_courR08_tf);
g_screenChangeFlag = true;
if (!rtc.begin()) {
Serial.println("Could not find RTC! Check circuit.");
}
Wire.beginTransmission(0x68); // address DS3231
Wire.write(0x0E); // select CONTROL register
Wire.write(0b000011100); // write register (bit 7 is EOSC)
Wire.endTransmission();
Wire.beginTransmission(0x68);
Wire.write(0x0F); // select STATUS register
Wire.write(0b00001000); // write register (bit 7 is OSF)
Wire.endTransmission();
//rtc.adjust(DateTime(__DATE__, __TIME__));
scd30.begin();
bme.begin(0x76); //bme Sensor
if (!scd30.setMeasurementInterval(2)) {
Serial.println("Failed to Set Interval");
}
Serial.print("Measurement Interval: ");
Serial.print(scd30.getMeasurementInterval());
Serial.println(" seconds");
int wificheck = 10;
Serial.println("Connecting to WiFi...");
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED && wificheck) {
delay(1000);
wificheck--;
Serial.println("Connecting to WiFi...");
}
if (WiFi.status() == WL_CONNECTED) {
g_WiFiConnected = true;
Serial.println("Connected to WiFi");
} else {
g_WiFiConnected = false;
Serial.println("Not Connected to WiFi, synchronising with RTC");
}
delay(2000);
synchTime(g_WiFiConnected);
checkforData();
}
void fixRTCError() {
int t = 0;
Serial.println("RTC Error detected, Please reset over Serial or continue");
while (1) {
if (digitalRead(SET_RTC) == HIGH) {
setRTC();
break;
}
if (digitalRead(MODE_SWITCH) == HIGH || t == 60) break;
sleep(1);
t++;
}
Serial.println();
}
void getTime() {
DateTime now = rtc.now();
g_timeYear = String(now.year(), DEC);
g_timeMonth = String(now.month(), DEC);
g_timeDay = String(now.day(), DEC);
g_timeHour = String(now.hour(), DEC);
g_timeMinute = String(now.minute(), DEC);
g_timeSecond = String(now.second(), DEC);
if ((g_timeMonth.length()) == 1) { g_timeMonth = "0" + g_timeMonth; } // eine null voranstellen
if ((g_timeDay.length()) == 1) { g_timeDay = "0" + g_timeDay; }
if ((g_timeHour.length()) == 1) { g_timeHour = "0" + g_timeHour; }
if ((g_timeMinute.length()) == 1) { g_timeMinute = "0" + g_timeMinute; }
if ((g_timeSecond.length()) == 1) { g_timeSecond = "0" + g_timeSecond; }
if (g_date != g_timeDay + "." + g_timeMonth + "." + g_timeYear) {
g_date = g_timeDay + "." + g_timeMonth + "." + g_timeYear;
g_graphedIndex = 0;
g_screenChangeFlag = true;
}
g_time_hms = g_timeHour + ":" + g_timeMinute + ":" + g_timeSecond;
g_timeStamp = g_date + "-" + g_time_hms;
g_fileName = "/data_" + g_timeDay + "_" + g_timeMonth + "_" + g_timeYear + ".csv";
g_currentData.time = g_timeStamp;
}
void getSensorData() {
if (scd30.dataReady()) {
scd30.read();
g_currentData.co2 = scd30.CO2;
g_currentData.temperature = bme.readTemperature();
//pressure = bme.readPressure() / 100.0F;
g_currentData.humidity = bme.readHumidity();
//Serial.println(g_timeStamp+","+String(g_currentData.temperature)+","+String(g_currentData.humidity)+","+String(g_currentData.co2));
}
}
void drawOnScreen() {
if (g_screenChangeFlag) {
tft.fillScreen(TFT_BLACK);
tft.drawLine(29, 20, 29, 220, TFT_WHITE);
tft.drawLine(29, 220, 320, 220, TFT_WHITE);
for (int i = 0; i < 13; i++) {
if (i != 12) tft.drawCentreString(String(i * 2), 30 + i * 24, 227, FONT_SIZE_LEGEND);
tft.drawLine(30 + i * 24, 220, 30 + i * 24, 225, TFT_WHITE);
}
}
float data[288];
//small screen
u8g2.clearBuffer();
u8g2.drawStr(X_OFFSET, 10, (g_date + "-" + g_time_hms).c_str());
g_tempData = "Temp: " + String(g_currentData.temperature) + "C";
g_humidData = "Humid: " + String(g_currentData.humidity) + "%";
g_co2Data = "CO2: " + String(g_currentData.co2) + "ppm";
u8g2.drawStr(X_OFFSET, 19, g_tempData.c_str());
u8g2.drawStr(X_OFFSET, 28, g_humidData.c_str());
u8g2.drawStr(X_OFFSET, 37, g_co2Data.c_str());
u8g2.sendBuffer();
//big screen
switch (g_screenSelect) {
case 0: //co2
if (g_screenChangeFlag) {
Serial.println("showing CO2 Graph");
tft.drawCentreString("CO2 Concentration Statistics for today", CENTER_X, 5, FONT_SIZE);
tft.drawCentreString("ppm", 29, 10, FONT_SIZE_LEGEND);
g_screenChangeFlag = false;
tft.drawCentreString("500", 16, 197, FONT_SIZE_LEGEND);
tft.drawLine(24, 197, 29, 197, TFT_WHITE); //500
tft.drawCentreString("750", 16, 142, FONT_SIZE_LEGEND);
tft.drawLine(24, 142, 29, 142, TFT_WHITE); //1000
tft.drawCentreString("1000", 16, 86, FONT_SIZE_LEGEND);
tft.drawLine(29, 86, 320, 86, TFT_YELLOW); //Ab hier lüften
tft.drawLine(24, 86, 29, 86, TFT_WHITE); //1500
}
for (int i = 0; i < 288; i++) {
data[i] = ga_graphed_data[i].co2;
}
break;
case 1: //temp
if (g_screenChangeFlag) {
Serial.println("showing Temperature Graph");
tft.drawCentreString("Temperature Statistics for today", CENTER_X, 5, FONT_SIZE);
tft.drawCentreString("°C", 29, 10, FONT_SIZE_LEGEND);
g_screenChangeFlag = false;
tft.drawCentreString("20", 16, 170, FONT_SIZE_LEGEND);
tft.drawLine(24, 170, 29, 170, TFT_WHITE); //20
tft.drawCentreString("25", 16, 120, FONT_SIZE_LEGEND);
tft.drawLine(24, 120, 29, 120, TFT_WHITE); //25
tft.drawCentreString("30", 16, 70, FONT_SIZE_LEGEND);
tft.drawLine(24, 70, 29, 70, TFT_WHITE); //30
}
for (int i = 0; i < 288; i++) {
data[i] = ga_graphed_data[i].temperature;
}
break;
case 2: //humidity
if (g_screenChangeFlag) {
Serial.println("Showing Humidity Graph");
tft.drawCentreString("Humidity Statistics for today", CENTER_X, 5, FONT_SIZE);
tft.drawCentreString("%", 29, 10, FONT_SIZE_LEGEND);
g_screenChangeFlag = false;
}
for (int i = 0; i < 288; i++) {
data[i] = ga_graphed_data[i].humidity;
}
break;
//
default:
break;
}
drawGraph(data, g_graphedIndex, g_screenSelect);
}
void combineData() {
g_DataPoint = g_timeStamp + ";" + String(g_currentData.temperature) + ";" + String(g_currentData.humidity) + ";" + String(g_currentData.co2) + "\n";
Serial.print(g_DataPoint);
g_path = g_fileName;
int data;
String dataString = "";
g_myFile = SD.open(g_path.c_str());
while (g_myFile.available()) {
data = g_myFile.read();
dataString += char(data);
}
g_myFile.close();
g_myFile = SD.open(g_path.c_str(), FILE_WRITE);
if (!g_myFile) {
Serial.println("opening Log File for write failed - - - " + g_timeStamp);
}
g_myFile.print(dataString + g_DataPoint);
g_myFile.close();
Serial.println("Logging complete");
Serial.println("Current graphed index: " + String(g_graphedIndex));
}
void loop() {
if (rtc.lostPower()) {
Serial.println("RTC lost power at some point...");
}
if (digitalRead(MODE_SWITCH) == HIGH) { //LOW
if (!g_modeSwitchActive) {
g_screenSelect++;
g_screenChangeFlag = true;
if (g_screenSelect > 1) {
g_screenSelect = 0;
}
g_modeSwitchActive = true;
}
} else {
g_modeSwitchActive = false;
}
if (digitalRead(FORCE_REDRAW) == HIGH || g_IndexMisMatchReDraw) {
g_IndexMisMatchReDraw = false;
if (!g_debounceForceReDraw) {
checkforData();
g_screenChangeFlag = true;
drawOnScreen();
g_debounceForceReDraw = true;
}
} else {
g_debounceForceReDraw = false;
}
if (digitalRead(SET_RTC) == HIGH) {
if (!g_debounceRTCSet) {
setRTC();
g_debounceRTCSet = true;
}
} else {
g_debounceRTCSet = false;
}
getTime();
getSensorData();
g_rtcError = g_timeHour.toInt() > 23 || g_timeMinute.toInt() > 60 || g_timeSecond.toInt() > 60 || g_timeDay.toInt() > 31 || g_timeMonth.toInt() > 12;
if (g_rtcError) {
if (!g_debounceRtcError) {
g_debounceRtcError = true;
fixRTCError();
}
} else {
g_debounceRtcError = false;
}
if ((g_timeMinute.toInt() % 5 == 0) && g_timeSecond.toInt() == 0) {
if (!g_triggeredLogging) {
Serial.println("Logging current Data...");
combineData();
ga_graphed_data[g_graphedIndex] = { g_timeStamp, g_currentData.temperature, g_currentData.humidity, g_currentData.co2 };
if (g_graphedIndex + 2 < g_timeStamp.substring(11, 13).toInt() * 12 + floor(g_timeStamp.substring(14, 16).toInt() / 5)) {
g_IndexMisMatchReDraw = true;
Serial.println("Detected Mismatch in Indeces");
}
g_graphedIndex++;
if (g_graphedIndex > 287) {
for (int i = 1; i < 288; i++) {
ga_graphed_data[i - 1] = ga_graphed_data[i];
}
g_graphedIndex = 286;
g_screenChangeFlag = true;
}
g_triggeredLogging = true;
}
} else {
g_triggeredLogging = false;
}
if (g_timeSecond.toInt() % 2 == 0) {
if (!g_debounceSerialOut) {
drawOnScreen();
g_debounceSerialOut = true;
}
} else {
g_debounceSerialOut = false;
}
delay(20);
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,29 @@
from serial import Serial
import time
ser = Serial()
def getPortName() -> str:
return "COM"+input("Enter the number of the connected Port: ")
def getBaudRate() -> int:
return int(input("Enter the Baudrate you are using"))
def getTimeStamp() -> str:
current_time = time.strftime("%y%m%d%w%H%M%S")+"x" #YYMMDDwHHMMSS
print("Getting current Time")
return current_time
def main():
ser.port = getPortName()
if input("Are you using 57600 as baud rate ? (y/N)").lower() == "y":
ser.baudrate = 57600
else:
ser.baudrate = getBaudRate()
timestamp =getTimeStamp()
print(f"Opening port {ser.port} at baudrate {ser.baudrate}")
ser.open()
print("Sending current time to Port")
print(timestamp)
ser.write(timestamp.encode())
print("Closing Port")
ser.close()
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,128 @@
#include <Arduino.h>
#include <Adafruit_SCD30.h>
#include <Adafruit_BME280.h>
#include <DS3231.h>
#include <Wire.h>
#include <U8g2lib.h>
DS3231 RTC;
U8G2_SH1106_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
Adafruit_BME280 bme; // I2C
Adafruit_SCD30 scd30; //I2C
#define x_offset 3
#define datapoints_on_screen 128
struct datapoint{
String time;
float temperature;
float humidity;
int co2;
};
datapoint current_data = {"",0,0,0};
datapoint graphed_data[datapoints_on_screen];
bool h12_flag;
bool pm_flag;
bool century = false;
String year;
String month;
String day;
String hour;
String minute;
String second;
String timestamp;
String date;
String time_hms;
String co2data;
String humiddata;
String tempdata;
float temperature;
float humidity;
float pressure;
float co2;
int screenselect = 0;
void setup() {
// put your setup code here, to run once:
Wire.begin();
u8g2.begin();
u8g2.clearDisplay();
scd30.begin();
bme.begin(0x76); //bme Sensor
if(!scd30.setMeasurementInterval(2)){
Serial.println("Failed to Set Interval");
}
Serial.print("Measurement Interval: ");
Serial.print(scd30.getMeasurementInterval());
Serial.println(" seconds");
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_courR08_tf);
Serial.begin(57600);
}
String getTime(){
year = "20"+String(RTC.getYear(),DEC);
month = String(RTC.getMonth(century),DEC);
day= String(RTC.getDate(),DEC);
hour= String(RTC.getHour(h12_flag, pm_flag),DEC);
minute= String(RTC.getMinute(),DEC);
second= String(RTC.getSecond(),DEC);
if ((month.length()) == 1 ) {month= "0" + month;} // eine null voranstellen
if ((day.length()) == 1 ) {day= "0" + day;}
if ((hour.length()) == 1 ) {hour= "0" + hour;}
if ((minute.length()) == 1 ) {minute= "0" + minute;}
if ((second.length()) == 1 ) {second= "0" + second;}
date = day+"."+month+"."+year;
time_hms = hour+":"+minute+":"+second;
timestamp = date+"-"+time_hms;
current_data.time = timestamp;
return timestamp;
}
void getSensorData(){
current_data.temperature = bme.readTemperature();
pressure = bme.readPressure() / 100.0F;
current_data.humidity = bme.readHumidity();
if(scd30.dataReady()){
scd30.read();
current_data.co2 = scd30.CO2;
}
}
void drawOnScreen(){
switch(screenselect){
case 0:
u8g2.clearBuffer();
u8g2.drawStr(x_offset, 10, (date+"-"+time_hms).c_str());
tempdata = "Temp: "+String(current_data.temperature)+"C";
humiddata = "Humid: "+String(current_data.humidity)+"%";
co2data = "CO2: "+String(current_data.co2)+"ppm";
u8g2.drawStr(x_offset,19,tempdata.c_str());
u8g2.drawStr(x_offset,28,humiddata.c_str());
u8g2.drawStr(x_offset,37,co2data.c_str());
u8g2.sendBuffer();
break;
case 1:
Serial.println("Screen 1");
//Insert co2 graph
break;
case 2:
Serial.println("Screen 1");
break;
//
default:
break;
}
}
void combineData(){
String DataPoint = timestamp+","+String(current_data.temperature)+","+String(current_data.humidity)+","+String(current_data.co2);
Serial.println(DataPoint);
}
void loop() {
getSensorData();
getTime();
drawOnScreen();
combineData();
delay(1000);
}

View File

@@ -0,0 +1,115 @@
/*
DS3231_set.pde
Eric Ayars
4/11
Test of set-time routines for a DS3231 RTC
*/
#include <DS3231.h>
#include <Wire.h>
DS3231 myRTC;
byte year;
byte month;
byte date;
byte dOW;
byte hour;
byte minute;
byte second;
void getDateStuff(byte& year, byte& month, byte& date, byte& dOW,
byte& hour, byte& minute, byte& second) {
// Call this if you notice something coming in on
// the serial port. The stuff coming in should be in
// the order YYMMDDwHHMMSS, with an 'x' at the end.
boolean gotString = false;
char inChar;
byte temp1, temp2;
char inString[20];
byte j=0;
while (!gotString) {
if (Serial.available()) {
inChar = Serial.read();
inString[j] = inChar;
j += 1;
if (inChar == 'x') {
gotString = true;
}
}
}
Serial.println(inString);
// Read year first
temp1 = (byte)inString[0] -48;
temp2 = (byte)inString[1] -48;
year = temp1*10 + temp2;
// now month
temp1 = (byte)inString[2] -48;
temp2 = (byte)inString[3] -48;
month = temp1*10 + temp2;
// now date
temp1 = (byte)inString[4] -48;
temp2 = (byte)inString[5] -48;
date = temp1*10 + temp2;
// now Day of Week
dOW = (byte)inString[6] - 48;
// now hour
temp1 = (byte)inString[7] -48;
temp2 = (byte)inString[8] -48;
hour = temp1*10 + temp2;
// now minute
temp1 = (byte)inString[9] -48;
temp2 = (byte)inString[10] -48;
minute = temp1*10 + temp2;
// now second
temp1 = (byte)inString[11] -48;
temp2 = (byte)inString[12] -48;
second = temp1*10 + temp2;
}
void setup() {
// Start the serial port
Serial.begin(57600);
// Start the I2C interface
Wire.begin();
}
void loop() {
// If something is coming in on the serial line, it's
// a time correction so set the clock accordingly.
if (Serial.available()) {
getDateStuff(year, month, date, dOW, hour, minute, second);
myRTC.setClockMode(false); // set to 24h
//setClockMode(true); // set to 12h
myRTC.setYear(year);
myRTC.setMonth(month);
myRTC.setDate(date);
myRTC.setDoW(dOW);
myRTC.setHour(hour);
myRTC.setMinute(minute);
myRTC.setSecond(second);
Serial.print(year,DEC);
Serial.print("-");
Serial.print(month,DEC);
Serial.print("-");
Serial.print(date,DEC);
Serial.print("-");
Serial.print(hour,DEC);
Serial.print("-");
Serial.print(minute,DEC);
Serial.print("-");
Serial.println(second,DEC);
}
else{
Serial.println("No Serial connected");
}
delay(1000);
}

View File

@@ -0,0 +1,32 @@
//**** INCLUDES *************************************************************
//**** CONSTANTS ************************************************************
//**** PIN ASSIGNMENT OF OUR SHIELD *****************************************
static const int buttonLeft = D7;
static const int buttonRight = D6;
static const int ledBlue = D5;
static const int ledRed = D3;
static const int ldr = A0;
static const int buzzer = 26;
//**** SETUP ****************************************************************
void setup() {
Serial.begin(9600);
pinMode(buttonLeft, INPUT_PULLUP);
pinMode(buttonRight, INPUT_PULLUP);
pinMode(LED_BUILTIN, OUTPUT);
pinMode(ledBlue, OUTPUT);
pinMode(ledRed, OUTPUT);
pinMode(buzzer, OUTPUT);
pinMode(ldr, INPUT);
}
//**** LOOP *****************************************************************
void loop() {
int Brightness = map(analogRead(ldr), 0, 1023, 255, 0);
analogWrite(ledBlue, Brightness);
delay(70);
}

View File

@@ -0,0 +1,62 @@
//Display SCL,SDA
#include <U8g2lib.h> // Display 1.3" oder Display 0.96" - Library Includes all graphics procedures (https://github.com/olikraus/u8g2/)
#include <Arduino.h> //Standard Bibliothek
//Display 128x64 Pixel, umfangreiche grafische Funktionen
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
//Variablen für Ultraschall definieren
int trigger=0; //Trigger Pin GPIO0, D3, Ausgang
int echo=14; //Echo Pin GPIO14, D5, Eingang, Vorsicht nur 3,3V erlaubt
long dauer=0; //Zeit die eine Schallwelle bis zur Reflektion und zurück benötigt
long entfernung=0; //berechnete Entfernung
void setup() {
// put your setup code here, to run once:
Serial.begin(9600); //Seriellen Monitor vorbereiten
//Ultraschallsensor HC SR04
pinMode(trigger, OUTPUT); //Trigger Pin GPIO0, D3, Ausgang
pinMode(echo, INPUT); //Echo Pin GPIO14, D5, Eingang, Vorsicht nur 3,3V erlaubt
//Display vorbereiten
u8g2.begin();
u8g2.clearBuffer(); //Display löschen
u8g2.setFont(u8g2_font_courB10_tf); //Font (Schriftart) auswählen (Courier 10 pixel hoch) https://github.com/olikraus/u8g2/wiki/fntlistall
u8g2.drawStr(0,10,"Ultraschall"); //den Text am Display anzeigen, Position, x=0, y=10, angegeben in Pixeln
u8g2.sendBuffer(); //Übertragen aufs Display
delay(1000);
}
void loop() { //Hauptschleife
// put your main code here, to run repeatedly:
digitalWrite(trigger, LOW);
delay(5);
digitalWrite(trigger, HIGH); //Ultraschallwelle lossenden
delay(10); //dauer 10 Millisekunden
digitalWrite(trigger, LOW); //Ultraschall aus
dauer = pulseIn(echo, HIGH); //Zeit bis der Schall zurückkommt
entfernung = (dauer/2) * 0.03432; //Wert multipliziert man mit der Schallgeschwindigkeit in der Einheit Zentimeter/Mikrosekunde --> Entfernung in cm
if (entfernung >= 500 || entfernung <= 0) // die zwei senkrechten Zeichen || entsprechen einem 'oder'
{
Serial.println("Kein Messwert");
}
else
{
Serial.print("Entfernung ");
Serial.print(entfernung);
Serial.println(" cm");
}
delay(1000);
u8g2.clearBuffer(); //Display löschen
u8g2.drawStr(0, 10, "Entfernung"); //den Text am Display anzeigen, Position, x=0, y=10, angegeben in Pixeln
u8g2.setCursor (20,35); //Cusrsor setzen
u8g2.print(entfernung); //Variable anzeigen
u8g2.setCursor (50,35); //Cusrsor setzen
u8g2.print(" cm");
u8g2.sendBuffer(); //Übertragen aufs Display, Display updaten
delay(50);
}

View File

@@ -0,0 +1 @@
int trigger = 0

40
Sketches/SLE2/SLE2.ino Normal file
View File

@@ -0,0 +1,40 @@
//Display SCL,SDA
#include <U8g2lib.h> // Display 1.3" oder Display 0.96" - Library Includes all graphics procedures (https://github.com/olikraus/u8g2/)
#include <Arduino.h> //Standard Bibliothek
#include <OneWire.h> //onewire Bibliothek
#include <DallasTemperature.h> //Temperatur Sensor Dallas DS18B20
//Display 128x64 Pixel, umfangreiche grafische Funktionen
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
const unsigned char ONE_WIRE_BUS = 0; //Datenleitung für den onewire Bus, Digital Eingang 0, D3 festlegen
OneWire onewire(ONE_WIRE_BUS); //Variable onewire des Typs OneWire definieren
/*Variable sensoren des Typs DallasTemperature definieren, Adresse des Sensors wird dem onewire Bus übergeben,
OneWire ist eine Klasse in der Bibliothek, onewire ist ein Objekt*/
DallasTemperature sensoren(&onewire);
void setup() {
// put your setup code here, to run once:
Serial.begin(9600); //Seriellen Monitor vorbereiten
sensoren.begin();
int n=sensoren.getDeviceCount(); //Anzahl der gefundenen Sensoren am onewire Bus in der integer Variablen n ablegen
//Display vorbereiten
u8g2.begin();
u8g2.clearBuffer(); //Display löschen
u8g2.setFont(u8g2_font_courB10_tf); //Font (Schriftart) auswählen (Courier 10 pixel hoch) https://github.com/olikraus/u8g2/wiki/fntlistall
u8g2.drawStr(0,10,"Anzahl der"); //den Text am Display anzeigen, Position, x=0, y=10, angegeben in Pixeln
u8g2.drawStr(0,25,"Sensoren"); //den Text am Display anzeigen, Position, x=0, y=25, angegeben in Pixeln
u8g2.setCursor (40,50); //Cusrsor setzen
u8g2.print(n); // die Variable n anzeigen
u8g2.sendBuffer(); //Übertragen aufs Display
delay(1000);
}
void loop() { //Hauptschleife
// put your main code here, to run repeatedly:
delay(2000);
}

80
bme680test/bme680test.ino Normal file
View File

@@ -0,0 +1,80 @@
/***************************************************************************
This is a library for the BME680 gas, humidity, temperature & pressure sensor
Designed specifically to work with the Adafruit BME680 Breakout
----> http://www.adafruit.com/products/3660
These sensors use I2C or SPI to communicate, 2 or 4 pins are required
to interface.
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 & Kevin Townsend for Adafruit Industries.
BSD license, all text above must be included in any redistribution
***************************************************************************/
#include <Wire.h>
#include <SPI.h>
#include <Adafruit_Sensor.h>
#include "Adafruit_BME680.h"
#define BME_SCK 13
#define BME_MISO 12
#define BME_MOSI 11
#define BME_CS 10
#define SEALEVELPRESSURE_HPA (1013.25)
Adafruit_BME680 bme(&Wire); // I2C
//Adafruit_BME680 bme(&Wire1); // example of I2C on another bus
//Adafruit_BME680 bme(BME_CS); // hardware SPI
//Adafruit_BME680 bme(BME_CS, BME_MOSI, BME_MISO, BME_SCK);
void setup() {
Serial.begin(57600);
while (!Serial);
Serial.println(F("BME680 test"));
if (!bme.begin(118)) {
Serial.println("Could not find a valid BME680 sensor, check wiring!");
while (1);
}
// Set up oversampling and filter initialization
bme.setTemperatureOversampling(BME680_OS_8X);
bme.setHumidityOversampling(BME680_OS_2X);
bme.setPressureOversampling(BME680_OS_4X);
bme.setIIRFilterSize(BME680_FILTER_SIZE_3);
bme.setGasHeater(320, 150); // 320*C for 150 ms
}
void loop() {
if (! bme.performReading()) {
Serial.println("Failed to perform reading :(");
return;
}
Serial.print("Temperature = ");
Serial.print(bme.temperature);
Serial.println(" *C");
Serial.print("Pressure = ");
Serial.print(bme.pressure / 100.0);
Serial.println(" hPa");
Serial.print("Humidity = ");
Serial.print(bme.humidity);
Serial.println(" %");
Serial.print("Gas = ");
Serial.print(bme.gas_resistance / 1000.0);
Serial.println(" KOhms");
Serial.print("Approx. Altitude = ");
Serial.print(bme.readAltitude(SEALEVELPRESSURE_HPA));
Serial.println(" m");
Serial.println();
delay(2000);
}

1857
bsec_iot_example/bme68x.c Normal file

File diff suppressed because it is too large Load Diff

323
bsec_iot_example/bme68x.h Normal file
View File

@@ -0,0 +1,323 @@
/**
* Copyright (c) 2023 Bosch Sensortec GmbH. All rights reserved.
*
* BSD-3-Clause
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @file bme68x.h
* @date 2023-02-07
* @version v4.4.8
*
*/
/*!
* @defgroup bme68x BME68X
* @brief <a href="https://www.bosch-sensortec.com/bst/products/all_products/bme680">Product Overview</a>
* and <a href="https://github.com/BoschSensortec/BME68x-Sensor-API">Sensor API Source Code</a>
*/
#ifndef BME68X_H_
#define BME68X_H_
#include "bme68x_defs.h"
/* CPP guard */
#ifdef __cplusplus
extern "C" {
#endif
/**
* \ingroup bme68x
* \defgroup bme68xApiInit Initialization
* @brief Initialize the sensor and device structure
*/
/*!
* \ingroup bme68xApiInit
* \page bme68x_api_bme68x_init bme68x_init
* \code
* int8_t bme68x_init(struct bme68x_dev *dev);
* \endcode
* @details This API reads the chip-id of the sensor which is the first step to
* verify the sensor and also calibrates the sensor
* As this API is the entry point, call this API before using other APIs.
*
* @param[in,out] dev : Structure instance of bme68x_dev
*
* @return Result of API execution status
* @retval 0 -> Success
* @retval < 0 -> Fail
*/
int8_t bme68x_init(struct bme68x_dev *dev);
/**
* \ingroup bme68x
* \defgroup bme68xApiRegister Registers
* @brief Generic API for accessing sensor registers
*/
/*!
* \ingroup bme68xApiRegister
* \page bme68x_api_bme68x_set_regs bme68x_set_regs
* \code
* int8_t bme68x_set_regs(const uint8_t reg_addr, const uint8_t *reg_data, uint32_t len, struct bme68x_dev *dev)
* \endcode
* @details This API writes the given data to the register address of the sensor
*
* @param[in] reg_addr : Register addresses to where the data is to be written
* @param[in] reg_data : Pointer to data buffer which is to be written
* in the reg_addr of sensor.
* @param[in] len : No of bytes of data to write
* @param[in,out] dev : Structure instance of bme68x_dev
*
* @return Result of API execution status
* @retval 0 -> Success
* @retval < 0 -> Fail
*/
int8_t bme68x_set_regs(const uint8_t *reg_addr, const uint8_t *reg_data, uint32_t len, struct bme68x_dev *dev);
/*!
* \ingroup bme68xApiRegister
* \page bme68x_api_bme68x_get_regs bme68x_get_regs
* \code
* int8_t bme68x_get_regs(uint8_t reg_addr, uint8_t *reg_data, uint32_t len, struct bme68x_dev *dev)
* \endcode
* @details This API reads the data from the given register address of sensor.
*
* @param[in] reg_addr : Register address from where the data to be read
* @param[out] reg_data : Pointer to data buffer to store the read data.
* @param[in] len : No of bytes of data to be read.
* @param[in,out] dev : Structure instance of bme68x_dev.
*
* @return Result of API execution status
* @retval 0 -> Success
* @retval < 0 -> Fail
*/
int8_t bme68x_get_regs(uint8_t reg_addr, uint8_t *reg_data, uint32_t len, struct bme68x_dev *dev);
/**
* \ingroup bme68x
* \defgroup bme68xApiSystem System
* @brief API that performs system-level operations
*/
/*!
* \ingroup bme68xApiSystem
* \page bme68x_api_bme68x_soft_reset bme68x_soft_reset
* \code
* int8_t bme68x_soft_reset(struct bme68x_dev *dev);
* \endcode
* @details This API soft-resets the sensor.
*
* @param[in,out] dev : Structure instance of bme68x_dev.
*
* @return Result of API execution status
* @retval 0 -> Success
* @retval < 0 -> Fail
*/
int8_t bme68x_soft_reset(struct bme68x_dev *dev);
/**
* \ingroup bme68x
* \defgroup bme68xApiOm Operation mode
* @brief API to configure operation mode
*/
/*!
* \ingroup bme68xApiOm
* \page bme68x_api_bme68x_set_op_mode bme68x_set_op_mode
* \code
* int8_t bme68x_set_op_mode(const uint8_t op_mode, struct bme68x_dev *dev);
* \endcode
* @details This API is used to set the operation mode of the sensor
* @param[in] op_mode : Desired operation mode.
* @param[in] dev : Structure instance of bme68x_dev
*
* @return Result of API execution status
* @retval 0 -> Success
* @retval < 0 -> Fail
*/
int8_t bme68x_set_op_mode(const uint8_t op_mode, struct bme68x_dev *dev);
/*!
* \ingroup bme68xApiOm
* \page bme68x_api_bme68x_get_op_mode bme68x_get_op_mode
* \code
* int8_t bme68x_get_op_mode(uint8_t *op_mode, struct bme68x_dev *dev);
* \endcode
* @details This API is used to get the operation mode of the sensor.
*
* @param[out] op_mode : Desired operation mode.
* @param[in,out] dev : Structure instance of bme68x_dev
*
* @return Result of API execution status
* @retval 0 -> Success
* @retval < 0 -> Fail
*/
int8_t bme68x_get_op_mode(uint8_t *op_mode, struct bme68x_dev *dev);
/*!
* \ingroup bme68xApiConfig
* \page bme68x_api_bme68x_get_meas_dur bme68x_get_meas_dur
* \code
* uint32_t bme68x_get_meas_dur(const uint8_t op_mode, struct bme68x_conf *conf, struct bme68x_dev *dev);
* \endcode
* @details This API is used to get the remaining duration that can be used for heating.
*
* @param[in] op_mode : Desired operation mode.
* @param[in] conf : Desired sensor configuration.
* @param[in] dev : Structure instance of bme68x_dev
*
* @return Measurement duration calculated in microseconds
*/
uint32_t bme68x_get_meas_dur(const uint8_t op_mode, struct bme68x_conf *conf, struct bme68x_dev *dev);
/**
* \ingroup bme68x
* \defgroup bme68xApiData Data Read out
* @brief Read our data from the sensor
*/
/*!
* \ingroup bme68xApiData
* \page bme68x_api_bme68x_get_data bme68x_get_data
* \code
* int8_t bme68x_get_data(uint8_t op_mode, struct bme68x_data *data, uint8_t *n_data, struct bme68x_dev *dev);
* \endcode
* @details This API reads the pressure, temperature and humidity and gas data
* from the sensor, compensates the data and store it in the bme68x_data
* structure instance passed by the user.
*
* @param[in] op_mode : Expected operation mode.
* @param[out] data : Structure instance to hold the data.
* @param[out] n_data : Number of data instances available.
* @param[in,out] dev : Structure instance of bme68x_dev
*
* @return Result of API execution status
* @retval 0 -> Success
* @retval < 0 -> Fail
*/
int8_t bme68x_get_data(uint8_t op_mode, struct bme68x_data *data, uint8_t *n_data, struct bme68x_dev *dev);
/**
* \ingroup bme68x
* \defgroup bme68xApiConfig Configuration
* @brief Configuration API of sensor
*/
/*!
* \ingroup bme68xApiConfig
* \page bme68x_api_bme68x_set_conf bme68x_set_conf
* \code
* int8_t bme68x_set_conf(struct bme68x_conf *conf, struct bme68x_dev *dev);
* \endcode
* @details This API is used to set the oversampling, filter and odr configuration
*
* @param[in] conf : Desired sensor configuration.
* @param[in,out] dev : Structure instance of bme68x_dev.
*
* @return Result of API execution status
* @retval 0 -> Success
* @retval < 0 -> Fail
*/
int8_t bme68x_set_conf(struct bme68x_conf *conf, struct bme68x_dev *dev);
/*!
* \ingroup bme68xApiConfig
* \page bme68x_api_bme68x_get_conf bme68x_get_conf
* \code
* int8_t bme68x_get_conf(struct bme68x_conf *conf, struct bme68x_dev *dev);
* \endcode
* @details This API is used to get the oversampling, filter and odr
* configuration
*
* @param[out] conf : Present sensor configuration.
* @param[in,out] dev : Structure instance of bme68x_dev.
*
* @return Result of API execution status
* @retval 0 -> Success
* @retval < 0 -> Fail
*/
int8_t bme68x_get_conf(struct bme68x_conf *conf, struct bme68x_dev *dev);
/*!
* \ingroup bme68xApiConfig
* \page bme68x_api_bme68x_set_heatr_conf bme68x_set_heatr_conf
* \code
* int8_t bme68x_set_heatr_conf(uint8_t op_mode, const struct bme68x_heatr_conf *conf, struct bme68x_dev *dev);
* \endcode
* @details This API is used to set the gas configuration of the sensor.
*
* @param[in] op_mode : Expected operation mode of the sensor.
* @param[in] conf : Desired heating configuration.
* @param[in,out] dev : Structure instance of bme68x_dev.
*
* @return Result of API execution status
* @retval 0 -> Success
* @retval < 0 -> Fail
*/
int8_t bme68x_set_heatr_conf(uint8_t op_mode, const struct bme68x_heatr_conf *conf, struct bme68x_dev *dev);
/*!
* \ingroup bme68xApiConfig
* \page bme68x_api_bme68x_get_heatr_conf bme68x_get_heatr_conf
* \code
* int8_t bme68x_get_heatr_conf(const struct bme68x_heatr_conf *conf, struct bme68x_dev *dev);
* \endcode
* @details This API is used to get the gas configuration of the sensor.
*
* @param[out] conf : Current configurations of the gas sensor.
* @param[in,out] dev : Structure instance of bme68x_dev.
*
* @return Result of API execution status
* @retval 0 -> Success
* @retval < 0 -> Fail
*/
int8_t bme68x_get_heatr_conf(const struct bme68x_heatr_conf *conf, struct bme68x_dev *dev);
/*!
* \ingroup bme68xApiSystem
* \page bme68x_api_bme68x_selftest_check bme68x_selftest_check
* \code
* int8_t bme68x_selftest_check(const struct bme68x_dev *dev);
* \endcode
* @details This API performs Self-test of low gas variant of BME68X
*
* @param[in, out] dev : Structure instance of bme68x_dev
*
* @return Result of API execution status
* @retval 0 -> Success
* @retval < 0 -> Fail
*/
int8_t bme68x_selftest_check(const struct bme68x_dev *dev);
#ifdef __cplusplus
}
#endif /* End of CPP guard */
#endif /* BME68X_H_ */

View File

@@ -0,0 +1,972 @@
/**
* Copyright (c) 2023 Bosch Sensortec GmbH. All rights reserved.
*
* BSD-3-Clause
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @file bme68x_defs.h
* @date 2023-02-07
* @version v4.4.8
*
*/
/*! @cond DOXYGEN_SUPRESS */
#ifndef BME68X_DEFS_H_
#define BME68X_DEFS_H_
/********************************************************* */
/*! Header includes */
/********************************************************* */
#ifdef __KERNEL__
#include <linux/types.h>
#include <linux/kernel.h>
#else
#include <stdint.h>
#include <stddef.h>
#endif
/********************************************************* */
/*! Common Macros */
/********************************************************* */
#ifdef __KERNEL__
#if !defined(UINT8_C) && !defined(INT8_C)
#define INT8_C(x) S8_C(x)
#define UINT8_C(x) U8_C(x)
#endif
#if !defined(UINT16_C) && !defined(INT16_C)
#define INT16_C(x) S16_C(x)
#define UINT16_C(x) U16_C(x)
#endif
#if !defined(INT32_C) && !defined(UINT32_C)
#define INT32_C(x) S32_C(x)
#define UINT32_C(x) U32_C(x)
#endif
#if !defined(INT64_C) && !defined(UINT64_C)
#define INT64_C(x) S64_C(x)
#define UINT64_C(x) U64_C(x)
#endif
#endif
/*! C standard macros */
#ifndef NULL
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void *) 0)
#endif
#endif
#ifndef BME68X_DO_NOT_USE_FPU
/* Comment or un-comment the macro to provide floating point data output */
#define BME68X_USE_FPU
#endif
/* Period between two polls (value can be given by user) */
#ifndef BME68X_PERIOD_POLL
#define BME68X_PERIOD_POLL UINT32_C(10000)
#endif
/* BME68X unique chip identifier */
#define BME68X_CHIP_ID UINT8_C(0x61)
/* Period for a soft reset */
#define BME68X_PERIOD_RESET UINT32_C(10000)
/* BME68X lower I2C address */
#define BME68X_I2C_ADDR_LOW UINT8_C(0x76)
/* BME68X higher I2C address */
#define BME68X_I2C_ADDR_HIGH UINT8_C(0x77)
/* Soft reset command */
#define BME68X_SOFT_RESET_CMD UINT8_C(0xb6)
/* Return code definitions */
/* Success */
#define BME68X_OK INT8_C(0)
/* Errors */
/* Null pointer passed */
#define BME68X_E_NULL_PTR INT8_C(-1)
/* Communication failure */
#define BME68X_E_COM_FAIL INT8_C(-2)
/* Sensor not found */
#define BME68X_E_DEV_NOT_FOUND INT8_C(-3)
/* Incorrect length parameter */
#define BME68X_E_INVALID_LENGTH INT8_C(-4)
/* Self test fail error */
#define BME68X_E_SELF_TEST INT8_C(-5)
/* Warnings */
/* Define a valid operation mode */
#define BME68X_W_DEFINE_OP_MODE INT8_C(1)
/* No new data was found */
#define BME68X_W_NO_NEW_DATA INT8_C(2)
/* Define the shared heating duration */
#define BME68X_W_DEFINE_SHD_HEATR_DUR INT8_C(3)
/* Information - only available via bme68x_dev.info_msg */
#define BME68X_I_PARAM_CORR UINT8_C(1)
/* Register map addresses in I2C */
/* Register for 3rd group of coefficients */
#define BME68X_REG_COEFF3 UINT8_C(0x00)
/* 0th Field address*/
#define BME68X_REG_FIELD0 UINT8_C(0x1d)
/* 0th Current DAC address*/
#define BME68X_REG_IDAC_HEAT0 UINT8_C(0x50)
/* 0th Res heat address */
#define BME68X_REG_RES_HEAT0 UINT8_C(0x5a)
/* 0th Gas wait address */
#define BME68X_REG_GAS_WAIT0 UINT8_C(0x64)
/* Shared heating duration address */
#define BME68X_REG_SHD_HEATR_DUR UINT8_C(0x6E)
/* CTRL_GAS_0 address */
#define BME68X_REG_CTRL_GAS_0 UINT8_C(0x70)
/* CTRL_GAS_1 address */
#define BME68X_REG_CTRL_GAS_1 UINT8_C(0x71)
/* CTRL_HUM address */
#define BME68X_REG_CTRL_HUM UINT8_C(0x72)
/* CTRL_MEAS address */
#define BME68X_REG_CTRL_MEAS UINT8_C(0x74)
/* CONFIG address */
#define BME68X_REG_CONFIG UINT8_C(0x75)
/* MEM_PAGE address */
#define BME68X_REG_MEM_PAGE UINT8_C(0xf3)
/* Unique ID address */
#define BME68X_REG_UNIQUE_ID UINT8_C(0x83)
/* Register for 1st group of coefficients */
#define BME68X_REG_COEFF1 UINT8_C(0x8a)
/* Chip ID address */
#define BME68X_REG_CHIP_ID UINT8_C(0xd0)
/* Soft reset address */
#define BME68X_REG_SOFT_RESET UINT8_C(0xe0)
/* Register for 2nd group of coefficients */
#define BME68X_REG_COEFF2 UINT8_C(0xe1)
/* Variant ID Register */
#define BME68X_REG_VARIANT_ID UINT8_C(0xF0)
/* Enable/Disable macros */
/* Enable */
#define BME68X_ENABLE UINT8_C(0x01)
/* Disable */
#define BME68X_DISABLE UINT8_C(0x00)
/* Variant ID macros */
/* Low Gas variant */
#define BME68X_VARIANT_GAS_LOW UINT8_C(0x00)
/* High Gas variant */
#define BME68X_VARIANT_GAS_HIGH UINT8_C(0x01)
/* Oversampling setting macros */
/* Switch off measurement */
#define BME68X_OS_NONE UINT8_C(0)
/* Perform 1 measurement */
#define BME68X_OS_1X UINT8_C(1)
/* Perform 2 measurements */
#define BME68X_OS_2X UINT8_C(2)
/* Perform 4 measurements */
#define BME68X_OS_4X UINT8_C(3)
/* Perform 8 measurements */
#define BME68X_OS_8X UINT8_C(4)
/* Perform 16 measurements */
#define BME68X_OS_16X UINT8_C(5)
/* IIR Filter settings */
/* Switch off the filter */
#define BME68X_FILTER_OFF UINT8_C(0)
/* Filter coefficient of 2 */
#define BME68X_FILTER_SIZE_1 UINT8_C(1)
/* Filter coefficient of 4 */
#define BME68X_FILTER_SIZE_3 UINT8_C(2)
/* Filter coefficient of 8 */
#define BME68X_FILTER_SIZE_7 UINT8_C(3)
/* Filter coefficient of 16 */
#define BME68X_FILTER_SIZE_15 UINT8_C(4)
/* Filter coefficient of 32 */
#define BME68X_FILTER_SIZE_31 UINT8_C(5)
/* Filter coefficient of 64 */
#define BME68X_FILTER_SIZE_63 UINT8_C(6)
/* Filter coefficient of 128 */
#define BME68X_FILTER_SIZE_127 UINT8_C(7)
/* ODR/Standby time macros */
/* Standby time of 0.59ms */
#define BME68X_ODR_0_59_MS UINT8_C(0)
/* Standby time of 62.5ms */
#define BME68X_ODR_62_5_MS UINT8_C(1)
/* Standby time of 125ms */
#define BME68X_ODR_125_MS UINT8_C(2)
/* Standby time of 250ms */
#define BME68X_ODR_250_MS UINT8_C(3)
/* Standby time of 500ms */
#define BME68X_ODR_500_MS UINT8_C(4)
/* Standby time of 1s */
#define BME68X_ODR_1000_MS UINT8_C(5)
/* Standby time of 10ms */
#define BME68X_ODR_10_MS UINT8_C(6)
/* Standby time of 20ms */
#define BME68X_ODR_20_MS UINT8_C(7)
/* No standby time */
#define BME68X_ODR_NONE UINT8_C(8)
/* Operating mode macros */
/* Sleep operation mode */
#define BME68X_SLEEP_MODE UINT8_C(0)
/* Forced operation mode */
#define BME68X_FORCED_MODE UINT8_C(1)
/* Parallel operation mode */
#define BME68X_PARALLEL_MODE UINT8_C(2)
/* Sequential operation mode */
#define BME68X_SEQUENTIAL_MODE UINT8_C(3)
/* SPI page macros */
/* SPI memory page 0 */
#define BME68X_MEM_PAGE0 UINT8_C(0x10)
/* SPI memory page 1 */
#define BME68X_MEM_PAGE1 UINT8_C(0x00)
/* Coefficient index macros */
/* Length for all coefficients */
#define BME68X_LEN_COEFF_ALL UINT8_C(42)
/* Length for 1st group of coefficients */
#define BME68X_LEN_COEFF1 UINT8_C(23)
/* Length for 2nd group of coefficients */
#define BME68X_LEN_COEFF2 UINT8_C(14)
/* Length for 3rd group of coefficients */
#define BME68X_LEN_COEFF3 UINT8_C(5)
/* Length of the field */
#define BME68X_LEN_FIELD UINT8_C(17)
/* Length between two fields */
#define BME68X_LEN_FIELD_OFFSET UINT8_C(17)
/* Length of the configuration register */
#define BME68X_LEN_CONFIG UINT8_C(5)
/* Length of the interleaved buffer */
#define BME68X_LEN_INTERLEAVE_BUFF UINT8_C(20)
/* Coefficient index macros */
/* Coefficient T2 LSB position */
#define BME68X_IDX_T2_LSB (0)
/* Coefficient T2 MSB position */
#define BME68X_IDX_T2_MSB (1)
/* Coefficient T3 position */
#define BME68X_IDX_T3 (2)
/* Coefficient P1 LSB position */
#define BME68X_IDX_P1_LSB (4)
/* Coefficient P1 MSB position */
#define BME68X_IDX_P1_MSB (5)
/* Coefficient P2 LSB position */
#define BME68X_IDX_P2_LSB (6)
/* Coefficient P2 MSB position */
#define BME68X_IDX_P2_MSB (7)
/* Coefficient P3 position */
#define BME68X_IDX_P3 (8)
/* Coefficient P4 LSB position */
#define BME68X_IDX_P4_LSB (10)
/* Coefficient P4 MSB position */
#define BME68X_IDX_P4_MSB (11)
/* Coefficient P5 LSB position */
#define BME68X_IDX_P5_LSB (12)
/* Coefficient P5 MSB position */
#define BME68X_IDX_P5_MSB (13)
/* Coefficient P7 position */
#define BME68X_IDX_P7 (14)
/* Coefficient P6 position */
#define BME68X_IDX_P6 (15)
/* Coefficient P8 LSB position */
#define BME68X_IDX_P8_LSB (18)
/* Coefficient P8 MSB position */
#define BME68X_IDX_P8_MSB (19)
/* Coefficient P9 LSB position */
#define BME68X_IDX_P9_LSB (20)
/* Coefficient P9 MSB position */
#define BME68X_IDX_P9_MSB (21)
/* Coefficient P10 position */
#define BME68X_IDX_P10 (22)
/* Coefficient H2 MSB position */
#define BME68X_IDX_H2_MSB (23)
/* Coefficient H2 LSB position */
#define BME68X_IDX_H2_LSB (24)
/* Coefficient H1 LSB position */
#define BME68X_IDX_H1_LSB (24)
/* Coefficient H1 MSB position */
#define BME68X_IDX_H1_MSB (25)
/* Coefficient H3 position */
#define BME68X_IDX_H3 (26)
/* Coefficient H4 position */
#define BME68X_IDX_H4 (27)
/* Coefficient H5 position */
#define BME68X_IDX_H5 (28)
/* Coefficient H6 position */
#define BME68X_IDX_H6 (29)
/* Coefficient H7 position */
#define BME68X_IDX_H7 (30)
/* Coefficient T1 LSB position */
#define BME68X_IDX_T1_LSB (31)
/* Coefficient T1 MSB position */
#define BME68X_IDX_T1_MSB (32)
/* Coefficient GH2 LSB position */
#define BME68X_IDX_GH2_LSB (33)
/* Coefficient GH2 MSB position */
#define BME68X_IDX_GH2_MSB (34)
/* Coefficient GH1 position */
#define BME68X_IDX_GH1 (35)
/* Coefficient GH3 position */
#define BME68X_IDX_GH3 (36)
/* Coefficient res heat value position */
#define BME68X_IDX_RES_HEAT_VAL (37)
/* Coefficient res heat range position */
#define BME68X_IDX_RES_HEAT_RANGE (39)
/* Coefficient range switching error position */
#define BME68X_IDX_RANGE_SW_ERR (41)
/* Gas measurement macros */
/* Disable gas measurement */
#define BME68X_DISABLE_GAS_MEAS UINT8_C(0x00)
/* Enable gas measurement low */
#define BME68X_ENABLE_GAS_MEAS_L UINT8_C(0x01)
/* Enable gas measurement high */
#define BME68X_ENABLE_GAS_MEAS_H UINT8_C(0x02)
/* Heater control macros */
/* Enable heater */
#define BME68X_ENABLE_HEATER UINT8_C(0x00)
/* Disable heater */
#define BME68X_DISABLE_HEATER UINT8_C(0x01)
#ifdef BME68X_USE_FPU
/* 0 degree Celsius */
#define BME68X_MIN_TEMPERATURE INT16_C(0)
/* 60 degree Celsius */
#define BME68X_MAX_TEMPERATURE INT16_C(60)
/* 900 hecto Pascals */
#define BME68X_MIN_PRESSURE UINT32_C(90000)
/* 1100 hecto Pascals */
#define BME68X_MAX_PRESSURE UINT32_C(110000)
/* 20% relative humidity */
#define BME68X_MIN_HUMIDITY UINT32_C(20)
/* 80% relative humidity*/
#define BME68X_MAX_HUMIDITY UINT32_C(80)
#else
/* 0 degree Celsius */
#define BME68X_MIN_TEMPERATURE INT16_C(0)
/* 60 degree Celsius */
#define BME68X_MAX_TEMPERATURE INT16_C(6000)
/* 900 hecto Pascals */
#define BME68X_MIN_PRESSURE UINT32_C(90000)
/* 1100 hecto Pascals */
#define BME68X_MAX_PRESSURE UINT32_C(110000)
/* 20% relative humidity */
#define BME68X_MIN_HUMIDITY UINT32_C(20000)
/* 80% relative humidity*/
#define BME68X_MAX_HUMIDITY UINT32_C(80000)
#endif
#define BME68X_HEATR_DUR1 UINT16_C(1000)
#define BME68X_HEATR_DUR2 UINT16_C(2000)
#define BME68X_HEATR_DUR1_DELAY UINT32_C(1000000)
#define BME68X_HEATR_DUR2_DELAY UINT32_C(2000000)
#define BME68X_N_MEAS UINT8_C(6)
#define BME68X_LOW_TEMP UINT8_C(150)
#define BME68X_HIGH_TEMP UINT16_C(350)
/* Mask macros */
/* Mask for number of conversions */
#define BME68X_NBCONV_MSK UINT8_C(0X0f)
/* Mask for IIR filter */
#define BME68X_FILTER_MSK UINT8_C(0X1c)
/* Mask for ODR[3] */
#define BME68X_ODR3_MSK UINT8_C(0x80)
/* Mask for ODR[2:0] */
#define BME68X_ODR20_MSK UINT8_C(0xe0)
/* Mask for temperature oversampling */
#define BME68X_OST_MSK UINT8_C(0Xe0)
/* Mask for pressure oversampling */
#define BME68X_OSP_MSK UINT8_C(0X1c)
/* Mask for humidity oversampling */
#define BME68X_OSH_MSK UINT8_C(0X07)
/* Mask for heater control */
#define BME68X_HCTRL_MSK UINT8_C(0x08)
/* Mask for run gas */
#define BME68X_RUN_GAS_MSK UINT8_C(0x30)
/* Mask for operation mode */
#define BME68X_MODE_MSK UINT8_C(0x03)
/* Mask for res heat range */
#define BME68X_RHRANGE_MSK UINT8_C(0x30)
/* Mask for range switching error */
#define BME68X_RSERROR_MSK UINT8_C(0xf0)
/* Mask for new data */
#define BME68X_NEW_DATA_MSK UINT8_C(0x80)
/* Mask for gas index */
#define BME68X_GAS_INDEX_MSK UINT8_C(0x0f)
/* Mask for gas range */
#define BME68X_GAS_RANGE_MSK UINT8_C(0x0f)
/* Mask for gas measurement valid */
#define BME68X_GASM_VALID_MSK UINT8_C(0x20)
/* Mask for heater stability */
#define BME68X_HEAT_STAB_MSK UINT8_C(0x10)
/* Mask for SPI memory page */
#define BME68X_MEM_PAGE_MSK UINT8_C(0x10)
/* Mask for reading a register in SPI */
#define BME68X_SPI_RD_MSK UINT8_C(0x80)
/* Mask for writing a register in SPI */
#define BME68X_SPI_WR_MSK UINT8_C(0x7f)
/* Mask for the H1 calibration coefficient */
#define BME68X_BIT_H1_DATA_MSK UINT8_C(0x0f)
/* Position macros */
/* Filter bit position */
#define BME68X_FILTER_POS UINT8_C(2)
/* Temperature oversampling bit position */
#define BME68X_OST_POS UINT8_C(5)
/* Pressure oversampling bit position */
#define BME68X_OSP_POS UINT8_C(2)
/* ODR[3] bit position */
#define BME68X_ODR3_POS UINT8_C(7)
/* ODR[2:0] bit position */
#define BME68X_ODR20_POS UINT8_C(5)
/* Run gas bit position */
#define BME68X_RUN_GAS_POS UINT8_C(4)
/* Heater control bit position */
#define BME68X_HCTRL_POS UINT8_C(3)
/* Macro to combine two 8 bit data's to form a 16 bit data */
#define BME68X_CONCAT_BYTES(msb, lsb) (((uint16_t)msb << 8) | (uint16_t)lsb)
/* Macro to set bits */
#define BME68X_SET_BITS(reg_data, bitname, data) \
((reg_data & ~(bitname##_MSK)) | \
((data << bitname##_POS) & bitname##_MSK))
/* Macro to get bits */
#define BME68X_GET_BITS(reg_data, bitname) ((reg_data & (bitname##_MSK)) >> \
(bitname##_POS))
/* Macro to set bits starting from position 0 */
#define BME68X_SET_BITS_POS_0(reg_data, bitname, data) \
((reg_data & ~(bitname##_MSK)) | \
(data & bitname##_MSK))
/* Macro to get bits starting from position 0 */
#define BME68X_GET_BITS_POS_0(reg_data, bitname) (reg_data & (bitname##_MSK))
/**
* BME68X_INTF_RET_TYPE is the read/write interface return type which can be overwritten by the build system.
* The default is set to int8_t.
*/
#ifndef BME68X_INTF_RET_TYPE
#define BME68X_INTF_RET_TYPE int8_t
#endif
/**
* BME68X_INTF_RET_SUCCESS is the success return value read/write interface return type which can be
* overwritten by the build system. The default is set to 0. It is used to check for a successful
* execution of the read/write functions
*/
#ifndef BME68X_INTF_RET_SUCCESS
#define BME68X_INTF_RET_SUCCESS INT8_C(0)
#endif
/********************************************************* */
/*! Function Pointers */
/********************************************************* */
/*!
* @brief Bus communication function pointer which should be mapped to
* the platform specific read functions of the user
*
* @param[in] reg_addr : 8bit register address of the sensor
* @param[out] reg_data : Data from the specified address
* @param[in] length : Length of the reg_data array
* @param[in,out] intf_ptr : Void pointer that can enable the linking of descriptors
* for interface related callbacks
* @retval 0 for Success
* @retval Non-zero for Failure
*/
typedef BME68X_INTF_RET_TYPE (*bme68x_read_fptr_t)(uint8_t reg_addr, uint8_t *reg_data, uint32_t length,
void *intf_ptr);
/*!
* @brief Bus communication function pointer which should be mapped to
* the platform specific write functions of the user
*
* @param[in] reg_addr : 8bit register address of the sensor
* @param[out] reg_data : Data to the specified address
* @param[in] length : Length of the reg_data array
* @param[in,out] intf_ptr : Void pointer that can enable the linking of descriptors
* for interface related callbacks
* @retval 0 for Success
* @retval Non-zero for Failure
*
*/
typedef BME68X_INTF_RET_TYPE (*bme68x_write_fptr_t)(uint8_t reg_addr, const uint8_t *reg_data, uint32_t length,
void *intf_ptr);
/*!
* @brief Delay function pointer which should be mapped to
* delay function of the user
*
* @param period - The time period in microseconds
* @param[in,out] intf_ptr : Void pointer that can enable the linking of descriptors
* for interface related callbacks
*/
typedef void (*bme68x_delay_us_fptr_t)(uint32_t period, void *intf_ptr);
/*
* @brief Generic communication function pointer
* @param[in] dev_id: Place holder to store the id of the device structure
* Can be used to store the index of the Chip select or
* I2C address of the device.
* @param[in] reg_addr: Used to select the register the where data needs to
* be read from or written to.
* @param[in,out] reg_data: Data array to read/write
* @param[in] len: Length of the data array
*/
/*
* @brief Interface selection Enumerations
*/
enum bme68x_intf {
/*! SPI interface */
BME68X_SPI_INTF,
/*! I2C interface */
BME68X_I2C_INTF
};
/* Structure definitions */
/*
* @brief Sensor field data structure
*/
struct bme68x_data
{
/*! Contains new_data, gasm_valid & heat_stab */
uint8_t status;
/*! The index of the heater profile used */
uint8_t gas_index;
/*! Measurement index to track order */
uint8_t meas_index;
/*! Heater resistance */
uint8_t res_heat;
/*! Current DAC */
uint8_t idac;
/*! Gas wait period */
uint8_t gas_wait;
#ifndef BME68X_USE_FPU
/*! Temperature in degree celsius x100 */
int16_t temperature;
/*! Pressure in Pascal */
uint32_t pressure;
/*! Humidity in % relative humidity x1000 */
uint32_t humidity;
/*! Gas resistance in Ohms */
uint32_t gas_resistance;
#else
/*! Temperature in degree celsius */
float temperature;
/*! Pressure in Pascal */
float pressure;
/*! Humidity in % relative humidity x1000 */
float humidity;
/*! Gas resistance in Ohms */
float gas_resistance;
#endif
};
/*
* @brief Structure to hold the calibration coefficients
*/
struct bme68x_calib_data
{
/*! Calibration coefficient for the humidity sensor */
uint16_t par_h1;
/*! Calibration coefficient for the humidity sensor */
uint16_t par_h2;
/*! Calibration coefficient for the humidity sensor */
int8_t par_h3;
/*! Calibration coefficient for the humidity sensor */
int8_t par_h4;
/*! Calibration coefficient for the humidity sensor */
int8_t par_h5;
/*! Calibration coefficient for the humidity sensor */
uint8_t par_h6;
/*! Calibration coefficient for the humidity sensor */
int8_t par_h7;
/*! Calibration coefficient for the gas sensor */
int8_t par_gh1;
/*! Calibration coefficient for the gas sensor */
int16_t par_gh2;
/*! Calibration coefficient for the gas sensor */
int8_t par_gh3;
/*! Calibration coefficient for the temperature sensor */
uint16_t par_t1;
/*! Calibration coefficient for the temperature sensor */
int16_t par_t2;
/*! Calibration coefficient for the temperature sensor */
int8_t par_t3;
/*! Calibration coefficient for the pressure sensor */
uint16_t par_p1;
/*! Calibration coefficient for the pressure sensor */
int16_t par_p2;
/*! Calibration coefficient for the pressure sensor */
int8_t par_p3;
/*! Calibration coefficient for the pressure sensor */
int16_t par_p4;
/*! Calibration coefficient for the pressure sensor */
int16_t par_p5;
/*! Calibration coefficient for the pressure sensor */
int8_t par_p6;
/*! Calibration coefficient for the pressure sensor */
int8_t par_p7;
/*! Calibration coefficient for the pressure sensor */
int16_t par_p8;
/*! Calibration coefficient for the pressure sensor */
int16_t par_p9;
/*! Calibration coefficient for the pressure sensor */
uint8_t par_p10;
#ifndef BME68X_USE_FPU
/*! Variable to store the intermediate temperature coefficient */
int32_t t_fine;
#else
/*! Variable to store the intermediate temperature coefficient */
float t_fine;
#endif
/*! Heater resistance range coefficient */
uint8_t res_heat_range;
/*! Heater resistance value coefficient */
int8_t res_heat_val;
/*! Gas resistance range switching error coefficient */
int8_t range_sw_err;
};
/*
* @brief BME68X sensor settings structure which comprises of ODR,
* over-sampling and filter settings.
*/
struct bme68x_conf
{
/*! Humidity oversampling. Refer @ref osx*/
uint8_t os_hum;
/*! Temperature oversampling. Refer @ref osx */
uint8_t os_temp;
/*! Pressure oversampling. Refer @ref osx */
uint8_t os_pres;
/*! Filter coefficient. Refer @ref filter*/
uint8_t filter;
/*!
* Standby time between sequential mode measurement profiles.
* Refer @ref odr
*/
uint8_t odr;
};
/*
* @brief BME68X gas heater configuration
*/
struct bme68x_heatr_conf
{
/*! Enable gas measurement. Refer @ref en_dis */
uint8_t enable;
/*! Store the heater temperature for forced mode degree Celsius */
uint16_t heatr_temp;
/*! Store the heating duration for forced mode in milliseconds */
uint16_t heatr_dur;
/*! Store the heater temperature profile in degree Celsius */
uint16_t *heatr_temp_prof;
/*! Store the heating duration profile in milliseconds */
uint16_t *heatr_dur_prof;
/*! Variable to store the length of the heating profile */
uint8_t profile_len;
/*!
* Variable to store heating duration for parallel mode
* in milliseconds
*/
uint16_t shared_heatr_dur;
};
/*
* @brief BME68X device structure
*/
struct bme68x_dev
{
/*! Chip Id */
uint8_t chip_id;
/*!
* The interface pointer is used to enable the user
* to link their interface descriptors for reference during the
* implementation of the read and write interfaces to the
* hardware.
*/
void *intf_ptr;
/*!
* Variant id
* ----------------------------------------
* Value | Variant
* ----------------------------------------
* 0 | BME68X_VARIANT_GAS_LOW
* 1 | BME68X_VARIANT_GAS_HIGH
* ----------------------------------------
*/
uint32_t variant_id;
/*! SPI/I2C interface */
enum bme68x_intf intf;
/*! Memory page used */
uint8_t mem_page;
/*! Ambient temperature in Degree C*/
int8_t amb_temp;
/*! Sensor calibration data */
struct bme68x_calib_data calib;
/*! Read function pointer */
bme68x_read_fptr_t read;
/*! Write function pointer */
bme68x_write_fptr_t write;
/*! Delay function pointer */
bme68x_delay_us_fptr_t delay_us;
/*! To store interface pointer error */
BME68X_INTF_RET_TYPE intf_rslt;
/*! Store the info messages */
uint8_t info_msg;
};
#endif /* BME68X_DEFS_H_ */
/*! @endcond */

View File

@@ -0,0 +1,540 @@
/**
* Copyright (C) Bosch Sensortec GmbH. All Rights Reserved. Confidential.
*
* Disclaimer
*
* Common:
* Bosch Sensortec products are developed for the consumer goods industry. They may only be used
* within the parameters of the respective valid product data sheet. Bosch Sensortec products are
* provided with the express understanding that there is no warranty of fitness for a particular purpose.
* They are not fit for use in life-sustaining, safety or security sensitive systems or any system or device
* that may lead to bodily harm or property damage if the system or device malfunctions. In addition,
* Bosch Sensortec products are not fit for use in products which interact with motor vehicle systems.
* The resale and/or use of products are at the purchaser's own risk and his own responsibility. The
* examination of fitness for the intended use is the sole responsibility of the Purchaser.
*
* The purchaser shall indemnify Bosch Sensortec from all third party claims, including any claims for
* incidental, or consequential damages, arising from any product use not covered by the parameters of
* the respective valid product data sheet or not approved by Bosch Sensortec and reimburse Bosch
* Sensortec for all costs in connection with such claims.
*
* The purchaser must monitor the market for the purchased products, particularly with regard to
* product safety and inform Bosch Sensortec without delay of all security relevant incidents.
*
* Engineering Samples are marked with an asterisk (*) or (e). Samples may vary from the valid
* technical specifications of the product series. They are therefore not intended or fit for resale to third
* parties or for use in end products. Their sole purpose is internal client testing. The testing of an
* engineering sample may in no way replace the testing of a product series. Bosch Sensortec
* assumes no liability for the use of engineering samples. By accepting the engineering samples, the
* Purchaser agrees to indemnify Bosch Sensortec from all claims arising from the use of engineering
* samples.
*
* Special:
* This software module (hereinafter called "Software") and any information on application-sheets
* (hereinafter called "Information") is provided free of charge for the sole purpose to support your
* application work. The Software and Information is subject to the following terms and conditions:
*
* The Software is specifically designed for the exclusive use for Bosch Sensortec products by
* personnel who have special experience and training. Do not use this Software if you do not have the
* proper experience or training.
*
* This Software package is provided `` as is `` and without any expressed or implied warranties,
* including without limitation, the implied warranties of merchantability and fitness for a particular
* purpose.
*
* Bosch Sensortec and their representatives and agents deny any liability for the functional impairment
* of this Software in terms of fitness, performance and safety. Bosch Sensortec and their
* representatives and agents shall not be liable for any direct or indirect damages or injury, except as
* otherwise stipulated in mandatory applicable law.
*
* The Information provided is believed to be accurate and reliable. Bosch Sensortec assumes no
* responsibility for the consequences of use of such Information nor for any infringement of patents or
* other rights of third parties which may result from its use. No license is granted by implication or
* otherwise under any patent or patent rights of Bosch. Specifications mentioned in the Information are
* subject to change without notice.
*
* It is not allowed to deliver the source code of the Software to any third party without permission of
* Bosch Sensortec.
*
* @file bsec_datatypes.h
*
* @brief
* Contains the data types used by BSEC
*
*/
#ifndef __BSEC_DATATYPES_H__
#define __BSEC_DATATYPES_H__
#ifdef __cplusplus
extern "C"
{
#endif
/*!
* @addtogroup bsec_datatypes BSEC Enumerations and Definitions
* @brief
* @{*/
#ifdef __KERNEL__
#include <linux/types.h>
#endif
#include <stdint.h>
#include <stddef.h>
#define BSEC_MAX_WORKBUFFER_SIZE (4096) /*!< Maximum size (in bytes) of the work buffer */
#define BSEC_MAX_PHYSICAL_SENSOR (8) /*!< Number of physical sensors that need allocated space before calling bsec_update_subscription() */
#define BSEC_MAX_PROPERTY_BLOB_SIZE (1943) /*!< Maximum size (in bytes) of the data blobs returned by bsec_get_configuration() */
#define BSEC_MAX_STATE_BLOB_SIZE (238) /*!< Maximum size (in bytes) of the data blobs returned by bsec_get_state()*/
#define BSEC_SAMPLE_RATE_DISABLED (65535.0f) /*!< Sample rate of a disabled sensor */
#define BSEC_SAMPLE_RATE_ULP (0.0033333f) /*!< Sample rate in case of Ultra Low Power Mode */
#define BSEC_SAMPLE_RATE_CONT (1.0f) /*!< Sample rate in case of Continuous Mode */
#define BSEC_SAMPLE_RATE_LP (0.33333f) /*!< Sample rate in case of Low Power Mode */
#define BSEC_SAMPLE_RATE_ULP_MEASUREMENT_ON_DEMAND (0.0f) /*!< Input value used to trigger an extra measurment (ULP plus) */
#define BSEC_SAMPLE_RATE_SCAN (0.055556f) /*!< Sample rate in case of scan mode */
#define BSEC_PROCESS_PRESSURE (1 << (BSEC_INPUT_PRESSURE-1)) /*!< process_data bitfield constant for pressure @sa bsec_bme_settings_t */
#define BSEC_PROCESS_TEMPERATURE (1 << (BSEC_INPUT_TEMPERATURE-1))/*!< process_data bitfield constant for temperature @sa bsec_bme_settings_t */
#define BSEC_PROCESS_HUMIDITY (1 << (BSEC_INPUT_HUMIDITY-1)) /*!< process_data bitfield constant for humidity @sa bsec_bme_settings_t */
#define BSEC_PROCESS_GAS (1 << (BSEC_INPUT_GASRESISTOR-1)) /*!< process_data bitfield constant for gas sensor @sa bsec_bme_settings_t */
#define BSEC_PROCESS_PROFILE_PART (1 << (BSEC_INPUT_PROFILE_PART-1)) /*!< process_data bitfield constant for gas sensor @sa bsec_bme_settings_t */
#define BSEC_NUMBER_OUTPUTS (23) /*!< Number of outputs, depending on solution */
#define BSEC_OUTPUT_INCLUDED (1072855535) /*!< bitfield that indicates which outputs are included in the solution */
/*!
* @brief Enumeration for input (physical) sensors.
*
* Used to populate bsec_input_t::sensor_id. It is also used in bsec_sensor_configuration_t::sensor_id structs
* returned in the parameter required_sensor_settings of bsec_update_subscription().
*
* @sa bsec_sensor_configuration_t @sa bsec_input_t
*/
typedef enum
{
/**
* @brief Pressure sensor output of BME68x [Pa]
*/
BSEC_INPUT_PRESSURE = 1,
/**
* @brief Humidity sensor output of BME68x [%]
*
* @note Relative humidity strongly depends on the temperature (it is measured at). It may require a conversion to
* the temperature outside of the device.
*
* @sa bsec_virtual_sensor_t
*/
BSEC_INPUT_HUMIDITY = 2,
/**
* @brief Temperature sensor output of BME68x [degrees Celsius]
*
* @note The BME68x is factory trimmed, thus the temperature sensor of the BME68x is very accurate.
* The temperature value is a very local measurement value and can be influenced by external heat sources.
*
* @sa bsec_virtual_sensor_t
*/
BSEC_INPUT_TEMPERATURE = 3,
/**
* @brief Gas sensor resistance output of BME68x [Ohm]
*
* The resistance value changes due to varying VOC concentrations (the higher the concentration of reducing VOCs,
* the lower the resistance and vice versa).
*/
BSEC_INPUT_GASRESISTOR = 4, /*!< */
/**
* @brief Additional input for device heat compensation
*
* IAQ solution: The value is subtracted from ::BSEC_INPUT_TEMPERATURE to compute
* ::BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE.
*
* ALL solution: Generic heat source 1
*
* @sa bsec_virtual_sensor_t
*/
BSEC_INPUT_HEATSOURCE = 14,
/**
* @brief Additional input that disables baseline tracker
*
* 0 - Normal,
* 1 - Event 1,
* 2 - Event 2
*/
BSEC_INPUT_DISABLE_BASELINE_TRACKER = 23,
/**
* @brief Additional input that provides information about the state of the profile (1-9)
*
*/
BSEC_INPUT_PROFILE_PART = 24
} bsec_physical_sensor_t;
/*!
* @brief Enumeration for output (virtual) sensors
*
* Used to populate bsec_output_t::sensor_id. It is also used in bsec_sensor_configuration_t::sensor_id structs
* passed in the parameter requested_virtual_sensors of bsec_update_subscription().
*
* @sa bsec_sensor_configuration_t @sa bsec_output_t
*/
typedef enum
{
/**
* @brief Indoor-air-quality estimate [0-500]
*
* Indoor-air-quality (IAQ) gives an indication of the relative change in ambient TVOCs detected by BME68x.
*
* @note The IAQ scale ranges from 0 (clean air) to 500 (heavily polluted air). During operation, algorithms
* automatically calibrate and adapt themselves to the typical environments where the sensor is operated
* (e.g., home, workplace, inside a car, etc.).This automatic background calibration ensures that users experience
* consistent IAQ performance. The calibration process considers the recent measurement history (typ. up to four
* days) to ensure that IAQ=50 corresponds to typical good air and IAQ=200 indicates typical polluted air.
*/
BSEC_OUTPUT_IAQ = 1,
BSEC_OUTPUT_STATIC_IAQ = 2, /*!< Unscaled indoor-air-quality estimate */
BSEC_OUTPUT_CO2_EQUIVALENT = 3, /*!< CO2 equivalent estimate [ppm] */
BSEC_OUTPUT_BREATH_VOC_EQUIVALENT = 4, /*!< Breath VOC concentration estimate [ppm] */
/**
* @brief Temperature sensor signal [degrees Celsius]
*
* Temperature directly measured by BME68x in degree Celsius.
*
* @note This value is cross-influenced by the sensor heating and device specific heating.
*/
BSEC_OUTPUT_RAW_TEMPERATURE = 6,
/**
* @brief Pressure sensor signal [Pa]
*
* Pressure directly measured by the BME68x in Pa.
*/
BSEC_OUTPUT_RAW_PRESSURE = 7,
/**
* @brief Relative humidity sensor signal [%]
*
* Relative humidity directly measured by the BME68x in %.
*
* @note This value is cross-influenced by the sensor heating and device specific heating.
*/
BSEC_OUTPUT_RAW_HUMIDITY = 8,
/**
* @brief Gas sensor signal [Ohm]
*
* Gas resistance measured directly by the BME68x in Ohm.The resistance value changes due to varying VOC
* concentrations (the higher the concentration of reducing VOCs, the lower the resistance and vice versa).
*/
BSEC_OUTPUT_RAW_GAS = 9,
/**
* @brief Gas sensor stabilization status [boolean]
*
* Indicates initial stabilization status of the gas sensor element: stabilization is ongoing (0) or stabilization
* is finished (1).
*/
BSEC_OUTPUT_STABILIZATION_STATUS = 12,
/**
* @brief Gas sensor run-in status [boolean]
*
* Dynamicaly tracks the power-on stabilization of the gas sensor element: stabilization is ongoing (0) or stabilization
* is finished (1). It depends on how long the sensor has been turn off. A power-on conditioning has been employed for early stabilization of BME sensors.
*/
BSEC_OUTPUT_RUN_IN_STATUS = 13,
/**
* @brief Sensor heat compensated temperature [degrees Celsius]
*
* Temperature measured by BME68x which is compensated for the influence of sensor (heater) in degree Celsius.
* The self heating introduced by the heater is depending on the sensor operation mode and the sensor supply voltage.
*
*
* @note In addition, the temperature output can be compensated by an user defined value
* (::BSEC_INPUT_HEATSOURCE in degrees Celsius), which represents the device specific self-heating.
*
* Thus, the value is calculated as follows:
* * ```BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE = ::BSEC_INPUT_TEMPERATURE - function(sensor operation mode, sensor supply voltage) - ::BSEC_INPUT_HEATSOURCE```
*
*
* The self-heating in operation mode BSEC_SAMPLE_RATE_ULP is negligible.
* The self-heating in operation mode BSEC_SAMPLE_RATE_LP is supported for 1.8V by default (no config file required). If the BME68x sensor supply voltage is 3.3V, the corresponding config file shall be used.
*/
BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE = 14,
/**
* @brief Sensor heat compensated humidity [%]
*
* Relative humidity measured by BME68x which is compensated for the influence of sensor (heater) in %.
*
* It converts the ::BSEC_INPUT_HUMIDITY from temperature ::BSEC_INPUT_TEMPERATURE to temperature
* ::BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE.
*
* @note If ::BSEC_INPUT_HEATSOURCE is used for device specific temperature compensation, it will be
* effective for ::BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY too.
*/
BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY = 15,
/**
* @brief Raw gas resistance compensated by temperature and humidity influences [ohm].
*
* The effect of temperature and humidity on the gas resistance is eleminated to a good extend and it is further linearized
* to log scale for estimation of the compensated gas resistance.
*
*/
BSEC_OUTPUT_COMPENSATED_GAS = 18,
BSEC_OUTPUT_GAS_PERCENTAGE = 21, /*!< Percentage of min and max filtered gas value [%] */
/**
* @brief Gas estimate output channel 1 [0-1]
*
* The gas scan result is given in probability for each of the used gases.
* In standard scan mode, the probability of H2S and non-H2S is provided by the variables BSEC_OUTPUT_GAS_ESTIMATE_1 & BSEC_OUTPUT_GAS_ESTIMATE_2 respectively. A maximum of 4 classes can be used by configuring using BME AI-studio.
*/
BSEC_OUTPUT_GAS_ESTIMATE_1 = 22,
BSEC_OUTPUT_GAS_ESTIMATE_2 = 23, /*!< Gas estimate output channel 2 [0-1] */
BSEC_OUTPUT_GAS_ESTIMATE_3 = 24, /*!< Gas estimate output channel 3 [0-1] */
BSEC_OUTPUT_GAS_ESTIMATE_4 = 25, /*!< Gas estimate output channel 4 [0-1] */
BSEC_OUTPUT_RAW_GAS_INDEX = 26, /*!< Gas index cyclically running from 0 to heater_profile_length-1, range of heater profile length is from 1 to 10, default being 10 */
/**
* @brief Regression estimate output channel 1
*
* The regression estimate gives the quantitative measurement of the gases used.
* In standard scan mode, quantification of the gas is provided by the variables BSEC_OUTPUT_REGRESSION_ESTIMATE_1. A maximum of 4 gas targets can be used by configuring using BME AI-studio.
*/
BSEC_OUTPUT_REGRESSION_ESTIMATE_1 = 27,
BSEC_OUTPUT_REGRESSION_ESTIMATE_2 = 28, /*!< Regression estimate output channel 2 */
BSEC_OUTPUT_REGRESSION_ESTIMATE_3 = 29, /*!< Regression estimate output channel 3 */
BSEC_OUTPUT_REGRESSION_ESTIMATE_4 = 30 /*!< Regression estimate output channel 4 */
} bsec_virtual_sensor_t;
/*!
* @brief Enumeration for function return codes
*/
typedef enum
{
BSEC_OK = 0, /*!< Function execution successful */
BSEC_E_DOSTEPS_INVALIDINPUT = -1, /*!< Input (physical) sensor id passed to bsec_do_steps() is not in the valid range or not valid for requested virtual sensor */
BSEC_E_DOSTEPS_VALUELIMITS = -2, /*!< Value of input (physical) sensor signal passed to bsec_do_steps() is not in the valid range */
BSEC_W_DOSTEPS_TSINTRADIFFOUTOFRANGE = 4, /*!< Past timestamps passed to bsec_do_steps() */
BSEC_E_DOSTEPS_DUPLICATEINPUT = -6, /*!< Duplicate input (physical) sensor ids passed as input to bsec_do_steps() */
BSEC_I_DOSTEPS_NOOUTPUTSRETURNABLE = 2, /*!< No memory allocated to hold return values from bsec_do_steps(), i.e., n_outputs == 0 */
BSEC_W_DOSTEPS_EXCESSOUTPUTS = 3, /*!< Not enough memory allocated to hold return values from bsec_do_steps(), i.e., n_outputs < maximum number of requested output (virtual) sensors */
BSEC_W_DOSTEPS_GASINDEXMISS = 5, /*!< Gas index not provided to bsec_do_steps() */
BSEC_E_SU_WRONGDATARATE = -10, /*!< The sample_rate of the requested output (virtual) sensor passed to bsec_update_subscription() is zero */
BSEC_E_SU_SAMPLERATELIMITS = -12, /*!< The sample_rate of the requested output (virtual) sensor passed to bsec_update_subscription() does not match with the sampling rate allowed for that sensor */
BSEC_E_SU_DUPLICATEGATE = -13, /*!< Duplicate output (virtual) sensor ids requested through bsec_update_subscription() */
BSEC_E_SU_INVALIDSAMPLERATE = -14, /*!< The sample_rate of the requested output (virtual) sensor passed to bsec_update_subscription() does not fall within the global minimum and maximum sampling rates */
BSEC_E_SU_GATECOUNTEXCEEDSARRAY = -15, /*!< Not enough memory allocated to hold returned input (physical) sensor data from bsec_update_subscription(), i.e., n_required_sensor_settings ::BSEC_MAX_PHYSICAL_SENSOR */
BSEC_E_SU_SAMPLINTVLINTEGERMULT = -16, /*!< The sample_rate of the requested output (virtual) sensor passed to bsec_update_subscription() is not correct */
BSEC_E_SU_MULTGASSAMPLINTVL = -17, /*!< The sample_rate of the requested output (virtual), which requires the gas sensor, is not equal to the sample_rate that the gas sensor is being operated */
BSEC_E_SU_HIGHHEATERONDURATION = -18, /*!< The duration of one measurement is longer than the requested sampling interval */
BSEC_W_SU_UNKNOWNOUTPUTGATE = 10, /*!< Output (virtual) sensor id passed to bsec_update_subscription() is not in the valid range; e.g., n_requested_virtual_sensors > actual number of output (virtual) sensors requested */
BSEC_W_SU_MODINNOULP = 11, /*!< ULP plus can not be requested in non-ulp mode */ /*MOD_ONLY*/
BSEC_I_SU_SUBSCRIBEDOUTPUTGATES = 12, /*!< No output (virtual) sensor data were requested via bsec_update_subscription() */
BSEC_I_SU_GASESTIMATEPRECEDENCE = 13, /*!< GAS_ESTIMATE is suscribed and take precedence over other requested outputs */
BSEC_W_SU_SAMPLERATEMISMATCH = 14, /*!< Subscriped sample rate of the output is not matching with configured sample rate. For example if user used the configuration of ULP and outputs subscribed for LP mode this warning will inform the user about this mismatch*/
BSEC_E_PARSE_SECTIONEXCEEDSWORKBUFFER = -32, /*!< n_work_buffer_size passed to bsec_set_[configuration/state]() not sufficient */
BSEC_E_CONFIG_FAIL = -33, /*!< Configuration failed */
BSEC_E_CONFIG_VERSIONMISMATCH = -34, /*!< Version encoded in serialized_[settings/state] passed to bsec_set_[configuration/state]() does not match with current version */
BSEC_E_CONFIG_FEATUREMISMATCH = -35, /*!< Enabled features encoded in serialized_[settings/state] passed to bsec_set_[configuration/state]() does not match with current library implementation or subscribed outputs*/
BSEC_E_CONFIG_CRCMISMATCH = -36, /*!< serialized_[settings/state] passed to bsec_set_[configuration/state]() is corrupted */
BSEC_E_CONFIG_EMPTY = -37, /*!< n_serialized_[settings/state] passed to bsec_set_[configuration/state]() is to short to be valid */
BSEC_E_CONFIG_INSUFFICIENTWORKBUFFER = -38, /*!< Provided work_buffer is not large enough to hold the desired string */
BSEC_E_CONFIG_INVALIDSTRINGSIZE = -40, /*!< String size encoded in configuration/state strings passed to bsec_set_[configuration/state]() does not match with the actual string size n_serialized_[settings/state] passed to these functions */
BSEC_E_CONFIG_INSUFFICIENTBUFFER = -41, /*!< String buffer insufficient to hold serialized data from BSEC library */
BSEC_E_SET_INVALIDCHANNELIDENTIFIER = -100, /*!< Internal error code, size of work buffer in setConfig must be set to #BSEC_MAX_WORKBUFFER_SIZE */
BSEC_E_SET_INVALIDLENGTH = -104, /*!< Internal error code */
BSEC_W_SC_CALL_TIMING_VIOLATION = 100, /*!< Difference between actual and defined sampling intervals of bsec_sensor_control() greater than allowed */
BSEC_W_SC_MODEXCEEDULPTIMELIMIT = 101, /*!< ULP plus is not allowed because an ULP measurement just took or will take place */ /*MOD_ONLY*/
BSEC_W_SC_MODINSUFFICIENTWAITTIME = 102 /*!< ULP plus is not allowed because not sufficient time passed since last ULP plus */ /*MOD_ONLY*/
} bsec_library_return_t;
/*!
* @brief Structure containing the version information
*
* Please note that configuration and state strings are coded to a specific version and will not be accepted by other
* versions of BSEC.
*
*/
typedef struct
{
uint8_t major; /**< @brief Major version */
uint8_t minor; /**< @brief Minor version */
uint8_t major_bugfix; /**< @brief Major bug fix version */
uint8_t minor_bugfix; /**< @brief Minor bug fix version */
} bsec_version_t;
/*!
* @brief Structure describing an input sample to the library
*
* Each input sample is provided to BSEC as an element in a struct array of this type. Timestamps must be provided
* in nanosecond resolution. Moreover, duplicate timestamps for subsequent samples are not allowed and will results in
* an error code being returned from bsec_do_steps().
*
* The meaning unit of the signal field are determined by the bsec_input_t::sensor_id field content. Possible
* bsec_input_t::sensor_id values and and their meaning are described in ::bsec_physical_sensor_t.
*
* @sa bsec_physical_sensor_t
*
*/
typedef struct
{
/**
* @brief Time stamp in nanosecond resolution [ns]
*
* Timestamps must be provided as non-repeating and increasing values. They can have their 0-points at system start or
* at a defined wall-clock time (e.g., 01-Jan-1970 00:00:00)
*/
int64_t time_stamp;
float signal; /*!< @brief Signal sample in the unit defined for the respective sensor_id @sa bsec_physical_sensor_t */
uint8_t signal_dimensions; /*!< @brief Signal dimensions (reserved for future use, shall be set to 1) */
uint8_t sensor_id; /*!< @brief Identifier of physical sensor @sa bsec_physical_sensor_t */
} bsec_input_t;
/*!
* @brief Structure describing an output sample of the library
*
* Each output sample is returned from BSEC by populating the element of a struct array of this type. The contents of
* the signal field is defined by the supplied bsec_output_t::sensor_id. Possible output
* bsec_output_t::sensor_id values are defined in ::bsec_virtual_sensor_t.
*
* @sa bsec_virtual_sensor_t
*/
typedef struct
{
int64_t time_stamp; /*!< @brief Time stamp in nanosecond resolution as provided as input [ns] */
float signal; /*!< @brief Signal sample in the unit defined for the respective bsec_output_t::sensor_id @sa bsec_virtual_sensor_t */
uint8_t signal_dimensions; /*!< @brief Signal dimensions (reserved for future use, shall be set to 1) */
uint8_t sensor_id; /*!< @brief Identifier of virtual sensor @sa bsec_virtual_sensor_t */
/**
* @brief Accuracy status 0-3
*
* Some virtual sensors provide a value in the accuracy field. If this is the case, the meaning of the field is as
* follows:
*
* | Name | Value | Accuracy description |
* |----------------------------|-------|-------------------------------------------------------------------------------------------------------------|
* | UNRELIABLE | 0 | Sensor data is unreliable, the sensor must be calibrated |
* | LOW_ACCURACY | 1 | Reliability of virtual sensor is low, sensor should be calibrated |
* | MEDIUM_ACCURACY | 2 | Medium reliability, sensor calibration or training may improve performance |
* | HIGH_ACCURACY | 3 | High reliability |
*
* For example:
*
* - IAQ accuracy indicator will notify the user when she/he should initiate a calibration process. Calibration is
* performed automatically in the background if the sensor is exposed to clean and polluted air for approximately
* 30 minutes each.
*
* | Virtual sensor | Value | Accuracy description |
* |----------------------------|-------|---------------------------------------------------------------------------------------------------------------------------------------------------------------|
* | IAQ | 0 | Stabilization / run-in ongoing |
* | | 1 | Low accuracy,to reach high accuracy(3),please expose sensor once to good air (e.g. outdoor air) and bad air (e.g. box with exhaled breath) for auto-trimming |
* | | 2 | Medium accuracy: auto-trimming ongoing |
* | | 3 | High accuracy
*
* - Gas estimator accuracy indicator will notify the user when she/he gets valid gas prediction output.
*
* | Virtual sensor | Value | Accuracy description |
* |----------------------------|-------|---------------------------------------------------------------------------------------------------------------------------------------------------------------|
* | GAS_ESTIMATE_x* | 0 | No valid gas estimate found - BSEC collecting gas features |
* | | 3 | Gas estimate prediction available |
*
* <sup>*</sup> GAS_ESTIMATE_1, GAS_ESTIMATE_2, GAS_ESTIMATE_3, GAS_ESTIMATE_4
* - Regression estimate accuracy will notify the user when she/he gets valid regression estimate output.
*
* | Virtual sensor | Value | Accuracy description |
* |----------------------------|-------|---------------------------------------------------------------------------------------------------------------------------------------------------------------|
* | REGRESSION_ESTIMATE_x* | 0 | No valid regression estimate output found - BSEC collecting gas features |
* | | 2 | Predicted regression estimate output is not within the value of the label present in the training data |
* | | 3 | Predicted regression estimate output is within the the value of the label present in the training data |
*
* <sup>*</sup> REGRESSION_ESTIMATE_1, REGRESSION_ESTIMATE_2, REGRESSION_ESTIMATE_3, REGRESSION_ESTIMATE_4
*/
uint8_t accuracy;
} bsec_output_t;
/*!
* @brief Structure describing sample rate of physical/virtual sensors
*
* This structure is used together with bsec_update_subscription() to enable BSEC outputs and to retrieve information
* about the sample rates used for BSEC inputs.
*/
typedef struct
{
/**
* @brief Sample rate of the virtual or physical sensor in Hertz [Hz]
*
* Only supported sample rates are allowed.
*/
float sample_rate;
/**
* @brief Identifier of the virtual or physical sensor
*
* The meaning of this field changes depending on whether the structs are as the requested_virtual_sensors argument
* to bsec_update_subscription() or as the required_sensor_settings argument.
*
* | bsec_update_subscription() argument | sensor_id field interpretation |
* |-------------------------------------|--------------------------------|
* | requested_virtual_sensors | ::bsec_virtual_sensor_t |
* | required_sensor_settings | ::bsec_physical_sensor_t |
*
* @sa bsec_physical_sensor_t
* @sa bsec_virtual_sensor_t
*/
uint8_t sensor_id;
} bsec_sensor_configuration_t;
/*!
* @brief Structure returned by bsec_sensor_control() to configure BME68x sensor
*
* This structure contains settings that must be used to configure the BME68x to perform a forced-mode measurement.
* A measurement should only be executed if bsec_bme_settings_t::trigger_measurement is 1. If so, the oversampling
* settings for temperature, humidity, and pressure should be set to the provided settings provided in
* bsec_bme_settings_t::temperature_oversampling, bsec_bme_settings_t::humidity_oversampling, and
* bsec_bme_settings_t::pressure_oversampling, respectively.
*
* In case of bsec_bme_settings_t::run_gas = 1, the gas sensor must be enabled with the provided
* bsec_bme_settings_t::heater_temperature and bsec_bme_settings_t::heating_duration settings.
*/
typedef struct
{
int64_t next_call; /*!< @brief Time stamp of the next call of the sensor_control*/
uint32_t process_data; /*!< @brief Bit field describing which data is to be passed to bsec_do_steps() @sa BSEC_PROCESS_GAS, BSEC_PROCESS_TEMPERATURE, BSEC_PROCESS_HUMIDITY, BSEC_PROCESS_PRESSURE */
uint16_t heater_temperature; /*!< @brief Heater temperature [degrees Celsius] */
uint16_t heater_duration; /*!< @brief Heater duration [ms] */
uint16_t heater_temperature_profile[10];/*!< @brief Heater temperature profile [degrees Celsius] */
uint16_t heater_duration_profile[10]; /*!< @brief Heater duration profile [ms] */
uint8_t heater_profile_len; /*!< @brief Heater profile length [0-10] */
uint8_t run_gas; /*!< @brief Enable gas measurements [0/1] */
uint8_t pressure_oversampling; /*!< @brief Pressure oversampling settings [0-5] */
uint8_t temperature_oversampling; /*!< @brief Temperature oversampling settings [0-5] */
uint8_t humidity_oversampling; /*!< @brief Humidity oversampling settings [0-5] */
uint8_t trigger_measurement; /*!< @brief Trigger a forced measurement with these settings now [0/1] */
uint8_t op_mode; /*!< @brief Sensor operation mode [0/1] */
} bsec_bme_settings_t;
/* internal defines and backward compatibility */
#define BSEC_STRUCT_NAME Bsec /*!< Internal struct name */
/*@}*/
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,762 @@
/**
* Copyright (C) Bosch Sensortec GmbH. All Rights Reserved. Confidential.
*
* Disclaimer
*
* Common:
* Bosch Sensortec products are developed for the consumer goods industry. They may only be used
* within the parameters of the respective valid product data sheet. Bosch Sensortec products are
* provided with the express understanding that there is no warranty of fitness for a particular purpose.
* They are not fit for use in life-sustaining, safety or security sensitive systems or any system or device
* that may lead to bodily harm or property damage if the system or device malfunctions. In addition,
* Bosch Sensortec products are not fit for use in products which interact with motor vehicle systems.
* The resale and/or use of products are at the purchaser's own risk and his own responsibility. The
* examination of fitness for the intended use is the sole responsibility of the Purchaser.
*
* The purchaser shall indemnify Bosch Sensortec from all third party claims, including any claims for
* incidental, or consequential damages, arising from any product use not covered by the parameters of
* the respective valid product data sheet or not approved by Bosch Sensortec and reimburse Bosch
* Sensortec for all costs in connection with such claims.
*
* The purchaser must monitor the market for the purchased products, particularly with regard to
* product safety and inform Bosch Sensortec without delay of all security relevant incidents.
*
* Engineering Samples are marked with an asterisk (*) or (e). Samples may vary from the valid
* technical specifications of the product series. They are therefore not intended or fit for resale to third
* parties or for use in end products. Their sole purpose is internal client testing. The testing of an
* engineering sample may in no way replace the testing of a product series. Bosch Sensortec
* assumes no liability for the use of engineering samples. By accepting the engineering samples, the
* Purchaser agrees to indemnify Bosch Sensortec from all claims arising from the use of engineering
* samples.
*
* Special:
* This software module (hereinafter called "Software") and any information on application-sheets
* (hereinafter called "Information") is provided free of charge for the sole purpose to support your
* application work. The Software and Information is subject to the following terms and conditions:
*
* The Software is specifically designed for the exclusive use for Bosch Sensortec products by
* personnel who have special experience and training. Do not use this Software if you do not have the
* proper experience or training.
*
* This Software package is provided `` as is `` and without any expressed or implied warranties,
* including without limitation, the implied warranties of merchantability and fitness for a particular
* purpose.
*
* Bosch Sensortec and their representatives and agents deny any liability for the functional impairment
* of this Software in terms of fitness, performance and safety. Bosch Sensortec and their
* representatives and agents shall not be liable for any direct or indirect damages or injury, except as
* otherwise stipulated in mandatory applicable law.
*
* The Information provided is believed to be accurate and reliable. Bosch Sensortec assumes no
* responsibility for the consequences of use of such Information nor for any infringement of patents or
* other rights of third parties which may result from its use. No license is granted by implication or
* otherwise under any patent or patent rights of Bosch. Specifications mentioned in the Information are
* subject to change without notice.
*
* It is not allowed to deliver the source code of the Software to any third party without permission of
* Bosch Sensortec.
*
*/
/*!
* @file bsec_integration.c
*
* @brief
* Private part of the example for using of BSEC library.
*/
/*!
* @addtogroup bsec_examples BSEC Examples
* @brief BSEC usage examples
* @{*/
/**********************************************************************************************************************/
/* header files */
/**********************************************************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include "bsec_integration.h"
/**********************************************************************************************************************/
/* local macro definitions */
/**********************************************************************************************************************/
#if (OUTPUT_MODE == CLASSIFICATION || OUTPUT_MODE == REGRESSION)
#define NUM_USED_OUTPUTS 9
#elif (OUTPUT_MODE == IAQ)
#define NUM_USED_OUTPUTS 14
#endif
/**********************************************************************************************************************/
/* global variable declarations */
/**********************************************************************************************************************/
/* Global sensor APIs data structure */
static struct bme68x_dev bme68x_g[NUM_OF_SENS] = {};
static struct bme68x_conf conf;
static struct bme68x_heatr_conf heatr_conf;
static struct bme68x_data sensor_data[3];
uint8_t dev_addr = BME68X_I2C_ADDR_LOW;
/* State change and temporary data place holders */
uint8_t lastOpMode[NUM_OF_SENS] = { BME68X_SLEEP_MODE, BME68X_SLEEP_MODE, BME68X_SLEEP_MODE, BME68X_SLEEP_MODE,
BME68X_SLEEP_MODE, BME68X_SLEEP_MODE, BME68X_SLEEP_MODE, BME68X_SLEEP_MODE };
float extTempOffset = 0.0f;
uint8_t opMode[NUM_OF_SENS];
uint8_t nFields, iFields;
/**********************************************************************************************************************/
/* functions */
/**********************************************************************************************************************/
/*!
* @brief Virtual sensor subscription
* Please call this function before processing of data using bsec_do_steps function
*
* @param[in] sample_rate mode to be used (either BSEC_SAMPLE_RATE_ULP or BSEC_SAMPLE_RATE_LP)
*
* @return subscription result, zero when successful
*/
static bsec_library_return_t bme68x_bsec_update_subscription(float sample_rate, uint8_t sens_no)
{
bsec_sensor_configuration_t requested_virtual_sensors[NUM_USED_OUTPUTS];
uint8_t n_requested_virtual_sensors = NUM_USED_OUTPUTS;
bsec_sensor_configuration_t required_sensor_settings[BSEC_MAX_PHYSICAL_SENSOR];
uint8_t n_required_sensor_settings = BSEC_MAX_PHYSICAL_SENSOR;
bsec_library_return_t status = BSEC_OK;
/* note: Virtual sensors as desired to be added here */
requested_virtual_sensors[0].sensor_id = BSEC_OUTPUT_RAW_PRESSURE;
requested_virtual_sensors[0].sample_rate = sample_rate;
requested_virtual_sensors[1].sensor_id = BSEC_OUTPUT_RAW_TEMPERATURE;
requested_virtual_sensors[1].sample_rate = sample_rate;
requested_virtual_sensors[2].sensor_id = BSEC_OUTPUT_RAW_HUMIDITY;
requested_virtual_sensors[2].sample_rate = sample_rate;
requested_virtual_sensors[3].sensor_id = BSEC_OUTPUT_RAW_GAS;
requested_virtual_sensors[3].sample_rate = sample_rate;
#if (OUTPUT_MODE == CLASSIFICATION)
requested_virtual_sensors[4].sensor_id = BSEC_OUTPUT_GAS_ESTIMATE_1;
requested_virtual_sensors[4].sample_rate = sample_rate;
requested_virtual_sensors[5].sensor_id = BSEC_OUTPUT_GAS_ESTIMATE_2;
requested_virtual_sensors[5].sample_rate = sample_rate;
requested_virtual_sensors[6].sensor_id = BSEC_OUTPUT_GAS_ESTIMATE_3;
requested_virtual_sensors[6].sample_rate = sample_rate;
requested_virtual_sensors[7].sensor_id = BSEC_OUTPUT_GAS_ESTIMATE_4;
requested_virtual_sensors[7].sample_rate = sample_rate;
requested_virtual_sensors[8].sensor_id = BSEC_OUTPUT_RAW_GAS_INDEX;
requested_virtual_sensors[8].sample_rate = sample_rate;
#elif (OUTPUT_MODE == REGRESSION)
requested_virtual_sensors[4].sensor_id = BSEC_OUTPUT_REGRESSION_ESTIMATE_1;
requested_virtual_sensors[4].sample_rate = sample_rate;
requested_virtual_sensors[5].sensor_id = BSEC_OUTPUT_REGRESSION_ESTIMATE_2;
requested_virtual_sensors[5].sample_rate = sample_rate;
requested_virtual_sensors[6].sensor_id = BSEC_OUTPUT_REGRESSION_ESTIMATE_3;
requested_virtual_sensors[6].sample_rate = sample_rate;
requested_virtual_sensors[7].sensor_id = BSEC_OUTPUT_REGRESSION_ESTIMATE_4;
requested_virtual_sensors[7].sample_rate = sample_rate;
requested_virtual_sensors[8].sensor_id = BSEC_OUTPUT_RAW_GAS_INDEX;
requested_virtual_sensors[8].sample_rate = sample_rate;
#elif (OUTPUT_MODE == IAQ)
requested_virtual_sensors[4].sensor_id = BSEC_OUTPUT_IAQ;
requested_virtual_sensors[4].sample_rate = sample_rate;
requested_virtual_sensors[5].sensor_id = BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE;
requested_virtual_sensors[5].sample_rate = sample_rate;
requested_virtual_sensors[6].sensor_id = BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY;
requested_virtual_sensors[6].sample_rate = sample_rate;
requested_virtual_sensors[7].sensor_id = BSEC_OUTPUT_STATIC_IAQ;
requested_virtual_sensors[7].sample_rate = sample_rate;
requested_virtual_sensors[8].sensor_id = BSEC_OUTPUT_CO2_EQUIVALENT;
requested_virtual_sensors[8].sample_rate = sample_rate;
requested_virtual_sensors[9].sensor_id = BSEC_OUTPUT_BREATH_VOC_EQUIVALENT;
requested_virtual_sensors[9].sample_rate = sample_rate;
requested_virtual_sensors[10].sensor_id = BSEC_OUTPUT_STABILIZATION_STATUS;
requested_virtual_sensors[10].sample_rate = sample_rate;
requested_virtual_sensors[11].sensor_id = BSEC_OUTPUT_RUN_IN_STATUS;
requested_virtual_sensors[11].sample_rate = sample_rate;
requested_virtual_sensors[12].sensor_id = BSEC_OUTPUT_GAS_PERCENTAGE;
requested_virtual_sensors[12].sample_rate = sample_rate;
requested_virtual_sensors[13].sensor_id = BSEC_OUTPUT_COMPENSATED_GAS;
requested_virtual_sensors[13].sample_rate = sample_rate;
#endif
/* Call bsec_update_subscription() to enable/disable the requested virtual sensors */
status = bsec_update_subscription_m(bsecInstance[sens_no], requested_virtual_sensors, n_requested_virtual_sensors, required_sensor_settings,
&n_required_sensor_settings);
return status;
}
/*!
* @brief Initialize the bme68x sensor and the BSEC library
*
* @param[in] sample_rate mode to be used (either BSEC_SAMPLE_RATE_ULP or BSEC_SAMPLE_RATE_LP)
* @param[in] temperature_offset device-specific temperature offset (due to self-heating)
* @param[in] bus_write pointer to the bus writing function
* @param[in] bus_read pointer to the bus reading function
* @param[in] sleep pointer to the system specific sleep function
* @param[in] state_load pointer to the system-specific state load function
* @param[in] config_load pointer to the system-specific config load function
* @param[in] dev pointer to the sensor communication and inventory details strucuture
*
* @return zero if successful, negative otherwise
*/
return_values_init bsec_iot_init(float sample_rate, float temperature_offset, bme68x_write_fptr_t bus_write,
bme68x_read_fptr_t bus_read, sleep_fct sleep, state_load_fct state_load, config_load_fct config_load, struct bme68x_dev dev, uint8_t sens_no)
{
return_values_init ret = {BME68X_OK, BSEC_OK};
uint8_t bsec_state[BSEC_MAX_STATE_BLOB_SIZE] = {0};
uint8_t bsec_config[BSEC_MAX_PROPERTY_BLOB_SIZE] = {0};
uint8_t work_buffer[BSEC_MAX_WORKBUFFER_SIZE] = {0};
int32_t bsec_state_len, bsec_config_len;
bme68x_g[sens_no] = dev;
/* Initialize bme68x API */
ret.bme68x_status = bme68x_init(&bme68x_g[sens_no]);
if (ret.bme68x_status != BME68X_OK)
{
return ret;
}
/* Initialize BSEC library */
ret.bsec_status = bsec_init_m(bsecInstance[sens_no]);
if (ret.bsec_status != BSEC_OK)
{
return ret;
}
/* Load library config, if available */
bsec_config_len = config_load(bsec_config, sizeof(bsec_config));
if (bsec_config_len != 0)
{
ret.bsec_status = bsec_set_configuration_m(bsecInstance[sens_no], bsec_config, bsec_config_len, work_buffer, sizeof(work_buffer));
if (ret.bsec_status != BSEC_OK)
{
return ret;
}
}
/* Load previous library state, if available */
bsec_state_len = state_load(bsec_state, sizeof(bsec_state));
if (bsec_state_len != 0)
{
ret.bsec_status = bsec_set_state_m(bsecInstance[sens_no], bsec_state, bsec_state_len, work_buffer, sizeof(work_buffer));
if (ret.bsec_status != BSEC_OK)
{
return ret;
}
}
/*
* The default offset provided has been determined by testing the sensor in LP and ULP mode on application board 3.0
* Please update the offset value after testing this on your product
*/
if (sample_rate == BSEC_SAMPLE_RATE_ULP)
{
extTempOffset = TEMP_OFFSET_ULP;
}
else if (sample_rate == BSEC_SAMPLE_RATE_LP)
{
extTempOffset = TEMP_OFFSET_LP;
}
/* Call to the function which sets the library with subscription information */
ret.bsec_status = bme68x_bsec_update_subscription(sample_rate, sens_no);
if (ret.bsec_status != BSEC_OK)
{
return ret;
}
return ret;
}
/*!
* @brief This function is written to process the sensor data for the requested virtual sensors
*
* @param[in] bsec_inputs input structure containing the information on sensors to be passed to do_steps
* @param[in] num_bsec_inputs number of inputs to be passed to do_steps
* @param[in] output_ready pointer to the function processing obtained BSEC outputs
*
* @return library function return codes, zero when successful
*/
static bsec_library_return_t bme68x_bsec_process_data(bsec_input_t *bsec_inputs, uint8_t num_bsec_inputs, output_ready_fct output_ready, uint8_t sens_no)
{
/* Output buffer set to the maximum virtual sensor outputs supported */
bsec_output_t bsec_outputs[BSEC_NUMBER_OUTPUTS];
uint8_t num_bsec_outputs = 0;
uint8_t index = 0;
bsec_library_return_t bsec_status = BSEC_OK;
output_t output = {0};
/* Check if something should be processed by BSEC */
if (num_bsec_inputs > 0)
{
/* Set number of outputs to the size of the allocated buffer */
/* BSEC_NUMBER_OUTPUTS to be defined */
num_bsec_outputs = BSEC_NUMBER_OUTPUTS;
/* Perform processing of the data by BSEC
Note:
* The number of outputs you get depends on what you asked for during bsec_update_subscription(). This is
handled under bme68x_bsec_update_subscription() function in this example file.
* The number of actual outputs that are returned is written to num_bsec_outputs. */
bsec_status = bsec_do_steps_m(bsecInstance[sens_no], bsec_inputs, num_bsec_inputs, bsec_outputs, &num_bsec_outputs);
/* Iterate through the outputs and extract the relevant ones. */
for (index = 0; index < num_bsec_outputs; index++)
{
switch (bsec_outputs[index].sensor_id)
{
case BSEC_OUTPUT_GAS_ESTIMATE_1:
output.gas_estimate_1 = bsec_outputs[index].signal;
output.gas_accuracy_1 = bsec_outputs[index].accuracy;
break;
case BSEC_OUTPUT_GAS_ESTIMATE_2:
output.gas_estimate_2 = bsec_outputs[index].signal;
output.gas_accuracy_2 = bsec_outputs[index].accuracy;
break;
case BSEC_OUTPUT_GAS_ESTIMATE_3:
output.gas_estimate_3 = bsec_outputs[index].signal;
output.gas_accuracy_3 = bsec_outputs[index].accuracy;
break;
case BSEC_OUTPUT_GAS_ESTIMATE_4:
output.gas_estimate_4 = bsec_outputs[index].signal;
output.gas_accuracy_4 = bsec_outputs[index].accuracy;
break;
case BSEC_OUTPUT_RAW_PRESSURE:
output.raw_pressure = bsec_outputs[index].signal;
break;
case BSEC_OUTPUT_RAW_TEMPERATURE:
output.raw_temp = bsec_outputs[index].signal;
break;
case BSEC_OUTPUT_RAW_HUMIDITY:
output.raw_humidity = bsec_outputs[index].signal;
break;
case BSEC_OUTPUT_RAW_GAS:
output.raw_gas = bsec_outputs[index].signal;
break;
case BSEC_OUTPUT_RAW_GAS_INDEX:
output.raw_gas_index = (uint8_t)bsec_outputs[index].signal;
break;
case BSEC_OUTPUT_REGRESSION_ESTIMATE_1:
output.gas_estimate_1 = bsec_outputs[index].signal;
output.gas_accuracy_1 = bsec_outputs[index].accuracy;
break;
case BSEC_OUTPUT_REGRESSION_ESTIMATE_2:
output.gas_estimate_2 = bsec_outputs[index].signal;
output.gas_accuracy_2 = bsec_outputs[index].accuracy;
break;
case BSEC_OUTPUT_REGRESSION_ESTIMATE_3:
output.gas_estimate_3 = bsec_outputs[index].signal;
output.gas_accuracy_3 = bsec_outputs[index].accuracy;
break;
case BSEC_OUTPUT_REGRESSION_ESTIMATE_4:
output.gas_estimate_4 = bsec_outputs[index].signal;
output.gas_accuracy_4 = bsec_outputs[index].accuracy;
break;
case BSEC_OUTPUT_IAQ:
output.iaq = bsec_outputs[index].signal;
output.iaq_accuracy = bsec_outputs[index].accuracy;
break;
case BSEC_OUTPUT_STATIC_IAQ:
output.static_iaq = bsec_outputs[index].signal;
break;
case BSEC_OUTPUT_CO2_EQUIVALENT:
output.co2_equivalent = bsec_outputs[index].signal;
break;
case BSEC_OUTPUT_BREATH_VOC_EQUIVALENT:
output.breath_voc_equivalent = bsec_outputs[index].signal;
break;
case BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE:
output.temperature = bsec_outputs[index].signal;
break;
case BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY:
output.humidity = bsec_outputs[index].signal;
break;
case BSEC_OUTPUT_STABILIZATION_STATUS:
output.stabStatus = bsec_outputs[index].signal;
break;
case BSEC_OUTPUT_RUN_IN_STATUS:
output.runInStatus = bsec_outputs[index].signal;
break;
case BSEC_OUTPUT_GAS_PERCENTAGE:
output.gas_percentage = bsec_outputs[index].signal;
break;
case BSEC_OUTPUT_COMPENSATED_GAS:
output.compensated_gas = bsec_outputs[index].signal;
break;
default:
continue;
}
/* Assume that all the returned timestamps are the same */
output.timestamp = bsec_outputs[index].time_stamp;
}
output.sens_no = sens_no;
/* Pass the extracted outputs to the user provided output_ready() function. */
if (num_bsec_outputs != 0)
output_ready(&output, bsec_status);
}
return bsec_status;
}
/*!
* @brief Read the data from registers and populate the inputs structure to be passed to do_steps function
*
* @param[in] currTimeNs system timestamp value passed for processing data
* @param[in] data input structure that contains the gas sensor data to be passed to process data
* @param[in] bsec_process_data process data variable returned from sensor_control
* @param[in] output_ready pointer to the function processing obtained BSEC outputs
*
* @return function result, one when successful & zero when unsuccessful
*/
uint8_t processData(int64_t currTimeNs, struct bme68x_data data, int32_t bsec_process_data, output_ready_fct output_ready, uint8_t sens_no)
{
bsec_input_t inputs[BSEC_MAX_PHYSICAL_SENSOR]; /* Temp, Pres, Hum & Gas */
bsec_library_return_t bsec_status = BSEC_OK;
uint8_t nInputs = 0;
/* Checks all the required sensor inputs, required for the BSEC library for the requested outputs */
if (BSEC_CHECK_INPUT(bsec_process_data, BSEC_INPUT_HEATSOURCE))
{
inputs[nInputs].sensor_id = BSEC_INPUT_HEATSOURCE;
inputs[nInputs].signal = extTempOffset;
inputs[nInputs].time_stamp = currTimeNs;
nInputs++;
}
if (BSEC_CHECK_INPUT(bsec_process_data, BSEC_INPUT_TEMPERATURE))
{
#ifdef BME68X_USE_FPU
inputs[nInputs].sensor_id = BSEC_INPUT_TEMPERATURE;
#else
inputs[nInputs].sensor_id = BSEC_INPUT_TEMPERATURE / 100.0f;
#endif
inputs[nInputs].signal = data.temperature;
inputs[nInputs].time_stamp = currTimeNs;
nInputs++;
}
if (BSEC_CHECK_INPUT(bsec_process_data, BSEC_INPUT_HUMIDITY))
{
#ifdef BME68X_USE_FPU
inputs[nInputs].sensor_id = BSEC_INPUT_HUMIDITY;
#else
inputs[nInputs].sensor_id = BSEC_INPUT_HUMIDITY / 1000.0f;
#endif
inputs[nInputs].signal = data.humidity;
inputs[nInputs].time_stamp = currTimeNs;
nInputs++;
}
if (BSEC_CHECK_INPUT(bsec_process_data, BSEC_INPUT_PRESSURE))
{
inputs[nInputs].sensor_id = BSEC_INPUT_PRESSURE;
inputs[nInputs].signal = data.pressure;
inputs[nInputs].time_stamp = currTimeNs;
nInputs++;
}
if (BSEC_CHECK_INPUT(bsec_process_data, BSEC_INPUT_GASRESISTOR) &&
(data.status & BME68X_GASM_VALID_MSK))
{
inputs[nInputs].sensor_id = BSEC_INPUT_GASRESISTOR;
inputs[nInputs].signal = data.gas_resistance;
inputs[nInputs].time_stamp = currTimeNs;
nInputs++;
}
if (BSEC_CHECK_INPUT(bsec_process_data, BSEC_INPUT_PROFILE_PART) &&
(data.status & BME68X_GASM_VALID_MSK))
{
inputs[nInputs].sensor_id = BSEC_INPUT_PROFILE_PART;
inputs[nInputs].signal = (opMode[sens_no] == BME68X_FORCED_MODE) ? 0 : data.gas_index;
inputs[nInputs].time_stamp = currTimeNs;
nInputs++;
}
if (nInputs > 0)
{
/* Processing of the input signals and returning of output samples is performed by bsec_do_steps() */
bsec_status = bme68x_bsec_process_data(inputs, nInputs, output_ready, sens_no);
if (bsec_status != BSEC_OK)
return 0;
}
return 1;
}
/*!
* @brief Function to get the measurement duration in microseconds
*
* @param[in] mode sensor operation mode to calculate the shared heater duration
*
* @return calculated duration
*/
uint32_t getMeasDur(uint8_t mode, uint8_t sens_no)
{
if (mode == BME68X_SLEEP_MODE)
mode = lastOpMode[sens_no];
return bme68x_get_meas_dur(mode, &conf, &bme68x_g[sens_no]);
}
/**
* @brief Set the BME68X sensor configuration to parallel mode
*
* @param[in] sensor_settings settings of the bme68x sensor adopted by sensor control function
*
* @return none
*/
void setBme68xConfigParallel(bsec_bme_settings_t *sensor_settings, uint8_t sens_no)
{
uint16_t sharedHeaterDur = 0;
int8_t status;
/* Set the filter, odr, temperature, pressure and humidity settings */
status = bme68x_get_conf(&conf, &bme68x_g[sens_no]);
if (status != BME68X_OK)
return;
conf.os_hum = sensor_settings->humidity_oversampling;
conf.os_temp = sensor_settings->temperature_oversampling;
conf.os_pres = sensor_settings->pressure_oversampling;
status = bme68x_set_conf(&conf, &bme68x_g[sens_no]);
if (status != BME68X_OK)
return;
sharedHeaterDur = BSEC_TOTAL_HEAT_DUR - (getMeasDur(BME68X_PARALLEL_MODE, sens_no) / INT64_C(1000));
heatr_conf.enable = BME68X_ENABLE;
heatr_conf.heatr_temp_prof = sensor_settings->heater_temperature_profile;
heatr_conf.heatr_dur_prof = sensor_settings->heater_duration_profile;
heatr_conf.shared_heatr_dur = sharedHeaterDur;
heatr_conf.profile_len = sensor_settings->heater_profile_len;
status = bme68x_set_heatr_conf(BME68X_PARALLEL_MODE, &heatr_conf, &bme68x_g[sens_no]);
if (status != BME68X_OK)
return;
status = bme68x_set_op_mode(BME68X_PARALLEL_MODE, &bme68x_g[sens_no]);
if (status != BME68X_OK)
return;
lastOpMode[sens_no] = BME68X_PARALLEL_MODE;
opMode[sens_no] = BME68X_PARALLEL_MODE;
}
/**
* @brief Set the BME68X sensor configuration to forced mode
*
* @param[in] sensor_settings settings of the bme68x sensor adopted by sensor control function
*
* @return none
*/
void setBme68xConfigForced(bsec_bme_settings_t *sensor_settings, uint8_t sens_no)
{
int8_t status;
/* Set the filter, odr, temperature, pressure and humidity settings */
status = bme68x_get_conf(&conf, &bme68x_g[sens_no]);
if (status != BME68X_OK)
return;
conf.os_hum = sensor_settings->humidity_oversampling;
conf.os_temp = sensor_settings->temperature_oversampling;
conf.os_pres = sensor_settings->pressure_oversampling;
status = bme68x_set_conf(&conf, &bme68x_g[sens_no]);
if (status != BME68X_OK)
return;
heatr_conf.enable = BME68X_ENABLE;
heatr_conf.heatr_temp = sensor_settings->heater_temperature;
heatr_conf.heatr_dur = sensor_settings->heater_duration;
status = bme68x_set_heatr_conf(BME68X_FORCED_MODE, &heatr_conf, &bme68x_g[sens_no]);
if (status != BME68X_OK)
return;
status = bme68x_set_op_mode(BME68X_FORCED_MODE, &bme68x_g[sens_no]);
if (status != BME68X_OK)
return;
lastOpMode[sens_no] = BME68X_FORCED_MODE;
opMode[sens_no] = BME68X_FORCED_MODE;
}
/**
* @brief Function to get a single data field
*/
/*!
* @brief Function to get a single data field
*
* @param[in] currTimeNs system timestamp value passed for processing data
* @param[in] data input structure that contains the gas sensor raw data collected
*
* @return number of fields to process, zero when nothing to process
*/
uint8_t getData(struct bme68x_data *data, uint8_t sens_no)
{
if (lastOpMode[sens_no] == BME68X_FORCED_MODE)
{
*data = sensor_data[0];
} else
{
if (nFields)
{
/* iFields spans from 0-2 while nFields spans from
* 0-3, where 0 means that there is no new data
*/
*data = sensor_data[iFields];
iFields++;
/* Limit reading continuously to the last fields read */
if (iFields >= nFields)
{
iFields = nFields - 1;
return 0;
}
/* Indicate if there is something left to read */
return nFields - iFields;
}
}
return 0;
}
/*!
* @brief Runs the main (endless) loop that queries sensor settings, applies them, and processes the measured data
*
* @param[in] sleep pointer to the system specific sleep function
* @param[in] get_timestamp_us pointer to the system specific timestamp derivation function
* @param[in] output_ready pointer to the function processing obtained BSEC outputs
* @param[in] state_save pointer to the system-specific state save function
* @param[in] save_intvl interval at which BSEC state should be saved (in samples)
*
* @return none
*/
void bsec_iot_loop(sleep_fct sleep, get_timestamp_us_fct get_timestamp_us, output_ready_fct output_ready,
state_save_fct state_save, uint32_t save_intvl)
{
/* Timestamp variables */
int64_t time_stamp = 0;
/* BSEC sensor settings struct */
bsec_bme_settings_t sensor_settings[NUM_OF_SENS];
for (uint8_t i = 0; i < NUM_OF_SENS; i++) {
memset(&sensor_settings[i], 0, sizeof(sensor_settings[i]));
opMode[i] = sensor_settings[i].op_mode;
sensor_settings[i].next_call = 0;
}
/* BSEC sensor data */
struct bme68x_data data;
/* Save state variables */
uint8_t bsec_state[BSEC_MAX_STATE_BLOB_SIZE];
uint8_t work_buffer[BSEC_MAX_WORKBUFFER_SIZE];
uint8_t nFieldsLeft = 0;
uint32_t bsec_state_len = 0;
uint32_t n_samples = 0;
int8_t ret_val;
bsec_library_return_t bsec_status = BSEC_OK;
while (1)
{
for (uint8_t sens_no = 0; sens_no < NUM_OF_SENS; sens_no++) {
/* get the timestamp in nanoseconds before calling bsec_sensor_control() */
time_stamp = get_timestamp_us() * 1000;
if (time_stamp >= sensor_settings[sens_no].next_call)
{
/* Retrieve sensor settings to be used in this time instant by calling bsec_sensor_control */
bsec_status = bsec_sensor_control_m(bsecInstance[sens_no], time_stamp, &sensor_settings[sens_no]);
if (bsec_status != BSEC_OK)
{
if (bsec_status < BSEC_OK)
{
printf("ERROR: bsec_sensor_control: %d\n", bsec_status);
break;
}
else
{
printf("WARNING: bsec_sensor_control: %d\n", bsec_status);
}
}
switch (sensor_settings[sens_no].op_mode)
{
case BME68X_FORCED_MODE:
setBme68xConfigForced(&sensor_settings[sens_no], sens_no);
break;
case BME68X_PARALLEL_MODE:
if (opMode[sens_no] != sensor_settings[sens_no].op_mode)
{
setBme68xConfigParallel(&sensor_settings[sens_no], sens_no);
}
break;
case BME68X_SLEEP_MODE:
if (opMode[sens_no] != sensor_settings[sens_no].op_mode)
{
ret_val = bme68x_set_op_mode(BME68X_SLEEP_MODE, &bme68x_g[sens_no]);
if ((ret_val == BME68X_OK) && (opMode[sens_no] != BME68X_SLEEP_MODE))
{
opMode[sens_no] = BME68X_SLEEP_MODE;
}
}
break;
}
if (sensor_settings[sens_no].trigger_measurement && sensor_settings[sens_no].op_mode != BME68X_SLEEP_MODE)
{
nFields = 0;
bme68x_get_data(lastOpMode[sens_no], &sensor_data[0], &nFields, &bme68x_g[sens_no]);
iFields = 0;
if(nFields)
{
do
{
nFieldsLeft = getData(&data, sens_no);
/* check for valid gas data */
if (data.status & BME68X_GASM_VALID_MSK)
{
if (!processData(time_stamp, data, sensor_settings[sens_no].process_data, output_ready, sens_no))
{
return;
}
}
}while(nFieldsLeft);
}
}
/* Increment sample counter */
n_samples++;
/* Retrieve and store state if the passed save_intvl */
if (n_samples >= save_intvl)
{
bsec_status = bsec_get_state_m(bsecInstance[sens_no], 0, bsec_state, sizeof(bsec_state), work_buffer, sizeof(work_buffer), &bsec_state_len);
if (bsec_status == BSEC_OK)
{
state_save(bsec_state, bsec_state_len);
}
n_samples = 0;
}
}
}
}
}
/**
* @brief Function to assign the memory block to the bsec instance
*/
void allocateMemory(uint8_t *memBlock, uint8_t sens_no)
{
/* allocating memory for the bsec instance */
bsecInstance[sens_no] = memBlock;
}
/*! @}*/

View File

@@ -0,0 +1,240 @@
/**
* Copyright (C) Bosch Sensortec GmbH. All Rights Reserved. Confidential.
*
* Disclaimer
*
* Common:
* Bosch Sensortec products are developed for the consumer goods industry. They may only be used
* within the parameters of the respective valid product data sheet. Bosch Sensortec products are
* provided with the express understanding that there is no warranty of fitness for a particular purpose.
* They are not fit for use in life-sustaining, safety or security sensitive systems or any system or device
* that may lead to bodily harm or property damage if the system or device malfunctions. In addition,
* Bosch Sensortec products are not fit for use in products which interact with motor vehicle systems.
* The resale and/or use of products are at the purchaser's own risk and his own responsibility. The
* examination of fitness for the intended use is the sole responsibility of the Purchaser.
*
* The purchaser shall indemnify Bosch Sensortec from all third party claims, including any claims for
* incidental, or consequential damages, arising from any product use not covered by the parameters of
* the respective valid product data sheet or not approved by Bosch Sensortec and reimburse Bosch
* Sensortec for all costs in connection with such claims.
*
* The purchaser must monitor the market for the purchased products, particularly with regard to
* product safety and inform Bosch Sensortec without delay of all security relevant incidents.
*
* Engineering Samples are marked with an asterisk (*) or (e). Samples may vary from the valid
* technical specifications of the product series. They are therefore not intended or fit for resale to third
* parties or for use in end products. Their sole purpose is internal client testing. The testing of an
* engineering sample may in no way replace the testing of a product series. Bosch Sensortec
* assumes no liability for the use of engineering samples. By accepting the engineering samples, the
* Purchaser agrees to indemnify Bosch Sensortec from all claims arising from the use of engineering
* samples.
*
* Special:
* This software module (hereinafter called "Software") and any information on application-sheets
* (hereinafter called "Information") is provided free of charge for the sole purpose to support your
* application work. The Software and Information is subject to the following terms and conditions:
*
* The Software is specifically designed for the exclusive use for Bosch Sensortec products by
* personnel who have special experience and training. Do not use this Software if you do not have the
* proper experience or training.
*
* This Software package is provided `` as is `` and without any expressed or implied warranties,
* including without limitation, the implied warranties of merchantability and fitness for a particular
* purpose.
*
* Bosch Sensortec and their representatives and agents deny any liability for the functional impairment
* of this Software in terms of fitness, performance and safety. Bosch Sensortec and their
* representatives and agents shall not be liable for any direct or indirect damages or injury, except as
* otherwise stipulated in mandatory applicable law.
*
* The Information provided is believed to be accurate and reliable. Bosch Sensortec assumes no
* responsibility for the consequences of use of such Information nor for any infringement of patents or
* other rights of third parties which may result from its use. No license is granted by implication or
* otherwise under any patent or patent rights of Bosch. Specifications mentioned in the Information are
* subject to change without notice.
*
* It is not allowed to deliver the source code of the Software to any third party without permission of
* Bosch Sensortec.
*
*/
/*!
* @file bsec_integration.h
*
* @brief
* Contains BSEC integration API
*/
/*!
* @addtogroup bsec_examples BSEC Examples
* @brief BSEC usage examples
* @{*/
#ifndef __BSEC_INTEGRATION_H__
#define __BSEC_INTEGRATION_H__
#ifdef __cplusplus
extern "C"
{
#endif
/**********************************************************************************************************************/
/* header files */
/**********************************************************************************************************************/
#include "bme68x.h"
/* BSEC header files are available in the inc/ folder of the release package */
#include "bsec_interface_multi.h"
#include "bsec_datatypes.h"
#define BSEC_CHECK_INPUT(x, shift) (x & (1 << (shift-1)))
#define BSEC_TOTAL_HEAT_DUR UINT16_C(140)
/* Note :
For the classification output from BSEC algorithm set OUTPUT_MODE to CLASSIFICATION (default).
For the regression output from BSEC algorithm set OUTPUT_MODE to REGRESSION.
For the LP, ULP, CONT output from BSEC algorithm set OUTPUT_MODE to IAQ
*/
#define CLASSIFICATION 1
#define REGRESSION 2
#define IAQ 3
#define OUTPUT_MODE CLASSIFICATION
/* Note :
Set the appropriate "SAMPLE_RATE" based on configured "OUTPUT_MODE".
* If the "OUTPUT_MODE" value is "CLASSIFICATION" (or) "REGRESSION", the "SAMPLE_RATE" assigned is "BSEC_SAMPLE_RATE_SCAN" (default).
* If the "OUTPUT_MODE" value is "IAQ", the "SAMPLE_RATE" assigned is "BSEC_SAMPLE_RATE_ULP" (default).
* For the "OUTPUT_MODE" as "IAQ" the other supported "SAMPLE_RATE" is "BSEC_SAMPLE_RATE_CONT" (or) "BSEC_SAMPLE_RATE_LP".
*/
#if (OUTPUT_MODE == CLASSIFICATION || OUTPUT_MODE == REGRESSION)
#define SAMPLE_RATE BSEC_SAMPLE_RATE_SCAN
#elif (OUTPUT_MODE == IAQ)
#define SAMPLE_RATE BSEC_SAMPLE_RATE_ULP
#endif
#define BSEC_INSTANCE_SIZE 3272
#define NUM_OF_SENS UINT8_C(8)
/*
* The default offset provided has been determined by testing the sensor in LP and ULP mode on application board 3.0
* Please update the offset value after testing this on your product
*/
#define TEMP_OFFSET_LP (1.3255f)
#define TEMP_OFFSET_ULP (0.466f)
uint8_t bsec_mem_block[NUM_OF_SENS][BSEC_INSTANCE_SIZE];
uint8_t *bsecInstance[NUM_OF_SENS];
/**********************************************************************************************************************/
/* type definitions */
/**********************************************************************************************************************/
/* Structure to store the BSEC output values */
typedef struct
{
int64_t timestamp;
float gas_estimate_1;
float gas_estimate_2;
float gas_estimate_3;
float gas_estimate_4;
float raw_pressure;
float raw_temp;
float raw_humidity;
float raw_gas;
uint8_t raw_gas_index;
uint8_t gas_accuracy_1;
uint8_t gas_accuracy_2;
uint8_t gas_accuracy_3;
uint8_t gas_accuracy_4;
uint8_t sens_no;
float iaq;
uint8_t iaq_accuracy;
float temperature;
float humidity;
float static_iaq;
float stabStatus;
float runInStatus;
float co2_equivalent;
float breath_voc_equivalent;
float gas_percentage;
float compensated_gas;
}output_t;
/* function pointer to the system specific sleep function */
typedef void (*sleep_fct)(uint32_t t_us,void *intf_ptr);
/* function pointer to the system specific timestamp derivation function */
typedef int64_t (*get_timestamp_us_fct)();
/* function pointer to the function processing obtained BSEC outputs */
typedef void (*output_ready_fct)(output_t *output, bsec_library_return_t bsec_status);
/* function pointer to the function loading a previous BSEC state from NVM */
typedef uint32_t (*state_load_fct)(uint8_t *state_buffer, uint32_t n_buffer);
/* function pointer to the function saving BSEC state to NVM */
typedef void (*state_save_fct)(const uint8_t *state_buffer, uint32_t length);
/* function pointer to the function loading the BSEC configuration string from NVM */
typedef uint32_t (*config_load_fct)(uint8_t *state_buffer, uint32_t n_buffer);
/* structure definitions */
/* Structure with the return value from bsec_iot_init() */
typedef struct{
/*! Result of API execution status */
int8_t bme68x_status;
/*! Result of BSEC library */
bsec_library_return_t bsec_status;
}return_values_init;
/**********************************************************************************************************************/
/* function declarations */
/**********************************************************************************************************************/
/*!
* @brief Initialize the bme68x sensor and the BSEC library
*
* @param[in] sample_rate mode to be used (either BSEC_SAMPLE_RATE_ULP or BSEC_SAMPLE_RATE_LP)
* @param[in] temperature_offset device-specific temperature offset (due to self-heating)
* @param[in] bus_write pointer to the bus writing function
* @param[in] bus_read pointer to the bus reading function
* @param[in] sleep pointer to the system-specific sleep function
* @param[in] state_load pointer to the system-specific state load function
* @param[in] sens_no sensor no
*
* @return zero if successful, negative otherwise
*/
return_values_init bsec_iot_init(float sample_rate, float temperature_offset, bme68x_write_fptr_t bus_write, bme68x_read_fptr_t bus_read,
sleep_fct sleep_n, state_load_fct state_load, config_load_fct config_load, struct bme68x_dev dev, uint8_t sens_no);
/*!
* @brief Runs the main (endless) loop that queries sensor settings, applies them, and processes the measured data
*
* @param[in] sleep pointer to the system-specific sleep function
* @param[in] get_timestamp_us pointer to the system-specific timestamp derivation function
* @param[in] output_ready pointer to the function processing obtained BSEC outputs
* @param[in] state_save pointer to the system-specific state save function
* @param[in] save_intvl interval at which BSEC state should be saved (in samples)
*
* @return return_values_init struct with the result of the API and the BSEC library
*/
void bsec_iot_loop(sleep_fct sleep_n, get_timestamp_us_fct get_timestamp_us, output_ready_fct output_ready,
state_save_fct state_save, uint32_t save_intvl);
/**
* @brief Function to assign the memory block to the bsec instance
*
* @param[in] memBlock : reference to the memory block
* @param[in] sens_no : sensor no
*/
void allocateMemory(uint8_t *memBlock, uint8_t sens_no);
#ifdef __cplusplus
}
#endif
#endif /* __BSEC_INTEGRATION_H__ */
/*! @}*/

View File

@@ -0,0 +1,563 @@
/**
* Copyright (C) Bosch Sensortec GmbH. All Rights Reserved. Confidential.
*
* Disclaimer
*
* Common:
* Bosch Sensortec products are developed for the consumer goods industry. They may only be used
* within the parameters of the respective valid product data sheet. Bosch Sensortec products are
* provided with the express understanding that there is no warranty of fitness for a particular purpose.
* They are not fit for use in life-sustaining, safety or security sensitive systems or any system or device
* that may lead to bodily harm or property damage if the system or device malfunctions. In addition,
* Bosch Sensortec products are not fit for use in products which interact with motor vehicle systems.
* The resale and/or use of products are at the purchaser's own risk and his own responsibility. The
* examination of fitness for the intended use is the sole responsibility of the Purchaser.
*
* The purchaser shall indemnify Bosch Sensortec from all third party claims, including any claims for
* incidental, or consequential damages, arising from any product use not covered by the parameters of
* the respective valid product data sheet or not approved by Bosch Sensortec and reimburse Bosch
* Sensortec for all costs in connection with such claims.
*
* The purchaser must monitor the market for the purchased products, particularly with regard to
* product safety and inform Bosch Sensortec without delay of all security relevant incidents.
*
* Engineering Samples are marked with an asterisk (*) or (e). Samples may vary from the valid
* technical specifications of the product series. They are therefore not intended or fit for resale to third
* parties or for use in end products. Their sole purpose is internal client testing. The testing of an
* engineering sample may in no way replace the testing of a product series. Bosch Sensortec
* assumes no liability for the use of engineering samples. By accepting the engineering samples, the
* Purchaser agrees to indemnify Bosch Sensortec from all claims arising from the use of engineering
* samples.
*
* Special:
* This software module (hereinafter called "Software") and any information on application-sheets
* (hereinafter called "Information") is provided free of charge for the sole purpose to support your
* application work. The Software and Information is subject to the following terms and conditions:
*
* The Software is specifically designed for the exclusive use for Bosch Sensortec products by
* personnel who have special experience and training. Do not use this Software if you do not have the
* proper experience or training.
*
* This Software package is provided `` as is `` and without any expressed or implied warranties,
* including without limitation, the implied warranties of merchantability and fitness for a particular
* purpose.
*
* Bosch Sensortec and their representatives and agents deny any liability for the functional impairment
* of this Software in terms of fitness, performance and safety. Bosch Sensortec and their
* representatives and agents shall not be liable for any direct or indirect damages or injury, except as
* otherwise stipulated in mandatory applicable law.
*
* The Information provided is believed to be accurate and reliable. Bosch Sensortec assumes no
* responsibility for the consequences of use of such Information nor for any infringement of patents or
* other rights of third parties which may result from its use. No license is granted by implication or
* otherwise under any patent or patent rights of Bosch. Specifications mentioned in the Information are
* subject to change without notice.
*
* It is not allowed to deliver the source code of the Software to any third party without permission of
* Bosch Sensortec.
*
* @file bsec_interface.h
*
* @brief
* Contains the API for BSEC
*
*/
#ifndef __BSEC_INTERFACE_H__
#define __BSEC_INTERFACE_H__
#include "bsec_datatypes.h"
#ifdef __cplusplus
extern "C" {
#endif
/*! @addtogroup bsec_interface BSEC Standard Interfaces
* @brief Standard interfaces of BSEC signal processing library.
* These interfaces supports in interfacing single BME68x sensor with the BSEC library.
*
* ### Interface usage
*
* The following provides a short overview on the typical operation sequence for BSEC.
*
* - Initialization of the library
*
* | Steps | Function |
* |---------------------------------------------------------------------|--------------------------|
* | Initialization of library | bsec_init() |
* | Update configuration settings (optional) | bsec_set_configuration() |
* | Restore the state of the library (optional) | bsec_set_state() |
*
*
* - The following function is called to enable output signals and define their sampling rate / operation mode.
*
* | Steps | Function |
* |---------------------------------------------|----------------------------|
* | Enable library outputs with specified mode | bsec_update_subscription() |
*
*
* - This table describes the main processing loop.
*
* | Steps | Function |
* |-------------------------------------------|----------------------------------|
* | Retrieve sensor settings to be used | bsec_sensor_control() |
* | Configure sensor and trigger measurement | [See BME68x API and example codes](https://github.com/BoschSensortec/BME68x-Sensor-API) |
* | Read results from sensor | [See BME68x API and example codes](https://github.com/BoschSensortec/BME68x-Sensor-API) |
* | Perform signal processing | bsec_do_steps() |
*
*
* - Before shutting down the system, the current state of BSEC can be retrieved and can then be used during
* re-initialization to continue processing.
*
* | Steps | Function |
* |---------------------------------------------|-------------------|
* | Retrieve the current library state | bsec_get_state() |
* | Retrieve the current library configuration | bsec_get_configuration() |
*
*
* ### Configuration and state
*
* Values of variables belonging to a BSEC instance are divided into two groups:
* - Values **not updated by processing** of signals belong to the **configuration group**. If available, BSEC can be
* configured before use with a customer specific configuration string.
* - Values **updated during processing** are member of the **state group**. Saving and restoring of the state of BSEC
* is necessary to maintain previously estimated sensor models and baseline information which is important for best
* performance of the gas sensor outputs.
*
* @note BSEC library consists of adaptive algorithms which models the gas sensor which improves its performance over
* the time. These will be lost if library is initialized due to system reset. In order to avoid this situation
* library state shall be stored in non volatile memory so that it can be loaded after system reset.
*
*
* @{
*/
/*!
* @brief Return the version information of BSEC library
*
* @param [out] bsec_version_p pointer to struct which is to be populated with the version information
*
* @return Zero if successful, otherwise an error code
*
* See also: bsec_version_t
*
\code{.c}
// Example //
bsec_version_t version;
bsec_get_version(&version);
printf("BSEC version: %d.%d.%d.%d",version.major, version.minor, version.major_bugfix, version.minor_bugfix);
\endcode
*/
bsec_library_return_t bsec_get_version(bsec_version_t * bsec_version_p);
/*!
* @brief Initialize the library
*
* Initialization and reset of BSEC is performed by calling bsec_init(). Calling this function sets up the relation
* among all internal modules, initializes run-time dependent library states and resets the configuration and state
* of all BSEC signal processing modules to defaults.
*
* Before any further use, the library must be initialized. This ensure that all memory and states are in defined
* conditions prior to processing any data.
*
* @return Zero if successful, otherwise an error code
*
\code{.c}
// Initialize BSEC library before further use
bsec_init();
\endcode
*/
bsec_library_return_t bsec_init(void);
/*!
* @brief Subscribe to library virtual sensors outputs
*
* Use bsec_update_subscription() to instruct BSEC which of the processed output signals are requested at which sample rates.
* See ::bsec_virtual_sensor_t for available library outputs.
*
* Based on the requested virtual sensors outputs, BSEC will provide information about the required physical sensor input signals
* (see ::bsec_physical_sensor_t) with corresponding sample rates. This information is purely informational as bsec_sensor_control()
* will ensure the sensor is operated in the required manner. To disable a virtual sensor, set the sample rate to ::BSEC_SAMPLE_RATE_DISABLED.
*
* The subscription update using bsec_update_subscription() is apart from the signal processing one of the the most
* important functions. It allows to enable the desired library outputs. The function determines which physical input
* sensor signals are required at which sample rate to produce the virtual output sensor signals requested by the user.
* When this function returns with success, the requested outputs are called subscribed. A very important feature is the
* retaining of already subscribed outputs. Further outputs can be requested or disabled both individually and
* group-wise in addition to already subscribed outputs without changing them unless a change of already subscribed
* outputs is requested.
*
* @note The state of the library concerning the subscribed outputs cannot be retained among reboots.
*
* The interface of bsec_update_subscription() requires the usage of arrays of sensor configuration structures.
* Such a structure has the fields sensor identifier and sample rate. These fields have the properties:
* - Output signals of virtual sensors must be requested using unique identifiers (Member of ::bsec_virtual_sensor_t)
* - Different sets of identifiers are available for inputs of physical sensors and outputs of virtual sensors
* - Identifiers are unique values defined by the library, not from external
* - Sample rates must be provided as value of
* - An allowed sample rate for continuously sampled signals
* - 65535.0f (BSEC_SAMPLE_RATE_DISABLED) to turn off outputs and identify disabled inputs
*
* @note The same sensor identifiers are also used within the functions bsec_do_steps().
*
* The usage principles of bsec_update_subscription() are:
* - Differential updates (i.e., only asking for outputs that the user would like to change) is supported.
* - Invalid requests of outputs are ignored. Also if one of the requested outputs is unavailable, all the requests
* are ignored. At the same time, a warning is returned.
* - To disable BSEC, all outputs shall be turned off. Only enabled (subscribed) outputs have to be disabled while
* already disabled outputs do not have to be disabled explicitly.
*
* @param[in] requested_virtual_sensors Pointer to array of requested virtual sensor (output) configurations for the library
* @param[in] n_requested_virtual_sensors Number of virtual sensor structs pointed by requested_virtual_sensors
* @param[out] required_sensor_settings Pointer to array of required physical sensor configurations for the library
* @param[in,out] n_required_sensor_settings [in] Size of allocated required_sensor_settings array, [out] number of sensor configurations returned
*
* @return Zero when successful, otherwise an error code
*
* @sa bsec_sensor_configuration_t
* @sa bsec_physical_sensor_t
* @sa bsec_virtual_sensor_t
*
\code{.c}
// Example //
// Change 3 virtual sensors (switch IAQ and raw temperature -> on / pressure -> off)
bsec_sensor_configuration_t requested_virtual_sensors[3];
uint8_t n_requested_virtual_sensors = 3;
requested_virtual_sensors[0].sensor_id = BSEC_OUTPUT_IAQ;
requested_virtual_sensors[0].sample_rate = BSEC_SAMPLE_RATE_ULP;
requested_virtual_sensors[1].sensor_id = BSEC_OUTPUT_RAW_TEMPERATURE;
requested_virtual_sensors[1].sample_rate = BSEC_SAMPLE_RATE_ULP;
requested_virtual_sensors[2].sensor_id = BSEC_OUTPUT_RAW_PRESSURE;
requested_virtual_sensors[2].sample_rate = BSEC_SAMPLE_RATE_DISABLED;
// Allocate a struct for the returned physical sensor settings
bsec_sensor_configuration_t required_sensor_settings[BSEC_MAX_PHYSICAL_SENSOR];
uint8_t n_required_sensor_settings = BSEC_MAX_PHYSICAL_SENSOR;
// Call bsec_update_subscription() to enable/disable the requested virtual sensors
bsec_update_subscription(requested_virtual_sensors, n_requested_virtual_sensors, required_sensor_settings, &n_required_sensor_settings);
\endcode
*
*/
bsec_library_return_t bsec_update_subscription(const bsec_sensor_configuration_t * const requested_virtual_sensors,
const uint8_t n_requested_virtual_sensors, bsec_sensor_configuration_t * required_sensor_settings,
uint8_t * n_required_sensor_settings);
/*!
* @brief Main signal processing function of BSEC
*
*
* Processing of the input signals and returning of output samples is performed by bsec_do_steps().
* - The samples of all library inputs must be passed with unique identifiers representing the input signals from
* physical sensors where the order of these inputs can be chosen arbitrary. However, all input have to be provided
* within the same time period as they are read. A sequential provision to the library might result in undefined
* behavior.
* - The samples of all library outputs are returned with unique identifiers corresponding to the output signals of
* virtual sensors where the order of the returned outputs may be arbitrary.
* - The samples of all input as well as output signals of physical as well as virtual sensors use the same
* representation in memory with the following fields:
* - Sensor identifier:
* - For inputs: required to identify the input signal from a physical sensor
* - For output: overwritten by bsec_do_steps() to identify the returned signal from a virtual sensor
* - Time stamp of the sample
*
* Calling bsec_do_steps() requires the samples of the input signals to be provided along with their time stamp when
* they are recorded and only when they are acquired. Repetition of samples with the same time stamp are ignored and
* result in a warning. Repetition of values of samples which are not acquired anew by a sensor result in deviations
* of the computed output signals. Concerning the returned output samples, an important feature is, that a value is
* returned for an output only when a new occurrence has been computed. A sample of an output signal is returned only
* once.
*
*
* @param[in] inputs Array of input data samples. Each array element represents a sample of a different physical sensor.
* @param[in] n_inputs Number of passed input data structs.
* @param[out] outputs Array of output data samples. Each array element represents a sample of a different virtual sensor.
* @param[in,out] n_outputs [in] Number of allocated output structs, [out] number of outputs returned
*
* @return Zero when successful, otherwise an error code
*
\code{.c}
// Example //
// Allocate input and output memory
bsec_input_t input[3];
uint8_t n_input = 3;
bsec_output_t output[2];
uint8_t n_output=2;
bsec_library_return_t status;
// Populate the input structs, assuming the we have timestamp (ts),
// gas sensor resistance (R), temperature (T), and humidity (rH) available
// as input variables
input[0].sensor_id = BSEC_INPUT_GASRESISTOR;
input[0].signal = R;
input[0].time_stamp= ts;
input[1].sensor_id = BSEC_INPUT_TEMPERATURE;
input[1].signal = T;
input[1].time_stamp= ts;
input[2].sensor_id = BSEC_INPUT_HUMIDITY;
input[2].signal = rH;
input[2].time_stamp= ts;
// Invoke main processing BSEC function
status = bsec_do_steps( input, n_input, output, &n_output );
// Iterate through the BSEC output data, if the call succeeded
if(status == BSEC_OK)
{
for(int i = 0; i < n_output; i++)
{
switch(output[i].sensor_id)
{
case BSEC_OUTPUT_IAQ:
// Retrieve the IAQ results from output[i].signal
// and do something with the data
break;
case BSEC_OUTPUT_STATIC_IAQ:
// Retrieve the static IAQ results from output[i].signal
// and do something with the data
break;
}
}
}
\endcode
*/
bsec_library_return_t bsec_do_steps(const bsec_input_t * const inputs, const uint8_t n_inputs, bsec_output_t * outputs, uint8_t * n_outputs);
/*!
* @brief Reset a particular virtual sensor output
*
* This function allows specific virtual sensor outputs to be reset. The meaning of "reset" depends on the specific
* output. In case of the IAQ output, reset means zeroing the output to the current ambient conditions.
*
* @param[in] sensor_id Virtual sensor to be reset
*
* @return Zero when successful, otherwise an error code
*
*
\code{.c}
// Example //
bsec_reset_output(BSEC_OUTPUT_IAQ);
\endcode
*/
bsec_library_return_t bsec_reset_output(uint8_t sensor_id);
/*!
* @brief Update algorithm configuration parameters
*
* BSEC uses a default configuration for the modules and common settings. The initial configuration can be customized
* by bsec_set_configuration(). This is an optional step.
*
* @note A work buffer with sufficient size is required and has to be provided by the function caller to decompose
* the serialization and apply it to the library and its modules.
*
* Please use #BSEC_MAX_PROPERTY_BLOB_SIZE for allotting the required size.
*
* @param[in] serialized_settings Settings serialized to a binary blob
* @param[in] n_serialized_settings Size of the settings blob
* @param[in,out] work_buffer Work buffer used to parse the blob
* @param[in] n_work_buffer_size Length of the work buffer available for parsing the blob
*
* @return Zero when successful, otherwise an error code
*
\code{.c}
// Example //
// Allocate variables
uint8_t serialized_settings[BSEC_MAX_PROPERTY_BLOB_SIZE];
uint32_t n_serialized_settings_max = BSEC_MAX_PROPERTY_BLOB_SIZE;
uint8_t work_buffer[BSEC_MAX_WORKBUFFER_SIZE];
uint32_t n_work_buffer = BSEC_MAX_WORKBUFFER_SIZE;
// Here we will load a provided config string into serialized_settings
// Apply the configuration
bsec_set_configuration(serialized_settings, n_serialized_settings_max, work_buffer, n_work_buffer);
\endcode
*/
bsec_library_return_t bsec_set_configuration(const uint8_t * const serialized_settings,
const uint32_t n_serialized_settings, uint8_t * work_buffer,
const uint32_t n_work_buffer_size);
/*!
* @brief Restore the internal state of the library
*
* BSEC uses a default state for all signal processing modules and the BSEC module. To ensure optimal performance,
* especially of the gas sensor functionality, it is recommended to retrieve the state using bsec_get_state()
* before unloading the library, storing it in some form of non-volatile memory, and setting it using bsec_set_state()
* before resuming further operation of the library.
*
* @note A work buffer with sufficient size is required and has to be provided by the function caller to decompose the
* serialization and apply it to the library and its modules.
*
* Please use #BSEC_MAX_STATE_BLOB_SIZE for allotting the required size.
*
* @param[in] serialized_state States serialized to a binary blob
* @param[in] n_serialized_state Size of the state blob
* @param[in,out] work_buffer Work buffer used to parse the blob
* @param[in] n_work_buffer_size Length of the work buffer available for parsing the blob
*
* @return Zero when successful, otherwise an error code
*
\code{.c}
// Example //
// Allocate variables
uint8_t serialized_state[BSEC_MAX_PROPERTY_BLOB_SIZE];
uint32_t n_serialized_state = BSEC_MAX_PROPERTY_BLOB_SIZE;
uint8_t work_buffer_state[BSEC_MAX_WORKBUFFER_SIZE];
uint32_t n_work_buffer_size = BSEC_MAX_WORKBUFFER_SIZE;
// Here we will load a state string from a previous use of BSEC
// Apply the previous state to the current BSEC session
bsec_set_state(serialized_state, n_serialized_state, work_buffer_state, n_work_buffer_size);
\endcode
*/
bsec_library_return_t bsec_set_state(const uint8_t * const serialized_state, const uint32_t n_serialized_state,
uint8_t * work_buffer, const uint32_t n_work_buffer_size);
/*!
* @brief Retrieve the current library configuration
*
* BSEC allows to retrieve the current configuration using bsec_get_configuration(). Returns a binary blob encoding
* the current configuration parameters of the library in a format compatible with bsec_set_configuration().
*
* @note The function bsec_get_configuration() is required to be used for debugging purposes only.
* @note A work buffer with sufficient size is required and has to be provided by the function caller to decompose the
* serialization and apply it to the library and its modules.
*
* Please use #BSEC_MAX_PROPERTY_BLOB_SIZE for allotting the required size.
*
* @param[in] config_id Identifier for a specific set of configuration settings to be returned;
* shall be zero to retrieve all configuration settings.
* @param[out] serialized_settings Buffer to hold the serialized config blob
* @param[in] n_serialized_settings_max Maximum available size for the serialized settings
* @param[in,out] work_buffer Work buffer used to parse the binary blob
* @param[in] n_work_buffer Length of the work buffer available for parsing the blob
* @param[out] n_serialized_settings Actual size of the returned serialized configuration blob
*
* @return Zero when successful, otherwise an error code
*
\code{.c}
// Example //
// Allocate variables
uint8_t serialized_settings[BSEC_MAX_PROPERTY_BLOB_SIZE];
uint32_t n_serialized_settings_max = BSEC_MAX_PROPERTY_BLOB_SIZE;
uint8_t work_buffer[BSEC_MAX_WORKBUFFER_SIZE];
uint32_t n_work_buffer = BSEC_MAX_WORKBUFFER_SIZE;
uint32_t n_serialized_settings = 0;
// Configuration of BSEC algorithm is stored in 'serialized_settings'
bsec_get_configuration(0, serialized_settings, n_serialized_settings_max, work_buffer, n_work_buffer, &n_serialized_settings);
\endcode
*/
bsec_library_return_t bsec_get_configuration(const uint8_t config_id, uint8_t * serialized_settings, const uint32_t n_serialized_settings_max,
uint8_t * work_buffer, const uint32_t n_work_buffer, uint32_t * n_serialized_settings);
/*!
*@brief Retrieve the current internal library state
*
* BSEC allows to retrieve the current states of all signal processing modules and the BSEC module using
* bsec_get_state(). This allows a restart of the processing after a reboot of the system by calling bsec_set_state().
*
* @note A work buffer with sufficient size is required and has to be provided by the function caller to decompose the
* serialization and apply it to the library and its modules.
*
* Please use #BSEC_MAX_STATE_BLOB_SIZE for allotting the required size.
*
* @param[in] state_set_id Identifier for a specific set of states to be returned; shall be
* zero to retrieve all states.
* @param[out] serialized_state Buffer to hold the serialized config blob
* @param[in] n_serialized_state_max Maximum available size for the serialized states
* @param[in,out] work_buffer Work buffer used to parse the blob
* @param[in] n_work_buffer Length of the work buffer available for parsing the blob
* @param[out] n_serialized_state Actual size of the returned serialized blob
*
* @return Zero when successful, otherwise an error code
*
\code{.c}
// Example //
// Allocate variables
uint8_t serialized_state[BSEC_MAX_STATE_BLOB_SIZE];
uint32_t n_serialized_state_max = BSEC_MAX_STATE_BLOB_SIZE;
uint32_t n_serialized_state = BSEC_MAX_STATE_BLOB_SIZE;
uint8_t work_buffer_state[BSEC_MAX_WORKBUFFER_SIZE];
uint32_t n_work_buffer_size = BSEC_MAX_WORKBUFFER_SIZE;
// Algorithm state is stored in 'serialized_state'
bsec_get_state(0, serialized_state, n_serialized_state_max, work_buffer_state, n_work_buffer_size, &n_serialized_state);
\endcode
*/
bsec_library_return_t bsec_get_state(const uint8_t state_set_id, uint8_t * serialized_state,
const uint32_t n_serialized_state_max, uint8_t * work_buffer, const uint32_t n_work_buffer,
uint32_t * n_serialized_state);
/*!
* @brief Retrieve BMExxx sensor instructions
*
* The bsec_sensor_control() interface is a key feature of BSEC, as it allows an easy way for the signal processing
* library to control the operation of the BME sensor. This is important since gas sensor behaviour is mainly
* determined by how the integrated heater is configured. To ensure an easy integration of BSEC into any system,
* bsec_sensor_control() will provide the caller with information about the current sensor configuration that is
* necessary to fulfill the input requirements derived from the current outputs requested via
* bsec_update_subscription().
*
* In practice the use of this function shall be as follows:
* - Call bsec_sensor_control() which returns a bsec_bme_settings_t struct.
* - Based on the information contained in this struct, the sensor is configured and a forced-mode measurement is
* triggered if requested by bsec_sensor_control().
* - Once this forced-mode measurement is complete, the signals specified in this struct shall be passed to
* bsec_do_steps() to perform the signal processing.
* - After processing, the process should sleep until the bsec_bme_settings_t::next_call timestamp is reached.
*
*
* @param [in] time_stamp Current timestamp in [ns]
* @param[out] sensor_settings Settings to be passed to API to operate sensor at this time instance
*
* @return Zero when successful, otherwise an error code
*/
bsec_library_return_t bsec_sensor_control(const int64_t time_stamp, bsec_bme_settings_t *sensor_settings);
/*@}*/ //BSEC Interface
#ifdef __cplusplus
}
#endif
#endif /* __BSEC_INTERFACE_H__ */

View File

@@ -0,0 +1,334 @@
/**
* Copyright (C) Bosch Sensortec GmbH. All Rights Reserved. Confidential.
*
* Disclaimer
*
* Common:
* Bosch Sensortec products are developed for the consumer goods industry. They may only be used
* within the parameters of the respective valid product data sheet. Bosch Sensortec products are
* provided with the express understanding that there is no warranty of fitness for a particular purpose.
* They are not fit for use in life-sustaining, safety or security sensitive systems or any system or device
* that may lead to bodily harm or property damage if the system or device malfunctions. In addition,
* Bosch Sensortec products are not fit for use in products which interact with motor vehicle systems.
* The resale and/or use of products are at the purchaser's own risk and his own responsibility. The
* examination of fitness for the intended use is the sole responsibility of the Purchaser.
*
* The purchaser shall indemnify Bosch Sensortec from all third party claims, including any claims for
* incidental, or consequential damages, arising from any product use not covered by the parameters of
* the respective valid product data sheet or not approved by Bosch Sensortec and reimburse Bosch
* Sensortec for all costs in connection with such claims.
*
* The purchaser must monitor the market for the purchased products, particularly with regard to
* product safety and inform Bosch Sensortec without delay of all security relevant incidents.
*
* Engineering Samples are marked with an asterisk (*) or (e). Samples may vary from the valid
* technical specifications of the product series. They are therefore not intended or fit for resale to third
* parties or for use in end products. Their sole purpose is internal client testing. The testing of an
* engineering sample may in no way replace the testing of a product series. Bosch Sensortec
* assumes no liability for the use of engineering samples. By accepting the engineering samples, the
* Purchaser agrees to indemnify Bosch Sensortec from all claims arising from the use of engineering
* samples.
*
* Special:
* This software module (hereinafter called "Software") and any information on application-sheets
* (hereinafter called "Information") is provided free of charge for the sole purpose to support your
* application work. The Software and Information is subject to the following terms and conditions:
*
* The Software is specifically designed for the exclusive use for Bosch Sensortec products by
* personnel who have special experience and training. Do not use this Software if you do not have the
* proper experience or training.
*
* This Software package is provided `` as is `` and without any expressed or implied warranties,
* including without limitation, the implied warranties of merchantability and fitness for a particular
* purpose.
*
* Bosch Sensortec and their representatives and agents deny any liability for the functional impairment
* of this Software in terms of fitness, performance and safety. Bosch Sensortec and their
* representatives and agents shall not be liable for any direct or indirect damages or injury, except as
* otherwise stipulated in mandatory applicable law.
*
* The Information provided is believed to be accurate and reliable. Bosch Sensortec assumes no
* responsibility for the consequences of use of such Information nor for any infringement of patents or
* other rights of third parties which may result from its use. No license is granted by implication or
* otherwise under any patent or patent rights of Bosch. Specifications mentioned in the Information are
* subject to change without notice.
*
* It is not allowed to deliver the source code of the Software to any third party without permission of
* Bosch Sensortec.
*
* @file bsec_interface_multi.h
*
* @brief
* Contains the multi-instance API for BSEC
*
*/
#ifndef __BSEC_INTERFACE_MULTI_H__
#define __BSEC_INTERFACE_MULTI_H__
#include "bsec_datatypes.h"
#ifdef __cplusplus
extern "C" {
#endif
/*! @addtogroup bsec_lib_interface BSEC Multi-instance Interfaces
* @brief The multi-instance interface of BSEC signal processing library is used for interfacing multiple sensors with BSEC library.
*
* # Multi-instance interface usage
*
* The following provides a short overview on the typical operation sequence for BSEC.
*
* - Initialization of the library
*
* | Steps | Function |
* |---------------------------------------------------------------------|--------------------------|
* | Initialization of library | bsec_init_m() |
* | Update configuration settings (optional) | bsec_set_configuration_m() |
* | Restore the state of the library (optional) | bsec_set_state_m() |
*
*
* - The following function is called to enable output signals and define their sampling rate / operation mode.
*
* | Steps | Function |
* |---------------------------------------------|----------------------------|
* | Enable library outputs with specified mode | bsec_update_subscription_m() |
*
*
* - This table describes the main processing loop.
*
* | Steps | Function |
* |-------------------------------------------|----------------------------------|
* | Retrieve sensor settings to be used | bsec_sensor_control_m() |
* | Configure sensor and trigger measurement | See BME688 API and example codes |
* | Read results from sensor | See BME688 API and example codes |
* | Perform signal processing | bsec_do_steps_m() |
*
*
* - Before shutting down the system, the current state of BSEC can be retrieved and can then be used during
* re-initialization to continue processing.
*
* | Steps | Function |
* |---------------------------------------------|-------------------|
* | Retrieve the current library state | bsec_get_state_m() |
* | Retrieve the current library configuration | bsec_get_configuration_m() |
*
*
* ### Configuration and state
*
* Values of variables belonging to a BSEC instance are divided into two groups:
* - Values **not updated by processing** of signals belong to the **configuration group**. If available, BSEC can be
* configured before use with a customer specific configuration string.
* - Values **updated during processing** are member of the **state group**. Saving and restoring of the state of BSEC
* is necessary to maintain previously estimated sensor models and baseline information which is important for best
* performance of the gas sensor outputs.
*
* @note BSEC library consists of adaptive algorithms which models the gas sensor which improves its performance over
* the time. These will be lost if library is initialized due to system reset. In order to avoid this situation
* library state shall be stored in non volatile memory so that it can be loaded after system reset.
*
*
* @{
*/
/********************************************************/
/* function prototype declarations */
/*!
* @brief Function that provides the size of the internal instance in bytes.
* To be used for allocating memory for struct BSEC_STRUCT_NAME
* @return Size of the internal instance in bytes
*/
size_t bsec_get_instance_size_m(void);
/*!
* @brief Return the version information of BSEC library instance
* @param[in,out] inst Reference to the pointer containing the instance
* @param [out] bsec_version_p pointer to struct which is to be populated with the version information
*
* @return Zero if successful, otherwise an error code
*
* See also: bsec_version_t
*
*/
bsec_library_return_t bsec_get_version_m(void *inst, bsec_version_t *bsec_version_p);
/*!
* @brief Initialize the library instance
*
* Initialization and reset of BSEC library instance is performed by calling bsec_init_m() as done with bsec_init() for standard interface.
*
* @param[in,out] inst Reference to the pointer containing the instance
*
* @return Zero if successful, otherwise an error code
*
*/
bsec_library_return_t bsec_init_m(void *inst);
/*!
* @brief Subscribe to library virtual sensors outputs
*
* Like bsec_update_subscription(), bsec_update_subscription_m() is used to instruct BSEC which of the processed output signals
* of the library instance are requested at which sample rates.
*
* @param[in,out] inst Reference to the pointer containing the instance
* @param[in] requested_virtual_sensors Pointer to array of requested virtual sensor (output) configurations for the library
* @param[in] n_requested_virtual_sensors Number of virtual sensor structs pointed by requested_virtual_sensors
* @param[out] required_sensor_settings Pointer to array of required physical sensor configurations for the library
* @param[in,out] n_required_sensor_settings [in] Size of allocated required_sensor_settings array, [out] number of sensor configurations returned
*
* @return Zero when successful, otherwise an error code
*
* @sa bsec_sensor_configuration_t
* @sa bsec_physical_sensor_t
* @sa bsec_virtual_sensor_t
*
*/
bsec_library_return_t bsec_update_subscription_m(void *inst, const bsec_sensor_configuration_t *const requested_virtual_sensors,
const uint8_t n_requested_virtual_sensors, bsec_sensor_configuration_t *required_sensor_settings,
uint8_t *n_required_sensor_settings);
/*!
* @brief Main signal processing function of BSEC library instance
*
*
* Processing of the input signals and returning of output samples for each instances of BSEC library is performed by bsec_do_steps_m().
* bsec_do_steps_m() processes multiple instaces of BSEC library simillar to how bsec_do_steps() handles single instance.
*
* @param[in,out] inst Reference to the pointer containing the instance
* @param[in] inputs Array of input data samples. Each array element represents a sample of a different physical sensor.
* @param[in] n_inputs Number of passed input data structs.
* @param[out] outputs Array of output data samples. Each array element represents a sample of a different virtual sensor.
* @param[in,out] n_outputs [in] Number of allocated output structs, [out] number of outputs returned
*
* @return Zero when successful, otherwise an error code
*
*/
bsec_library_return_t bsec_do_steps_m(void *inst, const bsec_input_t *const inputs, const uint8_t n_inputs, bsec_output_t *outputs, uint8_t *n_outputs);
/*!
* @brief Reset a particular virtual sensor output of the library instance
*
* This function allows specific virtual sensor outputs of each library instance to be reset.
* It processes in same way as bsec_reset_output().
*
* @param[in,out] inst Reference to the pointer containing the instance
* @param[in] sensor_id Virtual sensor to be reset
*
* @return Zero when successful, otherwise an error code
*
*/
bsec_library_return_t bsec_reset_output_m(void *inst, uint8_t sensor_id);
/*!
* @brief Update algorithm configuration parameters of the library instance
*
* As done with bsec_set_configuration(), the initial configuration of BSEC libray instance can be customized
* by bsec_set_configuration_m(). This is an optional step.
*
* Please use #BSEC_MAX_PROPERTY_BLOB_SIZE for allotting the required size.
*
* @param[in,out] inst Reference to the pointer containing the instance
* @param[in] serialized_settings Settings serialized to a binary blob
* @param[in] n_serialized_settings Size of the settings blob
* @param[in,out] work_buffer Work buffer used to parse the blob
* @param[in] n_work_buffer_size Length of the work buffer available for parsing the blob
*
* @return Zero when successful, otherwise an error code
*
*/
bsec_library_return_t bsec_set_configuration_m(void *inst, const uint8_t *const serialized_settings,
const uint32_t n_serialized_settings, uint8_t *work_buffer,
const uint32_t n_work_buffer_size);
/*!
* @brief Restore the internal state of the library instance
*
* BSEC uses a default state for all signal processing modules and the BSEC module for each instance. To ensure optimal performance,
* especially of the gas sensor functionality, it is recommended to retrieve the state using bsec_get_state_m()
* before unloading the library, storing it in some form of non-volatile memory, and setting it using bsec_set_state_m()
* before resuming further operation of the library.
*
* Please use #BSEC_MAX_STATE_BLOB_SIZE for allotting the required size.
*
* @param[in,out] inst Reference to the pointer containing the instance
* @param[in] serialized_state States serialized to a binary blob
* @param[in] n_serialized_state Size of the state blob
* @param[in,out] work_buffer Work buffer used to parse the blob
* @param[in] n_work_buffer_size Length of the work buffer available for parsing the blob
*
* @return Zero when successful, otherwise an error code
*
*/
bsec_library_return_t bsec_set_state_m(void *inst, const uint8_t *const serialized_state, const uint32_t n_serialized_state,
uint8_t *work_buffer, const uint32_t n_work_buffer_size);
/*!
* @brief Retrieve the current library instance configuration
*
* BSEC allows to retrieve the current configuration of the library instance using bsec_get_configuration_m().
* In the same way as bsec_get_configuration(), this API returns a binary blob encoding
* the current configuration parameters of the library in a format compatible with bsec_set_configuration_m().
*
* Please use #BSEC_MAX_PROPERTY_BLOB_SIZE for allotting the required size.
*
* @param[in,out] inst Reference to the pointer containing the instance
* @param[in] config_id Identifier for a specific set of configuration settings to be returned;
* shall be zero to retrieve all configuration settings.
* @param[out] serialized_settings Buffer to hold the serialized config blob
* @param[in] n_serialized_settings_max Maximum available size for the serialized settings
* @param[in,out] work_buffer Work buffer used to parse the binary blob
* @param[in] n_work_buffer Length of the work buffer available for parsing the blob
* @param[out] n_serialized_settings Actual size of the returned serialized configuration blob
*
* @return Zero when successful, otherwise an error code
*
*/
bsec_library_return_t bsec_get_configuration_m(void *inst, const uint8_t config_id, uint8_t *serialized_settings, const uint32_t n_serialized_settings_max,
uint8_t *work_buffer, const uint32_t n_work_buffer, uint32_t *n_serialized_settings);
/*!
*@brief Retrieve the current internal library instance state
*
* BSEC allows to retrieve the current states of all signal processing modules and the BSEC module of the library instance using
* bsec_get_state_m(). As done by bsec_get_state(), this allows a restart of the processing after a reboot of the system by calling bsec_set_state_m().
*
* Please use #BSEC_MAX_STATE_BLOB_SIZE for allotting the required size.
*
* @param[in,out] inst Reference to the pointer containing the instance
* @param[in] state_set_id Identifier for a specific set of states to be returned; shall be
* zero to retrieve all states.
* @param[out] serialized_state Buffer to hold the serialized config blob
* @param[in] n_serialized_state_max Maximum available size for the serialized states
* @param[in,out] work_buffer Work buffer used to parse the blob
* @param[in] n_work_buffer Length of the work buffer available for parsing the blob
* @param[out] n_serialized_state Actual size of the returned serialized blob
*
* @return Zero when successful, otherwise an error code
*
*/
bsec_library_return_t bsec_get_state_m(void *inst, const uint8_t state_set_id, uint8_t *serialized_state,
const uint32_t n_serialized_state_max, uint8_t *work_buffer, const uint32_t n_work_buffer,
uint32_t *n_serialized_state);
/*!
* @brief Retrieve BMExxx sensor instructions for the library instance
*
* The bsec_sensor_control_m() allows an easy way for the signal processing library to control the operation of the
* BME sensor which uses the correspodning BSEC library instance. Operation of bsec_sensor_control_m() is simillar to bsec_sensor_control()
* except that former API supports multiples library instances.
*
* @param[in,out] inst Reference to the pointer containing the instance
* @param [in] time_stamp Current timestamp in [ns]
* @param[out] sensor_settings Settings to be passed to API to operate sensor at this time instance
*
* @return Zero when successful, otherwise an error code
*/
bsec_library_return_t bsec_sensor_control_m(void *inst, const int64_t time_stamp, bsec_bme_settings_t *sensor_settings);
/*@}*/ //BSEC Interface
#ifdef __cplusplus
}
#endif
#endif /* __BSEC_INTERFACE_MULTI_H__ */

View File

@@ -0,0 +1,249 @@
/**
* Copyright (C) Bosch Sensortec GmbH. All Rights Reserved. Confidential.
*
* Disclaimer
*
* Common:
* Bosch Sensortec products are developed for the consumer goods industry. They may only be used
* within the parameters of the respective valid product data sheet. Bosch Sensortec products are
* provided with the express understanding that there is no warranty of fitness for a particular purpose.
* They are not fit for use in life-sustaining, safety or security sensitive systems or any system or device
* that may lead to bodily harm or property damage if the system or device malfunctions. In addition,
* Bosch Sensortec products are not fit for use in products which interact with motor vehicle systems.
* The resale and/or use of products are at the purchaser's own risk and his own responsibility. The
* examination of fitness for the intended use is the sole responsibility of the Purchaser.
*
* The purchaser shall indemnify Bosch Sensortec from all third party claims, including any claims for
* incidental, or consequential damages, arising from any product use not covered by the parameters of
* the respective valid product data sheet or not approved by Bosch Sensortec and reimburse Bosch
* Sensortec for all costs in connection with such claims.
*
* The purchaser must monitor the market for the purchased products, particularly with regard to
* product safety and inform Bosch Sensortec without delay of all security relevant incidents.
*
* Engineering Samples are marked with an asterisk (*) or (e). Samples may vary from the valid
* technical specifications of the product series. They are therefore not intended or fit for resale to third
* parties or for use in end products. Their sole purpose is internal client testing. The testing of an
* engineering sample may in no way replace the testing of a product series. Bosch Sensortec
* assumes no liability for the use of engineering samples. By accepting the engineering samples, the
* Purchaser agrees to indemnify Bosch Sensortec from all claims arising from the use of engineering
* samples.
*
* Special:
* This software module (hereinafter called "Software") and any information on application-sheets
* (hereinafter called "Information") is provided free of charge for the sole purpose to support your
* application work. The Software and Information is subject to the following terms and conditions:
*
* The Software is specifically designed for the exclusive use for Bosch Sensortec products by
* personnel who have special experience and training. Do not use this Software if you do not have the
* proper experience or training.
*
* This Software package is provided `` as is `` and without any expressed or implied warranties,
* including without limitation, the implied warranties of merchantability and fitness for a particular
* purpose.
*
* Bosch Sensortec and their representatives and agents deny any liability for the functional impairment
* of this Software in terms of fitness, performance and safety. Bosch Sensortec and their
* representatives and agents shall not be liable for any direct or indirect damages or injury, except as
* otherwise stipulated in mandatory applicable law.
*
* The Information provided is believed to be accurate and reliable. Bosch Sensortec assumes no
* responsibility for the consequences of use of such Information nor for any infringement of patents or
* other rights of third parties which may result from its use. No license is granted by implication or
* otherwise under any patent or patent rights of Bosch. Specifications mentioned in the Information are
* subject to change without notice.
*
* It is not allowed to deliver the source code of the Software to any third party without permission of
* Bosch Sensortec.
*
*/
/*!
* @file bsec_iot_example.c
*
* @brief
* Example for using of BSEC library in a fixed configuration with the BME68x sensor.
* This works by running an endless loop in the bsec_iot_loop() function.
*/
/*!
* @addtogroup bsec_examples BSEC Examples
* @brief BSEC usage examples
* @{*/
/**********************************************************************************************************************/
/* header files */
/**********************************************************************************************************************/
#include "bsec_integration.h"
/**********************************************************************************************************************/
/* functions */
/**********************************************************************************************************************/
/*!
* @brief Write operation in either Wire or SPI
*
* param[in] reg_addr register address
* param[in] reg_data_ptr pointer to the data to be written
* param[in] data_len number of bytes to be written
* param[in] intf_ptr interface pointer
*
* @return result of the bus communication function
*/
int8_t bus_write(uint8_t reg_addr, const uint8_t *reg_data_ptr, uint32_t data_len, void *intf_ptr)
{
// ...
// Please insert system specific function to write to the bus where BME68x is connected
// ...
return 0;
}
/*!
* @brief Read operation in either Wire or SPI
*
* param[in] reg_addr register address
* param[out] reg_data_ptr pointer to the memory to be used to store the read data
* param[in] data_len number of bytes to be read
* param[in] intf_ptr interface pointer
*
* @return result of the bus communication function
*/
int8_t bus_read(uint8_t reg_addr, uint8_t *reg_data_ptr, uint32_t data_len, void *intf_ptr)
{
// ...
// Please insert system specific function to read from bus where BME68x is connected
// ...
return 0;
}
/*!
* @brief System specific implementation of sleep function
*
* @param[in] t_us Time in microseconds
* @param[in] intf_ptr Pointer to the interface descriptor
*
* @return none
*/
void sleep_n(uint32_t t_us, void *intf_ptr)
{
// ...
// Please insert system specific function sleep or delay for t_ms milliseconds
// ...
}
/*!
* @brief Capture the system time in microseconds
*
* @return system_current_time current system timestamp in microseconds
*/
int64_t get_timestamp_us()
{
int64_t system_current_time = 0;
// ...
// Please insert system specific function to retrieve a timestamp (in microseconds)
// ...
return system_current_time;
}
/*!
* @brief Handling of the ready outputs
*
* @param[in] outputs output_t structure
* @param[in] bsec_status value returned by the bsec_do_steps() call
*
* @return none
*/
void output_ready(output_t *outputs, bsec_library_return_t bsec_status)
{
// ...
// Please insert system specific code to further process or display the BSEC outputs
// ...
}
/*!
* @brief Load previous library state from non-volatile memory
*
* @param[in,out] state_buffer buffer to hold the loaded state string
* @param[in] n_buffer size of the allocated state buffer
*
* @return number of bytes copied to state_buffer
*/
uint32_t state_load(uint8_t *state_buffer, uint32_t n_buffer)
{
// ...
// Load a previous library state from non-volatile memory, if available.
//
// Return zero if loading was unsuccessful or no state was available,
// otherwise return length of loaded state string.
// ...
return 0;
}
/*!
* @brief Save library state to non-volatile memory
*
* @param[in] state_buffer buffer holding the state to be stored
* @param[in] length length of the state string to be stored
*
* @return none
*/
void state_save(const uint8_t *state_buffer, uint32_t length)
{
// ...
// Save the string some form of non-volatile memory, if possible.
// ...
}
/*!
* @brief Load library config from non-volatile memory
*
* @param[in,out] config_buffer buffer to hold the loaded state string
* @param[in] n_buffer size of the allocated state buffer
*
* @return number of bytes copied to config_buffer
*/
uint32_t config_load(uint8_t *config_buffer, uint32_t n_buffer)
{
// ...
// Load a library config from non-volatile memory, if available.
//
// Return zero if loading was unsuccessful or no config was available,
// otherwise return length of loaded config string.
// ...
return 0;
}
/*!
* @brief Main function which configures BSEC library and then reads and processes the data from sensor based
* on timer ticks
*
* @return result of the processing
*/
int main()
{
return_values_init ret;
struct bme68x_dev bme_dev;
memset(&bme_dev,0,sizeof(bme_dev));
/* Call to the function which initializes the BSEC library
* Switch on low-power mode and provide no temperature offset */
ret = bsec_iot_init(BSEC_SAMPLE_RATE_LP, 0.0f, bus_write, bus_read, sleep_n, state_load, config_load, bme_dev, 0);
if (ret.bme68x_status)
{
/* Could not intialize BME68x */
return (int)ret.bme68x_status;
}
else if (ret.bsec_status)
{
/* Could not intialize BSEC library */
return (int)ret.bsec_status;
}
/* Call to endless loop function which reads and processes data based on sensor settings */
/* State is saved every 10.000 samples, which means every 10.000 * 3 secs = 500 minutes */
bsec_iot_loop(sleep_n, get_timestamp_us, output_ready, state_save, 10000);
return 0;
}
/*! @}*/

View File

@@ -0,0 +1,356 @@
/**
* Copyright (C) Bosch Sensortec GmbH. All Rights Reserved. Confidential.
*
* Disclaimer
*
* Common:
* Bosch Sensortec products are developed for the consumer goods industry. They may only be used
* within the parameters of the respective valid product data sheet. Bosch Sensortec products are
* provided with the express understanding that there is no warranty of fitness for a particular purpose.
* They are not fit for use in life-sustaining, safety or security sensitive systems or any system or device
* that may lead to bodily harm or property damage if the system or device malfunctions. In addition,
* Bosch Sensortec products are not fit for use in products which interact with motor vehicle systems.
* The resale and/or use of products are at the purchaser's own risk and his own responsibility. The
* examination of fitness for the intended use is the sole responsibility of the Purchaser.
*
* The purchaser shall indemnify Bosch Sensortec from all third party claims, including any claims for
* incidental, or consequential damages, arising from any product use not covered by the parameters of
* the respective valid product data sheet or not approved by Bosch Sensortec and reimburse Bosch
* Sensortec for all costs in connection with such claims.
*
* The purchaser must monitor the market for the purchased products, particularly with regard to
* product safety and inform Bosch Sensortec without delay of all security relevant incidents.
*
* Engineering Samples are marked with an asterisk (*) or (e). Samples may vary from the valid
* technical specifications of the product series. They are therefore not intended or fit for resale to third
* parties or for use in end products. Their sole purpose is internal client testing. The testing of an
* engineering sample may in no way replace the testing of a product series. Bosch Sensortec
* assumes no liability for the use of engineering samples. By accepting the engineering samples, the
* Purchaser agrees to indemnify Bosch Sensortec from all claims arising from the use of engineering
* samples.
*
* Special:
* This software module (hereinafter called "Software") and any information on application-sheets
* (hereinafter called "Information") is provided free of charge for the sole purpose to support your
* application work. The Software and Information is subject to the following terms and conditions:
*
* The Software is specifically designed for the exclusive use for Bosch Sensortec products by
* personnel who have special experience and training. Do not use this Software if you do not have the
* proper experience or training.
*
* This Software package is provided `` as is `` and without any expressed or implied warranties,
* including without limitation, the implied warranties of merchantability and fitness for a particular
* purpose.
*
* Bosch Sensortec and their representatives and agents deny any liability for the functional impairment
* of this Software in terms of fitness, performance and safety. Bosch Sensortec and their
* representatives and agents shall not be liable for any direct or indirect damages or injury, except as
* otherwise stipulated in mandatory applicable law.
*
* The Information provided is believed to be accurate and reliable. Bosch Sensortec assumes no
* responsibility for the consequences of use of such Information nor for any infringement of patents or
* other rights of third parties which may result from its use. No license is granted by implication or
* otherwise under any patent or patent rights of Bosch. Specifications mentioned in the Information are
* subject to change without notice.
*
* It is not allowed to deliver the source code of the Software to any third party without permission of
* Bosch Sensortec.
*
*/
/*!
* @file bsec_iot_example.ino
*
* @brief
* Example for using of BSEC library in a fixed configuration with the BME68x sensor.
* This works by running an endless loop in the bsec_iot_loop() function.
*/
/*!
* @addtogroup bsec_examples BSEC Examples
* @brief BSEC usage examples
* @{*/
/**********************************************************************************************************************/
/* header files */
/**********************************************************************************************************************/
#include "bsec_integration.h"
#include "commMux.h"
#include "bsec_selectivity.h"
#include <Wire.h>
String output;
uint32_t overflowCounter;
uint32_t lastTimeMS;
commMux communicationSetup[NUM_OF_SENS];
/**********************************************************************************************************************/
/* functions */
/**********************************************************************************************************************/
/*!
* @brief Write operation in either Wire or SPI
*
* param[in] reg_addr register address
* param[in] reg_data_ptr pointer to the data to be written
* param[in] data_len number of bytes to be written
* param[in] intf_ptr interface pointer
*
* @return result of the bus communication function
*/
int8_t bus_write(uint8_t reg_addr, const uint8_t *reg_data_ptr, uint32_t data_len, void *intf_ptr)
{
uint8_t dev_addr = *(uint8_t*)intf_ptr;
Wire.beginTransmission(dev_addr);
Wire.write(reg_addr); /* Set register address to start writing to */
/* Write the data */
for (int index = 0; index < data_len; index++) {
Wire.write(reg_data_ptr[index]);
}
return (int8_t)Wire.endTransmission();
}
/*!
* @brief Read operation in either Wire or SPI
*
* param[in] reg_addr register address
* param[out] reg_data_ptr pointer to the memory to be used to store the read data
* param[in] data_len number of bytes to be read
* param[in] intf_ptr interface pointer
*
* @return result of the bus communication function
*/
int8_t bus_read(uint8_t reg_addr, uint8_t *reg_data_ptr, uint32_t data_len, void *intf_ptr)
{
int8_t comResult = 0;
uint8_t dev_addr = *(uint8_t*)intf_ptr;
Wire.beginTransmission(dev_addr);
Wire.write(reg_addr); /* Set register address to start reading from */
comResult = Wire.endTransmission();
delayMicroseconds(150); /* Precautionary response delay */
Wire.requestFrom(dev_addr, (uint8_t)data_len); /* Request data */
int index = 0;
while (Wire.available()) /* The slave device may send less than requested (burst read) */
{
reg_data_ptr[index] = Wire.read();
index++;
}
return comResult;
}
/*!
* @brief System specific implementation of sleep function
*
* @param[in] t_us Time in microseconds
* @param[in] intf_ptr Pointer to the interface descriptor
*
* @return none
*/
void sleep_n(uint32_t t_us, void *intf_ptr)
{
delay(t_us / 1000);
}
/*!
* @brief Capture the system time in microseconds
*
* @return system_current_time current system timestamp in microseconds
*/
int64_t get_timestamp_us()
{
int64_t timeMs = millis() * 1000;
if (lastTimeMS > timeMs) /* An overflow occurred */
{
overflowCounter++;
}
lastTimeMS = timeMs;
return timeMs + (overflowCounter * INT64_C(0xFFFFFFFF));
}
/*!
* @brief Handling of the ready outputs
*
* @param[in] outputs output_t structure
* @param[in] bsec_status value returned by the bsec_do_steps() call
*
* @return none
*/
void output_ready(output_t *outputs, bsec_library_return_t bsec_status)
{
digitalWrite(LED_BUILTIN, LOW);
float timestamp_ms = outputs->timestamp/1e6;
output = String(outputs->sens_no) + ",";
output += String(timestamp_ms) + ", ";
#if (OUTPUT_MODE == CLASSIFICATION || OUTPUT_MODE == REGRESSION)
output += String(outputs->gas_estimate_1) + ", ";
output += String(outputs->gas_estimate_2) + ", ";
output += String(outputs->gas_estimate_3) + ", ";
output += String(outputs->gas_estimate_4) + ", ";
output += String(outputs->gas_accuracy_1) + ", ";
output += String(outputs->gas_accuracy_2) + ", ";
output += String(outputs->gas_accuracy_3) + ", ";
output += String(outputs->gas_accuracy_4) + ", ";
output += String(outputs->raw_pressure) + ", ";
output += String(outputs->raw_temp) + ", ";
output += String(outputs->raw_humidity) + ", ";
output += String(outputs->raw_gas) + ", ";
output += String(outputs->raw_gas_index) + ", ";
#elif (OUTPUT_MODE == IAQ)
output += String(outputs->iaq) + ", ";
output += String(outputs->iaq_accuracy) + ", ";
output += String(outputs->static_iaq) + ", ";
output += String(outputs->raw_temp) + ", ";
output += String(outputs->raw_humidity) + ", ";
output += String(outputs->temperature) + ", ";
output += String(outputs->humidity) + ", ";
output += String(outputs->raw_pressure) + ", ";
output += String(outputs->raw_gas) + ", ";
output += String(outputs->gas_percentage) + ", ";
output += String(outputs->co2_equivalent) + ", ";
output += String(outputs->breath_voc_equivalent) + ", ";
output += String(outputs->stabStatus) + ", ";
output += String(outputs->runInStatus) + ", ";
output += String(outputs->compensated_gas) + ", ";
#endif
output += String(bsec_status);
Serial.println(output);
digitalWrite(LED_BUILTIN, HIGH);
}
/*!
* @brief Load previous library state from non-volatile memory
*
* @param[in,out] state_buffer buffer to hold the loaded state string
* @param[in] n_buffer size of the allocated state buffer
*
* @return number of bytes copied to state_buffer
*/
uint32_t state_load(uint8_t *state_buffer, uint32_t n_buffer)
{
// ...
// Load a previous library state from non-volatile memory, if available.
//
// Return zero if loading was unsuccessful or no state was available,
// otherwise return length of loaded state string.
// ...
return 0;
}
/*!
* @brief Save library state to non-volatile memory
*
* @param[in] state_buffer buffer holding the state to be stored
* @param[in] length length of the state string to be stored
*
* @return none
*/
void state_save(const uint8_t *state_buffer, uint32_t length)
{
// ...
// Save the string some form of non-volatile memory, if possible.
// ...
}
/*!
* @brief Load library config from non-volatile memory
*
* @param[in,out] config_buffer buffer to hold the loaded state string
* @param[in] n_buffer size of the allocated state buffer
*
* @return number of bytes copied to config_buffer
*/
uint32_t config_load(uint8_t *config_buffer, uint32_t n_buffer)
{
memcpy(config_buffer, bsec_config_selectivity, n_buffer);
return n_buffer;
}
/*!
* @brief Main function which configures BSEC library and then reads and processes the data from sensor based
* on timer ticks
*
* @return result of the processing
*/
void setup()
{
return_values_init ret;
pinMode(LED_BUILTIN, OUTPUT);
/* Init I2C and serial communication */
Wire.begin();
commMuxBegin(Wire, SPI);
Serial.begin(115200);
delay(1000);
struct bme68x_dev bme_dev[NUM_OF_SENS];
for (uint8_t i = 0; i < NUM_OF_SENS; i++) {
/* Sets the Communication interface for the given sensor */
communicationSetup[i] = commMuxSetConfig(Wire, SPI, i/*SENS_NUM*/, communicationSetup[i]);
memset(&bme_dev[i],0,sizeof(bme_dev[i]));
bme_dev[i].intf = BME68X_SPI_INTF;
bme_dev[i].read = commMuxRead;
bme_dev[i].write = commMuxWrite;
bme_dev[i].delay_us = commMuxDelay;
bme_dev[i].intf_ptr = &communicationSetup[i];
bme_dev[i].amb_temp = 25;
/* Assigning a chunk of memory block to the bsecInstance */
allocateMemory(bsec_mem_block[i], i);
/* Call to the function which initializes the BSEC library
* Switch on low-power mode and provide no temperature offset */
ret = bsec_iot_init(SAMPLE_RATE, 0.0f, bus_write, bus_read, sleep_n, state_load, config_load, bme_dev[i], i);
if (ret.bme68x_status)
{
/* Could not initialize BME68x */
Serial.println("ERROR while initializing BME68x:"+String(ret.bme68x_status));
return;
}
else if (ret.bsec_status < BSEC_OK)
{
printf("\nERROR while initializing BSEC library: %d\n", ret.bsec_status);
return;
}
else if (ret.bsec_status > BSEC_OK)
{
printf("\nWARNING while initializing BSEC library: %d\n", ret.bsec_status);
}
}
bsec_version_t version;
bsec_get_version_m(bsecInstance, &version);
Serial.println("\nBSEC library version " + String(version.major) + "." + String(version.minor) + "." \
+ String(version.major_bugfix) + "." + String(version.minor_bugfix));
#if (OUTPUT_MODE == CLASSIFICATION || OUTPUT_MODE == REGRESSION)
String file_header = "\nSensor_No, Time(ms), Class/Target_1_prediction, Class/Target_2_prediction, Class/Target_3_prediction, Class/Target_4_prediction, Prediction_accuracy_1, Prediction_accuracy_2, Prediction_accuracy_3, Prediction_accuracy_4, Raw_pressure(Pa), Raw_Temperature(degC), Raw_Humidity(%rH), Raw_Gas(ohm), Raw_Gas_Index(num), Bsec_status";
#elif (OUTPUT_MODE == IAQ)
String file_header = "\nSensor_No, Time(ms), IAQ, IAQ_accuracy, Static_IAQ, Raw_Temperature(degC), Raw_Humidity(%rH), Comp_Temperature(degC), Comp_Humidity(%rH), Raw_pressure(Pa), Raw_Gas(ohms), Gas_percentage, CO2, bVOC, Stabilization_status, Run_in_status, Compensated_gas, Bsec_status";
#endif
Serial.println(file_header);
/* Call to endless loop function which reads and processes data based on sensor settings */
/* State is saved every 10.000 samples, which means every 10.000 * 3 secs = 500 minutes */
bsec_iot_loop(sleep_n, get_timestamp_us, output_ready, state_save, 10000);
}
void loop()
{
}
/*! @}*/

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,4 @@
#include <stdint.h>
extern const uint8_t bsec_config_selectivity[1943];

View File

@@ -0,0 +1,165 @@
/**
Copyright (c) 2021 Bosch Sensortec GmbH. All rights reserved.
BSD-3-Clause
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
@file commMux.cpp
@date 19 September 2022
@version 2.0.2
*/
#include "commMux.h"
#define CLOCK_FREQUENCY 400000
#define COMM_SPEED 8000000
const uint8_t I2C_EXPANDER_ADDR = 0x20;
const uint8_t I2C_EXPANDER_OUTPUT_REG_ADDR = 0x01;
const uint8_t I2C_EXPANDER_OUTPUT_DESELECT = 0xFF;
const uint8_t I2C_EXPANDER_CONFIG_REG_ADDR = 0x03;
const uint8_t I2C_EXPANDER_CONFIG_REG_MASK = 0x00;
/**
* @brief Function to configure the communication across sensors
*/
commMux commMuxSetConfig(TwoWire &wireobj, SPIClass &spiobj, uint8_t idx, commMux &comm)
{
comm.select = ((0x01 << idx) ^ 0xFF);
comm.spiobj = &spiobj;
comm.wireobj = &wireobj;
return comm;
}
/**
* @brief Function to trigger the communication
*/
void commMuxBegin(TwoWire &wireobj, SPIClass &spiobj)
{
wireobj.begin();
wireobj.setClock(CLOCK_FREQUENCY);
wireobj.beginTransmission(I2C_EXPANDER_ADDR);
wireobj.write(I2C_EXPANDER_CONFIG_REG_ADDR);
wireobj.write(I2C_EXPANDER_CONFIG_REG_MASK);
wireobj.endTransmission();
spiobj.begin();
}
/**
* @brief Function to set the ship select pin of the SPI
*/
static void setChipSelect(TwoWire *wireobj, uint8_t mask)
{
// send I2C-Expander device address
wireobj->beginTransmission(I2C_EXPANDER_ADDR);
// send I2C-Expander output register address
wireobj->write(I2C_EXPANDER_OUTPUT_REG_ADDR);
// send mask to set output level of GPIO pins
wireobj->write(mask);
// end communication
wireobj->endTransmission();
}
/**
* @brief Function to write the sensor data to the register
*/
int8_t commMuxWrite(uint8_t reg_addr, const uint8_t *reg_data, uint32_t length, void *intf_ptr)
{
commMux *comm = (commMux*) intf_ptr;
uint32_t i;
if (comm)
{
setChipSelect(comm->wireobj, comm->select);
comm->spiobj->beginTransaction(SPISettings(COMM_SPEED, MSBFIRST, SPI_MODE0));
comm->spiobj->transfer(reg_addr);
for (i = 0; i < length; i++)
{
comm->spiobj->transfer(reg_data[i]);
}
comm->spiobj->endTransaction();
setChipSelect(comm->wireobj, I2C_EXPANDER_OUTPUT_DESELECT);
return 0;
}
return 1;
}
/**
* @brief Function to read the sensor data from the register
*/
int8_t commMuxRead(uint8_t reg_addr, uint8_t *reg_data, uint32_t length, void *intf_ptr)
{
commMux *comm = (commMux*) intf_ptr;
uint32_t i;
if (comm)
{
setChipSelect(comm->wireobj, comm->select);
comm->spiobj->beginTransaction(SPISettings(COMM_SPEED, MSBFIRST, SPI_MODE0));
comm->spiobj->transfer(reg_addr);
for (i = 0; i < length; i++)
{
reg_data[i] = comm->spiobj->transfer(0xFF);
}
comm->spiobj->endTransaction();
setChipSelect(comm->wireobj, I2C_EXPANDER_OUTPUT_DESELECT);
return 0;
}
return 1;
}
void commMuxSwitch(void *intf_ptr)
{
commMux *comm = (commMux*) intf_ptr;
if (comm)
{
setChipSelect(comm->wireobj, comm->select);
}
}
/**
* @brief Function to maintain a delay between communication
*/
void commMuxDelay(uint32_t period_us, void *intf_ptr)
{
(void) intf_ptr;
delayMicroseconds(period_us);
}

100
bsec_iot_example/commMux.h Normal file
View File

@@ -0,0 +1,100 @@
/**
Copyright (c) 2021 Bosch Sensortec GmbH. All rights reserved.
BSD-3-Clause
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
@file commMux.h
@date 19 September 2022
@version 2.0.2
*/
#ifndef COMM_MUX_H
#define COMM_MUX_H
#include "Arduino.h"
#include "Wire.h"
#include "SPI.h"
/**
* Datatype working as an interface descriptor
*/
typedef struct {
TwoWire *wireobj;
SPIClass *spiobj;
uint8_t select;
} commMux;
/**
* @brief Function to configure the communication across sensors
* @param wireobj : The TwoWire object
* @param spiobj : The SPIClass object
* @param idx : Selected sensor for communication interface
* @param comm : Structure for selected sensor
* @return : Structure holding the communication setup
*/
commMux commMuxSetConfig(TwoWire &wireobj, SPIClass &spiobj, uint8_t idx, commMux &comm);
/**
* @brief Function to trigger the communication
* @param wireobj : The TwoWire object
* @param spiobj : The SPIClass object
*/
void commMuxBegin(TwoWire &wireobj, SPIClass &spiobj);
/**
* @brief Function to write the sensor data to the register
* @param reg_addr : Address of the register
* @param reg_data : Pointer to the data to be written
* @param length : length of the register data
* @param intf_ptr : Pointer to the interface descriptor
* @return 0 if successful, non-zero otherwise
*/
int8_t commMuxWrite(uint8_t reg_addr, const uint8_t *reg_data, uint32_t length, void *intf_ptr);
/**
* @brief Function to read the sensor data from the register
* @param reg_addr : Address of the register
* @param reg_data : Pointer to the data to be read from the sensor
* @param length : length of the register data
* @param intf_ptr : Pointer to the interface descriptor
* @return 0 if successful, non-zero otherwise
*/
int8_t commMuxRead(uint8_t reg_addr, uint8_t *reg_data, uint32_t length, void *intf_ptr);
/**
* @brief Function to maintain a delay between communication
* @param period_us : Time delay in micro secs
* @param intf_ptr : Pointer to the interface descriptor
*/
void commMuxDelay(uint32_t period_us, void *intf_ptr);
void commMuxSwitch(void *intf_ptr);
#endif /* COMM_MUX_H */

View File

@@ -0,0 +1,21 @@
//**** INCLUDES *************************************************************
//**** CONSTANTS ************************************************************
//**** PIN ASSIGNMENT OF OUR SHIELD *****************************************
static const int buzzer = 2;
//**** SETUP ****************************************************************
void setup() {
Serial.begin(9600);
pinMode(buzzer, OUTPUT);
}
//**** LOOP *****************************************************************
void loop(){
tone(buzzer,400, 200);
}

38
i2c_test/i2c_test.ino Normal file
View File

@@ -0,0 +1,38 @@
#include <Wire.h>
void setup()
{
Serial.begin (57600);
Wire.begin (); // sda= GPIO_21 /scl= GPIO_22
}
void Scanner ()
{
Serial.println ();
Serial.println ("I2C scanner. Scanning ...");
byte count = 0;
Wire.begin();
for (byte i = 8; i < 120; i++)
{
Wire.beginTransmission (i); // Begin I2C transmission Address (i)
if (Wire.endTransmission () == 0) // Receive 0 = success (ACK response)
{
Serial.print ("Found address: ");
Serial.print (i, DEC);
Serial.print (" (0x");
Serial.print (i, HEX); // PCF8574 7 bit address
Serial.println (")");
count++;
}
}
Serial.print ("Found ");
Serial.print (count, DEC); // numbers of devices
Serial.println (" device(s).");
}
void loop()
{
Scanner ();
delay (10000);
}

View File

@@ -0,0 +1,646 @@
/*!
* @file Adafruit_BME280.cpp
*
* @mainpage Adafruit BME280 humidity, temperature & pressure sensor
*
* @section intro_sec Introduction
*
* Driver for the BME280 humidity, temperature & pressure sensor
*
* These sensors use I2C or SPI to communicate, 2 or 4 pins are required
* to interface.
*
* Designed specifically to work with the Adafruit BME280 Breakout
* ----> http://www.adafruit.com/products/2652
*
* Adafruit invests time and resources providing this open source code,
* please support Adafruit and open-source hardware by purchasing
* products from Adafruit!
*
* @section author Author
*
* Written by Kevin "KTOWN" Townsend for Adafruit Industries.
*
* @section license License
*
* BSD license, all text here must be included in any redistribution.
* See the LICENSE file for details.
*
*/
#include "Adafruit_BME280.h"
#include "Arduino.h"
/*!
* @brief class constructor
*/
Adafruit_BME280::Adafruit_BME280() {}
/*!
* @brief class constructor if using hardware SPI
* @param cspin the chip select pin to use
* @param *theSPI
* optional SPI object
*/
Adafruit_BME280::Adafruit_BME280(int8_t cspin, SPIClass *theSPI) {
spi_dev = new Adafruit_SPIDevice(cspin, 1000000, SPI_BITORDER_MSBFIRST,
SPI_MODE0, theSPI);
}
/*!
* @brief class constructor if using software SPI
* @param cspin the chip select pin to use
* @param mosipin the MOSI pin to use
* @param misopin the MISO pin to use
* @param sckpin the SCK pin to use
*/
Adafruit_BME280::Adafruit_BME280(int8_t cspin, int8_t mosipin, int8_t misopin,
int8_t sckpin) {
spi_dev = new Adafruit_SPIDevice(cspin, sckpin, misopin, mosipin);
}
Adafruit_BME280::~Adafruit_BME280(void) {
if (spi_dev) {
delete spi_dev;
}
if (i2c_dev) {
delete i2c_dev;
}
if (temp_sensor) {
delete temp_sensor;
}
if (pressure_sensor) {
delete pressure_sensor;
}
if (humidity_sensor) {
delete humidity_sensor;
}
}
/*!
* @brief Initialise sensor with given parameters / settings
* @param addr the I2C address the device can be found on
* @param theWire the I2C object to use, defaults to &Wire
* @returns true on success, false otherwise
*/
bool Adafruit_BME280::begin(uint8_t addr, TwoWire *theWire) {
if (spi_dev == NULL) {
// I2C mode
if (i2c_dev)
delete i2c_dev;
i2c_dev = new Adafruit_I2CDevice(addr, theWire);
if (!i2c_dev->begin())
return false;
} else {
// SPI mode
if (!spi_dev->begin())
return false;
}
return init();
}
/*!
* @brief Initialise sensor with given parameters / settings
* @returns true on success, false otherwise
*/
bool Adafruit_BME280::init() {
// check if sensor, i.e. the chip ID is correct
_sensorID = read8(BME280_REGISTER_CHIPID);
if (_sensorID != 0x60)
return false;
// reset the device using soft-reset
// this makes sure the IIR is off, etc.
write8(BME280_REGISTER_SOFTRESET, 0xB6);
// wait for chip to wake up.
delay(10);
// if chip is still reading calibration, delay
while (isReadingCalibration())
delay(10);
readCoefficients(); // read trimming parameters, see DS 4.2.2
setSampling(); // use defaults
delay(100);
return true;
}
/*!
* @brief setup sensor with given parameters / settings
*
* This is simply a overload to the normal begin()-function, so SPI users
* don't get confused about the library requiring an address.
* @param mode the power mode to use for the sensor
* @param tempSampling the temp samping rate to use
* @param pressSampling the pressure sampling rate to use
* @param humSampling the humidity sampling rate to use
* @param filter the filter mode to use
* @param duration the standby duration to use
*/
void Adafruit_BME280::setSampling(sensor_mode mode,
sensor_sampling tempSampling,
sensor_sampling pressSampling,
sensor_sampling humSampling,
sensor_filter filter,
standby_duration duration) {
_measReg.mode = mode;
_measReg.osrs_t = tempSampling;
_measReg.osrs_p = pressSampling;
_humReg.osrs_h = humSampling;
_configReg.filter = filter;
_configReg.t_sb = duration;
_configReg.spi3w_en = 0;
// making sure sensor is in sleep mode before setting configuration
// as it otherwise may be ignored
write8(BME280_REGISTER_CONTROL, MODE_SLEEP);
// you must make sure to also set REGISTER_CONTROL after setting the
// CONTROLHUMID register, otherwise the values won't be applied (see
// DS 5.4.3)
write8(BME280_REGISTER_CONTROLHUMID, _humReg.get());
write8(BME280_REGISTER_CONFIG, _configReg.get());
write8(BME280_REGISTER_CONTROL, _measReg.get());
}
/*!
* @brief Writes an 8 bit value over I2C or SPI
* @param reg the register address to write to
* @param value the value to write to the register
*/
void Adafruit_BME280::write8(byte reg, byte value) {
byte buffer[2];
buffer[1] = value;
if (i2c_dev) {
buffer[0] = reg;
i2c_dev->write(buffer, 2);
} else {
buffer[0] = reg & ~0x80;
spi_dev->write(buffer, 2);
}
}
/*!
* @brief Reads an 8 bit value over I2C or SPI
* @param reg the register address to read from
* @returns the data byte read from the device
*/
uint8_t Adafruit_BME280::read8(byte reg) {
uint8_t buffer[1];
if (i2c_dev) {
buffer[0] = uint8_t(reg);
i2c_dev->write_then_read(buffer, 1, buffer, 1);
} else {
buffer[0] = uint8_t(reg | 0x80);
spi_dev->write_then_read(buffer, 1, buffer, 1);
}
return buffer[0];
}
/*!
* @brief Reads a 16 bit value over I2C or SPI
* @param reg the register address to read from
* @returns the 16 bit data value read from the device
*/
uint16_t Adafruit_BME280::read16(byte reg) {
uint8_t buffer[2];
if (i2c_dev) {
buffer[0] = uint8_t(reg);
i2c_dev->write_then_read(buffer, 1, buffer, 2);
} else {
buffer[0] = uint8_t(reg | 0x80);
spi_dev->write_then_read(buffer, 1, buffer, 2);
}
return uint16_t(buffer[0]) << 8 | uint16_t(buffer[1]);
}
/*!
* @brief Reads a signed 16 bit little endian value over I2C or SPI
* @param reg the register address to read from
* @returns the 16 bit data value read from the device
*/
uint16_t Adafruit_BME280::read16_LE(byte reg) {
uint16_t temp = read16(reg);
return (temp >> 8) | (temp << 8);
}
/*!
* @brief Reads a signed 16 bit value over I2C or SPI
* @param reg the register address to read from
* @returns the 16 bit data value read from the device
*/
int16_t Adafruit_BME280::readS16(byte reg) { return (int16_t)read16(reg); }
/*!
* @brief Reads a signed little endian 16 bit value over I2C or SPI
* @param reg the register address to read from
* @returns the 16 bit data value read from the device
*/
int16_t Adafruit_BME280::readS16_LE(byte reg) {
return (int16_t)read16_LE(reg);
}
/*!
* @brief Reads a 24 bit value over I2C
* @param reg the register address to read from
* @returns the 24 bit data value read from the device
*/
uint32_t Adafruit_BME280::read24(byte reg) {
uint8_t buffer[3];
if (i2c_dev) {
buffer[0] = uint8_t(reg);
i2c_dev->write_then_read(buffer, 1, buffer, 3);
} else {
buffer[0] = uint8_t(reg | 0x80);
spi_dev->write_then_read(buffer, 1, buffer, 3);
}
return uint32_t(buffer[0]) << 16 | uint32_t(buffer[1]) << 8 |
uint32_t(buffer[2]);
}
/*!
* @brief Take a new measurement (only possible in forced mode)
@returns true in case of success else false
*/
bool Adafruit_BME280::takeForcedMeasurement(void) {
bool return_value = false;
// If we are in forced mode, the BME sensor goes back to sleep after each
// measurement and we need to set it to forced mode once at this point, so
// it will take the next measurement and then return to sleep again.
// In normal mode simply does new measurements periodically.
if (_measReg.mode == MODE_FORCED) {
return_value = true;
// set to forced mode, i.e. "take next measurement"
write8(BME280_REGISTER_CONTROL, _measReg.get());
// Store current time to measure the timeout
uint32_t timeout_start = millis();
// wait until measurement has been completed, otherwise we would read the
// the values from the last measurement or the timeout occurred after 2 sec.
while (read8(BME280_REGISTER_STATUS) & 0x08) {
// In case of a timeout, stop the while loop
if ((millis() - timeout_start) > 2000) {
return_value = false;
break;
}
delay(1);
}
}
return return_value;
}
/*!
* @brief Reads the factory-set coefficients
*/
void Adafruit_BME280::readCoefficients(void) {
_bme280_calib.dig_T1 = read16_LE(BME280_REGISTER_DIG_T1);
_bme280_calib.dig_T2 = readS16_LE(BME280_REGISTER_DIG_T2);
_bme280_calib.dig_T3 = readS16_LE(BME280_REGISTER_DIG_T3);
_bme280_calib.dig_P1 = read16_LE(BME280_REGISTER_DIG_P1);
_bme280_calib.dig_P2 = readS16_LE(BME280_REGISTER_DIG_P2);
_bme280_calib.dig_P3 = readS16_LE(BME280_REGISTER_DIG_P3);
_bme280_calib.dig_P4 = readS16_LE(BME280_REGISTER_DIG_P4);
_bme280_calib.dig_P5 = readS16_LE(BME280_REGISTER_DIG_P5);
_bme280_calib.dig_P6 = readS16_LE(BME280_REGISTER_DIG_P6);
_bme280_calib.dig_P7 = readS16_LE(BME280_REGISTER_DIG_P7);
_bme280_calib.dig_P8 = readS16_LE(BME280_REGISTER_DIG_P8);
_bme280_calib.dig_P9 = readS16_LE(BME280_REGISTER_DIG_P9);
_bme280_calib.dig_H1 = read8(BME280_REGISTER_DIG_H1);
_bme280_calib.dig_H2 = readS16_LE(BME280_REGISTER_DIG_H2);
_bme280_calib.dig_H3 = read8(BME280_REGISTER_DIG_H3);
_bme280_calib.dig_H4 = ((int8_t)read8(BME280_REGISTER_DIG_H4) << 4) |
(read8(BME280_REGISTER_DIG_H4 + 1) & 0xF);
_bme280_calib.dig_H5 = ((int8_t)read8(BME280_REGISTER_DIG_H5 + 1) << 4) |
(read8(BME280_REGISTER_DIG_H5) >> 4);
_bme280_calib.dig_H6 = (int8_t)read8(BME280_REGISTER_DIG_H6);
}
/*!
* @brief return true if chip is busy reading cal data
* @returns true if reading calibration, false otherwise
*/
bool Adafruit_BME280::isReadingCalibration(void) {
uint8_t const rStatus = read8(BME280_REGISTER_STATUS);
return (rStatus & (1 << 0)) != 0;
}
/*!
* @brief Returns the temperature from the sensor
* @returns the temperature read from the device
*/
float Adafruit_BME280::readTemperature(void) {
int32_t var1, var2;
int32_t adc_T = read24(BME280_REGISTER_TEMPDATA);
if (adc_T == 0x800000) // value in case temp measurement was disabled
return NAN;
adc_T >>= 4;
var1 = (int32_t)((adc_T / 8) - ((int32_t)_bme280_calib.dig_T1 * 2));
var1 = (var1 * ((int32_t)_bme280_calib.dig_T2)) / 2048;
var2 = (int32_t)((adc_T / 16) - ((int32_t)_bme280_calib.dig_T1));
var2 = (((var2 * var2) / 4096) * ((int32_t)_bme280_calib.dig_T3)) / 16384;
t_fine = var1 + var2 + t_fine_adjust;
int32_t T = (t_fine * 5 + 128) / 256;
return (float)T / 100;
}
/*!
* @brief Returns the pressure from the sensor
* @returns the pressure value (in Pascal) read from the device
*/
float Adafruit_BME280::readPressure(void) {
int64_t var1, var2, var3, var4;
readTemperature(); // must be done first to get t_fine
int32_t adc_P = read24(BME280_REGISTER_PRESSUREDATA);
if (adc_P == 0x800000) // value in case pressure measurement was disabled
return NAN;
adc_P >>= 4;
var1 = ((int64_t)t_fine) - 128000;
var2 = var1 * var1 * (int64_t)_bme280_calib.dig_P6;
var2 = var2 + ((var1 * (int64_t)_bme280_calib.dig_P5) * 131072);
var2 = var2 + (((int64_t)_bme280_calib.dig_P4) * 34359738368);
var1 = ((var1 * var1 * (int64_t)_bme280_calib.dig_P3) / 256) +
((var1 * ((int64_t)_bme280_calib.dig_P2) * 4096));
var3 = ((int64_t)1) * 140737488355328;
var1 = (var3 + var1) * ((int64_t)_bme280_calib.dig_P1) / 8589934592;
if (var1 == 0) {
return 0; // avoid exception caused by division by zero
}
var4 = 1048576 - adc_P;
var4 = (((var4 * 2147483648) - var2) * 3125) / var1;
var1 = (((int64_t)_bme280_calib.dig_P9) * (var4 / 8192) * (var4 / 8192)) /
33554432;
var2 = (((int64_t)_bme280_calib.dig_P8) * var4) / 524288;
var4 = ((var4 + var1 + var2) / 256) + (((int64_t)_bme280_calib.dig_P7) * 16);
float P = var4 / 256.0;
return P;
}
/*!
* @brief Returns the humidity from the sensor
* @returns the humidity value read from the device
*/
float Adafruit_BME280::readHumidity(void) {
int32_t var1, var2, var3, var4, var5;
readTemperature(); // must be done first to get t_fine
int32_t adc_H = read16(BME280_REGISTER_HUMIDDATA);
if (adc_H == 0x8000) // value in case humidity measurement was disabled
return NAN;
var1 = t_fine - ((int32_t)76800);
var2 = (int32_t)(adc_H * 16384);
var3 = (int32_t)(((int32_t)_bme280_calib.dig_H4) * 1048576);
var4 = ((int32_t)_bme280_calib.dig_H5) * var1;
var5 = (((var2 - var3) - var4) + (int32_t)16384) / 32768;
var2 = (var1 * ((int32_t)_bme280_calib.dig_H6)) / 1024;
var3 = (var1 * ((int32_t)_bme280_calib.dig_H3)) / 2048;
var4 = ((var2 * (var3 + (int32_t)32768)) / 1024) + (int32_t)2097152;
var2 = ((var4 * ((int32_t)_bme280_calib.dig_H2)) + 8192) / 16384;
var3 = var5 * var2;
var4 = ((var3 / 32768) * (var3 / 32768)) / 128;
var5 = var3 - ((var4 * ((int32_t)_bme280_calib.dig_H1)) / 16);
var5 = (var5 < 0 ? 0 : var5);
var5 = (var5 > 419430400 ? 419430400 : var5);
uint32_t H = (uint32_t)(var5 / 4096);
return (float)H / 1024.0;
}
/*!
* Calculates the altitude (in meters) from the specified atmospheric
* pressure (in hPa), and sea-level pressure (in hPa).
* @param seaLevel Sea-level pressure in hPa
* @returns the altitude value read from the device
*/
float Adafruit_BME280::readAltitude(float seaLevel) {
// Equation taken from BMP180 datasheet (page 16):
// http://www.adafruit.com/datasheets/BST-BMP180-DS000-09.pdf
// Note that using the equation from wikipedia can give bad results
// at high altitude. See this thread for more information:
// http://forums.adafruit.com/viewtopic.php?f=22&t=58064
float atmospheric = readPressure() / 100.0F;
return 44330.0 * (1.0 - pow(atmospheric / seaLevel, 0.1903));
}
/*!
* Calculates the pressure at sea level (in hPa) from the specified
* altitude (in meters), and atmospheric pressure (in hPa).
* @param altitude Altitude in meters
* @param atmospheric Atmospheric pressure in hPa
* @returns the pressure at sea level (in hPa) from the specified altitude
*/
float Adafruit_BME280::seaLevelForAltitude(float altitude, float atmospheric) {
// Equation taken from BMP180 datasheet (page 17):
// http://www.adafruit.com/datasheets/BST-BMP180-DS000-09.pdf
// Note that using the equation from wikipedia can give bad results
// at high altitude. See this thread for more information:
// http://forums.adafruit.com/viewtopic.php?f=22&t=58064
return atmospheric / pow(1.0 - (altitude / 44330.0), 5.255);
}
/*!
* Returns Sensor ID found by init() for diagnostics
* @returns Sensor ID 0x60 for BME280, 0x56, 0x57, 0x58 BMP280
*/
uint32_t Adafruit_BME280::sensorID(void) { return _sensorID; }
/*!
* Returns the current temperature compensation value in degrees Celsius
* @returns the current temperature compensation value in degrees Celsius
*/
float Adafruit_BME280::getTemperatureCompensation(void) {
return float((t_fine_adjust * 5) >> 8) / 100.0;
};
/*!
* Sets a value to be added to each temperature reading. This adjusted
* temperature is used in pressure and humidity readings.
* @param adjustment Value to be added to each temperature reading in Celsius
*/
void Adafruit_BME280::setTemperatureCompensation(float adjustment) {
// convert the value in C into and adjustment to t_fine
t_fine_adjust = ((int32_t(adjustment * 100) << 8)) / 5;
};
/*!
@brief Gets an Adafruit Unified Sensor object for the temp sensor component
@return Adafruit_Sensor pointer to temperature sensor
*/
Adafruit_Sensor *Adafruit_BME280::getTemperatureSensor(void) {
if (!temp_sensor) {
temp_sensor = new Adafruit_BME280_Temp(this);
}
return temp_sensor;
}
/*!
@brief Gets an Adafruit Unified Sensor object for the pressure sensor
component
@return Adafruit_Sensor pointer to pressure sensor
*/
Adafruit_Sensor *Adafruit_BME280::getPressureSensor(void) {
if (!pressure_sensor) {
pressure_sensor = new Adafruit_BME280_Pressure(this);
}
return pressure_sensor;
}
/*!
@brief Gets an Adafruit Unified Sensor object for the humidity sensor
component
@return Adafruit_Sensor pointer to humidity sensor
*/
Adafruit_Sensor *Adafruit_BME280::getHumiditySensor(void) {
if (!humidity_sensor) {
humidity_sensor = new Adafruit_BME280_Humidity(this);
}
return humidity_sensor;
}
/**************************************************************************/
/*!
@brief Gets the sensor_t data for the BME280's temperature sensor
*/
/**************************************************************************/
void Adafruit_BME280_Temp::getSensor(sensor_t *sensor) {
/* Clear the sensor_t object */
memset(sensor, 0, sizeof(sensor_t));
/* Insert the sensor name in the fixed length char array */
strncpy(sensor->name, "BME280", sizeof(sensor->name) - 1);
sensor->name[sizeof(sensor->name) - 1] = 0;
sensor->version = 1;
sensor->sensor_id = _sensorID;
sensor->type = SENSOR_TYPE_AMBIENT_TEMPERATURE;
sensor->min_delay = 0;
sensor->min_value = -40.0; /* Temperature range -40 ~ +85 C */
sensor->max_value = +85.0;
sensor->resolution = 0.01; /* 0.01 C */
}
/**************************************************************************/
/*!
@brief Gets the temperature as a standard sensor event
@param event Sensor event object that will be populated
@returns True
*/
/**************************************************************************/
bool Adafruit_BME280_Temp::getEvent(sensors_event_t *event) {
/* Clear the event */
memset(event, 0, sizeof(sensors_event_t));
event->version = sizeof(sensors_event_t);
event->sensor_id = _sensorID;
event->type = SENSOR_TYPE_AMBIENT_TEMPERATURE;
event->timestamp = millis();
event->temperature = _theBME280->readTemperature();
return true;
}
/**************************************************************************/
/*!
@brief Gets the sensor_t data for the BME280's pressure sensor
*/
/**************************************************************************/
void Adafruit_BME280_Pressure::getSensor(sensor_t *sensor) {
/* Clear the sensor_t object */
memset(sensor, 0, sizeof(sensor_t));
/* Insert the sensor name in the fixed length char array */
strncpy(sensor->name, "BME280", sizeof(sensor->name) - 1);
sensor->name[sizeof(sensor->name) - 1] = 0;
sensor->version = 1;
sensor->sensor_id = _sensorID;
sensor->type = SENSOR_TYPE_PRESSURE;
sensor->min_delay = 0;
sensor->min_value = 300.0; /* 300 ~ 1100 hPa */
sensor->max_value = 1100.0;
sensor->resolution = 0.012; /* 0.12 hPa relative */
}
/**************************************************************************/
/*!
@brief Gets the pressure as a standard sensor event
@param event Sensor event object that will be populated
@returns True
*/
/**************************************************************************/
bool Adafruit_BME280_Pressure::getEvent(sensors_event_t *event) {
/* Clear the event */
memset(event, 0, sizeof(sensors_event_t));
event->version = sizeof(sensors_event_t);
event->sensor_id = _sensorID;
event->type = SENSOR_TYPE_PRESSURE;
event->timestamp = millis();
event->pressure = _theBME280->readPressure() / 100; // convert Pa to hPa
return true;
}
/**************************************************************************/
/*!
@brief Gets the sensor_t data for the BME280's humidity sensor
*/
/**************************************************************************/
void Adafruit_BME280_Humidity::getSensor(sensor_t *sensor) {
/* Clear the sensor_t object */
memset(sensor, 0, sizeof(sensor_t));
/* Insert the sensor name in the fixed length char array */
strncpy(sensor->name, "BME280", sizeof(sensor->name) - 1);
sensor->name[sizeof(sensor->name) - 1] = 0;
sensor->version = 1;
sensor->sensor_id = _sensorID;
sensor->type = SENSOR_TYPE_RELATIVE_HUMIDITY;
sensor->min_delay = 0;
sensor->min_value = 0;
sensor->max_value = 100; /* 0 - 100 % */
sensor->resolution = 3; /* 3% accuracy */
}
/**************************************************************************/
/*!
@brief Gets the humidity as a standard sensor event
@param event Sensor event object that will be populated
@returns True
*/
/**************************************************************************/
bool Adafruit_BME280_Humidity::getEvent(sensors_event_t *event) {
/* Clear the event */
memset(event, 0, sizeof(sensors_event_t));
event->version = sizeof(sensors_event_t);
event->sensor_id = _sensorID;
event->type = SENSOR_TYPE_RELATIVE_HUMIDITY;
event->timestamp = millis();
event->relative_humidity = _theBME280->readHumidity();
return true;
}

View File

@@ -0,0 +1,372 @@
/*!
* @file Adafruit_BME280.h
*
* Designed specifically to work with the Adafruit BME280 Breakout
* ----> http://www.adafruit.com/products/2650
*
* These sensors use I2C or SPI to communicate, 2 or 4 pins are required
* to interface.
*
* Adafruit invests time and resources providing this open source code,
* please support Adafruit and open-source hardware by purchasing
* products from Adafruit!
*
* Written by Kevin "KTOWN" Townsend for Adafruit Industries.
*
* BSD license, all text here must be included in any redistribution.
* See the LICENSE file for details.
*
*/
#ifndef __BME280_H__
#define __BME280_H__
#include "Arduino.h"
#include <Adafruit_I2CDevice.h>
#include <Adafruit_SPIDevice.h>
#include <Adafruit_Sensor.h>
/*!
* @brief default I2C address
*/
#define BME280_ADDRESS (0x77) // Primary I2C Address
/*!
* @brief alternate I2C address
*/
#define BME280_ADDRESS_ALTERNATE (0x76) // Alternate Address
/*!
* @brief Register addresses
*/
enum {
BME280_REGISTER_DIG_T1 = 0x88,
BME280_REGISTER_DIG_T2 = 0x8A,
BME280_REGISTER_DIG_T3 = 0x8C,
BME280_REGISTER_DIG_P1 = 0x8E,
BME280_REGISTER_DIG_P2 = 0x90,
BME280_REGISTER_DIG_P3 = 0x92,
BME280_REGISTER_DIG_P4 = 0x94,
BME280_REGISTER_DIG_P5 = 0x96,
BME280_REGISTER_DIG_P6 = 0x98,
BME280_REGISTER_DIG_P7 = 0x9A,
BME280_REGISTER_DIG_P8 = 0x9C,
BME280_REGISTER_DIG_P9 = 0x9E,
BME280_REGISTER_DIG_H1 = 0xA1,
BME280_REGISTER_DIG_H2 = 0xE1,
BME280_REGISTER_DIG_H3 = 0xE3,
BME280_REGISTER_DIG_H4 = 0xE4,
BME280_REGISTER_DIG_H5 = 0xE5,
BME280_REGISTER_DIG_H6 = 0xE7,
BME280_REGISTER_CHIPID = 0xD0,
BME280_REGISTER_VERSION = 0xD1,
BME280_REGISTER_SOFTRESET = 0xE0,
BME280_REGISTER_CAL26 = 0xE1, // R calibration stored in 0xE1-0xF0
BME280_REGISTER_CONTROLHUMID = 0xF2,
BME280_REGISTER_STATUS = 0XF3,
BME280_REGISTER_CONTROL = 0xF4,
BME280_REGISTER_CONFIG = 0xF5,
BME280_REGISTER_PRESSUREDATA = 0xF7,
BME280_REGISTER_TEMPDATA = 0xFA,
BME280_REGISTER_HUMIDDATA = 0xFD
};
/**************************************************************************/
/*!
@brief calibration data
*/
/**************************************************************************/
typedef struct {
uint16_t dig_T1; ///< temperature compensation value
int16_t dig_T2; ///< temperature compensation value
int16_t dig_T3; ///< temperature compensation value
uint16_t dig_P1; ///< pressure compensation value
int16_t dig_P2; ///< pressure compensation value
int16_t dig_P3; ///< pressure compensation value
int16_t dig_P4; ///< pressure compensation value
int16_t dig_P5; ///< pressure compensation value
int16_t dig_P6; ///< pressure compensation value
int16_t dig_P7; ///< pressure compensation value
int16_t dig_P8; ///< pressure compensation value
int16_t dig_P9; ///< pressure compensation value
uint8_t dig_H1; ///< humidity compensation value
int16_t dig_H2; ///< humidity compensation value
uint8_t dig_H3; ///< humidity compensation value
int16_t dig_H4; ///< humidity compensation value
int16_t dig_H5; ///< humidity compensation value
int8_t dig_H6; ///< humidity compensation value
} bme280_calib_data;
/*=========================================================================*/
class Adafruit_BME280;
/** Adafruit Unified Sensor interface for temperature component of BME280 */
class Adafruit_BME280_Temp : public Adafruit_Sensor {
public:
/** @brief Create an Adafruit_Sensor compatible object for the temp sensor
@param parent A pointer to the BME280 class */
Adafruit_BME280_Temp(Adafruit_BME280 *parent) { _theBME280 = parent; }
bool getEvent(sensors_event_t *);
void getSensor(sensor_t *);
private:
int _sensorID = 280;
Adafruit_BME280 *_theBME280 = NULL;
};
/** Adafruit Unified Sensor interface for pressure component of BME280 */
class Adafruit_BME280_Pressure : public Adafruit_Sensor {
public:
/** @brief Create an Adafruit_Sensor compatible object for the pressure sensor
@param parent A pointer to the BME280 class */
Adafruit_BME280_Pressure(Adafruit_BME280 *parent) { _theBME280 = parent; }
bool getEvent(sensors_event_t *);
void getSensor(sensor_t *);
private:
int _sensorID = 280;
Adafruit_BME280 *_theBME280 = NULL;
};
/** Adafruit Unified Sensor interface for humidity component of BME280 */
class Adafruit_BME280_Humidity : public Adafruit_Sensor {
public:
/** @brief Create an Adafruit_Sensor compatible object for the humidity sensor
@param parent A pointer to the BME280 class */
Adafruit_BME280_Humidity(Adafruit_BME280 *parent) { _theBME280 = parent; }
bool getEvent(sensors_event_t *);
void getSensor(sensor_t *);
private:
int _sensorID = 280;
Adafruit_BME280 *_theBME280 = NULL;
};
/**************************************************************************/
/*!
@brief Class that stores state and functions for interacting with BME280 IC
*/
/**************************************************************************/
class Adafruit_BME280 {
public:
/**************************************************************************/
/*!
@brief sampling rates
*/
/**************************************************************************/
enum sensor_sampling {
SAMPLING_NONE = 0b000,
SAMPLING_X1 = 0b001,
SAMPLING_X2 = 0b010,
SAMPLING_X4 = 0b011,
SAMPLING_X8 = 0b100,
SAMPLING_X16 = 0b101
};
/**************************************************************************/
/*!
@brief power modes
*/
/**************************************************************************/
enum sensor_mode {
MODE_SLEEP = 0b00,
MODE_FORCED = 0b01,
MODE_NORMAL = 0b11
};
/**************************************************************************/
/*!
@brief filter values
*/
/**************************************************************************/
enum sensor_filter {
FILTER_OFF = 0b000,
FILTER_X2 = 0b001,
FILTER_X4 = 0b010,
FILTER_X8 = 0b011,
FILTER_X16 = 0b100
};
/**************************************************************************/
/*!
@brief standby duration in ms
*/
/**************************************************************************/
enum standby_duration {
STANDBY_MS_0_5 = 0b000,
STANDBY_MS_10 = 0b110,
STANDBY_MS_20 = 0b111,
STANDBY_MS_62_5 = 0b001,
STANDBY_MS_125 = 0b010,
STANDBY_MS_250 = 0b011,
STANDBY_MS_500 = 0b100,
STANDBY_MS_1000 = 0b101
};
// constructors
Adafruit_BME280();
Adafruit_BME280(int8_t cspin, SPIClass *theSPI = &SPI);
Adafruit_BME280(int8_t cspin, int8_t mosipin, int8_t misopin, int8_t sckpin);
~Adafruit_BME280(void);
bool begin(uint8_t addr = BME280_ADDRESS, TwoWire *theWire = &Wire);
bool init();
void setSampling(sensor_mode mode = MODE_NORMAL,
sensor_sampling tempSampling = SAMPLING_X16,
sensor_sampling pressSampling = SAMPLING_X16,
sensor_sampling humSampling = SAMPLING_X16,
sensor_filter filter = FILTER_OFF,
standby_duration duration = STANDBY_MS_0_5);
bool takeForcedMeasurement(void);
float readTemperature(void);
float readPressure(void);
float readHumidity(void);
float readAltitude(float seaLevel);
float seaLevelForAltitude(float altitude, float pressure);
uint32_t sensorID(void);
float getTemperatureCompensation(void);
void setTemperatureCompensation(float);
Adafruit_Sensor *getTemperatureSensor(void);
Adafruit_Sensor *getPressureSensor(void);
Adafruit_Sensor *getHumiditySensor(void);
protected:
Adafruit_I2CDevice *i2c_dev = NULL; ///< Pointer to I2C bus interface
Adafruit_SPIDevice *spi_dev = NULL; ///< Pointer to SPI bus interface
Adafruit_BME280_Temp *temp_sensor = NULL;
//!< Adafruit_Sensor compat temperature sensor component
Adafruit_BME280_Pressure *pressure_sensor = NULL;
//!< Adafruit_Sensor compat pressure sensor component
Adafruit_BME280_Humidity *humidity_sensor = NULL;
//!< Adafruit_Sensor compat humidity sensor component
void readCoefficients(void);
bool isReadingCalibration(void);
void write8(byte reg, byte value);
uint8_t read8(byte reg);
uint16_t read16(byte reg);
uint32_t read24(byte reg);
int16_t readS16(byte reg);
uint16_t read16_LE(byte reg); // little endian
int16_t readS16_LE(byte reg); // little endian
uint8_t _i2caddr; //!< I2C addr for the TwoWire interface
int32_t _sensorID; //!< ID of the BME Sensor
int32_t t_fine; //!< temperature with high resolution, stored as an attribute
//!< as this is used for temperature compensation reading
//!< humidity and pressure
int32_t t_fine_adjust = 0; //!< add to compensate temp readings and in turn
//!< to pressure and humidity readings
bme280_calib_data _bme280_calib; //!< here calibration data is stored
/**************************************************************************/
/*!
@brief config register
*/
/**************************************************************************/
struct config {
// inactive duration (standby time) in normal mode
// 000 = 0.5 ms
// 001 = 62.5 ms
// 010 = 125 ms
// 011 = 250 ms
// 100 = 500 ms
// 101 = 1000 ms
// 110 = 10 ms
// 111 = 20 ms
unsigned int t_sb : 3; ///< inactive duration (standby time) in normal mode
// filter settings
// 000 = filter off
// 001 = 2x filter
// 010 = 4x filter
// 011 = 8x filter
// 100 and above = 16x filter
unsigned int filter : 3; ///< filter settings
// unused - don't set
unsigned int none : 1; ///< unused - don't set
unsigned int spi3w_en : 1; ///< unused - don't set
/// @return combined config register
unsigned int get() { return (t_sb << 5) | (filter << 2) | spi3w_en; }
};
config _configReg; //!< config register object
/**************************************************************************/
/*!
@brief ctrl_meas register
*/
/**************************************************************************/
struct ctrl_meas {
// temperature oversampling
// 000 = skipped
// 001 = x1
// 010 = x2
// 011 = x4
// 100 = x8
// 101 and above = x16
unsigned int osrs_t : 3; ///< temperature oversampling
// pressure oversampling
// 000 = skipped
// 001 = x1
// 010 = x2
// 011 = x4
// 100 = x8
// 101 and above = x16
unsigned int osrs_p : 3; ///< pressure oversampling
// device mode
// 00 = sleep
// 01 or 10 = forced
// 11 = normal
unsigned int mode : 2; ///< device mode
/// @return combined ctrl register
unsigned int get() { return (osrs_t << 5) | (osrs_p << 2) | mode; }
};
ctrl_meas _measReg; //!< measurement register object
/**************************************************************************/
/*!
@brief ctrl_hum register
*/
/**************************************************************************/
struct ctrl_hum {
/// unused - don't set
unsigned int none : 5;
// pressure oversampling
// 000 = skipped
// 001 = x1
// 010 = x2
// 011 = x4
// 100 = x8
// 101 and above = x16
unsigned int osrs_h : 3; ///< pressure oversampling
/// @return combined ctrl hum register
unsigned int get() { return (osrs_h); }
};
ctrl_hum _humReg; //!< hum register object
};
#endif

View File

@@ -0,0 +1,27 @@
Copyright (c) 2015, Limor Fried & Kevin Townsend for Adafruit Industries
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of Adafruit Industries nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

View File

@@ -0,0 +1,54 @@
# Adafruit BME280 Library [![Build Status](https://github.com/adafruit/Adafruit_BME280_Library/workflows/Arduino%20Library%20CI/badge.svg)](https://github.com/adafruit/Adafruit_BME280_Library/actions)[![Documentation](https://github.com/adafruit/ci-arduino/blob/master/assets/doxygen_badge.svg)](http://adafruit.github.io/Adafruit_BME280_Library/html/index.html)
<a href="http://www.adafruit.com/products/2652"><img src="./assets/board.jpg" width="500"/></a>
This is a library for the Adafruit BME280 Humidity, Barometric Pressure + Temp sensor
Designed specifically to work with the Adafruit BME280 Breakout
* http://www.adafruit.com/products/2652
Adafruit invests time and resources providing this open source code, please support Adafruit and open-source hardware by purchasing products from Adafruit!
# Installation
To install, use the Arduino Library Manager and search for "Adafruit BME280" and install the library.
## Dependencies
* [Adafruit Unified Sensor Driver](https://github.com/adafruit/Adafruit_Sensor)
# Contributing
Contributions are welcome! Please read our [Code of Conduct](https://github.com/adafruit/Adafruit_PM25AQI/blob/master/CODE_OF_CONDUCT.md>)
before contributing to help this project stay welcoming.
## Documentation and doxygen
Documentation is produced by doxygen. Contributions should include documentation for any new code added.
Some examples of how to use doxygen can be found in these guide pages:
https://learn.adafruit.com/the-well-automated-arduino-library/doxygen
https://learn.adafruit.com/the-well-automated-arduino-library/doxygen-tips
## Formatting and clang-format
This library uses [`clang-format`](https://releases.llvm.org/download.html) to standardize the formatting of `.cpp` and `.h` files.
Contributions should be formatted using `clang-format`:
The `-i` flag will make the changes to the file.
```bash
clang-format -i *.cpp *.h
```
If you prefer to make the changes yourself, running `clang-format` without the `-i` flag will print out a formatted version of the file. You can save this to a file and diff it against the original to see the changes.
Note that the formatting output by `clang-format` is what the automated formatting checker will expect. Any diffs from this formatting will result in a failed build until they are addressed. Using the `-i` flag is highly recommended.
### clang-format resources
* [Binary builds and source available on the LLVM downloads page](https://releases.llvm.org/download.html)
* [Documentation and IDE integration](https://clang.llvm.org/docs/ClangFormat.html)
## About this Driver
Written by Ladyada for Adafruit Industries.
BSD license, check license.txt for more information
All text above must be included in any redistribution

Binary file not shown.

After

Width:  |  Height:  |  Size: 431 KiB

View File

@@ -0,0 +1,159 @@
/***************************************************************************
This is a library for the BME280 humidity, temperature & pressure sensor
Designed specifically to work with the Adafruit BME280 Breakout
----> http://www.adafruit.com/products/2650
These sensors use I2C or SPI to communicate, 2 or 4 pins are required
to interface. The device's I2C address is either 0x76 or 0x77.
Adafruit invests time and resources providing this open source code,
please support Adafruit andopen-source hardware by purchasing products
from Adafruit!
Written by Limor Fried & Kevin Townsend for Adafruit Industries.
BSD license, all text above must be included in any redistribution
See the LICENSE file for details.
***************************************************************************/
#include <Wire.h>
#include <SPI.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#define BME_SCK 13
#define BME_MISO 12
#define BME_MOSI 11
#define BME_CS 10
#define SEALEVELPRESSURE_HPA (1013.25)
Adafruit_BME280 bme; // I2C
//Adafruit_BME280 bme(BME_CS); // hardware SPI
//Adafruit_BME280 bme(BME_CS, BME_MOSI, BME_MISO, BME_SCK); // software SPI
unsigned long delayTime;
void setup() {
Serial.begin(9600);
Serial.println(F("BME280 test"));
if (! bme.begin(0x77, &Wire)) {
Serial.println("Could not find a valid BME280 sensor, check wiring!");
while (1);
}
Serial.println("-- Default Test --");
Serial.println("normal mode, 16x oversampling for all, filter off,");
Serial.println("0.5ms standby period");
delayTime = 5000;
// For more details on the following scenarious, see chapter
// 3.5 "Recommended modes of operation" in the datasheet
/*
// weather monitoring
Serial.println("-- Weather Station Scenario --");
Serial.println("forced mode, 1x temperature / 1x humidity / 1x pressure oversampling,");
Serial.println("filter off");
bme.setSampling(Adafruit_BME280::MODE_FORCED,
Adafruit_BME280::SAMPLING_X1, // temperature
Adafruit_BME280::SAMPLING_X1, // pressure
Adafruit_BME280::SAMPLING_X1, // humidity
Adafruit_BME280::FILTER_OFF );
// suggested rate is 1/60Hz (1m)
delayTime = 60000; // in milliseconds
*/
/*
// humidity sensing
Serial.println("-- Humidity Sensing Scenario --");
Serial.println("forced mode, 1x temperature / 1x humidity / 0x pressure oversampling");
Serial.println("= pressure off, filter off");
bme.setSampling(Adafruit_BME280::MODE_FORCED,
Adafruit_BME280::SAMPLING_X1, // temperature
Adafruit_BME280::SAMPLING_NONE, // pressure
Adafruit_BME280::SAMPLING_X1, // humidity
Adafruit_BME280::FILTER_OFF );
// suggested rate is 1Hz (1s)
delayTime = 1000; // in milliseconds
*/
/*
// indoor navigation
Serial.println("-- Indoor Navigation Scenario --");
Serial.println("normal mode, 16x pressure / 2x temperature / 1x humidity oversampling,");
Serial.println("0.5ms standby period, filter 16x");
bme.setSampling(Adafruit_BME280::MODE_NORMAL,
Adafruit_BME280::SAMPLING_X2, // temperature
Adafruit_BME280::SAMPLING_X16, // pressure
Adafruit_BME280::SAMPLING_X1, // humidity
Adafruit_BME280::FILTER_X16,
Adafruit_BME280::STANDBY_MS_0_5 );
// suggested rate is 25Hz
// 1 + (2 * T_ovs) + (2 * P_ovs + 0.5) + (2 * H_ovs + 0.5)
// T_ovs = 2
// P_ovs = 16
// H_ovs = 1
// = 40ms (25Hz)
// with standby time that should really be 24.16913... Hz
delayTime = 41;
*/
/*
// gaming
Serial.println("-- Gaming Scenario --");
Serial.println("normal mode, 4x pressure / 1x temperature / 0x humidity oversampling,");
Serial.println("= humidity off, 0.5ms standby period, filter 16x");
bme.setSampling(Adafruit_BME280::MODE_NORMAL,
Adafruit_BME280::SAMPLING_X1, // temperature
Adafruit_BME280::SAMPLING_X4, // pressure
Adafruit_BME280::SAMPLING_NONE, // humidity
Adafruit_BME280::FILTER_X16,
Adafruit_BME280::STANDBY_MS_0_5 );
// Suggested rate is 83Hz
// 1 + (2 * T_ovs) + (2 * P_ovs + 0.5)
// T_ovs = 1
// P_ovs = 4
// = 11.5ms + 0.5ms standby
delayTime = 12;
*/
Serial.println();
}
void loop() {
// Only needed in forced mode! In normal mode, you can remove the next line.
bme.takeForcedMeasurement(); // has no effect in normal mode
printValues();
delay(delayTime);
}
void printValues() {
Serial.print("Temperature = ");
Serial.print(bme.readTemperature());
Serial.println(" *C");
Serial.print("Pressure = ");
Serial.print(bme.readPressure() / 100.0F);
Serial.println(" hPa");
Serial.print("Approx. Altitude = ");
Serial.print(bme.readAltitude(SEALEVELPRESSURE_HPA));
Serial.println(" m");
Serial.print("Humidity = ");
Serial.print(bme.readHumidity());
Serial.println(" %");
Serial.println();
}

View File

@@ -0,0 +1,62 @@
/***************************************************************************
This is a library for the BME280 humidity, temperature & pressure sensor
This example shows how to take Sensor Events instead of direct readings
Designed specifically to work with the Adafruit BME280 Breakout
----> http://www.adafruit.com/products/2652
These sensors use I2C or SPI to communicate, 2 or 4 pins are required
to interface.
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 & Kevin Townsend for Adafruit Industries.
BSD license, all text above must be included in any redistribution
***************************************************************************/
#include <Wire.h>
#include <SPI.h>
#include <Adafruit_BME280.h>
Adafruit_BME280 bme; // use I2C interface
Adafruit_Sensor *bme_temp = bme.getTemperatureSensor();
Adafruit_Sensor *bme_pressure = bme.getPressureSensor();
Adafruit_Sensor *bme_humidity = bme.getHumiditySensor();
void setup() {
Serial.begin(9600);
Serial.println(F("BME280 Sensor event test"));
if (!bme.begin()) {
Serial.println(F("Could not find a valid BME280 sensor, check wiring!"));
while (1) delay(10);
}
bme_temp->printSensorDetails();
bme_pressure->printSensorDetails();
bme_humidity->printSensorDetails();
}
void loop() {
sensors_event_t temp_event, pressure_event, humidity_event;
bme_temp->getEvent(&temp_event);
bme_pressure->getEvent(&pressure_event);
bme_humidity->getEvent(&humidity_event);
Serial.print(F("Temperature = "));
Serial.print(temp_event.temperature);
Serial.println(" *C");
Serial.print(F("Humidity = "));
Serial.print(humidity_event.relative_humidity);
Serial.println(" %");
Serial.print(F("Pressure = "));
Serial.print(pressure_event.pressure);
Serial.println(" hPa");
Serial.println();
delay(1000);
}

View File

@@ -0,0 +1,90 @@
/***************************************************************************
This is a library for the BME280 humidity, temperature & pressure sensor
Designed specifically to work with the Adafruit BME280 Breakout
----> http://www.adafruit.com/products/2650
These sensors use I2C or SPI to communicate, 2 or 4 pins are required
to interface. The device's I2C address is either 0x76 or 0x77.
Adafruit invests time and resources providing this open source code,
please support Adafruit andopen-source hardware by purchasing products
from Adafruit!
Written by Limor Fried & Kevin Townsend for Adafruit Industries.
BSD license, all text above must be included in any redistribution
See the LICENSE file for details.
***************************************************************************/
#include <Wire.h>
#include <SPI.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#define BME_SCK 13
#define BME_MISO 12
#define BME_MOSI 11
#define BME_CS 10
#define SEALEVELPRESSURE_HPA (1013.25)
Adafruit_BME280 bme; // I2C
//Adafruit_BME280 bme(BME_CS); // hardware SPI
//Adafruit_BME280 bme(BME_CS, BME_MOSI, BME_MISO, BME_SCK); // software SPI
unsigned long delayTime;
void setup() {
Serial.begin(9600);
while(!Serial); // time to get serial running
Serial.println(F("BME280 test"));
unsigned status;
// default settings
status = bme.begin();
// You can also pass in a Wire library object like &Wire2
// status = bme.begin(0x76, &Wire2)
if (!status) {
Serial.println("Could not find a valid BME280 sensor, check wiring, address, sensor ID!");
Serial.print("SensorID was: 0x"); Serial.println(bme.sensorID(),16);
Serial.print(" ID of 0xFF probably means a bad address, a BMP 180 or BMP 085\n");
Serial.print(" ID of 0x56-0x58 represents a BMP 280,\n");
Serial.print(" ID of 0x60 represents a BME 280.\n");
Serial.print(" ID of 0x61 represents a BME 680.\n");
while (1) delay(10);
}
Serial.println("-- Default Test --");
delayTime = 1000;
Serial.println();
}
void loop() {
printValues();
delay(delayTime);
}
void printValues() {
Serial.print("Temperature = ");
Serial.print(bme.readTemperature());
Serial.println(" °C");
Serial.print("Pressure = ");
Serial.print(bme.readPressure() / 100.0F);
Serial.println(" hPa");
Serial.print("Approx. Altitude = ");
Serial.print(bme.readAltitude(SEALEVELPRESSURE_HPA));
Serial.println(" m");
Serial.print("Humidity = ");
Serial.print(bme.readHumidity());
Serial.println(" %");
Serial.println();
}

View File

@@ -0,0 +1,10 @@
name=Adafruit BME280 Library
version=2.2.4
author=Adafruit
maintainer=Adafruit <info@adafruit.com>
sentence=Arduino library for BME280 sensors.
paragraph=Arduino library for BME280 humidity and pressure sensors.
category=Sensors
url=https://github.com/adafruit/Adafruit_BME280_Library
architectures=*
depends=Adafruit Unified Sensor, Adafruit BusIO

View File

@@ -0,0 +1,609 @@
/*!
* @file Adafruit_BME680.cpp
*
* @mainpage Adafruit BME680 temperature, humidity, barometric pressure and gas
* sensor driver
*
* @section intro_sec Introduction
*
* This is the documentation for Adafruit's BME680 driver for the
* Arduino platform. It is designed specifically to work with the
* Adafruit BME680 breakout: https://www.adafruit.com/products/3660
*
* These sensors use I2C to communicate, 2 pins (SCL+SDA) are required
* to interface with the breakout.
*
* Adafruit invests time and resources providing this open source code,
* please support Adafruit and open-source hardware by purchasing
* products from Adafruit!
*
* @section author Author
*
* Written by Ladyada for Adafruit Industries.
*
* @section license License
*
* BSD license, all text here must be included in any redistribution.
*
*/
#include "Adafruit_BME680.h"
#include "Arduino.h"
//#define BME680_DEBUG
/** Our hardware interface functions **/
static int8_t i2c_read(uint8_t reg_addr, uint8_t *reg_data, uint32_t len,
void *interface);
static int8_t i2c_write(uint8_t reg_addr, const uint8_t *reg_data, uint32_t len,
void *interface);
static int8_t spi_read(uint8_t reg_addr, uint8_t *reg_data, uint32_t len,
void *interface);
static int8_t spi_write(uint8_t reg_addr, const uint8_t *reg_data, uint32_t len,
void *interface);
static void delay_usec(uint32_t us, void *intf_ptr);
// PUBLIC FUNCTIONS
/*!
* @brief Instantiates sensor with i2c.
* @param *theWire
* optional Wire object
*/
Adafruit_BME680::Adafruit_BME680(TwoWire *theWire)
: _meas_start(0), _meas_period(0) {
_wire = theWire;
}
/*!
* @brief Instantiates sensor with Hardware SPI.
* @param cspin
* SPI chip select.
* @param theSPI
* optional SPI object
*/
Adafruit_BME680::Adafruit_BME680(int8_t cspin, SPIClass *theSPI)
: _meas_start(0), _meas_period(0) {
_spidev = new Adafruit_SPIDevice(cspin, 1000000, SPI_BITORDER_MSBFIRST,
SPI_MODE0, theSPI);
}
/*!
* @brief Instantiates sensor with Software (bit-bang) SPI.
* @param cspin
* SPI chip select
* @param mosipin
* SPI MOSI (Data from microcontroller to sensor)
* @param misopin
* SPI MISO (Data to microcontroller from sensor)
* @param sckpin
* SPI Clock
*/
Adafruit_BME680::Adafruit_BME680(int8_t cspin, int8_t mosipin, int8_t misopin,
int8_t sckpin)
: _meas_start(0), _meas_period(0) {
_spidev = new Adafruit_SPIDevice(cspin, sckpin, misopin, mosipin, 1000000,
SPI_BITORDER_MSBFIRST, SPI_MODE0);
}
/*!
* @brief Initializes the sensor
* Hardware ss initialized, verifies it is in the I2C or SPI bus, then
* reads calibration data in preparation for sensor reads.
* @param addr
* Optional parameter for the I2C address of BME680. Default is 0x77
* @param initSettings
* Optional parameter for initializing the sensor settings.
* Default is true.
* @return True on sensor initialization success. False on failure.
*/
bool Adafruit_BME680::begin(uint8_t addr, bool initSettings) {
int8_t rslt;
if (!_spidev) { // i2c
if (_i2cdev) {
delete _i2cdev;
}
_i2cdev = new Adafruit_I2CDevice(addr, _wire);
if (!_i2cdev->begin()) {
return false;
}
gas_sensor.chip_id = addr;
gas_sensor.intf = BME68X_I2C_INTF;
gas_sensor.intf_ptr = (void *)_i2cdev;
gas_sensor.read = &i2c_read;
gas_sensor.write = &i2c_write;
} else {
if (!_spidev->begin()) {
return false;
}
gas_sensor.chip_id = 0;
gas_sensor.intf = BME68X_SPI_INTF;
gas_sensor.intf_ptr = (void *)_spidev;
gas_sensor.read = &spi_read;
gas_sensor.write = &spi_write;
}
gas_sensor.amb_temp = 25; /* The ambient temperature in deg C is used for
defining the heater temperature */
gas_sensor.delay_us = delay_usec;
rslt = bme68x_init(&gas_sensor);
#ifdef BME680_DEBUG
Serial.print(F("Init Result: "));
Serial.println(rslt);
#endif
if (rslt != BME68X_OK)
return false;
#ifdef BME680_DEBUG
Serial.print("T1 = ");
Serial.println(gas_sensor.calib.par_t1);
Serial.print("T2 = ");
Serial.println(gas_sensor.calib.par_t2);
Serial.print("T3 = ");
Serial.println(gas_sensor.calib.par_t3);
Serial.print("P1 = ");
Serial.println(gas_sensor.calib.par_p1);
Serial.print("P2 = ");
Serial.println(gas_sensor.calib.par_p2);
Serial.print("P3 = ");
Serial.println(gas_sensor.calib.par_p3);
Serial.print("P4 = ");
Serial.println(gas_sensor.calib.par_p4);
Serial.print("P5 = ");
Serial.println(gas_sensor.calib.par_p5);
Serial.print("P6 = ");
Serial.println(gas_sensor.calib.par_p6);
Serial.print("P7 = ");
Serial.println(gas_sensor.calib.par_p7);
Serial.print("P8 = ");
Serial.println(gas_sensor.calib.par_p8);
Serial.print("P9 = ");
Serial.println(gas_sensor.calib.par_p9);
Serial.print("P10 = ");
Serial.println(gas_sensor.calib.par_p10);
Serial.print("H1 = ");
Serial.println(gas_sensor.calib.par_h1);
Serial.print("H2 = ");
Serial.println(gas_sensor.calib.par_h2);
Serial.print("H3 = ");
Serial.println(gas_sensor.calib.par_h3);
Serial.print("H4 = ");
Serial.println(gas_sensor.calib.par_h4);
Serial.print("H5 = ");
Serial.println(gas_sensor.calib.par_h5);
Serial.print("H6 = ");
Serial.println(gas_sensor.calib.par_h6);
Serial.print("H7 = ");
Serial.println(gas_sensor.calib.par_h7);
Serial.print("G1 = ");
Serial.println(gas_sensor.calib.par_gh1);
Serial.print("G2 = ");
Serial.println(gas_sensor.calib.par_gh2);
Serial.print("G3 = ");
Serial.println(gas_sensor.calib.par_gh3);
Serial.print("G1 = ");
Serial.println(gas_sensor.calib.par_gh1);
Serial.print("G2 = ");
Serial.println(gas_sensor.calib.par_gh2);
Serial.print("G3 = ");
Serial.println(gas_sensor.calib.par_gh3);
Serial.print("Heat Range = ");
Serial.println(gas_sensor.calib.res_heat_range);
Serial.print("Heat Val = ");
Serial.println(gas_sensor.calib.res_heat_val);
Serial.print("SW Error = ");
Serial.println(gas_sensor.calib.range_sw_err);
#endif
if (initSettings) {
setIIRFilterSize(BME68X_FILTER_SIZE_3);
setODR(BME68X_ODR_NONE);
setHumidityOversampling(BME68X_OS_2X);
setPressureOversampling(BME68X_OS_4X);
setTemperatureOversampling(BME68X_OS_8X);
setGasHeater(320, 150); // 320*C for 150 ms
} else {
setGasHeater(0, 0);
}
// don't do anything till we request a reading
rslt = bme68x_set_op_mode(BME68X_FORCED_MODE, &gas_sensor);
#ifdef BME680_DEBUG
Serial.print(F("Opmode Result: "));
Serial.println(rslt);
#endif
if (rslt != BME68X_OK)
return false;
return true;
}
/*!
* @brief Performs a reading and returns the ambient temperature.
* @return Temperature in degrees Centigrade
*/
float Adafruit_BME680::readTemperature(void) {
performReading();
return temperature;
}
/*!
* @brief Performs a reading and returns the barometric pressure.
* @return Barometic pressure in Pascals
*/
float Adafruit_BME680::readPressure(void) {
performReading();
return pressure;
}
/*!
* @brief Performs a reading and returns the relative humidity.
* @return Relative humidity as floating point
*/
float Adafruit_BME680::readHumidity(void) {
performReading();
return humidity;
}
/*!
* @brief Calculates the resistance of the MOX gas sensor.
* @return Resistance in Ohms
*/
uint32_t Adafruit_BME680::readGas(void) {
performReading();
return gas_resistance;
}
/*!
* @brief Calculates the altitude (in meters).
* Reads the current atmostpheric pressure (in hPa) from the sensor and
* calculates via the provided sea-level pressure (in hPa).
* @param seaLevel
* Sea-level pressure in hPa
* @return Altitude in meters
*/
float Adafruit_BME680::readAltitude(float seaLevel) {
// Equation taken from BMP180 datasheet (page 16):
// http://www.adafruit.com/datasheets/BST-BMP180-DS000-09.pdf
// Note that using the equation from wikipedia can give bad results
// at high altitude. See this thread for more information:
// http://forums.adafruit.com/viewtopic.php?f=22&t=58064
float atmospheric = readPressure() / 100.0F;
return 44330.0 * (1.0 - pow(atmospheric / seaLevel, 0.1903));
}
/*!
* @brief Performs a full reading of all 4 sensors in the BME680.
* Assigns the internal Adafruit_BME680#temperature,
* Adafruit_BME680#pressure, Adafruit_BME680#humidity and
* Adafruit_BME680#gas_resistance member variables
* @return True on success, False on failure
*/
bool Adafruit_BME680::performReading(void) { return endReading(); }
/*! @brief Begin an asynchronous reading.
* @return When the reading would be ready as absolute time in millis().
*/
uint32_t Adafruit_BME680::beginReading(void) {
if (_meas_start != 0) {
/* A measurement is already in progress */
return _meas_start + _meas_period;
}
int8_t rslt = bme68x_set_op_mode(BME68X_FORCED_MODE, &gas_sensor);
#ifdef BME680_DEBUG
Serial.print(F("Opmode Result: "));
Serial.println(rslt);
#endif
if (rslt != BME68X_OK)
return false;
/* Calculate delay period in microseconds */
uint32_t delayus_period = (uint32_t)bme68x_get_meas_dur(
BME68X_FORCED_MODE, &gas_conf, &gas_sensor) +
((uint32_t)gas_heatr_conf.heatr_dur * 1000);
// Serial.print("measure: ");
// Serial.println(bme68x_get_meas_dur(BME68X_FORCED_MODE, &gas_conf,
// &gas_sensor)); Serial.print("heater: ");
// Serial.println((uint32_t)gas_heatr_conf.heatr_dur * 1000);
_meas_start = millis();
_meas_period = delayus_period / 1000;
return _meas_start + _meas_period;
}
/*! @brief End an asynchronous reading.
* If the asynchronous reading is still in progress, block until it
* ends. If no asynchronous reading has started, this is equivalent to
* performReading().
* @return Whether success.
*/
bool Adafruit_BME680::endReading(void) {
uint32_t meas_end = beginReading();
if (meas_end == 0) {
return false;
}
int remaining_millis = remainingReadingMillis();
if (remaining_millis > 0) {
#ifdef BME680_DEBUG
Serial.print(F("Waiting (ms) "));
Serial.println(remaining_millis);
#endif
delay(static_cast<unsigned int>(remaining_millis) *
2); /* Delay till the measurement is ready */
}
_meas_start = 0; /* Allow new measurement to begin */
_meas_period = 0;
#ifdef BME680_DEBUG
Serial.print(F("t_fine = "));
Serial.println(gas_sensor.calib.t_fine);
#endif
struct bme68x_data data;
uint8_t n_fields;
#ifdef BME680_DEBUG
Serial.println(F("Getting sensor data"));
#endif
int8_t rslt =
bme68x_get_data(BME68X_FORCED_MODE, &data, &n_fields, &gas_sensor);
#ifdef BME680_DEBUG
Serial.print(F("GetData Result: "));
Serial.println(rslt);
#endif
if (rslt != BME68X_OK)
return false;
if (n_fields) {
temperature = data.temperature;
humidity = data.humidity;
pressure = data.pressure;
#ifdef BME680_DEBUG
Serial.print(F("data.status 0x"));
Serial.println(data.status, HEX);
#endif
if (data.status & (BME68X_HEAT_STAB_MSK | BME68X_GASM_VALID_MSK)) {
// Serial.print("Gas resistance: "); Serial.println(data.gas_resistance);
gas_resistance = data.gas_resistance;
} else {
gas_resistance = 0;
// Serial.println("Gas reading unstable!");
}
}
return true;
}
/*! @brief Get remaining time for an asynchronous reading.
* If the asynchronous reading is still in progress, how many millis
* until its completion. If the asynchronous reading is completed, 0. If no
* asynchronous reading has started, -1 or
* Adafruit_BME680::reading_not_started. Does not block.
* @return Remaining millis until endReading will not block if invoked.
*/
int Adafruit_BME680::remainingReadingMillis(void) {
if (_meas_start != 0) {
/* A measurement is already in progress */
int remaining_time = (int)_meas_period - (millis() - _meas_start);
return remaining_time < 0 ? reading_complete : remaining_time;
}
return reading_not_started;
}
/*!
* @brief Enable and configure gas reading + heater
* @param heaterTemp
* Desired temperature in degrees Centigrade
* @param heaterTime
* Time to keep heater on in milliseconds
* @return True on success, False on failure
*/
bool Adafruit_BME680::setGasHeater(uint16_t heaterTemp, uint16_t heaterTime) {
if ((heaterTemp == 0) || (heaterTime == 0)) {
gas_heatr_conf.enable = BME68X_DISABLE;
} else {
gas_heatr_conf.enable = BME68X_ENABLE;
gas_heatr_conf.heatr_temp = heaterTemp;
gas_heatr_conf.heatr_dur = heaterTime;
}
int8_t rslt =
bme68x_set_heatr_conf(BME68X_FORCED_MODE, &gas_heatr_conf, &gas_sensor);
#ifdef BME680_DEBUG
Serial.print(F("SetHeaterConf Result: "));
Serial.println(rslt);
#endif
return rslt == 0;
}
/*!
* @brief Setter for Output Data Rate
* @param odr
* Output data rate setting, can be BME68X_ODR_NONE,
* BME68X_ODR_0_59_MS, BME68X_ODR_10_MS, BME68X_ODR_20_MS, BME68X_ODR_62_5_MS,
* BME68X_ODR_125_MS, BME68X_ODR_250_MS, BME68X_ODR_500_MS, BME68X_ODR_1000_MS
* @return True on success, False on failure
*/
bool Adafruit_BME680::setODR(uint8_t odr) {
if (odr > BME68X_ODR_NONE)
return false;
gas_conf.odr = odr;
int8_t rslt = bme68x_set_conf(&gas_conf, &gas_sensor);
#ifdef BME680_DEBUG
Serial.print(F("SetConf Result: "));
Serial.println(rslt);
#endif
return rslt == 0;
}
/*!
* @brief Setter for Temperature oversampling
* @param oversample
* Oversampling setting, can be BME68X_OS_NONE (turn off Temperature
* reading), BME68X_OS_1X, BME68X_OS_2X, BME68X_OS_4X, BME68X_OS_8X or
* BME68X_OS_16X
* @return True on success, False on failure
*/
bool Adafruit_BME680::setTemperatureOversampling(uint8_t oversample) {
if (oversample > BME68X_OS_16X)
return false;
gas_conf.os_temp = oversample;
int8_t rslt = bme68x_set_conf(&gas_conf, &gas_sensor);
#ifdef BME680_DEBUG
Serial.print(F("SetConf Result: "));
Serial.println(rslt);
#endif
return rslt == 0;
}
/*!
* @brief Setter for Humidity oversampling
* @param oversample
* Oversampling setting, can be BME68X_OS_NONE (turn off Humidity
* reading), BME68X_OS_1X, BME68X_OS_2X, BME68X_OS_4X, BME68X_OS_8X or
* BME68X_OS_16X
* @return True on success, False on failure
*/
bool Adafruit_BME680::setHumidityOversampling(uint8_t oversample) {
if (oversample > BME68X_OS_16X)
return false;
gas_conf.os_hum = oversample;
int8_t rslt = bme68x_set_conf(&gas_conf, &gas_sensor);
#ifdef BME680_DEBUG
Serial.print(F("SetConf Result: "));
Serial.println(rslt);
#endif
return rslt == 0;
}
/*!
* @brief Setter for Pressure oversampling
* @param oversample
* Oversampling setting, can be BME68X_OS_NONE (turn off Pressure
* reading), BME68X_OS_1X, BME68X_OS_2X, BME68X_OS_4X, BME68X_OS_8X or
* BME68X_OS_16X
* @return True on success, False on failure
*/
bool Adafruit_BME680::setPressureOversampling(uint8_t oversample) {
if (oversample > BME68X_OS_16X)
return false;
gas_conf.os_pres = oversample;
int8_t rslt = bme68x_set_conf(&gas_conf, &gas_sensor);
#ifdef BME680_DEBUG
Serial.print(F("SetConf Result: "));
Serial.println(rslt);
#endif
return rslt == 0;
}
/*!
* @brief Setter for IIR filter.
* @param filtersize
* Size of the filter (in samples).
* Can be BME68X_FILTER_SIZE_0 (no filtering), BME68X_FILTER_SIZE_1,
* BME68X_FILTER_SIZE_3, BME68X_FILTER_SIZE_7, BME68X_FILTER_SIZE_15,
* BME68X_FILTER_SIZE_31, BME68X_FILTER_SIZE_63, BME68X_FILTER_SIZE_127
* @return True on success, False on failure
*/
bool Adafruit_BME680::setIIRFilterSize(uint8_t filtersize) {
if (filtersize > BME68X_FILTER_SIZE_127)
return false;
gas_conf.filter = filtersize;
int8_t rslt = bme68x_set_conf(&gas_conf, &gas_sensor);
#ifdef BME680_DEBUG
Serial.print(F("SetConf Result: "));
Serial.println(rslt);
#endif
return rslt == 0;
}
/*!
* @brief Reads 8 bit values over I2C
*/
int8_t i2c_read(uint8_t reg_addr, uint8_t *reg_data, uint32_t len, void *intf) {
Adafruit_I2CDevice *_dev = (Adafruit_I2CDevice *)intf;
if (!_dev->write_then_read(&reg_addr, 1, reg_data, len, true)) {
return -1;
}
return 0;
}
/*!
* @brief Writes 8 bit values over I2C
*/
int8_t i2c_write(uint8_t reg_addr, const uint8_t *reg_data, uint32_t len,
void *intf) {
Adafruit_I2CDevice *_dev = (Adafruit_I2CDevice *)intf;
if (!_dev->write((uint8_t *)reg_data, len, true, &reg_addr, 1)) {
return -1;
}
return 0;
}
/*!
* @brief Reads 8 bit values over SPI
*/
static int8_t spi_read(uint8_t reg_addr, uint8_t *reg_data, uint32_t len,
void *intf_ptr) {
Adafruit_SPIDevice *_dev = (Adafruit_SPIDevice *)intf_ptr;
reg_addr |= 0x80;
if (!_dev->write_then_read(&reg_addr, 1, reg_data, len, 0x0)) {
return -1;
}
return 0;
}
/*!
* @brief Writes 8 bit values over SPI
*/
static int8_t spi_write(uint8_t reg_addr, const uint8_t *reg_data, uint32_t len,
void *intf_ptr) {
Adafruit_SPIDevice *_dev = (Adafruit_SPIDevice *)intf_ptr;
if (!_dev->write((uint8_t *)reg_data, len, &reg_addr, 1)) {
return -1;
}
return 0;
}
static void delay_usec(uint32_t us, void *intf_ptr) {
(void)intf_ptr; // Unused parameter
delayMicroseconds(us);
yield();
}

View File

@@ -0,0 +1,128 @@
/*!
* @file Adafruit_BME680.h
*
* Adafruit BME680 temperature, humidity, barometric pressure and gas sensor
* driver
*
* This is the documentation for Adafruit's BME680 driver for the
* Arduino platform. It is designed specifically to work with the
* Adafruit BME680 breakout: https://www.adafruit.com/products/3660
*
* These sensors use I2C to communicate, 2 pins (SCL+SDA) are required
* to interface with the breakout.
*
* Adafruit invests time and resources providing this open source code,
* please support Adafruit and open-source hardware by purchasing
* products from Adafruit!
*
* Written by Ladyada for Adafruit Industries.
*
* BSD license, all text here must be included in any redistribution.
*
*/
#ifndef __BME680_H__
#define __BME680_H__
#include "Arduino.h"
#include "bme68x.h"
#include <Adafruit_I2CDevice.h>
#include <Adafruit_SPIDevice.h>
#include <Adafruit_Sensor.h>
#include <Wire.h>
#define BME68X_DEFAULT_ADDRESS (0x77) ///< The default I2C address
#define BME68X_DEFAULT_SPIFREQ (1000000) ///< The default SPI Clock speed
#define BME680_OS_16X BME68X_OS_16X ///< Alias for BME680 existing examples
#define BME680_OS_8X BME68X_OS_8X ///< Alias for BME680 existing examples
#define BME680_OS_4X BME68X_OS_4X ///< Alias for BME680 existing examples
#define BME680_OS_2X BME68X_OS_2X ///< Alias for BME680 existing examples
#define BME680_OS_1X BME68X_OS_1X ///< Alias for BME680 existing examples
#define BME680_OS_NONE BME68X_OS_NONE ///< Alias for BME680 existing examples
#define BME680_FILTER_SIZE_127 \
BME68X_FILTER_SIZE_127 ///< Alias for BME680 existing examples
#define BME680_FILTER_SIZE_63 \
BME68X_FILTER_SIZE_63 ///< Alias for BME680 existing examples
#define BME680_FILTER_SIZE_31 \
BME68X_FILTER_SIZE_31 ///< Alias for BME680 existing examples
#define BME680_FILTER_SIZE_15 \
BME68X_FILTER_SIZE_15 ///< Alias for BME680 existing examples
#define BME680_FILTER_SIZE_7 \
BME68X_FILTER_SIZE_7 ///< Alias for BME680 existing examples
#define BME680_FILTER_SIZE_3 \
BME68X_FILTER_SIZE_3 ///< Alias for BME680 existing examples
#define BME680_FILTER_SIZE_1 \
BME68X_FILTER_SIZE_1 ///< Alias for BME680 existing examples
#define BME680_FILTER_SIZE_0 \
BME68X_FILTER_OFF ///< Alias for BME680 existing examples
/*! Adafruit_BME680 Class for both I2C and SPI usage.
* Wraps the Bosch library for Arduino usage
*/
class Adafruit_BME680 {
public:
/** Value returned by remainingReadingMillis indicating no asynchronous
* reading has been initiated by beginReading. **/
static constexpr int reading_not_started = -1;
/** Value returned by remainingReadingMillis indicating asynchronous reading
* is complete and calling endReading will not block. **/
static constexpr int reading_complete = 0;
Adafruit_BME680(TwoWire *theWire = &Wire);
Adafruit_BME680(int8_t cspin, SPIClass *theSPI = &SPI);
Adafruit_BME680(int8_t cspin, int8_t mosipin, int8_t misopin, int8_t sckpin);
bool begin(uint8_t addr = BME68X_DEFAULT_ADDRESS, bool initSettings = true);
float readTemperature();
float readPressure();
float readHumidity();
uint32_t readGas();
float readAltitude(float seaLevel);
bool setTemperatureOversampling(uint8_t os);
bool setPressureOversampling(uint8_t os);
bool setHumidityOversampling(uint8_t os);
bool setIIRFilterSize(uint8_t fs);
bool setGasHeater(uint16_t heaterTemp, uint16_t heaterTime);
bool setODR(uint8_t odr);
// Perform a reading in blocking mode.
bool performReading();
uint32_t beginReading();
bool endReading();
int remainingReadingMillis();
/** Temperature (Celsius) assigned after calling performReading() or
* endReading() **/
float temperature;
/** Pressure (Pascals) assigned after calling performReading() or endReading()
* **/
uint32_t pressure;
/** Humidity (RH %) assigned after calling performReading() or endReading()
* **/
float humidity;
/** Gas resistor (ohms) assigned after calling performReading() or
* endReading() **/
uint32_t gas_resistance;
private:
Adafruit_I2CDevice *_i2cdev = NULL;
Adafruit_SPIDevice *_spidev = NULL;
TwoWire *_wire = NULL;
int32_t _sensorID;
uint32_t _meas_start = 0;
uint16_t _meas_period = 0;
struct bme68x_dev gas_sensor;
struct bme68x_conf gas_conf;
struct bme68x_heatr_conf gas_heatr_conf;
};
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,31 @@
# Adafruit BME680 Library [![Build Status](https://github.com/adafruit/Adafruit_BME680/workflows/Arduino%20Library%20CI/badge.svg)](https://github.com/adafruit/Adafruit_BMPE680/actions)[![Documentation](https://github.com/adafruit/ci-arduino/blob/master/assets/doxygen_badge.svg)](http://adafruit.github.io/Adafruit_BME680/html/index.html)
<a href="http://www.adafruit.com/products/3660">
<img src="./assets/board.jpg" width="500px" />
</a>
The long awaited BME680 from Bosch gives you all the environmental sensing you want in one small package. This little sensor contains temperature, humidity, barometric pressure, and VOC gas sensing capabilities. All over SPI or I2C at a great price!
Like the BME280 & BMP280, this precision sensor from Bosch can measure humidity with ±3% accuracy, barometric pressure with ±1 hPa absolute accuracy, and temperature with ±1.0°C accuracy. Because pressure changes with altitude, and the pressure measurements are so good, you can also use it as an altimeter with ±1 meter or better accuracy!
The BME680 takes those sensors to the next step in that it contains a small MOX sensor. The heated metal oxide changes resistance based on the volatile organic compounds (VOC) in the air, so it can be used to detect gasses & alcohols such as Ethanol, Alcohol and Carbon Monoxide, and perform air quality measurements. Note it will give you one resistance value, with overall VOC content, but it cannot differentiate gasses or alcohols.
Designed specifically to work with the Adafruit BME680 Breakout
* http://www.adafruit.com/products/3660
These sensors use I2C or SPI to communicate, up to 4 pins are required to interface
Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!
Check out the links above for our tutorials and wiring diagrams
On-line documention for the APIs is available, too:
* https://adafruit.github.io/Adafruit_BME680/html/index.html
Requires installation of the Adafruit Unified Sensor library:
* https://github.com/adafruit/Adafruit_Sensor
Written by Limor Fried/Ladyada for Adafruit Industries.
BSD license, all text above must be included in any redistribution

Binary file not shown.

After

Width:  |  Height:  |  Size: 681 KiB

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,323 @@
/**
* Copyright (c) 2021 Bosch Sensortec GmbH. All rights reserved.
*
* BSD-3-Clause
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @file bme68x.h
* @date 2021-05-24
* @version v4.4.6
*
*/
/*!
* @defgroup bme68x BME68X
* @brief <a href="https://www.bosch-sensortec.com/bst/products/all_products/bme680">Product Overview</a>
* and <a href="https://github.com/BoschSensortec/BME68x-Sensor-API">Sensor API Source Code</a>
*/
#ifndef BME68X_H_
#define BME68X_H_
#include "bme68x_defs.h"
/* CPP guard */
#ifdef __cplusplus
extern "C" {
#endif
/**
* \ingroup bme68x
* \defgroup bme68xApiInit Initialization
* @brief Initialize the sensor and device structure
*/
/*!
* \ingroup bme68xApiInit
* \page bme68x_api_bme68x_init bme68x_init
* \code
* int8_t bme68x_init(struct bme68x_dev *dev);
* \endcode
* @details This API reads the chip-id of the sensor which is the first step to
* verify the sensor and also calibrates the sensor
* As this API is the entry point, call this API before using other APIs.
*
* @param[in,out] dev : Structure instance of bme68x_dev
*
* @return Result of API execution status
* @retval 0 -> Success
* @retval < 0 -> Fail
*/
int8_t bme68x_init(struct bme68x_dev *dev);
/**
* \ingroup bme68x
* \defgroup bme68xApiRegister Registers
* @brief Generic API for accessing sensor registers
*/
/*!
* \ingroup bme68xApiRegister
* \page bme68x_api_bme68x_set_regs bme68x_set_regs
* \code
* int8_t bme68x_set_regs(const uint8_t reg_addr, const uint8_t *reg_data, uint32_t len, struct bme68x_dev *dev)
* \endcode
* @details This API writes the given data to the register address of the sensor
*
* @param[in] reg_addr : Register addresses to where the data is to be written
* @param[in] reg_data : Pointer to data buffer which is to be written
* in the reg_addr of sensor.
* @param[in] len : No of bytes of data to write
* @param[in,out] dev : Structure instance of bme68x_dev
*
* @return Result of API execution status
* @retval 0 -> Success
* @retval < 0 -> Fail
*/
int8_t bme68x_set_regs(const uint8_t *reg_addr, const uint8_t *reg_data, uint32_t len, struct bme68x_dev *dev);
/*!
* \ingroup bme68xApiRegister
* \page bme68x_api_bme68x_get_regs bme68x_get_regs
* \code
* int8_t bme68x_get_regs(uint8_t reg_addr, uint8_t *reg_data, uint32_t len, struct bme68x_dev *dev)
* \endcode
* @details This API reads the data from the given register address of sensor.
*
* @param[in] reg_addr : Register address from where the data to be read
* @param[out] reg_data : Pointer to data buffer to store the read data.
* @param[in] len : No of bytes of data to be read.
* @param[in,out] dev : Structure instance of bme68x_dev.
*
* @return Result of API execution status
* @retval 0 -> Success
* @retval < 0 -> Fail
*/
int8_t bme68x_get_regs(uint8_t reg_addr, uint8_t *reg_data, uint32_t len, struct bme68x_dev *dev);
/**
* \ingroup bme68x
* \defgroup bme68xApiSystem System
* @brief API that performs system-level operations
*/
/*!
* \ingroup bme68xApiSystem
* \page bme68x_api_bme68x_soft_reset bme68x_soft_reset
* \code
* int8_t bme68x_soft_reset(struct bme68x_dev *dev);
* \endcode
* @details This API soft-resets the sensor.
*
* @param[in,out] dev : Structure instance of bme68x_dev.
*
* @return Result of API execution status
* @retval 0 -> Success
* @retval < 0 -> Fail
*/
int8_t bme68x_soft_reset(struct bme68x_dev *dev);
/**
* \ingroup bme68x
* \defgroup bme68xApiOm Operation mode
* @brief API to configure operation mode
*/
/*!
* \ingroup bme68xApiOm
* \page bme68x_api_bme68x_set_op_mode bme68x_set_op_mode
* \code
* int8_t bme68x_set_op_mode(const uint8_t op_mode, struct bme68x_dev *dev);
* \endcode
* @details This API is used to set the operation mode of the sensor
* @param[in] op_mode : Desired operation mode.
* @param[in] dev : Structure instance of bme68x_dev
*
* @return Result of API execution status
* @retval 0 -> Success
* @retval < 0 -> Fail
*/
int8_t bme68x_set_op_mode(const uint8_t op_mode, struct bme68x_dev *dev);
/*!
* \ingroup bme68xApiOm
* \page bme68x_api_bme68x_get_op_mode bme68x_get_op_mode
* \code
* int8_t bme68x_get_op_mode(uint8_t *op_mode, struct bme68x_dev *dev);
* \endcode
* @details This API is used to get the operation mode of the sensor.
*
* @param[out] op_mode : Desired operation mode.
* @param[in,out] dev : Structure instance of bme68x_dev
*
* @return Result of API execution status
* @retval 0 -> Success
* @retval < 0 -> Fail
*/
int8_t bme68x_get_op_mode(uint8_t *op_mode, struct bme68x_dev *dev);
/*!
* \ingroup bme68xApiConfig
* \page bme68x_api_bme68x_get_meas_dur bme68x_get_meas_dur
* \code
* uint32_t bme68x_get_meas_dur(const uint8_t op_mode, struct bme68x_conf *conf, struct bme68x_dev *dev);
* \endcode
* @details This API is used to get the remaining duration that can be used for heating.
*
* @param[in] op_mode : Desired operation mode.
* @param[in] conf : Desired sensor configuration.
* @param[in] dev : Structure instance of bme68x_dev
*
* @return Measurement duration calculated in microseconds
*/
uint32_t bme68x_get_meas_dur(const uint8_t op_mode, struct bme68x_conf *conf, struct bme68x_dev *dev);
/**
* \ingroup bme68x
* \defgroup bme68xApiData Data Read out
* @brief Read our data from the sensor
*/
/*!
* \ingroup bme68xApiData
* \page bme68x_api_bme68x_get_data bme68x_get_data
* \code
* int8_t bme68x_get_data(uint8_t op_mode, struct bme68x_data *data, uint8_t *n_data, struct bme68x_dev *dev);
* \endcode
* @details This API reads the pressure, temperature and humidity and gas data
* from the sensor, compensates the data and store it in the bme68x_data
* structure instance passed by the user.
*
* @param[in] op_mode : Expected operation mode.
* @param[out] data : Structure instance to hold the data.
* @param[out] n_data : Number of data instances available.
* @param[in,out] dev : Structure instance of bme68x_dev
*
* @return Result of API execution status
* @retval 0 -> Success
* @retval < 0 -> Fail
*/
int8_t bme68x_get_data(uint8_t op_mode, struct bme68x_data *data, uint8_t *n_data, struct bme68x_dev *dev);
/**
* \ingroup bme68x
* \defgroup bme68xApiConfig Configuration
* @brief Configuration API of sensor
*/
/*!
* \ingroup bme68xApiConfig
* \page bme68x_api_bme68x_set_conf bme68x_set_conf
* \code
* int8_t bme68x_set_conf(struct bme68x_conf *conf, struct bme68x_dev *dev);
* \endcode
* @details This API is used to set the oversampling, filter and odr configuration
*
* @param[in] conf : Desired sensor configuration.
* @param[in,out] dev : Structure instance of bme68x_dev.
*
* @return Result of API execution status
* @retval 0 -> Success
* @retval < 0 -> Fail
*/
int8_t bme68x_set_conf(struct bme68x_conf *conf, struct bme68x_dev *dev);
/*!
* \ingroup bme68xApiConfig
* \page bme68x_api_bme68x_get_conf bme68x_get_conf
* \code
* int8_t bme68x_get_conf(struct bme68x_conf *conf, struct bme68x_dev *dev);
* \endcode
* @details This API is used to get the oversampling, filter and odr
* configuration
*
* @param[out] conf : Present sensor configuration.
* @param[in,out] dev : Structure instance of bme68x_dev.
*
* @return Result of API execution status
* @retval 0 -> Success
* @retval < 0 -> Fail
*/
int8_t bme68x_get_conf(struct bme68x_conf *conf, struct bme68x_dev *dev);
/*!
* \ingroup bme68xApiConfig
* \page bme68x_api_bme68x_set_heatr_conf bme68x_set_heatr_conf
* \code
* int8_t bme68x_set_heatr_conf(uint8_t op_mode, const struct bme68x_heatr_conf *conf, struct bme68x_dev *dev);
* \endcode
* @details This API is used to set the gas configuration of the sensor.
*
* @param[in] op_mode : Expected operation mode of the sensor.
* @param[in] conf : Desired heating configuration.
* @param[in,out] dev : Structure instance of bme68x_dev.
*
* @return Result of API execution status
* @retval 0 -> Success
* @retval < 0 -> Fail
*/
int8_t bme68x_set_heatr_conf(uint8_t op_mode, const struct bme68x_heatr_conf *conf, struct bme68x_dev *dev);
/*!
* \ingroup bme68xApiConfig
* \page bme68x_api_bme68x_get_heatr_conf bme68x_get_heatr_conf
* \code
* int8_t bme68x_get_heatr_conf(const struct bme68x_heatr_conf *conf, struct bme68x_dev *dev);
* \endcode
* @details This API is used to get the gas configuration of the sensor.
*
* @param[out] conf : Current configurations of the gas sensor.
* @param[in,out] dev : Structure instance of bme68x_dev.
*
* @return Result of API execution status
* @retval 0 -> Success
* @retval < 0 -> Fail
*/
int8_t bme68x_get_heatr_conf(const struct bme68x_heatr_conf *conf, struct bme68x_dev *dev);
/*!
* \ingroup bme68xApiSystem
* \page bme68x_api_bme68x_low_gas_selftest_check bme68x_low_gas_selftest_check
* \code
* int8_t bme68x_low_gas_selftest_check(const struct bme68x_dev *dev);
* \endcode
* @details This API performs Self-test of low gas variant of BME68X
*
* @param[in, out] dev : Structure instance of bme68x_dev
*
* @return Result of API execution status
* @retval 0 -> Success
* @retval < 0 -> Fail
*/
int8_t bme68x_low_gas_selftest_check(const struct bme68x_dev *dev);
#ifdef __cplusplus
}
#endif /* End of CPP guard */
#endif /* BME68X_H_ */

View File

@@ -0,0 +1,972 @@
/**
* Copyright (c) 2021 Bosch Sensortec GmbH. All rights reserved.
*
* BSD-3-Clause
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @file bme68x_defs.h
* @date 2021-05-24
* @version v4.4.6
*
*/
/*! @cond DOXYGEN_SUPRESS */
#ifndef BME68X_DEFS_H_
#define BME68X_DEFS_H_
/********************************************************* */
/*! Header includes */
/********************************************************* */
#ifdef __KERNEL__
#include <linux/types.h>
#include <linux/kernel.h>
#else
#include <stdint.h>
#include <stddef.h>
#endif
/********************************************************* */
/*! Common Macros */
/********************************************************* */
#ifdef __KERNEL__
#if !defined(UINT8_C) && !defined(INT8_C)
#define INT8_C(x) S8_C(x)
#define UINT8_C(x) U8_C(x)
#endif
#if !defined(UINT16_C) && !defined(INT16_C)
#define INT16_C(x) S16_C(x)
#define UINT16_C(x) U16_C(x)
#endif
#if !defined(INT32_C) && !defined(UINT32_C)
#define INT32_C(x) S32_C(x)
#define UINT32_C(x) U32_C(x)
#endif
#if !defined(INT64_C) && !defined(UINT64_C)
#define INT64_C(x) S64_C(x)
#define UINT64_C(x) U64_C(x)
#endif
#endif
/*! C standard macros */
#ifndef NULL
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void *) 0)
#endif
#endif
#ifndef BME68X_DO_NOT_USE_FPU
/* Comment or un-comment the macro to provide floating point data output */
#define BME68X_USE_FPU
#endif
/* Period between two polls (value can be given by user) */
#ifndef BME68X_PERIOD_POLL
#define BME68X_PERIOD_POLL UINT32_C(10000)
#endif
/* BME68X unique chip identifier */
#define BME68X_CHIP_ID UINT8_C(0x61)
/* Period for a soft reset */
#define BME68X_PERIOD_RESET UINT32_C(10000)
/* BME68X lower I2C address */
#define BME68X_I2C_ADDR_LOW UINT8_C(0x76)
/* BME68X higher I2C address */
#define BME68X_I2C_ADDR_HIGH UINT8_C(0x77)
/* Soft reset command */
#define BME68X_SOFT_RESET_CMD UINT8_C(0xb6)
/* Return code definitions */
/* Success */
#define BME68X_OK INT8_C(0)
/* Errors */
/* Null pointer passed */
#define BME68X_E_NULL_PTR INT8_C(-1)
/* Communication failure */
#define BME68X_E_COM_FAIL INT8_C(-2)
/* Sensor not found */
#define BME68X_E_DEV_NOT_FOUND INT8_C(-3)
/* Incorrect length parameter */
#define BME68X_E_INVALID_LENGTH INT8_C(-4)
/* Self test fail error */
#define BME68X_E_SELF_TEST INT8_C(-5)
/* Warnings */
/* Define a valid operation mode */
#define BME68X_W_DEFINE_OP_MODE INT8_C(1)
/* No new data was found */
#define BME68X_W_NO_NEW_DATA INT8_C(2)
/* Define the shared heating duration */
#define BME68X_W_DEFINE_SHD_HEATR_DUR INT8_C(3)
/* Information - only available via bme68x_dev.info_msg */
#define BME68X_I_PARAM_CORR UINT8_C(1)
/* Register map addresses in I2C */
/* Register for 3rd group of coefficients */
#define BME68X_REG_COEFF3 UINT8_C(0x00)
/* 0th Field address*/
#define BME68X_REG_FIELD0 UINT8_C(0x1d)
/* 0th Current DAC address*/
#define BME68X_REG_IDAC_HEAT0 UINT8_C(0x50)
/* 0th Res heat address */
#define BME68X_REG_RES_HEAT0 UINT8_C(0x5a)
/* 0th Gas wait address */
#define BME68X_REG_GAS_WAIT0 UINT8_C(0x64)
/* Shared heating duration address */
#define BME68X_REG_SHD_HEATR_DUR UINT8_C(0x6E)
/* CTRL_GAS_0 address */
#define BME68X_REG_CTRL_GAS_0 UINT8_C(0x70)
/* CTRL_GAS_1 address */
#define BME68X_REG_CTRL_GAS_1 UINT8_C(0x71)
/* CTRL_HUM address */
#define BME68X_REG_CTRL_HUM UINT8_C(0x72)
/* CTRL_MEAS address */
#define BME68X_REG_CTRL_MEAS UINT8_C(0x74)
/* CONFIG address */
#define BME68X_REG_CONFIG UINT8_C(0x75)
/* MEM_PAGE address */
#define BME68X_REG_MEM_PAGE UINT8_C(0xf3)
/* Unique ID address */
#define BME68X_REG_UNIQUE_ID UINT8_C(0x83)
/* Register for 1st group of coefficients */
#define BME68X_REG_COEFF1 UINT8_C(0x8a)
/* Chip ID address */
#define BME68X_REG_CHIP_ID UINT8_C(0xd0)
/* Soft reset address */
#define BME68X_REG_SOFT_RESET UINT8_C(0xe0)
/* Register for 2nd group of coefficients */
#define BME68X_REG_COEFF2 UINT8_C(0xe1)
/* Variant ID Register */
#define BME68X_REG_VARIANT_ID UINT8_C(0xF0)
/* Enable/Disable macros */
/* Enable */
#define BME68X_ENABLE UINT8_C(0x01)
/* Disable */
#define BME68X_DISABLE UINT8_C(0x00)
/* Variant ID macros */
/* Low Gas variant */
#define BME68X_VARIANT_GAS_LOW UINT8_C(0x00)
/* High Gas variant */
#define BME68X_VARIANT_GAS_HIGH UINT8_C(0x01)
/* Oversampling setting macros */
/* Switch off measurement */
#define BME68X_OS_NONE UINT8_C(0)
/* Perform 1 measurement */
#define BME68X_OS_1X UINT8_C(1)
/* Perform 2 measurements */
#define BME68X_OS_2X UINT8_C(2)
/* Perform 4 measurements */
#define BME68X_OS_4X UINT8_C(3)
/* Perform 8 measurements */
#define BME68X_OS_8X UINT8_C(4)
/* Perform 16 measurements */
#define BME68X_OS_16X UINT8_C(5)
/* IIR Filter settings */
/* Switch off the filter */
#define BME68X_FILTER_OFF UINT8_C(0)
/* Filter coefficient of 2 */
#define BME68X_FILTER_SIZE_1 UINT8_C(1)
/* Filter coefficient of 4 */
#define BME68X_FILTER_SIZE_3 UINT8_C(2)
/* Filter coefficient of 8 */
#define BME68X_FILTER_SIZE_7 UINT8_C(3)
/* Filter coefficient of 16 */
#define BME68X_FILTER_SIZE_15 UINT8_C(4)
/* Filter coefficient of 32 */
#define BME68X_FILTER_SIZE_31 UINT8_C(5)
/* Filter coefficient of 64 */
#define BME68X_FILTER_SIZE_63 UINT8_C(6)
/* Filter coefficient of 128 */
#define BME68X_FILTER_SIZE_127 UINT8_C(7)
/* ODR/Standby time macros */
/* Standby time of 0.59ms */
#define BME68X_ODR_0_59_MS UINT8_C(0)
/* Standby time of 62.5ms */
#define BME68X_ODR_62_5_MS UINT8_C(1)
/* Standby time of 125ms */
#define BME68X_ODR_125_MS UINT8_C(2)
/* Standby time of 250ms */
#define BME68X_ODR_250_MS UINT8_C(3)
/* Standby time of 500ms */
#define BME68X_ODR_500_MS UINT8_C(4)
/* Standby time of 1s */
#define BME68X_ODR_1000_MS UINT8_C(5)
/* Standby time of 10ms */
#define BME68X_ODR_10_MS UINT8_C(6)
/* Standby time of 20ms */
#define BME68X_ODR_20_MS UINT8_C(7)
/* No standby time */
#define BME68X_ODR_NONE UINT8_C(8)
/* Operating mode macros */
/* Sleep operation mode */
#define BME68X_SLEEP_MODE UINT8_C(0)
/* Forced operation mode */
#define BME68X_FORCED_MODE UINT8_C(1)
/* Parallel operation mode */
#define BME68X_PARALLEL_MODE UINT8_C(2)
/* Sequential operation mode */
#define BME68X_SEQUENTIAL_MODE UINT8_C(3)
/* SPI page macros */
/* SPI memory page 0 */
#define BME68X_MEM_PAGE0 UINT8_C(0x10)
/* SPI memory page 1 */
#define BME68X_MEM_PAGE1 UINT8_C(0x00)
/* Coefficient index macros */
/* Length for all coefficients */
#define BME68X_LEN_COEFF_ALL UINT8_C(42)
/* Length for 1st group of coefficients */
#define BME68X_LEN_COEFF1 UINT8_C(23)
/* Length for 2nd group of coefficients */
#define BME68X_LEN_COEFF2 UINT8_C(14)
/* Length for 3rd group of coefficients */
#define BME68X_LEN_COEFF3 UINT8_C(5)
/* Length of the field */
#define BME68X_LEN_FIELD UINT8_C(17)
/* Length between two fields */
#define BME68X_LEN_FIELD_OFFSET UINT8_C(17)
/* Length of the configuration register */
#define BME68X_LEN_CONFIG UINT8_C(5)
/* Length of the interleaved buffer */
#define BME68X_LEN_INTERLEAVE_BUFF UINT8_C(20)
/* Coefficient index macros */
/* Coefficient T2 LSB position */
#define BME68X_IDX_T2_LSB (0)
/* Coefficient T2 MSB position */
#define BME68X_IDX_T2_MSB (1)
/* Coefficient T3 position */
#define BME68X_IDX_T3 (2)
/* Coefficient P1 LSB position */
#define BME68X_IDX_P1_LSB (4)
/* Coefficient P1 MSB position */
#define BME68X_IDX_P1_MSB (5)
/* Coefficient P2 LSB position */
#define BME68X_IDX_P2_LSB (6)
/* Coefficient P2 MSB position */
#define BME68X_IDX_P2_MSB (7)
/* Coefficient P3 position */
#define BME68X_IDX_P3 (8)
/* Coefficient P4 LSB position */
#define BME68X_IDX_P4_LSB (10)
/* Coefficient P4 MSB position */
#define BME68X_IDX_P4_MSB (11)
/* Coefficient P5 LSB position */
#define BME68X_IDX_P5_LSB (12)
/* Coefficient P5 MSB position */
#define BME68X_IDX_P5_MSB (13)
/* Coefficient P7 position */
#define BME68X_IDX_P7 (14)
/* Coefficient P6 position */
#define BME68X_IDX_P6 (15)
/* Coefficient P8 LSB position */
#define BME68X_IDX_P8_LSB (18)
/* Coefficient P8 MSB position */
#define BME68X_IDX_P8_MSB (19)
/* Coefficient P9 LSB position */
#define BME68X_IDX_P9_LSB (20)
/* Coefficient P9 MSB position */
#define BME68X_IDX_P9_MSB (21)
/* Coefficient P10 position */
#define BME68X_IDX_P10 (22)
/* Coefficient H2 MSB position */
#define BME68X_IDX_H2_MSB (23)
/* Coefficient H2 LSB position */
#define BME68X_IDX_H2_LSB (24)
/* Coefficient H1 LSB position */
#define BME68X_IDX_H1_LSB (24)
/* Coefficient H1 MSB position */
#define BME68X_IDX_H1_MSB (25)
/* Coefficient H3 position */
#define BME68X_IDX_H3 (26)
/* Coefficient H4 position */
#define BME68X_IDX_H4 (27)
/* Coefficient H5 position */
#define BME68X_IDX_H5 (28)
/* Coefficient H6 position */
#define BME68X_IDX_H6 (29)
/* Coefficient H7 position */
#define BME68X_IDX_H7 (30)
/* Coefficient T1 LSB position */
#define BME68X_IDX_T1_LSB (31)
/* Coefficient T1 MSB position */
#define BME68X_IDX_T1_MSB (32)
/* Coefficient GH2 LSB position */
#define BME68X_IDX_GH2_LSB (33)
/* Coefficient GH2 MSB position */
#define BME68X_IDX_GH2_MSB (34)
/* Coefficient GH1 position */
#define BME68X_IDX_GH1 (35)
/* Coefficient GH3 position */
#define BME68X_IDX_GH3 (36)
/* Coefficient res heat value position */
#define BME68X_IDX_RES_HEAT_VAL (37)
/* Coefficient res heat range position */
#define BME68X_IDX_RES_HEAT_RANGE (39)
/* Coefficient range switching error position */
#define BME68X_IDX_RANGE_SW_ERR (41)
/* Gas measurement macros */
/* Disable gas measurement */
#define BME68X_DISABLE_GAS_MEAS UINT8_C(0x00)
/* Enable gas measurement low */
#define BME68X_ENABLE_GAS_MEAS_L UINT8_C(0x01)
/* Enable gas measurement high */
#define BME68X_ENABLE_GAS_MEAS_H UINT8_C(0x02)
/* Heater control macros */
/* Enable heater */
#define BME68X_ENABLE_HEATER UINT8_C(0x00)
/* Disable heater */
#define BME68X_DISABLE_HEATER UINT8_C(0x01)
#ifdef BME68X_USE_FPU
/* 0 degree Celsius */
#define BME68X_MIN_TEMPERATURE INT16_C(0)
/* 60 degree Celsius */
#define BME68X_MAX_TEMPERATURE INT16_C(60)
/* 900 hecto Pascals */
#define BME68X_MIN_PRESSURE UINT32_C(90000)
/* 1100 hecto Pascals */
#define BME68X_MAX_PRESSURE UINT32_C(110000)
/* 20% relative humidity */
#define BME68X_MIN_HUMIDITY UINT32_C(20)
/* 80% relative humidity*/
#define BME68X_MAX_HUMIDITY UINT32_C(80)
#else
/* 0 degree Celsius */
#define BME68X_MIN_TEMPERATURE INT16_C(0)
/* 60 degree Celsius */
#define BME68X_MAX_TEMPERATURE INT16_C(6000)
/* 900 hecto Pascals */
#define BME68X_MIN_PRESSURE UINT32_C(90000)
/* 1100 hecto Pascals */
#define BME68X_MAX_PRESSURE UINT32_C(110000)
/* 20% relative humidity */
#define BME68X_MIN_HUMIDITY UINT32_C(20000)
/* 80% relative humidity*/
#define BME68X_MAX_HUMIDITY UINT32_C(80000)
#endif
#define BME68X_HEATR_DUR1 UINT16_C(1000)
#define BME68X_HEATR_DUR2 UINT16_C(2000)
#define BME68X_HEATR_DUR1_DELAY UINT32_C(1000000)
#define BME68X_HEATR_DUR2_DELAY UINT32_C(2000000)
#define BME68X_N_MEAS UINT8_C(6)
#define BME68X_LOW_TEMP UINT8_C(150)
#define BME68X_HIGH_TEMP UINT16_C(350)
/* Mask macros */
/* Mask for number of conversions */
#define BME68X_NBCONV_MSK UINT8_C(0X0f)
/* Mask for IIR filter */
#define BME68X_FILTER_MSK UINT8_C(0X1c)
/* Mask for ODR[3] */
#define BME68X_ODR3_MSK UINT8_C(0x80)
/* Mask for ODR[2:0] */
#define BME68X_ODR20_MSK UINT8_C(0xe0)
/* Mask for temperature oversampling */
#define BME68X_OST_MSK UINT8_C(0Xe0)
/* Mask for pressure oversampling */
#define BME68X_OSP_MSK UINT8_C(0X1c)
/* Mask for humidity oversampling */
#define BME68X_OSH_MSK UINT8_C(0X07)
/* Mask for heater control */
#define BME68X_HCTRL_MSK UINT8_C(0x08)
/* Mask for run gas */
#define BME68X_RUN_GAS_MSK UINT8_C(0x30)
/* Mask for operation mode */
#define BME68X_MODE_MSK UINT8_C(0x03)
/* Mask for res heat range */
#define BME68X_RHRANGE_MSK UINT8_C(0x30)
/* Mask for range switching error */
#define BME68X_RSERROR_MSK UINT8_C(0xf0)
/* Mask for new data */
#define BME68X_NEW_DATA_MSK UINT8_C(0x80)
/* Mask for gas index */
#define BME68X_GAS_INDEX_MSK UINT8_C(0x0f)
/* Mask for gas range */
#define BME68X_GAS_RANGE_MSK UINT8_C(0x0f)
/* Mask for gas measurement valid */
#define BME68X_GASM_VALID_MSK UINT8_C(0x20)
/* Mask for heater stability */
#define BME68X_HEAT_STAB_MSK UINT8_C(0x10)
/* Mask for SPI memory page */
#define BME68X_MEM_PAGE_MSK UINT8_C(0x10)
/* Mask for reading a register in SPI */
#define BME68X_SPI_RD_MSK UINT8_C(0x80)
/* Mask for writing a register in SPI */
#define BME68X_SPI_WR_MSK UINT8_C(0x7f)
/* Mask for the H1 calibration coefficient */
#define BME68X_BIT_H1_DATA_MSK UINT8_C(0x0f)
/* Position macros */
/* Filter bit position */
#define BME68X_FILTER_POS UINT8_C(2)
/* Temperature oversampling bit position */
#define BME68X_OST_POS UINT8_C(5)
/* Pressure oversampling bit position */
#define BME68X_OSP_POS UINT8_C(2)
/* ODR[3] bit position */
#define BME68X_ODR3_POS UINT8_C(7)
/* ODR[2:0] bit position */
#define BME68X_ODR20_POS UINT8_C(5)
/* Run gas bit position */
#define BME68X_RUN_GAS_POS UINT8_C(4)
/* Heater control bit position */
#define BME68X_HCTRL_POS UINT8_C(3)
/* Macro to combine two 8 bit data's to form a 16 bit data */
#define BME68X_CONCAT_BYTES(msb, lsb) (((uint16_t)msb << 8) | (uint16_t)lsb)
/* Macro to set bits */
#define BME68X_SET_BITS(reg_data, bitname, data) \
((reg_data & ~(bitname##_MSK)) | \
((data << bitname##_POS) & bitname##_MSK))
/* Macro to get bits */
#define BME68X_GET_BITS(reg_data, bitname) ((reg_data & (bitname##_MSK)) >> \
(bitname##_POS))
/* Macro to set bits starting from position 0 */
#define BME68X_SET_BITS_POS_0(reg_data, bitname, data) \
((reg_data & ~(bitname##_MSK)) | \
(data & bitname##_MSK))
/* Macro to get bits starting from position 0 */
#define BME68X_GET_BITS_POS_0(reg_data, bitname) (reg_data & (bitname##_MSK))
/**
* BME68X_INTF_RET_TYPE is the read/write interface return type which can be overwritten by the build system.
* The default is set to int8_t.
*/
#ifndef BME68X_INTF_RET_TYPE
#define BME68X_INTF_RET_TYPE int8_t
#endif
/**
* BME68X_INTF_RET_SUCCESS is the success return value read/write interface return type which can be
* overwritten by the build system. The default is set to 0. It is used to check for a successful
* execution of the read/write functions
*/
#ifndef BME68X_INTF_RET_SUCCESS
#define BME68X_INTF_RET_SUCCESS INT8_C(0)
#endif
/********************************************************* */
/*! Function Pointers */
/********************************************************* */
/*!
* @brief Bus communication function pointer which should be mapped to
* the platform specific read functions of the user
*
* @param[in] reg_addr : 8bit register address of the sensor
* @param[out] reg_data : Data from the specified address
* @param[in] length : Length of the reg_data array
* @param[in,out] intf_ptr : Void pointer that can enable the linking of descriptors
* for interface related callbacks
* @retval 0 for Success
* @retval Non-zero for Failure
*/
typedef BME68X_INTF_RET_TYPE (*bme68x_read_fptr_t)(uint8_t reg_addr, uint8_t *reg_data, uint32_t length,
void *intf_ptr);
/*!
* @brief Bus communication function pointer which should be mapped to
* the platform specific write functions of the user
*
* @param[in] reg_addr : 8bit register address of the sensor
* @param[out] reg_data : Data to the specified address
* @param[in] length : Length of the reg_data array
* @param[in,out] intf_ptr : Void pointer that can enable the linking of descriptors
* for interface related callbacks
* @retval 0 for Success
* @retval Non-zero for Failure
*
*/
typedef BME68X_INTF_RET_TYPE (*bme68x_write_fptr_t)(uint8_t reg_addr, const uint8_t *reg_data, uint32_t length,
void *intf_ptr);
/*!
* @brief Delay function pointer which should be mapped to
* delay function of the user
*
* @param period - The time period in microseconds
* @param[in,out] intf_ptr : Void pointer that can enable the linking of descriptors
* for interface related callbacks
*/
typedef void (*bme68x_delay_us_fptr_t)(uint32_t period, void *intf_ptr);
/*
* @brief Generic communication function pointer
* @param[in] dev_id: Place holder to store the id of the device structure
* Can be used to store the index of the Chip select or
* I2C address of the device.
* @param[in] reg_addr: Used to select the register the where data needs to
* be read from or written to.
* @param[in,out] reg_data: Data array to read/write
* @param[in] len: Length of the data array
*/
/*
* @brief Interface selection Enumerations
*/
enum bme68x_intf {
/*! SPI interface */
BME68X_SPI_INTF,
/*! I2C interface */
BME68X_I2C_INTF
};
/* Structure definitions */
/*
* @brief Sensor field data structure
*/
struct bme68x_data
{
/*! Contains new_data, gasm_valid & heat_stab */
uint8_t status;
/*! The index of the heater profile used */
uint8_t gas_index;
/*! Measurement index to track order */
uint8_t meas_index;
/*! Heater resistance */
uint8_t res_heat;
/*! Current DAC */
uint8_t idac;
/*! Gas wait period */
uint8_t gas_wait;
#ifndef BME68X_USE_FPU
/*! Temperature in degree celsius x100 */
int16_t temperature;
/*! Pressure in Pascal */
uint32_t pressure;
/*! Humidity in % relative humidity x1000 */
uint32_t humidity;
/*! Gas resistance in Ohms */
uint32_t gas_resistance;
#else
/*! Temperature in degree celsius */
float temperature;
/*! Pressure in Pascal */
float pressure;
/*! Humidity in % relative humidity x1000 */
float humidity;
/*! Gas resistance in Ohms */
float gas_resistance;
#endif
};
/*
* @brief Structure to hold the calibration coefficients
*/
struct bme68x_calib_data
{
/*! Calibration coefficient for the humidity sensor */
uint16_t par_h1;
/*! Calibration coefficient for the humidity sensor */
uint16_t par_h2;
/*! Calibration coefficient for the humidity sensor */
int8_t par_h3;
/*! Calibration coefficient for the humidity sensor */
int8_t par_h4;
/*! Calibration coefficient for the humidity sensor */
int8_t par_h5;
/*! Calibration coefficient for the humidity sensor */
uint8_t par_h6;
/*! Calibration coefficient for the humidity sensor */
int8_t par_h7;
/*! Calibration coefficient for the gas sensor */
int8_t par_gh1;
/*! Calibration coefficient for the gas sensor */
int16_t par_gh2;
/*! Calibration coefficient for the gas sensor */
int8_t par_gh3;
/*! Calibration coefficient for the temperature sensor */
uint16_t par_t1;
/*! Calibration coefficient for the temperature sensor */
int16_t par_t2;
/*! Calibration coefficient for the temperature sensor */
int8_t par_t3;
/*! Calibration coefficient for the pressure sensor */
uint16_t par_p1;
/*! Calibration coefficient for the pressure sensor */
int16_t par_p2;
/*! Calibration coefficient for the pressure sensor */
int8_t par_p3;
/*! Calibration coefficient for the pressure sensor */
int16_t par_p4;
/*! Calibration coefficient for the pressure sensor */
int16_t par_p5;
/*! Calibration coefficient for the pressure sensor */
int8_t par_p6;
/*! Calibration coefficient for the pressure sensor */
int8_t par_p7;
/*! Calibration coefficient for the pressure sensor */
int16_t par_p8;
/*! Calibration coefficient for the pressure sensor */
int16_t par_p9;
/*! Calibration coefficient for the pressure sensor */
uint8_t par_p10;
#ifndef BME68X_USE_FPU
/*! Variable to store the intermediate temperature coefficient */
int32_t t_fine;
#else
/*! Variable to store the intermediate temperature coefficient */
float t_fine;
#endif
/*! Heater resistance range coefficient */
uint8_t res_heat_range;
/*! Heater resistance value coefficient */
int8_t res_heat_val;
/*! Gas resistance range switching error coefficient */
int8_t range_sw_err;
};
/*
* @brief BME68X sensor settings structure which comprises of ODR,
* over-sampling and filter settings.
*/
struct bme68x_conf
{
/*! Humidity oversampling. Refer @ref osx*/
uint8_t os_hum;
/*! Temperature oversampling. Refer @ref osx */
uint8_t os_temp;
/*! Pressure oversampling. Refer @ref osx */
uint8_t os_pres;
/*! Filter coefficient. Refer @ref filter*/
uint8_t filter;
/*!
* Standby time between sequential mode measurement profiles.
* Refer @ref odr
*/
uint8_t odr;
};
/*
* @brief BME68X gas heater configuration
*/
struct bme68x_heatr_conf
{
/*! Enable gas measurement. Refer @ref en_dis */
uint8_t enable;
/*! Store the heater temperature for forced mode degree Celsius */
uint16_t heatr_temp;
/*! Store the heating duration for forced mode in milliseconds */
uint16_t heatr_dur;
/*! Store the heater temperature profile in degree Celsius */
uint16_t *heatr_temp_prof;
/*! Store the heating duration profile in milliseconds */
uint16_t *heatr_dur_prof;
/*! Variable to store the length of the heating profile */
uint8_t profile_len;
/*!
* Variable to store heating duration for parallel mode
* in milliseconds
*/
uint16_t shared_heatr_dur;
};
/*
* @brief BME68X device structure
*/
struct bme68x_dev
{
/*! Chip Id */
uint8_t chip_id;
/*!
* The interface pointer is used to enable the user
* to link their interface descriptors for reference during the
* implementation of the read and write interfaces to the
* hardware.
*/
void *intf_ptr;
/*!
* Variant id
* ----------------------------------------
* Value | Variant
* ----------------------------------------
* 0 | BME68X_VARIANT_GAS_LOW
* 1 | BME68X_VARIANT_GAS_HIGH
* ----------------------------------------
*/
uint32_t variant_id;
/*! SPI/I2C interface */
enum bme68x_intf intf;
/*! Memory page used */
uint8_t mem_page;
/*! Ambient temperature in Degree C*/
int8_t amb_temp;
/*! Sensor calibration data */
struct bme68x_calib_data calib;
/*! Read function pointer */
bme68x_read_fptr_t read;
/*! Write function pointer */
bme68x_write_fptr_t write;
/*! Delay function pointer */
bme68x_delay_us_fptr_t delay_us;
/*! To store interface pointer error */
BME68X_INTF_RET_TYPE intf_rslt;
/*! Store the info messages */
uint8_t info_msg;
};
#endif /* BME68X_DEFS_H_ */
/*! @endcond */

View File

@@ -0,0 +1,101 @@
/***************************************************************************
This is a library for the BME680 gas, humidity, temperature & pressure sensor
Designed specifically to work with the Adafruit BME680 Breakout
----> http://www.adafruit.com/products/3660
These sensors use I2C or SPI to communicate, 2 or 4 pins are required
to interface.
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 & Kevin Townsend for Adafruit Industries.
BSD license, all text above must be included in any redistribution
***************************************************************************/
#include <Wire.h>
#include <SPI.h>
#include <Adafruit_Sensor.h>
#include "Adafruit_BME680.h"
#define BME_SCK 13
#define BME_MISO 12
#define BME_MOSI 11
#define BME_CS 10
#define SEALEVELPRESSURE_HPA (1013.25)
Adafruit_BME680 bme; // I2C
//Adafruit_BME680 bme(BME_CS); // hardware SPI
//Adafruit_BME680 bme(BME_CS, BME_MOSI, BME_MISO, BME_SCK);
void setup() {
Serial.begin(9600);
while (!Serial);
Serial.println(F("BME680 async test"));
if (!bme.begin()) {
Serial.println(F("Could not find a valid BME680 sensor, check wiring!"));
while (1);
}
// Set up oversampling and filter initialization
bme.setTemperatureOversampling(BME680_OS_8X);
bme.setHumidityOversampling(BME680_OS_2X);
bme.setPressureOversampling(BME680_OS_4X);
bme.setIIRFilterSize(BME680_FILTER_SIZE_3);
bme.setGasHeater(320, 150); // 320*C for 150 ms
}
void loop() {
// Tell BME680 to begin measurement.
unsigned long endTime = bme.beginReading();
if (endTime == 0) {
Serial.println(F("Failed to begin reading :("));
return;
}
Serial.print(F("Reading started at "));
Serial.print(millis());
Serial.print(F(" and will finish at "));
Serial.println(endTime);
Serial.println(F("You can do other work during BME680 measurement."));
delay(50); // This represents parallel work.
// There's no need to delay() until millis() >= endTime: bme.endReading()
// takes care of that. It's okay for parallel work to take longer than
// BME680's measurement time.
// Obtain measurement results from BME680. Note that this operation isn't
// instantaneous even if milli() >= endTime due to I2C/SPI latency.
if (!bme.endReading()) {
Serial.println(F("Failed to complete reading :("));
return;
}
Serial.print(F("Reading completed at "));
Serial.println(millis());
Serial.print(F("Temperature = "));
Serial.print(bme.temperature);
Serial.println(F(" *C"));
Serial.print(F("Pressure = "));
Serial.print(bme.pressure / 100.0);
Serial.println(F(" hPa"));
Serial.print(F("Humidity = "));
Serial.print(bme.humidity);
Serial.println(F(" %"));
Serial.print(F("Gas = "));
Serial.print(bme.gas_resistance / 1000.0);
Serial.println(F(" KOhms"));
Serial.print(F("Approx. Altitude = "));
Serial.print(bme.readAltitude(SEALEVELPRESSURE_HPA));
Serial.println(F(" m"));
Serial.println();
delay(2000);
}

View File

@@ -0,0 +1,88 @@
/***************************************************************************
This is a library for the BME680 gas, humidity, temperature & pressure sensor
Designed specifically to work with the Adafruit BME680 Breakout
----> http://www.adafruit.com/products/3660
These sensors use I2C or SPI to communicate, 2 or 4 pins are required
to interface.
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 & Kevin Townsend for Adafruit Industries.
BSD license, all text above must be included in any redistribution
***************************************************************************/
#include <Wire.h>
#include <SPI.h>
#include <Adafruit_Sensor.h>
#include "Adafruit_BME680.h"
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define BME_SCK 13
#define BME_MISO 12
#define BME_MOSI 11
#define BME_CS 10
#define SEALEVELPRESSURE_HPA (1013.25)
Adafruit_BME680 bme; // I2C
//Adafruit_BME680 bme(BME_CS); // hardware SPI
//Adafruit_BME680 bme(BME_CS, BME_MOSI, BME_MISO, BME_SCK);
Adafruit_SSD1306 display = Adafruit_SSD1306();
void setup() {
Serial.begin(9600);
Serial.println(F("BME680 test"));
// by default, we'll generate the high voltage from the 3.3v line internally! (neat!)
display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // initialize with the I2C addr 0x3C (for the 128x32)
// init done
display.display();
delay(100);
display.clearDisplay();
display.display();
display.setTextSize(1);
display.setTextColor(WHITE);
if (!bme.begin()) {
Serial.println("Could not find a valid BME680 sensor, check wiring!");
while (1);
}
// Set up oversampling and filter initialization
bme.setTemperatureOversampling(BME680_OS_8X);
bme.setHumidityOversampling(BME680_OS_2X);
bme.setPressureOversampling(BME680_OS_4X);
bme.setIIRFilterSize(BME680_FILTER_SIZE_3);
bme.setGasHeater(320, 150); // 320*C for 150 ms
}
void loop() {
display.setCursor(0,0);
display.clearDisplay();
if (! bme.performReading()) {
Serial.println("Failed to perform reading :(");
return;
}
Serial.print("Temperature = "); Serial.print(bme.temperature); Serial.println(" *C");
display.print("Temperature: "); display.print(bme.temperature); display.println(" *C");
Serial.print("Pressure = "); Serial.print(bme.pressure / 100.0); Serial.println(" hPa");
display.print("Pressure: "); display.print(bme.pressure / 100); display.println(" hPa");
Serial.print("Humidity = "); Serial.print(bme.humidity); Serial.println(" %");
display.print("Humidity: "); display.print(bme.humidity); display.println(" %");
Serial.print("Gas = "); Serial.print(bme.gas_resistance / 1000.0); Serial.println(" KOhms");
display.print("Gas: "); display.print(bme.gas_resistance / 1000.0); display.println(" KOhms");
Serial.println();
display.display();
delay(2000);
}

View File

@@ -0,0 +1,80 @@
/***************************************************************************
This is a library for the BME680 gas, humidity, temperature & pressure sensor
Designed specifically to work with the Adafruit BME680 Breakout
----> http://www.adafruit.com/products/3660
These sensors use I2C or SPI to communicate, 2 or 4 pins are required
to interface.
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 & Kevin Townsend for Adafruit Industries.
BSD license, all text above must be included in any redistribution
***************************************************************************/
#include <Wire.h>
#include <SPI.h>
#include <Adafruit_Sensor.h>
#include "Adafruit_BME680.h"
#define BME_SCK 13
#define BME_MISO 12
#define BME_MOSI 11
#define BME_CS 10
#define SEALEVELPRESSURE_HPA (1013.25)
Adafruit_BME680 bme(&Wire); // I2C
//Adafruit_BME680 bme(&Wire1); // example of I2C on another bus
//Adafruit_BME680 bme(BME_CS); // hardware SPI
//Adafruit_BME680 bme(BME_CS, BME_MOSI, BME_MISO, BME_SCK);
void setup() {
Serial.begin(9600);
while (!Serial);
Serial.println(F("BME680 test"));
if (!bme.begin()) {
Serial.println("Could not find a valid BME680 sensor, check wiring!");
while (1);
}
// Set up oversampling and filter initialization
bme.setTemperatureOversampling(BME680_OS_8X);
bme.setHumidityOversampling(BME680_OS_2X);
bme.setPressureOversampling(BME680_OS_4X);
bme.setIIRFilterSize(BME680_FILTER_SIZE_3);
bme.setGasHeater(320, 150); // 320*C for 150 ms
}
void loop() {
if (! bme.performReading()) {
Serial.println("Failed to perform reading :(");
return;
}
Serial.print("Temperature = ");
Serial.print(bme.temperature);
Serial.println(" *C");
Serial.print("Pressure = ");
Serial.print(bme.pressure / 100.0);
Serial.println(" hPa");
Serial.print("Humidity = ");
Serial.print(bme.humidity);
Serial.println(" %");
Serial.print("Gas = ");
Serial.print(bme.gas_resistance / 1000.0);
Serial.println(" KOhms");
Serial.print("Approx. Altitude = ");
Serial.print(bme.readAltitude(SEALEVELPRESSURE_HPA));
Serial.println(" m");
Serial.println();
delay(2000);
}

View File

@@ -0,0 +1,10 @@
name=Adafruit BME680 Library
version=2.0.5
author=Adafruit
maintainer=Adafruit <info@adafruit.com>
sentence=Arduino library for BME680 and BME688 sensors.
paragraph=Arduino library for BME680 and BME688 humidity and pressure sensors.
category=Sensors
url=https://github.com/adafruit/Adafruit_BME680
architectures=*
depends=Adafruit Unified Sensor, Adafruit GFX Library, Adafruit SSD1306, Adafruit BusIO

View File

@@ -0,0 +1,493 @@
/*!
* @file Adafruit_BMP280.cpp
*
* This is a library for the BMP280 orientation sensor
*
* Designed specifically to work with the Adafruit BMP280 Sensor.
*
* Pick one up today in the adafruit shop!
* ------> https://www.adafruit.com/product/2651
*
* These sensors use I2C to communicate, 2 pins are required to interface.
*
* Adafruit invests time and resources providing this open source code,
* please support Adafruit andopen-source hardware by purchasing products
* from Adafruit!
*
* K.Townsend (Adafruit Industries)
*
* BSD license, all text above must be included in any redistribution
*/
#include <Adafruit_BMP280.h>
/*!
* @brief BMP280 constructor using i2c
* @param *theWire
* optional wire
*/
Adafruit_BMP280::Adafruit_BMP280(TwoWire *theWire) {
_wire = theWire;
temp_sensor = new Adafruit_BMP280_Temp(this);
pressure_sensor = new Adafruit_BMP280_Pressure(this);
}
/*!
* @brief BMP280 constructor using hardware SPI
* @param cspin
* cs pin number
* @param theSPI
* optional SPI object
*/
Adafruit_BMP280::Adafruit_BMP280(int8_t cspin, SPIClass *theSPI) {
spi_dev = new Adafruit_SPIDevice(cspin, 1000000, SPI_BITORDER_MSBFIRST,
SPI_MODE0, theSPI);
temp_sensor = new Adafruit_BMP280_Temp(this);
pressure_sensor = new Adafruit_BMP280_Pressure(this);
}
/*!
* @brief BMP280 constructor using bitbang SPI
* @param cspin
* The pin to use for CS/SSEL.
* @param mosipin
* The pin to use for MOSI.
* @param misopin
* The pin to use for MISO.
* @param sckpin
* The pin to use for SCK.
*/
Adafruit_BMP280::Adafruit_BMP280(int8_t cspin, int8_t mosipin, int8_t misopin,
int8_t sckpin) {
spi_dev = new Adafruit_SPIDevice(cspin, sckpin, misopin, mosipin);
temp_sensor = new Adafruit_BMP280_Temp(this);
pressure_sensor = new Adafruit_BMP280_Pressure(this);
}
Adafruit_BMP280::~Adafruit_BMP280(void) {
if (spi_dev)
delete spi_dev;
if (i2c_dev)
delete i2c_dev;
if (temp_sensor)
delete temp_sensor;
if (pressure_sensor)
delete pressure_sensor;
}
/*!
* Initialises the sensor.
* @param addr
* The I2C address to use (default = 0x77)
* @param chipid
* The expected chip ID (used to validate connection).
* @return True if the init was successful, otherwise false.
*/
bool Adafruit_BMP280::begin(uint8_t addr, uint8_t chipid) {
if (spi_dev == NULL) {
// I2C mode
if (i2c_dev)
delete i2c_dev;
i2c_dev = new Adafruit_I2CDevice(addr, _wire);
if (!i2c_dev->begin())
return false;
} else {
// SPI mode
if (!spi_dev->begin())
return false;
}
// check if sensor, i.e. the chip ID is correct
_sensorID = read8(BMP280_REGISTER_CHIPID);
if (_sensorID != chipid)
return false;
readCoefficients();
// write8(BMP280_REGISTER_CONTROL, 0x3F); /* needed? */
setSampling();
delay(100);
return true;
}
/*!
* Sets the sampling config for the device.
* @param mode
* The operating mode of the sensor.
* @param tempSampling
* The sampling scheme for temp readings.
* @param pressSampling
* The sampling scheme for pressure readings.
* @param filter
* The filtering mode to apply (if any).
* @param duration
* The sampling duration.
*/
void Adafruit_BMP280::setSampling(sensor_mode mode,
sensor_sampling tempSampling,
sensor_sampling pressSampling,
sensor_filter filter,
standby_duration duration) {
if (!_sensorID)
return; // begin() not called yet
_measReg.mode = mode;
_measReg.osrs_t = tempSampling;
_measReg.osrs_p = pressSampling;
_configReg.filter = filter;
_configReg.t_sb = duration;
write8(BMP280_REGISTER_CONFIG, _configReg.get());
write8(BMP280_REGISTER_CONTROL, _measReg.get());
}
/**************************************************************************/
/*!
@brief Writes an 8 bit value over I2C/SPI
*/
/**************************************************************************/
void Adafruit_BMP280::write8(byte reg, byte value) {
byte buffer[2];
buffer[1] = value;
if (i2c_dev) {
buffer[0] = reg;
i2c_dev->write(buffer, 2);
} else {
buffer[0] = reg & ~0x80;
spi_dev->write(buffer, 2);
}
}
/*!
* @brief Reads an 8 bit value over I2C/SPI
* @param reg
* selected register
* @return value from selected register
*/
uint8_t Adafruit_BMP280::read8(byte reg) {
uint8_t buffer[1];
if (i2c_dev) {
buffer[0] = uint8_t(reg);
i2c_dev->write_then_read(buffer, 1, buffer, 1);
} else {
buffer[0] = uint8_t(reg | 0x80);
spi_dev->write_then_read(buffer, 1, buffer, 1);
}
return buffer[0];
}
/*!
* @brief Reads a 16 bit value over I2C/SPI
*/
uint16_t Adafruit_BMP280::read16(byte reg) {
uint8_t buffer[2];
if (i2c_dev) {
buffer[0] = uint8_t(reg);
i2c_dev->write_then_read(buffer, 1, buffer, 2);
} else {
buffer[0] = uint8_t(reg | 0x80);
spi_dev->write_then_read(buffer, 1, buffer, 2);
}
return uint16_t(buffer[0]) << 8 | uint16_t(buffer[1]);
}
uint16_t Adafruit_BMP280::read16_LE(byte reg) {
uint16_t temp = read16(reg);
return (temp >> 8) | (temp << 8);
}
/*!
* @brief Reads a signed 16 bit value over I2C/SPI
*/
int16_t Adafruit_BMP280::readS16(byte reg) { return (int16_t)read16(reg); }
int16_t Adafruit_BMP280::readS16_LE(byte reg) {
return (int16_t)read16_LE(reg);
}
/*!
* @brief Reads a 24 bit value over I2C/SPI
*/
uint32_t Adafruit_BMP280::read24(byte reg) {
uint8_t buffer[3];
if (i2c_dev) {
buffer[0] = uint8_t(reg);
i2c_dev->write_then_read(buffer, 1, buffer, 3);
} else {
buffer[0] = uint8_t(reg | 0x80);
spi_dev->write_then_read(buffer, 1, buffer, 3);
}
return uint32_t(buffer[0]) << 16 | uint32_t(buffer[1]) << 8 |
uint32_t(buffer[2]);
}
/*!
* @brief Reads the factory-set coefficients
*/
void Adafruit_BMP280::readCoefficients() {
_bmp280_calib.dig_T1 = read16_LE(BMP280_REGISTER_DIG_T1);
_bmp280_calib.dig_T2 = readS16_LE(BMP280_REGISTER_DIG_T2);
_bmp280_calib.dig_T3 = readS16_LE(BMP280_REGISTER_DIG_T3);
_bmp280_calib.dig_P1 = read16_LE(BMP280_REGISTER_DIG_P1);
_bmp280_calib.dig_P2 = readS16_LE(BMP280_REGISTER_DIG_P2);
_bmp280_calib.dig_P3 = readS16_LE(BMP280_REGISTER_DIG_P3);
_bmp280_calib.dig_P4 = readS16_LE(BMP280_REGISTER_DIG_P4);
_bmp280_calib.dig_P5 = readS16_LE(BMP280_REGISTER_DIG_P5);
_bmp280_calib.dig_P6 = readS16_LE(BMP280_REGISTER_DIG_P6);
_bmp280_calib.dig_P7 = readS16_LE(BMP280_REGISTER_DIG_P7);
_bmp280_calib.dig_P8 = readS16_LE(BMP280_REGISTER_DIG_P8);
_bmp280_calib.dig_P9 = readS16_LE(BMP280_REGISTER_DIG_P9);
}
/*!
* Reads the temperature from the device.
* @return The temperature in degrees celsius.
*/
float Adafruit_BMP280::readTemperature() {
int32_t var1, var2;
if (!_sensorID)
return NAN; // begin() not called yet
int32_t adc_T = read24(BMP280_REGISTER_TEMPDATA);
adc_T >>= 4;
var1 = ((((adc_T >> 3) - ((int32_t)_bmp280_calib.dig_T1 << 1))) *
((int32_t)_bmp280_calib.dig_T2)) >>
11;
var2 = (((((adc_T >> 4) - ((int32_t)_bmp280_calib.dig_T1)) *
((adc_T >> 4) - ((int32_t)_bmp280_calib.dig_T1))) >>
12) *
((int32_t)_bmp280_calib.dig_T3)) >>
14;
t_fine = var1 + var2;
float T = (t_fine * 5 + 128) >> 8;
return T / 100;
}
/*!
* Reads the barometric pressure from the device.
* @return Barometric pressure in Pa.
*/
float Adafruit_BMP280::readPressure() {
int64_t var1, var2, p;
if (!_sensorID)
return NAN; // begin() not called yet
// Must be done first to get the t_fine variable set up
readTemperature();
int32_t adc_P = read24(BMP280_REGISTER_PRESSUREDATA);
adc_P >>= 4;
var1 = ((int64_t)t_fine) - 128000;
var2 = var1 * var1 * (int64_t)_bmp280_calib.dig_P6;
var2 = var2 + ((var1 * (int64_t)_bmp280_calib.dig_P5) << 17);
var2 = var2 + (((int64_t)_bmp280_calib.dig_P4) << 35);
var1 = ((var1 * var1 * (int64_t)_bmp280_calib.dig_P3) >> 8) +
((var1 * (int64_t)_bmp280_calib.dig_P2) << 12);
var1 =
(((((int64_t)1) << 47) + var1)) * ((int64_t)_bmp280_calib.dig_P1) >> 33;
if (var1 == 0) {
return 0; // avoid exception caused by division by zero
}
p = 1048576 - adc_P;
p = (((p << 31) - var2) * 3125) / var1;
var1 = (((int64_t)_bmp280_calib.dig_P9) * (p >> 13) * (p >> 13)) >> 25;
var2 = (((int64_t)_bmp280_calib.dig_P8) * p) >> 19;
p = ((p + var1 + var2) >> 8) + (((int64_t)_bmp280_calib.dig_P7) << 4);
return (float)p / 256;
}
/*!
* @brief Calculates the approximate altitude using barometric pressure and the
* supplied sea level hPa as a reference.
* @param seaLevelhPa
* The current hPa at sea level.
* @return The approximate altitude above sea level in meters.
*/
float Adafruit_BMP280::readAltitude(float seaLevelhPa) {
float altitude;
float pressure = readPressure(); // in Si units for Pascal
pressure /= 100;
altitude = 44330 * (1.0 - pow(pressure / seaLevelhPa, 0.1903));
return altitude;
}
/*!
* Calculates the pressure at sea level (QNH) from the specified altitude,
* and atmospheric pressure (QFE).
* @param altitude Altitude in m
* @param atmospheric Atmospheric pressure in hPa
* @return The approximate pressure in hPa
*/
float Adafruit_BMP280::seaLevelForAltitude(float altitude, float atmospheric) {
// Equation taken from BMP180 datasheet (page 17):
// http://www.adafruit.com/datasheets/BST-BMP180-DS000-09.pdf
// Note that using the equation from wikipedia can give bad results
// at high altitude. See this thread for more information:
// http://forums.adafruit.com/viewtopic.php?f=22&t=58064
return atmospheric / pow(1.0 - (altitude / 44330.0), 5.255);
}
/*!
@brief calculates the boiling point of water by a given pressure
@param pressure pressure in hPa
@return temperature in °C
*/
float Adafruit_BMP280::waterBoilingPoint(float pressure) {
// Magnusformular for calculation of the boiling point of water at a given
// pressure
return (234.175 * log(pressure / 6.1078)) /
(17.08085 - log(pressure / 6.1078));
}
/*!
@brief Take a new measurement (only possible in forced mode)
@return true if successful, otherwise false
*/
bool Adafruit_BMP280::takeForcedMeasurement() {
// If we are in forced mode, the BME sensor goes back to sleep after each
// measurement and we need to set it to forced mode once at this point, so
// it will take the next measurement and then return to sleep again.
// In normal mode simply does new measurements periodically.
if (_measReg.mode == MODE_FORCED) {
// set to forced mode, i.e. "take next measurement"
write8(BMP280_REGISTER_CONTROL, _measReg.get());
// wait until measurement has been completed, otherwise we would read
// the values from the last measurement
while (read8(BMP280_REGISTER_STATUS) & 0x08)
delay(1);
return true;
}
return false;
}
/*!
* @brief Resets the chip via soft reset
*/
void Adafruit_BMP280::reset(void) {
write8(BMP280_REGISTER_SOFTRESET, MODE_SOFT_RESET_CODE);
}
/*!
* Returns Sensor ID for diagnostics
* @returns 0x61 for BME680, 0x60 for BME280, 0x56, 0x57, 0x58 for BMP280
*/
uint8_t Adafruit_BMP280::sensorID(void) { return _sensorID; };
/*!
@brief Gets the most recent sensor event from the hardware status register.
@return Sensor status as a byte.
*/
uint8_t Adafruit_BMP280::getStatus(void) {
return read8(BMP280_REGISTER_STATUS);
}
/*!
@brief Gets an Adafruit Unified Sensor object for the temp sensor component
@return Adafruit_Sensor pointer to temperature sensor
*/
Adafruit_Sensor *Adafruit_BMP280::getTemperatureSensor(void) {
return temp_sensor;
}
/*!
@brief Gets an Adafruit Unified Sensor object for the pressure sensor
component
@return Adafruit_Sensor pointer to pressure sensor
*/
Adafruit_Sensor *Adafruit_BMP280::getPressureSensor(void) {
return pressure_sensor;
}
/**************************************************************************/
/*!
@brief Gets the sensor_t data for the BMP280's temperature sensor
*/
/**************************************************************************/
void Adafruit_BMP280_Temp::getSensor(sensor_t *sensor) {
/* Clear the sensor_t object */
memset(sensor, 0, sizeof(sensor_t));
/* Insert the sensor name in the fixed length char array */
strncpy(sensor->name, "BMP280", sizeof(sensor->name) - 1);
sensor->name[sizeof(sensor->name) - 1] = 0;
sensor->version = 1;
sensor->sensor_id = _sensorID;
sensor->type = SENSOR_TYPE_AMBIENT_TEMPERATURE;
sensor->min_delay = 0;
sensor->min_value = -40.0; /* Temperature range -40 ~ +85 C */
sensor->max_value = +85.0;
sensor->resolution = 0.01; /* 0.01 C */
}
/**************************************************************************/
/*!
@brief Gets the temperature as a standard sensor event
@param event Sensor event object that will be populated
@returns True
*/
/**************************************************************************/
bool Adafruit_BMP280_Temp::getEvent(sensors_event_t *event) {
/* Clear the event */
memset(event, 0, sizeof(sensors_event_t));
event->version = sizeof(sensors_event_t);
event->sensor_id = _sensorID;
event->type = SENSOR_TYPE_AMBIENT_TEMPERATURE;
event->timestamp = millis();
event->temperature = _theBMP280->readTemperature();
return true;
}
/**************************************************************************/
/*!
@brief Gets the sensor_t data for the BMP280's pressure sensor
*/
/**************************************************************************/
void Adafruit_BMP280_Pressure::getSensor(sensor_t *sensor) {
/* Clear the sensor_t object */
memset(sensor, 0, sizeof(sensor_t));
/* Insert the sensor name in the fixed length char array */
strncpy(sensor->name, "BMP280", sizeof(sensor->name) - 1);
sensor->name[sizeof(sensor->name) - 1] = 0;
sensor->version = 1;
sensor->sensor_id = _sensorID;
sensor->type = SENSOR_TYPE_PRESSURE;
sensor->min_delay = 0;
sensor->min_value = 300.0; /* 300 ~ 1100 hPa */
sensor->max_value = 1100.0;
sensor->resolution = 0.012; /* 0.12 hPa relative */
}
/**************************************************************************/
/*!
@brief Gets the pressure as a standard sensor event
@param event Sensor event object that will be populated
@returns True
*/
/**************************************************************************/
bool Adafruit_BMP280_Pressure::getEvent(sensors_event_t *event) {
/* Clear the event */
memset(event, 0, sizeof(sensors_event_t));
event->version = sizeof(sensors_event_t);
event->sensor_id = _sensorID;
event->type = SENSOR_TYPE_PRESSURE;
event->timestamp = millis();
event->pressure = _theBMP280->readPressure() / 100; // convert Pa to hPa
return true;
}

View File

@@ -0,0 +1,267 @@
/*!
* @file Adafruit_BMP280.h
*
* This is a library for the Adafruit BMP280 Breakout.
*
* Designed specifically to work with the Adafruit BMP280 Breakout.
*
* Pick one up today in the adafruit shop!
* ------> https://www.adafruit.com/product/2651
*
* These sensors use I2C to communicate, 2 pins are required to interface.
*
* Adafruit invests time and resources providing this open source code,
* please support Adafruit andopen-source hardware by purchasing products
* from Adafruit!
*
* K.Townsend (Adafruit Industries)
*
* BSD license, all text above must be included in any redistribution
*/
#ifndef __BMP280_H__
#define __BMP280_H__
// clang-format off
#include <Arduino.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_I2CDevice.h>
#include <Adafruit_SPIDevice.h>
// clang-format on
/*!
* I2C ADDRESS/BITS/SETTINGS
*/
#define BMP280_ADDRESS (0x77) /**< The default I2C address for the sensor. */
#define BMP280_ADDRESS_ALT \
(0x76) /**< Alternative I2C address for the sensor. */
#define BMP280_CHIPID (0x58) /**< Default chip ID. */
/*!
* Registers available on the sensor.
*/
enum {
BMP280_REGISTER_DIG_T1 = 0x88,
BMP280_REGISTER_DIG_T2 = 0x8A,
BMP280_REGISTER_DIG_T3 = 0x8C,
BMP280_REGISTER_DIG_P1 = 0x8E,
BMP280_REGISTER_DIG_P2 = 0x90,
BMP280_REGISTER_DIG_P3 = 0x92,
BMP280_REGISTER_DIG_P4 = 0x94,
BMP280_REGISTER_DIG_P5 = 0x96,
BMP280_REGISTER_DIG_P6 = 0x98,
BMP280_REGISTER_DIG_P7 = 0x9A,
BMP280_REGISTER_DIG_P8 = 0x9C,
BMP280_REGISTER_DIG_P9 = 0x9E,
BMP280_REGISTER_CHIPID = 0xD0,
BMP280_REGISTER_VERSION = 0xD1,
BMP280_REGISTER_SOFTRESET = 0xE0,
BMP280_REGISTER_CAL26 = 0xE1, /**< R calibration = 0xE1-0xF0 */
BMP280_REGISTER_STATUS = 0xF3,
BMP280_REGISTER_CONTROL = 0xF4,
BMP280_REGISTER_CONFIG = 0xF5,
BMP280_REGISTER_PRESSUREDATA = 0xF7,
BMP280_REGISTER_TEMPDATA = 0xFA,
};
/*!
* Struct to hold calibration data.
*/
typedef struct {
uint16_t dig_T1; /**< dig_T1 cal register. */
int16_t dig_T2; /**< dig_T2 cal register. */
int16_t dig_T3; /**< dig_T3 cal register. */
uint16_t dig_P1; /**< dig_P1 cal register. */
int16_t dig_P2; /**< dig_P2 cal register. */
int16_t dig_P3; /**< dig_P3 cal register. */
int16_t dig_P4; /**< dig_P4 cal register. */
int16_t dig_P5; /**< dig_P5 cal register. */
int16_t dig_P6; /**< dig_P6 cal register. */
int16_t dig_P7; /**< dig_P7 cal register. */
int16_t dig_P8; /**< dig_P8 cal register. */
int16_t dig_P9; /**< dig_P9 cal register. */
} bmp280_calib_data;
class Adafruit_BMP280;
/** Adafruit Unified Sensor interface for temperature component of BMP280 */
class Adafruit_BMP280_Temp : public Adafruit_Sensor {
public:
/** @brief Create an Adafruit_Sensor compatible object for the temp sensor
@param parent A pointer to the BMP280 class */
Adafruit_BMP280_Temp(Adafruit_BMP280 *parent) { _theBMP280 = parent; }
bool getEvent(sensors_event_t *);
void getSensor(sensor_t *);
private:
int _sensorID = 280;
Adafruit_BMP280 *_theBMP280 = NULL;
};
/** Adafruit Unified Sensor interface for pressure component of BMP280 */
class Adafruit_BMP280_Pressure : public Adafruit_Sensor {
public:
/** @brief Create an Adafruit_Sensor compatible object for the pressure sensor
@param parent A pointer to the BMP280 class */
Adafruit_BMP280_Pressure(Adafruit_BMP280 *parent) { _theBMP280 = parent; }
bool getEvent(sensors_event_t *);
void getSensor(sensor_t *);
private:
int _sensorID = 0;
Adafruit_BMP280 *_theBMP280 = NULL;
};
/**
* Driver for the Adafruit BMP280 barometric pressure sensor.
*/
class Adafruit_BMP280 {
public:
/** Oversampling rate for the sensor. */
enum sensor_sampling {
/** No over-sampling. */
SAMPLING_NONE = 0x00,
/** 1x over-sampling. */
SAMPLING_X1 = 0x01,
/** 2x over-sampling. */
SAMPLING_X2 = 0x02,
/** 4x over-sampling. */
SAMPLING_X4 = 0x03,
/** 8x over-sampling. */
SAMPLING_X8 = 0x04,
/** 16x over-sampling. */
SAMPLING_X16 = 0x05
};
/** Operating mode for the sensor. */
enum sensor_mode {
/** Sleep mode. */
MODE_SLEEP = 0x00,
/** Forced mode. */
MODE_FORCED = 0x01,
/** Normal mode. */
MODE_NORMAL = 0x03,
/** Software reset. */
MODE_SOFT_RESET_CODE = 0xB6
};
/** Filtering level for sensor data. */
enum sensor_filter {
/** No filtering. */
FILTER_OFF = 0x00,
/** 2x filtering. */
FILTER_X2 = 0x01,
/** 4x filtering. */
FILTER_X4 = 0x02,
/** 8x filtering. */
FILTER_X8 = 0x03,
/** 16x filtering. */
FILTER_X16 = 0x04
};
/** Standby duration in ms */
enum standby_duration {
/** 1 ms standby. */
STANDBY_MS_1 = 0x00,
/** 62.5 ms standby. */
STANDBY_MS_63 = 0x01,
/** 125 ms standby. */
STANDBY_MS_125 = 0x02,
/** 250 ms standby. */
STANDBY_MS_250 = 0x03,
/** 500 ms standby. */
STANDBY_MS_500 = 0x04,
/** 1000 ms standby. */
STANDBY_MS_1000 = 0x05,
/** 2000 ms standby. */
STANDBY_MS_2000 = 0x06,
/** 4000 ms standby. */
STANDBY_MS_4000 = 0x07
};
Adafruit_BMP280(TwoWire *theWire = &Wire);
Adafruit_BMP280(int8_t cspin, SPIClass *theSPI = &SPI);
Adafruit_BMP280(int8_t cspin, int8_t mosipin, int8_t misopin, int8_t sckpin);
~Adafruit_BMP280(void);
bool begin(uint8_t addr = BMP280_ADDRESS, uint8_t chipid = BMP280_CHIPID);
void reset(void);
uint8_t getStatus(void);
uint8_t sensorID(void);
float readTemperature();
float readPressure(void);
float readAltitude(float seaLevelhPa = 1013.25);
float seaLevelForAltitude(float altitude, float atmospheric);
float waterBoilingPoint(float pressure);
bool takeForcedMeasurement();
Adafruit_Sensor *getTemperatureSensor(void);
Adafruit_Sensor *getPressureSensor(void);
void setSampling(sensor_mode mode = MODE_NORMAL,
sensor_sampling tempSampling = SAMPLING_X16,
sensor_sampling pressSampling = SAMPLING_X16,
sensor_filter filter = FILTER_OFF,
standby_duration duration = STANDBY_MS_1);
private:
TwoWire *_wire; /**< Wire object */
Adafruit_I2CDevice *i2c_dev = NULL; ///< Pointer to I2C bus interface
Adafruit_SPIDevice *spi_dev = NULL; ///< Pointer to SPI bus interface
Adafruit_BMP280_Temp *temp_sensor = NULL;
Adafruit_BMP280_Pressure *pressure_sensor = NULL;
/** Encapsulates the config register */
struct config {
/** Initialize to power-on-reset state */
config() : t_sb(STANDBY_MS_1), filter(FILTER_OFF), none(0), spi3w_en(0) {}
/** Inactive duration (standby time) in normal mode */
unsigned int t_sb : 3;
/** Filter settings */
unsigned int filter : 3;
/** Unused - don't set */
unsigned int none : 1;
/** Enables 3-wire SPI */
unsigned int spi3w_en : 1;
/** Used to retrieve the assembled config register's byte value. */
unsigned int get() { return (t_sb << 5) | (filter << 2) | spi3w_en; }
};
/** Encapsulates trhe ctrl_meas register */
struct ctrl_meas {
/** Initialize to power-on-reset state */
ctrl_meas()
: osrs_t(SAMPLING_NONE), osrs_p(SAMPLING_NONE), mode(MODE_SLEEP) {}
/** Temperature oversampling. */
unsigned int osrs_t : 3;
/** Pressure oversampling. */
unsigned int osrs_p : 3;
/** Device mode */
unsigned int mode : 2;
/** Used to retrieve the assembled ctrl_meas register's byte value. */
unsigned int get() { return (osrs_t << 5) | (osrs_p << 2) | mode; }
};
void readCoefficients(void);
uint8_t spixfer(uint8_t x);
void write8(byte reg, byte value);
uint8_t read8(byte reg);
uint16_t read16(byte reg);
uint32_t read24(byte reg);
int16_t readS16(byte reg);
uint16_t read16_LE(byte reg);
int16_t readS16_LE(byte reg);
uint8_t _i2caddr;
int32_t _sensorID = 0;
int32_t t_fine;
// int8_t _cs, _mosi, _miso, _sck;
bmp280_calib_data _bmp280_calib;
config _configReg;
ctrl_meas _measReg;
};
#endif

View File

@@ -0,0 +1,47 @@
# Adafruit BMP280 Driver (Barometric Pressure Sensor) [![Build Status](https://travis-ci.com/adafruit/Adafruit_BMP280_Library.svg?branch=master)](https://travis-ci.com/adafruit/Adafruit_BMP280_Library)
This driver is for the [Adafruit BMP280 Breakout](http://www.adafruit.com/products/2651)
<a href="https://www.adafruit.com/product/2651"><img src="assets/board.jpg" width="500"/></a>
## About the BMP280 ##
This precision sensor from Bosch is the best low-cost sensing solution for measuring barometric pressure and temperature. Because pressure changes with altitude you can also use it as an altimeter!
## About this Driver ##
Adafruit invests time and resources providing this open source code. Please support Adafruit and open-source hardware by purchasing products from Adafruit!
Written by Kevin (KTOWN) Townsend for Adafruit Industries.
<!-- START COMPATIBILITY TABLE -->
## Compatibility
MCU | Tested Works | Doesn't Work | Not Tested | Notes
------------------ | :----------: | :----------: | :---------: | -----
Atmega328 @ 16MHz | X | | |
Atmega328 @ 12MHz | X | | |
Atmega32u4 @ 16MHz | X | | | Use SDA/SCL on pins D2 &amp; D3
Atmega32u4 @ 8MHz | X | | | Use SDA/SCL on pins D2 &amp; D3
ESP8266 | X | | | SDA/SCL default to pins 4 &amp; 5 but any two pins can be assigned as SDA/SCL using Wire.begin(SDA,SCL)
Atmega2560 @ 16MHz | X | | | Use SDA/SCL on pins 20 &amp; 21
ATSAM3X8E | X | | | Use SDA/SCL on pins 20 &amp; 21
ATSAM21D | X | | |
ATtiny85 @ 16MHz | | X | |
ATtiny85 @ 8MHz | | X | |
Intel Curie @ 32MHz | | | X |
STM32F2 | | | X |
* ATmega328 @ 16MHz : Arduino UNO, Adafruit Pro Trinket 5V, Adafruit Metro 328, Adafruit Metro Mini
* ATmega328 @ 12MHz : Adafruit Pro Trinket 3V
* ATmega32u4 @ 16MHz : Arduino Leonardo, Arduino Micro, Arduino Yun, Teensy 2.0
* ATmega32u4 @ 8MHz : Adafruit Flora, Bluefruit Micro
* ESP8266 : Adafruit Huzzah
* ATmega2560 @ 16MHz : Arduino Mega
* ATSAM3X8E : Arduino Due
* ATSAM21D : Arduino Zero, M0 Pro
* ATtiny85 @ 16MHz : Adafruit Trinket 5V
* ATtiny85 @ 8MHz : Adafruit Gemma, Arduino Gemma, Adafruit Trinket 3V
<!-- END COMPATIBILITY TABLE -->

Binary file not shown.

After

Width:  |  Height:  |  Size: 453 KiB

View File

@@ -0,0 +1,72 @@
/***************************************************************************
This is a library for the BMP280 humidity, temperature & pressure sensor
Designed specifically to work with the Adafruit BMP280 Breakout
----> http://www.adafruit.com/products/2651
These sensors use I2C or SPI to communicate, 2 or 4 pins are required
to interface.
Adafruit invests time and resources providing this open source code,
please support Adafruit andopen-source hardware by purchasing products
from Adafruit!
Written by Limor Fried & Kevin Townsend for Adafruit Industries.
BSD license, all text above must be included in any redistribution
***************************************************************************/
#include <Adafruit_BMP280.h>
#define BMP_SCK (13)
#define BMP_MISO (12)
#define BMP_MOSI (11)
#define BMP_CS (10)
Adafruit_BMP280 bmp; // I2C
//Adafruit_BMP280 bmp(BMP_CS); // hardware SPI
//Adafruit_BMP280 bmp(BMP_CS, BMP_MOSI, BMP_MISO, BMP_SCK);
void setup() {
Serial.begin(9600);
Serial.println(F("BMP280 Forced Mode Test."));
//if (!bmp.begin(BMP280_ADDRESS_ALT, BMP280_CHIPID)) {
if (!bmp.begin()) {
Serial.println(F("Could not find a valid BMP280 sensor, check wiring or "
"try a different address!"));
while (1) delay(10);
}
/* Default settings from datasheet. */
bmp.setSampling(Adafruit_BMP280::MODE_FORCED, /* Operating Mode. */
Adafruit_BMP280::SAMPLING_X2, /* Temp. oversampling */
Adafruit_BMP280::SAMPLING_X16, /* Pressure oversampling */
Adafruit_BMP280::FILTER_X16, /* Filtering. */
Adafruit_BMP280::STANDBY_MS_500); /* Standby time. */
}
void loop() {
// must call this to wake sensor up and get new measurement data
// it blocks until measurement is complete
if (bmp.takeForcedMeasurement()) {
// can now print out the new measurements
Serial.print(F("Temperature = "));
Serial.print(bmp.readTemperature());
Serial.println(" *C");
Serial.print(F("Pressure = "));
Serial.print(bmp.readPressure());
Serial.println(" Pa");
Serial.print(F("Approx altitude = "));
Serial.print(bmp.readAltitude(1013.25)); /* Adjusted to local forecast! */
Serial.println(" m");
Serial.println();
delay(2000);
} else {
Serial.println("Forced measurement failed!");
}
}

View File

@@ -0,0 +1,71 @@
/***************************************************************************
This is a library for the BMP280 humidity, temperature & pressure sensor
This example shows how to take Sensor Events instead of direct readings
Designed specifically to work with the Adafruit BMP280 Breakout
----> http://www.adafruit.com/products/2651
These sensors use I2C or SPI to communicate, 2 or 4 pins are required
to interface.
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 & Kevin Townsend for Adafruit Industries.
BSD license, all text above must be included in any redistribution
***************************************************************************/
#include <Wire.h>
#include <SPI.h>
#include <Adafruit_BMP280.h>
Adafruit_BMP280 bmp; // use I2C interface
Adafruit_Sensor *bmp_temp = bmp.getTemperatureSensor();
Adafruit_Sensor *bmp_pressure = bmp.getPressureSensor();
void setup() {
Serial.begin(9600);
while ( !Serial ) delay(100); // wait for native usb
Serial.println(F("BMP280 Sensor event test"));
unsigned status;
//status = bmp.begin(BMP280_ADDRESS_ALT, BMP280_CHIPID);
status = bmp.begin();
if (!status) {
Serial.println(F("Could not find a valid BMP280 sensor, check wiring or "
"try a different address!"));
Serial.print("SensorID was: 0x"); Serial.println(bmp.sensorID(),16);
Serial.print(" ID of 0xFF probably means a bad address, a BMP 180 or BMP 085\n");
Serial.print(" ID of 0x56-0x58 represents a BMP 280,\n");
Serial.print(" ID of 0x60 represents a BME 280.\n");
Serial.print(" ID of 0x61 represents a BME 680.\n");
while (1) delay(10);
}
/* Default settings from datasheet. */
bmp.setSampling(Adafruit_BMP280::MODE_NORMAL, /* Operating Mode. */
Adafruit_BMP280::SAMPLING_X2, /* Temp. oversampling */
Adafruit_BMP280::SAMPLING_X16, /* Pressure oversampling */
Adafruit_BMP280::FILTER_X16, /* Filtering. */
Adafruit_BMP280::STANDBY_MS_500); /* Standby time. */
bmp_temp->printSensorDetails();
}
void loop() {
sensors_event_t temp_event, pressure_event;
bmp_temp->getEvent(&temp_event);
bmp_pressure->getEvent(&pressure_event);
Serial.print(F("Temperature = "));
Serial.print(temp_event.temperature);
Serial.println(" *C");
Serial.print(F("Pressure = "));
Serial.print(pressure_event.pressure);
Serial.println(" hPa");
Serial.println();
delay(2000);
}

View File

@@ -0,0 +1,72 @@
/***************************************************************************
This is a library for the BMP280 humidity, temperature & pressure sensor
Designed specifically to work with the Adafruit BMP280 Breakout
----> http://www.adafruit.com/products/2651
These sensors use I2C or SPI to communicate, 2 or 4 pins are required
to interface.
Adafruit invests time and resources providing this open source code,
please support Adafruit andopen-source hardware by purchasing products
from Adafruit!
Written by Limor Fried & Kevin Townsend for Adafruit Industries.
BSD license, all text above must be included in any redistribution
***************************************************************************/
#include <Wire.h>
#include <SPI.h>
#include <Adafruit_BMP280.h>
#define BMP_SCK (13)
#define BMP_MISO (12)
#define BMP_MOSI (11)
#define BMP_CS (10)
Adafruit_BMP280 bmp; // I2C
//Adafruit_BMP280 bmp(BMP_CS); // hardware SPI
//Adafruit_BMP280 bmp(BMP_CS, BMP_MOSI, BMP_MISO, BMP_SCK);
void setup() {
Serial.begin(9600);
while ( !Serial ) delay(100); // wait for native usb
Serial.println(F("BMP280 test"));
unsigned status;
//status = bmp.begin(BMP280_ADDRESS_ALT, BMP280_CHIPID);
status = bmp.begin();
if (!status) {
Serial.println(F("Could not find a valid BMP280 sensor, check wiring or "
"try a different address!"));
Serial.print("SensorID was: 0x"); Serial.println(bmp.sensorID(),16);
Serial.print(" ID of 0xFF probably means a bad address, a BMP 180 or BMP 085\n");
Serial.print(" ID of 0x56-0x58 represents a BMP 280,\n");
Serial.print(" ID of 0x60 represents a BME 280.\n");
Serial.print(" ID of 0x61 represents a BME 680.\n");
while (1) delay(10);
}
/* Default settings from datasheet. */
bmp.setSampling(Adafruit_BMP280::MODE_NORMAL, /* Operating Mode. */
Adafruit_BMP280::SAMPLING_X2, /* Temp. oversampling */
Adafruit_BMP280::SAMPLING_X16, /* Pressure oversampling */
Adafruit_BMP280::FILTER_X16, /* Filtering. */
Adafruit_BMP280::STANDBY_MS_500); /* Standby time. */
}
void loop() {
Serial.print(F("Temperature = "));
Serial.print(bmp.readTemperature());
Serial.println(" *C");
Serial.print(F("Pressure = "));
Serial.print(bmp.readPressure());
Serial.println(" Pa");
Serial.print(F("Approx altitude = "));
Serial.print(bmp.readAltitude(1013.25)); /* Adjusted to local forecast! */
Serial.println(" m");
Serial.println();
delay(2000);
}

View File

@@ -0,0 +1,57 @@
#######################################
# Syntax Coloring Map for BMP280 library
#######################################
#######################################
# Datatypes (KEYWORD1)
#######################################
Adafruit_BMP280 KEYWORD1
Adafruit_BMP280_Temp KEYWORD1
Adafruit_BMP280_Pressure KEYWORD1
bmp280_calib_data KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
begin KEYWORD2
reset KEYWORD2
getStatus KEYWORD2
sensorID KEYWORD2
getEvent KEYWORD2
getSensor KEYWORD2
readTemperature KEYWORD2
readPressure KEYWORD2
readAltitude KEYWORD2
seaLevelForAltitude KEYWORD2
waterBoilingPoint KEYWORD2
takeForcedMeasurement KEYWORD2
getTemperatureSensor KEYWORD2
getPressureSensor KEYWORD2
setSampling KEYWORD2
#######################################
# Constants (LITERAL1)
#######################################
SAMPLING_NONE LITERAL1
SAMPLING_X1 LITERAL1
SAMPLING_X2 LITERAL1
SAMPLING_X4 LITERAL1
SAMPLING_X8 LITERAL1
SAMPLING_X16 LITERAL1
MODE_SLEEP LITERAL1
MODE_FORCED LITERAL1
MODE_NORMAL LITERAL1
MODE_SOFT_RESET_CODE LITERAL1
FILTER_OFF LITERAL1
FILTER_X2 LITERAL1
FILTER_X4 LITERAL1
FILTER_X8 LITERAL1
FILTER_X16 LITERAL1
STANDBY_MS_1 LITERAL1
STANDBY_MS_63 LITERAL1
STANDBY_MS_125 LITERAL1
STANDBY_MS_250 LITERAL1
STANDBY_MS_500 LITERAL1
STANDBY_MS_1000 LITERAL1
STANDBY_MS_2000 LITERAL1
STANDBY_MS_4000 LITERAL1

View File

@@ -0,0 +1,10 @@
name=Adafruit BMP280 Library
version=2.6.8
author=Adafruit
maintainer=Adafruit <info@adafruit.com>
sentence=Arduino library for BMP280 sensors.
paragraph=Arduino library for BMP280 pressure and altitude sensors.
category=Sensors
url=https://github.com/adafruit/Adafruit_BMP280_Library
architectures=*
depends=Adafruit Unified Sensor, Adafruit BusIO

View File

@@ -0,0 +1,365 @@
#include <Adafruit_BusIO_Register.h>
#if !defined(SPI_INTERFACES_COUNT) || \
(defined(SPI_INTERFACES_COUNT) && (SPI_INTERFACES_COUNT > 0))
/*!
* @brief Create a register we access over an I2C Device (which defines the
* bus and address)
* @param i2cdevice The I2CDevice to use for underlying I2C access
* @param reg_addr The address pointer value for the I2C/SMBus register, can
* be 8 or 16 bits
* @param width The width of the register data itself, defaults to 1 byte
* @param byteorder The byte order of the register (used when width is > 1),
* defaults to LSBFIRST
* @param address_width The width of the register address itself, defaults
* to 1 byte
*/
Adafruit_BusIO_Register::Adafruit_BusIO_Register(Adafruit_I2CDevice *i2cdevice,
uint16_t reg_addr,
uint8_t width,
uint8_t byteorder,
uint8_t address_width) {
_i2cdevice = i2cdevice;
_spidevice = nullptr;
_addrwidth = address_width;
_address = reg_addr;
_byteorder = byteorder;
_width = width;
}
/*!
* @brief Create a register we access over an SPI Device (which defines the
* bus and CS pin)
* @param spidevice The SPIDevice to use for underlying SPI access
* @param reg_addr The address pointer value for the SPI register, can
* be 8 or 16 bits
* @param type The method we use to read/write data to SPI (which is not
* as well defined as I2C)
* @param width The width of the register data itself, defaults to 1 byte
* @param byteorder The byte order of the register (used when width is > 1),
* defaults to LSBFIRST
* @param address_width The width of the register address itself, defaults
* to 1 byte
*/
Adafruit_BusIO_Register::Adafruit_BusIO_Register(Adafruit_SPIDevice *spidevice,
uint16_t reg_addr,
Adafruit_BusIO_SPIRegType type,
uint8_t width,
uint8_t byteorder,
uint8_t address_width) {
_spidevice = spidevice;
_spiregtype = type;
_i2cdevice = nullptr;
_addrwidth = address_width;
_address = reg_addr;
_byteorder = byteorder;
_width = width;
}
/*!
* @brief Create a register we access over an I2C or SPI Device. This is a
* handy function because we can pass in nullptr for the unused interface,
* allowing libraries to mass-define all the registers
* @param i2cdevice The I2CDevice to use for underlying I2C access, if
* nullptr we use SPI
* @param spidevice The SPIDevice to use for underlying SPI access, if
* nullptr we use I2C
* @param reg_addr The address pointer value for the I2C/SMBus/SPI register,
* can be 8 or 16 bits
* @param type The method we use to read/write data to SPI (which is not
* as well defined as I2C)
* @param width The width of the register data itself, defaults to 1 byte
* @param byteorder The byte order of the register (used when width is > 1),
* defaults to LSBFIRST
* @param address_width The width of the register address itself, defaults
* to 1 byte
*/
Adafruit_BusIO_Register::Adafruit_BusIO_Register(
Adafruit_I2CDevice *i2cdevice, Adafruit_SPIDevice *spidevice,
Adafruit_BusIO_SPIRegType type, uint16_t reg_addr, uint8_t width,
uint8_t byteorder, uint8_t address_width) {
_spidevice = spidevice;
_i2cdevice = i2cdevice;
_spiregtype = type;
_addrwidth = address_width;
_address = reg_addr;
_byteorder = byteorder;
_width = width;
}
/*!
* @brief Write a buffer of data to the register location
* @param buffer Pointer to data to write
* @param len Number of bytes to write
* @return True on successful write (only really useful for I2C as SPI is
* uncheckable)
*/
bool Adafruit_BusIO_Register::write(uint8_t *buffer, uint8_t len) {
uint8_t addrbuffer[2] = {(uint8_t)(_address & 0xFF),
(uint8_t)(_address >> 8)};
if (_i2cdevice) {
return _i2cdevice->write(buffer, len, true, addrbuffer, _addrwidth);
}
if (_spidevice) {
if (_spiregtype == ADDRESSED_OPCODE_BIT0_LOW_TO_WRITE) {
// very special case!
// pass the special opcode address which we set as the high byte of the
// regaddr
addrbuffer[0] =
(uint8_t)(_address >> 8) & ~0x01; // set bottom bit low to write
// the 'actual' reg addr is the second byte then
addrbuffer[1] = (uint8_t)(_address & 0xFF);
// the address appears to be a byte longer
return _spidevice->write(buffer, len, addrbuffer, _addrwidth + 1);
}
if (_spiregtype == ADDRBIT8_HIGH_TOREAD) {
addrbuffer[0] &= ~0x80;
}
if (_spiregtype == ADDRBIT8_HIGH_TOWRITE) {
addrbuffer[0] |= 0x80;
}
if (_spiregtype == AD8_HIGH_TOREAD_AD7_HIGH_TOINC) {
addrbuffer[0] &= ~0x80;
addrbuffer[0] |= 0x40;
}
return _spidevice->write(buffer, len, addrbuffer, _addrwidth);
}
return false;
}
/*!
* @brief Write up to 4 bytes of data to the register location
* @param value Data to write
* @param numbytes How many bytes from 'value' to write
* @return True on successful write (only really useful for I2C as SPI is
* uncheckable)
*/
bool Adafruit_BusIO_Register::write(uint32_t value, uint8_t numbytes) {
if (numbytes == 0) {
numbytes = _width;
}
if (numbytes > 4) {
return false;
}
// store a copy
_cached = value;
for (int i = 0; i < numbytes; i++) {
if (_byteorder == LSBFIRST) {
_buffer[i] = value & 0xFF;
} else {
_buffer[numbytes - i - 1] = value & 0xFF;
}
value >>= 8;
}
return write(_buffer, numbytes);
}
/*!
* @brief Read data from the register location. This does not do any error
* checking!
* @return Returns 0xFFFFFFFF on failure, value otherwise
*/
uint32_t Adafruit_BusIO_Register::read(void) {
if (!read(_buffer, _width)) {
return -1;
}
uint32_t value = 0;
for (int i = 0; i < _width; i++) {
value <<= 8;
if (_byteorder == LSBFIRST) {
value |= _buffer[_width - i - 1];
} else {
value |= _buffer[i];
}
}
return value;
}
/*!
* @brief Read cached data from last time we wrote to this register
* @return Returns 0xFFFFFFFF on failure, value otherwise
*/
uint32_t Adafruit_BusIO_Register::readCached(void) { return _cached; }
/*!
* @brief Read a buffer of data from the register location
* @param buffer Pointer to data to read into
* @param len Number of bytes to read
* @return True on successful write (only really useful for I2C as SPI is
* uncheckable)
*/
bool Adafruit_BusIO_Register::read(uint8_t *buffer, uint8_t len) {
uint8_t addrbuffer[2] = {(uint8_t)(_address & 0xFF),
(uint8_t)(_address >> 8)};
if (_i2cdevice) {
return _i2cdevice->write_then_read(addrbuffer, _addrwidth, buffer, len);
}
if (_spidevice) {
if (_spiregtype == ADDRESSED_OPCODE_BIT0_LOW_TO_WRITE) {
// very special case!
// pass the special opcode address which we set as the high byte of the
// regaddr
addrbuffer[0] =
(uint8_t)(_address >> 8) | 0x01; // set bottom bit high to read
// the 'actual' reg addr is the second byte then
addrbuffer[1] = (uint8_t)(_address & 0xFF);
// the address appears to be a byte longer
return _spidevice->write_then_read(addrbuffer, _addrwidth + 1, buffer,
len);
}
if (_spiregtype == ADDRBIT8_HIGH_TOREAD) {
addrbuffer[0] |= 0x80;
}
if (_spiregtype == ADDRBIT8_HIGH_TOWRITE) {
addrbuffer[0] &= ~0x80;
}
if (_spiregtype == AD8_HIGH_TOREAD_AD7_HIGH_TOINC) {
addrbuffer[0] |= 0x80 | 0x40;
}
return _spidevice->write_then_read(addrbuffer, _addrwidth, buffer, len);
}
return false;
}
/*!
* @brief Read 2 bytes of data from the register location
* @param value Pointer to uint16_t variable to read into
* @return True on successful write (only really useful for I2C as SPI is
* uncheckable)
*/
bool Adafruit_BusIO_Register::read(uint16_t *value) {
if (!read(_buffer, 2)) {
return false;
}
if (_byteorder == LSBFIRST) {
*value = _buffer[1];
*value <<= 8;
*value |= _buffer[0];
} else {
*value = _buffer[0];
*value <<= 8;
*value |= _buffer[1];
}
return true;
}
/*!
* @brief Read 1 byte of data from the register location
* @param value Pointer to uint8_t variable to read into
* @return True on successful write (only really useful for I2C as SPI is
* uncheckable)
*/
bool Adafruit_BusIO_Register::read(uint8_t *value) {
if (!read(_buffer, 1)) {
return false;
}
*value = _buffer[0];
return true;
}
/*!
* @brief Pretty printer for this register
* @param s The Stream to print to, defaults to &Serial
*/
void Adafruit_BusIO_Register::print(Stream *s) {
uint32_t val = read();
s->print("0x");
s->print(val, HEX);
}
/*!
* @brief Pretty printer for this register
* @param s The Stream to print to, defaults to &Serial
*/
void Adafruit_BusIO_Register::println(Stream *s) {
print(s);
s->println();
}
/*!
* @brief Create a slice of the register that we can address without
* touching other bits
* @param reg The Adafruit_BusIO_Register which defines the bus/register
* @param bits The number of bits wide we are slicing
* @param shift The number of bits that our bit-slice is shifted from LSB
*/
Adafruit_BusIO_RegisterBits::Adafruit_BusIO_RegisterBits(
Adafruit_BusIO_Register *reg, uint8_t bits, uint8_t shift) {
_register = reg;
_bits = bits;
_shift = shift;
}
/*!
* @brief Read 4 bytes of data from the register
* @return data The 4 bytes to read
*/
uint32_t Adafruit_BusIO_RegisterBits::read(void) {
uint32_t val = _register->read();
val >>= _shift;
return val & ((1 << (_bits)) - 1);
}
/*!
* @brief Write 4 bytes of data to the register
* @param data The 4 bytes to write
* @return True on successful write (only really useful for I2C as SPI is
* uncheckable)
*/
bool Adafruit_BusIO_RegisterBits::write(uint32_t data) {
uint32_t val = _register->read();
// mask off the data before writing
uint32_t mask = (1 << (_bits)) - 1;
data &= mask;
mask <<= _shift;
val &= ~mask; // remove the current data at that spot
val |= data << _shift; // and add in the new data
return _register->write(val, _register->width());
}
/*!
* @brief The width of the register data, helpful for doing calculations
* @returns The data width used when initializing the register
*/
uint8_t Adafruit_BusIO_Register::width(void) { return _width; }
/*!
* @brief Set the default width of data
* @param width the default width of data read from register
*/
void Adafruit_BusIO_Register::setWidth(uint8_t width) { _width = width; }
/*!
* @brief Set register address
* @param address the address from register
*/
void Adafruit_BusIO_Register::setAddress(uint16_t address) {
_address = address;
}
/*!
* @brief Set the width of register address
* @param address_width the width for register address
*/
void Adafruit_BusIO_Register::setAddressWidth(uint16_t address_width) {
_addrwidth = address_width;
}
#endif // SPI exists

View File

@@ -0,0 +1,105 @@
#ifndef Adafruit_BusIO_Register_h
#define Adafruit_BusIO_Register_h
#include <Arduino.h>
#if !defined(SPI_INTERFACES_COUNT) || \
(defined(SPI_INTERFACES_COUNT) && (SPI_INTERFACES_COUNT > 0))
#include <Adafruit_I2CDevice.h>
#include <Adafruit_SPIDevice.h>
typedef enum _Adafruit_BusIO_SPIRegType {
ADDRBIT8_HIGH_TOREAD = 0,
/*!<
* ADDRBIT8_HIGH_TOREAD
* When reading a register you must actually send the value 0x80 + register
* address to the device. e.g. To read the register 0x0B the register value
* 0x8B is sent and to write 0x0B is sent.
*/
AD8_HIGH_TOREAD_AD7_HIGH_TOINC = 1,
/*!<
* ADDRBIT8_HIGH_TOWRITE
* When writing to a register you must actually send the value 0x80 +
* the register address to the device. e.g. To write to the register 0x19 the
* register value 0x99 is sent and to read 0x19 is sent.
*/
ADDRBIT8_HIGH_TOWRITE = 2,
/*!<
* ADDRESSED_OPCODE_LOWBIT_TO_WRITE
* Used by the MCP23S series, we send 0x40 |'rd with the opcode
* Then set the lowest bit to write
*/
ADDRESSED_OPCODE_BIT0_LOW_TO_WRITE = 3,
} Adafruit_BusIO_SPIRegType;
/*!
* @brief The class which defines a device register (a location to read/write
* data from)
*/
class Adafruit_BusIO_Register {
public:
Adafruit_BusIO_Register(Adafruit_I2CDevice *i2cdevice, uint16_t reg_addr,
uint8_t width = 1, uint8_t byteorder = LSBFIRST,
uint8_t address_width = 1);
Adafruit_BusIO_Register(Adafruit_SPIDevice *spidevice, uint16_t reg_addr,
Adafruit_BusIO_SPIRegType type, uint8_t width = 1,
uint8_t byteorder = LSBFIRST,
uint8_t address_width = 1);
Adafruit_BusIO_Register(Adafruit_I2CDevice *i2cdevice,
Adafruit_SPIDevice *spidevice,
Adafruit_BusIO_SPIRegType type, uint16_t reg_addr,
uint8_t width = 1, uint8_t byteorder = LSBFIRST,
uint8_t address_width = 1);
bool read(uint8_t *buffer, uint8_t len);
bool read(uint8_t *value);
bool read(uint16_t *value);
uint32_t read(void);
uint32_t readCached(void);
bool write(uint8_t *buffer, uint8_t len);
bool write(uint32_t value, uint8_t numbytes = 0);
uint8_t width(void);
void setWidth(uint8_t width);
void setAddress(uint16_t address);
void setAddressWidth(uint16_t address_width);
void print(Stream *s = &Serial);
void println(Stream *s = &Serial);
private:
Adafruit_I2CDevice *_i2cdevice;
Adafruit_SPIDevice *_spidevice;
Adafruit_BusIO_SPIRegType _spiregtype;
uint16_t _address;
uint8_t _width, _addrwidth, _byteorder;
uint8_t _buffer[4]; // we won't support anything larger than uint32 for
// non-buffered read
uint32_t _cached = 0;
};
/*!
* @brief The class which defines a slice of bits from within a device register
* (a location to read/write data from)
*/
class Adafruit_BusIO_RegisterBits {
public:
Adafruit_BusIO_RegisterBits(Adafruit_BusIO_Register *reg, uint8_t bits,
uint8_t shift);
bool write(uint32_t value);
uint32_t read(void);
private:
Adafruit_BusIO_Register *_register;
uint8_t _bits, _shift;
};
#endif // SPI exists
#endif // BusIO_Register_h

View File

@@ -0,0 +1,320 @@
#include "Adafruit_I2CDevice.h"
//#define DEBUG_SERIAL Serial
/*!
* @brief Create an I2C device at a given address
* @param addr The 7-bit I2C address for the device
* @param theWire The I2C bus to use, defaults to &Wire
*/
Adafruit_I2CDevice::Adafruit_I2CDevice(uint8_t addr, TwoWire *theWire) {
_addr = addr;
_wire = theWire;
_begun = false;
#ifdef ARDUINO_ARCH_SAMD
_maxBufferSize = 250; // as defined in Wire.h's RingBuffer
#elif defined(ESP32)
_maxBufferSize = I2C_BUFFER_LENGTH;
#else
_maxBufferSize = 32;
#endif
}
/*!
* @brief Initializes and does basic address detection
* @param addr_detect Whether we should attempt to detect the I2C address
* with a scan. 99% of sensors/devices don't mind, but once in a while they
* don't respond well to a scan!
* @return True if I2C initialized and a device with the addr found
*/
bool Adafruit_I2CDevice::begin(bool addr_detect) {
_wire->begin();
_begun = true;
if (addr_detect) {
return detected();
}
return true;
}
/*!
* @brief De-initialize device, turn off the Wire interface
*/
void Adafruit_I2CDevice::end(void) {
// Not all port implement Wire::end(), such as
// - ESP8266
// - AVR core without WIRE_HAS_END
// - ESP32: end() is implemented since 2.0.1 which is latest at the moment.
// Temporarily disable for now to give time for user to update.
#if !(defined(ESP8266) || \
(defined(ARDUINO_ARCH_AVR) && !defined(WIRE_HAS_END)) || \
defined(ARDUINO_ARCH_ESP32))
_wire->end();
_begun = false;
#endif
}
/*!
* @brief Scans I2C for the address - note will give a false-positive
* if there's no pullups on I2C
* @return True if I2C initialized and a device with the addr found
*/
bool Adafruit_I2CDevice::detected(void) {
// Init I2C if not done yet
if (!_begun && !begin()) {
return false;
}
// A basic scanner, see if it ACK's
_wire->beginTransmission(_addr);
#ifdef DEBUG_SERIAL
DEBUG_SERIAL.print(F("Address 0x"));
DEBUG_SERIAL.print(_addr);
#endif
#ifdef ARDUINO_ARCH_MBED
_wire->write(0); // forces a write request instead of a read
#endif
if (_wire->endTransmission() == 0) {
#ifdef DEBUG_SERIAL
DEBUG_SERIAL.println(F(" Detected"));
#endif
return true;
}
#ifdef DEBUG_SERIAL
DEBUG_SERIAL.println(F(" Not detected"));
#endif
return false;
}
/*!
* @brief Write a buffer or two to the I2C device. Cannot be more than
* maxBufferSize() bytes.
* @param buffer Pointer to buffer of data to write. This is const to
* ensure the content of this buffer doesn't change.
* @param len Number of bytes from buffer to write
* @param prefix_buffer Pointer to optional array of data to write before
* buffer. Cannot be more than maxBufferSize() bytes. This is const to
* ensure the content of this buffer doesn't change.
* @param prefix_len Number of bytes from prefix buffer to write
* @param stop Whether to send an I2C STOP signal on write
* @return True if write was successful, otherwise false.
*/
bool Adafruit_I2CDevice::write(const uint8_t *buffer, size_t len, bool stop,
const uint8_t *prefix_buffer,
size_t prefix_len) {
if ((len + prefix_len) > maxBufferSize()) {
// currently not guaranteed to work if more than 32 bytes!
// we will need to find out if some platforms have larger
// I2C buffer sizes :/
#ifdef DEBUG_SERIAL
DEBUG_SERIAL.println(F("\tI2CDevice could not write such a large buffer"));
#endif
return false;
}
_wire->beginTransmission(_addr);
// Write the prefix data (usually an address)
if ((prefix_len != 0) && (prefix_buffer != nullptr)) {
if (_wire->write(prefix_buffer, prefix_len) != prefix_len) {
#ifdef DEBUG_SERIAL
DEBUG_SERIAL.println(F("\tI2CDevice failed to write"));
#endif
return false;
}
}
// Write the data itself
if (_wire->write(buffer, len) != len) {
#ifdef DEBUG_SERIAL
DEBUG_SERIAL.println(F("\tI2CDevice failed to write"));
#endif
return false;
}
#ifdef DEBUG_SERIAL
DEBUG_SERIAL.print(F("\tI2CWRITE @ 0x"));
DEBUG_SERIAL.print(_addr, HEX);
DEBUG_SERIAL.print(F(" :: "));
if ((prefix_len != 0) && (prefix_buffer != nullptr)) {
for (uint16_t i = 0; i < prefix_len; i++) {
DEBUG_SERIAL.print(F("0x"));
DEBUG_SERIAL.print(prefix_buffer[i], HEX);
DEBUG_SERIAL.print(F(", "));
}
}
for (uint16_t i = 0; i < len; i++) {
DEBUG_SERIAL.print(F("0x"));
DEBUG_SERIAL.print(buffer[i], HEX);
DEBUG_SERIAL.print(F(", "));
if (i % 32 == 31) {
DEBUG_SERIAL.println();
}
}
if (stop) {
DEBUG_SERIAL.print("\tSTOP");
}
#endif
if (_wire->endTransmission(stop) == 0) {
#ifdef DEBUG_SERIAL
DEBUG_SERIAL.println();
// DEBUG_SERIAL.println("Sent!");
#endif
return true;
} else {
#ifdef DEBUG_SERIAL
DEBUG_SERIAL.println("\tFailed to send!");
#endif
return false;
}
}
/*!
* @brief Read from I2C into a buffer from the I2C device.
* Cannot be more than maxBufferSize() bytes.
* @param buffer Pointer to buffer of data to read into
* @param len Number of bytes from buffer to read.
* @param stop Whether to send an I2C STOP signal on read
* @return True if read was successful, otherwise false.
*/
bool Adafruit_I2CDevice::read(uint8_t *buffer, size_t len, bool stop) {
size_t pos = 0;
while (pos < len) {
size_t read_len =
((len - pos) > maxBufferSize()) ? maxBufferSize() : (len - pos);
bool read_stop = (pos < (len - read_len)) ? false : stop;
if (!_read(buffer + pos, read_len, read_stop))
return false;
pos += read_len;
}
return true;
}
bool Adafruit_I2CDevice::_read(uint8_t *buffer, size_t len, bool stop) {
#if defined(TinyWireM_h)
size_t recv = _wire->requestFrom((uint8_t)_addr, (uint8_t)len);
#elif defined(ARDUINO_ARCH_MEGAAVR)
size_t recv = _wire->requestFrom(_addr, len, stop);
#else
size_t recv = _wire->requestFrom((uint8_t)_addr, (uint8_t)len, (uint8_t)stop);
#endif
if (recv != len) {
// Not enough data available to fulfill our obligation!
#ifdef DEBUG_SERIAL
DEBUG_SERIAL.print(F("\tI2CDevice did not receive enough data: "));
DEBUG_SERIAL.println(recv);
#endif
return false;
}
for (uint16_t i = 0; i < len; i++) {
buffer[i] = _wire->read();
}
#ifdef DEBUG_SERIAL
DEBUG_SERIAL.print(F("\tI2CREAD @ 0x"));
DEBUG_SERIAL.print(_addr, HEX);
DEBUG_SERIAL.print(F(" :: "));
for (uint16_t i = 0; i < len; i++) {
DEBUG_SERIAL.print(F("0x"));
DEBUG_SERIAL.print(buffer[i], HEX);
DEBUG_SERIAL.print(F(", "));
if (len % 32 == 31) {
DEBUG_SERIAL.println();
}
}
DEBUG_SERIAL.println();
#endif
return true;
}
/*!
* @brief Write some data, then read some data from I2C into another buffer.
* Cannot be more than maxBufferSize() bytes. The buffers can point to
* same/overlapping locations.
* @param write_buffer Pointer to buffer of data to write from
* @param write_len Number of bytes from buffer to write.
* @param read_buffer Pointer to buffer of data to read into.
* @param read_len Number of bytes from buffer to read.
* @param stop Whether to send an I2C STOP signal between the write and read
* @return True if write & read was successful, otherwise false.
*/
bool Adafruit_I2CDevice::write_then_read(const uint8_t *write_buffer,
size_t write_len, uint8_t *read_buffer,
size_t read_len, bool stop) {
if (!write(write_buffer, write_len, stop)) {
return false;
}
return read(read_buffer, read_len);
}
/*!
* @brief Returns the 7-bit address of this device
* @return The 7-bit address of this device
*/
uint8_t Adafruit_I2CDevice::address(void) { return _addr; }
/*!
* @brief Change the I2C clock speed to desired (relies on
* underlying Wire support!
* @param desiredclk The desired I2C SCL frequency
* @return True if this platform supports changing I2C speed.
* Not necessarily that the speed was achieved!
*/
bool Adafruit_I2CDevice::setSpeed(uint32_t desiredclk) {
#if defined(__AVR_ATmega328__) || \
defined(__AVR_ATmega328P__) // fix arduino core set clock
// calculate TWBR correctly
if ((F_CPU / 18) < desiredclk) {
#ifdef DEBUG_SERIAL
Serial.println(F("I2C.setSpeed too high."));
#endif
return false;
}
uint32_t atwbr = ((F_CPU / desiredclk) - 16) / 2;
if (atwbr > 16320) {
#ifdef DEBUG_SERIAL
Serial.println(F("I2C.setSpeed too low."));
#endif
return false;
}
if (atwbr <= 255) {
atwbr /= 1;
TWSR = 0x0;
} else if (atwbr <= 1020) {
atwbr /= 4;
TWSR = 0x1;
} else if (atwbr <= 4080) {
atwbr /= 16;
TWSR = 0x2;
} else { // if (atwbr <= 16320)
atwbr /= 64;
TWSR = 0x3;
}
TWBR = atwbr;
#ifdef DEBUG_SERIAL
Serial.print(F("TWSR prescaler = "));
Serial.println(pow(4, TWSR));
Serial.print(F("TWBR = "));
Serial.println(atwbr);
#endif
return true;
#elif (ARDUINO >= 157) && !defined(ARDUINO_STM32_FEATHER) && \
!defined(TinyWireM_h)
_wire->setClock(desiredclk);
return true;
#else
(void)desiredclk;
return false;
#endif
}

View File

@@ -0,0 +1,36 @@
#ifndef Adafruit_I2CDevice_h
#define Adafruit_I2CDevice_h
#include <Arduino.h>
#include <Wire.h>
///< The class which defines how we will talk to this device over I2C
class Adafruit_I2CDevice {
public:
Adafruit_I2CDevice(uint8_t addr, TwoWire *theWire = &Wire);
uint8_t address(void);
bool begin(bool addr_detect = true);
void end(void);
bool detected(void);
bool read(uint8_t *buffer, size_t len, bool stop = true);
bool write(const uint8_t *buffer, size_t len, bool stop = true,
const uint8_t *prefix_buffer = nullptr, size_t prefix_len = 0);
bool write_then_read(const uint8_t *write_buffer, size_t write_len,
uint8_t *read_buffer, size_t read_len,
bool stop = false);
bool setSpeed(uint32_t desiredclk);
/*! @brief How many bytes we can read in a transaction
* @return The size of the Wire receive/transmit buffer */
size_t maxBufferSize() { return _maxBufferSize; }
private:
uint8_t _addr;
TwoWire *_wire;
bool _begun;
size_t _maxBufferSize;
bool _read(uint8_t *buffer, size_t len, bool stop);
};
#endif // Adafruit_I2CDevice_h

View File

@@ -0,0 +1,10 @@
#ifndef _ADAFRUIT_I2C_REGISTER_H_
#define _ADAFRUIT_I2C_REGISTER_H_
#include <Adafruit_BusIO_Register.h>
#include <Arduino.h>
typedef Adafruit_BusIO_Register Adafruit_I2CRegister;
typedef Adafruit_BusIO_RegisterBits Adafruit_I2CRegisterBits;
#endif

View File

@@ -0,0 +1,508 @@
#include "Adafruit_SPIDevice.h"
//#define DEBUG_SERIAL Serial
/*!
* @brief Create an SPI device with the given CS pin and settings
* @param cspin The arduino pin number to use for chip select
* @param freq The SPI clock frequency to use, defaults to 1MHz
* @param dataOrder The SPI data order to use for bits within each byte,
* defaults to SPI_BITORDER_MSBFIRST
* @param dataMode The SPI mode to use, defaults to SPI_MODE0
* @param theSPI The SPI bus to use, defaults to &theSPI
*/
Adafruit_SPIDevice::Adafruit_SPIDevice(int8_t cspin, uint32_t freq,
BusIOBitOrder dataOrder,
uint8_t dataMode, SPIClass *theSPI) {
#ifdef BUSIO_HAS_HW_SPI
_cs = cspin;
_sck = _mosi = _miso = -1;
_spi = theSPI;
_begun = false;
_spiSetting = new SPISettings(freq, dataOrder, dataMode);
_freq = freq;
_dataOrder = dataOrder;
_dataMode = dataMode;
#else
// unused, but needed to suppress compiler warns
(void)cspin;
(void)freq;
(void)dataOrder;
(void)dataMode;
(void)theSPI;
#endif
}
/*!
* @brief Create an SPI device with the given CS pin and settings
* @param cspin The arduino pin number to use for chip select
* @param sckpin The arduino pin number to use for SCK
* @param misopin The arduino pin number to use for MISO, set to -1 if not
* used
* @param mosipin The arduino pin number to use for MOSI, set to -1 if not
* used
* @param freq The SPI clock frequency to use, defaults to 1MHz
* @param dataOrder The SPI data order to use for bits within each byte,
* defaults to SPI_BITORDER_MSBFIRST
* @param dataMode The SPI mode to use, defaults to SPI_MODE0
*/
Adafruit_SPIDevice::Adafruit_SPIDevice(int8_t cspin, int8_t sckpin,
int8_t misopin, int8_t mosipin,
uint32_t freq, BusIOBitOrder dataOrder,
uint8_t dataMode) {
_cs = cspin;
_sck = sckpin;
_miso = misopin;
_mosi = mosipin;
#ifdef BUSIO_USE_FAST_PINIO
csPort = (BusIO_PortReg *)portOutputRegister(digitalPinToPort(cspin));
csPinMask = digitalPinToBitMask(cspin);
if (mosipin != -1) {
mosiPort = (BusIO_PortReg *)portOutputRegister(digitalPinToPort(mosipin));
mosiPinMask = digitalPinToBitMask(mosipin);
}
if (misopin != -1) {
misoPort = (BusIO_PortReg *)portInputRegister(digitalPinToPort(misopin));
misoPinMask = digitalPinToBitMask(misopin);
}
clkPort = (BusIO_PortReg *)portOutputRegister(digitalPinToPort(sckpin));
clkPinMask = digitalPinToBitMask(sckpin);
#endif
_freq = freq;
_dataOrder = dataOrder;
_dataMode = dataMode;
_begun = false;
}
/*!
* @brief Release memory allocated in constructors
*/
Adafruit_SPIDevice::~Adafruit_SPIDevice() {
if (_spiSetting)
delete _spiSetting;
}
/*!
* @brief Initializes SPI bus and sets CS pin high
* @return Always returns true because there's no way to test success of SPI
* init
*/
bool Adafruit_SPIDevice::begin(void) {
if (_cs != -1) {
pinMode(_cs, OUTPUT);
digitalWrite(_cs, HIGH);
}
if (_spi) { // hardware SPI
#ifdef BUSIO_HAS_HW_SPI
_spi->begin();
#endif
} else {
pinMode(_sck, OUTPUT);
if ((_dataMode == SPI_MODE0) || (_dataMode == SPI_MODE1)) {
// idle low on mode 0 and 1
digitalWrite(_sck, LOW);
} else {
// idle high on mode 2 or 3
digitalWrite(_sck, HIGH);
}
if (_mosi != -1) {
pinMode(_mosi, OUTPUT);
digitalWrite(_mosi, HIGH);
}
if (_miso != -1) {
pinMode(_miso, INPUT);
}
}
_begun = true;
return true;
}
/*!
* @brief Transfer (send/receive) a buffer over hard/soft SPI, without
* transaction management
* @param buffer The buffer to send and receive at the same time
* @param len The number of bytes to transfer
*/
void Adafruit_SPIDevice::transfer(uint8_t *buffer, size_t len) {
//
// HARDWARE SPI
//
if (_spi) {
#ifdef BUSIO_HAS_HW_SPI
#if defined(SPARK)
_spi->transfer(buffer, buffer, len, nullptr);
#elif defined(STM32)
for (size_t i = 0; i < len; i++) {
_spi->transfer(buffer[i]);
}
#else
_spi->transfer(buffer, len);
#endif
return;
#endif
}
//
// SOFTWARE SPI
//
uint8_t startbit;
if (_dataOrder == SPI_BITORDER_LSBFIRST) {
startbit = 0x1;
} else {
startbit = 0x80;
}
bool towrite, lastmosi = !(buffer[0] & startbit);
uint8_t bitdelay_us = (1000000 / _freq) / 2;
for (size_t i = 0; i < len; i++) {
uint8_t reply = 0;
uint8_t send = buffer[i];
/*
Serial.print("\tSending software SPI byte 0x");
Serial.print(send, HEX);
Serial.print(" -> 0x");
*/
// Serial.print(send, HEX);
for (uint8_t b = startbit; b != 0;
b = (_dataOrder == SPI_BITORDER_LSBFIRST) ? b << 1 : b >> 1) {
if (bitdelay_us) {
delayMicroseconds(bitdelay_us);
}
if (_dataMode == SPI_MODE0 || _dataMode == SPI_MODE2) {
towrite = send & b;
if ((_mosi != -1) && (lastmosi != towrite)) {
#ifdef BUSIO_USE_FAST_PINIO
if (towrite)
*mosiPort = *mosiPort | mosiPinMask;
else
*mosiPort = *mosiPort & ~mosiPinMask;
#else
digitalWrite(_mosi, towrite);
#endif
lastmosi = towrite;
}
#ifdef BUSIO_USE_FAST_PINIO
*clkPort = *clkPort | clkPinMask; // Clock high
#else
digitalWrite(_sck, HIGH);
#endif
if (bitdelay_us) {
delayMicroseconds(bitdelay_us);
}
if (_miso != -1) {
#ifdef BUSIO_USE_FAST_PINIO
if (*misoPort & misoPinMask) {
#else
if (digitalRead(_miso)) {
#endif
reply |= b;
}
}
#ifdef BUSIO_USE_FAST_PINIO
*clkPort = *clkPort & ~clkPinMask; // Clock low
#else
digitalWrite(_sck, LOW);
#endif
} else { // if (_dataMode == SPI_MODE1 || _dataMode == SPI_MODE3)
#ifdef BUSIO_USE_FAST_PINIO
*clkPort = *clkPort | clkPinMask; // Clock high
#else
digitalWrite(_sck, HIGH);
#endif
if (bitdelay_us) {
delayMicroseconds(bitdelay_us);
}
if (_mosi != -1) {
#ifdef BUSIO_USE_FAST_PINIO
if (send & b)
*mosiPort = *mosiPort | mosiPinMask;
else
*mosiPort = *mosiPort & ~mosiPinMask;
#else
digitalWrite(_mosi, send & b);
#endif
}
#ifdef BUSIO_USE_FAST_PINIO
*clkPort = *clkPort & ~clkPinMask; // Clock low
#else
digitalWrite(_sck, LOW);
#endif
if (_miso != -1) {
#ifdef BUSIO_USE_FAST_PINIO
if (*misoPort & misoPinMask) {
#else
if (digitalRead(_miso)) {
#endif
reply |= b;
}
}
}
if (_miso != -1) {
buffer[i] = reply;
}
}
}
return;
}
/*!
* @brief Transfer (send/receive) one byte over hard/soft SPI, without
* transaction management
* @param send The byte to send
* @return The byte received while transmitting
*/
uint8_t Adafruit_SPIDevice::transfer(uint8_t send) {
uint8_t data = send;
transfer(&data, 1);
return data;
}
/*!
* @brief Manually begin a transaction (calls beginTransaction if hardware
* SPI)
*/
void Adafruit_SPIDevice::beginTransaction(void) {
if (_spi) {
#ifdef BUSIO_HAS_HW_SPI
_spi->beginTransaction(*_spiSetting);
#endif
}
}
/*!
* @brief Manually end a transaction (calls endTransaction if hardware SPI)
*/
void Adafruit_SPIDevice::endTransaction(void) {
if (_spi) {
#ifdef BUSIO_HAS_HW_SPI
_spi->endTransaction();
#endif
}
}
/*!
* @brief Assert/Deassert the CS pin if it is defined
* @param value The state the CS is set to
*/
void Adafruit_SPIDevice::setChipSelect(int value) {
if (_cs != -1) {
digitalWrite(_cs, value);
}
}
/*!
* @brief Write a buffer or two to the SPI device, with transaction
* management.
* @brief Manually begin a transaction (calls beginTransaction if hardware
* SPI) with asserting the CS pin
*/
void Adafruit_SPIDevice::beginTransactionWithAssertingCS() {
beginTransaction();
setChipSelect(LOW);
}
/*!
* @brief Manually end a transaction (calls endTransaction if hardware SPI)
* with deasserting the CS pin
*/
void Adafruit_SPIDevice::endTransactionWithDeassertingCS() {
setChipSelect(HIGH);
endTransaction();
}
/*!
* @brief Write a buffer or two to the SPI device, with transaction
* management.
* @param buffer Pointer to buffer of data to write
* @param len Number of bytes from buffer to write
* @param prefix_buffer Pointer to optional array of data to write before
* buffer.
* @param prefix_len Number of bytes from prefix buffer to write
* @return Always returns true because there's no way to test success of SPI
* writes
*/
bool Adafruit_SPIDevice::write(const uint8_t *buffer, size_t len,
const uint8_t *prefix_buffer,
size_t prefix_len) {
beginTransactionWithAssertingCS();
// do the writing
#if defined(ARDUINO_ARCH_ESP32)
if (_spi) {
if (prefix_len > 0) {
_spi->transferBytes((uint8_t *)prefix_buffer, nullptr, prefix_len);
}
if (len > 0) {
_spi->transferBytes((uint8_t *)buffer, nullptr, len);
}
} else
#endif
{
for (size_t i = 0; i < prefix_len; i++) {
transfer(prefix_buffer[i]);
}
for (size_t i = 0; i < len; i++) {
transfer(buffer[i]);
}
}
endTransactionWithDeassertingCS();
#ifdef DEBUG_SERIAL
DEBUG_SERIAL.print(F("\tSPIDevice Wrote: "));
if ((prefix_len != 0) && (prefix_buffer != nullptr)) {
for (uint16_t i = 0; i < prefix_len; i++) {
DEBUG_SERIAL.print(F("0x"));
DEBUG_SERIAL.print(prefix_buffer[i], HEX);
DEBUG_SERIAL.print(F(", "));
}
}
for (uint16_t i = 0; i < len; i++) {
DEBUG_SERIAL.print(F("0x"));
DEBUG_SERIAL.print(buffer[i], HEX);
DEBUG_SERIAL.print(F(", "));
if (i % 32 == 31) {
DEBUG_SERIAL.println();
}
}
DEBUG_SERIAL.println();
#endif
return true;
}
/*!
* @brief Read from SPI into a buffer from the SPI device, with transaction
* management.
* @param buffer Pointer to buffer of data to read into
* @param len Number of bytes from buffer to read.
* @param sendvalue The 8-bits of data to write when doing the data read,
* defaults to 0xFF
* @return Always returns true because there's no way to test success of SPI
* writes
*/
bool Adafruit_SPIDevice::read(uint8_t *buffer, size_t len, uint8_t sendvalue) {
memset(buffer, sendvalue, len); // clear out existing buffer
beginTransactionWithAssertingCS();
transfer(buffer, len);
endTransactionWithDeassertingCS();
#ifdef DEBUG_SERIAL
DEBUG_SERIAL.print(F("\tSPIDevice Read: "));
for (uint16_t i = 0; i < len; i++) {
DEBUG_SERIAL.print(F("0x"));
DEBUG_SERIAL.print(buffer[i], HEX);
DEBUG_SERIAL.print(F(", "));
if (len % 32 == 31) {
DEBUG_SERIAL.println();
}
}
DEBUG_SERIAL.println();
#endif
return true;
}
/*!
* @brief Write some data, then read some data from SPI into another buffer,
* with transaction management. The buffers can point to same/overlapping
* locations. This does not transmit-receive at the same time!
* @param write_buffer Pointer to buffer of data to write from
* @param write_len Number of bytes from buffer to write.
* @param read_buffer Pointer to buffer of data to read into.
* @param read_len Number of bytes from buffer to read.
* @param sendvalue The 8-bits of data to write when doing the data read,
* defaults to 0xFF
* @return Always returns true because there's no way to test success of SPI
* writes
*/
bool Adafruit_SPIDevice::write_then_read(const uint8_t *write_buffer,
size_t write_len, uint8_t *read_buffer,
size_t read_len, uint8_t sendvalue) {
beginTransactionWithAssertingCS();
// do the writing
#if defined(ARDUINO_ARCH_ESP32)
if (_spi) {
if (write_len > 0) {
_spi->transferBytes((uint8_t *)write_buffer, nullptr, write_len);
}
} else
#endif
{
for (size_t i = 0; i < write_len; i++) {
transfer(write_buffer[i]);
}
}
#ifdef DEBUG_SERIAL
DEBUG_SERIAL.print(F("\tSPIDevice Wrote: "));
for (uint16_t i = 0; i < write_len; i++) {
DEBUG_SERIAL.print(F("0x"));
DEBUG_SERIAL.print(write_buffer[i], HEX);
DEBUG_SERIAL.print(F(", "));
if (write_len % 32 == 31) {
DEBUG_SERIAL.println();
}
}
DEBUG_SERIAL.println();
#endif
// do the reading
for (size_t i = 0; i < read_len; i++) {
read_buffer[i] = transfer(sendvalue);
}
#ifdef DEBUG_SERIAL
DEBUG_SERIAL.print(F("\tSPIDevice Read: "));
for (uint16_t i = 0; i < read_len; i++) {
DEBUG_SERIAL.print(F("0x"));
DEBUG_SERIAL.print(read_buffer[i], HEX);
DEBUG_SERIAL.print(F(", "));
if (read_len % 32 == 31) {
DEBUG_SERIAL.println();
}
}
DEBUG_SERIAL.println();
#endif
endTransactionWithDeassertingCS();
return true;
}
/*!
* @brief Write some data and read some data at the same time from SPI
* into the same buffer, with transaction management. This is basicaly a wrapper
* for transfer() with CS-pin and transaction management. This /does/
* transmit-receive at the same time!
* @param buffer Pointer to buffer of data to write/read to/from
* @param len Number of bytes from buffer to write/read.
* @return Always returns true because there's no way to test success of SPI
* writes
*/
bool Adafruit_SPIDevice::write_and_read(uint8_t *buffer, size_t len) {
beginTransactionWithAssertingCS();
transfer(buffer, len);
endTransactionWithDeassertingCS();
return true;
}

View File

@@ -0,0 +1,144 @@
#ifndef Adafruit_SPIDevice_h
#define Adafruit_SPIDevice_h
#include <Arduino.h>
#if !defined(SPI_INTERFACES_COUNT) || \
(defined(SPI_INTERFACES_COUNT) && (SPI_INTERFACES_COUNT > 0))
// HW SPI available
#include <SPI.h>
#define BUSIO_HAS_HW_SPI
#else
// SW SPI ONLY
enum { SPI_MODE0, SPI_MODE1, SPI_MODE2, _SPI_MODE4 };
typedef uint8_t SPIClass;
#endif
// some modern SPI definitions don't have BitOrder enum
#if (defined(__AVR__) && !defined(ARDUINO_ARCH_MEGAAVR)) || \
defined(ESP8266) || defined(TEENSYDUINO) || defined(SPARK) || \
defined(ARDUINO_ARCH_SPRESENSE) || defined(MEGATINYCORE) || \
defined(DXCORE) || defined(ARDUINO_AVR_ATmega4809) || \
defined(ARDUINO_AVR_ATmega4808) || defined(ARDUINO_AVR_ATmega3209) || \
defined(ARDUINO_AVR_ATmega3208) || defined(ARDUINO_AVR_ATmega1609) || \
defined(ARDUINO_AVR_ATmega1608) || defined(ARDUINO_AVR_ATmega809) || \
defined(ARDUINO_AVR_ATmega808) || defined(ARDUINO_ARCH_ARC32) || \
defined(ARDUINO_ARCH_XMC)
typedef enum _BitOrder {
SPI_BITORDER_MSBFIRST = MSBFIRST,
SPI_BITORDER_LSBFIRST = LSBFIRST,
} BusIOBitOrder;
#elif defined(ESP32) || defined(__ASR6501__) || defined(__ASR6502__)
// some modern SPI definitions don't have BitOrder enum and have different SPI
// mode defines
typedef enum _BitOrder {
SPI_BITORDER_MSBFIRST = SPI_MSBFIRST,
SPI_BITORDER_LSBFIRST = SPI_LSBFIRST,
} BusIOBitOrder;
#else
// Some platforms have a BitOrder enum but its named MSBFIRST/LSBFIRST
#define SPI_BITORDER_MSBFIRST MSBFIRST
#define SPI_BITORDER_LSBFIRST LSBFIRST
typedef BitOrder BusIOBitOrder;
#endif
#if defined(__IMXRT1062__) // Teensy 4.x
// *Warning* I disabled the usage of FAST_PINIO as the set/clear operations
// used in the cpp file are not atomic and can effect multiple IO pins
// and if an interrupt happens in between the time the code reads the register
// and writes out the updated value, that changes one or more other IO pins
// on that same IO port, those change will be clobbered when the updated
// values are written back. A fast version can be implemented that uses the
// ports set and clear registers which are atomic.
// typedef volatile uint32_t BusIO_PortReg;
// typedef uint32_t BusIO_PortMask;
//#define BUSIO_USE_FAST_PINIO
#elif defined(ARDUINO_ARCH_XMC)
#undef BUSIO_USE_FAST_PINIO
#elif defined(__AVR__) || defined(TEENSYDUINO)
typedef volatile uint8_t BusIO_PortReg;
typedef uint8_t BusIO_PortMask;
#define BUSIO_USE_FAST_PINIO
#elif defined(ESP8266) || defined(ESP32) || defined(__SAM3X8E__) || \
defined(ARDUINO_ARCH_SAMD)
typedef volatile uint32_t BusIO_PortReg;
typedef uint32_t BusIO_PortMask;
#define BUSIO_USE_FAST_PINIO
#elif (defined(__arm__) || defined(ARDUINO_FEATHER52)) && \
!defined(ARDUINO_ARCH_MBED) && !defined(ARDUINO_ARCH_RP2040) && \
!defined(ARDUINO_SILABS) && !defined(ARDUINO_UNOR4_MINIMA) && \
!defined(ARDUINO_UNOR4_WIFI)
typedef volatile uint32_t BusIO_PortReg;
typedef uint32_t BusIO_PortMask;
#if !defined(__ASR6501__) && !defined(__ASR6502__)
#define BUSIO_USE_FAST_PINIO
#endif
#else
#undef BUSIO_USE_FAST_PINIO
#endif
/**! The class which defines how we will talk to this device over SPI **/
class Adafruit_SPIDevice {
public:
#ifdef BUSIO_HAS_HW_SPI
Adafruit_SPIDevice(int8_t cspin, uint32_t freq = 1000000,
BusIOBitOrder dataOrder = SPI_BITORDER_MSBFIRST,
uint8_t dataMode = SPI_MODE0, SPIClass *theSPI = &SPI);
#else
Adafruit_SPIDevice(int8_t cspin, uint32_t freq = 1000000,
BusIOBitOrder dataOrder = SPI_BITORDER_MSBFIRST,
uint8_t dataMode = SPI_MODE0, SPIClass *theSPI = nullptr);
#endif
Adafruit_SPIDevice(int8_t cspin, int8_t sck, int8_t miso, int8_t mosi,
uint32_t freq = 1000000,
BusIOBitOrder dataOrder = SPI_BITORDER_MSBFIRST,
uint8_t dataMode = SPI_MODE0);
~Adafruit_SPIDevice();
bool begin(void);
bool read(uint8_t *buffer, size_t len, uint8_t sendvalue = 0xFF);
bool write(const uint8_t *buffer, size_t len,
const uint8_t *prefix_buffer = nullptr, size_t prefix_len = 0);
bool write_then_read(const uint8_t *write_buffer, size_t write_len,
uint8_t *read_buffer, size_t read_len,
uint8_t sendvalue = 0xFF);
bool write_and_read(uint8_t *buffer, size_t len);
uint8_t transfer(uint8_t send);
void transfer(uint8_t *buffer, size_t len);
void beginTransaction(void);
void endTransaction(void);
void beginTransactionWithAssertingCS();
void endTransactionWithDeassertingCS();
private:
#ifdef BUSIO_HAS_HW_SPI
SPIClass *_spi = nullptr;
SPISettings *_spiSetting = nullptr;
#else
uint8_t *_spi = nullptr;
uint8_t *_spiSetting = nullptr;
#endif
uint32_t _freq;
BusIOBitOrder _dataOrder;
uint8_t _dataMode;
void setChipSelect(int value);
int8_t _cs, _sck, _mosi, _miso;
#ifdef BUSIO_USE_FAST_PINIO
BusIO_PortReg *mosiPort, *clkPort, *misoPort, *csPort;
BusIO_PortMask mosiPinMask, misoPinMask, clkPinMask, csPinMask;
#endif
bool _begun;
};
#endif // Adafruit_SPIDevice_h

View File

@@ -0,0 +1,11 @@
# Adafruit Bus IO Library
# https://github.com/adafruit/Adafruit_BusIO
# MIT License
cmake_minimum_required(VERSION 3.5)
idf_component_register(SRCS "Adafruit_I2CDevice.cpp" "Adafruit_BusIO_Register.cpp" "Adafruit_SPIDevice.cpp"
INCLUDE_DIRS "."
REQUIRES arduino)
project(Adafruit_BusIO)

View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2017 Adafruit Industries
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,8 @@
# Adafruit Bus IO Library [![Build Status](https://github.com/adafruit/Adafruit_BusIO/workflows/Arduino%20Library%20CI/badge.svg)](https://github.com/adafruit/Adafruit_BusIO/actions)
This is a helper library to abstract away I2C & SPI transactions and registers
Adafruit invests time and resources providing this open source code, please support Adafruit and open-source hardware by purchasing products from Adafruit!
MIT license, all text above must be included in any redistribution

View File

@@ -0,0 +1 @@
COMPONENT_ADD_INCLUDEDIRS = .

View File

@@ -0,0 +1,21 @@
#include <Adafruit_I2CDevice.h>
Adafruit_I2CDevice i2c_dev = Adafruit_I2CDevice(0x10);
void setup() {
while (!Serial) { delay(10); }
Serial.begin(115200);
Serial.println("I2C address detection test");
if (!i2c_dev.begin()) {
Serial.print("Did not find device at 0x");
Serial.println(i2c_dev.address(), HEX);
while (1);
}
Serial.print("Device found on address 0x");
Serial.println(i2c_dev.address(), HEX);
}
void loop() {
}

View File

@@ -0,0 +1,41 @@
#include <Adafruit_I2CDevice.h>
#define I2C_ADDRESS 0x60
Adafruit_I2CDevice i2c_dev = Adafruit_I2CDevice(I2C_ADDRESS);
void setup() {
while (!Serial) { delay(10); }
Serial.begin(115200);
Serial.println("I2C device read and write test");
if (!i2c_dev.begin()) {
Serial.print("Did not find device at 0x");
Serial.println(i2c_dev.address(), HEX);
while (1);
}
Serial.print("Device found on address 0x");
Serial.println(i2c_dev.address(), HEX);
uint8_t buffer[32];
// Try to read 32 bytes
i2c_dev.read(buffer, 32);
Serial.print("Read: ");
for (uint8_t i=0; i<32; i++) {
Serial.print("0x"); Serial.print(buffer[i], HEX); Serial.print(", ");
}
Serial.println();
// read a register by writing first, then reading
buffer[0] = 0x0C; // we'll reuse the same buffer
i2c_dev.write_then_read(buffer, 1, buffer, 2, false);
Serial.print("Write then Read: ");
for (uint8_t i=0; i<2; i++) {
Serial.print("0x"); Serial.print(buffer[i], HEX); Serial.print(", ");
}
Serial.println();
}
void loop() {
}

View File

@@ -0,0 +1,38 @@
#include <Adafruit_I2CDevice.h>
#include <Adafruit_BusIO_Register.h>
#define I2C_ADDRESS 0x60
Adafruit_I2CDevice i2c_dev = Adafruit_I2CDevice(I2C_ADDRESS);
void setup() {
while (!Serial) { delay(10); }
Serial.begin(115200);
Serial.println("I2C device register test");
if (!i2c_dev.begin()) {
Serial.print("Did not find device at 0x");
Serial.println(i2c_dev.address(), HEX);
while (1);
}
Serial.print("Device found on address 0x");
Serial.println(i2c_dev.address(), HEX);
Adafruit_BusIO_Register id_reg = Adafruit_BusIO_Register(&i2c_dev, 0x0C, 2, LSBFIRST);
uint16_t id;
id_reg.read(&id);
Serial.print("ID register = 0x"); Serial.println(id, HEX);
Adafruit_BusIO_Register thresh_reg = Adafruit_BusIO_Register(&i2c_dev, 0x01, 2, LSBFIRST);
uint16_t thresh;
thresh_reg.read(&thresh);
Serial.print("Initial threshold register = 0x"); Serial.println(thresh, HEX);
thresh_reg.write(~thresh);
Serial.print("Post threshold register = 0x"); Serial.println(thresh_reg.read(), HEX);
}
void loop() {
}

View File

@@ -0,0 +1,38 @@
#include <Adafruit_BusIO_Register.h>
// Define which interface to use by setting the unused interface to NULL!
#define SPIDEVICE_CS 10
Adafruit_SPIDevice *spi_dev = NULL; // new Adafruit_SPIDevice(SPIDEVICE_CS);
#define I2C_ADDRESS 0x5D
Adafruit_I2CDevice *i2c_dev = new Adafruit_I2CDevice(I2C_ADDRESS);
void setup() {
while (!Serial) { delay(10); }
Serial.begin(115200);
Serial.println("I2C or SPI device register test");
if (spi_dev && !spi_dev->begin()) {
Serial.println("Could not initialize SPI device");
}
if (i2c_dev) {
if (i2c_dev->begin()) {
Serial.print("Device found on I2C address 0x");
Serial.println(i2c_dev->address(), HEX);
} else {
Serial.print("Did not find I2C device at 0x");
Serial.println(i2c_dev->address(), HEX);
}
}
Adafruit_BusIO_Register id_reg = Adafruit_BusIO_Register(i2c_dev, spi_dev, ADDRBIT8_HIGH_TOREAD, 0x0F);
uint8_t id=0;
id_reg.read(&id);
Serial.print("ID register = 0x"); Serial.println(id, HEX);
}
void loop() {
}

View File

@@ -0,0 +1,29 @@
#include <Adafruit_SPIDevice.h>
#define SPIDEVICE_CS 10
Adafruit_SPIDevice spi_dev = Adafruit_SPIDevice(SPIDEVICE_CS, 100000, SPI_BITORDER_MSBFIRST, SPI_MODE1);
//Adafruit_SPIDevice spi_dev = Adafruit_SPIDevice(SPIDEVICE_CS, 13, 12, 11, 100000, SPI_BITORDER_MSBFIRST, SPI_MODE1);
void setup() {
while (!Serial) { delay(10); }
Serial.begin(115200);
Serial.println("SPI device mode test");
if (!spi_dev.begin()) {
Serial.println("Could not initialize SPI device");
while (1);
}
}
void loop() {
Serial.println("\n\nTransfer test");
for (uint16_t x=0; x<=0xFF; x++) {
uint8_t i = x;
Serial.print("0x"); Serial.print(i, HEX);
spi_dev.read(&i, 1, i);
Serial.print("/"); Serial.print(i, HEX);
Serial.print(", ");
delay(25);
}
}

View File

@@ -0,0 +1,39 @@
#include <Adafruit_SPIDevice.h>
#define SPIDEVICE_CS 10
Adafruit_SPIDevice spi_dev = Adafruit_SPIDevice(SPIDEVICE_CS);
void setup() {
while (!Serial) { delay(10); }
Serial.begin(115200);
Serial.println("SPI device read and write test");
if (!spi_dev.begin()) {
Serial.println("Could not initialize SPI device");
while (1);
}
uint8_t buffer[32];
// Try to read 32 bytes
spi_dev.read(buffer, 32);
Serial.print("Read: ");
for (uint8_t i=0; i<32; i++) {
Serial.print("0x"); Serial.print(buffer[i], HEX); Serial.print(", ");
}
Serial.println();
// read a register by writing first, then reading
buffer[0] = 0x8F; // we'll reuse the same buffer
spi_dev.write_then_read(buffer, 1, buffer, 2, false);
Serial.print("Write then Read: ");
for (uint8_t i=0; i<2; i++) {
Serial.print("0x"); Serial.print(buffer[i], HEX); Serial.print(", ");
}
Serial.println();
}
void loop() {
}

View File

@@ -0,0 +1,192 @@
/***************************************************
This is an example for how to use Adafruit_BusIO_RegisterBits from Adafruit_BusIO library.
Designed specifically to work with the Adafruit RTD Sensor
----> https://www.adafruit.com/products/3328
uisng a MAX31865 RTD-to-Digital Converter
----> https://datasheets.maximintegrated.com/en/ds/MAX31865.pdf
This sensor uses SPI to communicate, 4 pins are required to
interface.
A fifth pin helps to detect when a new conversion is ready.
Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!
Example written (2020/3) by Andreas Hardtung/AnHard.
BSD license, all text above must be included in any redistribution
****************************************************/
#include <Adafruit_BusIO_Register.h>
#include <Adafruit_SPIDevice.h>
#define MAX31865_SPI_SPEED (5000000)
#define MAX31865_SPI_BITORDER (SPI_BITORDER_MSBFIRST)
#define MAX31865_SPI_MODE (SPI_MODE1)
#define MAX31865_SPI_CS (10)
#define MAX31865_READY_PIN (2)
Adafruit_SPIDevice spi_dev = Adafruit_SPIDevice( MAX31865_SPI_CS, MAX31865_SPI_SPEED, MAX31865_SPI_BITORDER, MAX31865_SPI_MODE, &SPI); // Hardware SPI
// Adafruit_SPIDevice spi_dev = Adafruit_SPIDevice( MAX31865_SPI_CS, 13, 12, 11, MAX31865_SPI_SPEED, MAX31865_SPI_BITORDER, MAX31865_SPI_MODE); // Software SPI
// MAX31865 chip related *********************************************************************************************
Adafruit_BusIO_Register config_reg = Adafruit_BusIO_Register(&spi_dev, 0x00, ADDRBIT8_HIGH_TOWRITE, 1, MSBFIRST);
Adafruit_BusIO_RegisterBits bias_bit = Adafruit_BusIO_RegisterBits(&config_reg, 1, 7);
Adafruit_BusIO_RegisterBits auto_bit = Adafruit_BusIO_RegisterBits(&config_reg, 1, 6);
Adafruit_BusIO_RegisterBits oneS_bit = Adafruit_BusIO_RegisterBits(&config_reg, 1, 5);
Adafruit_BusIO_RegisterBits wire_bit = Adafruit_BusIO_RegisterBits(&config_reg, 1, 4);
Adafruit_BusIO_RegisterBits faultT_bits = Adafruit_BusIO_RegisterBits(&config_reg, 2, 2);
Adafruit_BusIO_RegisterBits faultR_bit = Adafruit_BusIO_RegisterBits(&config_reg, 1, 1);
Adafruit_BusIO_RegisterBits fi50hz_bit = Adafruit_BusIO_RegisterBits(&config_reg, 1, 0);
Adafruit_BusIO_Register rRatio_reg = Adafruit_BusIO_Register(&spi_dev, 0x01, ADDRBIT8_HIGH_TOWRITE, 2, MSBFIRST);
Adafruit_BusIO_RegisterBits rRatio_bits = Adafruit_BusIO_RegisterBits(&rRatio_reg, 15, 1);
Adafruit_BusIO_RegisterBits fault_bit = Adafruit_BusIO_RegisterBits(&rRatio_reg, 1, 0);
Adafruit_BusIO_Register maxRratio_reg = Adafruit_BusIO_Register(&spi_dev, 0x03, ADDRBIT8_HIGH_TOWRITE, 2, MSBFIRST);
Adafruit_BusIO_RegisterBits maxRratio_bits = Adafruit_BusIO_RegisterBits(&maxRratio_reg, 15, 1);
Adafruit_BusIO_Register minRratio_reg = Adafruit_BusIO_Register(&spi_dev, 0x05, ADDRBIT8_HIGH_TOWRITE, 2, MSBFIRST);
Adafruit_BusIO_RegisterBits minRratio_bits = Adafruit_BusIO_RegisterBits(&minRratio_reg, 15, 1);
Adafruit_BusIO_Register fault_reg = Adafruit_BusIO_Register(&spi_dev, 0x07, ADDRBIT8_HIGH_TOWRITE, 1, MSBFIRST);
Adafruit_BusIO_RegisterBits range_high_fault_bit = Adafruit_BusIO_RegisterBits(&fault_reg, 1, 7);
Adafruit_BusIO_RegisterBits range_low_fault_bit = Adafruit_BusIO_RegisterBits(&fault_reg, 1, 6);
Adafruit_BusIO_RegisterBits refin_high_fault_bit = Adafruit_BusIO_RegisterBits(&fault_reg, 1, 5);
Adafruit_BusIO_RegisterBits refin_low_fault_bit = Adafruit_BusIO_RegisterBits(&fault_reg, 1, 4);
Adafruit_BusIO_RegisterBits rtdin_low_fault_bit = Adafruit_BusIO_RegisterBits(&fault_reg, 1, 3);
Adafruit_BusIO_RegisterBits voltage_fault_bit = Adafruit_BusIO_RegisterBits(&fault_reg, 1, 2);
// Print the details of the configuration register.
void printConfig( void ) {
Serial.print("BIAS: "); if (bias_bit.read() ) Serial.print("ON"); else Serial.print("OFF");
Serial.print(", AUTO: "); if (auto_bit.read() ) Serial.print("ON"); else Serial.print("OFF");
Serial.print(", ONES: "); if (oneS_bit.read() ) Serial.print("ON"); else Serial.print("OFF");
Serial.print(", WIRE: "); if (wire_bit.read() ) Serial.print("3"); else Serial.print("2/4");
Serial.print(", FAULTCLEAR: "); if (faultR_bit.read() ) Serial.print("ON"); else Serial.print("OFF");
Serial.print(", "); if (fi50hz_bit.read() ) Serial.print("50HZ"); else Serial.print("60HZ");
Serial.println();
}
// Check and print faults. Then clear them.
void checkFaults( void ) {
if (fault_bit.read()) {
Serial.print("MAX: "); Serial.println(maxRratio_bits.read());
Serial.print("VAL: "); Serial.println( rRatio_bits.read());
Serial.print("MIN: "); Serial.println(minRratio_bits.read());
if (range_high_fault_bit.read() ) Serial.println("Range high fault");
if ( range_low_fault_bit.read() ) Serial.println("Range low fault");
if (refin_high_fault_bit.read() ) Serial.println("REFIN high fault");
if ( refin_low_fault_bit.read() ) Serial.println("REFIN low fault");
if ( rtdin_low_fault_bit.read() ) Serial.println("RTDIN low fault");
if ( voltage_fault_bit.read() ) Serial.println("Voltage fault");
faultR_bit.write(1); // clear fault
}
}
void setup() {
#if (MAX31865_1_READY_PIN != -1)
pinMode(MAX31865_READY_PIN ,INPUT_PULLUP);
#endif
while (!Serial) { delay(10); }
Serial.begin(115200);
Serial.println("SPI Adafruit_BusIO_RegisterBits test on MAX31865");
if (!spi_dev.begin()) {
Serial.println("Could not initialize SPI device");
while (1);
}
// Set up for automode 50Hz. We don't care about selfheating. We want the highest possible sampling rate.
auto_bit.write(0); // Don't switch filtermode while auto_mode is on.
fi50hz_bit.write(1); // Set filter to 50Hz mode.
faultR_bit.write(1); // Clear faults.
bias_bit.write(1); // In automode we want to have the bias current always on.
delay(5); // Wait until bias current settles down.
// 10.5 time constants of the input RC network is required.
// 10ms worst case for 10kω reference resistor and a 0.1µF capacitor across the RTD inputs.
// Adafruit Module has 0.1µF and only 430/4300ω So here 0.43/4.3ms
auto_bit.write(1); // Now we can set automode. Automatically starting first conversion.
// Test the READY_PIN
#if (defined( MAX31865_READY_PIN ) && (MAX31865_READY_PIN != -1))
int i = 0;
while (digitalRead(MAX31865_READY_PIN) && i++ <= 100) { delay(1); }
if (i >= 100) {
Serial.print("ERROR: Max31865 Pin detection does not work. PIN:");
Serial.println(MAX31865_READY_PIN);
}
#else
delay(100);
#endif
// Set ratio range.
// Setting the temperatures would need some more calculation - not related to Adafruit_BusIO_RegisterBits.
uint16_t ratio = rRatio_bits.read();
maxRratio_bits.write( (ratio < 0x8fffu-1000u) ? ratio + 1000u : 0x8fffu );
minRratio_bits.write( (ratio > 1000u) ? ratio - 1000u : 0u );
printConfig();
checkFaults();
}
void loop() {
#if (defined( MAX31865_READY_PIN ) && (MAX31865_1_READY_PIN != -1))
// Is conversion ready?
if (!digitalRead(MAX31865_READY_PIN))
#else
// Warant conversion is ready.
delay(21); // 21ms for 50Hz-mode. 19ms in 60Hz-mode.
#endif
{
// Read ratio, calculate temperature, scale, filter and print.
Serial.println( rRatio2C( rRatio_bits.read() ) * 100.0f, 0); // Temperature scaled by 100
// Check, print, clear faults.
checkFaults();
}
// Do something else.
//delay(15000);
}
// Module/Sensor related. Here Adafruit PT100 module with a 2_Wire PT100 Class C *****************************
float rRatio2C(uint16_t ratio) {
// A simple linear conversion.
const float R0 = 100.0f;
const float Rref = 430.0f;
const float alphaPT = 0.003850f;
const float ADCmax = (1u << 15) - 1.0f;
const float rscale = Rref / ADCmax;
// Measured temperature in boiling water 101.08°C with factor a = 1 and b = 0. Rref and MAX at about 22±2°C.
// Measured temperature in ice/water bath 0.76°C with factor a = 1 and b = 0. Rref and MAX at about 22±2°C.
//const float a = 1.0f / (alphaPT * R0);
const float a = (100.0f/101.08f) / (alphaPT * R0);
//const float b = 0.0f; // 101.08
const float b = -0.76f; // 100.32 > 101.08
return filterRing( ((ratio * rscale) - R0) * a + b );
}
// General purpose *********************************************************************************************
#define RINGLENGTH 250
float filterRing( float newVal ) {
static float ring[RINGLENGTH] = { 0.0 };
static uint8_t ringIndex = 0;
static bool ringFull = false;
if ( ringIndex == RINGLENGTH ) { ringFull = true; ringIndex = 0; }
ring[ringIndex] = newVal;
uint8_t loopEnd = (ringFull) ? RINGLENGTH : ringIndex + 1;
float ringSum = 0.0f;
for (uint8_t i = 0; i < loopEnd; i++) ringSum += ring[i];
ringIndex++;
return ringSum / loopEnd;
}

View File

@@ -0,0 +1,34 @@
#include <Adafruit_BusIO_Register.h>
#include <Adafruit_SPIDevice.h>
#define SPIDEVICE_CS 10
Adafruit_SPIDevice spi_dev = Adafruit_SPIDevice(SPIDEVICE_CS);
void setup() {
while (!Serial) { delay(10); }
Serial.begin(115200);
Serial.println("SPI device register test");
if (!spi_dev.begin()) {
Serial.println("Could not initialize SPI device");
while (1);
}
Adafruit_BusIO_Register id_reg = Adafruit_BusIO_Register(&spi_dev, 0x0F, ADDRBIT8_HIGH_TOREAD);
uint8_t id = 0;
id_reg.read(&id);
Serial.print("ID register = 0x"); Serial.println(id, HEX);
Adafruit_BusIO_Register thresh_reg = Adafruit_BusIO_Register(&spi_dev, 0x0C, ADDRBIT8_HIGH_TOREAD, 2, LSBFIRST);
uint16_t thresh = 0;
thresh_reg.read(&thresh);
Serial.print("Initial threshold register = 0x"); Serial.println(thresh, HEX);
thresh_reg.write(~thresh);
Serial.print("Post threshold register = 0x"); Serial.println(thresh_reg.read(), HEX);
}
void loop() {
}

View File

@@ -0,0 +1,9 @@
name=Adafruit BusIO
version=1.16.2
author=Adafruit
maintainer=Adafruit <info@adafruit.com>
sentence=This is a library for abstracting away I2C and SPI interfacing
paragraph=This is a library for abstracting away I2C and SPI interfacing
category=Signal Input/Output
url=https://github.com/adafruit/Adafruit_BusIO
architectures=*

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,391 @@
#ifndef _ADAFRUIT_GFX_H
#define _ADAFRUIT_GFX_H
#if ARDUINO >= 100
#include "Arduino.h"
#include "Print.h"
#else
#include "WProgram.h"
#endif
#include "gfxfont.h"
#include <Adafruit_I2CDevice.h>
#include <Adafruit_SPIDevice.h>
/// A generic graphics superclass that can handle all sorts of drawing. At a
/// minimum you can subclass and provide drawPixel(). At a maximum you can do a
/// ton of overriding to optimize. Used for any/all Adafruit displays!
class Adafruit_GFX : public Print {
public:
Adafruit_GFX(int16_t w, int16_t h); // Constructor
/**********************************************************************/
/*!
@brief Draw to the screen/framebuffer/etc.
Must be overridden in subclass.
@param x X coordinate in pixels
@param y Y coordinate in pixels
@param color 16-bit pixel color.
*/
/**********************************************************************/
virtual void drawPixel(int16_t x, int16_t y, uint16_t color) = 0;
// TRANSACTION API / CORE DRAW API
// These MAY be overridden by the subclass to provide device-specific
// optimized code. Otherwise 'generic' versions are used.
virtual void startWrite(void);
virtual void writePixel(int16_t x, int16_t y, uint16_t color);
virtual void writeFillRect(int16_t x, int16_t y, int16_t w, int16_t h,
uint16_t color);
virtual void writeFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color);
virtual void writeFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color);
virtual void writeLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1,
uint16_t color);
virtual void endWrite(void);
// CONTROL API
// These MAY be overridden by the subclass to provide device-specific
// optimized code. Otherwise 'generic' versions are used.
virtual void setRotation(uint8_t r);
virtual void invertDisplay(bool i);
// BASIC DRAW API
// These MAY be overridden by the subclass to provide device-specific
// optimized code. Otherwise 'generic' versions are used.
// It's good to implement those, even if using transaction API
virtual void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color);
virtual void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color);
virtual void fillRect(int16_t x, int16_t y, int16_t w, int16_t h,
uint16_t color);
virtual void fillScreen(uint16_t color);
// Optional and probably not necessary to change
virtual void drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1,
uint16_t color);
virtual void drawRect(int16_t x, int16_t y, int16_t w, int16_t h,
uint16_t color);
// These exist only with Adafruit_GFX (no subclass overrides)
void drawCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color);
void drawCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t cornername,
uint16_t color);
void fillCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color);
void fillCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t cornername,
int16_t delta, uint16_t color);
void drawTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2,
int16_t y2, uint16_t color);
void fillTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2,
int16_t y2, uint16_t color);
void drawRoundRect(int16_t x0, int16_t y0, int16_t w, int16_t h,
int16_t radius, uint16_t color);
void fillRoundRect(int16_t x0, int16_t y0, int16_t w, int16_t h,
int16_t radius, uint16_t color);
void drawBitmap(int16_t x, int16_t y, const uint8_t bitmap[], int16_t w,
int16_t h, uint16_t color);
void drawBitmap(int16_t x, int16_t y, const uint8_t bitmap[], int16_t w,
int16_t h, uint16_t color, uint16_t bg);
void drawBitmap(int16_t x, int16_t y, uint8_t *bitmap, int16_t w, int16_t h,
uint16_t color);
void drawBitmap(int16_t x, int16_t y, uint8_t *bitmap, int16_t w, int16_t h,
uint16_t color, uint16_t bg);
void drawXBitmap(int16_t x, int16_t y, const uint8_t bitmap[], int16_t w,
int16_t h, uint16_t color);
void drawGrayscaleBitmap(int16_t x, int16_t y, const uint8_t bitmap[],
int16_t w, int16_t h);
void drawGrayscaleBitmap(int16_t x, int16_t y, uint8_t *bitmap, int16_t w,
int16_t h);
void drawGrayscaleBitmap(int16_t x, int16_t y, const uint8_t bitmap[],
const uint8_t mask[], int16_t w, int16_t h);
void drawGrayscaleBitmap(int16_t x, int16_t y, uint8_t *bitmap, uint8_t *mask,
int16_t w, int16_t h);
void drawRGBBitmap(int16_t x, int16_t y, const uint16_t bitmap[], int16_t w,
int16_t h);
void drawRGBBitmap(int16_t x, int16_t y, uint16_t *bitmap, int16_t w,
int16_t h);
void drawRGBBitmap(int16_t x, int16_t y, const uint16_t bitmap[],
const uint8_t mask[], int16_t w, int16_t h);
void drawRGBBitmap(int16_t x, int16_t y, uint16_t *bitmap, uint8_t *mask,
int16_t w, int16_t h);
void drawChar(int16_t x, int16_t y, unsigned char c, uint16_t color,
uint16_t bg, uint8_t size);
void drawChar(int16_t x, int16_t y, unsigned char c, uint16_t color,
uint16_t bg, uint8_t size_x, uint8_t size_y);
void getTextBounds(const char *string, int16_t x, int16_t y, int16_t *x1,
int16_t *y1, uint16_t *w, uint16_t *h);
void getTextBounds(const __FlashStringHelper *s, int16_t x, int16_t y,
int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h);
void getTextBounds(const String &str, int16_t x, int16_t y, int16_t *x1,
int16_t *y1, uint16_t *w, uint16_t *h);
void setTextSize(uint8_t s);
void setTextSize(uint8_t sx, uint8_t sy);
void setFont(const GFXfont *f = NULL);
/**********************************************************************/
/*!
@brief Set text cursor location
@param x X coordinate in pixels
@param y Y coordinate in pixels
*/
/**********************************************************************/
void setCursor(int16_t x, int16_t y) {
cursor_x = x;
cursor_y = y;
}
/**********************************************************************/
/*!
@brief Set text font color with transparant background
@param c 16-bit 5-6-5 Color to draw text with
@note For 'transparent' background, background and foreground
are set to same color rather than using a separate flag.
*/
/**********************************************************************/
void setTextColor(uint16_t c) { textcolor = textbgcolor = c; }
/**********************************************************************/
/*!
@brief Set text font color with custom background color
@param c 16-bit 5-6-5 Color to draw text with
@param bg 16-bit 5-6-5 Color to draw background/fill with
*/
/**********************************************************************/
void setTextColor(uint16_t c, uint16_t bg) {
textcolor = c;
textbgcolor = bg;
}
/**********************************************************************/
/*!
@brief Set whether text that is too long for the screen width should
automatically wrap around to the next line (else clip right).
@param w true for wrapping, false for clipping
*/
/**********************************************************************/
void setTextWrap(bool w) { wrap = w; }
/**********************************************************************/
/*!
@brief Enable (or disable) Code Page 437-compatible charset.
There was an error in glcdfont.c for the longest time -- one
character (#176, the 'light shade' block) was missing -- this
threw off the index of every character that followed it.
But a TON of code has been written with the erroneous
character indices. By default, the library uses the original
'wrong' behavior and old sketches will still work. Pass
'true' to this function to use correct CP437 character values
in your code.
@param x true = enable (new behavior), false = disable (old behavior)
*/
/**********************************************************************/
void cp437(bool x = true) { _cp437 = x; }
using Print::write;
#if ARDUINO >= 100
virtual size_t write(uint8_t);
#else
virtual void write(uint8_t);
#endif
/************************************************************************/
/*!
@brief Get width of the display, accounting for current rotation
@returns Width in pixels
*/
/************************************************************************/
int16_t width(void) const { return _width; };
/************************************************************************/
/*!
@brief Get height of the display, accounting for current rotation
@returns Height in pixels
*/
/************************************************************************/
int16_t height(void) const { return _height; }
/************************************************************************/
/*!
@brief Get rotation setting for display
@returns 0 thru 3 corresponding to 4 cardinal rotations
*/
/************************************************************************/
uint8_t getRotation(void) const { return rotation; }
// get current cursor position (get rotation safe maximum values,
// using: width() for x, height() for y)
/************************************************************************/
/*!
@brief Get text cursor X location
@returns X coordinate in pixels
*/
/************************************************************************/
int16_t getCursorX(void) const { return cursor_x; }
/************************************************************************/
/*!
@brief Get text cursor Y location
@returns Y coordinate in pixels
*/
/************************************************************************/
int16_t getCursorY(void) const { return cursor_y; };
protected:
void charBounds(unsigned char c, int16_t *x, int16_t *y, int16_t *minx,
int16_t *miny, int16_t *maxx, int16_t *maxy);
int16_t WIDTH; ///< This is the 'raw' display width - never changes
int16_t HEIGHT; ///< This is the 'raw' display height - never changes
int16_t _width; ///< Display width as modified by current rotation
int16_t _height; ///< Display height as modified by current rotation
int16_t cursor_x; ///< x location to start print()ing text
int16_t cursor_y; ///< y location to start print()ing text
uint16_t textcolor; ///< 16-bit background color for print()
uint16_t textbgcolor; ///< 16-bit text color for print()
uint8_t textsize_x; ///< Desired magnification in X-axis of text to print()
uint8_t textsize_y; ///< Desired magnification in Y-axis of text to print()
uint8_t rotation; ///< Display rotation (0 thru 3)
bool wrap; ///< If set, 'wrap' text at right edge of display
bool _cp437; ///< If set, use correct CP437 charset (default is off)
GFXfont *gfxFont; ///< Pointer to special font
};
/// A simple drawn button UI element
class Adafruit_GFX_Button {
public:
Adafruit_GFX_Button(void);
// "Classic" initButton() uses center & size
void initButton(Adafruit_GFX *gfx, int16_t x, int16_t y, uint16_t w,
uint16_t h, uint16_t outline, uint16_t fill,
uint16_t textcolor, char *label, uint8_t textsize);
void initButton(Adafruit_GFX *gfx, int16_t x, int16_t y, uint16_t w,
uint16_t h, uint16_t outline, uint16_t fill,
uint16_t textcolor, char *label, uint8_t textsize_x,
uint8_t textsize_y);
// New/alt initButton() uses upper-left corner & size
void initButtonUL(Adafruit_GFX *gfx, int16_t x1, int16_t y1, uint16_t w,
uint16_t h, uint16_t outline, uint16_t fill,
uint16_t textcolor, char *label, uint8_t textsize);
void initButtonUL(Adafruit_GFX *gfx, int16_t x1, int16_t y1, uint16_t w,
uint16_t h, uint16_t outline, uint16_t fill,
uint16_t textcolor, char *label, uint8_t textsize_x,
uint8_t textsize_y);
void drawButton(bool inverted = false);
bool contains(int16_t x, int16_t y);
/**********************************************************************/
/*!
@brief Sets button state, should be done by some touch function
@param p True for pressed, false for not.
*/
/**********************************************************************/
void press(bool p) {
laststate = currstate;
currstate = p;
}
bool justPressed();
bool justReleased();
/**********************************************************************/
/*!
@brief Query whether the button is currently pressed
@returns True if pressed
*/
/**********************************************************************/
bool isPressed(void) { return currstate; };
private:
Adafruit_GFX *_gfx;
int16_t _x1, _y1; // Coordinates of top-left corner
uint16_t _w, _h;
uint8_t _textsize_x;
uint8_t _textsize_y;
uint16_t _outlinecolor, _fillcolor, _textcolor;
char _label[10];
bool currstate, laststate;
};
/// A GFX 1-bit canvas context for graphics
class GFXcanvas1 : public Adafruit_GFX {
public:
GFXcanvas1(uint16_t w, uint16_t h);
~GFXcanvas1(void);
void drawPixel(int16_t x, int16_t y, uint16_t color);
void fillScreen(uint16_t color);
void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color);
void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color);
bool getPixel(int16_t x, int16_t y) const;
/**********************************************************************/
/*!
@brief Get a pointer to the internal buffer memory
@returns A pointer to the allocated buffer
*/
/**********************************************************************/
uint8_t *getBuffer(void) const { return buffer; }
protected:
bool getRawPixel(int16_t x, int16_t y) const;
void drawFastRawVLine(int16_t x, int16_t y, int16_t h, uint16_t color);
void drawFastRawHLine(int16_t x, int16_t y, int16_t w, uint16_t color);
uint8_t *buffer; ///< Raster data: no longer private, allow subclass access
private:
#ifdef __AVR__
// Bitmask tables of 0x80>>X and ~(0x80>>X), because X>>Y is slow on AVR
static const uint8_t PROGMEM GFXsetBit[], GFXclrBit[];
#endif
};
/// A GFX 8-bit canvas context for graphics
class GFXcanvas8 : public Adafruit_GFX {
public:
GFXcanvas8(uint16_t w, uint16_t h);
~GFXcanvas8(void);
void drawPixel(int16_t x, int16_t y, uint16_t color);
void fillScreen(uint16_t color);
void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color);
void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color);
uint8_t getPixel(int16_t x, int16_t y) const;
/**********************************************************************/
/*!
@brief Get a pointer to the internal buffer memory
@returns A pointer to the allocated buffer
*/
/**********************************************************************/
uint8_t *getBuffer(void) const { return buffer; }
protected:
uint8_t getRawPixel(int16_t x, int16_t y) const;
void drawFastRawVLine(int16_t x, int16_t y, int16_t h, uint16_t color);
void drawFastRawHLine(int16_t x, int16_t y, int16_t w, uint16_t color);
uint8_t *buffer; ///< Raster data: no longer private, allow subclass access
};
/// A GFX 16-bit canvas context for graphics
class GFXcanvas16 : public Adafruit_GFX {
public:
GFXcanvas16(uint16_t w, uint16_t h);
~GFXcanvas16(void);
void drawPixel(int16_t x, int16_t y, uint16_t color);
void fillScreen(uint16_t color);
void byteSwap(void);
void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color);
void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color);
uint16_t getPixel(int16_t x, int16_t y) const;
/**********************************************************************/
/*!
@brief Get a pointer to the internal buffer memory
@returns A pointer to the allocated buffer
*/
/**********************************************************************/
uint16_t *getBuffer(void) const { return buffer; }
protected:
uint16_t getRawPixel(int16_t x, int16_t y) const;
void drawFastRawVLine(int16_t x, int16_t y, int16_t h, uint16_t color);
void drawFastRawHLine(int16_t x, int16_t y, int16_t w, uint16_t color);
uint16_t *buffer; ///< Raster data: no longer private, allow subclass access
};
#endif // _ADAFRUIT_GFX_H

View File

@@ -0,0 +1,422 @@
/*!
* @file Adafruit_GrayOLED.cpp
*
* This is documentation for Adafruit's generic library for grayscale
* OLED displays: http://www.adafruit.com/category/63_98
*
* These displays use I2C or SPI to communicate. I2C requires 2 pins
* (SCL+SDA) and optionally a RESET pin. SPI requires 4 pins (MOSI, SCK,
* select, data/command) and optionally a reset pin. Hardware SPI or
* 'bitbang' software SPI are both supported.
*
* Adafruit invests time and resources providing this open source code,
* please support Adafruit and open-source hardware by purchasing
* products from Adafruit!
*
*/
// Not for ATtiny, at all
#if !defined(__AVR_ATtiny85__) && !defined(__AVR_ATtiny84__)
#include "Adafruit_GrayOLED.h"
#include <Adafruit_GFX.h>
// SOME DEFINES AND STATIC VARIABLES USED INTERNALLY -----------------------
#define grayoled_swap(a, b) \
(((a) ^= (b)), ((b) ^= (a)), ((a) ^= (b))) ///< No-temp-var swap operation
// CONSTRUCTORS, DESTRUCTOR ------------------------------------------------
/*!
@brief Constructor for I2C-interfaced OLED displays.
@param bpp Bits per pixel, 1 for monochrome, 4 for 16-gray
@param w
Display width in pixels
@param h
Display height in pixels
@param twi
Pointer to an existing TwoWire instance (e.g. &Wire, the
microcontroller's primary I2C bus).
@param rst_pin
Reset pin (using Arduino pin numbering), or -1 if not used
(some displays might be wired to share the microcontroller's
reset pin).
@param clkDuring
Speed (in Hz) for Wire transmissions in library calls.
Defaults to 400000 (400 KHz), a known 'safe' value for most
microcontrollers, and meets the OLED datasheet spec.
Some systems can operate I2C faster (800 KHz for ESP32, 1 MHz
for many other 32-bit MCUs), and some (perhaps not all)
Many OLED's can work with this -- so it's optionally be specified
here and is not a default behavior. (Ignored if using pre-1.5.7
Arduino software, which operates I2C at a fixed 100 KHz.)
@param clkAfter
Speed (in Hz) for Wire transmissions following library
calls. Defaults to 100000 (100 KHz), the default Arduino Wire
speed. This is done rather than leaving it at the 'during' speed
because other devices on the I2C bus might not be compatible
with the faster rate. (Ignored if using pre-1.5.7 Arduino
software, which operates I2C at a fixed 100 KHz.)
@note Call the object's begin() function before use -- buffer
allocation is performed there!
*/
Adafruit_GrayOLED::Adafruit_GrayOLED(uint8_t bpp, uint16_t w, uint16_t h,
TwoWire *twi, int8_t rst_pin,
uint32_t clkDuring, uint32_t clkAfter)
: Adafruit_GFX(w, h), i2c_preclk(clkDuring), i2c_postclk(clkAfter),
buffer(NULL), dcPin(-1), csPin(-1), rstPin(rst_pin), _bpp(bpp) {
i2c_dev = NULL;
_theWire = twi;
}
/*!
@brief Constructor for SPI GrayOLED displays, using software (bitbang)
SPI.
@param bpp Bits per pixel, 1 for monochrome, 4 for 16-gray
@param w
Display width in pixels
@param h
Display height in pixels
@param mosi_pin
MOSI (master out, slave in) pin (using Arduino pin numbering).
This transfers serial data from microcontroller to display.
@param sclk_pin
SCLK (serial clock) pin (using Arduino pin numbering).
This clocks each bit from MOSI.
@param dc_pin
Data/command pin (using Arduino pin numbering), selects whether
display is receiving commands (low) or data (high).
@param rst_pin
Reset pin (using Arduino pin numbering), or -1 if not used
(some displays might be wired to share the microcontroller's
reset pin).
@param cs_pin
Chip-select pin (using Arduino pin numbering) for sharing the
bus with other devices. Active low.
@note Call the object's begin() function before use -- buffer
allocation is performed there!
*/
Adafruit_GrayOLED::Adafruit_GrayOLED(uint8_t bpp, uint16_t w, uint16_t h,
int8_t mosi_pin, int8_t sclk_pin,
int8_t dc_pin, int8_t rst_pin,
int8_t cs_pin)
: Adafruit_GFX(w, h), dcPin(dc_pin), csPin(cs_pin), rstPin(rst_pin),
_bpp(bpp) {
spi_dev = new Adafruit_SPIDevice(cs_pin, sclk_pin, -1, mosi_pin, 1000000);
}
/*!
@brief Constructor for SPI GrayOLED displays, using native hardware SPI.
@param bpp Bits per pixel, 1 for monochrome, 4 for 16-gray
@param w
Display width in pixels
@param h
Display height in pixels
@param spi
Pointer to an existing SPIClass instance (e.g. &SPI, the
microcontroller's primary SPI bus).
@param dc_pin
Data/command pin (using Arduino pin numbering), selects whether
display is receiving commands (low) or data (high).
@param rst_pin
Reset pin (using Arduino pin numbering), or -1 if not used
(some displays might be wired to share the microcontroller's
reset pin).
@param cs_pin
Chip-select pin (using Arduino pin numbering) for sharing the
bus with other devices. Active low.
@param bitrate
SPI clock rate for transfers to this display. Default if
unspecified is 8000000UL (8 MHz).
@note Call the object's begin() function before use -- buffer
allocation is performed there!
*/
Adafruit_GrayOLED::Adafruit_GrayOLED(uint8_t bpp, uint16_t w, uint16_t h,
SPIClass *spi, int8_t dc_pin,
int8_t rst_pin, int8_t cs_pin,
uint32_t bitrate)
: Adafruit_GFX(w, h), dcPin(dc_pin), csPin(cs_pin), rstPin(rst_pin),
_bpp(bpp) {
spi_dev = new Adafruit_SPIDevice(cs_pin, bitrate, SPI_BITORDER_MSBFIRST,
SPI_MODE0, spi);
}
/*!
@brief Destructor for Adafruit_GrayOLED object.
*/
Adafruit_GrayOLED::~Adafruit_GrayOLED(void) {
if (buffer) {
free(buffer);
buffer = NULL;
}
if (spi_dev)
delete spi_dev;
if (i2c_dev)
delete i2c_dev;
}
// LOW-LEVEL UTILS ---------------------------------------------------------
/*!
@brief Issue single command byte to OLED, using I2C or hard/soft SPI as
needed.
@param c The single byte command
*/
void Adafruit_GrayOLED::oled_command(uint8_t c) {
if (i2c_dev) { // I2C
uint8_t buf[2] = {0x00, c}; // Co = 0, D/C = 0
i2c_dev->write(buf, 2);
} else { // SPI (hw or soft) -- transaction started in calling function
digitalWrite(dcPin, LOW);
spi_dev->write(&c, 1);
}
}
// Issue list of commands to GrayOLED
/*!
@brief Issue multiple bytes of commands OLED, using I2C or hard/soft SPI as
needed.
@param c Pointer to the command array
@param n The number of bytes in the command array
@returns True for success on ability to write the data in I2C.
*/
bool Adafruit_GrayOLED::oled_commandList(const uint8_t *c, uint8_t n) {
if (i2c_dev) { // I2C
uint8_t dc_byte = 0x00; // Co = 0, D/C = 0
if (!i2c_dev->write((uint8_t *)c, n, true, &dc_byte, 1)) {
return false;
}
} else { // SPI -- transaction started in calling function
digitalWrite(dcPin, LOW);
if (!spi_dev->write((uint8_t *)c, n)) {
return false;
}
}
return true;
}
// ALLOCATE & INIT DISPLAY -------------------------------------------------
/*!
@brief Allocate RAM for image buffer, initialize peripherals and pins.
Note that subclasses must call this before other begin() init
@param addr
I2C address of corresponding oled display.
SPI displays (hardware or software) do not use addresses, but
this argument is still required. Default if unspecified is 0x3C.
@param reset
If true, and if the reset pin passed to the constructor is
valid, a hard reset will be performed before initializing the
display. If using multiple oled displays on the same bus, and
if they all share the same reset pin, you should only pass true
on the first display being initialized, false on all others,
else the already-initialized displays would be reset. Default if
unspecified is true.
@return true on successful allocation/init, false otherwise.
Well-behaved code should check the return value before
proceeding.
@note MUST call this function before any drawing or updates!
*/
bool Adafruit_GrayOLED::_init(uint8_t addr, bool reset) {
// attempt to malloc the bitmap framebuffer
if ((!buffer) &&
!(buffer = (uint8_t *)malloc(_bpp * WIDTH * ((HEIGHT + 7) / 8)))) {
return false;
}
// Reset OLED if requested and reset pin specified in constructor
if (reset && (rstPin >= 0)) {
pinMode(rstPin, OUTPUT);
digitalWrite(rstPin, HIGH);
delay(10); // VDD goes high at start, pause
digitalWrite(rstPin, LOW); // Bring reset low
delay(10); // Wait 10 ms
digitalWrite(rstPin, HIGH); // Bring out of reset
delay(10);
}
// Setup pin directions
if (_theWire) { // using I2C
i2c_dev = new Adafruit_I2CDevice(addr, _theWire);
// look for i2c address:
if (!i2c_dev || !i2c_dev->begin()) {
return false;
}
} else { // Using one of the SPI modes, either soft or hardware
if (!spi_dev || !spi_dev->begin()) {
return false;
}
pinMode(dcPin, OUTPUT); // Set data/command pin as output
}
clearDisplay();
// set max dirty window
window_x1 = 0;
window_y1 = 0;
window_x2 = WIDTH - 1;
window_y2 = HEIGHT - 1;
return true; // Success
}
// DRAWING FUNCTIONS -------------------------------------------------------
/*!
@brief Set/clear/invert a single pixel. This is also invoked by the
Adafruit_GFX library in generating many higher-level graphics
primitives.
@param x
Column of display -- 0 at left to (screen width - 1) at right.
@param y
Row of display -- 0 at top to (screen height -1) at bottom.
@param color
Pixel color, one of: MONOOLED_BLACK, MONOOLED_WHITE or
MONOOLED_INVERT.
@note Changes buffer contents only, no immediate effect on display.
Follow up with a call to display(), or with other graphics
commands as needed by one's own application.
*/
void Adafruit_GrayOLED::drawPixel(int16_t x, int16_t y, uint16_t color) {
if ((x >= 0) && (x < width()) && (y >= 0) && (y < height())) {
// Pixel is in-bounds. Rotate coordinates if needed.
switch (getRotation()) {
case 1:
grayoled_swap(x, y);
x = WIDTH - x - 1;
break;
case 2:
x = WIDTH - x - 1;
y = HEIGHT - y - 1;
break;
case 3:
grayoled_swap(x, y);
y = HEIGHT - y - 1;
break;
}
// adjust dirty window
window_x1 = min(window_x1, x);
window_y1 = min(window_y1, y);
window_x2 = max(window_x2, x);
window_y2 = max(window_y2, y);
if (_bpp == 1) {
switch (color) {
case MONOOLED_WHITE:
buffer[x + (y / 8) * WIDTH] |= (1 << (y & 7));
break;
case MONOOLED_BLACK:
buffer[x + (y / 8) * WIDTH] &= ~(1 << (y & 7));
break;
case MONOOLED_INVERSE:
buffer[x + (y / 8) * WIDTH] ^= (1 << (y & 7));
break;
}
}
if (_bpp == 4) {
uint8_t *pixelptr = &buffer[x / 2 + (y * WIDTH / 2)];
// Serial.printf("(%d, %d) -> offset %d\n", x, y, x/2 + (y * WIDTH / 2));
if (x % 2 == 0) { // even, left nibble
uint8_t t = pixelptr[0] & 0x0F;
t |= (color & 0xF) << 4;
pixelptr[0] = t;
} else { // odd, right lower nibble
uint8_t t = pixelptr[0] & 0xF0;
t |= color & 0xF;
pixelptr[0] = t;
}
}
}
}
/*!
@brief Clear contents of display buffer (set all pixels to off).
@note Changes buffer contents only, no immediate effect on display.
Follow up with a call to display(), or with other graphics
commands as needed by one's own application.
*/
void Adafruit_GrayOLED::clearDisplay(void) {
memset(buffer, 0, _bpp * WIDTH * ((HEIGHT + 7) / 8));
// set max dirty window
window_x1 = 0;
window_y1 = 0;
window_x2 = WIDTH - 1;
window_y2 = HEIGHT - 1;
}
/*!
@brief Return color of a single pixel in display buffer.
@param x
Column of display -- 0 at left to (screen width - 1) at right.
@param y
Row of display -- 0 at top to (screen height -1) at bottom.
@return true if pixel is set (usually MONOOLED_WHITE, unless display invert
mode is enabled), false if clear (MONOOLED_BLACK).
@note Reads from buffer contents; may not reflect current contents of
screen if display() has not been called.
*/
bool Adafruit_GrayOLED::getPixel(int16_t x, int16_t y) {
if ((x >= 0) && (x < width()) && (y >= 0) && (y < height())) {
// Pixel is in-bounds. Rotate coordinates if needed.
switch (getRotation()) {
case 1:
grayoled_swap(x, y);
x = WIDTH - x - 1;
break;
case 2:
x = WIDTH - x - 1;
y = HEIGHT - y - 1;
break;
case 3:
grayoled_swap(x, y);
y = HEIGHT - y - 1;
break;
}
return (buffer[x + (y / 8) * WIDTH] & (1 << (y & 7)));
}
return false; // Pixel out of bounds
}
/*!
@brief Get base address of display buffer for direct reading or writing.
@return Pointer to an unsigned 8-bit array, column-major, columns padded
to full byte boundary if needed.
*/
uint8_t *Adafruit_GrayOLED::getBuffer(void) { return buffer; }
// OTHER HARDWARE SETTINGS -------------------------------------------------
/*!
@brief Enable or disable display invert mode (white-on-black vs
black-on-white). Handy for testing!
@param i
If true, switch to invert mode (black-on-white), else normal
mode (white-on-black).
@note This has an immediate effect on the display, no need to call the
display() function -- buffer contents are not changed, rather a
different pixel mode of the display hardware is used. When
enabled, drawing MONOOLED_BLACK (value 0) pixels will actually draw
white, MONOOLED_WHITE (value 1) will draw black.
*/
void Adafruit_GrayOLED::invertDisplay(bool i) {
oled_command(i ? GRAYOLED_INVERTDISPLAY : GRAYOLED_NORMALDISPLAY);
}
/*!
@brief Adjust the display contrast.
@param level The contrast level from 0 to 0x7F
@note This has an immediate effect on the display, no need to call the
display() function -- buffer contents are not changed.
*/
void Adafruit_GrayOLED::setContrast(uint8_t level) {
uint8_t cmd[] = {GRAYOLED_SETCONTRAST, level};
oled_commandList(cmd, 2);
}
#endif /* ATTIN85 not supported */

View File

@@ -0,0 +1,101 @@
/*!
* @file Adafruit_GrayOLED.h
*
* This is part of for Adafruit's GFX library, supplying generic support
* for grayscale OLED displays: http://www.adafruit.com/category/63_98
*
* These displays use I2C or SPI to communicate. I2C requires 2 pins
* (SCL+SDA) and optionally a RESET pin. SPI requires 4 pins (MOSI, SCK,
* select, data/command) and optionally a reset pin. Hardware SPI or
* 'bitbang' software SPI are both supported.
*
* 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, with
* contributions from the open source community.
*
* BSD license, all text above, and the splash screen header file,
* must be included in any redistribution.
*
*/
#ifndef _Adafruit_GRAYOLED_H_
#define _Adafruit_GRAYOLED_H_
// Not for ATtiny, at all
#if !defined(__AVR_ATtiny85__) && !defined(__AVR_ATtiny84__)
#include <Adafruit_GFX.h>
#include <Adafruit_I2CDevice.h>
#include <Adafruit_SPIDevice.h>
#include <SPI.h>
#include <Wire.h>
#define GRAYOLED_SETCONTRAST 0x81 ///< Generic contrast for almost all OLEDs
#define GRAYOLED_NORMALDISPLAY 0xA6 ///< Generic non-invert for almost all OLEDs
#define GRAYOLED_INVERTDISPLAY 0xA7 ///< Generic invert for almost all OLEDs
#define MONOOLED_BLACK 0 ///< Default black 'color' for monochrome OLEDS
#define MONOOLED_WHITE 1 ///< Default white 'color' for monochrome OLEDS
#define MONOOLED_INVERSE 2 ///< Default inversion command for monochrome OLEDS
/*!
@brief Class that stores state and functions for interacting with
generic grayscale OLED displays.
*/
class Adafruit_GrayOLED : public Adafruit_GFX {
public:
Adafruit_GrayOLED(uint8_t bpp, uint16_t w, uint16_t h, TwoWire *twi = &Wire,
int8_t rst_pin = -1, uint32_t preclk = 400000,
uint32_t postclk = 100000);
Adafruit_GrayOLED(uint8_t bpp, uint16_t w, uint16_t h, int8_t mosi_pin,
int8_t sclk_pin, int8_t dc_pin, int8_t rst_pin,
int8_t cs_pin);
Adafruit_GrayOLED(uint8_t bpp, uint16_t w, uint16_t h, SPIClass *spi,
int8_t dc_pin, int8_t rst_pin, int8_t cs_pin,
uint32_t bitrate = 8000000UL);
~Adafruit_GrayOLED(void);
/**
@brief The function that sub-classes define that writes out the buffer to
the display over I2C or SPI
**/
virtual void display(void) = 0;
void clearDisplay(void);
void invertDisplay(bool i);
void setContrast(uint8_t contrastlevel);
void drawPixel(int16_t x, int16_t y, uint16_t color);
bool getPixel(int16_t x, int16_t y);
uint8_t *getBuffer(void);
void oled_command(uint8_t c);
bool oled_commandList(const uint8_t *c, uint8_t n);
protected:
bool _init(uint8_t i2caddr = 0x3C, bool reset = true);
Adafruit_SPIDevice *spi_dev = NULL; ///< The SPI interface BusIO device
Adafruit_I2CDevice *i2c_dev = NULL; ///< The I2C interface BusIO device
int32_t i2c_preclk = 400000, ///< Configurable 'high speed' I2C rate
i2c_postclk = 100000; ///< Configurable 'low speed' I2C rate
uint8_t *buffer = NULL; ///< Internal 1:1 framebuffer of display mem
int16_t window_x1, ///< Dirty tracking window minimum x
window_y1, ///< Dirty tracking window minimum y
window_x2, ///< Dirty tracking window maximum x
window_y2; ///< Dirty tracking window maximum y
int dcPin, ///< The Arduino pin connected to D/C (for SPI)
csPin, ///< The Arduino pin connected to CS (for SPI)
rstPin; ///< The Arduino pin connected to reset (-1 if unused)
uint8_t _bpp = 1; ///< Bits per pixel color for this display
private:
TwoWire *_theWire = NULL; ///< The underlying hardware I2C
};
#endif // end __AVR_ATtiny85__ __AVR_ATtiny84__
#endif // _Adafruit_GrayOLED_H_

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,531 @@
/*!
* @file Adafruit_SPITFT.h
*
* Part of Adafruit's GFX graphics library. Originally this class was
* written to handle a range of color TFT displays connected via SPI,
* but over time this library and some display-specific subclasses have
* mutated to include some color OLEDs as well as parallel-interfaced
* displays. The name's been kept for the sake of older code.
*
* 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 "ladyada" Fried for Adafruit Industries,
* with contributions from the open source community.
*
* BSD license, all text here must be included in any redistribution.
*/
#ifndef _ADAFRUIT_SPITFT_H_
#define _ADAFRUIT_SPITFT_H_
// Not for ATtiny, at all
#if !defined(__AVR_ATtiny85__) && !defined(__AVR_ATtiny84__)
#include "Adafruit_GFX.h"
#include <SPI.h>
// HARDWARE CONFIG ---------------------------------------------------------
#if defined(__AVR__)
typedef uint8_t ADAGFX_PORT_t; ///< PORT values are 8-bit
#define USE_FAST_PINIO ///< Use direct PORT register access
#elif defined(ARDUINO_STM32_FEATHER) // WICED
typedef class HardwareSPI SPIClass; ///< SPI is a bit odd on WICED
typedef uint32_t ADAGFX_PORT_t; ///< PORT values are 32-bit
#elif defined(__arm__)
#if defined(ARDUINO_ARCH_SAMD)
// Adafruit M0, M4
typedef uint32_t ADAGFX_PORT_t; ///< PORT values are 32-bit
#define USE_FAST_PINIO ///< Use direct PORT register access
#define HAS_PORT_SET_CLR ///< PORTs have set & clear registers
#elif defined(CORE_TEENSY)
// PJRC Teensy 4.x
#if defined(__IMXRT1052__) || defined(__IMXRT1062__) // Teensy 4.x
typedef uint32_t ADAGFX_PORT_t; ///< PORT values are 32-bit
// PJRC Teensy 3.x
#else
typedef uint8_t ADAGFX_PORT_t; ///< PORT values are 8-bit
#endif
#define USE_FAST_PINIO ///< Use direct PORT register access
#define HAS_PORT_SET_CLR ///< PORTs have set & clear registers
#else
// Arduino Due?
typedef uint32_t ADAGFX_PORT_t; ///< PORT values are 32-bit
// USE_FAST_PINIO not available here (yet)...Due has a totally different
// GPIO register set and will require some changes elsewhere (e.g. in
// constructors especially).
#endif
#else // !ARM
// Probably ESP8266 or ESP32. USE_FAST_PINIO is not available here (yet)
// but don't worry about it too much...the digitalWrite() implementation
// on these platforms is reasonably efficient and already RAM-resident,
// only gotcha then is no parallel connection support for now.
typedef uint32_t ADAGFX_PORT_t; ///< PORT values are 32-bit
#endif // end !ARM
typedef volatile ADAGFX_PORT_t *PORTreg_t; ///< PORT register type
#if defined(__AVR__)
#define DEFAULT_SPI_FREQ 8000000L ///< Hardware SPI default speed
#else
#define DEFAULT_SPI_FREQ 16000000L ///< Hardware SPI default speed
#endif
#if defined(ADAFRUIT_PYPORTAL) || defined(ADAFRUIT_PYPORTAL_M4_TITANO) || \
defined(ADAFRUIT_PYBADGE_M4_EXPRESS) || \
defined(ADAFRUIT_PYGAMER_M4_EXPRESS) || \
defined(ADAFRUIT_MONSTER_M4SK_EXPRESS) || defined(NRF52_SERIES) || \
defined(ADAFRUIT_CIRCUITPLAYGROUND_M0)
#define USE_SPI_DMA ///< Auto DMA
#else
//#define USE_SPI_DMA ///< If set,
// use DMA if available
#endif
// Another "oops" name -- this now also handles parallel DMA.
// If DMA is enabled, Arduino sketch MUST #include <Adafruit_ZeroDMA.h>
// Estimated RAM usage:
// 4 bytes/pixel on display major axis + 8 bytes/pixel on minor axis,
// e.g. 320x240 pixels = 320 * 4 + 240 * 8 = 3,200 bytes.
#if defined(USE_SPI_DMA) && (defined(__SAMD51__) || defined(ARDUINO_SAMD_ZERO))
#include <Adafruit_ZeroDMA.h>
#endif
// This is kind of a kludge. Needed a way to disambiguate the software SPI
// and parallel constructors via their argument lists. Originally tried a
// bool as the first argument to the parallel constructor (specifying 8-bit
// vs 16-bit interface) but the compiler regards this as equivalent to an
// integer and thus still ambiguous. SO...the parallel constructor requires
// an enumerated type as the first argument: tft8 (for 8-bit parallel) or
// tft16 (for 16-bit)...even though 16-bit isn't fully implemented or tested
// and might never be, still needed that disambiguation from soft SPI.
/*! For first arg to parallel constructor */
enum tftBusWidth { tft8bitbus, tft16bitbus };
// CLASS DEFINITION --------------------------------------------------------
/*!
@brief Adafruit_SPITFT is an intermediary class between Adafruit_GFX
and various hardware-specific subclasses for different displays.
It handles certain operations that are common to a range of
displays (address window, area fills, etc.). Originally these were
all color TFT displays interfaced via SPI, but it's since expanded
to include color OLEDs and parallel-interfaced TFTs. THE NAME HAS
BEEN KEPT TO AVOID BREAKING A LOT OF SUBCLASSES AND EXAMPLE CODE.
Many of the class member functions similarly live on with names
that don't necessarily accurately describe what they're doing,
again to avoid breaking a lot of other code. If in doubt, read
the comments.
*/
class Adafruit_SPITFT : public Adafruit_GFX {
public:
// CONSTRUCTORS --------------------------------------------------------
// Software SPI constructor: expects width & height (at default rotation
// setting 0), 4 signal pins (cs, dc, mosi, sclk), 2 optional pins
// (reset, miso). cs argument is required but can be -1 if unused --
// rather than moving it to the optional arguments, it was done this way
// to avoid breaking existing code (-1 option was a later addition).
Adafruit_SPITFT(uint16_t w, uint16_t h, int8_t cs, int8_t dc, int8_t mosi,
int8_t sck, int8_t rst = -1, int8_t miso = -1);
// Hardware SPI constructor using the default SPI port: expects width &
// height (at default rotation setting 0), 2 signal pins (cs, dc),
// optional reset pin. cs is required but can be -1 if unused -- rather
// than moving it to the optional arguments, it was done this way to
// avoid breaking existing code (-1 option was a later addition).
Adafruit_SPITFT(uint16_t w, uint16_t h, int8_t cs, int8_t dc,
int8_t rst = -1);
#if !defined(ESP8266) // See notes in .cpp
// Hardware SPI constructor using an arbitrary SPI peripheral: expects
// width & height (rotation 0), SPIClass pointer, 2 signal pins (cs, dc)
// and optional reset pin. cs is required but can be -1 if unused.
Adafruit_SPITFT(uint16_t w, uint16_t h, SPIClass *spiClass, int8_t cs,
int8_t dc, int8_t rst = -1);
#endif // end !ESP8266
// Parallel constructor: expects width & height (rotation 0), flag
// indicating whether 16-bit (true) or 8-bit (false) interface, 3 signal
// pins (d0, wr, dc), 3 optional pins (cs, rst, rd). 16-bit parallel
// isn't even fully implemented but the 'wide' flag was added as a
// required argument to avoid ambiguity with other constructors.
Adafruit_SPITFT(uint16_t w, uint16_t h, tftBusWidth busWidth, int8_t d0,
int8_t wr, int8_t dc, int8_t cs = -1, int8_t rst = -1,
int8_t rd = -1);
// DESTRUCTOR ----------------------------------------------------------
~Adafruit_SPITFT(){};
// CLASS MEMBER FUNCTIONS ----------------------------------------------
// These first two functions MUST be declared by subclasses:
/*!
@brief Display-specific initialization function.
@param freq SPI frequency, in hz (or 0 for default or unused).
*/
virtual void begin(uint32_t freq) = 0;
/*!
@brief Set up the specific display hardware's "address window"
for subsequent pixel-pushing operations.
@param x Leftmost pixel of area to be drawn (MUST be within
display bounds at current rotation setting).
@param y Topmost pixel of area to be drawn (MUST be within
display bounds at current rotation setting).
@param w Width of area to be drawn, in pixels (MUST be >0 and,
added to x, within display bounds at current rotation).
@param h Height of area to be drawn, in pixels (MUST be >0 and,
added to x, within display bounds at current rotation).
*/
virtual void setAddrWindow(uint16_t x, uint16_t y, uint16_t w,
uint16_t h) = 0;
// Remaining functions do not need to be declared in subclasses
// unless they wish to provide hardware-specific optimizations.
// Brief comments here...documented more thoroughly in .cpp file.
// Subclass' begin() function invokes this to initialize hardware.
// freq=0 to use default SPI speed. spiMode must be one of the SPI_MODEn
// values defined in SPI.h, which are NOT the same as 0 for SPI_MODE0,
// 1 for SPI_MODE1, etc...use ONLY the SPI_MODEn defines! Only!
// Name is outdated (interface may be parallel) but for compatibility:
void initSPI(uint32_t freq = 0, uint8_t spiMode = SPI_MODE0);
void setSPISpeed(uint32_t freq);
// Chip select and/or hardware SPI transaction start as needed:
void startWrite(void);
// Chip deselect and/or hardware SPI transaction end as needed:
void endWrite(void);
void sendCommand(uint8_t commandByte, uint8_t *dataBytes,
uint8_t numDataBytes);
void sendCommand(uint8_t commandByte, const uint8_t *dataBytes = NULL,
uint8_t numDataBytes = 0);
void sendCommand16(uint16_t commandWord, const uint8_t *dataBytes = NULL,
uint8_t numDataBytes = 0);
uint8_t readcommand8(uint8_t commandByte, uint8_t index = 0);
uint16_t readcommand16(uint16_t addr);
// These functions require a chip-select and/or SPI transaction
// around them. Higher-level graphics primitives might start a
// single transaction and then make multiple calls to these functions
// (e.g. circle or text rendering might make repeated lines or rects)
// before ending the transaction. It's more efficient than starting a
// transaction every time.
void writePixel(int16_t x, int16_t y, uint16_t color);
void writePixels(uint16_t *colors, uint32_t len, bool block = true,
bool bigEndian = false);
void writeColor(uint16_t color, uint32_t len);
void writeFillRect(int16_t x, int16_t y, int16_t w, int16_t h,
uint16_t color);
void writeFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color);
void writeFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color);
// This is a new function, similar to writeFillRect() except that
// all arguments MUST be onscreen, sorted and clipped. If higher-level
// primitives can handle their own sorting/clipping, it avoids repeating
// such operations in the low-level code, making it potentially faster.
// CALLING THIS WITH UNCLIPPED OR NEGATIVE VALUES COULD BE DISASTROUS.
inline void writeFillRectPreclipped(int16_t x, int16_t y, int16_t w,
int16_t h, uint16_t color);
// Another new function, companion to the new non-blocking
// writePixels() variant.
void dmaWait(void);
// Used by writePixels() in some situations, but might have rare need in
// user code, so it's public...
bool dmaBusy(void) const; // true if DMA is used and busy, false otherwise
void swapBytes(uint16_t *src, uint32_t len, uint16_t *dest = NULL);
// These functions are similar to the 'write' functions above, but with
// a chip-select and/or SPI transaction built-in. They're typically used
// solo -- that is, as graphics primitives in themselves, not invoked by
// higher-level primitives (which should use the functions above).
void drawPixel(int16_t x, int16_t y, uint16_t color);
void fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color);
void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color);
void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color);
// A single-pixel push encapsulated in a transaction. I don't think
// this is used anymore (BMP demos might've used it?) but is provided
// for backward compatibility, consider it deprecated:
void pushColor(uint16_t color);
using Adafruit_GFX::drawRGBBitmap; // Check base class first
void drawRGBBitmap(int16_t x, int16_t y, uint16_t *pcolors, int16_t w,
int16_t h);
void invertDisplay(bool i);
uint16_t color565(uint8_t r, uint8_t g, uint8_t b);
// Despite parallel additions, function names kept for compatibility:
void spiWrite(uint8_t b); // Write single byte as DATA
void writeCommand(uint8_t cmd); // Write single byte as COMMAND
uint8_t spiRead(void); // Read single byte of data
void write16(uint16_t w); // Write 16-bit value as DATA
void writeCommand16(uint16_t cmd); // Write 16-bit value as COMMAND
uint16_t read16(void); // Read single 16-bit value
// Most of these low-level functions were formerly macros in
// Adafruit_SPITFT_Macros.h. Some have been made into inline functions
// to avoid macro mishaps. Despite the addition of code for a parallel
// display interface, the names have been kept for backward
// compatibility (some subclasses may be invoking these):
void SPI_WRITE16(uint16_t w); // Not inline
void SPI_WRITE32(uint32_t l); // Not inline
// Old code had both a spiWrite16() function and SPI_WRITE16 macro
// in addition to the SPI_WRITE32 macro. The latter two have been
// made into functions here, and spiWrite16() removed (use SPI_WRITE16()
// instead). It looks like most subclasses had gotten comfortable with
// SPI_WRITE16 and SPI_WRITE32 anyway so those names were kept rather
// than the less-obnoxious camelcase variants, oh well.
// Placing these functions entirely in the class definition inlines
// them implicitly them while allowing their use in other code:
/*!
@brief Set the chip-select line HIGH. Does NOT check whether CS pin
is set (>=0), that should be handled in calling function.
Despite function name, this is used even if the display
connection is parallel.
*/
void SPI_CS_HIGH(void) {
#if defined(USE_FAST_PINIO)
#if defined(HAS_PORT_SET_CLR)
#if defined(KINETISK)
*csPortSet = 1;
#else // !KINETISK
*csPortSet = csPinMask;
#endif // end !KINETISK
#else // !HAS_PORT_SET_CLR
*csPort |= csPinMaskSet;
#endif // end !HAS_PORT_SET_CLR
#else // !USE_FAST_PINIO
digitalWrite(_cs, HIGH);
#endif // end !USE_FAST_PINIO
}
/*!
@brief Set the chip-select line LOW. Does NOT check whether CS pin
is set (>=0), that should be handled in calling function.
Despite function name, this is used even if the display
connection is parallel.
*/
void SPI_CS_LOW(void) {
#if defined(USE_FAST_PINIO)
#if defined(HAS_PORT_SET_CLR)
#if defined(KINETISK)
*csPortClr = 1;
#else // !KINETISK
*csPortClr = csPinMask;
#endif // end !KINETISK
#else // !HAS_PORT_SET_CLR
*csPort &= csPinMaskClr;
#endif // end !HAS_PORT_SET_CLR
#else // !USE_FAST_PINIO
digitalWrite(_cs, LOW);
#endif // end !USE_FAST_PINIO
}
/*!
@brief Set the data/command line HIGH (data mode).
*/
void SPI_DC_HIGH(void) {
#if defined(USE_FAST_PINIO)
#if defined(HAS_PORT_SET_CLR)
#if defined(KINETISK)
*dcPortSet = 1;
#else // !KINETISK
*dcPortSet = dcPinMask;
#endif // end !KINETISK
#else // !HAS_PORT_SET_CLR
*dcPort |= dcPinMaskSet;
#endif // end !HAS_PORT_SET_CLR
#else // !USE_FAST_PINIO
digitalWrite(_dc, HIGH);
#endif // end !USE_FAST_PINIO
}
/*!
@brief Set the data/command line LOW (command mode).
*/
void SPI_DC_LOW(void) {
#if defined(USE_FAST_PINIO)
#if defined(HAS_PORT_SET_CLR)
#if defined(KINETISK)
*dcPortClr = 1;
#else // !KINETISK
*dcPortClr = dcPinMask;
#endif // end !KINETISK
#else // !HAS_PORT_SET_CLR
*dcPort &= dcPinMaskClr;
#endif // end !HAS_PORT_SET_CLR
#else // !USE_FAST_PINIO
digitalWrite(_dc, LOW);
#endif // end !USE_FAST_PINIO
}
protected:
// A few more low-level member functions -- some may have previously
// been macros. Shouldn't have a need to access these externally, so
// they've been moved to the protected section. Additionally, they're
// declared inline here and the code is in the .cpp file, since outside
// code doesn't need to see these.
inline void SPI_MOSI_HIGH(void);
inline void SPI_MOSI_LOW(void);
inline void SPI_SCK_HIGH(void);
inline void SPI_SCK_LOW(void);
inline bool SPI_MISO_READ(void);
inline void SPI_BEGIN_TRANSACTION(void);
inline void SPI_END_TRANSACTION(void);
inline void TFT_WR_STROBE(void); // Parallel interface write strobe
inline void TFT_RD_HIGH(void); // Parallel interface read high
inline void TFT_RD_LOW(void); // Parallel interface read low
// CLASS INSTANCE VARIABLES --------------------------------------------
// Here be dragons! There's a big union of three structures here --
// one each for hardware SPI, software (bitbang) SPI, and parallel
// interfaces. This is to save some memory, since a display's connection
// will be only one of these. The order of some things is a little weird
// in an attempt to get values to align and pack better in RAM.
#if defined(USE_FAST_PINIO)
#if defined(HAS_PORT_SET_CLR)
PORTreg_t csPortSet; ///< PORT register for chip select SET
PORTreg_t csPortClr; ///< PORT register for chip select CLEAR
PORTreg_t dcPortSet; ///< PORT register for data/command SET
PORTreg_t dcPortClr; ///< PORT register for data/command CLEAR
#else // !HAS_PORT_SET_CLR
PORTreg_t csPort; ///< PORT register for chip select
PORTreg_t dcPort; ///< PORT register for data/command
#endif // end HAS_PORT_SET_CLR
#endif // end USE_FAST_PINIO
#if defined(__cplusplus) && (__cplusplus >= 201100)
union {
#endif
struct { // Values specific to HARDWARE SPI:
SPIClass *_spi; ///< SPI class pointer
#if defined(SPI_HAS_TRANSACTION)
SPISettings settings; ///< SPI transaction settings
#else
uint32_t _freq; ///< SPI bitrate (if no SPI transactions)
#endif
uint32_t _mode; ///< SPI data mode (transactions or no)
} hwspi; ///< Hardware SPI values
struct { // Values specific to SOFTWARE SPI:
#if defined(USE_FAST_PINIO)
PORTreg_t misoPort; ///< PORT (PIN) register for MISO
#if defined(HAS_PORT_SET_CLR)
PORTreg_t mosiPortSet; ///< PORT register for MOSI SET
PORTreg_t mosiPortClr; ///< PORT register for MOSI CLEAR
PORTreg_t sckPortSet; ///< PORT register for SCK SET
PORTreg_t sckPortClr; ///< PORT register for SCK CLEAR
#if !defined(KINETISK)
ADAGFX_PORT_t mosiPinMask; ///< Bitmask for MOSI
ADAGFX_PORT_t sckPinMask; ///< Bitmask for SCK
#endif // end !KINETISK
#else // !HAS_PORT_SET_CLR
PORTreg_t mosiPort; ///< PORT register for MOSI
PORTreg_t sckPort; ///< PORT register for SCK
ADAGFX_PORT_t mosiPinMaskSet; ///< Bitmask for MOSI SET (OR)
ADAGFX_PORT_t mosiPinMaskClr; ///< Bitmask for MOSI CLEAR (AND)
ADAGFX_PORT_t sckPinMaskSet; ///< Bitmask for SCK SET (OR bitmask)
ADAGFX_PORT_t sckPinMaskClr; ///< Bitmask for SCK CLEAR (AND)
#endif // end HAS_PORT_SET_CLR
#if !defined(KINETISK)
ADAGFX_PORT_t misoPinMask; ///< Bitmask for MISO
#endif // end !KINETISK
#endif // end USE_FAST_PINIO
int8_t _mosi; ///< MOSI pin #
int8_t _miso; ///< MISO pin #
int8_t _sck; ///< SCK pin #
} swspi; ///< Software SPI values
struct { // Values specific to 8-bit parallel:
#if defined(USE_FAST_PINIO)
#if defined(__IMXRT1052__) || defined(__IMXRT1062__) // Teensy 4.x
volatile uint32_t *writePort; ///< PORT register for DATA WRITE
volatile uint32_t *readPort; ///< PORT (PIN) register for DATA READ
#else
volatile uint8_t *writePort; ///< PORT register for DATA WRITE
volatile uint8_t *readPort; ///< PORT (PIN) register for DATA READ
#endif
#if defined(HAS_PORT_SET_CLR)
// Port direction register pointers are always 8-bit regardless of
// PORTreg_t -- even if 32-bit port, we modify a byte-aligned 8 bits.
#if defined(__IMXRT1052__) || defined(__IMXRT1062__) // Teensy 4.x
volatile uint32_t *dirSet; ///< PORT byte data direction SET
volatile uint32_t *dirClr; ///< PORT byte data direction CLEAR
#else
volatile uint8_t *dirSet; ///< PORT byte data direction SET
volatile uint8_t *dirClr; ///< PORT byte data direction CLEAR
#endif
PORTreg_t wrPortSet; ///< PORT register for write strobe SET
PORTreg_t wrPortClr; ///< PORT register for write strobe CLEAR
PORTreg_t rdPortSet; ///< PORT register for read strobe SET
PORTreg_t rdPortClr; ///< PORT register for read strobe CLEAR
#if !defined(KINETISK)
ADAGFX_PORT_t wrPinMask; ///< Bitmask for write strobe
#endif // end !KINETISK
ADAGFX_PORT_t rdPinMask; ///< Bitmask for read strobe
#else // !HAS_PORT_SET_CLR
// Port direction register pointer is always 8-bit regardless of
// PORTreg_t -- even if 32-bit port, we modify a byte-aligned 8 bits.
volatile uint8_t *portDir; ///< PORT direction register
PORTreg_t wrPort; ///< PORT register for write strobe
PORTreg_t rdPort; ///< PORT register for read strobe
ADAGFX_PORT_t wrPinMaskSet; ///< Bitmask for write strobe SET (OR)
ADAGFX_PORT_t wrPinMaskClr; ///< Bitmask for write strobe CLEAR (AND)
ADAGFX_PORT_t rdPinMaskSet; ///< Bitmask for read strobe SET (OR)
ADAGFX_PORT_t rdPinMaskClr; ///< Bitmask for read strobe CLEAR (AND)
#endif // end HAS_PORT_SET_CLR
#endif // end USE_FAST_PINIO
int8_t _d0; ///< Data pin 0 #
int8_t _wr; ///< Write strobe pin #
int8_t _rd; ///< Read strobe pin # (or -1)
bool wide = 0; ///< If true, is 16-bit interface
} tft8; ///< Parallel interface settings
#if defined(__cplusplus) && (__cplusplus >= 201100)
}; ///< Only one interface is active
#endif
#if defined(USE_SPI_DMA) && \
(defined(__SAMD51__) || \
defined(ARDUINO_SAMD_ZERO)) // Used by hardware SPI and tft8
Adafruit_ZeroDMA dma; ///< DMA instance
DmacDescriptor *dptr = NULL; ///< 1st descriptor
DmacDescriptor *descriptor = NULL; ///< Allocated descriptor list
uint16_t *pixelBuf[2]; ///< Working buffers
uint16_t maxFillLen; ///< Max pixels per DMA xfer
uint16_t lastFillColor = 0; ///< Last color used w/fill
uint32_t lastFillLen = 0; ///< # of pixels w/last fill
uint8_t onePixelBuf; ///< For hi==lo fill
#endif
#if defined(USE_FAST_PINIO)
#if defined(HAS_PORT_SET_CLR)
#if !defined(KINETISK)
ADAGFX_PORT_t csPinMask; ///< Bitmask for chip select
ADAGFX_PORT_t dcPinMask; ///< Bitmask for data/command
#endif // end !KINETISK
#else // !HAS_PORT_SET_CLR
ADAGFX_PORT_t csPinMaskSet; ///< Bitmask for chip select SET (OR)
ADAGFX_PORT_t csPinMaskClr; ///< Bitmask for chip select CLEAR (AND)
ADAGFX_PORT_t dcPinMaskSet; ///< Bitmask for data/command SET (OR)
ADAGFX_PORT_t dcPinMaskClr; ///< Bitmask for data/command CLEAR (AND)
#endif // end HAS_PORT_SET_CLR
#endif // end USE_FAST_PINIO
uint8_t connection; ///< TFT_HARD_SPI, TFT_SOFT_SPI, etc.
int8_t _rst; ///< Reset pin # (or -1)
int8_t _cs; ///< Chip select pin # (or -1)
int8_t _dc; ///< Data/command pin #
int16_t _xstart = 0; ///< Internal framebuffer X offset
int16_t _ystart = 0; ///< Internal framebuffer Y offset
uint8_t invertOnCommand = 0; ///< Command to enable invert mode
uint8_t invertOffCommand = 0; ///< Command to disable invert mode
uint32_t _freq = 0; ///< Dummy var to keep subclasses happy
};
#endif // end __AVR_ATtiny85__ __AVR_ATtiny84__
#endif // end _ADAFRUIT_SPITFT_H_

View File

@@ -0,0 +1,6 @@
// THIS FILE INTENTIONALLY LEFT BLANK.
// Macros previously #defined here have been made into (mostly) inline
// functions in the Adafruit_SPITFT class. Other libraries might still
// contain code trying to #include this header file, so until everything's
// updated this file still exists (but doing nothing) to avoid trouble.

View File

@@ -0,0 +1,11 @@
# Adafruit GFX Library
# https://github.com/adafruit/Adafruit-GFX-Library
# BSD License
cmake_minimum_required(VERSION 3.5)
idf_component_register(SRCS "Adafruit_GFX.cpp" "Adafruit_GrayOLED.cpp" "Adafruit_SPITFT.cpp" "glcdfont.c"
INCLUDE_DIRS "."
REQUIRES arduino Adafruit_BusIO)
project(Adafruit-GFX-Library)

View File

@@ -0,0 +1,229 @@
#pragma once
#include <Adafruit_GFX.h>
const uint8_t FreeMono12pt7bBitmaps[] PROGMEM = {
0x49, 0x24, 0x92, 0x48, 0x01, 0xF8, 0xE7, 0xE7, 0x67, 0x42, 0x42, 0x42,
0x42, 0x09, 0x02, 0x41, 0x10, 0x44, 0x11, 0x1F, 0xF1, 0x10, 0x4C, 0x12,
0x3F, 0xE1, 0x20, 0x48, 0x12, 0x04, 0x81, 0x20, 0x48, 0x04, 0x07, 0xA2,
0x19, 0x02, 0x40, 0x10, 0x03, 0x00, 0x3C, 0x00, 0x80, 0x10, 0x06, 0x01,
0xE0, 0xA7, 0xC0, 0x40, 0x10, 0x04, 0x00, 0x3C, 0x19, 0x84, 0x21, 0x08,
0x66, 0x0F, 0x00, 0x0C, 0x1C, 0x78, 0x01, 0xE0, 0xCC, 0x21, 0x08, 0x43,
0x30, 0x78, 0x3E, 0x30, 0x10, 0x08, 0x02, 0x03, 0x03, 0x47, 0x14, 0x8A,
0x43, 0x11, 0x8F, 0x60, 0xFD, 0xA4, 0x90, 0x05, 0x25, 0x24, 0x92, 0x48,
0x92, 0x24, 0x11, 0x24, 0x89, 0x24, 0x92, 0x92, 0x90, 0x00, 0x04, 0x02,
0x11, 0x07, 0xF0, 0xC0, 0x50, 0x48, 0x42, 0x00, 0x08, 0x04, 0x02, 0x01,
0x00, 0x87, 0xFC, 0x20, 0x10, 0x08, 0x04, 0x02, 0x00, 0x3B, 0x9C, 0xCE,
0x62, 0x00, 0xFF, 0xE0, 0xFF, 0x80, 0x00, 0x80, 0xC0, 0x40, 0x20, 0x20,
0x10, 0x10, 0x08, 0x08, 0x04, 0x04, 0x02, 0x02, 0x01, 0x01, 0x00, 0x80,
0x80, 0x40, 0x00, 0x1C, 0x31, 0x90, 0x58, 0x38, 0x0C, 0x06, 0x03, 0x01,
0x80, 0xC0, 0x60, 0x30, 0x34, 0x13, 0x18, 0x70, 0x30, 0xE1, 0x44, 0x81,
0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x81, 0x1F, 0xC0, 0x1E, 0x10, 0x90,
0x68, 0x10, 0x08, 0x0C, 0x04, 0x04, 0x04, 0x06, 0x06, 0x06, 0x06, 0x0E,
0x07, 0xFE, 0x3E, 0x10, 0x40, 0x08, 0x02, 0x00, 0x80, 0x40, 0xE0, 0x04,
0x00, 0x80, 0x10, 0x04, 0x01, 0x00, 0xD8, 0x63, 0xE0, 0x06, 0x0A, 0x0A,
0x12, 0x22, 0x22, 0x42, 0x42, 0x82, 0x82, 0xFF, 0x02, 0x02, 0x02, 0x0F,
0x7F, 0x20, 0x10, 0x08, 0x04, 0x02, 0xF1, 0x8C, 0x03, 0x00, 0x80, 0x40,
0x20, 0x18, 0x16, 0x18, 0xF0, 0x0F, 0x8C, 0x08, 0x08, 0x04, 0x04, 0x02,
0x79, 0x46, 0xC1, 0xE0, 0x60, 0x28, 0x14, 0x19, 0x08, 0x78, 0xFF, 0x81,
0x81, 0x02, 0x02, 0x02, 0x02, 0x04, 0x04, 0x04, 0x04, 0x08, 0x08, 0x08,
0x08, 0x3E, 0x31, 0xB0, 0x70, 0x18, 0x0C, 0x05, 0x8C, 0x38, 0x63, 0x40,
0x60, 0x30, 0x18, 0x1B, 0x18, 0xF8, 0x3C, 0x31, 0x30, 0x50, 0x28, 0x0C,
0x0F, 0x06, 0x85, 0x3C, 0x80, 0x40, 0x40, 0x20, 0x20, 0x63, 0xE0, 0xFF,
0x80, 0x07, 0xFC, 0x39, 0xCE, 0x00, 0x00, 0x06, 0x33, 0x98, 0xC4, 0x00,
0x00, 0xC0, 0x60, 0x18, 0x0C, 0x06, 0x01, 0x80, 0x0C, 0x00, 0x60, 0x03,
0x00, 0x30, 0x01, 0x00, 0xFF, 0xF0, 0x00, 0x00, 0x0F, 0xFF, 0xC0, 0x06,
0x00, 0x30, 0x01, 0x80, 0x18, 0x01, 0x80, 0xC0, 0x30, 0x18, 0x0C, 0x02,
0x00, 0x00, 0x3E, 0x60, 0xA0, 0x20, 0x10, 0x08, 0x08, 0x18, 0x10, 0x08,
0x00, 0x00, 0x00, 0x01, 0xC0, 0xE0, 0x1C, 0x31, 0x10, 0x50, 0x28, 0x14,
0x3A, 0x25, 0x22, 0x91, 0x4C, 0xA3, 0xF0, 0x08, 0x02, 0x01, 0x80, 0x7C,
0x3F, 0x00, 0x0C, 0x00, 0x48, 0x01, 0x20, 0x04, 0x40, 0x21, 0x00, 0x84,
0x04, 0x08, 0x1F, 0xE0, 0x40, 0x82, 0x01, 0x08, 0x04, 0x20, 0x13, 0xE1,
0xF0, 0xFF, 0x08, 0x11, 0x01, 0x20, 0x24, 0x04, 0x81, 0x1F, 0xC2, 0x06,
0x40, 0x68, 0x05, 0x00, 0xA0, 0x14, 0x05, 0xFF, 0x00, 0x1E, 0x48, 0x74,
0x05, 0x01, 0x80, 0x20, 0x08, 0x02, 0x00, 0x80, 0x20, 0x04, 0x01, 0x01,
0x30, 0x87, 0xC0, 0xFE, 0x10, 0x44, 0x09, 0x02, 0x40, 0x50, 0x14, 0x05,
0x01, 0x40, 0x50, 0x14, 0x0D, 0x02, 0x41, 0x3F, 0x80, 0xFF, 0xC8, 0x09,
0x01, 0x20, 0x04, 0x00, 0x88, 0x1F, 0x02, 0x20, 0x40, 0x08, 0x01, 0x00,
0xA0, 0x14, 0x03, 0xFF, 0xC0, 0xFF, 0xE8, 0x05, 0x00, 0xA0, 0x04, 0x00,
0x88, 0x1F, 0x02, 0x20, 0x40, 0x08, 0x01, 0x00, 0x20, 0x04, 0x01, 0xF0,
0x00, 0x1F, 0x46, 0x19, 0x01, 0x60, 0x28, 0x01, 0x00, 0x20, 0x04, 0x00,
0x83, 0xF0, 0x0B, 0x01, 0x20, 0x23, 0x0C, 0x3E, 0x00, 0xE1, 0xD0, 0x24,
0x09, 0x02, 0x40, 0x90, 0x27, 0xF9, 0x02, 0x40, 0x90, 0x24, 0x09, 0x02,
0x40, 0xB8, 0x70, 0xFE, 0x20, 0x40, 0x81, 0x02, 0x04, 0x08, 0x10, 0x20,
0x40, 0x81, 0x1F, 0xC0, 0x0F, 0xE0, 0x10, 0x02, 0x00, 0x40, 0x08, 0x01,
0x00, 0x20, 0x04, 0x80, 0x90, 0x12, 0x02, 0x40, 0xC6, 0x30, 0x7C, 0x00,
0xF1, 0xE4, 0x0C, 0x41, 0x04, 0x20, 0x44, 0x04, 0x80, 0x5C, 0x06, 0x60,
0x43, 0x04, 0x10, 0x40, 0x84, 0x08, 0x40, 0xCF, 0x07, 0xF8, 0x04, 0x00,
0x80, 0x10, 0x02, 0x00, 0x40, 0x08, 0x01, 0x00, 0x20, 0x04, 0x04, 0x80,
0x90, 0x12, 0x03, 0xFF, 0xC0, 0xE0, 0x3B, 0x01, 0x94, 0x14, 0xA0, 0xA4,
0x89, 0x24, 0x49, 0x14, 0x48, 0xA2, 0x45, 0x12, 0x10, 0x90, 0x04, 0x80,
0x24, 0x01, 0x78, 0x3C, 0xE0, 0xF6, 0x02, 0x50, 0x25, 0x02, 0x48, 0x24,
0xC2, 0x44, 0x24, 0x22, 0x43, 0x24, 0x12, 0x40, 0xA4, 0x0A, 0x40, 0x6F,
0x06, 0x0F, 0x03, 0x0C, 0x60, 0x64, 0x02, 0x80, 0x18, 0x01, 0x80, 0x18,
0x01, 0x80, 0x18, 0x01, 0x40, 0x26, 0x06, 0x30, 0xC0, 0xF0, 0xFF, 0x10,
0x64, 0x05, 0x01, 0x40, 0x50, 0x34, 0x19, 0xFC, 0x40, 0x10, 0x04, 0x01,
0x00, 0x40, 0x3E, 0x00, 0x0F, 0x03, 0x0C, 0x60, 0x64, 0x02, 0x80, 0x18,
0x01, 0x80, 0x18, 0x01, 0x80, 0x18, 0x01, 0x40, 0x26, 0x06, 0x30, 0xC1,
0xF0, 0x0C, 0x01, 0xF1, 0x30, 0xE0, 0xFF, 0x04, 0x18, 0x40, 0xC4, 0x04,
0x40, 0x44, 0x0C, 0x41, 0x87, 0xE0, 0x43, 0x04, 0x10, 0x40, 0x84, 0x04,
0x40, 0x4F, 0x03, 0x1F, 0x48, 0x34, 0x05, 0x01, 0x40, 0x08, 0x01, 0xC0,
0x0E, 0x00, 0x40, 0x18, 0x06, 0x01, 0xE1, 0xA7, 0xC0, 0xFF, 0xF0, 0x86,
0x10, 0x82, 0x00, 0x40, 0x08, 0x01, 0x00, 0x20, 0x04, 0x00, 0x80, 0x10,
0x02, 0x00, 0x40, 0x7F, 0x00, 0xF0, 0xF4, 0x02, 0x40, 0x24, 0x02, 0x40,
0x24, 0x02, 0x40, 0x24, 0x02, 0x40, 0x24, 0x02, 0x40, 0x22, 0x04, 0x30,
0xC0, 0xF0, 0xF8, 0x7C, 0x80, 0x22, 0x01, 0x04, 0x04, 0x10, 0x20, 0x40,
0x80, 0x82, 0x02, 0x10, 0x08, 0x40, 0x11, 0x00, 0x48, 0x01, 0xA0, 0x03,
0x00, 0x0C, 0x00, 0xF8, 0x7C, 0x80, 0x22, 0x00, 0x88, 0xC2, 0x23, 0x10,
0x8E, 0x42, 0x29, 0x09, 0x24, 0x24, 0x90, 0x91, 0x41, 0x85, 0x06, 0x14,
0x18, 0x70, 0x60, 0x80, 0xF0, 0xF2, 0x06, 0x30, 0x41, 0x08, 0x09, 0x80,
0x50, 0x06, 0x00, 0x60, 0x0D, 0x00, 0x88, 0x10, 0xC2, 0x04, 0x60, 0x2F,
0x0F, 0xF0, 0xF2, 0x02, 0x10, 0x41, 0x04, 0x08, 0x80, 0x50, 0x05, 0x00,
0x20, 0x02, 0x00, 0x20, 0x02, 0x00, 0x20, 0x02, 0x01, 0xFC, 0xFF, 0x40,
0xA0, 0x90, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x10, 0x50, 0x30, 0x18,
0x0F, 0xFC, 0xF2, 0x49, 0x24, 0x92, 0x49, 0x24, 0x9C, 0x80, 0x60, 0x10,
0x08, 0x02, 0x01, 0x00, 0x40, 0x20, 0x08, 0x04, 0x01, 0x00, 0x80, 0x20,
0x10, 0x04, 0x02, 0x00, 0x80, 0x40, 0xE4, 0x92, 0x49, 0x24, 0x92, 0x49,
0x3C, 0x08, 0x0C, 0x09, 0x0C, 0x4C, 0x14, 0x04, 0xFF, 0xFC, 0x84, 0x21,
0x3E, 0x00, 0x60, 0x08, 0x02, 0x3F, 0x98, 0x28, 0x0A, 0x02, 0xC3, 0x9F,
0x30, 0xE0, 0x01, 0x00, 0x08, 0x00, 0x40, 0x02, 0x00, 0x13, 0xE0, 0xA0,
0x86, 0x02, 0x20, 0x09, 0x00, 0x48, 0x02, 0x40, 0x13, 0x01, 0x14, 0x1B,
0x9F, 0x00, 0x1F, 0x4C, 0x19, 0x01, 0x40, 0x28, 0x01, 0x00, 0x20, 0x02,
0x00, 0x60, 0x43, 0xF0, 0x00, 0xC0, 0x08, 0x01, 0x00, 0x20, 0x04, 0x3C,
0x98, 0x52, 0x06, 0x80, 0x50, 0x0A, 0x01, 0x40, 0x24, 0x0C, 0xC2, 0x87,
0x98, 0x3F, 0x18, 0x68, 0x06, 0x01, 0xFF, 0xE0, 0x08, 0x03, 0x00, 0x60,
0xC7, 0xC0, 0x0F, 0x98, 0x08, 0x04, 0x02, 0x07, 0xF8, 0x80, 0x40, 0x20,
0x10, 0x08, 0x04, 0x02, 0x01, 0x03, 0xF8, 0x1E, 0x6C, 0x39, 0x03, 0x40,
0x28, 0x05, 0x00, 0xA0, 0x12, 0x06, 0x61, 0x43, 0xC8, 0x01, 0x00, 0x20,
0x08, 0x3E, 0x00, 0xC0, 0x10, 0x04, 0x01, 0x00, 0x40, 0x13, 0x87, 0x11,
0x82, 0x40, 0x90, 0x24, 0x09, 0x02, 0x40, 0x90, 0x2E, 0x1C, 0x08, 0x04,
0x02, 0x00, 0x00, 0x03, 0xC0, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, 0x00,
0x80, 0x43, 0xFE, 0x04, 0x08, 0x10, 0x00, 0x1F, 0xC0, 0x81, 0x02, 0x04,
0x08, 0x10, 0x20, 0x40, 0x81, 0x02, 0x0B, 0xE0, 0xE0, 0x02, 0x00, 0x20,
0x02, 0x00, 0x20, 0x02, 0x3C, 0x21, 0x02, 0x60, 0x2C, 0x03, 0x80, 0x24,
0x02, 0x20, 0x21, 0x02, 0x08, 0xE1, 0xF0, 0x78, 0x04, 0x02, 0x01, 0x00,
0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, 0x00, 0x80, 0x43, 0xFE,
0xDC, 0xE3, 0x19, 0x90, 0x84, 0x84, 0x24, 0x21, 0x21, 0x09, 0x08, 0x48,
0x42, 0x42, 0x17, 0x18, 0xC0, 0x67, 0x83, 0x84, 0x20, 0x22, 0x02, 0x20,
0x22, 0x02, 0x20, 0x22, 0x02, 0x20, 0x2F, 0x07, 0x1F, 0x04, 0x11, 0x01,
0x40, 0x18, 0x03, 0x00, 0x60, 0x0A, 0x02, 0x20, 0x83, 0xE0, 0xCF, 0x85,
0x06, 0x60, 0x24, 0x01, 0x40, 0x14, 0x01, 0x40, 0x16, 0x02, 0x50, 0x44,
0xF8, 0x40, 0x04, 0x00, 0x40, 0x0F, 0x00, 0x1E, 0x6C, 0x3B, 0x03, 0x40,
0x28, 0x05, 0x00, 0xA0, 0x12, 0x06, 0x61, 0x43, 0xC8, 0x01, 0x00, 0x20,
0x04, 0x03, 0xC0, 0xE3, 0x8B, 0x13, 0x80, 0x80, 0x20, 0x08, 0x02, 0x00,
0x80, 0x20, 0x3F, 0x80, 0x1F, 0x58, 0x34, 0x05, 0x80, 0x1E, 0x00, 0x60,
0x06, 0x01, 0xC0, 0xAF, 0xC0, 0x20, 0x04, 0x00, 0x80, 0x10, 0x0F, 0xF0,
0x40, 0x08, 0x01, 0x00, 0x20, 0x04, 0x00, 0x80, 0x10, 0x03, 0x04, 0x3F,
0x00, 0xC1, 0xC8, 0x09, 0x01, 0x20, 0x24, 0x04, 0x80, 0x90, 0x12, 0x02,
0x61, 0xC7, 0xCC, 0xF8, 0xF9, 0x01, 0x08, 0x10, 0x60, 0x81, 0x08, 0x08,
0x40, 0x22, 0x01, 0x20, 0x05, 0x00, 0x30, 0x00, 0xF0, 0x7A, 0x01, 0x10,
0x08, 0x8C, 0x42, 0x62, 0x12, 0x90, 0xA5, 0x05, 0x18, 0x28, 0xC0, 0x86,
0x00, 0x78, 0xF3, 0x04, 0x18, 0x80, 0xD0, 0x06, 0x00, 0x70, 0x09, 0x81,
0x0C, 0x20, 0x6F, 0x8F, 0xF0, 0xF2, 0x02, 0x20, 0x41, 0x04, 0x10, 0x80,
0x88, 0x09, 0x00, 0x50, 0x06, 0x00, 0x20, 0x04, 0x00, 0x40, 0x08, 0x0F,
0xE0, 0xFF, 0x41, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x40, 0xBF,
0xC0, 0x19, 0x08, 0x42, 0x10, 0x84, 0x64, 0x18, 0x42, 0x10, 0x84, 0x20,
0xC0, 0xFF, 0xFF, 0xC0, 0xC1, 0x08, 0x42, 0x10, 0x84, 0x10, 0x4C, 0x42,
0x10, 0x84, 0x26, 0x00, 0x38, 0x13, 0x38, 0x38};
const GFXglyph FreeMono12pt7bGlyphs[] PROGMEM = {
{0, 0, 0, 14, 0, 1}, // 0x20 ' '
{0, 3, 15, 14, 6, -14}, // 0x21 '!'
{6, 8, 7, 14, 3, -14}, // 0x22 '"'
{13, 10, 16, 14, 2, -14}, // 0x23 '#'
{33, 10, 17, 14, 2, -14}, // 0x24 '$'
{55, 10, 15, 14, 2, -14}, // 0x25 '%'
{74, 9, 12, 14, 3, -11}, // 0x26 '&'
{88, 3, 7, 14, 5, -14}, // 0x27 '''
{91, 3, 18, 14, 7, -14}, // 0x28 '('
{98, 3, 18, 14, 4, -14}, // 0x29 ')'
{105, 9, 9, 14, 3, -14}, // 0x2A '*'
{116, 9, 11, 14, 3, -11}, // 0x2B '+'
{129, 5, 7, 14, 3, -3}, // 0x2C ','
{134, 11, 1, 14, 2, -6}, // 0x2D '-'
{136, 3, 3, 14, 5, -2}, // 0x2E '.'
{138, 9, 18, 14, 3, -15}, // 0x2F '/'
{159, 9, 15, 14, 3, -14}, // 0x30 '0'
{176, 7, 14, 14, 4, -13}, // 0x31 '1'
{189, 9, 15, 14, 2, -14}, // 0x32 '2'
{206, 10, 15, 14, 2, -14}, // 0x33 '3'
{225, 8, 15, 14, 3, -14}, // 0x34 '4'
{240, 9, 15, 14, 3, -14}, // 0x35 '5'
{257, 9, 15, 14, 3, -14}, // 0x36 '6'
{274, 8, 15, 14, 3, -14}, // 0x37 '7'
{289, 9, 15, 14, 3, -14}, // 0x38 '8'
{306, 9, 15, 14, 3, -14}, // 0x39 '9'
{323, 3, 10, 14, 5, -9}, // 0x3A ':'
{327, 5, 13, 14, 3, -9}, // 0x3B ';'
{336, 11, 11, 14, 2, -11}, // 0x3C '<'
{352, 12, 4, 14, 1, -8}, // 0x3D '='
{358, 11, 11, 14, 2, -11}, // 0x3E '>'
{374, 9, 14, 14, 3, -13}, // 0x3F '?'
{390, 9, 16, 14, 3, -14}, // 0x40 '@'
{408, 14, 14, 14, 0, -13}, // 0x41 'A'
{433, 11, 14, 14, 2, -13}, // 0x42 'B'
{453, 10, 14, 14, 2, -13}, // 0x43 'C'
{471, 10, 14, 14, 2, -13}, // 0x44 'D'
{489, 11, 14, 14, 2, -13}, // 0x45 'E'
{509, 11, 14, 14, 2, -13}, // 0x46 'F'
{529, 11, 14, 14, 2, -13}, // 0x47 'G'
{549, 10, 14, 14, 2, -13}, // 0x48 'H'
{567, 7, 14, 14, 4, -13}, // 0x49 'I'
{580, 11, 14, 14, 2, -13}, // 0x4A 'J'
{600, 12, 14, 14, 2, -13}, // 0x4B 'K'
{621, 11, 14, 14, 2, -13}, // 0x4C 'L'
{641, 13, 14, 14, 1, -13}, // 0x4D 'M'
{664, 12, 14, 14, 1, -13}, // 0x4E 'N'
{685, 12, 14, 14, 1, -13}, // 0x4F 'O'
{706, 10, 14, 14, 2, -13}, // 0x50 'P'
{724, 12, 17, 14, 1, -13}, // 0x51 'Q'
{750, 12, 14, 14, 2, -13}, // 0x52 'R'
{771, 10, 14, 14, 2, -13}, // 0x53 'S'
{789, 11, 14, 14, 2, -13}, // 0x54 'T'
{809, 12, 14, 14, 1, -13}, // 0x55 'U'
{830, 14, 14, 14, 0, -13}, // 0x56 'V'
{855, 14, 14, 14, 0, -13}, // 0x57 'W'
{880, 12, 14, 14, 1, -13}, // 0x58 'X'
{901, 12, 14, 14, 1, -13}, // 0x59 'Y'
{922, 9, 14, 14, 3, -13}, // 0x5A 'Z'
{938, 3, 18, 14, 7, -14}, // 0x5B '['
{945, 9, 18, 14, 3, -15}, // 0x5C '\'
{966, 3, 18, 14, 5, -14}, // 0x5D ']'
{973, 9, 6, 14, 3, -14}, // 0x5E '^'
{980, 14, 1, 14, 0, 3}, // 0x5F '_'
{982, 4, 4, 14, 4, -15}, // 0x60 '`'
{984, 10, 10, 14, 2, -9}, // 0x61 'a'
{997, 13, 15, 14, 0, -14}, // 0x62 'b'
{1022, 11, 10, 14, 2, -9}, // 0x63 'c'
{1036, 11, 15, 14, 2, -14}, // 0x64 'd'
{1057, 10, 10, 14, 2, -9}, // 0x65 'e'
{1070, 9, 15, 14, 4, -14}, // 0x66 'f'
{1087, 11, 14, 14, 2, -9}, // 0x67 'g'
{1107, 10, 15, 14, 2, -14}, // 0x68 'h'
{1126, 9, 15, 14, 3, -14}, // 0x69 'i'
{1143, 7, 19, 14, 3, -14}, // 0x6A 'j'
{1160, 12, 15, 14, 1, -14}, // 0x6B 'k'
{1183, 9, 15, 14, 3, -14}, // 0x6C 'l'
{1200, 13, 10, 14, 1, -9}, // 0x6D 'm'
{1217, 12, 10, 14, 1, -9}, // 0x6E 'n'
{1232, 11, 10, 14, 2, -9}, // 0x6F 'o'
{1246, 12, 14, 14, 1, -9}, // 0x70 'p'
{1267, 11, 14, 14, 2, -9}, // 0x71 'q'
{1287, 10, 10, 14, 3, -9}, // 0x72 'r'
{1300, 10, 10, 14, 2, -9}, // 0x73 's'
{1313, 11, 14, 14, 1, -13}, // 0x74 't'
{1333, 11, 10, 14, 2, -9}, // 0x75 'u'
{1347, 13, 10, 14, 1, -9}, // 0x76 'v'
{1364, 13, 10, 14, 1, -9}, // 0x77 'w'
{1381, 12, 10, 14, 1, -9}, // 0x78 'x'
{1396, 12, 14, 14, 1, -9}, // 0x79 'y'
{1417, 9, 10, 14, 3, -9}, // 0x7A 'z'
{1429, 5, 18, 14, 5, -14}, // 0x7B '{'
{1441, 1, 18, 14, 7, -14}, // 0x7C '|'
{1444, 5, 18, 14, 5, -14}, // 0x7D '}'
{1456, 10, 3, 14, 2, -7}}; // 0x7E '~'
const GFXfont FreeMono12pt7b PROGMEM = {(uint8_t *)FreeMono12pt7bBitmaps,
(GFXglyph *)FreeMono12pt7bGlyphs, 0x20,
0x7E, 24};
// Approx. 2132 bytes

View File

@@ -0,0 +1,365 @@
#pragma once
#include <Adafruit_GFX.h>
const uint8_t FreeMono18pt7bBitmaps[] PROGMEM = {
0x27, 0x77, 0x77, 0x77, 0x77, 0x22, 0x22, 0x20, 0x00, 0x6F, 0xF6, 0xF1,
0xFE, 0x3F, 0xC7, 0xF8, 0xFF, 0x1E, 0xC3, 0x98, 0x33, 0x06, 0x60, 0xCC,
0x18, 0x04, 0x20, 0x10, 0x80, 0x42, 0x01, 0x08, 0x04, 0x20, 0x10, 0x80,
0x42, 0x01, 0x10, 0x04, 0x41, 0xFF, 0xF0, 0x44, 0x02, 0x10, 0x08, 0x40,
0x21, 0x0F, 0xFF, 0xC2, 0x10, 0x08, 0x40, 0x21, 0x00, 0x84, 0x02, 0x10,
0x08, 0x40, 0x23, 0x00, 0x88, 0x02, 0x20, 0x02, 0x00, 0x10, 0x00, 0x80,
0x1F, 0xA3, 0x07, 0x10, 0x09, 0x00, 0x48, 0x00, 0x40, 0x03, 0x00, 0x0C,
0x00, 0x3C, 0x00, 0x1E, 0x00, 0x18, 0x00, 0x20, 0x01, 0x80, 0x0C, 0x00,
0x70, 0x05, 0xE0, 0xC9, 0xF8, 0x01, 0x00, 0x08, 0x00, 0x40, 0x02, 0x00,
0x10, 0x00, 0x1E, 0x00, 0x42, 0x01, 0x02, 0x02, 0x04, 0x04, 0x08, 0x08,
0x10, 0x08, 0x40, 0x0F, 0x00, 0x00, 0x1E, 0x01, 0xF0, 0x1F, 0x01, 0xE0,
0x0E, 0x00, 0x00, 0x3C, 0x00, 0x86, 0x02, 0x06, 0x04, 0x04, 0x08, 0x08,
0x10, 0x30, 0x10, 0xC0, 0x1E, 0x00, 0x0F, 0xC1, 0x00, 0x20, 0x02, 0x00,
0x20, 0x02, 0x00, 0x10, 0x01, 0x00, 0x08, 0x03, 0xC0, 0x6C, 0x3C, 0x62,
0x82, 0x68, 0x34, 0x81, 0xCC, 0x08, 0x61, 0xC3, 0xE7, 0xFF, 0xFF, 0xF6,
0x66, 0x66, 0x08, 0xC4, 0x62, 0x31, 0x8C, 0xC6, 0x31, 0x8C, 0x63, 0x18,
0xC3, 0x18, 0xC2, 0x18, 0xC3, 0x18, 0x86, 0x10, 0xC2, 0x18, 0xC6, 0x10,
0xC6, 0x31, 0x8C, 0x63, 0x18, 0x8C, 0x62, 0x31, 0x98, 0x80, 0x02, 0x00,
0x10, 0x00, 0x80, 0x04, 0x0C, 0x21, 0x9D, 0x70, 0x1C, 0x00, 0xA0, 0x0D,
0x80, 0xC6, 0x04, 0x10, 0x40, 0x80, 0x01, 0x00, 0x02, 0x00, 0x04, 0x00,
0x08, 0x00, 0x10, 0x00, 0x20, 0x00, 0x40, 0x00, 0x80, 0xFF, 0xFE, 0x02,
0x00, 0x04, 0x00, 0x08, 0x00, 0x10, 0x00, 0x20, 0x00, 0x40, 0x00, 0x80,
0x01, 0x00, 0x3E, 0x78, 0xF3, 0xC7, 0x8E, 0x18, 0x70, 0xC1, 0x80, 0xFF,
0xFE, 0x77, 0xFF, 0xF7, 0x00, 0x00, 0x08, 0x00, 0xC0, 0x04, 0x00, 0x60,
0x02, 0x00, 0x30, 0x01, 0x00, 0x18, 0x00, 0x80, 0x0C, 0x00, 0x40, 0x02,
0x00, 0x20, 0x01, 0x00, 0x10, 0x00, 0x80, 0x08, 0x00, 0x40, 0x04, 0x00,
0x20, 0x02, 0x00, 0x10, 0x01, 0x00, 0x08, 0x00, 0x80, 0x04, 0x00, 0x00,
0x0F, 0x81, 0x82, 0x08, 0x08, 0x80, 0x24, 0x01, 0x60, 0x0E, 0x00, 0x30,
0x01, 0x80, 0x0C, 0x00, 0x60, 0x03, 0x00, 0x18, 0x00, 0xC0, 0x06, 0x00,
0x30, 0x03, 0x40, 0x12, 0x00, 0x88, 0x08, 0x60, 0xC0, 0xF8, 0x00, 0x06,
0x00, 0x70, 0x06, 0x80, 0x64, 0x06, 0x20, 0x31, 0x00, 0x08, 0x00, 0x40,
0x02, 0x00, 0x10, 0x00, 0x80, 0x04, 0x00, 0x20, 0x01, 0x00, 0x08, 0x00,
0x40, 0x02, 0x00, 0x10, 0x00, 0x80, 0x04, 0x0F, 0xFF, 0x80, 0x0F, 0x80,
0xC3, 0x08, 0x04, 0x80, 0x24, 0x00, 0x80, 0x04, 0x00, 0x20, 0x02, 0x00,
0x10, 0x01, 0x00, 0x10, 0x01, 0x80, 0x18, 0x01, 0x80, 0x18, 0x01, 0x80,
0x18, 0x01, 0x80, 0x58, 0x03, 0x80, 0x1F, 0xFF, 0x80, 0x0F, 0xC0, 0xC0,
0x86, 0x01, 0x00, 0x02, 0x00, 0x08, 0x00, 0x20, 0x00, 0x80, 0x04, 0x00,
0x20, 0x0F, 0x00, 0x06, 0x00, 0x04, 0x00, 0x08, 0x00, 0x10, 0x00, 0x40,
0x01, 0x00, 0x04, 0x00, 0x2C, 0x01, 0x9C, 0x0C, 0x0F, 0xC0, 0x01, 0xC0,
0x14, 0x02, 0x40, 0x64, 0x04, 0x40, 0xC4, 0x08, 0x41, 0x84, 0x10, 0x42,
0x04, 0x20, 0x44, 0x04, 0x40, 0x48, 0x04, 0xFF, 0xF0, 0x04, 0x00, 0x40,
0x04, 0x00, 0x40, 0x04, 0x07, 0xF0, 0x3F, 0xF0, 0x80, 0x02, 0x00, 0x08,
0x00, 0x20, 0x00, 0x80, 0x02, 0x00, 0x0B, 0xF0, 0x30, 0x30, 0x00, 0x60,
0x00, 0x80, 0x01, 0x00, 0x04, 0x00, 0x10, 0x00, 0x40, 0x01, 0x00, 0x0E,
0x00, 0x2C, 0x01, 0x0C, 0x18, 0x0F, 0xC0, 0x01, 0xF0, 0x60, 0x18, 0x03,
0x00, 0x20, 0x04, 0x00, 0x40, 0x0C, 0x00, 0x80, 0x08, 0xF8, 0x98, 0x4A,
0x02, 0xE0, 0x3C, 0x01, 0x80, 0x14, 0x01, 0x40, 0x14, 0x03, 0x20, 0x21,
0x0C, 0x0F, 0x80, 0xFF, 0xF8, 0x01, 0x80, 0x18, 0x03, 0x00, 0x20, 0x02,
0x00, 0x20, 0x04, 0x00, 0x40, 0x04, 0x00, 0xC0, 0x08, 0x00, 0x80, 0x18,
0x01, 0x00, 0x10, 0x01, 0x00, 0x30, 0x02, 0x00, 0x20, 0x02, 0x00, 0x0F,
0x81, 0x83, 0x10, 0x05, 0x80, 0x38, 0x00, 0xC0, 0x06, 0x00, 0x30, 0x03,
0x40, 0x11, 0x83, 0x07, 0xF0, 0x60, 0xC4, 0x01, 0x60, 0x0E, 0x00, 0x30,
0x01, 0x80, 0x0E, 0x00, 0xD0, 0x04, 0x60, 0xC1, 0xFC, 0x00, 0x1F, 0x03,
0x08, 0x40, 0x4C, 0x02, 0x80, 0x28, 0x02, 0x80, 0x18, 0x03, 0xC0, 0x74,
0x05, 0x21, 0x91, 0xF1, 0x00, 0x10, 0x03, 0x00, 0x20, 0x02, 0x00, 0x40,
0x0C, 0x01, 0x80, 0x60, 0xF8, 0x00, 0x77, 0xFF, 0xF7, 0x00, 0x00, 0x00,
0x1D, 0xFF, 0xFD, 0xC0, 0x1C, 0x7C, 0xF9, 0xF1, 0xC0, 0x00, 0x00, 0x00,
0x00, 0xF1, 0xE3, 0x8F, 0x1C, 0x38, 0xE1, 0xC3, 0x06, 0x00, 0x00, 0x06,
0x00, 0x18, 0x00, 0xE0, 0x07, 0x00, 0x38, 0x01, 0xC0, 0x06, 0x00, 0x38,
0x00, 0xE0, 0x00, 0x70, 0x00, 0x38, 0x00, 0x18, 0x00, 0x1C, 0x00, 0x0E,
0x00, 0x07, 0x00, 0x03, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x07, 0xFF, 0xFC, 0xC0, 0x00, 0xC0, 0x00, 0xE0, 0x00, 0x70,
0x00, 0x38, 0x00, 0x1C, 0x00, 0x0C, 0x00, 0x0E, 0x00, 0x0E, 0x00, 0x70,
0x03, 0x80, 0x0C, 0x00, 0x70, 0x03, 0x80, 0x1C, 0x00, 0x60, 0x00, 0x3F,
0x8E, 0x0C, 0x80, 0x28, 0x01, 0x80, 0x10, 0x01, 0x00, 0x10, 0x02, 0x00,
0xC0, 0x38, 0x06, 0x00, 0x40, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E,
0x01, 0xF0, 0x1F, 0x00, 0xE0, 0x0F, 0x01, 0x86, 0x08, 0x08, 0x80, 0x24,
0x01, 0x40, 0x0A, 0x00, 0x50, 0x1E, 0x83, 0x14, 0x20, 0xA2, 0x05, 0x10,
0x28, 0x81, 0x46, 0x0A, 0x18, 0x50, 0x3F, 0x80, 0x04, 0x00, 0x10, 0x00,
0x80, 0x02, 0x00, 0x18, 0x18, 0x3F, 0x00, 0x1F, 0xF0, 0x00, 0x06, 0x80,
0x00, 0x34, 0x00, 0x01, 0x30, 0x00, 0x18, 0x80, 0x00, 0x86, 0x00, 0x04,
0x30, 0x00, 0x60, 0x80, 0x02, 0x06, 0x00, 0x10, 0x10, 0x01, 0x80, 0x80,
0x08, 0x06, 0x00, 0x7F, 0xF0, 0x06, 0x00, 0x80, 0x20, 0x06, 0x01, 0x00,
0x10, 0x18, 0x00, 0xC0, 0x80, 0x06, 0x04, 0x00, 0x11, 0xFC, 0x0F, 0xF0,
0xFF, 0xF8, 0x04, 0x01, 0x01, 0x00, 0x20, 0x40, 0x04, 0x10, 0x01, 0x04,
0x00, 0x41, 0x00, 0x10, 0x40, 0x08, 0x10, 0x0C, 0x07, 0xFF, 0x01, 0x00,
0x70, 0x40, 0x06, 0x10, 0x00, 0x84, 0x00, 0x11, 0x00, 0x04, 0x40, 0x01,
0x10, 0x00, 0x44, 0x00, 0x21, 0x00, 0x33, 0xFF, 0xF8, 0x03, 0xF1, 0x06,
0x0E, 0x8C, 0x01, 0xC4, 0x00, 0x64, 0x00, 0x12, 0x00, 0x0A, 0x00, 0x01,
0x00, 0x00, 0x80, 0x00, 0x40, 0x00, 0x20, 0x00, 0x10, 0x00, 0x08, 0x00,
0x04, 0x00, 0x01, 0x00, 0x00, 0x80, 0x00, 0x20, 0x01, 0x88, 0x01, 0x83,
0x03, 0x80, 0x7E, 0x00, 0xFF, 0xE0, 0x20, 0x18, 0x20, 0x0C, 0x20, 0x04,
0x20, 0x02, 0x20, 0x02, 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, 0x20, 0x01,
0x20, 0x01, 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, 0x20, 0x02, 0x20, 0x02,
0x20, 0x04, 0x20, 0x0C, 0x20, 0x18, 0xFF, 0xE0, 0xFF, 0xFF, 0x08, 0x00,
0x84, 0x00, 0x42, 0x00, 0x21, 0x00, 0x10, 0x80, 0x00, 0x40, 0x00, 0x20,
0x40, 0x10, 0x20, 0x0F, 0xF0, 0x04, 0x08, 0x02, 0x04, 0x01, 0x00, 0x00,
0x80, 0x00, 0x40, 0x02, 0x20, 0x01, 0x10, 0x00, 0x88, 0x00, 0x44, 0x00,
0x3F, 0xFF, 0xF0, 0xFF, 0xFF, 0x88, 0x00, 0x44, 0x00, 0x22, 0x00, 0x11,
0x00, 0x08, 0x80, 0x00, 0x40, 0x00, 0x20, 0x40, 0x10, 0x20, 0x0F, 0xF0,
0x04, 0x08, 0x02, 0x04, 0x01, 0x00, 0x00, 0x80, 0x00, 0x40, 0x00, 0x20,
0x00, 0x10, 0x00, 0x08, 0x00, 0x04, 0x00, 0x1F, 0xF8, 0x00, 0x03, 0xF9,
0x06, 0x07, 0x84, 0x00, 0xC4, 0x00, 0x24, 0x00, 0x12, 0x00, 0x02, 0x00,
0x01, 0x00, 0x00, 0x80, 0x00, 0x40, 0x00, 0x20, 0x00, 0x10, 0x0F, 0xF8,
0x00, 0x14, 0x00, 0x09, 0x00, 0x04, 0x80, 0x02, 0x20, 0x01, 0x18, 0x00,
0x83, 0x01, 0xC0, 0x7F, 0x00, 0xFC, 0x3F, 0x20, 0x04, 0x20, 0x04, 0x20,
0x04, 0x20, 0x04, 0x20, 0x04, 0x20, 0x04, 0x20, 0x04, 0x20, 0x04, 0x3F,
0xFC, 0x20, 0x04, 0x20, 0x04, 0x20, 0x04, 0x20, 0x04, 0x20, 0x04, 0x20,
0x04, 0x20, 0x04, 0x20, 0x04, 0x20, 0x04, 0xFC, 0x3F, 0xFF, 0xF8, 0x10,
0x00, 0x80, 0x04, 0x00, 0x20, 0x01, 0x00, 0x08, 0x00, 0x40, 0x02, 0x00,
0x10, 0x00, 0x80, 0x04, 0x00, 0x20, 0x01, 0x00, 0x08, 0x00, 0x40, 0x02,
0x00, 0x10, 0x00, 0x81, 0xFF, 0xF0, 0x03, 0xFF, 0x80, 0x04, 0x00, 0x02,
0x00, 0x01, 0x00, 0x00, 0x80, 0x00, 0x40, 0x00, 0x20, 0x00, 0x10, 0x00,
0x08, 0x00, 0x04, 0x00, 0x02, 0x10, 0x01, 0x08, 0x00, 0x84, 0x00, 0x42,
0x00, 0x21, 0x00, 0x10, 0x80, 0x10, 0x20, 0x18, 0x0C, 0x18, 0x01, 0xF0,
0x00, 0xFF, 0x1F, 0x84, 0x01, 0x81, 0x00, 0xC0, 0x40, 0x60, 0x10, 0x30,
0x04, 0x18, 0x01, 0x0C, 0x00, 0x46, 0x00, 0x13, 0x00, 0x05, 0xF0, 0x01,
0xC6, 0x00, 0x60, 0xC0, 0x10, 0x18, 0x04, 0x06, 0x01, 0x00, 0xC0, 0x40,
0x30, 0x10, 0x04, 0x04, 0x01, 0x81, 0x00, 0x23, 0xFC, 0x0F, 0xFF, 0x80,
0x10, 0x00, 0x20, 0x00, 0x40, 0x00, 0x80, 0x01, 0x00, 0x02, 0x00, 0x04,
0x00, 0x08, 0x00, 0x10, 0x00, 0x20, 0x00, 0x40, 0x00, 0x80, 0x01, 0x00,
0x42, 0x00, 0x84, 0x01, 0x08, 0x02, 0x10, 0x04, 0x20, 0x0F, 0xFF, 0xF0,
0xF0, 0x01, 0xE7, 0x00, 0x70, 0xA0, 0x0A, 0x16, 0x03, 0x42, 0x40, 0x48,
0x4C, 0x19, 0x08, 0x82, 0x21, 0x10, 0x44, 0x23, 0x18, 0x84, 0x22, 0x10,
0x86, 0xC2, 0x10, 0x50, 0x42, 0x0E, 0x08, 0x41, 0xC1, 0x08, 0x00, 0x21,
0x00, 0x04, 0x20, 0x00, 0x84, 0x00, 0x10, 0x80, 0x02, 0x7F, 0x03, 0xF0,
0xF8, 0x1F, 0xC6, 0x00, 0x41, 0xC0, 0x10, 0x50, 0x04, 0x12, 0x01, 0x04,
0xC0, 0x41, 0x10, 0x10, 0x46, 0x04, 0x10, 0x81, 0x04, 0x10, 0x41, 0x04,
0x10, 0x40, 0x84, 0x10, 0x31, 0x04, 0x04, 0x41, 0x01, 0x90, 0x40, 0x24,
0x10, 0x05, 0x04, 0x01, 0xC1, 0x00, 0x31, 0xFC, 0x0C, 0x03, 0xE0, 0x06,
0x0C, 0x04, 0x01, 0x04, 0x00, 0x46, 0x00, 0x32, 0x00, 0x0B, 0x00, 0x05,
0x00, 0x01, 0x80, 0x00, 0xC0, 0x00, 0x60, 0x00, 0x30, 0x00, 0x18, 0x00,
0x0E, 0x00, 0x0D, 0x00, 0x04, 0xC0, 0x06, 0x20, 0x02, 0x08, 0x02, 0x03,
0x06, 0x00, 0x7C, 0x00, 0xFF, 0xF0, 0x10, 0x0C, 0x10, 0x02, 0x10, 0x03,
0x10, 0x01, 0x10, 0x01, 0x10, 0x01, 0x10, 0x03, 0x10, 0x06, 0x10, 0x0C,
0x1F, 0xF0, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00,
0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0xFF, 0xC0, 0x03, 0xE0, 0x06, 0x0C,
0x04, 0x01, 0x04, 0x00, 0x46, 0x00, 0x32, 0x00, 0x0B, 0x00, 0x07, 0x00,
0x01, 0x80, 0x00, 0xC0, 0x00, 0x60, 0x00, 0x30, 0x00, 0x18, 0x00, 0x0E,
0x00, 0x0D, 0x00, 0x04, 0xC0, 0x06, 0x20, 0x02, 0x08, 0x02, 0x03, 0x06,
0x00, 0xFC, 0x00, 0x30, 0x00, 0x30, 0x00, 0x7F, 0xC6, 0x38, 0x1E, 0xFF,
0xF0, 0x02, 0x01, 0x80, 0x40, 0x08, 0x08, 0x01, 0x81, 0x00, 0x10, 0x20,
0x02, 0x04, 0x00, 0x40, 0x80, 0x18, 0x10, 0x06, 0x02, 0x03, 0x80, 0x7F,
0xC0, 0x08, 0x18, 0x01, 0x01, 0x80, 0x20, 0x18, 0x04, 0x01, 0x80, 0x80,
0x10, 0x10, 0x03, 0x02, 0x00, 0x20, 0x40, 0x06, 0x7F, 0x80, 0x70, 0x0F,
0xC8, 0x61, 0xE2, 0x01, 0x90, 0x02, 0x40, 0x09, 0x00, 0x04, 0x00, 0x08,
0x00, 0x38, 0x00, 0x3E, 0x00, 0x0F, 0x00, 0x06, 0x00, 0x0C, 0x00, 0x18,
0x00, 0x60, 0x01, 0x80, 0x0F, 0x00, 0x2B, 0x03, 0x23, 0xF0, 0xFF, 0xFF,
0x02, 0x06, 0x04, 0x0C, 0x08, 0x18, 0x10, 0x20, 0x20, 0x00, 0x40, 0x00,
0x80, 0x01, 0x00, 0x02, 0x00, 0x04, 0x00, 0x08, 0x00, 0x10, 0x00, 0x20,
0x00, 0x40, 0x00, 0x80, 0x01, 0x00, 0x02, 0x00, 0x04, 0x01, 0xFF, 0xC0,
0xFC, 0x1F, 0x90, 0x01, 0x08, 0x00, 0x84, 0x00, 0x42, 0x00, 0x21, 0x00,
0x10, 0x80, 0x08, 0x40, 0x04, 0x20, 0x02, 0x10, 0x01, 0x08, 0x00, 0x84,
0x00, 0x42, 0x00, 0x21, 0x00, 0x10, 0x80, 0x08, 0x40, 0x04, 0x10, 0x04,
0x0C, 0x06, 0x03, 0x06, 0x00, 0x7C, 0x00, 0xFE, 0x03, 0xF8, 0x80, 0x02,
0x04, 0x00, 0x10, 0x30, 0x01, 0x80, 0x80, 0x08, 0x06, 0x00, 0xC0, 0x30,
0x06, 0x00, 0x80, 0x20, 0x06, 0x03, 0x00, 0x30, 0x10, 0x00, 0x80, 0x80,
0x06, 0x0C, 0x00, 0x10, 0x40, 0x00, 0x86, 0x00, 0x06, 0x20, 0x00, 0x11,
0x00, 0x00, 0xD8, 0x00, 0x06, 0x80, 0x00, 0x1C, 0x00, 0x00, 0xE0, 0x00,
0xFC, 0x0F, 0xE8, 0x00, 0x19, 0x00, 0x03, 0x10, 0x00, 0x62, 0x00, 0x08,
0x41, 0x81, 0x08, 0x28, 0x21, 0x05, 0x04, 0x21, 0xA0, 0x84, 0x36, 0x30,
0x84, 0x46, 0x08, 0x88, 0xC1, 0x31, 0x18, 0x24, 0x12, 0x04, 0x82, 0x40,
0xB0, 0x48, 0x14, 0x09, 0x02, 0x80, 0xA0, 0x30, 0x1C, 0x06, 0x03, 0x80,
0x7E, 0x0F, 0xC2, 0x00, 0x60, 0x60, 0x0C, 0x06, 0x03, 0x00, 0x60, 0xC0,
0x0C, 0x10, 0x00, 0xC6, 0x00, 0x0D, 0x80, 0x00, 0xA0, 0x00, 0x1C, 0x00,
0x03, 0x80, 0x00, 0xD8, 0x00, 0x11, 0x00, 0x06, 0x30, 0x01, 0x83, 0x00,
0x60, 0x30, 0x08, 0x06, 0x03, 0x00, 0x60, 0xC0, 0x06, 0x7F, 0x07, 0xF0,
0xFC, 0x1F, 0x98, 0x03, 0x04, 0x01, 0x03, 0x01, 0x80, 0xC1, 0x80, 0x20,
0x80, 0x18, 0xC0, 0x04, 0x40, 0x03, 0x60, 0x00, 0xE0, 0x00, 0x20, 0x00,
0x10, 0x00, 0x08, 0x00, 0x04, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x80,
0x00, 0x40, 0x00, 0x20, 0x03, 0xFF, 0x80, 0xFF, 0xF4, 0x00, 0xA0, 0x09,
0x00, 0x48, 0x04, 0x40, 0x40, 0x02, 0x00, 0x20, 0x02, 0x00, 0x10, 0x01,
0x00, 0x10, 0x00, 0x80, 0x08, 0x04, 0x80, 0x24, 0x01, 0x40, 0x0C, 0x00,
0x60, 0x03, 0xFF, 0xF0, 0xFC, 0x21, 0x08, 0x42, 0x10, 0x84, 0x21, 0x08,
0x42, 0x10, 0x84, 0x21, 0x08, 0x42, 0x10, 0xF8, 0x80, 0x02, 0x00, 0x10,
0x00, 0xC0, 0x02, 0x00, 0x18, 0x00, 0x40, 0x03, 0x00, 0x08, 0x00, 0x40,
0x01, 0x00, 0x08, 0x00, 0x20, 0x01, 0x00, 0x04, 0x00, 0x20, 0x00, 0x80,
0x04, 0x00, 0x10, 0x00, 0x80, 0x02, 0x00, 0x10, 0x00, 0x40, 0x02, 0x00,
0x08, 0x00, 0x40, 0xF8, 0x42, 0x10, 0x84, 0x21, 0x08, 0x42, 0x10, 0x84,
0x21, 0x08, 0x42, 0x10, 0x84, 0x21, 0xF8, 0x02, 0x00, 0x38, 0x03, 0x60,
0x11, 0x01, 0x8C, 0x18, 0x31, 0x80, 0xD8, 0x03, 0x80, 0x08, 0xFF, 0xFF,
0xF8, 0xC1, 0x83, 0x06, 0x0C, 0x0F, 0xC0, 0x70, 0x30, 0x00, 0x10, 0x00,
0x08, 0x00, 0x08, 0x00, 0x08, 0x0F, 0xF8, 0x30, 0x08, 0x40, 0x08, 0x80,
0x08, 0x80, 0x08, 0x80, 0x08, 0x80, 0x38, 0x60, 0xE8, 0x3F, 0x8F, 0xF0,
0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x40, 0x00, 0x10, 0x00, 0x04, 0x00,
0x01, 0x0F, 0x80, 0x4C, 0x18, 0x14, 0x01, 0x06, 0x00, 0x21, 0x80, 0x08,
0x40, 0x01, 0x10, 0x00, 0x44, 0x00, 0x11, 0x00, 0x04, 0x40, 0x01, 0x18,
0x00, 0x86, 0x00, 0x21, 0xC0, 0x10, 0x5C, 0x18, 0xF1, 0xF8, 0x00, 0x07,
0xE4, 0x30, 0x78, 0x80, 0x32, 0x00, 0x24, 0x00, 0x50, 0x00, 0x20, 0x00,
0x40, 0x00, 0x80, 0x01, 0x00, 0x03, 0x00, 0x02, 0x00, 0x12, 0x00, 0xC3,
0x07, 0x01, 0xF8, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x80, 0x00, 0x20, 0x00,
0x08, 0x00, 0x02, 0x00, 0x00, 0x80, 0x7C, 0x20, 0x60, 0xC8, 0x20, 0x0A,
0x10, 0x01, 0x84, 0x00, 0x62, 0x00, 0x08, 0x80, 0x02, 0x20, 0x00, 0x88,
0x00, 0x22, 0x00, 0x08, 0xC0, 0x06, 0x10, 0x01, 0x82, 0x00, 0xE0, 0x60,
0xE8, 0x0F, 0xE3, 0xC0, 0x07, 0xE0, 0x1C, 0x18, 0x30, 0x0C, 0x60, 0x06,
0x40, 0x03, 0xC0, 0x03, 0xC0, 0x01, 0xFF, 0xFF, 0xC0, 0x00, 0xC0, 0x00,
0x40, 0x00, 0x60, 0x00, 0x30, 0x03, 0x0C, 0x0E, 0x03, 0xF0, 0x03, 0xFC,
0x18, 0x00, 0x80, 0x02, 0x00, 0x08, 0x00, 0x20, 0x0F, 0xFF, 0x82, 0x00,
0x08, 0x00, 0x20, 0x00, 0x80, 0x02, 0x00, 0x08, 0x00, 0x20, 0x00, 0x80,
0x02, 0x00, 0x08, 0x00, 0x20, 0x00, 0x80, 0x02, 0x00, 0xFF, 0xF0, 0x0F,
0xC7, 0x9C, 0x3A, 0x18, 0x07, 0x08, 0x01, 0x8C, 0x00, 0xC4, 0x00, 0x22,
0x00, 0x11, 0x00, 0x08, 0x80, 0x04, 0x40, 0x02, 0x10, 0x03, 0x08, 0x01,
0x82, 0x01, 0x40, 0xC3, 0x20, 0x3F, 0x10, 0x00, 0x08, 0x00, 0x04, 0x00,
0x02, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x7F, 0x00, 0xF0, 0x00,
0x08, 0x00, 0x04, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x80, 0x00, 0x47,
0xC0, 0x2C, 0x18, 0x1C, 0x04, 0x0C, 0x01, 0x04, 0x00, 0x82, 0x00, 0x41,
0x00, 0x20, 0x80, 0x10, 0x40, 0x08, 0x20, 0x04, 0x10, 0x02, 0x08, 0x01,
0x04, 0x00, 0x82, 0x00, 0x47, 0xC0, 0xF8, 0x06, 0x00, 0x18, 0x00, 0x60,
0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x80, 0x02, 0x00, 0x08,
0x00, 0x20, 0x00, 0x80, 0x02, 0x00, 0x08, 0x00, 0x20, 0x00, 0x80, 0x02,
0x00, 0x08, 0x00, 0x20, 0x00, 0x80, 0x02, 0x03, 0xFF, 0xF0, 0x03, 0x00,
0xC0, 0x30, 0x0C, 0x00, 0x00, 0x00, 0x03, 0xFF, 0x00, 0x40, 0x10, 0x04,
0x01, 0x00, 0x40, 0x10, 0x04, 0x01, 0x00, 0x40, 0x10, 0x04, 0x01, 0x00,
0x40, 0x10, 0x04, 0x01, 0x00, 0x40, 0x10, 0x08, 0x06, 0xFE, 0x00, 0xF0,
0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10,
0xFE, 0x10, 0x30, 0x10, 0xE0, 0x11, 0xC0, 0x13, 0x00, 0x16, 0x00, 0x1E,
0x00, 0x1B, 0x00, 0x11, 0x80, 0x10, 0xC0, 0x10, 0x60, 0x10, 0x30, 0x10,
0x18, 0x10, 0x1C, 0xF0, 0x3F, 0x7E, 0x00, 0x08, 0x00, 0x20, 0x00, 0x80,
0x02, 0x00, 0x08, 0x00, 0x20, 0x00, 0x80, 0x02, 0x00, 0x08, 0x00, 0x20,
0x00, 0x80, 0x02, 0x00, 0x08, 0x00, 0x20, 0x00, 0x80, 0x02, 0x00, 0x08,
0x00, 0x20, 0x00, 0x80, 0xFF, 0xFC, 0xEF, 0x9E, 0x07, 0x1E, 0x20, 0xC1,
0x82, 0x10, 0x20, 0x42, 0x04, 0x08, 0x40, 0x81, 0x08, 0x10, 0x21, 0x02,
0x04, 0x20, 0x40, 0x84, 0x08, 0x10, 0x81, 0x02, 0x10, 0x20, 0x42, 0x04,
0x08, 0x40, 0x81, 0x3E, 0x1C, 0x38, 0x71, 0xF0, 0x0B, 0x06, 0x07, 0x01,
0x03, 0x00, 0x41, 0x00, 0x20, 0x80, 0x10, 0x40, 0x08, 0x20, 0x04, 0x10,
0x02, 0x08, 0x01, 0x04, 0x00, 0x82, 0x00, 0x41, 0x00, 0x20, 0x80, 0x13,
0xF0, 0x3E, 0x07, 0xC0, 0x30, 0x60, 0x80, 0x22, 0x00, 0x24, 0x00, 0x50,
0x00, 0x60, 0x00, 0xC0, 0x01, 0x80, 0x03, 0x00, 0x05, 0x00, 0x12, 0x00,
0x22, 0x00, 0x83, 0x06, 0x01, 0xF0, 0x00, 0xF1, 0xFC, 0x05, 0xC1, 0x81,
0xC0, 0x10, 0x60, 0x02, 0x18, 0x00, 0xC4, 0x00, 0x11, 0x00, 0x04, 0x40,
0x01, 0x10, 0x00, 0x44, 0x00, 0x11, 0x80, 0x08, 0x60, 0x02, 0x14, 0x01,
0x04, 0xC1, 0x81, 0x0F, 0x80, 0x40, 0x00, 0x10, 0x00, 0x04, 0x00, 0x01,
0x00, 0x00, 0x40, 0x00, 0x10, 0x00, 0x3F, 0xC0, 0x00, 0x0F, 0xE3, 0xC6,
0x0E, 0x86, 0x00, 0xE1, 0x00, 0x18, 0xC0, 0x06, 0x20, 0x00, 0x88, 0x00,
0x22, 0x00, 0x08, 0x80, 0x02, 0x20, 0x00, 0x84, 0x00, 0x61, 0x00, 0x18,
0x20, 0x0A, 0x06, 0x0C, 0x80, 0x7C, 0x20, 0x00, 0x08, 0x00, 0x02, 0x00,
0x00, 0x80, 0x00, 0x20, 0x00, 0x08, 0x00, 0x02, 0x00, 0x0F, 0xF0, 0xF8,
0x7C, 0x11, 0x8C, 0x2C, 0x00, 0x70, 0x00, 0xC0, 0x01, 0x00, 0x02, 0x00,
0x04, 0x00, 0x08, 0x00, 0x10, 0x00, 0x20, 0x00, 0x40, 0x00, 0x80, 0x01,
0x00, 0x3F, 0xFC, 0x00, 0x0F, 0xD1, 0x83, 0x98, 0x04, 0x80, 0x24, 0x00,
0x30, 0x00, 0xF0, 0x00, 0xFC, 0x00, 0x30, 0x00, 0xE0, 0x03, 0x00, 0x1C,
0x01, 0xF0, 0x1A, 0x7F, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08,
0x00, 0x08, 0x00, 0xFF, 0xFC, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08,
0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08,
0x00, 0x08, 0x00, 0x08, 0x01, 0x06, 0x0F, 0x03, 0xF8, 0xF0, 0x3E, 0x08,
0x01, 0x04, 0x00, 0x82, 0x00, 0x41, 0x00, 0x20, 0x80, 0x10, 0x40, 0x08,
0x20, 0x04, 0x10, 0x02, 0x08, 0x01, 0x04, 0x00, 0x82, 0x00, 0x41, 0x00,
0xE0, 0x41, 0xD0, 0x1F, 0x8E, 0xFE, 0x0F, 0xE2, 0x00, 0x20, 0x60, 0x0C,
0x0C, 0x01, 0x80, 0x80, 0x20, 0x18, 0x0C, 0x01, 0x01, 0x00, 0x30, 0x60,
0x02, 0x08, 0x00, 0x41, 0x00, 0x0C, 0x60, 0x00, 0x88, 0x00, 0x19, 0x00,
0x01, 0x40, 0x00, 0x38, 0x00, 0xFC, 0x07, 0xE4, 0x00, 0x10, 0x80, 0x02,
0x18, 0x20, 0xC3, 0x0E, 0x18, 0x21, 0x42, 0x04, 0x28, 0x40, 0x8D, 0x88,
0x19, 0x93, 0x03, 0x22, 0x60, 0x2C, 0x68, 0x05, 0x85, 0x00, 0xA0, 0xA0,
0x1C, 0x1C, 0x01, 0x81, 0x80, 0x7C, 0x1F, 0x18, 0x03, 0x06, 0x03, 0x01,
0x83, 0x00, 0x63, 0x00, 0x1B, 0x00, 0x07, 0x00, 0x03, 0x80, 0x03, 0x60,
0x03, 0x18, 0x03, 0x06, 0x03, 0x01, 0x83, 0x00, 0x61, 0x00, 0x33, 0xF0,
0x7E, 0xFC, 0x1F, 0x90, 0x01, 0x8C, 0x00, 0x86, 0x00, 0xC1, 0x80, 0x40,
0xC0, 0x60, 0x20, 0x20, 0x18, 0x30, 0x04, 0x10, 0x03, 0x08, 0x00, 0x8C,
0x00, 0x64, 0x00, 0x16, 0x00, 0x0E, 0x00, 0x07, 0x00, 0x01, 0x00, 0x01,
0x80, 0x00, 0x80, 0x00, 0xC0, 0x00, 0x60, 0x00, 0x20, 0x07, 0xFE, 0x00,
0xFF, 0xF4, 0x01, 0x20, 0x09, 0x00, 0x80, 0x08, 0x00, 0x80, 0x08, 0x00,
0xC0, 0x04, 0x00, 0x40, 0x04, 0x00, 0x40, 0x14, 0x00, 0xA0, 0x07, 0xFF,
0xE0, 0x07, 0x0C, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
0x30, 0xC0, 0x30, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
0x0C, 0x07, 0xFF, 0xFF, 0xFF, 0x80, 0xE0, 0x30, 0x10, 0x10, 0x10, 0x10,
0x10, 0x10, 0x10, 0x10, 0x10, 0x08, 0x07, 0x0C, 0x10, 0x10, 0x10, 0x10,
0x10, 0x10, 0x10, 0x10, 0x10, 0x30, 0xE0, 0x1C, 0x00, 0x44, 0x0D, 0x84,
0x36, 0x04, 0x40, 0x07, 0x00};
const GFXglyph FreeMono18pt7bGlyphs[] PROGMEM = {
{0, 0, 0, 21, 0, 1}, // 0x20 ' '
{0, 4, 22, 21, 8, -21}, // 0x21 '!'
{11, 11, 10, 21, 5, -20}, // 0x22 '"'
{25, 14, 24, 21, 3, -21}, // 0x23 '#'
{67, 13, 26, 21, 4, -22}, // 0x24 '$'
{110, 15, 21, 21, 3, -20}, // 0x25 '%'
{150, 12, 18, 21, 4, -17}, // 0x26 '&'
{177, 4, 10, 21, 8, -20}, // 0x27 '''
{182, 5, 25, 21, 10, -20}, // 0x28 '('
{198, 5, 25, 21, 6, -20}, // 0x29 ')'
{214, 13, 12, 21, 4, -20}, // 0x2A '*'
{234, 15, 17, 21, 3, -17}, // 0x2B '+'
{266, 7, 10, 21, 5, -4}, // 0x2C ','
{275, 15, 1, 21, 3, -9}, // 0x2D '-'
{277, 5, 5, 21, 8, -4}, // 0x2E '.'
{281, 13, 26, 21, 4, -22}, // 0x2F '/'
{324, 13, 21, 21, 4, -20}, // 0x30 '0'
{359, 13, 21, 21, 4, -20}, // 0x31 '1'
{394, 13, 21, 21, 3, -20}, // 0x32 '2'
{429, 14, 21, 21, 3, -20}, // 0x33 '3'
{466, 12, 21, 21, 4, -20}, // 0x34 '4'
{498, 14, 21, 21, 3, -20}, // 0x35 '5'
{535, 12, 21, 21, 5, -20}, // 0x36 '6'
{567, 12, 21, 21, 4, -20}, // 0x37 '7'
{599, 13, 21, 21, 4, -20}, // 0x38 '8'
{634, 12, 21, 21, 5, -20}, // 0x39 '9'
{666, 5, 15, 21, 8, -14}, // 0x3A ':'
{676, 7, 20, 21, 5, -14}, // 0x3B ';'
{694, 15, 16, 21, 3, -17}, // 0x3C '<'
{724, 17, 6, 21, 2, -12}, // 0x3D '='
{737, 15, 16, 21, 3, -17}, // 0x3E '>'
{767, 12, 20, 21, 5, -19}, // 0x3F '?'
{797, 13, 23, 21, 4, -20}, // 0x40 '@'
{835, 21, 20, 21, 0, -19}, // 0x41 'A'
{888, 18, 20, 21, 1, -19}, // 0x42 'B'
{933, 17, 20, 21, 2, -19}, // 0x43 'C'
{976, 16, 20, 21, 2, -19}, // 0x44 'D'
{1016, 17, 20, 21, 1, -19}, // 0x45 'E'
{1059, 17, 20, 21, 1, -19}, // 0x46 'F'
{1102, 17, 20, 21, 2, -19}, // 0x47 'G'
{1145, 16, 20, 21, 2, -19}, // 0x48 'H'
{1185, 13, 20, 21, 4, -19}, // 0x49 'I'
{1218, 17, 20, 21, 3, -19}, // 0x4A 'J'
{1261, 18, 20, 21, 1, -19}, // 0x4B 'K'
{1306, 15, 20, 21, 3, -19}, // 0x4C 'L'
{1344, 19, 20, 21, 1, -19}, // 0x4D 'M'
{1392, 18, 20, 21, 1, -19}, // 0x4E 'N'
{1437, 17, 20, 21, 2, -19}, // 0x4F 'O'
{1480, 16, 20, 21, 1, -19}, // 0x50 'P'
{1520, 17, 24, 21, 2, -19}, // 0x51 'Q'
{1571, 19, 20, 21, 1, -19}, // 0x52 'R'
{1619, 14, 20, 21, 3, -19}, // 0x53 'S'
{1654, 15, 20, 21, 3, -19}, // 0x54 'T'
{1692, 17, 20, 21, 2, -19}, // 0x55 'U'
{1735, 21, 20, 21, 0, -19}, // 0x56 'V'
{1788, 19, 20, 21, 1, -19}, // 0x57 'W'
{1836, 19, 20, 21, 1, -19}, // 0x58 'X'
{1884, 17, 20, 21, 2, -19}, // 0x59 'Y'
{1927, 13, 20, 21, 4, -19}, // 0x5A 'Z'
{1960, 5, 25, 21, 10, -20}, // 0x5B '['
{1976, 13, 26, 21, 4, -22}, // 0x5C '\'
{2019, 5, 25, 21, 6, -20}, // 0x5D ']'
{2035, 13, 9, 21, 4, -20}, // 0x5E '^'
{2050, 21, 1, 21, 0, 4}, // 0x5F '_'
{2053, 6, 5, 21, 5, -21}, // 0x60 '`'
{2057, 16, 15, 21, 3, -14}, // 0x61 'a'
{2087, 18, 21, 21, 1, -20}, // 0x62 'b'
{2135, 15, 15, 21, 3, -14}, // 0x63 'c'
{2164, 18, 21, 21, 2, -20}, // 0x64 'd'
{2212, 16, 15, 21, 2, -14}, // 0x65 'e'
{2242, 14, 21, 21, 4, -20}, // 0x66 'f'
{2279, 17, 22, 21, 2, -14}, // 0x67 'g'
{2326, 17, 21, 21, 1, -20}, // 0x68 'h'
{2371, 14, 22, 21, 4, -21}, // 0x69 'i'
{2410, 10, 29, 21, 5, -21}, // 0x6A 'j'
{2447, 16, 21, 21, 2, -20}, // 0x6B 'k'
{2489, 14, 21, 21, 4, -20}, // 0x6C 'l'
{2526, 19, 15, 21, 1, -14}, // 0x6D 'm'
{2562, 17, 15, 21, 1, -14}, // 0x6E 'n'
{2594, 15, 15, 21, 3, -14}, // 0x6F 'o'
{2623, 18, 22, 21, 1, -14}, // 0x70 'p'
{2673, 18, 22, 21, 2, -14}, // 0x71 'q'
{2723, 15, 15, 21, 3, -14}, // 0x72 'r'
{2752, 13, 15, 21, 4, -14}, // 0x73 's'
{2777, 16, 20, 21, 1, -19}, // 0x74 't'
{2817, 17, 15, 21, 1, -14}, // 0x75 'u'
{2849, 19, 15, 21, 1, -14}, // 0x76 'v'
{2885, 19, 15, 21, 1, -14}, // 0x77 'w'
{2921, 17, 15, 21, 2, -14}, // 0x78 'x'
{2953, 17, 22, 21, 2, -14}, // 0x79 'y'
{3000, 13, 15, 21, 4, -14}, // 0x7A 'z'
{3025, 8, 25, 21, 6, -20}, // 0x7B '{'
{3050, 1, 25, 21, 10, -20}, // 0x7C '|'
{3054, 8, 25, 21, 7, -20}, // 0x7D '}'
{3079, 15, 5, 21, 3, -11}}; // 0x7E '~'
const GFXfont FreeMono18pt7b PROGMEM = {(uint8_t *)FreeMono18pt7bBitmaps,
(GFXglyph *)FreeMono18pt7bGlyphs, 0x20,
0x7E, 35};
// Approx. 3761 bytes

View File

@@ -0,0 +1,579 @@
#pragma once
#include <Adafruit_GFX.h>
const uint8_t FreeMono24pt7bBitmaps[] PROGMEM = {
0x73, 0x9C, 0xE7, 0x39, 0xCE, 0x73, 0x9C, 0xE7, 0x10, 0x84, 0x21, 0x08,
0x00, 0x00, 0x00, 0x03, 0xBF, 0xFF, 0xB8, 0xFE, 0x7F, 0x7C, 0x3E, 0x7C,
0x3E, 0x7C, 0x3E, 0x7C, 0x3E, 0x7C, 0x3E, 0x7C, 0x3E, 0x7C, 0x3E, 0x3C,
0x3E, 0x38, 0x1C, 0x38, 0x1C, 0x38, 0x1C, 0x38, 0x1C, 0x38, 0x1C, 0x01,
0x86, 0x00, 0x30, 0xC0, 0x06, 0x18, 0x00, 0xC3, 0x00, 0x18, 0x60, 0x03,
0x0C, 0x00, 0x61, 0x80, 0x0C, 0x70, 0x01, 0x8C, 0x00, 0x61, 0x80, 0x0C,
0x30, 0x3F, 0xFF, 0xF7, 0xFF, 0xFE, 0x06, 0x18, 0x00, 0xC3, 0x00, 0x18,
0x60, 0x03, 0x0C, 0x00, 0x61, 0x80, 0x0C, 0x30, 0x7F, 0xFF, 0xEF, 0xFF,
0xFC, 0x06, 0x18, 0x00, 0xC7, 0x00, 0x38, 0xC0, 0x06, 0x18, 0x00, 0xC3,
0x00, 0x18, 0x60, 0x03, 0x0C, 0x00, 0x61, 0x80, 0x0C, 0x30, 0x01, 0x86,
0x00, 0x30, 0xC0, 0x00, 0xC0, 0x00, 0x30, 0x00, 0x0C, 0x00, 0x0F, 0xC0,
0x0F, 0xFD, 0x87, 0x03, 0xE3, 0x80, 0x39, 0xC0, 0x06, 0x60, 0x01, 0x98,
0x00, 0x06, 0x00, 0x01, 0xC0, 0x00, 0x38, 0x00, 0x07, 0xC0, 0x00, 0x7F,
0x80, 0x03, 0xF8, 0x00, 0x0F, 0x80, 0x00, 0x60, 0x00, 0x1C, 0x00, 0x03,
0x80, 0x00, 0xF0, 0x00, 0x3C, 0x00, 0x1F, 0x80, 0x0E, 0xFC, 0x0F, 0x37,
0xFF, 0x80, 0x7F, 0x80, 0x03, 0x00, 0x00, 0xC0, 0x00, 0x30, 0x00, 0x0C,
0x00, 0x03, 0x00, 0x00, 0xC0, 0x00, 0x07, 0x80, 0x01, 0xFE, 0x00, 0x38,
0x70, 0x03, 0x03, 0x00, 0x60, 0x18, 0x06, 0x01, 0x80, 0x60, 0x18, 0x06,
0x01, 0x80, 0x30, 0x30, 0x03, 0x87, 0x00, 0x1F, 0xE0, 0x30, 0x78, 0x1F,
0x00, 0x1F, 0x80, 0x0F, 0xC0, 0x07, 0xE0, 0x03, 0xF0, 0x00, 0xF8, 0x00,
0x0C, 0x01, 0xE0, 0x00, 0x7F, 0x80, 0x0E, 0x1C, 0x00, 0xC0, 0xC0, 0x18,
0x06, 0x01, 0x80, 0x60, 0x18, 0x06, 0x01, 0x80, 0x60, 0x0C, 0x0E, 0x00,
0xE1, 0xC0, 0x07, 0xF8, 0x00, 0x1E, 0x00, 0x03, 0xEC, 0x01, 0xFF, 0x00,
0xE1, 0x00, 0x70, 0x00, 0x18, 0x00, 0x06, 0x00, 0x01, 0x80, 0x00, 0x30,
0x00, 0x0C, 0x00, 0x01, 0x80, 0x00, 0x60, 0x00, 0x7C, 0x00, 0x3B, 0x83,
0xD8, 0x60, 0xFE, 0x0C, 0x33, 0x03, 0x98, 0xC0, 0x66, 0x30, 0x0D, 0x8C,
0x03, 0xC3, 0x00, 0x70, 0x60, 0x1C, 0x1C, 0x0F, 0x03, 0x87, 0x7C, 0x7F,
0x9F, 0x07, 0x80, 0x00, 0xFE, 0xF9, 0xF3, 0xE7, 0xCF, 0x9F, 0x3E, 0x3C,
0x70, 0xE1, 0xC3, 0x87, 0x00, 0x06, 0x1C, 0x30, 0xE1, 0x87, 0x0E, 0x18,
0x70, 0xE1, 0xC3, 0x0E, 0x1C, 0x38, 0x70, 0xE1, 0xC3, 0x87, 0x0E, 0x0C,
0x1C, 0x38, 0x70, 0x60, 0xE1, 0xC1, 0x83, 0x83, 0x06, 0x06, 0x04, 0xC1,
0xC1, 0x83, 0x83, 0x07, 0x0E, 0x0C, 0x1C, 0x38, 0x70, 0xE0, 0xE1, 0xC3,
0x87, 0x0E, 0x1C, 0x38, 0x70, 0xE1, 0x87, 0x0E, 0x1C, 0x30, 0x61, 0xC3,
0x0E, 0x18, 0x70, 0xC1, 0x00, 0x00, 0xC0, 0x00, 0x30, 0x00, 0x0C, 0x00,
0x03, 0x00, 0x00, 0xC0, 0x10, 0x30, 0x3F, 0x8C, 0x7C, 0xFF, 0xFC, 0x07,
0xF8, 0x00, 0x78, 0x00, 0x1F, 0x00, 0x0C, 0xC0, 0x06, 0x18, 0x03, 0x87,
0x00, 0xC0, 0xC0, 0x60, 0x18, 0x00, 0x60, 0x00, 0x06, 0x00, 0x00, 0x60,
0x00, 0x06, 0x00, 0x00, 0x60, 0x00, 0x06, 0x00, 0x00, 0x60, 0x00, 0x06,
0x00, 0x00, 0x60, 0x00, 0x06, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
0x60, 0x00, 0x06, 0x00, 0x00, 0x60, 0x00, 0x06, 0x00, 0x00, 0x60, 0x00,
0x06, 0x00, 0x00, 0x60, 0x00, 0x06, 0x00, 0x00, 0x60, 0x00, 0x06, 0x00,
0x1F, 0x8F, 0x87, 0xC7, 0xC3, 0xE1, 0xE1, 0xF0, 0xF0, 0x78, 0x38, 0x3C,
0x1C, 0x0E, 0x06, 0x00, 0x7F, 0xFF, 0xFD, 0xFF, 0xFF, 0xF0, 0x7D, 0xFF,
0xFF, 0xFF, 0xEF, 0x80, 0x00, 0x00, 0xC0, 0x00, 0x70, 0x00, 0x18, 0x00,
0x06, 0x00, 0x03, 0x00, 0x00, 0xC0, 0x00, 0x60, 0x00, 0x18, 0x00, 0x0C,
0x00, 0x03, 0x00, 0x01, 0x80, 0x00, 0x60, 0x00, 0x30, 0x00, 0x0C, 0x00,
0x06, 0x00, 0x01, 0x80, 0x00, 0xC0, 0x00, 0x30, 0x00, 0x18, 0x00, 0x06,
0x00, 0x03, 0x80, 0x00, 0xC0, 0x00, 0x70, 0x00, 0x18, 0x00, 0x0E, 0x00,
0x03, 0x00, 0x01, 0xC0, 0x00, 0x60, 0x00, 0x38, 0x00, 0x0C, 0x00, 0x07,
0x00, 0x01, 0x80, 0x00, 0x60, 0x00, 0x30, 0x00, 0x0C, 0x00, 0x00, 0x03,
0xF0, 0x03, 0xFF, 0x01, 0xE1, 0xE0, 0xE0, 0x18, 0x30, 0x03, 0x1C, 0x00,
0xE6, 0x00, 0x19, 0x80, 0x06, 0xE0, 0x01, 0xF0, 0x00, 0x3C, 0x00, 0x0F,
0x00, 0x03, 0xC0, 0x00, 0xF0, 0x00, 0x3C, 0x00, 0x0F, 0x00, 0x03, 0xC0,
0x00, 0xF0, 0x00, 0x3C, 0x00, 0x0F, 0x00, 0x03, 0xC0, 0x00, 0xF8, 0x00,
0x76, 0x00, 0x19, 0x80, 0x06, 0x70, 0x03, 0x8C, 0x00, 0xC3, 0x80, 0x60,
0x78, 0x78, 0x0F, 0xFC, 0x00, 0xFC, 0x00, 0x03, 0x80, 0x07, 0x80, 0x0F,
0x80, 0x1D, 0x80, 0x39, 0x80, 0x71, 0x80, 0xE1, 0x80, 0xC1, 0x80, 0x01,
0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01,
0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01,
0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01,
0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0xF0, 0x03, 0xFF, 0x01, 0xC0, 0xE0,
0xC0, 0x1C, 0x60, 0x03, 0xB8, 0x00, 0x6C, 0x00, 0x0F, 0x00, 0x03, 0x00,
0x00, 0xC0, 0x00, 0x30, 0x00, 0x18, 0x00, 0x06, 0x00, 0x03, 0x00, 0x01,
0x80, 0x00, 0xC0, 0x00, 0x60, 0x00, 0x30, 0x00, 0x18, 0x00, 0x0C, 0x00,
0x06, 0x00, 0x03, 0x00, 0x01, 0x80, 0x00, 0xC0, 0x00, 0x60, 0x00, 0x30,
0x00, 0xD0, 0x00, 0x38, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x03,
0xF8, 0x01, 0xFF, 0xC0, 0x70, 0x3C, 0x18, 0x01, 0xC6, 0x00, 0x18, 0x00,
0x01, 0x80, 0x00, 0x30, 0x00, 0x06, 0x00, 0x00, 0xC0, 0x00, 0x18, 0x00,
0x06, 0x00, 0x01, 0xC0, 0x00, 0x70, 0x01, 0xFC, 0x00, 0x3F, 0x00, 0x00,
0x78, 0x00, 0x03, 0x80, 0x00, 0x38, 0x00, 0x03, 0x00, 0x00, 0x30, 0x00,
0x06, 0x00, 0x00, 0xC0, 0x00, 0x18, 0x00, 0x03, 0x00, 0x00, 0xD8, 0x00,
0x3B, 0x80, 0x0E, 0x3E, 0x07, 0x81, 0xFF, 0xE0, 0x07, 0xE0, 0x00, 0x00,
0x3C, 0x00, 0x7C, 0x00, 0x6C, 0x00, 0xCC, 0x00, 0x8C, 0x01, 0x8C, 0x03,
0x0C, 0x03, 0x0C, 0x06, 0x0C, 0x04, 0x0C, 0x0C, 0x0C, 0x08, 0x0C, 0x10,
0x0C, 0x30, 0x0C, 0x20, 0x0C, 0x60, 0x0C, 0x40, 0x0C, 0x80, 0x0C, 0xFF,
0xFF, 0xFF, 0xFF, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x0C, 0x00,
0x0C, 0x00, 0x0C, 0x00, 0xFF, 0x00, 0xFF, 0x3F, 0xFF, 0x07, 0xFF, 0xE0,
0xC0, 0x00, 0x18, 0x00, 0x03, 0x00, 0x00, 0x60, 0x00, 0x0C, 0x00, 0x01,
0x80, 0x00, 0x30, 0x00, 0x06, 0x00, 0x00, 0xC7, 0xE0, 0x1F, 0xFF, 0x03,
0x80, 0x70, 0x00, 0x03, 0x00, 0x00, 0x30, 0x00, 0x06, 0x00, 0x00, 0x60,
0x00, 0x0C, 0x00, 0x01, 0x80, 0x00, 0x30, 0x00, 0x06, 0x00, 0x00, 0xC0,
0x00, 0x30, 0x00, 0x06, 0xC0, 0x01, 0xDC, 0x00, 0x71, 0xF0, 0x3C, 0x0F,
0xFF, 0x00, 0x3F, 0x00, 0x00, 0x3F, 0x80, 0x3F, 0xF0, 0x3E, 0x00, 0x1E,
0x00, 0x0E, 0x00, 0x07, 0x00, 0x03, 0x80, 0x00, 0xC0, 0x00, 0x70, 0x00,
0x18, 0x00, 0x06, 0x00, 0x03, 0x80, 0x00, 0xC1, 0xF8, 0x31, 0xFF, 0x0C,
0xF0, 0xF3, 0x70, 0x0C, 0xD8, 0x01, 0xBC, 0x00, 0x6E, 0x00, 0x0F, 0x80,
0x03, 0xC0, 0x00, 0xD8, 0x00, 0x36, 0x00, 0x0D, 0x80, 0x03, 0x30, 0x01,
0x8E, 0x00, 0x61, 0xC0, 0x30, 0x38, 0x38, 0x07, 0xFC, 0x00, 0x7C, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x0F, 0x00, 0x03, 0xC0, 0x01, 0xC0,
0x00, 0x60, 0x00, 0x18, 0x00, 0x0E, 0x00, 0x03, 0x00, 0x00, 0xC0, 0x00,
0x30, 0x00, 0x18, 0x00, 0x06, 0x00, 0x01, 0x80, 0x00, 0xC0, 0x00, 0x30,
0x00, 0x0C, 0x00, 0x06, 0x00, 0x01, 0x80, 0x00, 0x60, 0x00, 0x30, 0x00,
0x0C, 0x00, 0x03, 0x00, 0x01, 0x80, 0x00, 0x60, 0x00, 0x18, 0x00, 0x0C,
0x00, 0x03, 0x00, 0x03, 0xF0, 0x03, 0xFF, 0x03, 0xC0, 0xF1, 0xC0, 0x0E,
0x60, 0x01, 0xB8, 0x00, 0x7C, 0x00, 0x0F, 0x00, 0x03, 0xC0, 0x00, 0xF0,
0x00, 0x36, 0x00, 0x18, 0xC0, 0x0C, 0x1C, 0x0E, 0x03, 0xFF, 0x00, 0xFF,
0xC0, 0x70, 0x38, 0x30, 0x03, 0x18, 0x00, 0x66, 0x00, 0x1B, 0x00, 0x03,
0xC0, 0x00, 0xF0, 0x00, 0x3C, 0x00, 0x0F, 0x00, 0x03, 0x60, 0x01, 0x98,
0x00, 0xE3, 0x00, 0x70, 0x70, 0x38, 0x0F, 0xFC, 0x00, 0xFC, 0x00, 0x07,
0xE0, 0x03, 0xFE, 0x01, 0xC1, 0xC0, 0xC0, 0x38, 0x60, 0x07, 0x18, 0x00,
0xCC, 0x00, 0x1B, 0x00, 0x06, 0xC0, 0x01, 0xB0, 0x00, 0x3C, 0x00, 0x1F,
0x00, 0x07, 0x60, 0x03, 0xD8, 0x01, 0xB3, 0x00, 0xCC, 0xF0, 0xF3, 0x0F,
0xF8, 0xC1, 0xF8, 0x30, 0x00, 0x1C, 0x00, 0x06, 0x00, 0x01, 0x80, 0x00,
0xE0, 0x00, 0x30, 0x00, 0x1C, 0x00, 0x0E, 0x00, 0x07, 0x00, 0x07, 0x80,
0x07, 0xC0, 0xFF, 0xC0, 0x1F, 0xC0, 0x00, 0x7D, 0xFF, 0xFF, 0xFF, 0xEF,
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0xFF, 0xFF, 0xFF,
0xF7, 0xC0, 0x0F, 0x87, 0xF1, 0xFC, 0x7F, 0x1F, 0xC3, 0xE0, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xF1, 0xF8, 0x7C, 0x3F, 0x0F,
0x83, 0xE0, 0xF0, 0x7C, 0x1E, 0x07, 0x81, 0xC0, 0xF0, 0x38, 0x04, 0x00,
0x00, 0x00, 0x18, 0x00, 0x01, 0xE0, 0x00, 0x1E, 0x00, 0x00, 0xE0, 0x00,
0x0F, 0x00, 0x00, 0xF0, 0x00, 0x0F, 0x00, 0x00, 0xF0, 0x00, 0x07, 0x00,
0x00, 0x78, 0x00, 0x07, 0x80, 0x00, 0x0F, 0x00, 0x00, 0x1E, 0x00, 0x00,
0x1E, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x1E, 0x00, 0x00,
0x3C, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x38, 0x00, 0x00,
0x20, 0x7F, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF,
0xFF, 0x7F, 0xFF, 0xFF, 0xC0, 0x00, 0x07, 0x80, 0x00, 0x0F, 0x00, 0x00,
0x1E, 0x00, 0x00, 0x38, 0x00, 0x00, 0xF0, 0x00, 0x01, 0xE0, 0x00, 0x03,
0xC0, 0x00, 0x07, 0x80, 0x00, 0x0E, 0x00, 0x00, 0x3C, 0x00, 0x01, 0xE0,
0x00, 0x3C, 0x00, 0x07, 0x80, 0x00, 0xF0, 0x00, 0x1E, 0x00, 0x01, 0xE0,
0x00, 0x3C, 0x00, 0x07, 0x80, 0x00, 0xF0, 0x00, 0x0E, 0x00, 0x00, 0x60,
0x00, 0x00, 0x07, 0xF0, 0x1F, 0xFE, 0x3E, 0x07, 0x98, 0x00, 0xEC, 0x00,
0x36, 0x00, 0x0F, 0x00, 0x06, 0x00, 0x03, 0x00, 0x01, 0x80, 0x01, 0xC0,
0x00, 0xC0, 0x01, 0xC0, 0x03, 0xC0, 0x07, 0xC0, 0x07, 0x00, 0x03, 0x00,
0x01, 0x80, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x07, 0x80, 0x07, 0xE0, 0x03, 0xF0, 0x01, 0xF8, 0x00,
0x78, 0x00, 0x03, 0xF0, 0x03, 0xFF, 0x01, 0xE0, 0xE0, 0xE0, 0x1C, 0x30,
0x03, 0x1C, 0x00, 0x66, 0x00, 0x19, 0x80, 0x06, 0xC0, 0x01, 0xB0, 0x07,
0xEC, 0x07, 0xFB, 0x03, 0xC6, 0xC1, 0xC1, 0xB0, 0xE0, 0x6C, 0x30, 0x1B,
0x0C, 0x06, 0xC3, 0x01, 0xB0, 0xC0, 0x6C, 0x18, 0x1B, 0x07, 0x86, 0xC0,
0xFF, 0xF0, 0x0F, 0xFC, 0x00, 0x03, 0x00, 0x00, 0x60, 0x00, 0x18, 0x00,
0x07, 0x00, 0x00, 0xC0, 0x00, 0x38, 0x00, 0x07, 0x80, 0xC0, 0xFF, 0xF0,
0x0F, 0xE0, 0x07, 0xFF, 0x00, 0x00, 0x7F, 0xF0, 0x00, 0x00, 0x1B, 0x00,
0x00, 0x01, 0x98, 0x00, 0x00, 0x11, 0x80, 0x00, 0x03, 0x0C, 0x00, 0x00,
0x30, 0xC0, 0x00, 0x06, 0x0C, 0x00, 0x00, 0x60, 0x60, 0x00, 0x06, 0x06,
0x00, 0x00, 0xC0, 0x30, 0x00, 0x0C, 0x03, 0x00, 0x00, 0x80, 0x30, 0x00,
0x18, 0x01, 0x80, 0x01, 0x80, 0x18, 0x00, 0x3F, 0xFF, 0x80, 0x03, 0xFF,
0xFC, 0x00, 0x20, 0x00, 0xC0, 0x06, 0x00, 0x06, 0x00, 0x60, 0x00, 0x60,
0x0C, 0x00, 0x06, 0x00, 0xC0, 0x00, 0x30, 0x0C, 0x00, 0x03, 0x01, 0x80,
0x00, 0x18, 0x7F, 0xC0, 0x3F, 0xF7, 0xFC, 0x03, 0xFF, 0xFF, 0xFF, 0x03,
0xFF, 0xFF, 0x01, 0x80, 0x0E, 0x06, 0x00, 0x1C, 0x18, 0x00, 0x38, 0x60,
0x00, 0x61, 0x80, 0x01, 0x86, 0x00, 0x06, 0x18, 0x00, 0x38, 0x60, 0x01,
0xC1, 0x80, 0x1E, 0x07, 0xFF, 0xE0, 0x1F, 0xFF, 0xC0, 0x60, 0x03, 0xC1,
0x80, 0x03, 0x86, 0x00, 0x06, 0x18, 0x00, 0x1C, 0x60, 0x00, 0x31, 0x80,
0x00, 0xC6, 0x00, 0x03, 0x18, 0x00, 0x0C, 0x60, 0x00, 0x61, 0x80, 0x03,
0x86, 0x00, 0x1C, 0xFF, 0xFF, 0xE3, 0xFF, 0xFE, 0x00, 0x00, 0xFC, 0x00,
0x0F, 0xFE, 0x60, 0xF0, 0x3D, 0x87, 0x00, 0x3E, 0x38, 0x00, 0x38, 0xC0,
0x00, 0xE7, 0x00, 0x01, 0x98, 0x00, 0x06, 0x60, 0x00, 0x03, 0x00, 0x00,
0x0C, 0x00, 0x00, 0x30, 0x00, 0x00, 0xC0, 0x00, 0x03, 0x00, 0x00, 0x0C,
0x00, 0x00, 0x30, 0x00, 0x00, 0xC0, 0x00, 0x03, 0x00, 0x00, 0x0C, 0x00,
0x00, 0x18, 0x00, 0x00, 0x60, 0x00, 0x01, 0xC0, 0x00, 0x03, 0x80, 0x00,
0xC7, 0x00, 0x06, 0x0E, 0x00, 0x70, 0x1E, 0x07, 0x80, 0x3F, 0xFC, 0x00,
0x1F, 0x80, 0xFF, 0xFE, 0x03, 0xFF, 0xFE, 0x03, 0x00, 0x3C, 0x0C, 0x00,
0x38, 0x30, 0x00, 0x70, 0xC0, 0x00, 0xC3, 0x00, 0x03, 0x8C, 0x00, 0x06,
0x30, 0x00, 0x1C, 0xC0, 0x00, 0x33, 0x00, 0x00, 0xCC, 0x00, 0x03, 0x30,
0x00, 0x0C, 0xC0, 0x00, 0x33, 0x00, 0x00, 0xCC, 0x00, 0x03, 0x30, 0x00,
0x0C, 0xC0, 0x00, 0x33, 0x00, 0x01, 0x8C, 0x00, 0x06, 0x30, 0x00, 0x30,
0xC0, 0x01, 0xC3, 0x00, 0x0E, 0x0C, 0x00, 0xF0, 0xFF, 0xFF, 0x83, 0xFF,
0xF8, 0x00, 0xFF, 0xFF, 0xFB, 0xFF, 0xFF, 0xE1, 0x80, 0x01, 0x86, 0x00,
0x06, 0x18, 0x00, 0x18, 0x60, 0x00, 0x61, 0x80, 0x01, 0x86, 0x00, 0x00,
0x18, 0x0C, 0x00, 0x60, 0x30, 0x01, 0x80, 0xC0, 0x07, 0xFF, 0x00, 0x1F,
0xFC, 0x00, 0x60, 0x30, 0x01, 0x80, 0xC0, 0x06, 0x03, 0x00, 0x18, 0x00,
0x00, 0x60, 0x00, 0x01, 0x80, 0x00, 0xC6, 0x00, 0x03, 0x18, 0x00, 0x0C,
0x60, 0x00, 0x31, 0x80, 0x00, 0xC6, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF1, 0x80, 0x00, 0xC6, 0x00,
0x03, 0x18, 0x00, 0x0C, 0x60, 0x00, 0x31, 0x80, 0x00, 0xC6, 0x00, 0x00,
0x18, 0x0C, 0x00, 0x60, 0x30, 0x01, 0x80, 0xC0, 0x07, 0xFF, 0x00, 0x1F,
0xFC, 0x00, 0x60, 0x30, 0x01, 0x80, 0xC0, 0x06, 0x03, 0x00, 0x18, 0x00,
0x00, 0x60, 0x00, 0x01, 0x80, 0x00, 0x06, 0x00, 0x00, 0x18, 0x00, 0x00,
0x60, 0x00, 0x01, 0x80, 0x00, 0x06, 0x00, 0x00, 0xFF, 0xF0, 0x03, 0xFF,
0xC0, 0x00, 0x00, 0xFF, 0x00, 0x07, 0xFF, 0x98, 0x1E, 0x03, 0xF0, 0x70,
0x01, 0xE1, 0x80, 0x01, 0xC6, 0x00, 0x01, 0x9C, 0x00, 0x03, 0x30, 0x00,
0x00, 0x60, 0x00, 0x01, 0xC0, 0x00, 0x03, 0x00, 0x00, 0x06, 0x00, 0x00,
0x0C, 0x00, 0x00, 0x18, 0x00, 0x00, 0x30, 0x00, 0x00, 0x60, 0x03, 0xFF,
0xC0, 0x07, 0xFF, 0x80, 0x00, 0x1B, 0x00, 0x00, 0x37, 0x00, 0x00, 0x66,
0x00, 0x00, 0xCC, 0x00, 0x01, 0x8C, 0x00, 0x03, 0x1C, 0x00, 0x06, 0x1E,
0x00, 0x0C, 0x0F, 0x00, 0xF8, 0x0F, 0xFF, 0xC0, 0x03, 0xFC, 0x00, 0x7F,
0x01, 0xFC, 0xFE, 0x03, 0xF8, 0x60, 0x00, 0xC0, 0xC0, 0x01, 0x81, 0x80,
0x03, 0x03, 0x00, 0x06, 0x06, 0x00, 0x0C, 0x0C, 0x00, 0x18, 0x18, 0x00,
0x30, 0x30, 0x00, 0x60, 0x60, 0x00, 0xC0, 0xFF, 0xFF, 0x81, 0xFF, 0xFF,
0x03, 0x00, 0x06, 0x06, 0x00, 0x0C, 0x0C, 0x00, 0x18, 0x18, 0x00, 0x30,
0x30, 0x00, 0x60, 0x60, 0x00, 0xC0, 0xC0, 0x01, 0x81, 0x80, 0x03, 0x03,
0x00, 0x06, 0x06, 0x00, 0x0C, 0x0C, 0x00, 0x18, 0xFF, 0x01, 0xFF, 0xFE,
0x03, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80,
0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80,
0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80,
0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80,
0x01, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFE, 0x01, 0xFF, 0xFC,
0x00, 0x03, 0x00, 0x00, 0x06, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x18, 0x00,
0x00, 0x30, 0x00, 0x00, 0x60, 0x00, 0x00, 0xC0, 0x00, 0x01, 0x80, 0x00,
0x03, 0x00, 0x00, 0x06, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x18, 0x00, 0x00,
0x30, 0x60, 0x00, 0x60, 0xC0, 0x00, 0xC1, 0x80, 0x01, 0x83, 0x00, 0x03,
0x06, 0x00, 0x06, 0x0C, 0x00, 0x0C, 0x18, 0x00, 0x30, 0x38, 0x00, 0x60,
0x38, 0x01, 0x80, 0x3C, 0x0E, 0x00, 0x3F, 0xF8, 0x00, 0x0F, 0xC0, 0x00,
0xFF, 0x81, 0xFE, 0xFF, 0x81, 0xFE, 0x18, 0x00, 0x30, 0x18, 0x00, 0xE0,
0x18, 0x01, 0xC0, 0x18, 0x03, 0x80, 0x18, 0x07, 0x00, 0x18, 0x0E, 0x00,
0x18, 0x18, 0x00, 0x18, 0x70, 0x00, 0x18, 0xE0, 0x00, 0x19, 0xE0, 0x00,
0x1B, 0xF8, 0x00, 0x1F, 0x1C, 0x00, 0x1C, 0x06, 0x00, 0x18, 0x03, 0x00,
0x18, 0x03, 0x80, 0x18, 0x01, 0x80, 0x18, 0x00, 0xC0, 0x18, 0x00, 0xC0,
0x18, 0x00, 0x60, 0x18, 0x00, 0x60, 0x18, 0x00, 0x70, 0x18, 0x00, 0x30,
0xFF, 0x80, 0x3F, 0xFF, 0x80, 0x1F, 0xFF, 0xF0, 0x07, 0xFF, 0x80, 0x01,
0x80, 0x00, 0x0C, 0x00, 0x00, 0x60, 0x00, 0x03, 0x00, 0x00, 0x18, 0x00,
0x00, 0xC0, 0x00, 0x06, 0x00, 0x00, 0x30, 0x00, 0x01, 0x80, 0x00, 0x0C,
0x00, 0x00, 0x60, 0x00, 0x03, 0x00, 0x00, 0x18, 0x00, 0x00, 0xC0, 0x00,
0x06, 0x00, 0x18, 0x30, 0x00, 0xC1, 0x80, 0x06, 0x0C, 0x00, 0x30, 0x60,
0x01, 0x83, 0x00, 0x0C, 0x18, 0x00, 0x60, 0xC0, 0x03, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xC0, 0xFC, 0x00, 0x0F, 0xFF, 0x00, 0x03, 0xF3, 0x60, 0x01,
0xB0, 0xD8, 0x00, 0x6C, 0x33, 0x00, 0x33, 0x0C, 0xC0, 0x0C, 0xC3, 0x38,
0x07, 0x30, 0xC6, 0x01, 0x8C, 0x31, 0xC0, 0xE3, 0x0C, 0x30, 0x30, 0xC3,
0x0C, 0x0C, 0x30, 0xC1, 0x86, 0x0C, 0x30, 0x61, 0x83, 0x0C, 0x0C, 0xC0,
0xC3, 0x03, 0x30, 0x30, 0xC0, 0x78, 0x0C, 0x30, 0x1E, 0x03, 0x0C, 0x03,
0x00, 0xC3, 0x00, 0x00, 0x30, 0xC0, 0x00, 0x0C, 0x30, 0x00, 0x03, 0x0C,
0x00, 0x00, 0xC3, 0x00, 0x00, 0x30, 0xC0, 0x00, 0x0C, 0xFF, 0x00, 0x3F,
0xFF, 0xC0, 0x0F, 0xF0, 0xFC, 0x00, 0xFF, 0xFC, 0x00, 0xFF, 0x1E, 0x00,
0x0C, 0x1F, 0x00, 0x0C, 0x1B, 0x00, 0x0C, 0x19, 0x80, 0x0C, 0x19, 0xC0,
0x0C, 0x18, 0xC0, 0x0C, 0x18, 0x60, 0x0C, 0x18, 0x60, 0x0C, 0x18, 0x30,
0x0C, 0x18, 0x38, 0x0C, 0x18, 0x18, 0x0C, 0x18, 0x0C, 0x0C, 0x18, 0x0E,
0x0C, 0x18, 0x06, 0x0C, 0x18, 0x03, 0x0C, 0x18, 0x03, 0x0C, 0x18, 0x01,
0x8C, 0x18, 0x01, 0xCC, 0x18, 0x00, 0xCC, 0x18, 0x00, 0x6C, 0x18, 0x00,
0x7C, 0x18, 0x00, 0x3C, 0x7F, 0x80, 0x1C, 0x7F, 0x80, 0x1C, 0x00, 0x7E,
0x00, 0x01, 0xFF, 0xC0, 0x07, 0x81, 0xE0, 0x0E, 0x00, 0x70, 0x1C, 0x00,
0x38, 0x38, 0x00, 0x1C, 0x30, 0x00, 0x0C, 0x70, 0x00, 0x0E, 0x60, 0x00,
0x06, 0x60, 0x00, 0x06, 0xC0, 0x00, 0x03, 0xC0, 0x00, 0x03, 0xC0, 0x00,
0x03, 0xC0, 0x00, 0x03, 0xC0, 0x00, 0x03, 0xC0, 0x00, 0x03, 0xC0, 0x00,
0x03, 0xC0, 0x00, 0x03, 0x60, 0x00, 0x06, 0x60, 0x00, 0x06, 0x70, 0x00,
0x0E, 0x30, 0x00, 0x0C, 0x38, 0x00, 0x1C, 0x1C, 0x00, 0x38, 0x0E, 0x00,
0x70, 0x07, 0x81, 0xE0, 0x03, 0xFF, 0xC0, 0x00, 0x7E, 0x00, 0xFF, 0xFF,
0x07, 0xFF, 0xFE, 0x06, 0x00, 0x78, 0x30, 0x00, 0xE1, 0x80, 0x03, 0x0C,
0x00, 0x0C, 0x60, 0x00, 0x63, 0x00, 0x03, 0x18, 0x00, 0x18, 0xC0, 0x01,
0xC6, 0x00, 0x0C, 0x30, 0x00, 0xC1, 0x80, 0x1E, 0x0F, 0xFF, 0xC0, 0x7F,
0xF8, 0x03, 0x00, 0x00, 0x18, 0x00, 0x00, 0xC0, 0x00, 0x06, 0x00, 0x00,
0x30, 0x00, 0x01, 0x80, 0x00, 0x0C, 0x00, 0x00, 0x60, 0x00, 0x03, 0x00,
0x00, 0xFF, 0xF0, 0x07, 0xFF, 0x80, 0x00, 0x00, 0x7E, 0x00, 0x01, 0xFF,
0x80, 0x07, 0x81, 0xE0, 0x0E, 0x00, 0x70, 0x1C, 0x00, 0x38, 0x38, 0x00,
0x1C, 0x30, 0x00, 0x0C, 0x70, 0x00, 0x0E, 0x60, 0x00, 0x06, 0x60, 0x00,
0x06, 0xC0, 0x00, 0x03, 0xC0, 0x00, 0x03, 0xC0, 0x00, 0x03, 0xC0, 0x00,
0x03, 0xC0, 0x00, 0x03, 0xC0, 0x00, 0x03, 0xC0, 0x00, 0x03, 0xC0, 0x00,
0x03, 0x60, 0x00, 0x06, 0x60, 0x00, 0x06, 0x70, 0x00, 0x0E, 0x30, 0x00,
0x0C, 0x18, 0x00, 0x1C, 0x0C, 0x00, 0x38, 0x06, 0x00, 0x70, 0x03, 0x81,
0xE0, 0x00, 0xFF, 0xC0, 0x00, 0x7E, 0x00, 0x00, 0xE0, 0x00, 0x03, 0xFF,
0x87, 0x07, 0xFF, 0xFE, 0x07, 0x00, 0xF8, 0xFF, 0xFE, 0x00, 0xFF, 0xFF,
0x80, 0x18, 0x03, 0xC0, 0x18, 0x00, 0xE0, 0x18, 0x00, 0x60, 0x18, 0x00,
0x30, 0x18, 0x00, 0x30, 0x18, 0x00, 0x30, 0x18, 0x00, 0x30, 0x18, 0x00,
0x70, 0x18, 0x00, 0x60, 0x18, 0x01, 0xC0, 0x18, 0x07, 0x80, 0x1F, 0xFF,
0x00, 0x1F, 0xFC, 0x00, 0x18, 0x0E, 0x00, 0x18, 0x07, 0x00, 0x18, 0x03,
0x80, 0x18, 0x01, 0xC0, 0x18, 0x00, 0xE0, 0x18, 0x00, 0x60, 0x18, 0x00,
0x30, 0x18, 0x00, 0x30, 0x18, 0x00, 0x18, 0xFF, 0x80, 0x1F, 0xFF, 0x80,
0x0F, 0x03, 0xF8, 0x00, 0xFF, 0xE6, 0x1E, 0x07, 0xE3, 0x80, 0x1E, 0x30,
0x00, 0xE6, 0x00, 0x06, 0x60, 0x00, 0x66, 0x00, 0x06, 0x60, 0x00, 0x07,
0x00, 0x00, 0x30, 0x00, 0x01, 0xC0, 0x00, 0x0F, 0xC0, 0x00, 0x3F, 0xC0,
0x00, 0x3F, 0x80, 0x00, 0x1C, 0x00, 0x00, 0xE0, 0x00, 0x07, 0x00, 0x00,
0x30, 0x00, 0x03, 0xC0, 0x00, 0x3C, 0x00, 0x03, 0xE0, 0x00, 0x7E, 0x00,
0x06, 0xF8, 0x01, 0xED, 0xE0, 0x7C, 0xCF, 0xFF, 0x00, 0x3F, 0xC0, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x03, 0x00, 0xF0, 0x0C, 0x03, 0xC0, 0x30,
0x0F, 0x00, 0xC0, 0x3C, 0x03, 0x00, 0xC0, 0x0C, 0x00, 0x00, 0x30, 0x00,
0x00, 0xC0, 0x00, 0x03, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x30, 0x00, 0x00,
0xC0, 0x00, 0x03, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x30, 0x00, 0x00, 0xC0,
0x00, 0x03, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x30, 0x00, 0x00, 0xC0, 0x00,
0x03, 0x00, 0x00, 0x0C, 0x00, 0x0F, 0xFF, 0xC0, 0x3F, 0xFF, 0x00, 0xFF,
0x01, 0xFF, 0xFE, 0x03, 0xFC, 0xC0, 0x00, 0x61, 0x80, 0x00, 0xC3, 0x00,
0x01, 0x86, 0x00, 0x03, 0x0C, 0x00, 0x06, 0x18, 0x00, 0x0C, 0x30, 0x00,
0x18, 0x60, 0x00, 0x30, 0xC0, 0x00, 0x61, 0x80, 0x00, 0xC3, 0x00, 0x01,
0x86, 0x00, 0x03, 0x0C, 0x00, 0x06, 0x18, 0x00, 0x0C, 0x30, 0x00, 0x18,
0x60, 0x00, 0x30, 0xC0, 0x00, 0x61, 0x80, 0x00, 0xC3, 0x80, 0x03, 0x83,
0x00, 0x06, 0x07, 0x00, 0x1C, 0x07, 0x00, 0x70, 0x07, 0x83, 0xC0, 0x07,
0xFF, 0x00, 0x03, 0xF8, 0x00, 0x7F, 0xC0, 0x3F, 0xF7, 0xFC, 0x03, 0xFF,
0x18, 0x00, 0x01, 0x80, 0xC0, 0x00, 0x30, 0x0C, 0x00, 0x03, 0x00, 0x60,
0x00, 0x30, 0x06, 0x00, 0x06, 0x00, 0x60, 0x00, 0x60, 0x03, 0x00, 0x0C,
0x00, 0x30, 0x00, 0xC0, 0x03, 0x80, 0x0C, 0x00, 0x18, 0x01, 0x80, 0x01,
0x80, 0x18, 0x00, 0x0C, 0x03, 0x00, 0x00, 0xC0, 0x30, 0x00, 0x0E, 0x03,
0x00, 0x00, 0x60, 0x60, 0x00, 0x06, 0x06, 0x00, 0x00, 0x30, 0xC0, 0x00,
0x03, 0x0C, 0x00, 0x00, 0x30, 0x80, 0x00, 0x01, 0x98, 0x00, 0x00, 0x19,
0x80, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0xE0, 0x00,
0xFF, 0x80, 0x7F, 0xFF, 0xE0, 0x1F, 0xF3, 0x00, 0x00, 0x30, 0xC0, 0x00,
0x0C, 0x30, 0x00, 0x03, 0x0C, 0x03, 0x80, 0xC3, 0x01, 0xE0, 0x30, 0x60,
0x78, 0x0C, 0x18, 0x1F, 0x02, 0x06, 0x04, 0xC0, 0x81, 0x83, 0x30, 0x60,
0x60, 0xCC, 0x18, 0x18, 0x31, 0x86, 0x06, 0x18, 0x61, 0x81, 0x86, 0x18,
0x60, 0x71, 0x87, 0x18, 0x0C, 0x40, 0xC6, 0x03, 0x30, 0x31, 0x00, 0xCC,
0x0C, 0xC0, 0x33, 0x01, 0xB0, 0x0D, 0x80, 0x6C, 0x03, 0x60, 0x1B, 0x00,
0xD8, 0x06, 0xC0, 0x34, 0x00, 0xF0, 0x07, 0x00, 0x3C, 0x01, 0xC0, 0x0E,
0x00, 0x7F, 0x00, 0xFF, 0x7F, 0x00, 0xFF, 0x18, 0x00, 0x18, 0x0C, 0x00,
0x38, 0x0E, 0x00, 0x70, 0x07, 0x00, 0x60, 0x03, 0x00, 0xC0, 0x01, 0x81,
0x80, 0x01, 0xC3, 0x80, 0x00, 0xE7, 0x00, 0x00, 0x76, 0x00, 0x00, 0x3C,
0x00, 0x00, 0x18, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x66,
0x00, 0x00, 0xC3, 0x00, 0x01, 0x81, 0x80, 0x03, 0x81, 0xC0, 0x07, 0x00,
0xE0, 0x06, 0x00, 0x60, 0x0C, 0x00, 0x30, 0x18, 0x00, 0x18, 0x38, 0x00,
0x1C, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00,
0xFF, 0x18, 0x00, 0x18, 0x0C, 0x00, 0x30, 0x0E, 0x00, 0x70, 0x06, 0x00,
0x60, 0x03, 0x00, 0xC0, 0x03, 0x81, 0xC0, 0x01, 0x81, 0x80, 0x00, 0xC3,
0x00, 0x00, 0xE7, 0x00, 0x00, 0x66, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x3C,
0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18,
0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18,
0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x07, 0xFF, 0xE0, 0x07, 0xFF,
0xE0, 0x7F, 0xFF, 0x9F, 0xFF, 0xE6, 0x00, 0x19, 0x80, 0x0C, 0x60, 0x07,
0x18, 0x03, 0x86, 0x00, 0xC1, 0x80, 0x70, 0x00, 0x38, 0x00, 0x0C, 0x00,
0x07, 0x00, 0x03, 0x80, 0x00, 0xC0, 0x00, 0x60, 0x00, 0x38, 0x00, 0x1C,
0x00, 0x06, 0x00, 0x03, 0x80, 0x31, 0xC0, 0x0C, 0x60, 0x03, 0x30, 0x00,
0xDC, 0x00, 0x3E, 0x00, 0x0F, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0,
0xFF, 0xFF, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC1, 0x83, 0x06, 0x0C, 0x18,
0x30, 0x60, 0xC1, 0x83, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC1, 0x83, 0x06,
0x0C, 0x18, 0x30, 0x60, 0xFF, 0xFC, 0xC0, 0x00, 0x30, 0x00, 0x06, 0x00,
0x01, 0x80, 0x00, 0x30, 0x00, 0x0C, 0x00, 0x01, 0x80, 0x00, 0x60, 0x00,
0x0C, 0x00, 0x03, 0x00, 0x00, 0x60, 0x00, 0x18, 0x00, 0x03, 0x00, 0x00,
0xC0, 0x00, 0x18, 0x00, 0x06, 0x00, 0x00, 0xC0, 0x00, 0x30, 0x00, 0x06,
0x00, 0x01, 0x80, 0x00, 0x30, 0x00, 0x0C, 0x00, 0x03, 0x80, 0x00, 0x60,
0x00, 0x1C, 0x00, 0x03, 0x00, 0x00, 0xE0, 0x00, 0x18, 0x00, 0x07, 0x00,
0x00, 0xC0, 0x00, 0x30, 0x00, 0x06, 0x00, 0x01, 0x80, 0x00, 0x30, 0x00,
0x0C, 0xFF, 0xFC, 0x18, 0x30, 0x60, 0xC1, 0x83, 0x06, 0x0C, 0x18, 0x30,
0x60, 0xC1, 0x83, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC1, 0x83, 0x06, 0x0C,
0x18, 0x30, 0x60, 0xC1, 0x83, 0xFF, 0xFC, 0x00, 0x40, 0x00, 0x30, 0x00,
0x1E, 0x00, 0x0E, 0xC0, 0x07, 0x38, 0x01, 0x87, 0x00, 0xC0, 0xC0, 0x60,
0x18, 0x38, 0x03, 0x1C, 0x00, 0xE6, 0x00, 0x1F, 0x00, 0x03, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xE0, 0x70, 0x3C, 0x0E, 0x07, 0x03,
0x01, 0xFC, 0x00, 0x7F, 0xFC, 0x01, 0xC0, 0x3C, 0x00, 0x00, 0x30, 0x00,
0x00, 0x60, 0x00, 0x01, 0x80, 0x00, 0x06, 0x00, 0x00, 0x18, 0x00, 0x00,
0x60, 0x0F, 0xF9, 0x81, 0xFF, 0xFE, 0x0F, 0x80, 0x38, 0x70, 0x00, 0x63,
0x80, 0x01, 0x8C, 0x00, 0x06, 0x30, 0x00, 0x18, 0xC0, 0x00, 0xE3, 0x00,
0x07, 0x86, 0x00, 0x76, 0x1E, 0x07, 0x9F, 0x3F, 0xF8, 0x7C, 0x3F, 0x80,
0x00, 0xF8, 0x00, 0x01, 0xF0, 0x00, 0x00, 0x60, 0x00, 0x00, 0xC0, 0x00,
0x01, 0x80, 0x00, 0x03, 0x00, 0x00, 0x06, 0x00, 0x00, 0x0C, 0x1F, 0x80,
0x18, 0xFF, 0xC0, 0x33, 0x81, 0xC0, 0x6E, 0x01, 0xC0, 0xF0, 0x00, 0xC1,
0xE0, 0x01, 0xC3, 0x80, 0x01, 0x87, 0x00, 0x03, 0x8C, 0x00, 0x03, 0x18,
0x00, 0x06, 0x30, 0x00, 0x0C, 0x60, 0x00, 0x18, 0xC0, 0x00, 0x31, 0x80,
0x00, 0x63, 0x80, 0x01, 0x87, 0x00, 0x03, 0x0F, 0x00, 0x0E, 0x1F, 0x00,
0x38, 0x37, 0x00, 0xE3, 0xE7, 0x03, 0x87, 0xC7, 0xFE, 0x00, 0x03, 0xF0,
0x00, 0x01, 0xFC, 0x00, 0x3F, 0xF9, 0x83, 0xC0, 0xFC, 0x38, 0x01, 0xE3,
0x00, 0x07, 0x38, 0x00, 0x19, 0x80, 0x00, 0xDC, 0x00, 0x06, 0xC0, 0x00,
0x06, 0x00, 0x00, 0x30, 0x00, 0x01, 0x80, 0x00, 0x0C, 0x00, 0x00, 0x60,
0x00, 0x03, 0x80, 0x00, 0x0C, 0x00, 0x00, 0x70, 0x00, 0x01, 0x80, 0x00,
0xC7, 0x00, 0x1E, 0x1E, 0x03, 0xC0, 0x7F, 0xFC, 0x00, 0xFF, 0x00, 0x00,
0x00, 0xF8, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00,
0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x01, 0xF8, 0x18, 0x07,
0xFE, 0x18, 0x0F, 0x07, 0x98, 0x1C, 0x01, 0xD8, 0x38, 0x00, 0xF8, 0x70,
0x00, 0x78, 0x60, 0x00, 0x38, 0xE0, 0x00, 0x38, 0xC0, 0x00, 0x18, 0xC0,
0x00, 0x18, 0xC0, 0x00, 0x18, 0xC0, 0x00, 0x18, 0xC0, 0x00, 0x18, 0xC0,
0x00, 0x18, 0x60, 0x00, 0x38, 0x60, 0x00, 0x38, 0x70, 0x00, 0x78, 0x38,
0x00, 0xD8, 0x1C, 0x01, 0xD8, 0x0F, 0x07, 0x9F, 0x07, 0xFE, 0x1F, 0x01,
0xF8, 0x00, 0x01, 0xFC, 0x00, 0x3F, 0xF8, 0x07, 0x80, 0xF0, 0x70, 0x01,
0xC3, 0x00, 0x07, 0x30, 0x00, 0x19, 0x80, 0x00, 0x78, 0x00, 0x03, 0xC0,
0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x0C, 0x00, 0x00,
0x60, 0x00, 0x01, 0x80, 0x00, 0x0C, 0x00, 0x00, 0x30, 0x00, 0x01, 0xC0,
0x00, 0xC7, 0x00, 0x0E, 0x1E, 0x03, 0xE0, 0x3F, 0xFC, 0x00, 0x7F, 0x00,
0x00, 0x7F, 0xC0, 0x3F, 0xFC, 0x0E, 0x00, 0x03, 0x80, 0x00, 0x60, 0x00,
0x0C, 0x00, 0x01, 0x80, 0x00, 0x30, 0x00, 0xFF, 0xFF, 0x9F, 0xFF, 0xF0,
0x18, 0x00, 0x03, 0x00, 0x00, 0x60, 0x00, 0x0C, 0x00, 0x01, 0x80, 0x00,
0x30, 0x00, 0x06, 0x00, 0x00, 0xC0, 0x00, 0x18, 0x00, 0x03, 0x00, 0x00,
0x60, 0x00, 0x0C, 0x00, 0x01, 0x80, 0x00, 0x30, 0x00, 0x06, 0x00, 0x00,
0xC0, 0x03, 0xFF, 0xFC, 0x7F, 0xFF, 0x80, 0x01, 0xF8, 0x00, 0x0F, 0xFC,
0x7C, 0x38, 0x1C, 0xF8, 0xE0, 0x0D, 0x83, 0x00, 0x0F, 0x0E, 0x00, 0x1E,
0x18, 0x00, 0x1C, 0x70, 0x00, 0x38, 0xC0, 0x00, 0x31, 0x80, 0x00, 0x63,
0x00, 0x00, 0xC6, 0x00, 0x01, 0x8C, 0x00, 0x03, 0x18, 0x00, 0x06, 0x18,
0x00, 0x1C, 0x30, 0x00, 0x38, 0x30, 0x00, 0xF0, 0x70, 0x03, 0x60, 0x78,
0x1C, 0xC0, 0x3F, 0xF1, 0x80, 0x1F, 0x83, 0x00, 0x00, 0x06, 0x00, 0x00,
0x0C, 0x00, 0x00, 0x18, 0x00, 0x00, 0x30, 0x00, 0x00, 0xC0, 0x00, 0x03,
0x80, 0x00, 0x0E, 0x00, 0x3F, 0xF8, 0x00, 0x7F, 0xC0, 0x00, 0xF8, 0x00,
0x01, 0xF0, 0x00, 0x00, 0x60, 0x00, 0x00, 0xC0, 0x00, 0x01, 0x80, 0x00,
0x03, 0x00, 0x00, 0x06, 0x00, 0x00, 0x0C, 0x3F, 0x00, 0x18, 0xFF, 0x80,
0x37, 0x03, 0x80, 0x7C, 0x03, 0x80, 0xF0, 0x03, 0x81, 0xC0, 0x03, 0x03,
0x00, 0x06, 0x06, 0x00, 0x0C, 0x0C, 0x00, 0x18, 0x18, 0x00, 0x30, 0x30,
0x00, 0x60, 0x60, 0x00, 0xC0, 0xC0, 0x01, 0x81, 0x80, 0x03, 0x03, 0x00,
0x06, 0x06, 0x00, 0x0C, 0x0C, 0x00, 0x18, 0x18, 0x00, 0x30, 0x30, 0x00,
0x63, 0xFC, 0x07, 0xFF, 0xF8, 0x0F, 0xF0, 0x01, 0xC0, 0x00, 0x70, 0x00,
0x1C, 0x00, 0x07, 0x00, 0x01, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x0F, 0xF0, 0x03, 0xFC, 0x00, 0x03, 0x00, 0x00, 0xC0,
0x00, 0x30, 0x00, 0x0C, 0x00, 0x03, 0x00, 0x00, 0xC0, 0x00, 0x30, 0x00,
0x0C, 0x00, 0x03, 0x00, 0x00, 0xC0, 0x00, 0x30, 0x00, 0x0C, 0x00, 0x03,
0x00, 0x00, 0xC0, 0x00, 0x30, 0x00, 0x0C, 0x03, 0xFF, 0xFF, 0xFF, 0xFF,
0xC0, 0x00, 0x70, 0x01, 0xC0, 0x07, 0x00, 0x1C, 0x00, 0x70, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xC0, 0x03, 0x00, 0x0C,
0x00, 0x30, 0x00, 0xC0, 0x03, 0x00, 0x0C, 0x00, 0x30, 0x00, 0xC0, 0x03,
0x00, 0x0C, 0x00, 0x30, 0x00, 0xC0, 0x03, 0x00, 0x0C, 0x00, 0x30, 0x00,
0xC0, 0x03, 0x00, 0x0C, 0x00, 0x30, 0x00, 0xC0, 0x03, 0x00, 0x0C, 0x00,
0x70, 0x03, 0x80, 0x1C, 0xFF, 0xE3, 0xFF, 0x00, 0xF8, 0x00, 0x03, 0xE0,
0x00, 0x01, 0x80, 0x00, 0x06, 0x00, 0x00, 0x18, 0x00, 0x00, 0x60, 0x00,
0x01, 0x80, 0x00, 0x06, 0x00, 0x00, 0x18, 0x1F, 0xE0, 0x60, 0x7F, 0x81,
0x80, 0x60, 0x06, 0x07, 0x00, 0x18, 0x38, 0x00, 0x61, 0xC0, 0x01, 0x8E,
0x00, 0x06, 0x70, 0x00, 0x1B, 0x80, 0x00, 0x7F, 0x00, 0x01, 0xCE, 0x00,
0x06, 0x1C, 0x00, 0x18, 0x38, 0x00, 0x60, 0x70, 0x01, 0x80, 0xE0, 0x06,
0x01, 0xC0, 0x18, 0x03, 0x80, 0x60, 0x07, 0x0F, 0x80, 0x7F, 0xFE, 0x01,
0xFF, 0x3F, 0xC0, 0x0F, 0xF0, 0x00, 0x0C, 0x00, 0x03, 0x00, 0x00, 0xC0,
0x00, 0x30, 0x00, 0x0C, 0x00, 0x03, 0x00, 0x00, 0xC0, 0x00, 0x30, 0x00,
0x0C, 0x00, 0x03, 0x00, 0x00, 0xC0, 0x00, 0x30, 0x00, 0x0C, 0x00, 0x03,
0x00, 0x00, 0xC0, 0x00, 0x30, 0x00, 0x0C, 0x00, 0x03, 0x00, 0x00, 0xC0,
0x00, 0x30, 0x00, 0x0C, 0x00, 0x03, 0x00, 0x00, 0xC0, 0x00, 0x30, 0x0F,
0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xF0, 0x3C, 0x0F, 0x9F, 0x87, 0xE0, 0xFB,
0x1C, 0xC7, 0x01, 0xE0, 0xD8, 0x38, 0x1C, 0x07, 0x01, 0x81, 0x80, 0x60,
0x18, 0x18, 0x06, 0x01, 0x81, 0x80, 0x60, 0x18, 0x18, 0x06, 0x01, 0x81,
0x80, 0x60, 0x18, 0x18, 0x06, 0x01, 0x81, 0x80, 0x60, 0x18, 0x18, 0x06,
0x01, 0x81, 0x80, 0x60, 0x18, 0x18, 0x06, 0x01, 0x81, 0x80, 0x60, 0x18,
0x18, 0x06, 0x01, 0x81, 0x80, 0x60, 0x18, 0x18, 0x06, 0x01, 0x8F, 0xE0,
0x7C, 0x1F, 0xFE, 0x07, 0xC1, 0xF0, 0x00, 0x1F, 0x00, 0xF8, 0xFF, 0x81,
0xF3, 0x83, 0x80, 0x6C, 0x03, 0x80, 0xF0, 0x03, 0x81, 0xC0, 0x03, 0x03,
0x00, 0x06, 0x06, 0x00, 0x0C, 0x0C, 0x00, 0x18, 0x18, 0x00, 0x30, 0x30,
0x00, 0x60, 0x60, 0x00, 0xC0, 0xC0, 0x01, 0x81, 0x80, 0x03, 0x03, 0x00,
0x06, 0x06, 0x00, 0x0C, 0x0C, 0x00, 0x18, 0x18, 0x00, 0x30, 0x30, 0x00,
0x67, 0xFC, 0x03, 0xFF, 0xF8, 0x07, 0xE0, 0x00, 0xFC, 0x00, 0x1F, 0xFE,
0x00, 0xF0, 0x3C, 0x07, 0x00, 0x38, 0x38, 0x00, 0x71, 0xC0, 0x00, 0xE6,
0x00, 0x01, 0x98, 0x00, 0x06, 0xC0, 0x00, 0x0F, 0x00, 0x00, 0x3C, 0x00,
0x00, 0xF0, 0x00, 0x03, 0xC0, 0x00, 0x0F, 0x00, 0x00, 0x36, 0x00, 0x01,
0x98, 0x00, 0x06, 0x70, 0x00, 0x38, 0xE0, 0x01, 0xC1, 0xC0, 0x0E, 0x03,
0xC0, 0xF0, 0x07, 0xFF, 0x80, 0x03, 0xF0, 0x00, 0x00, 0x3F, 0x01, 0xF1,
0xFF, 0x83, 0xE7, 0x03, 0x80, 0xD8, 0x01, 0x81, 0xE0, 0x01, 0x83, 0xC0,
0x03, 0x87, 0x00, 0x03, 0x0E, 0x00, 0x07, 0x18, 0x00, 0x06, 0x30, 0x00,
0x0C, 0x60, 0x00, 0x18, 0xC0, 0x00, 0x31, 0x80, 0x00, 0x63, 0x00, 0x00,
0xC7, 0x00, 0x03, 0x0E, 0x00, 0x06, 0x1E, 0x00, 0x18, 0x36, 0x00, 0x70,
0x67, 0x03, 0xC0, 0xC7, 0xFE, 0x01, 0x83, 0xF0, 0x03, 0x00, 0x00, 0x06,
0x00, 0x00, 0x0C, 0x00, 0x00, 0x18, 0x00, 0x00, 0x30, 0x00, 0x00, 0x60,
0x00, 0x00, 0xC0, 0x00, 0x0F, 0xFC, 0x00, 0x1F, 0xF8, 0x00, 0x00, 0x01,
0xF8, 0x00, 0x07, 0xFF, 0x1F, 0x0F, 0x07, 0x9F, 0x1C, 0x01, 0xD8, 0x38,
0x00, 0x78, 0x70, 0x00, 0x78, 0x60, 0x00, 0x38, 0xE0, 0x00, 0x38, 0xC0,
0x00, 0x18, 0xC0, 0x00, 0x18, 0xC0, 0x00, 0x18, 0xC0, 0x00, 0x18, 0xC0,
0x00, 0x18, 0xC0, 0x00, 0x18, 0x60, 0x00, 0x38, 0x70, 0x00, 0x78, 0x30,
0x00, 0x78, 0x1C, 0x01, 0xD8, 0x0F, 0x07, 0x98, 0x07, 0xFF, 0x18, 0x01,
0xFC, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00,
0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00,
0x03, 0xFF, 0x00, 0x03, 0xFF, 0x7E, 0x03, 0xC3, 0xF0, 0x7F, 0x81, 0x8F,
0x0E, 0x0C, 0xE0, 0x00, 0x7E, 0x00, 0x03, 0xC0, 0x00, 0x1C, 0x00, 0x00,
0xC0, 0x00, 0x06, 0x00, 0x00, 0x30, 0x00, 0x01, 0x80, 0x00, 0x0C, 0x00,
0x00, 0x60, 0x00, 0x03, 0x00, 0x00, 0x18, 0x00, 0x00, 0xC0, 0x00, 0x06,
0x00, 0x00, 0x30, 0x00, 0x3F, 0xFF, 0xC1, 0xFF, 0xFE, 0x00, 0x07, 0xF0,
0x07, 0xFF, 0x63, 0xC0, 0xF9, 0xC0, 0x0E, 0x60, 0x01, 0x98, 0x00, 0x66,
0x00, 0x19, 0xC0, 0x00, 0x38, 0x00, 0x07, 0xC0, 0x00, 0x7F, 0xC0, 0x00,
0x7C, 0x00, 0x03, 0x80, 0x00, 0x70, 0x00, 0x0F, 0x00, 0x03, 0xC0, 0x00,
0xF8, 0x00, 0x7F, 0x00, 0x3B, 0xF0, 0x3C, 0xDF, 0xFE, 0x00, 0xFE, 0x00,
0x0C, 0x00, 0x00, 0x60, 0x00, 0x03, 0x00, 0x00, 0x18, 0x00, 0x00, 0xC0,
0x00, 0x06, 0x00, 0x03, 0xFF, 0xFE, 0x1F, 0xFF, 0xF0, 0x0C, 0x00, 0x00,
0x60, 0x00, 0x03, 0x00, 0x00, 0x18, 0x00, 0x00, 0xC0, 0x00, 0x06, 0x00,
0x00, 0x30, 0x00, 0x01, 0x80, 0x00, 0x0C, 0x00, 0x00, 0x60, 0x00, 0x03,
0x00, 0x00, 0x18, 0x00, 0x00, 0xC0, 0x00, 0x06, 0x00, 0x00, 0x30, 0x00,
0x00, 0xC0, 0x07, 0x07, 0x01, 0xF0, 0x1F, 0xFF, 0x00, 0x3F, 0x80, 0xF8,
0x03, 0xF1, 0xF0, 0x07, 0xE0, 0x60, 0x00, 0xC0, 0xC0, 0x01, 0x81, 0x80,
0x03, 0x03, 0x00, 0x06, 0x06, 0x00, 0x0C, 0x0C, 0x00, 0x18, 0x18, 0x00,
0x30, 0x30, 0x00, 0x60, 0x60, 0x00, 0xC0, 0xC0, 0x01, 0x81, 0x80, 0x03,
0x03, 0x00, 0x06, 0x06, 0x00, 0x0C, 0x0C, 0x00, 0x38, 0x18, 0x00, 0xF0,
0x18, 0x03, 0x60, 0x38, 0x3C, 0xF8, 0x3F, 0xF1, 0xF0, 0x1F, 0x00, 0x00,
0x7F, 0xC0, 0xFF, 0xDF, 0xF0, 0x3F, 0xF0, 0xC0, 0x00, 0xC0, 0x30, 0x00,
0x30, 0x06, 0x00, 0x1C, 0x01, 0x80, 0x06, 0x00, 0x30, 0x01, 0x80, 0x0C,
0x00, 0xC0, 0x03, 0x80, 0x30, 0x00, 0x60, 0x18, 0x00, 0x18, 0x06, 0x00,
0x03, 0x03, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x18, 0x30, 0x00, 0x06, 0x18,
0x00, 0x00, 0xC6, 0x00, 0x00, 0x33, 0x00, 0x00, 0x0E, 0xC0, 0x00, 0x01,
0xE0, 0x00, 0x00, 0x78, 0x00, 0x7F, 0x00, 0x3F, 0xDF, 0xC0, 0x0F, 0xF1,
0x80, 0x00, 0x20, 0x60, 0x00, 0x18, 0x18, 0x00, 0x06, 0x06, 0x03, 0x01,
0x80, 0x81, 0xE0, 0x60, 0x30, 0x78, 0x10, 0x0C, 0x1E, 0x0C, 0x03, 0x0C,
0xC3, 0x00, 0xC3, 0x30, 0xC0, 0x10, 0xCC, 0x30, 0x06, 0x61, 0x98, 0x01,
0x98, 0x66, 0x00, 0x66, 0x19, 0x80, 0x0B, 0x03, 0x60, 0x03, 0xC0, 0xD0,
0x00, 0xF0, 0x1C, 0x00, 0x38, 0x07, 0x00, 0x0E, 0x01, 0xC0, 0x3F, 0x81,
0xFE, 0x3F, 0x81, 0xFE, 0x0C, 0x00, 0x38, 0x06, 0x00, 0x70, 0x03, 0x00,
0xE0, 0x01, 0x81, 0xC0, 0x00, 0xC3, 0x80, 0x00, 0x67, 0x00, 0x00, 0x3C,
0x00, 0x00, 0x18, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x67, 0x00, 0x00, 0xC3,
0x80, 0x01, 0x81, 0xC0, 0x03, 0x00, 0xE0, 0x06, 0x00, 0x70, 0x0C, 0x00,
0x38, 0x18, 0x00, 0x1C, 0x7F, 0x81, 0xFF, 0x7F, 0x81, 0xFF, 0x7F, 0x00,
0xFF, 0x7F, 0x00, 0xFF, 0x18, 0x00, 0x0C, 0x18, 0x00, 0x18, 0x0C, 0x00,
0x18, 0x0C, 0x00, 0x30, 0x06, 0x00, 0x30, 0x06, 0x00, 0x60, 0x03, 0x00,
0x60, 0x03, 0x00, 0xC0, 0x01, 0x80, 0xC0, 0x01, 0x81, 0x80, 0x00, 0xC1,
0x80, 0x00, 0xC3, 0x00, 0x00, 0x63, 0x00, 0x00, 0x66, 0x00, 0x00, 0x36,
0x00, 0x00, 0x34, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18,
0x00, 0x00, 0x18, 0x00, 0x00, 0x30, 0x00, 0x00, 0x30, 0x00, 0x00, 0x60,
0x00, 0x00, 0x60, 0x00, 0x00, 0xC0, 0x00, 0x7F, 0xFC, 0x00, 0x7F, 0xFC,
0x00, 0xFF, 0xFF, 0x7F, 0xFF, 0xB0, 0x01, 0x98, 0x01, 0xCC, 0x01, 0xC0,
0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xE0,
0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x03, 0x70,
0x01, 0xB0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0xE0, 0x7C, 0x0C,
0x03, 0x00, 0x60, 0x0C, 0x01, 0x80, 0x30, 0x06, 0x00, 0xC0, 0x18, 0x03,
0x00, 0x60, 0x0C, 0x03, 0x00, 0xE0, 0xF0, 0x1E, 0x00, 0x70, 0x06, 0x00,
0x60, 0x0C, 0x01, 0x80, 0x30, 0x06, 0x00, 0xC0, 0x18, 0x03, 0x00, 0x60,
0x0C, 0x01, 0x80, 0x18, 0x03, 0xE0, 0x1C, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xF0, 0xE0, 0x1F, 0x00, 0x60, 0x06, 0x00, 0xC0, 0x18,
0x03, 0x00, 0x60, 0x0C, 0x01, 0x80, 0x30, 0x06, 0x00, 0xC0, 0x18, 0x01,
0x80, 0x38, 0x01, 0xE0, 0x3C, 0x1C, 0x03, 0x00, 0xC0, 0x18, 0x03, 0x00,
0x60, 0x0C, 0x01, 0x80, 0x30, 0x06, 0x00, 0xC0, 0x18, 0x03, 0x00, 0xC0,
0xF8, 0x1C, 0x00, 0x0F, 0x00, 0x03, 0xFC, 0x03, 0x70, 0xE0, 0x76, 0x07,
0x8E, 0xC0, 0x1F, 0xC0, 0x00, 0xF0};
const GFXglyph FreeMono24pt7bGlyphs[] PROGMEM = {
{0, 0, 0, 28, 0, 1}, // 0x20 ' '
{0, 5, 30, 28, 11, -28}, // 0x21 '!'
{19, 16, 14, 28, 6, -28}, // 0x22 '"'
{47, 19, 32, 28, 4, -29}, // 0x23 '#'
{123, 18, 33, 28, 5, -29}, // 0x24 '$'
{198, 20, 29, 28, 4, -27}, // 0x25 '%'
{271, 18, 25, 28, 5, -23}, // 0x26 '&'
{328, 7, 14, 28, 11, -28}, // 0x27 '''
{341, 7, 34, 28, 14, -27}, // 0x28 '('
{371, 7, 34, 28, 8, -27}, // 0x29 ')'
{401, 18, 16, 28, 5, -27}, // 0x2A '*'
{437, 20, 22, 28, 4, -23}, // 0x2B '+'
{492, 9, 14, 28, 6, -6}, // 0x2C ','
{508, 22, 2, 28, 3, -13}, // 0x2D '-'
{514, 7, 6, 28, 11, -4}, // 0x2E '.'
{520, 18, 35, 28, 5, -30}, // 0x2F '/'
{599, 18, 30, 28, 5, -28}, // 0x30 '0'
{667, 16, 29, 28, 6, -28}, // 0x31 '1'
{725, 18, 29, 28, 5, -28}, // 0x32 '2'
{791, 19, 30, 28, 5, -28}, // 0x33 '3'
{863, 16, 28, 28, 6, -27}, // 0x34 '4'
{919, 19, 29, 28, 5, -27}, // 0x35 '5'
{988, 18, 30, 28, 6, -28}, // 0x36 '6'
{1056, 18, 28, 28, 5, -27}, // 0x37 '7'
{1119, 18, 30, 28, 5, -28}, // 0x38 '8'
{1187, 18, 30, 28, 6, -28}, // 0x39 '9'
{1255, 7, 21, 28, 11, -19}, // 0x3A ':'
{1274, 10, 27, 28, 7, -19}, // 0x3B ';'
{1308, 22, 22, 28, 3, -23}, // 0x3C '<'
{1369, 24, 9, 28, 2, -17}, // 0x3D '='
{1396, 21, 22, 28, 4, -23}, // 0x3E '>'
{1454, 17, 28, 28, 6, -26}, // 0x3F '?'
{1514, 18, 32, 28, 5, -28}, // 0x40 '@'
{1586, 28, 26, 28, 0, -25}, // 0x41 'A'
{1677, 22, 26, 28, 3, -25}, // 0x42 'B'
{1749, 22, 28, 28, 3, -26}, // 0x43 'C'
{1826, 22, 26, 28, 3, -25}, // 0x44 'D'
{1898, 22, 26, 28, 3, -25}, // 0x45 'E'
{1970, 22, 26, 28, 3, -25}, // 0x46 'F'
{2042, 23, 28, 28, 3, -26}, // 0x47 'G'
{2123, 23, 26, 28, 3, -25}, // 0x48 'H'
{2198, 16, 26, 28, 6, -25}, // 0x49 'I'
{2250, 23, 27, 28, 4, -25}, // 0x4A 'J'
{2328, 24, 26, 28, 3, -25}, // 0x4B 'K'
{2406, 21, 26, 28, 4, -25}, // 0x4C 'L'
{2475, 26, 26, 28, 1, -25}, // 0x4D 'M'
{2560, 24, 26, 28, 2, -25}, // 0x4E 'N'
{2638, 24, 28, 28, 2, -26}, // 0x4F 'O'
{2722, 21, 26, 28, 3, -25}, // 0x50 'P'
{2791, 24, 32, 28, 2, -26}, // 0x51 'Q'
{2887, 24, 26, 28, 3, -25}, // 0x52 'R'
{2965, 20, 28, 28, 4, -26}, // 0x53 'S'
{3035, 22, 26, 28, 3, -25}, // 0x54 'T'
{3107, 23, 27, 28, 3, -25}, // 0x55 'U'
{3185, 28, 26, 28, 0, -25}, // 0x56 'V'
{3276, 26, 26, 28, 1, -25}, // 0x57 'W'
{3361, 24, 26, 28, 2, -25}, // 0x58 'X'
{3439, 24, 26, 28, 2, -25}, // 0x59 'Y'
{3517, 18, 26, 28, 5, -25}, // 0x5A 'Z'
{3576, 7, 34, 28, 13, -27}, // 0x5B '['
{3606, 18, 35, 28, 5, -30}, // 0x5C '\'
{3685, 7, 34, 28, 8, -27}, // 0x5D ']'
{3715, 18, 12, 28, 5, -28}, // 0x5E '^'
{3742, 28, 2, 28, 0, 5}, // 0x5F '_'
{3749, 8, 7, 28, 7, -29}, // 0x60 '`'
{3756, 22, 22, 28, 3, -20}, // 0x61 'a'
{3817, 23, 29, 28, 2, -27}, // 0x62 'b'
{3901, 21, 22, 28, 4, -20}, // 0x63 'c'
{3959, 24, 29, 28, 3, -27}, // 0x64 'd'
{4046, 21, 22, 28, 3, -20}, // 0x65 'e'
{4104, 19, 28, 28, 6, -27}, // 0x66 'f'
{4171, 23, 30, 28, 3, -20}, // 0x67 'g'
{4258, 23, 28, 28, 3, -27}, // 0x68 'h'
{4339, 18, 29, 28, 5, -28}, // 0x69 'i'
{4405, 14, 38, 28, 6, -28}, // 0x6A 'j'
{4472, 22, 28, 28, 4, -27}, // 0x6B 'k'
{4549, 18, 28, 28, 5, -27}, // 0x6C 'l'
{4612, 28, 21, 28, 0, -20}, // 0x6D 'm'
{4686, 23, 21, 28, 2, -20}, // 0x6E 'n'
{4747, 22, 22, 28, 3, -20}, // 0x6F 'o'
{4808, 23, 30, 28, 2, -20}, // 0x70 'p'
{4895, 24, 30, 28, 3, -20}, // 0x71 'q'
{4985, 21, 20, 28, 5, -19}, // 0x72 'r'
{5038, 18, 22, 28, 5, -20}, // 0x73 's'
{5088, 21, 27, 28, 3, -25}, // 0x74 't'
{5159, 23, 21, 28, 3, -19}, // 0x75 'u'
{5220, 26, 20, 28, 1, -19}, // 0x76 'v'
{5285, 26, 20, 28, 1, -19}, // 0x77 'w'
{5350, 24, 20, 28, 2, -19}, // 0x78 'x'
{5410, 24, 29, 28, 2, -19}, // 0x79 'y'
{5497, 17, 20, 28, 6, -19}, // 0x7A 'z'
{5540, 11, 34, 28, 8, -27}, // 0x7B '{'
{5587, 2, 34, 28, 13, -27}, // 0x7C '|'
{5596, 11, 34, 28, 9, -27}, // 0x7D '}'
{5643, 20, 6, 28, 4, -15}}; // 0x7E '~'
const GFXfont FreeMono24pt7b PROGMEM = {(uint8_t *)FreeMono24pt7bBitmaps,
(GFXglyph *)FreeMono24pt7bGlyphs, 0x20,
0x7E, 47};
// Approx. 6330 bytes

View File

@@ -0,0 +1,178 @@
#pragma once
#include <Adafruit_GFX.h>
const uint8_t FreeMono9pt7bBitmaps[] PROGMEM = {
0xAA, 0xA8, 0x0C, 0xED, 0x24, 0x92, 0x48, 0x24, 0x48, 0x91, 0x2F, 0xE4,
0x89, 0x7F, 0x28, 0x51, 0x22, 0x40, 0x08, 0x3E, 0x62, 0x40, 0x30, 0x0E,
0x01, 0x81, 0xC3, 0xBE, 0x08, 0x08, 0x71, 0x12, 0x23, 0x80, 0x23, 0xB8,
0x0E, 0x22, 0x44, 0x70, 0x38, 0x81, 0x02, 0x06, 0x1A, 0x65, 0x46, 0xC8,
0xEC, 0xE9, 0x24, 0x5A, 0xAA, 0xA9, 0x40, 0xA9, 0x55, 0x5A, 0x80, 0x10,
0x22, 0x4B, 0xE3, 0x05, 0x11, 0x00, 0x10, 0x20, 0x47, 0xF1, 0x02, 0x04,
0x00, 0x6B, 0x48, 0xFF, 0x00, 0xF0, 0x02, 0x08, 0x10, 0x60, 0x81, 0x04,
0x08, 0x20, 0x41, 0x02, 0x08, 0x00, 0x38, 0x8A, 0x0C, 0x18, 0x30, 0x60,
0xC1, 0x82, 0x88, 0xE0, 0x27, 0x28, 0x42, 0x10, 0x84, 0x21, 0x3E, 0x38,
0x8A, 0x08, 0x10, 0x20, 0x82, 0x08, 0x61, 0x03, 0xF8, 0x7C, 0x06, 0x02,
0x02, 0x1C, 0x06, 0x01, 0x01, 0x01, 0x42, 0x3C, 0x18, 0xA2, 0x92, 0x8A,
0x28, 0xBF, 0x08, 0x21, 0xC0, 0x7C, 0x81, 0x03, 0xE4, 0x40, 0x40, 0x81,
0x03, 0x88, 0xE0, 0x1E, 0x41, 0x04, 0x0B, 0x98, 0xB0, 0xC1, 0xC2, 0x88,
0xE0, 0xFE, 0x04, 0x08, 0x20, 0x40, 0x82, 0x04, 0x08, 0x20, 0x40, 0x38,
0x8A, 0x0C, 0x14, 0x47, 0x11, 0x41, 0x83, 0x8C, 0xE0, 0x38, 0x8A, 0x1C,
0x18, 0x68, 0xCE, 0x81, 0x04, 0x13, 0xC0, 0xF0, 0x0F, 0x6C, 0x00, 0xD2,
0xD2, 0x00, 0x03, 0x04, 0x18, 0x60, 0x60, 0x18, 0x04, 0x03, 0xFF, 0x80,
0x00, 0x1F, 0xF0, 0x40, 0x18, 0x03, 0x00, 0x60, 0x20, 0x60, 0xC0, 0x80,
0x3D, 0x84, 0x08, 0x30, 0xC2, 0x00, 0x00, 0x00, 0x30, 0x3C, 0x46, 0x82,
0x8E, 0xB2, 0xA2, 0xA2, 0x9F, 0x80, 0x80, 0x40, 0x3C, 0x3C, 0x01, 0x40,
0x28, 0x09, 0x01, 0x10, 0x42, 0x0F, 0xC1, 0x04, 0x40, 0x9E, 0x3C, 0xFE,
0x21, 0x90, 0x48, 0x67, 0xE2, 0x09, 0x02, 0x81, 0x41, 0xFF, 0x80, 0x3E,
0xB0, 0xF0, 0x30, 0x08, 0x04, 0x02, 0x00, 0x80, 0x60, 0x8F, 0x80, 0xFE,
0x21, 0x90, 0x68, 0x14, 0x0A, 0x05, 0x02, 0x83, 0x43, 0x7F, 0x00, 0xFF,
0x20, 0x90, 0x08, 0x87, 0xC2, 0x21, 0x00, 0x81, 0x40, 0xFF, 0xC0, 0xFF,
0xA0, 0x50, 0x08, 0x87, 0xC2, 0x21, 0x00, 0x80, 0x40, 0x78, 0x00, 0x1E,
0x98, 0x6C, 0x0A, 0x00, 0x80, 0x20, 0xF8, 0x0B, 0x02, 0x60, 0x87, 0xC0,
0xE3, 0xA0, 0x90, 0x48, 0x27, 0xF2, 0x09, 0x04, 0x82, 0x41, 0x71, 0xC0,
0xF9, 0x08, 0x42, 0x10, 0x84, 0x27, 0xC0, 0x1F, 0x02, 0x02, 0x02, 0x02,
0x02, 0x82, 0x82, 0xC6, 0x78, 0xE3, 0xA1, 0x11, 0x09, 0x05, 0x83, 0x21,
0x08, 0x84, 0x41, 0x70, 0xC0, 0xE0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x41,
0x41, 0x41, 0xFF, 0xE0, 0xEC, 0x19, 0x45, 0x28, 0xA4, 0xA4, 0x94, 0x91,
0x12, 0x02, 0x40, 0x5C, 0x1C, 0xC3, 0xB0, 0x94, 0x4A, 0x24, 0x92, 0x49,
0x14, 0x8A, 0x43, 0x70, 0x80, 0x1E, 0x31, 0x90, 0x50, 0x18, 0x0C, 0x06,
0x02, 0x82, 0x63, 0x0F, 0x00, 0xFE, 0x43, 0x41, 0x41, 0x42, 0x7C, 0x40,
0x40, 0x40, 0xF0, 0x1C, 0x31, 0x90, 0x50, 0x18, 0x0C, 0x06, 0x02, 0x82,
0x63, 0x1F, 0x04, 0x07, 0x92, 0x30, 0xFE, 0x21, 0x90, 0x48, 0x24, 0x23,
0xE1, 0x10, 0x84, 0x41, 0x70, 0xC0, 0x3A, 0xCD, 0x0A, 0x03, 0x01, 0x80,
0xC1, 0xC7, 0x78, 0xFF, 0xC4, 0x62, 0x21, 0x00, 0x80, 0x40, 0x20, 0x10,
0x08, 0x1F, 0x00, 0xE3, 0xA0, 0x90, 0x48, 0x24, 0x12, 0x09, 0x04, 0x82,
0x22, 0x0E, 0x00, 0xF1, 0xE8, 0x10, 0x82, 0x10, 0x42, 0x10, 0x22, 0x04,
0x80, 0x50, 0x0C, 0x00, 0x80, 0xF1, 0xE8, 0x09, 0x11, 0x25, 0x44, 0xA8,
0x55, 0x0C, 0xA1, 0x8C, 0x31, 0x84, 0x30, 0xE3, 0xA0, 0x88, 0x82, 0x80,
0x80, 0xC0, 0x90, 0x44, 0x41, 0x71, 0xC0, 0xE3, 0xA0, 0x88, 0x82, 0x81,
0x40, 0x40, 0x20, 0x10, 0x08, 0x1F, 0x00, 0xFD, 0x0A, 0x20, 0x81, 0x04,
0x10, 0x21, 0x83, 0xFC, 0xEA, 0xAA, 0xAA, 0xC0, 0x80, 0x81, 0x03, 0x02,
0x04, 0x04, 0x08, 0x08, 0x10, 0x10, 0x20, 0x20, 0xD5, 0x55, 0x55, 0xC0,
0x10, 0x51, 0x22, 0x28, 0x20, 0xFF, 0xE0, 0x88, 0x80, 0x7E, 0x00, 0x80,
0x47, 0xEC, 0x14, 0x0A, 0x0C, 0xFB, 0xC0, 0x20, 0x10, 0x0B, 0xC6, 0x12,
0x05, 0x02, 0x81, 0x40, 0xB0, 0xB7, 0x80, 0x3A, 0x8E, 0x0C, 0x08, 0x10,
0x10, 0x9E, 0x03, 0x00, 0x80, 0x47, 0xA4, 0x34, 0x0A, 0x05, 0x02, 0x81,
0x21, 0x8F, 0x60, 0x3C, 0x43, 0x81, 0xFF, 0x80, 0x80, 0x61, 0x3E, 0x3D,
0x04, 0x3E, 0x41, 0x04, 0x10, 0x41, 0x0F, 0x80, 0x3D, 0xA1, 0xA0, 0x50,
0x28, 0x14, 0x09, 0x0C, 0x7A, 0x01, 0x01, 0x87, 0x80, 0xC0, 0x20, 0x10,
0x0B, 0xC6, 0x32, 0x09, 0x04, 0x82, 0x41, 0x20, 0xB8, 0xE0, 0x10, 0x01,
0xC0, 0x81, 0x02, 0x04, 0x08, 0x11, 0xFC, 0x10, 0x3E, 0x10, 0x84, 0x21,
0x08, 0x42, 0x3F, 0x00, 0xC0, 0x40, 0x40, 0x4F, 0x44, 0x58, 0x70, 0x48,
0x44, 0x42, 0xC7, 0x70, 0x20, 0x40, 0x81, 0x02, 0x04, 0x08, 0x10, 0x23,
0xF8, 0xB7, 0x64, 0x62, 0x31, 0x18, 0x8C, 0x46, 0x23, 0x91, 0x5E, 0x31,
0x90, 0x48, 0x24, 0x12, 0x09, 0x05, 0xC7, 0x3E, 0x31, 0xA0, 0x30, 0x18,
0x0C, 0x05, 0x8C, 0x7C, 0xDE, 0x30, 0x90, 0x28, 0x14, 0x0A, 0x05, 0x84,
0xBC, 0x40, 0x20, 0x38, 0x00, 0x3D, 0xA1, 0xA0, 0x50, 0x28, 0x14, 0x09,
0x0C, 0x7A, 0x01, 0x00, 0x80, 0xE0, 0xCE, 0xA1, 0x82, 0x04, 0x08, 0x10,
0x7C, 0x3A, 0x8D, 0x0B, 0x80, 0xF0, 0x70, 0xDE, 0x40, 0x40, 0xFC, 0x40,
0x40, 0x40, 0x40, 0x40, 0x41, 0x3E, 0xC3, 0x41, 0x41, 0x41, 0x41, 0x41,
0x43, 0x3D, 0xE3, 0xA0, 0x90, 0x84, 0x42, 0x20, 0xA0, 0x50, 0x10, 0xE3,
0xC0, 0x92, 0x4B, 0x25, 0x92, 0xA9, 0x98, 0x44, 0xE3, 0x31, 0x05, 0x01,
0x01, 0x41, 0x11, 0x05, 0xC7, 0xE3, 0xA0, 0x90, 0x84, 0x42, 0x40, 0xA0,
0x60, 0x10, 0x10, 0x08, 0x3E, 0x00, 0xFD, 0x08, 0x20, 0x82, 0x08, 0x10,
0xBF, 0x29, 0x24, 0xA2, 0x49, 0x26, 0xFF, 0xF8, 0x89, 0x24, 0x8A, 0x49,
0x2C, 0x61, 0x24, 0x30};
const GFXglyph FreeMono9pt7bGlyphs[] PROGMEM = {
{0, 0, 0, 11, 0, 1}, // 0x20 ' '
{0, 2, 11, 11, 4, -10}, // 0x21 '!'
{3, 6, 5, 11, 2, -10}, // 0x22 '"'
{7, 7, 12, 11, 2, -10}, // 0x23 '#'
{18, 8, 12, 11, 1, -10}, // 0x24 '$'
{30, 7, 11, 11, 2, -10}, // 0x25 '%'
{40, 7, 10, 11, 2, -9}, // 0x26 '&'
{49, 3, 5, 11, 4, -10}, // 0x27 '''
{51, 2, 13, 11, 5, -10}, // 0x28 '('
{55, 2, 13, 11, 4, -10}, // 0x29 ')'
{59, 7, 7, 11, 2, -10}, // 0x2A '*'
{66, 7, 7, 11, 2, -8}, // 0x2B '+'
{73, 3, 5, 11, 2, -1}, // 0x2C ','
{75, 9, 1, 11, 1, -5}, // 0x2D '-'
{77, 2, 2, 11, 4, -1}, // 0x2E '.'
{78, 7, 13, 11, 2, -11}, // 0x2F '/'
{90, 7, 11, 11, 2, -10}, // 0x30 '0'
{100, 5, 11, 11, 3, -10}, // 0x31 '1'
{107, 7, 11, 11, 2, -10}, // 0x32 '2'
{117, 8, 11, 11, 1, -10}, // 0x33 '3'
{128, 6, 11, 11, 3, -10}, // 0x34 '4'
{137, 7, 11, 11, 2, -10}, // 0x35 '5'
{147, 7, 11, 11, 2, -10}, // 0x36 '6'
{157, 7, 11, 11, 2, -10}, // 0x37 '7'
{167, 7, 11, 11, 2, -10}, // 0x38 '8'
{177, 7, 11, 11, 2, -10}, // 0x39 '9'
{187, 2, 8, 11, 4, -7}, // 0x3A ':'
{189, 3, 11, 11, 3, -7}, // 0x3B ';'
{194, 8, 8, 11, 1, -8}, // 0x3C '<'
{202, 9, 4, 11, 1, -6}, // 0x3D '='
{207, 9, 8, 11, 1, -8}, // 0x3E '>'
{216, 7, 10, 11, 2, -9}, // 0x3F '?'
{225, 8, 12, 11, 2, -10}, // 0x40 '@'
{237, 11, 10, 11, 0, -9}, // 0x41 'A'
{251, 9, 10, 11, 1, -9}, // 0x42 'B'
{263, 9, 10, 11, 1, -9}, // 0x43 'C'
{275, 9, 10, 11, 1, -9}, // 0x44 'D'
{287, 9, 10, 11, 1, -9}, // 0x45 'E'
{299, 9, 10, 11, 1, -9}, // 0x46 'F'
{311, 10, 10, 11, 1, -9}, // 0x47 'G'
{324, 9, 10, 11, 1, -9}, // 0x48 'H'
{336, 5, 10, 11, 3, -9}, // 0x49 'I'
{343, 8, 10, 11, 2, -9}, // 0x4A 'J'
{353, 9, 10, 11, 1, -9}, // 0x4B 'K'
{365, 8, 10, 11, 2, -9}, // 0x4C 'L'
{375, 11, 10, 11, 0, -9}, // 0x4D 'M'
{389, 9, 10, 11, 1, -9}, // 0x4E 'N'
{401, 9, 10, 11, 1, -9}, // 0x4F 'O'
{413, 8, 10, 11, 1, -9}, // 0x50 'P'
{423, 9, 13, 11, 1, -9}, // 0x51 'Q'
{438, 9, 10, 11, 1, -9}, // 0x52 'R'
{450, 7, 10, 11, 2, -9}, // 0x53 'S'
{459, 9, 10, 11, 1, -9}, // 0x54 'T'
{471, 9, 10, 11, 1, -9}, // 0x55 'U'
{483, 11, 10, 11, 0, -9}, // 0x56 'V'
{497, 11, 10, 11, 0, -9}, // 0x57 'W'
{511, 9, 10, 11, 1, -9}, // 0x58 'X'
{523, 9, 10, 11, 1, -9}, // 0x59 'Y'
{535, 7, 10, 11, 2, -9}, // 0x5A 'Z'
{544, 2, 13, 11, 5, -10}, // 0x5B '['
{548, 7, 13, 11, 2, -11}, // 0x5C '\'
{560, 2, 13, 11, 4, -10}, // 0x5D ']'
{564, 7, 5, 11, 2, -10}, // 0x5E '^'
{569, 11, 1, 11, 0, 2}, // 0x5F '_'
{571, 3, 3, 11, 3, -11}, // 0x60 '`'
{573, 9, 8, 11, 1, -7}, // 0x61 'a'
{582, 9, 11, 11, 1, -10}, // 0x62 'b'
{595, 7, 8, 11, 2, -7}, // 0x63 'c'
{602, 9, 11, 11, 1, -10}, // 0x64 'd'
{615, 8, 8, 11, 1, -7}, // 0x65 'e'
{623, 6, 11, 11, 3, -10}, // 0x66 'f'
{632, 9, 11, 11, 1, -7}, // 0x67 'g'
{645, 9, 11, 11, 1, -10}, // 0x68 'h'
{658, 7, 10, 11, 2, -9}, // 0x69 'i'
{667, 5, 13, 11, 3, -9}, // 0x6A 'j'
{676, 8, 11, 11, 2, -10}, // 0x6B 'k'
{687, 7, 11, 11, 2, -10}, // 0x6C 'l'
{697, 9, 8, 11, 1, -7}, // 0x6D 'm'
{706, 9, 8, 11, 1, -7}, // 0x6E 'n'
{715, 9, 8, 11, 1, -7}, // 0x6F 'o'
{724, 9, 11, 11, 1, -7}, // 0x70 'p'
{737, 9, 11, 11, 1, -7}, // 0x71 'q'
{750, 7, 8, 11, 3, -7}, // 0x72 'r'
{757, 7, 8, 11, 2, -7}, // 0x73 's'
{764, 8, 10, 11, 2, -9}, // 0x74 't'
{774, 8, 8, 11, 1, -7}, // 0x75 'u'
{782, 9, 8, 11, 1, -7}, // 0x76 'v'
{791, 9, 8, 11, 1, -7}, // 0x77 'w'
{800, 9, 8, 11, 1, -7}, // 0x78 'x'
{809, 9, 11, 11, 1, -7}, // 0x79 'y'
{822, 7, 8, 11, 2, -7}, // 0x7A 'z'
{829, 3, 13, 11, 4, -10}, // 0x7B '{'
{834, 1, 13, 11, 5, -10}, // 0x7C '|'
{836, 3, 13, 11, 4, -10}, // 0x7D '}'
{841, 7, 3, 11, 2, -6}}; // 0x7E '~'
const GFXfont FreeMono9pt7b PROGMEM = {(uint8_t *)FreeMono9pt7bBitmaps,
(GFXglyph *)FreeMono9pt7bGlyphs, 0x20,
0x7E, 18};
// Approx. 1516 bytes

View File

@@ -0,0 +1,252 @@
#pragma once
#include <Adafruit_GFX.h>
const uint8_t FreeMonoBold12pt7bBitmaps[] PROGMEM = {
0xFF, 0xFF, 0xFF, 0xF6, 0x66, 0x60, 0x6F, 0x60, 0xE7, 0xE7, 0x62, 0x42,
0x42, 0x42, 0x42, 0x11, 0x87, 0x30, 0xC6, 0x18, 0xC3, 0x31, 0xFF, 0xFF,
0xF9, 0x98, 0x33, 0x06, 0x60, 0xCC, 0x7F, 0xEF, 0xFC, 0x66, 0x0C, 0xC3,
0x98, 0x63, 0x04, 0x40, 0x0C, 0x03, 0x00, 0xC0, 0xFE, 0x7F, 0x9C, 0x66,
0x09, 0x80, 0x78, 0x0F, 0xE0, 0x7F, 0x03, 0xE0, 0xF8, 0x7F, 0xFB, 0xFC,
0x0C, 0x03, 0x00, 0xC0, 0x30, 0x38, 0x1F, 0x0C, 0x42, 0x10, 0xC4, 0x1F,
0x03, 0x9C, 0x3C, 0x7F, 0x33, 0xE0, 0x8C, 0x21, 0x08, 0xC3, 0xE0, 0x70,
0x3E, 0x1F, 0xC6, 0x61, 0x80, 0x70, 0x0C, 0x07, 0x83, 0xEE, 0xDF, 0xB3,
0xCC, 0x73, 0xFE, 0x7F, 0x80, 0xFD, 0x24, 0x90, 0x39, 0xDC, 0xE6, 0x73,
0x18, 0xC6, 0x31, 0x8C, 0x31, 0x8E, 0x31, 0xC4, 0xE7, 0x1C, 0xE3, 0x1C,
0x63, 0x18, 0xC6, 0x31, 0x98, 0xCE, 0x67, 0x10, 0x0C, 0x03, 0x00, 0xC3,
0xB7, 0xFF, 0xDF, 0xE1, 0xE0, 0xFC, 0x33, 0x0C, 0xC0, 0x06, 0x00, 0x60,
0x06, 0x00, 0x60, 0x06, 0x0F, 0xFF, 0xFF, 0xF0, 0x60, 0x06, 0x00, 0x60,
0x06, 0x00, 0x60, 0x06, 0x00, 0x3B, 0x9C, 0xCE, 0x62, 0x00, 0xFF, 0xFF,
0xFF, 0xFF, 0x80, 0x00, 0x40, 0x30, 0x1C, 0x07, 0x03, 0x80, 0xE0, 0x30,
0x1C, 0x06, 0x03, 0x80, 0xC0, 0x70, 0x18, 0x0E, 0x03, 0x01, 0xC0, 0x60,
0x38, 0x0E, 0x01, 0x00, 0x1E, 0x0F, 0xC6, 0x1B, 0x87, 0xC0, 0xF0, 0x3C,
0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x87, 0x61, 0x8F, 0xC1, 0xE0, 0x1C,
0x0F, 0x0F, 0xC3, 0xB0, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00,
0xC0, 0x30, 0x0C, 0x3F, 0xFF, 0xFC, 0x1F, 0x1F, 0xEE, 0x1F, 0x83, 0xC0,
0xC0, 0x70, 0x38, 0x1E, 0x0F, 0x07, 0x83, 0xC1, 0xE3, 0xF0, 0xFF, 0xFF,
0xFC, 0x3F, 0x0F, 0xF1, 0x87, 0x00, 0x60, 0x0C, 0x03, 0x83, 0xE0, 0x7C,
0x01, 0xC0, 0x0C, 0x01, 0x80, 0x3C, 0x0F, 0xFF, 0x9F, 0xC0, 0x07, 0x07,
0x83, 0xC3, 0xE1, 0xB1, 0xD8, 0xCC, 0xC6, 0xE3, 0x7F, 0xFF, 0xE0, 0x61,
0xF8, 0xFC, 0x7F, 0x9F, 0xE6, 0x01, 0x80, 0x60, 0x1F, 0x87, 0xF9, 0x86,
0x00, 0xC0, 0x30, 0x0C, 0x03, 0xC1, 0xBF, 0xE7, 0xE0, 0x07, 0xC7, 0xF3,
0xC1, 0xC0, 0x60, 0x38, 0x0E, 0xF3, 0xFE, 0xF1, 0xF8, 0x3E, 0x0F, 0x83,
0x71, 0xCF, 0xE1, 0xF0, 0xFF, 0xFF, 0xFC, 0x1F, 0x07, 0x01, 0x80, 0x60,
0x38, 0x0C, 0x03, 0x01, 0xC0, 0x60, 0x18, 0x0E, 0x03, 0x00, 0xC0, 0x1E,
0x1F, 0xEE, 0x1F, 0x03, 0xC0, 0xF0, 0x36, 0x19, 0xFE, 0x7F, 0xB8, 0x7C,
0x0F, 0x03, 0xE1, 0xDF, 0xE3, 0xF0, 0x3E, 0x1F, 0xCE, 0x3B, 0x07, 0xC1,
0xF0, 0x7E, 0x3D, 0xFF, 0x3D, 0xC0, 0x70, 0x18, 0x0E, 0x0F, 0x3F, 0x8F,
0x80, 0xFF, 0x80, 0x00, 0xFF, 0x80, 0x77, 0x70, 0x00, 0x00, 0x76, 0x6C,
0xC8, 0x80, 0x00, 0x30, 0x0F, 0x03, 0xE0, 0xF8, 0x3E, 0x0F, 0x80, 0x3E,
0x00, 0xF8, 0x03, 0xE0, 0x0F, 0x00, 0x20, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xF0, 0x60, 0x0F, 0x80, 0x3E, 0x00, 0xF8,
0x03, 0xE0, 0x1F, 0x07, 0xC1, 0xF0, 0x7C, 0x0F, 0x00, 0x40, 0x00, 0x7C,
0x7F, 0xB0, 0xF8, 0x30, 0x18, 0x1C, 0x3C, 0x3C, 0x18, 0x08, 0x00, 0x07,
0x03, 0x81, 0xC0, 0x1E, 0x07, 0xF1, 0xC7, 0x30, 0x6C, 0x0D, 0x87, 0xB3,
0xF6, 0xE6, 0xD8, 0xDB, 0x1B, 0x73, 0x67, 0xFC, 0x7F, 0x80, 0x30, 0x03,
0x00, 0x71, 0xC7, 0xF8, 0x7C, 0x00, 0x3F, 0x80, 0x7F, 0x80, 0x1F, 0x00,
0x76, 0x00, 0xEE, 0x01, 0x8C, 0x07, 0x18, 0x0E, 0x38, 0x1F, 0xF0, 0x7F,
0xF0, 0xC0, 0x61, 0x80, 0xCF, 0xC7, 0xFF, 0x8F, 0xC0, 0xFF, 0xC7, 0xFF,
0x0C, 0x1C, 0x60, 0x63, 0x03, 0x18, 0x38, 0xFF, 0x87, 0xFE, 0x30, 0x39,
0x80, 0xCC, 0x06, 0x60, 0x7F, 0xFF, 0x7F, 0xF0, 0x0F, 0xF3, 0xFF, 0x70,
0x76, 0x03, 0xC0, 0x3C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0x60,
0x37, 0x07, 0x3F, 0xF0, 0xFC, 0xFF, 0x0F, 0xFC, 0x60, 0xE6, 0x06, 0x60,
0x36, 0x03, 0x60, 0x36, 0x03, 0x60, 0x36, 0x03, 0x60, 0x76, 0x0E, 0xFF,
0xCF, 0xF8, 0xFF, 0xF7, 0xFF, 0x8C, 0x0C, 0x60, 0x63, 0x1B, 0x18, 0xC0,
0xFE, 0x07, 0xF0, 0x31, 0x81, 0x8C, 0xCC, 0x06, 0x60, 0x3F, 0xFF, 0xFF,
0xFC, 0xFF, 0xFF, 0xFF, 0xCC, 0x06, 0x60, 0x33, 0x19, 0x98, 0xC0, 0xFE,
0x07, 0xF0, 0x31, 0x81, 0x8C, 0x0C, 0x00, 0x60, 0x0F, 0xF0, 0x7F, 0x80,
0x0F, 0xF1, 0xFF, 0x9C, 0x1C, 0xC0, 0x6C, 0x03, 0x60, 0x03, 0x00, 0x18,
0x7F, 0xC3, 0xFE, 0x01, 0xB8, 0x0C, 0xE0, 0xE3, 0xFF, 0x07, 0xE0, 0x7C,
0xF9, 0xF3, 0xE3, 0x03, 0x0C, 0x0C, 0x30, 0x30, 0xC0, 0xC3, 0xFF, 0x0F,
0xFC, 0x30, 0x30, 0xC0, 0xC3, 0x03, 0x0C, 0x0C, 0xFC, 0xFF, 0xF3, 0xF0,
0xFF, 0xFF, 0xF0, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03,
0x00, 0xC0, 0x30, 0xFF, 0xFF, 0xF0, 0x0F, 0xF8, 0x7F, 0xC0, 0x30, 0x01,
0x80, 0x0C, 0x00, 0x60, 0x03, 0x18, 0x18, 0xC0, 0xC6, 0x06, 0x30, 0x31,
0xC3, 0x0F, 0xF8, 0x1F, 0x00, 0xFC, 0xFB, 0xF3, 0xE3, 0x0E, 0x0C, 0x70,
0x33, 0x80, 0xFC, 0x03, 0xF0, 0x0F, 0xE0, 0x39, 0xC0, 0xC3, 0x03, 0x0E,
0x0C, 0x18, 0xFC, 0x7F, 0xF0, 0xF0, 0xFF, 0x0F, 0xF0, 0x18, 0x01, 0x80,
0x18, 0x01, 0x80, 0x18, 0x01, 0x80, 0x18, 0x31, 0x83, 0x18, 0x31, 0x83,
0xFF, 0xFF, 0xFF, 0xF0, 0x3F, 0xC0, 0xF7, 0x87, 0x9E, 0x1E, 0x7C, 0xF9,
0xB3, 0xE6, 0xFD, 0x99, 0xF6, 0x67, 0x99, 0x8E, 0x66, 0x31, 0x98, 0x06,
0xFC, 0xFF, 0xF3, 0xF0, 0xF1, 0xFF, 0xCF, 0xCF, 0x0C, 0x78, 0x63, 0xE3,
0x1B, 0x18, 0xDC, 0xC6, 0x76, 0x31, 0xB1, 0x8F, 0x8C, 0x3C, 0x61, 0xE7,
0xE7, 0x3F, 0x18, 0x0F, 0x03, 0xFC, 0x70, 0xE6, 0x06, 0xE0, 0x7C, 0x03,
0xC0, 0x3C, 0x03, 0xC0, 0x3E, 0x07, 0x60, 0x67, 0x0E, 0x3F, 0xC0, 0xF0,
0xFF, 0x8F, 0xFE, 0x30, 0x73, 0x03, 0x30, 0x33, 0x03, 0x30, 0x73, 0xFE,
0x3F, 0x83, 0x00, 0x30, 0x03, 0x00, 0xFF, 0x0F, 0xF0, 0x0F, 0x03, 0xFC,
0x70, 0xE6, 0x06, 0xE0, 0x7C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x3E, 0x07,
0x60, 0x67, 0x0E, 0x3F, 0xC1, 0xF0, 0x18, 0x33, 0xFF, 0x3F, 0xE0, 0xFF,
0x83, 0xFF, 0x83, 0x07, 0x0C, 0x0C, 0x30, 0x30, 0xC1, 0xC3, 0xFE, 0x0F,
0xF0, 0x31, 0xE0, 0xC3, 0x83, 0x07, 0x0C, 0x0C, 0xFE, 0x3F, 0xF8, 0x70,
0x3F, 0xDF, 0xFE, 0x1F, 0x03, 0xC0, 0xF8, 0x07, 0xE0, 0x7E, 0x01, 0xF0,
0x3C, 0x0F, 0x87, 0xFF, 0xBF, 0xC0, 0xFF, 0xFF, 0xFF, 0xC6, 0x3C, 0x63,
0xC6, 0x3C, 0x63, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60,
0x3F, 0xC3, 0xFC, 0xFF, 0xFF, 0xFF, 0x60, 0x66, 0x06, 0x60, 0x66, 0x06,
0x60, 0x66, 0x06, 0x60, 0x66, 0x06, 0x60, 0x63, 0x9C, 0x1F, 0xC0, 0xF0,
0xFC, 0x3F, 0xFC, 0x3F, 0x30, 0x0C, 0x38, 0x1C, 0x18, 0x18, 0x1C, 0x38,
0x1C, 0x38, 0x0E, 0x70, 0x0E, 0x70, 0x0F, 0x60, 0x07, 0xE0, 0x07, 0xE0,
0x03, 0xC0, 0x03, 0xC0, 0xFC, 0xFF, 0xF3, 0xF6, 0x01, 0xDC, 0xC6, 0x77,
0x99, 0xDE, 0x67, 0x79, 0x8D, 0xFE, 0x3F, 0xF8, 0xF3, 0xE3, 0xCF, 0x8F,
0x3C, 0x38, 0x70, 0xE1, 0xC0, 0xF8, 0xFB, 0xE3, 0xE3, 0x86, 0x0F, 0x38,
0x1F, 0xC0, 0x3E, 0x00, 0x70, 0x03, 0xE0, 0x0F, 0x80, 0x77, 0x03, 0x8E,
0x1E, 0x1C, 0xFC, 0xFF, 0xF3, 0xF0, 0xF9, 0xFF, 0x9F, 0x30, 0xC3, 0x9C,
0x19, 0x81, 0xF8, 0x0F, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60,
0x3F, 0xC3, 0xFC, 0xFF, 0xBF, 0xEC, 0x3B, 0x0C, 0xC6, 0x33, 0x80, 0xC0,
0x60, 0x38, 0xCC, 0x36, 0x0F, 0x03, 0xFF, 0xFF, 0xF0, 0xFF, 0xF1, 0x8C,
0x63, 0x18, 0xC6, 0x31, 0x8C, 0x63, 0x18, 0xC7, 0xFE, 0x40, 0x30, 0x0E,
0x01, 0x80, 0x70, 0x0C, 0x03, 0x80, 0x60, 0x1C, 0x03, 0x00, 0xE0, 0x18,
0x07, 0x00, 0xC0, 0x38, 0x0E, 0x01, 0xC0, 0x70, 0x0C, 0x01, 0xFF, 0xC6,
0x31, 0x8C, 0x63, 0x18, 0xC6, 0x31, 0x8C, 0x63, 0x1F, 0xFE, 0x04, 0x03,
0x01, 0xE0, 0xFC, 0x7B, 0x9C, 0x7E, 0x1F, 0x03, 0xFF, 0xFF, 0xFF, 0xF0,
0xCE, 0x73, 0x3F, 0x07, 0xF8, 0x00, 0xC0, 0x0C, 0x1F, 0xC7, 0xFC, 0x60,
0xCC, 0x0C, 0xC1, 0xCF, 0xFF, 0x3F, 0xF0, 0xF0, 0x07, 0x80, 0x0C, 0x00,
0x60, 0x03, 0x7C, 0x1F, 0xF8, 0xF1, 0xC7, 0x07, 0x30, 0x19, 0x80, 0xCC,
0x06, 0x60, 0x73, 0xC7, 0x7F, 0xFB, 0xDF, 0x00, 0x1F, 0xB3, 0xFF, 0x70,
0xFE, 0x07, 0xC0, 0x3C, 0x00, 0xC0, 0x0C, 0x00, 0x70, 0x77, 0xFF, 0x1F,
0xC0, 0x01, 0xE0, 0x0F, 0x00, 0x18, 0x00, 0xC1, 0xF6, 0x3F, 0xF1, 0xC7,
0x9C, 0x1C, 0xC0, 0x66, 0x03, 0x30, 0x19, 0x81, 0xC7, 0x1E, 0x3F, 0xFC,
0x7D, 0xE0, 0x1F, 0x83, 0xFC, 0x70, 0xEE, 0x07, 0xFF, 0xFF, 0xFF, 0xE0,
0x0E, 0x00, 0x70, 0x73, 0xFF, 0x1F, 0xC0, 0x07, 0xC3, 0xFC, 0x60, 0x0C,
0x0F, 0xFD, 0xFF, 0x86, 0x00, 0xC0, 0x18, 0x03, 0x00, 0x60, 0x0C, 0x01,
0x81, 0xFF, 0xBF, 0xF0, 0x1F, 0x79, 0xFF, 0xDC, 0x79, 0x81, 0xCC, 0x06,
0x60, 0x33, 0x01, 0x9C, 0x1C, 0x71, 0xE1, 0xFF, 0x07, 0xD8, 0x00, 0xC0,
0x06, 0x00, 0x70, 0x7F, 0x03, 0xF0, 0xF0, 0x03, 0xC0, 0x03, 0x00, 0x0C,
0x00, 0x37, 0xC0, 0xFF, 0x83, 0xC7, 0x0C, 0x0C, 0x30, 0x30, 0xC0, 0xC3,
0x03, 0x0C, 0x0C, 0x30, 0x33, 0xF3, 0xFF, 0xCF, 0xC0, 0x06, 0x00, 0xC0,
0x00, 0x3F, 0x07, 0xE0, 0x0C, 0x01, 0x80, 0x30, 0x06, 0x00, 0xC0, 0x18,
0x03, 0x0F, 0xFF, 0xFF, 0xC0, 0x06, 0x06, 0x00, 0xFF, 0xFF, 0x03, 0x03,
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x07, 0xFE, 0xFC,
0xF0, 0x07, 0x80, 0x0C, 0x00, 0x60, 0x03, 0x3F, 0x19, 0xF8, 0xDE, 0x07,
0xE0, 0x3E, 0x01, 0xF0, 0x0F, 0xC0, 0x6F, 0x03, 0x1C, 0x78, 0xFF, 0xC7,
0xE0, 0x7E, 0x0F, 0xC0, 0x18, 0x03, 0x00, 0x60, 0x0C, 0x01, 0x80, 0x30,
0x06, 0x00, 0xC0, 0x18, 0x03, 0x00, 0x61, 0xFF, 0xFF, 0xF8, 0xFE, 0xF1,
0xFF, 0xF1, 0xCE, 0x63, 0x18, 0xC6, 0x31, 0x8C, 0x63, 0x18, 0xC6, 0x31,
0x8C, 0x63, 0x19, 0xF7, 0xBF, 0xEF, 0x78, 0x77, 0xC1, 0xFF, 0x83, 0xC7,
0x0C, 0x0C, 0x30, 0x30, 0xC0, 0xC3, 0x03, 0x0C, 0x0C, 0x30, 0x33, 0xF1,
0xFF, 0xC7, 0xC0, 0x1F, 0x83, 0xFC, 0x70, 0xEE, 0x07, 0xC0, 0x3C, 0x03,
0xC0, 0x3E, 0x07, 0x70, 0xE3, 0xFC, 0x1F, 0x80, 0xF7, 0xE3, 0xFF, 0xC3,
0xC3, 0x8E, 0x07, 0x30, 0x0C, 0xC0, 0x33, 0x00, 0xCE, 0x07, 0x3C, 0x38,
0xFF, 0xC3, 0x7E, 0x0C, 0x00, 0x30, 0x00, 0xC0, 0x0F, 0xE0, 0x3F, 0x80,
0x1F, 0xBC, 0xFF, 0xF7, 0x0F, 0x38, 0x1C, 0xC0, 0x33, 0x00, 0xCC, 0x03,
0x38, 0x1C, 0x70, 0xF0, 0xFF, 0xC1, 0xFB, 0x00, 0x0C, 0x00, 0x30, 0x00,
0xC0, 0x1F, 0xC0, 0x7F, 0x79, 0xE7, 0xFF, 0x1F, 0x31, 0xC0, 0x18, 0x01,
0x80, 0x18, 0x01, 0x80, 0x18, 0x0F, 0xFC, 0xFF, 0xC0, 0x3F, 0x9F, 0xFE,
0x1F, 0x82, 0xFE, 0x1F, 0xE0, 0xFF, 0x03, 0xE0, 0xFF, 0xFF, 0xF0, 0x30,
0x06, 0x00, 0xC0, 0x7F, 0xEF, 0xFC, 0x60, 0x0C, 0x01, 0x80, 0x30, 0x06,
0x00, 0xC0, 0x18, 0x71, 0xFE, 0x1F, 0x00, 0xF1, 0xF7, 0x8F, 0x8C, 0x0C,
0x60, 0x63, 0x03, 0x18, 0x18, 0xC0, 0xC6, 0x06, 0x38, 0xF0, 0xFF, 0xC3,
0xEE, 0xFC, 0xFF, 0xF3, 0xF3, 0x87, 0x0E, 0x1C, 0x1C, 0x60, 0x73, 0x80,
0xEC, 0x03, 0xF0, 0x07, 0x80, 0x1E, 0x00, 0x78, 0x00, 0xF8, 0x7F, 0xE1,
0xF7, 0x39, 0x8C, 0xE6, 0x37, 0xB0, 0xFF, 0xC3, 0xFF, 0x07, 0xBC, 0x1C,
0xF0, 0x73, 0x81, 0x86, 0x00, 0x7C, 0xF9, 0xF3, 0xE3, 0xCF, 0x07, 0xF8,
0x0F, 0xC0, 0x1E, 0x00, 0xFC, 0x07, 0x38, 0x38, 0x73, 0xF3, 0xFF, 0xCF,
0xC0, 0xF9, 0xFF, 0x9F, 0x70, 0xE3, 0x0C, 0x39, 0xC1, 0x98, 0x19, 0x81,
0xF8, 0x0F, 0x00, 0xF0, 0x06, 0x00, 0x60, 0x0E, 0x00, 0xC0, 0xFF, 0x0F,
0xF0, 0x7F, 0xCF, 0xF9, 0x8E, 0x33, 0x80, 0x70, 0x1C, 0x07, 0x01, 0xC6,
0x70, 0xFF, 0xFF, 0xFF, 0x80, 0x0E, 0x3C, 0x60, 0xC1, 0x83, 0x06, 0x0C,
0x39, 0xE3, 0xC0, 0xC1, 0x83, 0x06, 0x0C, 0x18, 0x3C, 0x38, 0xFF, 0xFF,
0xFF, 0xFF, 0xF0, 0xE1, 0xC0, 0xC1, 0x83, 0x06, 0x0C, 0x18, 0x30, 0x3C,
0x79, 0x83, 0x06, 0x0C, 0x18, 0x31, 0xE3, 0x80, 0x3C, 0x37, 0xE7, 0x67,
0xE6, 0x1C};
const GFXglyph FreeMonoBold12pt7bGlyphs[] PROGMEM = {
{0, 0, 0, 14, 0, 1}, // 0x20 ' '
{0, 4, 15, 14, 5, -14}, // 0x21 '!'
{8, 8, 7, 14, 3, -13}, // 0x22 '"'
{15, 11, 18, 14, 2, -15}, // 0x23 '#'
{40, 10, 20, 14, 2, -16}, // 0x24 '$'
{65, 10, 15, 14, 2, -14}, // 0x25 '%'
{84, 10, 13, 14, 2, -12}, // 0x26 '&'
{101, 3, 7, 14, 5, -13}, // 0x27 '''
{104, 5, 19, 14, 6, -14}, // 0x28 '('
{116, 5, 19, 14, 3, -14}, // 0x29 ')'
{128, 10, 10, 14, 2, -14}, // 0x2A '*'
{141, 12, 13, 14, 1, -12}, // 0x2B '+'
{161, 5, 7, 14, 4, -2}, // 0x2C ','
{166, 12, 2, 14, 1, -7}, // 0x2D '-'
{169, 3, 3, 14, 5, -2}, // 0x2E '.'
{171, 10, 20, 14, 2, -16}, // 0x2F '/'
{196, 10, 15, 14, 2, -14}, // 0x30 '0'
{215, 10, 15, 14, 2, -14}, // 0x31 '1'
{234, 10, 15, 14, 2, -14}, // 0x32 '2'
{253, 11, 15, 14, 1, -14}, // 0x33 '3'
{274, 9, 14, 14, 2, -13}, // 0x34 '4'
{290, 10, 15, 14, 2, -14}, // 0x35 '5'
{309, 10, 15, 14, 2, -14}, // 0x36 '6'
{328, 10, 15, 14, 2, -14}, // 0x37 '7'
{347, 10, 15, 14, 2, -14}, // 0x38 '8'
{366, 10, 15, 14, 3, -14}, // 0x39 '9'
{385, 3, 11, 14, 5, -10}, // 0x3A ':'
{390, 4, 15, 14, 4, -10}, // 0x3B ';'
{398, 12, 11, 14, 1, -11}, // 0x3C '<'
{415, 12, 7, 14, 1, -9}, // 0x3D '='
{426, 12, 11, 14, 1, -11}, // 0x3E '>'
{443, 9, 14, 14, 3, -13}, // 0x3F '?'
{459, 11, 19, 14, 2, -14}, // 0x40 '@'
{486, 15, 14, 14, -1, -13}, // 0x41 'A'
{513, 13, 14, 14, 0, -13}, // 0x42 'B'
{536, 12, 14, 14, 1, -13}, // 0x43 'C'
{557, 12, 14, 14, 1, -13}, // 0x44 'D'
{578, 13, 14, 14, 0, -13}, // 0x45 'E'
{601, 13, 14, 14, 0, -13}, // 0x46 'F'
{624, 13, 14, 14, 1, -13}, // 0x47 'G'
{647, 14, 14, 14, 0, -13}, // 0x48 'H'
{672, 10, 14, 14, 2, -13}, // 0x49 'I'
{690, 13, 14, 14, 1, -13}, // 0x4A 'J'
{713, 14, 14, 14, 0, -13}, // 0x4B 'K'
{738, 12, 14, 14, 1, -13}, // 0x4C 'L'
{759, 14, 14, 14, 0, -13}, // 0x4D 'M'
{784, 13, 14, 14, 0, -13}, // 0x4E 'N'
{807, 12, 14, 14, 1, -13}, // 0x4F 'O'
{828, 12, 14, 14, 0, -13}, // 0x50 'P'
{849, 12, 17, 14, 1, -13}, // 0x51 'Q'
{875, 14, 14, 14, 0, -13}, // 0x52 'R'
{900, 10, 14, 14, 2, -13}, // 0x53 'S'
{918, 12, 14, 14, 1, -13}, // 0x54 'T'
{939, 12, 14, 14, 1, -13}, // 0x55 'U'
{960, 16, 14, 14, -1, -13}, // 0x56 'V'
{988, 14, 14, 14, 0, -13}, // 0x57 'W'
{1013, 14, 14, 14, 0, -13}, // 0x58 'X'
{1038, 12, 14, 14, 1, -13}, // 0x59 'Y'
{1059, 10, 14, 14, 2, -13}, // 0x5A 'Z'
{1077, 5, 19, 14, 6, -14}, // 0x5B '['
{1089, 10, 20, 14, 2, -16}, // 0x5C '\'
{1114, 5, 19, 14, 3, -14}, // 0x5D ']'
{1126, 10, 8, 14, 2, -15}, // 0x5E '^'
{1136, 14, 2, 14, 0, 4}, // 0x5F '_'
{1140, 4, 4, 14, 4, -15}, // 0x60 '`'
{1142, 12, 11, 14, 1, -10}, // 0x61 'a'
{1159, 13, 15, 14, 0, -14}, // 0x62 'b'
{1184, 12, 11, 14, 1, -10}, // 0x63 'c'
{1201, 13, 15, 14, 1, -14}, // 0x64 'd'
{1226, 12, 11, 14, 1, -10}, // 0x65 'e'
{1243, 11, 15, 14, 2, -14}, // 0x66 'f'
{1264, 13, 16, 14, 1, -10}, // 0x67 'g'
{1290, 14, 15, 14, 0, -14}, // 0x68 'h'
{1317, 11, 14, 14, 1, -13}, // 0x69 'i'
{1337, 8, 19, 15, 3, -13}, // 0x6A 'j'
{1356, 13, 15, 14, 1, -14}, // 0x6B 'k'
{1381, 11, 15, 14, 1, -14}, // 0x6C 'l'
{1402, 15, 11, 14, 0, -10}, // 0x6D 'm'
{1423, 14, 11, 14, 0, -10}, // 0x6E 'n'
{1443, 12, 11, 14, 1, -10}, // 0x6F 'o'
{1460, 14, 16, 14, 0, -10}, // 0x70 'p'
{1488, 14, 16, 14, 0, -10}, // 0x71 'q'
{1516, 12, 11, 14, 1, -10}, // 0x72 'r'
{1533, 10, 11, 14, 2, -10}, // 0x73 's'
{1547, 11, 14, 14, 1, -13}, // 0x74 't'
{1567, 13, 11, 14, 0, -10}, // 0x75 'u'
{1585, 14, 11, 14, 0, -10}, // 0x76 'v'
{1605, 14, 11, 14, 0, -10}, // 0x77 'w'
{1625, 14, 11, 14, 0, -10}, // 0x78 'x'
{1645, 12, 16, 14, 1, -10}, // 0x79 'y'
{1669, 11, 11, 14, 1, -10}, // 0x7A 'z'
{1685, 7, 19, 14, 3, -14}, // 0x7B '{'
{1702, 2, 19, 14, 6, -14}, // 0x7C '|'
{1707, 7, 19, 14, 4, -14}, // 0x7D '}'
{1724, 12, 4, 14, 1, -7}}; // 0x7E '~'
const GFXfont FreeMonoBold12pt7b PROGMEM = {
(uint8_t *)FreeMonoBold12pt7bBitmaps, (GFXglyph *)FreeMonoBold12pt7bGlyphs,
0x20, 0x7E, 24};
// Approx. 2402 bytes

View File

@@ -0,0 +1,425 @@
#pragma once
#include <Adafruit_GFX.h>
const uint8_t FreeMonoBold18pt7bBitmaps[] PROGMEM = {
0x77, 0xFF, 0xFF, 0xFF, 0xFF, 0xFB, 0x9C, 0xE7, 0x39, 0xC4, 0x03, 0xBF,
0xFF, 0xB8, 0xF1, 0xFE, 0x3F, 0xC7, 0xF8, 0xFF, 0x1E, 0xC1, 0x98, 0x33,
0x06, 0x60, 0xCC, 0x18, 0x0E, 0x1C, 0x0F, 0x3C, 0x1F, 0x3C, 0x1E, 0x3C,
0x1E, 0x3C, 0x1E, 0x78, 0x1E, 0x78, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFE, 0x1E, 0x78, 0x1E, 0x78, 0x1E, 0x78, 0x7F, 0xFE, 0x7F, 0xFE,
0x7F, 0xFE, 0x7F, 0xFE, 0x3C, 0x78, 0x3C, 0x78, 0x3C, 0x78, 0x3C, 0xF0,
0x3C, 0xF0, 0x3C, 0xF0, 0x3C, 0xF0, 0x03, 0x00, 0x1E, 0x00, 0x78, 0x01,
0xE0, 0x1F, 0xF1, 0xFF, 0xE7, 0xFF, 0xBE, 0x1E, 0xF0, 0x3B, 0xC0, 0xCF,
0xE0, 0x3F, 0xF8, 0x7F, 0xF0, 0x7F, 0xE0, 0x1F, 0xF0, 0x0F, 0xE0, 0x3F,
0x80, 0xFF, 0x87, 0xFF, 0xFE, 0xFF, 0xF3, 0x7F, 0x80, 0x78, 0x01, 0xE0,
0x07, 0x80, 0x1E, 0x00, 0x78, 0x00, 0xC0, 0x1E, 0x00, 0xFF, 0x03, 0x86,
0x06, 0x06, 0x0C, 0x0C, 0x18, 0x18, 0x38, 0x70, 0x3F, 0xC2, 0x1E, 0x3E,
0x03, 0xF8, 0x3F, 0x83, 0xF8, 0x0F, 0x8F, 0x18, 0x7F, 0x01, 0xC7, 0x03,
0x06, 0x06, 0x0C, 0x0C, 0x18, 0x1C, 0x70, 0x1F, 0xC0, 0x0F, 0x00, 0x03,
0xD0, 0x1F, 0xF0, 0x7F, 0xE1, 0xFF, 0xC3, 0xE6, 0x07, 0x80, 0x0F, 0x00,
0x0F, 0x00, 0x1F, 0x00, 0x3E, 0x00, 0xFE, 0x03, 0xFE, 0xFF, 0xBD, 0xFE,
0x3F, 0xFC, 0x3F, 0x7C, 0x7C, 0xFF, 0xFE, 0xFF, 0xFC, 0xFF, 0xF8, 0x7E,
0xF0, 0xFF, 0xFF, 0xF6, 0x66, 0x66, 0x07, 0x0F, 0x1F, 0x1E, 0x3E, 0x3C,
0x78, 0x78, 0x78, 0x70, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
0x78, 0x78, 0x78, 0x3C, 0x3C, 0x1E, 0x1F, 0x0F, 0x07, 0xE0, 0xF0, 0xF8,
0x78, 0x7C, 0x3C, 0x3E, 0x1E, 0x1E, 0x1E, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
0x0F, 0x0F, 0x0E, 0x1E, 0x1E, 0x1E, 0x3C, 0x3C, 0x78, 0xF8, 0xF0, 0xE0,
0x01, 0x80, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0xFF, 0xFF,
0xFF, 0xFF, 0x7F, 0xFE, 0x1F, 0xF8, 0x07, 0xE0, 0x0F, 0xF0, 0x1F, 0xF8,
0x1E, 0x78, 0x1C, 0x38, 0x18, 0x18, 0x01, 0xC0, 0x03, 0xC0, 0x03, 0xC0,
0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0,
0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x01, 0x80, 0x3E, 0x78, 0xF3, 0xC7,
0x8E, 0x1C, 0x70, 0xE1, 0x80, 0x7F, 0xFF, 0xDF, 0xFF, 0xF9, 0xFF, 0xFF,
0x3F, 0xFF, 0xE0, 0x77, 0xFF, 0xF7, 0x00, 0x00, 0x0E, 0x00, 0x3C, 0x00,
0x78, 0x01, 0xE0, 0x03, 0xC0, 0x07, 0x00, 0x1E, 0x00, 0x38, 0x00, 0xF0,
0x01, 0xC0, 0x07, 0x80, 0x0F, 0x00, 0x3C, 0x00, 0x78, 0x01, 0xE0, 0x03,
0xC0, 0x0F, 0x00, 0x1E, 0x00, 0x78, 0x00, 0xF0, 0x03, 0xC0, 0x07, 0x80,
0x1E, 0x00, 0x3C, 0x00, 0x70, 0x01, 0xE0, 0x03, 0x80, 0x03, 0x00, 0x00,
0x07, 0xE0, 0x1F, 0xF8, 0x3F, 0xFC, 0x3F, 0xFC, 0x7C, 0x3E, 0x78, 0x1E,
0xF8, 0x1F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F,
0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF8, 0x1F, 0x78, 0x1E,
0x7C, 0x3E, 0x3F, 0xFC, 0x3F, 0xFC, 0x1F, 0xF8, 0x07, 0xE0, 0x07, 0xC0,
0x1F, 0x80, 0xFF, 0x03, 0xFE, 0x0F, 0xBC, 0x0C, 0x78, 0x00, 0xF0, 0x01,
0xE0, 0x03, 0xC0, 0x07, 0x80, 0x0F, 0x00, 0x1E, 0x00, 0x3C, 0x00, 0x78,
0x00, 0xF0, 0x01, 0xE0, 0x03, 0xC0, 0x07, 0x81, 0xFF, 0xFB, 0xFF, 0xF7,
0xFF, 0xE7, 0xFF, 0x80, 0x0F, 0xC0, 0x7F, 0xE1, 0xFF, 0xE3, 0xFF, 0xEF,
0x87, 0xDE, 0x07, 0xF8, 0x07, 0x80, 0x0F, 0x00, 0x1E, 0x00, 0x7C, 0x01,
0xF0, 0x07, 0xC0, 0x1F, 0x00, 0x7C, 0x01, 0xF0, 0x07, 0xC0, 0x1F, 0x00,
0x78, 0x03, 0xE0, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80,
0x0F, 0xC0, 0x7F, 0xF0, 0xFF, 0xF8, 0xFF, 0xFC, 0x70, 0x3E, 0x00, 0x1E,
0x00, 0x1E, 0x00, 0x1E, 0x00, 0x3C, 0x03, 0xFC, 0x03, 0xF0, 0x03, 0xF0,
0x03, 0xFC, 0x00, 0x3E, 0x00, 0x1F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F,
0xE0, 0x3F, 0xFF, 0xFE, 0xFF, 0xFC, 0x7F, 0xF8, 0x1F, 0xE0, 0x00, 0xF8,
0x03, 0xF0, 0x07, 0xE0, 0x1F, 0xC0, 0x77, 0x80, 0xEF, 0x03, 0x9E, 0x0F,
0x3C, 0x1C, 0x78, 0x70, 0xF1, 0xE1, 0xE3, 0x83, 0xCF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x78, 0x07, 0xFC, 0x0F, 0xF8, 0x1F, 0xF0,
0x1F, 0xC0, 0x3F, 0xFC, 0x1F, 0xFE, 0x0F, 0xFF, 0x07, 0xFF, 0x83, 0xC0,
0x01, 0xE0, 0x00, 0xF0, 0x00, 0x7B, 0xE0, 0x3F, 0xFC, 0x1F, 0xFF, 0x0F,
0xFF, 0xC3, 0x83, 0xE0, 0x00, 0xF8, 0x00, 0x3C, 0x00, 0x1E, 0x00, 0x0F,
0x00, 0x0F, 0xB8, 0x0F, 0xBF, 0xFF, 0xCF, 0xFF, 0xC3, 0xFF, 0xC0, 0x7F,
0x80, 0x00, 0xFC, 0x07, 0xFC, 0x3F, 0xF8, 0xFF, 0xF1, 0xF8, 0x07, 0xC0,
0x1F, 0x00, 0x3C, 0x00, 0xF0, 0x01, 0xE7, 0xC3, 0xDF, 0xC7, 0x7F, 0xCF,
0xFF, 0xDF, 0x8F, 0xFC, 0x07, 0xF0, 0x0F, 0xF0, 0x1F, 0xE0, 0x3D, 0xE0,
0xFB, 0xFF, 0xE3, 0xFF, 0xC3, 0xFF, 0x01, 0xF8, 0x00, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x01, 0xE0, 0x03, 0x80, 0x0F, 0x00, 0x1E,
0x00, 0x38, 0x00, 0xF0, 0x01, 0xE0, 0x07, 0x80, 0x0F, 0x00, 0x1E, 0x00,
0x78, 0x00, 0xF0, 0x01, 0xE0, 0x07, 0x80, 0x0F, 0x00, 0x1E, 0x00, 0x38,
0x00, 0x70, 0x00, 0x07, 0xC0, 0x3F, 0xE0, 0xFF, 0xE3, 0xFF, 0xEF, 0x83,
0xFE, 0x03, 0xFC, 0x07, 0xF8, 0x0F, 0xF0, 0x1E, 0xF0, 0x78, 0xFF, 0xE0,
0xFF, 0x81, 0xFF, 0x0F, 0xFF, 0x9E, 0x0F, 0x78, 0x0F, 0xF0, 0x1F, 0xE0,
0x3F, 0xE0, 0xFB, 0xFF, 0xE7, 0xFF, 0xC7, 0xFF, 0x03, 0xF8, 0x00, 0x0F,
0xC0, 0x3F, 0xE0, 0xFF, 0xE3, 0xFF, 0xEF, 0xC3, 0xDF, 0x03, 0xBC, 0x07,
0xF8, 0x0F, 0xF0, 0x1F, 0xF0, 0x3D, 0xF1, 0xFB, 0xFF, 0xF3, 0xFE, 0xE3,
0xFB, 0xC3, 0xE7, 0x80, 0x1E, 0x00, 0x7C, 0x01, 0xF0, 0x07, 0xE7, 0xFF,
0x8F, 0xFE, 0x1F, 0xF0, 0x1F, 0x80, 0x00, 0x77, 0xFF, 0xF7, 0x00, 0x00,
0x00, 0x00, 0xEF, 0xFF, 0xEE, 0x1C, 0x7C, 0xF9, 0xF1, 0xC0, 0x00, 0x00,
0x00, 0x00, 0x00, 0xF3, 0xC7, 0x8E, 0x3C, 0x70, 0xE1, 0x87, 0x0C, 0x00,
0x00, 0x00, 0x00, 0x80, 0x00, 0xF0, 0x00, 0xFC, 0x00, 0xFE, 0x00, 0xFE,
0x00, 0xFE, 0x00, 0xFE, 0x00, 0xFE, 0x00, 0x7F, 0x00, 0x07, 0xF0, 0x00,
0x7F, 0x00, 0x07, 0xF0, 0x00, 0x7F, 0x00, 0x07, 0xF0, 0x00, 0x7C, 0x00,
0x07, 0x7F, 0xFF, 0xDF, 0xFF, 0xF9, 0xFF, 0xFF, 0x3F, 0xFF, 0xE0, 0x00,
0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF7, 0xFF, 0xFE, 0x7F, 0xFF, 0xCF, 0xFF,
0xF8, 0x00, 0x00, 0x3C, 0x00, 0x0F, 0xC0, 0x01, 0xFC, 0x00, 0x1F, 0xC0,
0x01, 0xFC, 0x00, 0x1F, 0xC0, 0x01, 0xFC, 0x00, 0x3F, 0x80, 0x3F, 0x80,
0x3F, 0x80, 0x3F, 0x80, 0x3F, 0x80, 0x3F, 0x80, 0x0F, 0x80, 0x03, 0x80,
0x00, 0x1F, 0xC0, 0xFF, 0xE3, 0xFF, 0xF7, 0xFF, 0xEF, 0x07, 0xFE, 0x03,
0xDC, 0x07, 0x80, 0x0F, 0x00, 0x7C, 0x03, 0xF8, 0x1F, 0xC0, 0x1E, 0x00,
0x30, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x1F, 0x00, 0x3E,
0x00, 0x7C, 0x00, 0x70, 0x00, 0x07, 0xE0, 0x1F, 0xE0, 0x7F, 0xE1, 0xE1,
0xC7, 0x83, 0xCE, 0x03, 0xBC, 0x07, 0x70, 0x0E, 0xE0, 0x7D, 0xC3, 0xFB,
0x8F, 0xF7, 0x3C, 0xEE, 0x71, 0xDC, 0xE3, 0xB9, 0xC7, 0x73, 0xCE, 0xE3,
0xFF, 0xC3, 0xFF, 0x83, 0xFF, 0x00, 0x07, 0x00, 0x0E, 0x00, 0x1E, 0x02,
0x1E, 0x1E, 0x3F, 0xFC, 0x1F, 0xF0, 0x1F, 0x80, 0x0F, 0xF8, 0x00, 0x7F,
0xF0, 0x01, 0xFF, 0xC0, 0x03, 0xFF, 0x00, 0x01, 0xFE, 0x00, 0x07, 0xF8,
0x00, 0x1C, 0xF0, 0x00, 0xF3, 0xC0, 0x03, 0xCF, 0x00, 0x1E, 0x1E, 0x00,
0x78, 0x78, 0x03, 0xC0, 0xF0, 0x0F, 0xFF, 0xC0, 0x3F, 0xFF, 0x01, 0xFF,
0xFE, 0x07, 0xFF, 0xF8, 0x3C, 0x00, 0xF3, 0xFC, 0x1F, 0xEF, 0xF8, 0x7F,
0xFF, 0xE1, 0xFF, 0x7F, 0x03, 0xF8, 0x7F, 0xFC, 0x0F, 0xFF, 0xF0, 0xFF,
0xFF, 0x8F, 0xFF, 0xF8, 0x3C, 0x07, 0xC3, 0xC0, 0x3C, 0x3C, 0x03, 0xC3,
0xC0, 0x7C, 0x3F, 0xFF, 0x83, 0xFF, 0xF0, 0x3F, 0xFF, 0x83, 0xFF, 0xFE,
0x3C, 0x03, 0xE3, 0xC0, 0x1F, 0x3C, 0x00, 0xF3, 0xC0, 0x0F, 0x3C, 0x01,
0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xEF, 0xFF, 0xFC, 0x7F, 0xFF, 0x00, 0x01,
0xF8, 0xC1, 0xFF, 0xFC, 0x7F, 0xFF, 0x9F, 0xFF, 0xF7, 0xE0, 0x7E, 0xF8,
0x07, 0xFE, 0x00, 0x7F, 0x80, 0x0E, 0xF0, 0x00, 0x1E, 0x00, 0x03, 0xC0,
0x00, 0x78, 0x00, 0x0F, 0x00, 0x01, 0xE0, 0x00, 0x3E, 0x00, 0x03, 0xE0,
0x07, 0x7F, 0x03, 0xE7, 0xFF, 0xFC, 0x7F, 0xFF, 0x03, 0xFF, 0xC0, 0x1F,
0xE0, 0xFF, 0xF0, 0x3F, 0xFF, 0x0F, 0xFF, 0xE3, 0xFF, 0xFC, 0x78, 0x1F,
0x9E, 0x03, 0xE7, 0x80, 0x79, 0xE0, 0x0F, 0x78, 0x03, 0xDE, 0x00, 0xF7,
0x80, 0x3D, 0xE0, 0x0F, 0x78, 0x03, 0xDE, 0x00, 0xF7, 0x80, 0x7D, 0xE0,
0x1E, 0x78, 0x1F, 0xBF, 0xFF, 0xCF, 0xFF, 0xF3, 0xFF, 0xF0, 0x7F, 0xF0,
0x00, 0x7F, 0xFF, 0xDF, 0xFF, 0xFB, 0xFF, 0xFF, 0x7F, 0xFF, 0xE3, 0xC0,
0x3C, 0x78, 0x07, 0x8F, 0x1C, 0xF1, 0xE3, 0xCC, 0x3F, 0xF8, 0x07, 0xFF,
0x00, 0xFF, 0xE0, 0x1F, 0xFC, 0x03, 0xC7, 0x80, 0x78, 0xF1, 0x8F, 0x0C,
0x79, 0xE0, 0x0F, 0x3C, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xF7, 0xFF, 0xFE, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xF3, 0xC0, 0x1E, 0x78, 0x63, 0xCF, 0x1E, 0x79, 0xE3, 0xC6, 0x3F, 0xF8,
0x07, 0xFF, 0x00, 0xFF, 0xE0, 0x1F, 0xFC, 0x03, 0xC7, 0x80, 0x78, 0xE0,
0x0F, 0x00, 0x01, 0xE0, 0x00, 0x3C, 0x00, 0x1F, 0xFC, 0x03, 0xFF, 0x80,
0x7F, 0xF0, 0x07, 0xFC, 0x00, 0x01, 0xFC, 0xE0, 0x7F, 0xFE, 0x1F, 0xFF,
0xE3, 0xFF, 0xFE, 0x7F, 0x03, 0xE7, 0xC0, 0x1E, 0xF8, 0x00, 0xEF, 0x00,
0x00, 0xF0, 0x00, 0x0F, 0x00, 0x00, 0xF0, 0x00, 0x0F, 0x03, 0xFE, 0xF0,
0x3F, 0xFF, 0x03, 0xFF, 0xF8, 0x3F, 0xF7, 0x80, 0x1E, 0x7E, 0x01, 0xE3,
0xFF, 0xFE, 0x1F, 0xFF, 0xE0, 0xFF, 0xF8, 0x01, 0xFE, 0x00, 0x7F, 0x0F,
0xE3, 0xFC, 0x7F, 0x9F, 0xE3, 0xFC, 0x7F, 0x1F, 0xC1, 0xE0, 0x3C, 0x0F,
0x01, 0xE0, 0x78, 0x0F, 0x03, 0xC0, 0x78, 0x1E, 0x03, 0xC0, 0xFF, 0xFE,
0x07, 0xFF, 0xF0, 0x3F, 0xFF, 0x81, 0xFF, 0xFC, 0x0F, 0x01, 0xE0, 0x78,
0x0F, 0x03, 0xC0, 0x78, 0x1E, 0x03, 0xC3, 0xFC, 0x7F, 0xBF, 0xE3, 0xFF,
0xFF, 0x1F, 0xF7, 0xF0, 0x7F, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0x07, 0x80, 0x1E, 0x00, 0x78, 0x01, 0xE0, 0x07, 0x80, 0x1E, 0x00,
0x78, 0x01, 0xE0, 0x07, 0x80, 0x1E, 0x00, 0x78, 0x01, 0xE0, 0x07, 0x83,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xF8, 0x01, 0xFF, 0xE0, 0x3F, 0xFC,
0x07, 0xFF, 0x80, 0xFF, 0xF0, 0x00, 0xF0, 0x00, 0x1E, 0x00, 0x03, 0xC0,
0x00, 0x78, 0x00, 0x0F, 0x00, 0x01, 0xE0, 0x00, 0x3C, 0x38, 0x07, 0x8F,
0x00, 0xF1, 0xE0, 0x1E, 0x3C, 0x03, 0xC7, 0x80, 0xF8, 0xF8, 0x3F, 0x1F,
0xFF, 0xC3, 0xFF, 0xF0, 0x1F, 0xFC, 0x00, 0x7E, 0x00, 0xFF, 0x0F, 0xCF,
0xF9, 0xFE, 0xFF, 0x9F, 0xEF, 0xF8, 0xFC, 0x3C, 0x1F, 0x03, 0xC3, 0xE0,
0x3C, 0x7C, 0x03, 0xCF, 0x80, 0x3D, 0xF0, 0x03, 0xFE, 0x00, 0x3F, 0xF8,
0x03, 0xFF, 0x80, 0x3E, 0x7C, 0x03, 0xC3, 0xE0, 0x3C, 0x1E, 0x03, 0xC0,
0xF0, 0x3C, 0x0F, 0x0F, 0xF8, 0x7E, 0xFF, 0x87, 0xFF, 0xF8, 0x7F, 0x7F,
0x03, 0xE0, 0xFF, 0xC0, 0x3F, 0xF0, 0x0F, 0xFC, 0x03, 0xFF, 0x00, 0x1E,
0x00, 0x07, 0x80, 0x01, 0xE0, 0x00, 0x78, 0x00, 0x1E, 0x00, 0x07, 0x80,
0x01, 0xE0, 0x00, 0x78, 0x00, 0x1E, 0x01, 0x87, 0x80, 0xF1, 0xE0, 0x3C,
0x78, 0x0F, 0x1E, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F,
0xFF, 0xC0, 0x3E, 0x00, 0xF8, 0xFC, 0x01, 0xF9, 0xFC, 0x07, 0xF3, 0xF8,
0x0F, 0xE3, 0xF8, 0x3F, 0x87, 0xF0, 0x7F, 0x0F, 0xF1, 0xFE, 0x1F, 0xE3,
0xFC, 0x3D, 0xE7, 0x78, 0x7B, 0xDE, 0xF0, 0xF7, 0xBD, 0xE1, 0xE7, 0xF3,
0xC3, 0xCF, 0xE7, 0x87, 0x8F, 0x8F, 0x0F, 0x1F, 0x1E, 0x1E, 0x1E, 0x3C,
0x3C, 0x00, 0x79, 0xFF, 0x07, 0xFF, 0xFE, 0x0F, 0xFF, 0xFC, 0x1F, 0xF7,
0xF0, 0x1F, 0xC0, 0xFC, 0x1F, 0xEF, 0xE1, 0xFF, 0xFE, 0x1F, 0xFF, 0xF1,
0xFF, 0x3F, 0x83, 0xC3, 0xF8, 0x3C, 0x3F, 0xC3, 0xC3, 0xFC, 0x3C, 0x3D,
0xE3, 0xC3, 0xDE, 0x3C, 0x3C, 0xF3, 0xC3, 0xC7, 0xBC, 0x3C, 0x7B, 0xC3,
0xC3, 0xFC, 0x3C, 0x3F, 0xC3, 0xC1, 0xFC, 0x3C, 0x1F, 0xCF, 0xF8, 0xFC,
0xFF, 0x87, 0xCF, 0xF8, 0x7C, 0x7F, 0x03, 0xC0, 0x01, 0xF8, 0x00, 0x7F,
0xE0, 0x0F, 0xFF, 0x81, 0xFF, 0xFC, 0x3F, 0x0F, 0xC7, 0xC0, 0x3E, 0x78,
0x01, 0xEF, 0x80, 0x1F, 0xF0, 0x00, 0xFF, 0x00, 0x0F, 0xF0, 0x00, 0xFF,
0x00, 0x0F, 0xF0, 0x00, 0xFF, 0x80, 0x1F, 0x78, 0x01, 0xE7, 0xC0, 0x3E,
0x3F, 0x0F, 0xC1, 0xFF, 0xF8, 0x1F, 0xFF, 0x00, 0x7F, 0xE0, 0x01, 0xF8,
0x00, 0x7F, 0xF8, 0x3F, 0xFF, 0x8F, 0xFF, 0xF3, 0xFF, 0xFE, 0x3C, 0x0F,
0xCF, 0x00, 0xF3, 0xC0, 0x3C, 0xF0, 0x0F, 0x3C, 0x03, 0xCF, 0x03, 0xF3,
0xFF, 0xF8, 0xFF, 0xFC, 0x3F, 0xFE, 0x0F, 0xFE, 0x03, 0xC0, 0x00, 0xF0,
0x00, 0x3C, 0x00, 0x3F, 0xF8, 0x0F, 0xFE, 0x03, 0xFF, 0x80, 0x7F, 0xC0,
0x00, 0x01, 0xF8, 0x00, 0x7F, 0xE0, 0x0F, 0xFF, 0x01, 0xFF, 0xF8, 0x3F,
0x0F, 0xC7, 0xC0, 0x3E, 0x78, 0x01, 0xEF, 0x80, 0x1F, 0xF0, 0x00, 0xFF,
0x00, 0x0F, 0xF0, 0x00, 0xFF, 0x00, 0x0F, 0xF0, 0x00, 0xFF, 0x80, 0x1F,
0x78, 0x01, 0xE7, 0xC0, 0x3E, 0x3F, 0x0F, 0xC1, 0xFF, 0xF8, 0x0F, 0xFF,
0x00, 0x7F, 0xE0, 0x03, 0xF8, 0x00, 0x3F, 0x8E, 0x07, 0xFF, 0xF0, 0xFF,
0xFF, 0x0F, 0xFF, 0xE0, 0x60, 0x78, 0x7F, 0xF8, 0x07, 0xFF, 0xF0, 0x3F,
0xFF, 0xE0, 0xFF, 0xFF, 0x01, 0xE0, 0x7C, 0x0F, 0x01, 0xE0, 0x78, 0x0F,
0x03, 0xC0, 0x78, 0x1E, 0x0F, 0xC0, 0xFF, 0xFC, 0x07, 0xFF, 0xC0, 0x3F,
0xF8, 0x01, 0xFF, 0xE0, 0x0F, 0x0F, 0x80, 0x78, 0x3C, 0x03, 0xC0, 0xF0,
0x1E, 0x07, 0xC3, 0xFE, 0x1F, 0xBF, 0xF0, 0x7F, 0xFF, 0x83, 0xF7, 0xF8,
0x0F, 0x00, 0x07, 0xE7, 0x07, 0xFF, 0x8F, 0xFF, 0xC7, 0xFF, 0xE7, 0xC1,
0xF3, 0xC0, 0x79, 0xE0, 0x3C, 0xF8, 0x00, 0x7F, 0x80, 0x1F, 0xFC, 0x07,
0xFF, 0x81, 0xFF, 0xE0, 0x0F, 0xFB, 0x00, 0x7F, 0xC0, 0x1F, 0xE0, 0x0F,
0xFC, 0x1F, 0xFF, 0xFF, 0xBF, 0xFF, 0x8D, 0xFF, 0x80, 0x3F, 0x00, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x1F, 0xE1,
0xE3, 0xFC, 0x3C, 0x7F, 0x87, 0x8F, 0x60, 0xF0, 0xC0, 0x1E, 0x00, 0x03,
0xC0, 0x00, 0x78, 0x00, 0x0F, 0x00, 0x01, 0xE0, 0x00, 0x3C, 0x00, 0x07,
0x80, 0x00, 0xF0, 0x01, 0xFF, 0xE0, 0x3F, 0xFC, 0x07, 0xFF, 0x80, 0x7F,
0xE0, 0xFF, 0x0F, 0xF7, 0xFC, 0x7F, 0xFF, 0xE3, 0xFE, 0xFF, 0x1F, 0xF3,
0xC0, 0x1E, 0x1E, 0x00, 0xF0, 0xF0, 0x07, 0x87, 0x80, 0x3C, 0x3C, 0x01,
0xE1, 0xE0, 0x0F, 0x0F, 0x00, 0x78, 0x78, 0x03, 0xC3, 0xC0, 0x1E, 0x1E,
0x00, 0xF0, 0xF0, 0x07, 0x87, 0xC0, 0x7C, 0x1F, 0x07, 0xC0, 0xFF, 0xFE,
0x03, 0xFF, 0xE0, 0x0F, 0xFE, 0x00, 0x1F, 0xC0, 0x00, 0xFF, 0x03, 0xFD,
0xFF, 0x07, 0xFF, 0xFE, 0x0F, 0xFB, 0xF8, 0x1F, 0xE1, 0xC0, 0x07, 0x03,
0xC0, 0x1E, 0x07, 0x80, 0x3C, 0x07, 0x80, 0xF0, 0x0F, 0x01, 0xE0, 0x0F,
0x03, 0x80, 0x1E, 0x0F, 0x00, 0x3E, 0x1E, 0x00, 0x3C, 0x78, 0x00, 0x78,
0xF0, 0x00, 0x7B, 0xC0, 0x00, 0xF7, 0x80, 0x01, 0xFF, 0x00, 0x01, 0xFC,
0x00, 0x03, 0xF8, 0x00, 0x03, 0xE0, 0x00, 0x07, 0xC0, 0x00, 0xFF, 0x0F,
0xF7, 0xFC, 0x7F, 0xFF, 0xE3, 0xFF, 0xFE, 0x0F, 0xF7, 0x80, 0x0F, 0x3C,
0x38, 0x78, 0xE3, 0xE3, 0x87, 0x1F, 0x1C, 0x38, 0xF8, 0xE1, 0xEF, 0xE7,
0x0F, 0x7F, 0x78, 0x7B, 0xBB, 0xC3, 0xFD, 0xFE, 0x0F, 0xEF, 0xF0, 0x7E,
0x3F, 0x03, 0xF1, 0xF8, 0x1F, 0x8F, 0xC0, 0xFC, 0x3E, 0x07, 0xC1, 0xF0,
0x3E, 0x0F, 0x81, 0xF0, 0x7C, 0x00, 0x7E, 0x0F, 0xDF, 0xE3, 0xFF, 0xFC,
0x7F, 0xBF, 0x07, 0xE1, 0xE0, 0xF8, 0x3E, 0x3E, 0x03, 0xEF, 0x80, 0x3D,
0xE0, 0x03, 0xF8, 0x00, 0x3E, 0x00, 0x03, 0xC0, 0x00, 0xF8, 0x00, 0x3F,
0x80, 0x0F, 0x78, 0x03, 0xC7, 0x80, 0xF8, 0x78, 0x3E, 0x0F, 0x8F, 0xE3,
0xFF, 0xFC, 0x7F, 0xFF, 0x8F, 0xF7, 0xE0, 0xFC, 0x7E, 0x07, 0xEF, 0xF0,
0xFF, 0xFF, 0x0F, 0xF7, 0xE0, 0x7E, 0x1E, 0x07, 0x81, 0xF0, 0xF8, 0x0F,
0x0F, 0x00, 0x79, 0xE0, 0x07, 0xFE, 0x00, 0x3F, 0xC0, 0x01, 0xF8, 0x00,
0x0F, 0x00, 0x00, 0xF0, 0x00, 0x0F, 0x00, 0x00, 0xF0, 0x00, 0x0F, 0x00,
0x00, 0xF0, 0x00, 0xFF, 0xE0, 0x0F, 0xFF, 0x00, 0xFF, 0xF0, 0x07, 0xFE,
0x00, 0xFF, 0xFC, 0xFF, 0xFC, 0xFF, 0xFC, 0xFF, 0xFC, 0xF0, 0x3C, 0xF0,
0x78, 0xF0, 0xF0, 0x70, 0xE0, 0x01, 0xE0, 0x03, 0xC0, 0x03, 0x80, 0x07,
0x00, 0x0F, 0x00, 0x1E, 0x0E, 0x1C, 0x0F, 0x38, 0x0F, 0x78, 0x0F, 0x7F,
0xFF, 0x7F, 0xFF, 0x7F, 0xFF, 0x7F, 0xFF, 0xFE, 0xFF, 0xFF, 0xFE, 0xF0,
0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xFE, 0xFF, 0xFF, 0xFE, 0xE0, 0x01,
0xE0, 0x03, 0xC0, 0x03, 0xC0, 0x07, 0x80, 0x07, 0x00, 0x0F, 0x00, 0x0E,
0x00, 0x1E, 0x00, 0x1C, 0x00, 0x3C, 0x00, 0x78, 0x00, 0x78, 0x00, 0xF0,
0x00, 0xF0, 0x01, 0xE0, 0x01, 0xE0, 0x03, 0xC0, 0x03, 0xC0, 0x07, 0x80,
0x07, 0x80, 0x0F, 0x00, 0x0F, 0x00, 0x1E, 0x00, 0x1C, 0x00, 0x3C, 0x00,
0x38, 0x00, 0x70, 0x7F, 0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
0x0F, 0x0F, 0x7F, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x07, 0x00, 0x1F, 0x00,
0x7F, 0x00, 0xFE, 0x03, 0xDE, 0x0F, 0x1E, 0x3E, 0x3E, 0xF8, 0x3F, 0xE0,
0x3F, 0x80, 0x38, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xF0, 0xC3, 0x87, 0x0E, 0x1C, 0x30, 0x01, 0xFC, 0x01, 0xFF, 0xC0,
0x3F, 0xFC, 0x07, 0xFF, 0xC0, 0x00, 0x78, 0x0F, 0xFF, 0x07, 0xFF, 0xE1,
0xFF, 0xFC, 0x7F, 0xFF, 0x9F, 0x80, 0xF3, 0xC0, 0x1E, 0x78, 0x0F, 0xCF,
0xFF, 0xFE, 0xFF, 0xFF, 0xCF, 0xFF, 0xF8, 0x7F, 0x3E, 0x7C, 0x00, 0x1F,
0x80, 0x03, 0xF0, 0x00, 0x7E, 0x00, 0x03, 0xC0, 0x00, 0x78, 0x00, 0x0F,
0x3F, 0x01, 0xFF, 0xF8, 0x3F, 0xFF, 0x87, 0xFF, 0xF0, 0xFC, 0x1F, 0x1F,
0x01, 0xF3, 0xC0, 0x1E, 0x78, 0x03, 0xCF, 0x00, 0x79, 0xE0, 0x0F, 0x3E,
0x03, 0xE7, 0xE0, 0xFB, 0xFF, 0xFF, 0x7F, 0xFF, 0xCF, 0xFF, 0xF0, 0xF9,
0xF8, 0x00, 0x03, 0xF3, 0x87, 0xFF, 0xCF, 0xFF, 0xEF, 0xFF, 0xF7, 0xE0,
0xFF, 0xC0, 0x3F, 0xC0, 0x0F, 0xE0, 0x00, 0xF0, 0x00, 0x78, 0x00, 0x3E,
0x00, 0x4F, 0x80, 0xF7, 0xFF, 0xF9, 0xFF, 0xF8, 0x7F, 0xF8, 0x0F, 0xF0,
0x00, 0x0F, 0xC0, 0x00, 0xFC, 0x00, 0x0F, 0xC0, 0x00, 0xFC, 0x00, 0x03,
0xC0, 0x00, 0x3C, 0x03, 0xF3, 0xC0, 0xFF, 0xBC, 0x1F, 0xFF, 0xC3, 0xFF,
0xFC, 0x7E, 0x0F, 0xC7, 0x80, 0x7C, 0xF0, 0x03, 0xCF, 0x00, 0x3C, 0xF0,
0x03, 0xCF, 0x00, 0x3C, 0xF8, 0x07, 0xC7, 0xE0, 0xFC, 0x7F, 0xFF, 0xF3,
0xFF, 0xFF, 0x0F, 0xFF, 0xF0, 0x3F, 0x3E, 0x03, 0xF0, 0x03, 0xFF, 0x01,
0xFF, 0xE0, 0xFF, 0xFC, 0x7E, 0x0F, 0x9E, 0x01, 0xEF, 0x00, 0x3F, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFD, 0xE0, 0x00, 0x7F, 0xFF,
0xCF, 0xFF, 0xF1, 0xFF, 0xF8, 0x0F, 0xF0, 0x03, 0xFC, 0x07, 0xFF, 0x0F,
0xFF, 0x1F, 0xFF, 0x1E, 0x00, 0x1E, 0x00, 0xFF, 0xF8, 0xFF, 0xFC, 0xFF,
0xFC, 0xFF, 0xF8, 0x1E, 0x00, 0x1E, 0x00, 0x1E, 0x00, 0x1E, 0x00, 0x1E,
0x00, 0x1E, 0x00, 0x1E, 0x00, 0x1E, 0x00, 0xFF, 0xF8, 0xFF, 0xF8, 0xFF,
0xF8, 0xFF, 0xF8, 0x07, 0xE7, 0xC3, 0xFF, 0xFC, 0xFF, 0xFF, 0xBF, 0xFF,
0xF7, 0xC1, 0xF9, 0xF0, 0x1F, 0x3C, 0x01, 0xE7, 0x80, 0x3C, 0xF0, 0x07,
0x9E, 0x00, 0xF3, 0xE0, 0x3E, 0x3E, 0x0F, 0xC7, 0xFF, 0xF8, 0x7F, 0xFF,
0x07, 0xFD, 0xE0, 0x3F, 0x3C, 0x00, 0x07, 0x80, 0x00, 0xF0, 0x00, 0x3E,
0x03, 0xFF, 0x80, 0x7F, 0xF0, 0x0F, 0xFC, 0x00, 0xFE, 0x00, 0x3E, 0x00,
0x03, 0xF0, 0x00, 0x1F, 0x80, 0x00, 0xFC, 0x00, 0x01, 0xE0, 0x00, 0x0F,
0x00, 0x00, 0x78, 0xF8, 0x03, 0xDF, 0xE0, 0x1F, 0xFF, 0x80, 0xFF, 0xFE,
0x07, 0xE1, 0xF0, 0x3E, 0x07, 0x81, 0xE0, 0x3C, 0x0F, 0x01, 0xE0, 0x78,
0x0F, 0x03, 0xC0, 0x78, 0x1E, 0x03, 0xC0, 0xF0, 0x1E, 0x1F, 0xC1, 0xFD,
0xFE, 0x0F, 0xFF, 0xF0, 0x7F, 0xBF, 0x01, 0xF8, 0x03, 0xC0, 0x03, 0xC0,
0x03, 0xC0, 0x03, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xC0, 0x3F, 0xC0,
0x3F, 0xC0, 0x3F, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0,
0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0xFF, 0xFE, 0xFF, 0xFF,
0xFF, 0xFF, 0x7F, 0xFE, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x3C, 0x00, 0x00,
0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xF7, 0xFF, 0x00, 0xF0, 0x0F, 0x00, 0xF0,
0x0F, 0x00, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0x00, 0xF0,
0x0F, 0x00, 0xF0, 0x0F, 0x01, 0xFF, 0xFE, 0xFF, 0xEF, 0xFC, 0x7F, 0x00,
0x7C, 0x00, 0x3F, 0x00, 0x0F, 0xC0, 0x03, 0xF0, 0x00, 0x3C, 0x00, 0x0F,
0x00, 0x03, 0xC7, 0xF0, 0xF3, 0xFC, 0x3C, 0xFF, 0x0F, 0x3F, 0x83, 0xDF,
0x00, 0xFF, 0x80, 0x3F, 0xC0, 0x0F, 0xE0, 0x03, 0xFC, 0x00, 0xF7, 0x80,
0x3C, 0xF0, 0x0F, 0x1F, 0x0F, 0xC3, 0xFB, 0xF1, 0xFF, 0xFC, 0x7F, 0xDF,
0x0F, 0xE0, 0x3F, 0xC0, 0x3F, 0xC0, 0x3F, 0xC0, 0x3F, 0xC0, 0x03, 0xC0,
0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0,
0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0,
0x03, 0xC0, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFE, 0x3D, 0xE3,
0xC1, 0xFF, 0xFF, 0xC7, 0xFF, 0xFF, 0x1F, 0xFF, 0xFE, 0x3E, 0x3C, 0x78,
0xF0, 0xF1, 0xE3, 0xC3, 0xC7, 0x8F, 0x0F, 0x1E, 0x3C, 0x3C, 0x78, 0xF0,
0xF1, 0xE3, 0xC3, 0xC7, 0x8F, 0x0F, 0x1E, 0xFE, 0x3E, 0x7F, 0xF8, 0xF9,
0xFF, 0xE3, 0xE7, 0xDF, 0x0F, 0x1E, 0x1E, 0x7C, 0x03, 0xEF, 0xF0, 0x3F,
0xFF, 0x83, 0xFF, 0xFC, 0x1F, 0x87, 0xC1, 0xE0, 0x3C, 0x1E, 0x03, 0xC1,
0xE0, 0x3C, 0x1E, 0x03, 0xC1, 0xE0, 0x3C, 0x1E, 0x03, 0xC1, 0xE0, 0x3C,
0x7F, 0x0F, 0xFF, 0xF0, 0xFF, 0xFF, 0x0F, 0xF7, 0xE0, 0x7E, 0x03, 0xF8,
0x01, 0xFF, 0xC0, 0x7F, 0xFC, 0x1F, 0xFF, 0xC7, 0xE0, 0xFD, 0xF0, 0x07,
0xFC, 0x00, 0x7F, 0x80, 0x0F, 0xF0, 0x01, 0xFE, 0x00, 0x3F, 0xE0, 0x0F,
0xBF, 0x07, 0xE3, 0xFF, 0xF8, 0x3F, 0xFE, 0x03, 0xFF, 0x80, 0x1F, 0xC0,
0x3E, 0x7E, 0x03, 0xF7, 0xFC, 0x1F, 0xFF, 0xF0, 0xFF, 0xFF, 0xC1, 0xF8,
0x3F, 0x0F, 0x80, 0x7C, 0x78, 0x01, 0xE3, 0xC0, 0x0F, 0x1E, 0x00, 0x78,
0xF0, 0x03, 0xC7, 0xC0, 0x3E, 0x3F, 0x07, 0xE1, 0xFF, 0xFE, 0x0F, 0xFF,
0xE0, 0x7B, 0xFE, 0x03, 0xCF, 0xC0, 0x1E, 0x00, 0x00, 0xF0, 0x00, 0x07,
0x80, 0x00, 0xFF, 0x80, 0x0F, 0xFC, 0x00, 0x7F, 0xE0, 0x01, 0xFE, 0x00,
0x00, 0x03, 0xF3, 0xE0, 0x7F, 0xDF, 0x87, 0xFF, 0xFC, 0x7F, 0xFF, 0xE7,
0xE0, 0xFC, 0x7C, 0x03, 0xE3, 0xC0, 0x0F, 0x1E, 0x00, 0x78, 0xF0, 0x03,
0xC7, 0x80, 0x1E, 0x3E, 0x01, 0xF0, 0xFC, 0x1F, 0x83, 0xFF, 0xFC, 0x1F,
0xFF, 0xE0, 0x3F, 0xEF, 0x00, 0x7E, 0x78, 0x00, 0x03, 0xC0, 0x00, 0x1E,
0x00, 0x00, 0xF0, 0x00, 0x3F, 0xE0, 0x01, 0xFF, 0x80, 0x0F, 0xFC, 0x00,
0x3F, 0xC0, 0x7E, 0x1E, 0x7F, 0x3F, 0xFF, 0xBF, 0xFF, 0xFF, 0xF1, 0xFE,
0x00, 0xFC, 0x00, 0x7C, 0x00, 0x3C, 0x00, 0x1E, 0x00, 0x0F, 0x00, 0x07,
0x80, 0x03, 0xC0, 0x0F, 0xFF, 0x87, 0xFF, 0xC3, 0xFF, 0xE1, 0xFF, 0xE0,
0x07, 0xE6, 0x1F, 0xFE, 0x7F, 0xFE, 0x7F, 0xFE, 0x78, 0x1E, 0x78, 0x0E,
0x7F, 0xE0, 0x3F, 0xFC, 0x03, 0xFE, 0x60, 0x1F, 0xE0, 0x0F, 0xF8, 0x1F,
0xFF, 0xFF, 0xFF, 0xFE, 0x7F, 0xFC, 0x07, 0xE0, 0x0C, 0x00, 0x0F, 0x00,
0x07, 0x80, 0x03, 0xC0, 0x01, 0xE0, 0x07, 0xFF, 0xF3, 0xFF, 0xF9, 0xFF,
0xFC, 0xFF, 0xFC, 0x0F, 0x00, 0x07, 0x80, 0x03, 0xC0, 0x01, 0xE0, 0x00,
0xF0, 0x00, 0x78, 0x00, 0x3C, 0x00, 0x1E, 0x07, 0x8F, 0xFF, 0xC3, 0xFF,
0xC1, 0xFF, 0xC0, 0x3F, 0x80, 0xFC, 0x1F, 0xBF, 0x0F, 0xEF, 0xC3, 0xFB,
0xF0, 0xFE, 0x3C, 0x07, 0x8F, 0x01, 0xE3, 0xC0, 0x78, 0xF0, 0x1E, 0x3C,
0x07, 0x8F, 0x01, 0xE3, 0xC0, 0x78, 0xF8, 0x7E, 0x3F, 0xFF, 0xC7, 0xFF,
0xF0, 0xFF, 0x7C, 0x0F, 0x9E, 0x7F, 0x07, 0xF7, 0xFC, 0x7F, 0xFF, 0xE3,
0xFE, 0xFE, 0x0F, 0xE1, 0xE0, 0x3C, 0x0F, 0x01, 0xE0, 0x3C, 0x1E, 0x01,
0xE0, 0xF0, 0x07, 0x8F, 0x00, 0x3E, 0x78, 0x00, 0xF7, 0x80, 0x07, 0xFC,
0x00, 0x1F, 0xC0, 0x00, 0xFE, 0x00, 0x03, 0xE0, 0x00, 0x1F, 0x00, 0x7E,
0x03, 0xF7, 0xF8, 0x3F, 0xFF, 0xC1, 0xFE, 0xFC, 0x07, 0xF3, 0xC7, 0x0F,
0x1E, 0x7C, 0xF0, 0x73, 0xE7, 0x83, 0x9F, 0x7C, 0x1F, 0xFF, 0xC0, 0xFF,
0xFE, 0x03, 0xF7, 0xF0, 0x1F, 0xBF, 0x80, 0xFC, 0xF8, 0x07, 0xC7, 0xC0,
0x1E, 0x3E, 0x00, 0xE0, 0xE0, 0x7E, 0x0F, 0xDF, 0xE3, 0xFF, 0xFC, 0x7F,
0xBF, 0x07, 0xE1, 0xF1, 0xF0, 0x1F, 0xFC, 0x01, 0xFF, 0x00, 0x1F, 0xC0,
0x07, 0xF8, 0x01, 0xFF, 0xC0, 0x7E, 0xFC, 0x1F, 0x8F, 0xC7, 0xE0, 0xFD,
0xFE, 0x3F, 0xFF, 0xC7, 0xFF, 0xF0, 0x7F, 0x7E, 0x0F, 0xDF, 0xE3, 0xFF,
0xFC, 0x7F, 0xBF, 0x07, 0xE3, 0xC0, 0x78, 0x3C, 0x0E, 0x07, 0x83, 0xC0,
0x78, 0x70, 0x0F, 0x1E, 0x00, 0xE3, 0x80, 0x1E, 0xF0, 0x01, 0xDC, 0x00,
0x3F, 0x80, 0x03, 0xE0, 0x00, 0x7C, 0x00, 0x07, 0x00, 0x01, 0xE0, 0x00,
0x38, 0x00, 0x0F, 0x00, 0x3F, 0xF0, 0x0F, 0xFF, 0x01, 0xFF, 0xE0, 0x1F,
0xF8, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF9, 0xC7,
0xC0, 0x3E, 0x01, 0xF0, 0x0F, 0x80, 0x78, 0x03, 0xC0, 0x1E, 0x07, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x81, 0xF0, 0xFC, 0x7E, 0x1F,
0x07, 0x81, 0xE0, 0x78, 0x1E, 0x07, 0x81, 0xE0, 0xF8, 0xFC, 0x3E, 0x0F,
0x83, 0xF0, 0x3E, 0x07, 0x81, 0xE0, 0x78, 0x1E, 0x07, 0x81, 0xF0, 0x7E,
0x0F, 0xC3, 0xF0, 0x38, 0x6F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x70, 0x3E, 0x0F, 0xC1, 0xF8, 0x3E,
0x07, 0x81, 0xE0, 0x78, 0x1E, 0x07, 0x81, 0xE0, 0x7C, 0x0F, 0xC1, 0xF0,
0x7C, 0x3F, 0x1F, 0x07, 0x81, 0xE0, 0x78, 0x1E, 0x07, 0x83, 0xE1, 0xF8,
0xFC, 0x3F, 0x07, 0x00, 0x1E, 0x00, 0x1F, 0xC0, 0x1F, 0xF0, 0xDF, 0xFC,
0xFF, 0x3F, 0xFB, 0x0F, 0xF8, 0x03, 0xF8, 0x00, 0x78};
const GFXglyph FreeMonoBold18pt7bGlyphs[] PROGMEM = {
{0, 0, 0, 21, 0, 1}, // 0x20 ' '
{0, 5, 22, 21, 8, -21}, // 0x21 '!'
{14, 11, 10, 21, 5, -20}, // 0x22 '"'
{28, 16, 25, 21, 3, -22}, // 0x23 '#'
{78, 14, 28, 21, 4, -23}, // 0x24 '$'
{127, 15, 21, 21, 3, -20}, // 0x25 '%'
{167, 15, 20, 21, 3, -19}, // 0x26 '&'
{205, 4, 10, 21, 8, -20}, // 0x27 '''
{210, 8, 27, 21, 9, -21}, // 0x28 '('
{237, 8, 27, 21, 4, -21}, // 0x29 ')'
{264, 16, 15, 21, 3, -21}, // 0x2A '*'
{294, 16, 19, 21, 3, -18}, // 0x2B '+'
{332, 7, 10, 21, 5, -3}, // 0x2C ','
{341, 19, 4, 21, 1, -11}, // 0x2D '-'
{351, 5, 5, 21, 8, -4}, // 0x2E '.'
{355, 15, 28, 21, 3, -23}, // 0x2F '/'
{408, 16, 23, 21, 3, -22}, // 0x30 '0'
{454, 15, 22, 21, 3, -21}, // 0x31 '1'
{496, 15, 23, 21, 3, -22}, // 0x32 '2'
{540, 16, 23, 21, 3, -22}, // 0x33 '3'
{586, 15, 21, 21, 3, -20}, // 0x34 '4'
{626, 17, 22, 21, 2, -21}, // 0x35 '5'
{673, 15, 23, 21, 4, -22}, // 0x36 '6'
{717, 15, 22, 21, 3, -21}, // 0x37 '7'
{759, 15, 23, 21, 3, -22}, // 0x38 '8'
{803, 15, 23, 21, 4, -22}, // 0x39 '9'
{847, 5, 16, 21, 8, -15}, // 0x3A ':'
{857, 7, 22, 21, 5, -15}, // 0x3B ';'
{877, 18, 16, 21, 1, -17}, // 0x3C '<'
{913, 19, 10, 21, 1, -14}, // 0x3D '='
{937, 18, 16, 21, 2, -17}, // 0x3E '>'
{973, 15, 21, 21, 4, -20}, // 0x3F '?'
{1013, 15, 27, 21, 3, -21}, // 0x40 '@'
{1064, 22, 21, 21, -1, -20}, // 0x41 'A'
{1122, 20, 21, 21, 1, -20}, // 0x42 'B'
{1175, 19, 21, 21, 1, -20}, // 0x43 'C'
{1225, 18, 21, 21, 2, -20}, // 0x44 'D'
{1273, 19, 21, 21, 1, -20}, // 0x45 'E'
{1323, 19, 21, 21, 1, -20}, // 0x46 'F'
{1373, 20, 21, 21, 1, -20}, // 0x47 'G'
{1426, 21, 21, 21, 0, -20}, // 0x48 'H'
{1482, 14, 21, 21, 4, -20}, // 0x49 'I'
{1519, 19, 21, 21, 2, -20}, // 0x4A 'J'
{1569, 20, 21, 21, 1, -20}, // 0x4B 'K'
{1622, 18, 21, 21, 2, -20}, // 0x4C 'L'
{1670, 23, 21, 21, -1, -20}, // 0x4D 'M'
{1731, 20, 21, 21, 1, -20}, // 0x4E 'N'
{1784, 20, 21, 21, 1, -20}, // 0x4F 'O'
{1837, 18, 21, 21, 1, -20}, // 0x50 'P'
{1885, 20, 26, 21, 1, -20}, // 0x51 'Q'
{1950, 21, 21, 21, 0, -20}, // 0x52 'R'
{2006, 17, 21, 21, 2, -20}, // 0x53 'S'
{2051, 19, 21, 21, 1, -20}, // 0x54 'T'
{2101, 21, 21, 21, 0, -20}, // 0x55 'U'
{2157, 23, 21, 21, -1, -20}, // 0x56 'V'
{2218, 21, 21, 21, 0, -20}, // 0x57 'W'
{2274, 19, 21, 21, 1, -20}, // 0x58 'X'
{2324, 20, 21, 21, 1, -20}, // 0x59 'Y'
{2377, 16, 21, 21, 3, -20}, // 0x5A 'Z'
{2419, 8, 27, 21, 9, -21}, // 0x5B '['
{2446, 15, 28, 21, 3, -23}, // 0x5C '\'
{2499, 8, 27, 21, 4, -21}, // 0x5D ']'
{2526, 15, 11, 21, 3, -21}, // 0x5E '^'
{2547, 21, 4, 21, 0, 4}, // 0x5F '_'
{2558, 6, 6, 21, 6, -22}, // 0x60 '`'
{2563, 19, 16, 21, 1, -15}, // 0x61 'a'
{2601, 19, 22, 21, 1, -21}, // 0x62 'b'
{2654, 17, 16, 21, 2, -15}, // 0x63 'c'
{2688, 20, 22, 21, 1, -21}, // 0x64 'd'
{2743, 18, 16, 21, 1, -15}, // 0x65 'e'
{2779, 16, 22, 21, 4, -21}, // 0x66 'f'
{2823, 19, 23, 21, 1, -15}, // 0x67 'g'
{2878, 21, 22, 21, 0, -21}, // 0x68 'h'
{2936, 16, 22, 21, 3, -21}, // 0x69 'i'
{2980, 12, 29, 21, 5, -21}, // 0x6A 'j'
{3024, 18, 22, 21, 2, -21}, // 0x6B 'k'
{3074, 16, 22, 21, 3, -21}, // 0x6C 'l'
{3118, 22, 16, 21, -1, -15}, // 0x6D 'm'
{3162, 20, 16, 21, 0, -15}, // 0x6E 'n'
{3202, 19, 16, 21, 1, -15}, // 0x6F 'o'
{3240, 21, 23, 21, 0, -15}, // 0x70 'p'
{3301, 21, 23, 22, 1, -15}, // 0x71 'q'
{3362, 17, 16, 21, 3, -15}, // 0x72 'r'
{3396, 16, 16, 21, 3, -15}, // 0x73 's'
{3428, 17, 21, 21, 1, -20}, // 0x74 't'
{3473, 18, 16, 21, 1, -15}, // 0x75 'u'
{3509, 21, 16, 21, 0, -15}, // 0x76 'v'
{3551, 21, 16, 21, 0, -15}, // 0x77 'w'
{3593, 19, 16, 21, 1, -15}, // 0x78 'x'
{3631, 19, 23, 21, 1, -15}, // 0x79 'y'
{3686, 14, 16, 21, 3, -15}, // 0x7A 'z'
{3714, 10, 27, 21, 6, -21}, // 0x7B '{'
{3748, 4, 27, 21, 9, -21}, // 0x7C '|'
{3762, 10, 27, 21, 6, -21}, // 0x7D '}'
{3796, 17, 8, 21, 2, -13}}; // 0x7E '~'
const GFXfont FreeMonoBold18pt7b PROGMEM = {
(uint8_t *)FreeMonoBold18pt7bBitmaps, (GFXglyph *)FreeMonoBold18pt7bGlyphs,
0x20, 0x7E, 35};
// Approx. 4485 bytes

View File

@@ -0,0 +1,674 @@
#pragma once
#include <Adafruit_GFX.h>
const uint8_t FreeMonoBold24pt7bBitmaps[] PROGMEM = {
0x38, 0xFB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFD, 0xF3, 0xE7, 0xCF,
0x9F, 0x3E, 0x7C, 0xF9, 0xF3, 0xE3, 0x82, 0x00, 0x00, 0x00, 0x71, 0xF7,
0xFF, 0xEF, 0x9E, 0x00, 0xFC, 0x7E, 0xF8, 0x7D, 0xF0, 0xFB, 0xE1, 0xF7,
0xC3, 0xEF, 0x87, 0xDF, 0x0F, 0xBE, 0x1F, 0x38, 0x1C, 0x70, 0x38, 0xE0,
0x71, 0xC0, 0xE3, 0x81, 0xC7, 0x03, 0x80, 0x01, 0xC1, 0xC0, 0x0F, 0x8F,
0x80, 0x3E, 0x3E, 0x00, 0xF8, 0xF8, 0x03, 0xE3, 0xE0, 0x0F, 0x8F, 0x80,
0x7E, 0x3E, 0x01, 0xF0, 0xF8, 0x07, 0xC7, 0xC0, 0x1F, 0x1F, 0x03, 0xFF,
0xFF, 0x9F, 0xFF, 0xFF, 0x7F, 0xFF, 0xFD, 0xFF, 0xFF, 0xF3, 0xFF, 0xFF,
0x81, 0xF1, 0xF0, 0x07, 0xC7, 0xC0, 0x1F, 0x1F, 0x00, 0x7C, 0x7C, 0x1F,
0xFF, 0xFC, 0xFF, 0xFF, 0xFB, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0x9F, 0xFF,
0xFC, 0x0F, 0x8F, 0x80, 0x3E, 0x3E, 0x00, 0xF8, 0xF8, 0x03, 0xE3, 0xE0,
0x0F, 0x8F, 0x80, 0x3E, 0x3E, 0x00, 0xF8, 0xF8, 0x03, 0xE3, 0xE0, 0x0F,
0x8F, 0x80, 0x3C, 0x3C, 0x00, 0x00, 0xE0, 0x00, 0x3E, 0x00, 0x07, 0xC0,
0x00, 0xF8, 0x00, 0x1F, 0x00, 0x1F, 0xFF, 0x07, 0xFF, 0xF1, 0xFF, 0xFE,
0x7F, 0xFF, 0xDF, 0xC1, 0xFB, 0xF0, 0x1F, 0x7C, 0x01, 0xEF, 0x80, 0x39,
0xF8, 0x00, 0x3F, 0xF8, 0x03, 0xFF, 0xE0, 0x3F, 0xFF, 0x03, 0xFF, 0xF0,
0x0F, 0xFF, 0x00, 0x1F, 0xE0, 0x00, 0x7F, 0xC0, 0x07, 0xF8, 0x00, 0xFF,
0x80, 0x1F, 0xF8, 0x07, 0xFF, 0x81, 0xFB, 0xFF, 0xFF, 0x7F, 0xFF, 0xCF,
0xFF, 0xF1, 0xDF, 0xFC, 0x00, 0x7C, 0x00, 0x0F, 0x80, 0x01, 0xF0, 0x00,
0x3E, 0x00, 0x07, 0xC0, 0x00, 0xF8, 0x00, 0x1F, 0x00, 0x01, 0xC0, 0x00,
0x0F, 0x80, 0x00, 0xFF, 0x00, 0x1F, 0xFC, 0x00, 0xF0, 0xE0, 0x0F, 0x07,
0x80, 0x70, 0x1C, 0x03, 0x80, 0xE0, 0x1C, 0x07, 0x00, 0xF0, 0x78, 0x03,
0xC3, 0x80, 0x1F, 0xFC, 0x00, 0x7F, 0xC1, 0xF0, 0xF8, 0x7F, 0x00, 0x3F,
0xF0, 0x0F, 0xFC, 0x03, 0xFF, 0x00, 0xFF, 0xC0, 0x07, 0xE0, 0xF8, 0x38,
0x1F, 0xE0, 0x01, 0xFF, 0x80, 0x0F, 0x1E, 0x00, 0xF0, 0x78, 0x07, 0x01,
0xC0, 0x38, 0x0E, 0x01, 0xC0, 0x70, 0x0F, 0x07, 0x80, 0x38, 0x78, 0x01,
0xFF, 0xC0, 0x07, 0xF8, 0x00, 0x0F, 0x80, 0x00, 0xF8, 0x00, 0x1F, 0xFC,
0x01, 0xFF, 0xE0, 0x1F, 0xFF, 0x00, 0xFF, 0xF8, 0x0F, 0xC7, 0x00, 0x7C,
0x10, 0x03, 0xE0, 0x00, 0x1F, 0x00, 0x00, 0xFC, 0x00, 0x03, 0xF0, 0x00,
0x1F, 0x80, 0x00, 0xFE, 0x00, 0x0F, 0xF8, 0x00, 0xFF, 0xC7, 0xCF, 0xFF,
0x3F, 0x7E, 0xFF, 0xFF, 0xE7, 0xFF, 0xBE, 0x1F, 0xF9, 0xF0, 0x7F, 0x8F,
0x83, 0xFC, 0x7C, 0x0F, 0xE3, 0xF0, 0x7F, 0xCF, 0xFF, 0xFF, 0x7F, 0xFF,
0xF9, 0xFF, 0xFF, 0xC7, 0xFF, 0xFC, 0x0F, 0xE0, 0x00, 0xFD, 0xF7, 0xDF,
0x7D, 0xF7, 0xDF, 0x38, 0xE3, 0x8E, 0x38, 0xE0, 0x01, 0x80, 0xF0, 0x7C,
0x3F, 0x0F, 0xC7, 0xE1, 0xF8, 0xFC, 0x3E, 0x0F, 0x87, 0xC1, 0xF0, 0x7C,
0x1F, 0x0F, 0x83, 0xE0, 0xF8, 0x3E, 0x0F, 0x83, 0xE0, 0xF8, 0x3E, 0x0F,
0x81, 0xF0, 0x7C, 0x1F, 0x07, 0xC0, 0xF8, 0x3E, 0x0F, 0xC1, 0xF0, 0x7E,
0x0F, 0x83, 0xF0, 0x7C, 0x1F, 0x03, 0xC0, 0x60, 0x3C, 0x0F, 0x83, 0xF0,
0xFC, 0x1F, 0x83, 0xE0, 0xFC, 0x1F, 0x07, 0xC1, 0xF8, 0x3E, 0x0F, 0x83,
0xE0, 0x7C, 0x1F, 0x07, 0xC1, 0xF0, 0x7C, 0x1F, 0x07, 0xC1, 0xF0, 0x7C,
0x1E, 0x0F, 0x83, 0xE0, 0xF8, 0x7C, 0x1F, 0x0F, 0xC3, 0xE1, 0xF8, 0x7C,
0x3F, 0x0F, 0x83, 0xE0, 0xF0, 0x00, 0x00, 0x70, 0x00, 0x07, 0xC0, 0x00,
0x3E, 0x00, 0x01, 0xF0, 0x00, 0x0F, 0x80, 0x10, 0x7C, 0x11, 0xF3, 0xE7,
0xDF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFB, 0xFF, 0xFF, 0x87, 0xFF, 0xF0, 0x07,
0xFC, 0x00, 0x3F, 0xE0, 0x03, 0xFF, 0x80, 0x3F, 0x7E, 0x01, 0xFB, 0xF0,
0x1F, 0x8F, 0xC0, 0xF8, 0x3E, 0x03, 0x80, 0xE0, 0x00, 0x38, 0x00, 0x00,
0xF8, 0x00, 0x01, 0xF0, 0x00, 0x03, 0xE0, 0x00, 0x07, 0xC0, 0x00, 0x0F,
0x80, 0x00, 0x1F, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x7C, 0x00, 0x00, 0xF8,
0x01, 0xFF, 0xFF, 0xF7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xDF, 0xFF, 0xFF, 0x00, 0x3E, 0x00, 0x00, 0x7C, 0x00, 0x00, 0xF8, 0x00,
0x01, 0xF0, 0x00, 0x03, 0xE0, 0x00, 0x07, 0xC0, 0x00, 0x0F, 0x80, 0x00,
0x1F, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x70, 0x00, 0x1F,
0x8F, 0x87, 0xC7, 0xC3, 0xE1, 0xE1, 0xF0, 0xF0, 0x78, 0x38, 0x3C, 0x1C,
0x0E, 0x06, 0x00, 0x7F, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFE, 0x7D, 0xFF, 0xFF, 0xFF, 0xEF, 0x80,
0x00, 0x00, 0x60, 0x00, 0x0F, 0x00, 0x01, 0xF0, 0x00, 0x1F, 0x00, 0x01,
0xF0, 0x00, 0x3E, 0x00, 0x03, 0xE0, 0x00, 0x7C, 0x00, 0x07, 0xC0, 0x00,
0xF8, 0x00, 0x0F, 0x80, 0x01, 0xF0, 0x00, 0x1F, 0x00, 0x03, 0xE0, 0x00,
0x3E, 0x00, 0x07, 0xC0, 0x00, 0x7C, 0x00, 0x0F, 0xC0, 0x00, 0xF8, 0x00,
0x1F, 0x80, 0x01, 0xF0, 0x00, 0x3F, 0x00, 0x03, 0xE0, 0x00, 0x3E, 0x00,
0x07, 0xC0, 0x00, 0x7C, 0x00, 0x0F, 0x80, 0x00, 0xF8, 0x00, 0x1F, 0x00,
0x01, 0xF0, 0x00, 0x3E, 0x00, 0x03, 0xE0, 0x00, 0x7C, 0x00, 0x07, 0xC0,
0x00, 0xFC, 0x00, 0x0F, 0x80, 0x00, 0xF8, 0x00, 0x0F, 0x00, 0x00, 0x01,
0xFC, 0x00, 0x3F, 0xF8, 0x03, 0xFF, 0xE0, 0x3F, 0xFF, 0x83, 0xFF, 0xFE,
0x1F, 0x83, 0xF1, 0xF8, 0x0F, 0xCF, 0x80, 0x3E, 0x7C, 0x01, 0xF7, 0xC0,
0x07, 0xFE, 0x00, 0x3F, 0xF0, 0x01, 0xFF, 0x80, 0x0F, 0xFC, 0x00, 0x7F,
0xE0, 0x03, 0xFF, 0x00, 0x1F, 0xF8, 0x00, 0xFF, 0xC0, 0x07, 0xFE, 0x00,
0x3F, 0xF0, 0x01, 0xFF, 0x80, 0x0F, 0xFC, 0x00, 0x7D, 0xF0, 0x07, 0xCF,
0x80, 0x3E, 0x7E, 0x03, 0xF1, 0xF8, 0x3F, 0x0F, 0xFF, 0xF8, 0x3F, 0xFF,
0x80, 0xFF, 0xF8, 0x03, 0xFF, 0x80, 0x07, 0xF0, 0x00, 0x01, 0xF8, 0x00,
0x3F, 0x80, 0x0F, 0xF8, 0x01, 0xFF, 0x80, 0x7F, 0xF8, 0x0F, 0xEF, 0x80,
0xFC, 0xF8, 0x07, 0x0F, 0x80, 0x00, 0xF8, 0x00, 0x0F, 0x80, 0x00, 0xF8,
0x00, 0x0F, 0x80, 0x00, 0xF8, 0x00, 0x0F, 0x80, 0x00, 0xF8, 0x00, 0x0F,
0x80, 0x00, 0xF8, 0x00, 0x0F, 0x80, 0x00, 0xF8, 0x00, 0x0F, 0x80, 0x00,
0xF8, 0x00, 0x0F, 0x80, 0x00, 0xF8, 0x00, 0x0F, 0x80, 0x3F, 0xFF, 0xE7,
0xFF, 0xFF, 0x7F, 0xFF, 0xF7, 0xFF, 0xFF, 0x3F, 0xFF, 0xE0, 0x01, 0xFC,
0x00, 0x3F, 0xF8, 0x07, 0xFF, 0xF0, 0x7F, 0xFF, 0xC7, 0xFF, 0xFF, 0x3F,
0x03, 0xFB, 0xF0, 0x07, 0xFF, 0x00, 0x1F, 0xF8, 0x00, 0xFB, 0x80, 0x07,
0xC0, 0x00, 0x3E, 0x00, 0x03, 0xF0, 0x00, 0x3F, 0x00, 0x03, 0xF8, 0x00,
0x3F, 0x80, 0x03, 0xF8, 0x00, 0x3F, 0x80, 0x03, 0xF8, 0x00, 0x3F, 0x00,
0x07, 0xF0, 0x00, 0x7F, 0x00, 0x07, 0xF0, 0x00, 0x7F, 0x00, 0x07, 0xE0,
0x0E, 0xFE, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x03, 0xF8, 0x00, 0xFF, 0xF8, 0x0F, 0xFF,
0xE0, 0xFF, 0xFF, 0x8F, 0xFF, 0xFE, 0x7E, 0x03, 0xF1, 0xC0, 0x0F, 0xC0,
0x00, 0x3E, 0x00, 0x01, 0xF0, 0x00, 0x0F, 0x80, 0x00, 0xFC, 0x00, 0x0F,
0xC0, 0x0F, 0xFC, 0x00, 0xFF, 0xC0, 0x07, 0xFC, 0x00, 0x3F, 0xF0, 0x00,
0xFF, 0xC0, 0x00, 0x7F, 0x00, 0x00, 0xFC, 0x00, 0x03, 0xF0, 0x00, 0x0F,
0x80, 0x00, 0x7C, 0x00, 0x03, 0xE0, 0x00, 0x1F, 0x00, 0x01, 0xFF, 0xC0,
0x3F, 0xBF, 0xFF, 0xFD, 0xFF, 0xFF, 0xC7, 0xFF, 0xFC, 0x1F, 0xFF, 0xC0,
0x1F, 0xF0, 0x00, 0x00, 0x3F, 0x80, 0x03, 0xF8, 0x00, 0x7F, 0x80, 0x07,
0xF8, 0x00, 0xFF, 0x80, 0x1F, 0xF8, 0x01, 0xEF, 0x80, 0x3E, 0xF8, 0x03,
0xCF, 0x80, 0x7C, 0xF8, 0x0F, 0x8F, 0x80, 0xF0, 0xF8, 0x1F, 0x0F, 0x81,
0xE0, 0xF8, 0x3E, 0x0F, 0x87, 0xC0, 0xF8, 0x78, 0x0F, 0x8F, 0xFF, 0xFE,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x0F,
0x80, 0x07, 0xFE, 0x00, 0xFF, 0xF0, 0x0F, 0xFF, 0x00, 0xFF, 0xF0, 0x07,
0xFE, 0x3F, 0xFF, 0xC1, 0xFF, 0xFF, 0x0F, 0xFF, 0xF8, 0x7F, 0xFF, 0xC3,
0xFF, 0xFC, 0x1F, 0x00, 0x00, 0xF8, 0x00, 0x07, 0xC0, 0x00, 0x3E, 0x00,
0x01, 0xF0, 0x00, 0x0F, 0xBF, 0x00, 0x7F, 0xFF, 0x03, 0xFF, 0xFC, 0x1F,
0xFF, 0xF0, 0xFF, 0xFF, 0x83, 0xC0, 0xFE, 0x00, 0x01, 0xF0, 0x00, 0x0F,
0xC0, 0x00, 0x3E, 0x00, 0x01, 0xF0, 0x00, 0x0F, 0x80, 0x00, 0x7C, 0x00,
0x03, 0xE0, 0x00, 0x3F, 0xF0, 0x03, 0xF7, 0xE0, 0x3F, 0xBF, 0xFF, 0xF9,
0xFF, 0xFF, 0xC7, 0xFF, 0xFC, 0x1F, 0xFF, 0x80, 0x1F, 0xF0, 0x00, 0x00,
0x1F, 0xC0, 0x0F, 0xFF, 0x01, 0xFF, 0xF0, 0x7F, 0xFF, 0x0F, 0xFF, 0xE1,
0xFF, 0x00, 0x1F, 0xC0, 0x03, 0xF0, 0x00, 0x7E, 0x00, 0x07, 0xE0, 0x00,
0x7C, 0x00, 0x0F, 0x8F, 0xC0, 0xF9, 0xFF, 0x0F, 0xFF, 0xF8, 0xFF, 0xFF,
0xCF, 0xFF, 0xFC, 0xFF, 0x0F, 0xEF, 0xE0, 0x3E, 0xFC, 0x03, 0xFF, 0x80,
0x1F, 0xF8, 0x01, 0xFF, 0x80, 0x1F, 0xF8, 0x01, 0xF7, 0xC0, 0x3F, 0x7E,
0x03, 0xF3, 0xF0, 0x7E, 0x3F, 0xFF, 0xE1, 0xFF, 0xFC, 0x0F, 0xFF, 0x80,
0x7F, 0xF0, 0x01, 0xFC, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x1F, 0xF0, 0x03, 0xE0, 0x00,
0x3E, 0x00, 0x03, 0xE0, 0x00, 0x7C, 0x00, 0x07, 0xC0, 0x00, 0x7C, 0x00,
0x0F, 0x80, 0x00, 0xF8, 0x00, 0x0F, 0x80, 0x01, 0xF0, 0x00, 0x1F, 0x00,
0x01, 0xF0, 0x00, 0x3E, 0x00, 0x03, 0xE0, 0x00, 0x3E, 0x00, 0x07, 0xC0,
0x00, 0x7C, 0x00, 0x07, 0xC0, 0x00, 0xF8, 0x00, 0x0F, 0x80, 0x00, 0xF8,
0x00, 0x0F, 0x00, 0x00, 0xF0, 0x00, 0x06, 0x00, 0x01, 0xF8, 0x00, 0xFF,
0xF0, 0x1F, 0xFF, 0x83, 0xFF, 0xFC, 0x7F, 0xFF, 0xE7, 0xE0, 0x7E, 0xFC,
0x03, 0xFF, 0x80, 0x1F, 0xF8, 0x01, 0xFF, 0x80, 0x1F, 0xF8, 0x01, 0xF7,
0xC0, 0x3E, 0x7E, 0x07, 0xE3, 0xFF, 0xFC, 0x0F, 0xFF, 0x00, 0xFF, 0xF0,
0x1F, 0xFF, 0x83, 0xFF, 0xFC, 0x7F, 0x0F, 0xE7, 0xC0, 0x3E, 0xF8, 0x01,
0xFF, 0x80, 0x1F, 0xF8, 0x01, 0xFF, 0x80, 0x1F, 0xFC, 0x03, 0xF7, 0xE0,
0x7E, 0x7F, 0xFF, 0xE3, 0xFF, 0xFC, 0x1F, 0xFF, 0x80, 0xFF, 0xF0, 0x03,
0xFC, 0x00, 0x03, 0xF8, 0x00, 0xFF, 0xE0, 0x1F, 0xFF, 0x83, 0xFF, 0xF8,
0x7F, 0xFF, 0xC7, 0xE0, 0xFE, 0xFC, 0x03, 0xEF, 0x80, 0x3E, 0xF8, 0x01,
0xFF, 0x80, 0x1F, 0xF8, 0x01, 0xFF, 0x80, 0x3F, 0xFC, 0x07, 0xF7, 0xE0,
0xFF, 0x7F, 0xFF, 0xF3, 0xFF, 0xFF, 0x1F, 0xFF, 0xF0, 0xFF, 0x9F, 0x03,
0xF1, 0xF0, 0x00, 0x3F, 0x00, 0x03, 0xE0, 0x00, 0x7E, 0x00, 0x0F, 0xC0,
0x01, 0xFC, 0x00, 0x3F, 0x80, 0x0F, 0xF0, 0x7F, 0xFE, 0x0F, 0xFF, 0xC0,
0xFF, 0xF8, 0x0F, 0xFF, 0x00, 0x3F, 0x80, 0x00, 0x7D, 0xFF, 0xFF, 0xFF,
0xEF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7D, 0xFF,
0xFF, 0xFF, 0xEF, 0x80, 0x0F, 0x87, 0xF1, 0xFC, 0x7F, 0x1F, 0xC3, 0xE0,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F,
0x1F, 0x87, 0xE1, 0xF0, 0xFC, 0x3E, 0x0F, 0x03, 0xC1, 0xE0, 0x78, 0x1C,
0x07, 0x01, 0x80, 0x00, 0x00, 0x04, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x7F,
0x00, 0x01, 0xFE, 0x00, 0x07, 0xFC, 0x00, 0x1F, 0xF0, 0x00, 0x7F, 0xC0,
0x01, 0xFF, 0x00, 0x07, 0xFE, 0x00, 0x1F, 0xF8, 0x00, 0x7F, 0xE0, 0x00,
0xFF, 0xE0, 0x00, 0x1F, 0xF8, 0x00, 0x07, 0xFE, 0x00, 0x01, 0xFF, 0x80,
0x00, 0x7F, 0xE0, 0x00, 0x1F, 0xF8, 0x00, 0x07, 0xFC, 0x00, 0x01, 0xFE,
0x00, 0x00, 0x7F, 0x00, 0x00, 0x1E, 0x7F, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFE, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFE,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFE,
0x00, 0x00, 0x01, 0xE0, 0x00, 0x03, 0xF0, 0x00, 0x07, 0xF8, 0x00, 0x07,
0xFC, 0x00, 0x03, 0xFE, 0x00, 0x01, 0xFF, 0x00, 0x00, 0xFF, 0x80, 0x00,
0x7F, 0xC0, 0x00, 0x7F, 0xE0, 0x00, 0x3F, 0xF0, 0x00, 0x3F, 0xF0, 0x01,
0xFF, 0x00, 0x0F, 0xF8, 0x00, 0x7F, 0xC0, 0x03, 0xFE, 0x00, 0x1F, 0xF0,
0x00, 0xFF, 0x80, 0x03, 0xFC, 0x00, 0x07, 0xE0, 0x00, 0x0F, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x03, 0xF8, 0x01, 0xFF, 0xF0, 0xFF, 0xFF, 0x8F,
0xFF, 0xFC, 0xFF, 0xFF, 0xEF, 0xC0, 0x7E, 0xF8, 0x03, 0xFF, 0x80, 0x1F,
0x70, 0x01, 0xF0, 0x00, 0x1F, 0x00, 0x03, 0xF0, 0x00, 0x7E, 0x00, 0x3F,
0xE0, 0x0F, 0xFC, 0x01, 0xFF, 0x00, 0x0F, 0xC0, 0x00, 0xF0, 0x00, 0x0F,
0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x1F, 0x00, 0x03, 0xF8, 0x00, 0x3F, 0x80, 0x03, 0xF8, 0x00,
0x3F, 0x80, 0x01, 0xF0, 0x00, 0x01, 0xF0, 0x00, 0xFF, 0x80, 0x3F, 0xF8,
0x0F, 0xFF, 0x83, 0xE0, 0xF8, 0x78, 0x07, 0x1E, 0x00, 0xF3, 0x80, 0x0E,
0x70, 0x01, 0xDE, 0x00, 0x3B, 0x80, 0x3F, 0x70, 0x1F, 0xEE, 0x07, 0xFD,
0xC1, 0xFF, 0xB8, 0x7E, 0x77, 0x0F, 0x0E, 0xE3, 0xC1, 0xDC, 0x70, 0x3B,
0x8E, 0x07, 0x71, 0xC0, 0xEE, 0x3C, 0x1D, 0xC3, 0xC3, 0xB8, 0x7F, 0xF7,
0x07, 0xFF, 0xE0, 0x7F, 0xFC, 0x03, 0xFB, 0xC0, 0x00, 0x38, 0x00, 0x07,
0x00, 0x00, 0xF0, 0x00, 0x0F, 0x00, 0x61, 0xF0, 0x3E, 0x1F, 0xFF, 0xC3,
0xFF, 0xF0, 0x1F, 0xFC, 0x01, 0xFC, 0x00, 0x07, 0xFF, 0x80, 0x00, 0x7F,
0xFE, 0x00, 0x03, 0xFF, 0xF0, 0x00, 0x1F, 0xFF, 0xC0, 0x00, 0x7F, 0xFE,
0x00, 0x00, 0x1F, 0xF0, 0x00, 0x01, 0xF7, 0xC0, 0x00, 0x0F, 0xBE, 0x00,
0x00, 0x7D, 0xF8, 0x00, 0x07, 0xC7, 0xC0, 0x00, 0x3E, 0x3E, 0x00, 0x03,
0xE0, 0xF8, 0x00, 0x1F, 0x07, 0xC0, 0x00, 0xF0, 0x3F, 0x00, 0x0F, 0x80,
0xF8, 0x00, 0x7F, 0xFF, 0xC0, 0x07, 0xFF, 0xFF, 0x00, 0x3F, 0xFF, 0xF8,
0x03, 0xFF, 0xFF, 0xE0, 0x1F, 0xFF, 0xFF, 0x00, 0xF8, 0x00, 0xF8, 0x0F,
0x80, 0x03, 0xE1, 0xFF, 0x80, 0xFF, 0xDF, 0xFE, 0x0F, 0xFF, 0xFF, 0xF0,
0x7F, 0xFF, 0xFF, 0x83, 0xFF, 0xDF, 0xF8, 0x0F, 0xFC, 0x7F, 0xFF, 0xC0,
0x3F, 0xFF, 0xFC, 0x0F, 0xFF, 0xFF, 0xC3, 0xFF, 0xFF, 0xF8, 0x7F, 0xFF,
0xFE, 0x07, 0xC0, 0x1F, 0xC1, 0xF0, 0x01, 0xF0, 0x7C, 0x00, 0x7C, 0x1F,
0x00, 0x1F, 0x07, 0xC0, 0x0F, 0xC1, 0xF0, 0x07, 0xE0, 0x7F, 0xFF, 0xF0,
0x1F, 0xFF, 0xF8, 0x07, 0xFF, 0xFF, 0x01, 0xFF, 0xFF, 0xE0, 0x7F, 0xFF,
0xFC, 0x1F, 0x00, 0x3F, 0x87, 0xC0, 0x03, 0xF1, 0xF0, 0x00, 0x7C, 0x7C,
0x00, 0x1F, 0x1F, 0x00, 0x07, 0xC7, 0xC0, 0x03, 0xF7, 0xFF, 0xFF, 0xFB,
0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0x87, 0xFF, 0xFF,
0x00, 0x00, 0x7F, 0x00, 0x00, 0xFF, 0xE7, 0x01, 0xFF, 0xFF, 0xC1, 0xFF,
0xFF, 0xE1, 0xFF, 0xFF, 0xF1, 0xFE, 0x07, 0xF8, 0xFC, 0x01, 0xFC, 0xFC,
0x00, 0x7E, 0x7C, 0x00, 0x1F, 0x7E, 0x00, 0x0F, 0xBE, 0x00, 0x03, 0x9F,
0x00, 0x00, 0x0F, 0x80, 0x00, 0x07, 0xC0, 0x00, 0x03, 0xE0, 0x00, 0x01,
0xF0, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x3E, 0x00, 0x00,
0x1F, 0x80, 0x00, 0x07, 0xC0, 0x00, 0x03, 0xF0, 0x00, 0x39, 0xFC, 0x00,
0x7C, 0x7F, 0x80, 0xFF, 0x1F, 0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0x81, 0xFF,
0xFF, 0x00, 0x3F, 0xFF, 0x00, 0x07, 0xFC, 0x00, 0x7F, 0xFF, 0x00, 0x7F,
0xFF, 0xF0, 0x3F, 0xFF, 0xFC, 0x1F, 0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0xC1,
0xF0, 0x0F, 0xF0, 0xF8, 0x01, 0xF8, 0x7C, 0x00, 0x7E, 0x3E, 0x00, 0x1F,
0x1F, 0x00, 0x0F, 0xCF, 0x80, 0x03, 0xE7, 0xC0, 0x01, 0xF3, 0xE0, 0x00,
0xF9, 0xF0, 0x00, 0x7C, 0xF8, 0x00, 0x3E, 0x7C, 0x00, 0x1F, 0x3E, 0x00,
0x0F, 0x9F, 0x00, 0x07, 0xCF, 0x80, 0x07, 0xE7, 0xC0, 0x03, 0xE3, 0xE0,
0x03, 0xF1, 0xF0, 0x07, 0xF1, 0xFF, 0xFF, 0xF9, 0xFF, 0xFF, 0xF8, 0xFF,
0xFF, 0xF8, 0x7F, 0xFF, 0xF0, 0x1F, 0xFF, 0xE0, 0x00, 0x7F, 0xFF, 0xFF,
0x7F, 0xFF, 0xFF, 0xBF, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0xE7, 0xFF, 0xFF,
0xF0, 0xF8, 0x00, 0xF8, 0x7C, 0x00, 0x7C, 0x3E, 0x0E, 0x3E, 0x1F, 0x0F,
0x9F, 0x0F, 0x87, 0xC7, 0x07, 0xC3, 0xE0, 0x03, 0xFF, 0xF0, 0x01, 0xFF,
0xF8, 0x00, 0xFF, 0xFC, 0x00, 0x7F, 0xFE, 0x00, 0x3F, 0xFF, 0x00, 0x1F,
0x0F, 0x80, 0x0F, 0x87, 0xC3, 0x87, 0xC1, 0xC3, 0xE3, 0xE0, 0x01, 0xF1,
0xF0, 0x00, 0xF8, 0xF8, 0x00, 0x7D, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0xE0, 0x7F, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0xFF,
0xFF, 0xF8, 0xF8, 0x00, 0x7C, 0x7C, 0x00, 0x3E, 0x3E, 0x00, 0x1F, 0x1F,
0x07, 0x0F, 0x8F, 0x87, 0xC3, 0x87, 0xC3, 0xE0, 0x03, 0xFF, 0xF0, 0x01,
0xFF, 0xF8, 0x00, 0xFF, 0xFC, 0x00, 0x7F, 0xFE, 0x00, 0x3F, 0xFF, 0x00,
0x1F, 0x0F, 0x80, 0x0F, 0x87, 0xC0, 0x07, 0xC3, 0xE0, 0x03, 0xE0, 0xE0,
0x01, 0xF0, 0x00, 0x00, 0xF8, 0x00, 0x01, 0xFF, 0xF0, 0x01, 0xFF, 0xFC,
0x00, 0xFF, 0xFE, 0x00, 0x7F, 0xFF, 0x00, 0x1F, 0xFF, 0x00, 0x00, 0x00,
0x7F, 0x8E, 0x00, 0xFF, 0xF7, 0x81, 0xFF, 0xFF, 0xC1, 0xFF, 0xFF, 0xE1,
0xFF, 0xFF, 0xF1, 0xFE, 0x03, 0xF8, 0xFC, 0x00, 0xFC, 0xFC, 0x00, 0x3E,
0x7C, 0x00, 0x1F, 0x7E, 0x00, 0x07, 0x3E, 0x00, 0x00, 0x1F, 0x00, 0x00,
0x0F, 0x80, 0x00, 0x07, 0xC0, 0x00, 0x03, 0xE0, 0x00, 0x01, 0xF0, 0x0F,
0xFE, 0xF8, 0x0F, 0xFF, 0xFC, 0x07, 0xFF, 0xFE, 0x03, 0xFF, 0xFF, 0x00,
0xFF, 0xFF, 0xC0, 0x01, 0xF3, 0xF0, 0x00, 0xF9, 0xFC, 0x00, 0x7C, 0x7F,
0x80, 0xFE, 0x3F, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0x83, 0xFF, 0xFF, 0x80,
0x7F, 0xFF, 0x00, 0x07, 0xFC, 0x00, 0x3F, 0xE1, 0xFF, 0x1F, 0xFC, 0xFF,
0xE7, 0xFF, 0x3F, 0xF9, 0xFF, 0xCF, 0xFE, 0x3F, 0xE1, 0xFF, 0x07, 0xC0,
0x0F, 0x81, 0xF0, 0x03, 0xE0, 0x7C, 0x00, 0xF8, 0x1F, 0x00, 0x3E, 0x07,
0xC0, 0x0F, 0x81, 0xF0, 0x03, 0xE0, 0x7F, 0xFF, 0xF8, 0x1F, 0xFF, 0xFE,
0x07, 0xFF, 0xFF, 0x81, 0xFF, 0xFF, 0xE0, 0x7F, 0xFF, 0xF8, 0x1F, 0x00,
0x3E, 0x07, 0xC0, 0x0F, 0x81, 0xF0, 0x03, 0xE0, 0x7C, 0x00, 0xF8, 0x1F,
0x00, 0x3E, 0x07, 0xC0, 0x0F, 0x87, 0xFE, 0x1F, 0xFB, 0xFF, 0xCF, 0xFF,
0xFF, 0xF3, 0xFF, 0xFF, 0xFC, 0xFF, 0xF7, 0xFE, 0x1F, 0xF8, 0x7F, 0xFF,
0xDF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0xFF, 0xFC, 0x03, 0xE0,
0x00, 0x7C, 0x00, 0x0F, 0x80, 0x01, 0xF0, 0x00, 0x3E, 0x00, 0x07, 0xC0,
0x00, 0xF8, 0x00, 0x1F, 0x00, 0x03, 0xE0, 0x00, 0x7C, 0x00, 0x0F, 0x80,
0x01, 0xF0, 0x00, 0x3E, 0x00, 0x07, 0xC0, 0x00, 0xF8, 0x00, 0x1F, 0x00,
0x03, 0xE0, 0x1F, 0xFF, 0xF7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFD,
0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xC0, 0x7F, 0xFF,
0xE0, 0x3F, 0xFF, 0xF0, 0x0F, 0xFF, 0xF0, 0x00, 0x0F, 0x80, 0x00, 0x07,
0xC0, 0x00, 0x03, 0xE0, 0x00, 0x01, 0xF0, 0x00, 0x00, 0xF8, 0x00, 0x00,
0x7C, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x0F, 0x80, 0x00,
0x07, 0xC0, 0xE0, 0x03, 0xE0, 0xF8, 0x01, 0xF0, 0x7C, 0x00, 0xF8, 0x3E,
0x00, 0x7C, 0x1F, 0x00, 0x3E, 0x0F, 0x80, 0x1F, 0x07, 0xC0, 0x1F, 0x83,
0xF8, 0x3F, 0x81, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0xC0, 0x3F, 0xFF, 0xC0,
0x07, 0xFF, 0xC0, 0x00, 0x7F, 0x00, 0x00, 0x7F, 0xE0, 0xFF, 0x9F, 0xFE,
0x3F, 0xFB, 0xFF, 0xC7, 0xFF, 0x7F, 0xF8, 0xFF, 0xE7, 0xFE, 0x0F, 0xF8,
0x3E, 0x01, 0xF8, 0x07, 0xC0, 0xFE, 0x00, 0xF8, 0x3F, 0x80, 0x1F, 0x0F,
0xE0, 0x03, 0xE3, 0xF8, 0x00, 0x7D, 0xFC, 0x00, 0x0F, 0xFF, 0x00, 0x01,
0xFF, 0xF0, 0x00, 0x3F, 0xFF, 0x00, 0x07, 0xFF, 0xF0, 0x00, 0xFE, 0x7F,
0x00, 0x1F, 0x87, 0xF0, 0x03, 0xE0, 0x7E, 0x00, 0x7C, 0x07, 0xE0, 0x0F,
0x80, 0x7E, 0x01, 0xF0, 0x0F, 0xC0, 0x3E, 0x00, 0xF8, 0x1F, 0xF8, 0x1F,
0xF7, 0xFF, 0x81, 0xFF, 0xFF, 0xF0, 0x3F, 0xFF, 0xFE, 0x07, 0xFD, 0xFF,
0x80, 0x7F, 0x00, 0x7F, 0xFC, 0x00, 0x7F, 0xFF, 0x00, 0x3F, 0xFF, 0x80,
0x1F, 0xFF, 0xC0, 0x07, 0xFF, 0xC0, 0x00, 0x3E, 0x00, 0x00, 0x1F, 0x00,
0x00, 0x0F, 0x80, 0x00, 0x07, 0xC0, 0x00, 0x03, 0xE0, 0x00, 0x01, 0xF0,
0x00, 0x00, 0xF8, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x1F,
0x00, 0x00, 0x0F, 0x80, 0x0E, 0x07, 0xC0, 0x0F, 0x83, 0xE0, 0x07, 0xC1,
0xF0, 0x03, 0xE0, 0xF8, 0x01, 0xF0, 0x7C, 0x00, 0xF8, 0x3E, 0x00, 0x7D,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xDF, 0xFF, 0xFF, 0xE0, 0x3F, 0x80, 0x03, 0xF8, 0xFF, 0x80, 0x0F, 0xF9,
0xFF, 0x00, 0x1F, 0xF3, 0xFF, 0x00, 0x7F, 0xE3, 0xFE, 0x00, 0xFF, 0x83,
0xFE, 0x03, 0xFE, 0x07, 0xFC, 0x07, 0xFC, 0x0F, 0xFC, 0x1F, 0xF8, 0x1F,
0xF8, 0x3F, 0xF0, 0x3F, 0xF0, 0x7F, 0xE0, 0x7D, 0xF1, 0xF7, 0xC0, 0xFB,
0xE3, 0xEF, 0x81, 0xF7, 0xEF, 0xDF, 0x03, 0xE7, 0xDF, 0x3E, 0x07, 0xCF,
0xFE, 0x7C, 0x0F, 0x8F, 0xF8, 0xF8, 0x1F, 0x1F, 0xF1, 0xF0, 0x3E, 0x1F,
0xE3, 0xE0, 0x7C, 0x3F, 0x87, 0xC0, 0xF8, 0x3F, 0x0F, 0x81, 0xF0, 0x00,
0x1F, 0x03, 0xE0, 0x00, 0x3E, 0x1F, 0xF8, 0x03, 0xFF, 0x7F, 0xF8, 0x0F,
0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xE0, 0x3F, 0xFD, 0xFF, 0x80, 0x3F,
0xF0, 0x7F, 0x00, 0x7F, 0xEF, 0xF8, 0x0F, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF,
0xFC, 0x0F, 0xFF, 0x7F, 0xE0, 0x7F, 0xE1, 0xFF, 0x00, 0xF8, 0x1F, 0xF0,
0x0F, 0x81, 0xFF, 0x80, 0xF8, 0x1F, 0xFC, 0x0F, 0x81, 0xFF, 0xC0, 0xF8,
0x1F, 0x7E, 0x0F, 0x81, 0xF3, 0xF0, 0xF8, 0x1F, 0x3F, 0x0F, 0x81, 0xF1,
0xF8, 0xF8, 0x1F, 0x0F, 0xCF, 0x81, 0xF0, 0xFC, 0xF8, 0x1F, 0x07, 0xEF,
0x81, 0xF0, 0x3F, 0xF8, 0x1F, 0x03, 0xFF, 0x81, 0xF0, 0x1F, 0xF8, 0x1F,
0x00, 0xFF, 0x81, 0xF0, 0x0F, 0xF8, 0x7F, 0xE0, 0x7F, 0x8F, 0xFF, 0x03,
0xF8, 0xFF, 0xF0, 0x3F, 0x8F, 0xFF, 0x01, 0xF8, 0x7F, 0xE0, 0x0F, 0x80,
0x00, 0x3F, 0x80, 0x00, 0x3F, 0xFC, 0x00, 0x0F, 0xFF, 0xE0, 0x03, 0xFF,
0xFE, 0x00, 0xFF, 0xFF, 0xE0, 0x3F, 0xC1, 0xFE, 0x0F, 0xE0, 0x0F, 0xE1,
0xF8, 0x00, 0xFC, 0x7E, 0x00, 0x0F, 0xCF, 0x80, 0x00, 0xFB, 0xF0, 0x00,
0x1F, 0xFC, 0x00, 0x01, 0xFF, 0x80, 0x00, 0x3F, 0xF0, 0x00, 0x07, 0xFE,
0x00, 0x00, 0xFF, 0xC0, 0x00, 0x1F, 0xF8, 0x00, 0x03, 0xFF, 0x00, 0x00,
0x7F, 0xF0, 0x00, 0x1F, 0xBE, 0x00, 0x03, 0xE7, 0xE0, 0x00, 0xFC, 0x7E,
0x00, 0x3F, 0x0F, 0xE0, 0x0F, 0xE0, 0xFF, 0x07, 0xF8, 0x0F, 0xFF, 0xFE,
0x00, 0xFF, 0xFF, 0x80, 0x0F, 0xFF, 0xE0, 0x00, 0xFF, 0xF8, 0x00, 0x03,
0xF8, 0x00, 0x7F, 0xFF, 0x80, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xF8, 0xFF,
0xFF, 0xFC, 0x7F, 0xFF, 0xFE, 0x1F, 0x00, 0xFE, 0x1F, 0x00, 0x3F, 0x1F,
0x00, 0x1F, 0x1F, 0x00, 0x1F, 0x1F, 0x00, 0x1F, 0x1F, 0x00, 0x1F, 0x1F,
0x00, 0x3F, 0x1F, 0x00, 0x7E, 0x1F, 0xFF, 0xFE, 0x1F, 0xFF, 0xFC, 0x1F,
0xFF, 0xF8, 0x1F, 0xFF, 0xF0, 0x1F, 0xFF, 0x80, 0x1F, 0x00, 0x00, 0x1F,
0x00, 0x00, 0x1F, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x7F, 0xFC, 0x00, 0xFF,
0xFE, 0x00, 0xFF, 0xFE, 0x00, 0xFF, 0xFE, 0x00, 0x7F, 0xFC, 0x00, 0x00,
0x3F, 0x80, 0x00, 0x3F, 0xFC, 0x00, 0x0F, 0xFF, 0xE0, 0x03, 0xFF, 0xFE,
0x00, 0xFF, 0xFF, 0xE0, 0x3F, 0xC1, 0xFE, 0x0F, 0xE0, 0x0F, 0xE1, 0xF8,
0x00, 0xFC, 0x7E, 0x00, 0x0F, 0xCF, 0x80, 0x00, 0xFB, 0xF0, 0x00, 0x1F,
0xFC, 0x00, 0x01, 0xFF, 0x80, 0x00, 0x3F, 0xF0, 0x00, 0x07, 0xFE, 0x00,
0x00, 0xFF, 0xC0, 0x00, 0x1F, 0xF8, 0x00, 0x03, 0xFF, 0x80, 0x00, 0xFD,
0xF0, 0x00, 0x1F, 0x3F, 0x00, 0x07, 0xE7, 0xF0, 0x01, 0xF8, 0x7F, 0x00,
0x7F, 0x07, 0xF8, 0x3F, 0xC0, 0xFF, 0xFF, 0xF0, 0x07, 0xFF, 0xFC, 0x00,
0x7F, 0xFF, 0x00, 0x07, 0xFF, 0xC0, 0x00, 0x7F, 0xC0, 0x00, 0x0F, 0x00,
0x00, 0x03, 0xFF, 0x87, 0x80, 0xFF, 0xFF, 0xF8, 0x3F, 0xFF, 0xFF, 0x07,
0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0xF0, 0x0F, 0x01, 0xF8, 0x00, 0x7F, 0xFF,
0x80, 0x0F, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xF8, 0x0F, 0xFF, 0xFF, 0xC0,
0x7F, 0xFF, 0xFE, 0x00, 0xF8, 0x07, 0xE0, 0x0F, 0x80, 0x3F, 0x00, 0xF8,
0x01, 0xF0, 0x0F, 0x80, 0x1F, 0x00, 0xF8, 0x01, 0xF0, 0x0F, 0x80, 0x3F,
0x00, 0xF8, 0x0F, 0xE0, 0x0F, 0xFF, 0xFE, 0x00, 0xFF, 0xFF, 0xC0, 0x0F,
0xFF, 0xF0, 0x00, 0xFF, 0xFE, 0x00, 0x0F, 0xFF, 0xF0, 0x00, 0xF8, 0x3F,
0x80, 0x0F, 0x81, 0xFC, 0x00, 0xF8, 0x0F, 0xE0, 0x0F, 0x80, 0x7E, 0x00,
0xF8, 0x03, 0xF0, 0x7F, 0xF0, 0x1F, 0xEF, 0xFF, 0x81, 0xFF, 0xFF, 0xF8,
0x0F, 0xFF, 0xFF, 0x80, 0x7F, 0x7F, 0xF0, 0x07, 0xE0, 0x01, 0xFC, 0x70,
0x1F, 0xFD, 0xE0, 0xFF, 0xFF, 0x87, 0xFF, 0xFE, 0x3F, 0xFF, 0xF8, 0xFC,
0x0F, 0xE7, 0xE0, 0x1F, 0x9F, 0x00, 0x3E, 0x7C, 0x00, 0xF9, 0xF0, 0x01,
0xC7, 0xF0, 0x00, 0x0F, 0xF8, 0x00, 0x3F, 0xFF, 0x00, 0x7F, 0xFF, 0x00,
0xFF, 0xFF, 0x00, 0xFF, 0xFC, 0x00, 0x1F, 0xF8, 0x00, 0x07, 0xE0, 0x00,
0x0F, 0xDC, 0x00, 0x1F, 0xF8, 0x00, 0x7F, 0xE0, 0x01, 0xFF, 0xC0, 0x0F,
0xFF, 0xC0, 0xFE, 0xFF, 0xFF, 0xFB, 0xFF, 0xFF, 0xCF, 0xFF, 0xFE, 0x1C,
0xFF, 0xF0, 0x00, 0xFE, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC1, 0xF0, 0x7F,
0xE0, 0xF8, 0x3F, 0xF0, 0x7C, 0x1F, 0xF8, 0x3E, 0x0F, 0xFC, 0x1F, 0x07,
0xFE, 0x0F, 0x83, 0xEE, 0x07, 0xC0, 0xE0, 0x03, 0xE0, 0x00, 0x01, 0xF0,
0x00, 0x00, 0xF8, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x1F,
0x00, 0x00, 0x0F, 0x80, 0x00, 0x07, 0xC0, 0x00, 0x03, 0xE0, 0x00, 0x01,
0xF0, 0x00, 0x0F, 0xFF, 0x80, 0x0F, 0xFF, 0xE0, 0x07, 0xFF, 0xF0, 0x03,
0xFF, 0xF8, 0x00, 0xFF, 0xF8, 0x00, 0x7F, 0xE0, 0x7F, 0xEF, 0xFF, 0x0F,
0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xFF, 0x0F, 0xFF, 0x7F, 0xE0, 0x7F, 0xE1,
0xF0, 0x00, 0xF8, 0x1F, 0x00, 0x0F, 0x81, 0xF0, 0x00, 0xF8, 0x1F, 0x00,
0x0F, 0x81, 0xF0, 0x00, 0xF8, 0x1F, 0x00, 0x0F, 0x81, 0xF0, 0x00, 0xF8,
0x1F, 0x00, 0x0F, 0x81, 0xF0, 0x00, 0xF8, 0x1F, 0x00, 0x0F, 0x81, 0xF0,
0x00, 0xF8, 0x1F, 0x00, 0x0F, 0x81, 0xF0, 0x00, 0xF8, 0x1F, 0x00, 0x0F,
0x81, 0xF0, 0x00, 0xF8, 0x1F, 0x80, 0x1F, 0x80, 0xF8, 0x01, 0xF0, 0x0F,
0xE0, 0x7F, 0x00, 0x7F, 0xFF, 0xE0, 0x03, 0xFF, 0xFE, 0x00, 0x1F, 0xFF,
0x80, 0x00, 0xFF, 0xF0, 0x00, 0x03, 0xFC, 0x00, 0x7F, 0xE0, 0x1F, 0xFB,
0xFF, 0xC0, 0xFF, 0xFF, 0xFF, 0x03, 0xFF, 0xFF, 0xFC, 0x0F, 0xFF, 0x7F,
0xE0, 0x1F, 0xF8, 0x7C, 0x00, 0x0F, 0x80, 0xF8, 0x00, 0x7C, 0x03, 0xE0,
0x01, 0xF0, 0x07, 0xC0, 0x0F, 0x80, 0x1F, 0x00, 0x3E, 0x00, 0x7E, 0x00,
0xF8, 0x00, 0xF8, 0x07, 0xC0, 0x03, 0xF0, 0x1F, 0x00, 0x07, 0xC0, 0xF8,
0x00, 0x1F, 0x03, 0xE0, 0x00, 0x7E, 0x1F, 0x00, 0x00, 0xF8, 0x7C, 0x00,
0x03, 0xF3, 0xF0, 0x00, 0x07, 0xCF, 0x80, 0x00, 0x1F, 0xBE, 0x00, 0x00,
0x3F, 0xF0, 0x00, 0x00, 0xFF, 0xC0, 0x00, 0x03, 0xFE, 0x00, 0x00, 0x07,
0xF8, 0x00, 0x00, 0x1F, 0xE0, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0xFC,
0x00, 0x00, 0x7F, 0xE0, 0x7F, 0xEF, 0xFF, 0x0F, 0xFF, 0xFF, 0xF0, 0xFF,
0xFF, 0xFF, 0x0F, 0xFF, 0x7F, 0xE0, 0x7F, 0xE3, 0xE0, 0x00, 0x3C, 0x3E,
0x0F, 0x83, 0xC3, 0xE1, 0xF8, 0x3C, 0x3E, 0x1F, 0x87, 0xC3, 0xE1, 0xFC,
0x7C, 0x3E, 0x3F, 0xC7, 0xC1, 0xE3, 0xFC, 0x7C, 0x1F, 0x3F, 0xE7, 0xC1,
0xF7, 0xFE, 0x78, 0x1F, 0x7F, 0xE7, 0x81, 0xF7, 0x9F, 0xF8, 0x1F, 0xF9,
0xFF, 0x81, 0xFF, 0x9F, 0xF8, 0x0F, 0xF9, 0xFF, 0x80, 0xFF, 0x0F, 0xF8,
0x0F, 0xF0, 0xFF, 0x80, 0xFF, 0x0F, 0xF0, 0x0F, 0xE0, 0x7F, 0x00, 0xFE,
0x07, 0xF0, 0x0F, 0xE0, 0x7F, 0x00, 0xFC, 0x03, 0xF0, 0x07, 0xC0, 0x3F,
0x00, 0x7F, 0x80, 0xFF, 0x3F, 0xF0, 0x7F, 0xEF, 0xFC, 0x1F, 0xFB, 0xFF,
0x07, 0xFE, 0x7F, 0x80, 0xFF, 0x07, 0xE0, 0x3F, 0x00, 0xFC, 0x0F, 0x80,
0x1F, 0x87, 0xC0, 0x03, 0xF3, 0xE0, 0x00, 0xFF, 0xF8, 0x00, 0x1F, 0xFC,
0x00, 0x03, 0xFE, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x1F, 0xC0, 0x00, 0x07,
0xF0, 0x00, 0x03, 0xFE, 0x00, 0x01, 0xFF, 0xC0, 0x00, 0xFC, 0xF8, 0x00,
0x7E, 0x3F, 0x00, 0x3F, 0x07, 0xE0, 0x1F, 0x80, 0xFC, 0x07, 0xE0, 0x1F,
0x07, 0xFC, 0x0F, 0xFB, 0xFF, 0x87, 0xFF, 0xFF, 0xE1, 0xFF, 0xFF, 0xF8,
0x7F, 0xF7, 0xFC, 0x0F, 0xF8, 0x7F, 0x80, 0x7F, 0xBF, 0xF0, 0x3F, 0xFF,
0xFC, 0x0F, 0xFF, 0xFF, 0x03, 0xFF, 0x7F, 0x80, 0x7F, 0x87, 0xE0, 0x1F,
0x80, 0xFC, 0x07, 0xC0, 0x1F, 0x03, 0xE0, 0x03, 0xE1, 0xF8, 0x00, 0xFC,
0x7C, 0x00, 0x1F, 0xBE, 0x00, 0x03, 0xFF, 0x80, 0x00, 0x7F, 0xC0, 0x00,
0x1F, 0xE0, 0x00, 0x03, 0xF8, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x1F, 0x00,
0x00, 0x07, 0xC0, 0x00, 0x01, 0xF0, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x1F,
0x00, 0x00, 0x07, 0xC0, 0x00, 0x1F, 0xFF, 0x00, 0x0F, 0xFF, 0xE0, 0x03,
0xFF, 0xF8, 0x00, 0xFF, 0xFE, 0x00, 0x1F, 0xFF, 0x00, 0x7F, 0xFF, 0xF3,
0xFF, 0xFF, 0x9F, 0xFF, 0xFC, 0xFF, 0xFF, 0xE7, 0xFF, 0xFF, 0x3E, 0x03,
0xF1, 0xF0, 0x1F, 0x8F, 0x81, 0xF8, 0x7C, 0x1F, 0x83, 0xE1, 0xF8, 0x0E,
0x1F, 0x80, 0x01, 0xFC, 0x00, 0x0F, 0xC0, 0x00, 0xFC, 0x00, 0x0F, 0xC0,
0x00, 0xFC, 0x00, 0x0F, 0xE0, 0x70, 0x7E, 0x07, 0xC7, 0xE0, 0x3E, 0x7E,
0x01, 0xF7, 0xE0, 0x0F, 0xFF, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xBF, 0xFF, 0xFF,
0xFF, 0xFF, 0xBE, 0x0F, 0x83, 0xE0, 0xF8, 0x3E, 0x0F, 0x83, 0xE0, 0xF8,
0x3E, 0x0F, 0x83, 0xE0, 0xF8, 0x3E, 0x0F, 0x83, 0xE0, 0xF8, 0x3E, 0x0F,
0x83, 0xE0, 0xF8, 0x3E, 0x0F, 0x83, 0xE0, 0xF8, 0x3E, 0x0F, 0x83, 0xE0,
0xFF, 0xBF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x60, 0x00, 0x0F, 0x00, 0x00,
0xF8, 0x00, 0x0F, 0x80, 0x00, 0x7C, 0x00, 0x07, 0xC0, 0x00, 0x7E, 0x00,
0x03, 0xE0, 0x00, 0x3F, 0x00, 0x01, 0xF0, 0x00, 0x1F, 0x00, 0x00, 0xF8,
0x00, 0x0F, 0x80, 0x00, 0x7C, 0x00, 0x07, 0xC0, 0x00, 0x3E, 0x00, 0x03,
0xE0, 0x00, 0x1F, 0x00, 0x01, 0xF0, 0x00, 0x0F, 0x80, 0x00, 0xF8, 0x00,
0x07, 0xC0, 0x00, 0x7C, 0x00, 0x07, 0xE0, 0x00, 0x3E, 0x00, 0x03, 0xF0,
0x00, 0x1F, 0x00, 0x01, 0xF8, 0x00, 0x0F, 0x80, 0x00, 0xF8, 0x00, 0x07,
0xC0, 0x00, 0x7C, 0x00, 0x03, 0xE0, 0x00, 0x3E, 0x00, 0x01, 0xF0, 0x00,
0x1F, 0x00, 0x00, 0xF0, 0x00, 0x0F, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F,
0xC1, 0xF0, 0x7C, 0x1F, 0x07, 0xC1, 0xF0, 0x7C, 0x1F, 0x07, 0xC1, 0xF0,
0x7C, 0x1F, 0x07, 0xC1, 0xF0, 0x7C, 0x1F, 0x07, 0xC1, 0xF0, 0x7C, 0x1F,
0x07, 0xC1, 0xF0, 0x7C, 0x1F, 0x07, 0xC1, 0xF0, 0x7C, 0x1F, 0x7F, 0xFF,
0xFF, 0xFF, 0xFF, 0x7F, 0xC0, 0x00, 0x40, 0x00, 0x06, 0x00, 0x00, 0xF0,
0x00, 0x1F, 0x80, 0x03, 0xFC, 0x00, 0x7F, 0xE0, 0x0F, 0xFF, 0x00, 0xFF,
0xF8, 0x1F, 0x9F, 0x83, 0xF0, 0xFC, 0x7E, 0x07, 0xEF, 0xC0, 0x3F, 0xF8,
0x01, 0xFF, 0x80, 0x0F, 0x70, 0x00, 0x60, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xF0, 0xE0, 0x78, 0x3E, 0x0F, 0xC3, 0xF0, 0x7C, 0x1E, 0x06, 0x01, 0xFF,
0x00, 0x0F, 0xFF, 0xC0, 0x1F, 0xFF, 0xE0, 0x1F, 0xFF, 0xF0, 0x0F, 0xFF,
0xF8, 0x00, 0x01, 0xF8, 0x00, 0x00, 0xF8, 0x00, 0x00, 0xF8, 0x01, 0xFF,
0xF8, 0x07, 0xFF, 0xF8, 0x1F, 0xFF, 0xF8, 0x3F, 0xFF, 0xF8, 0x7F, 0xFF,
0xF8, 0x7F, 0x00, 0xF8, 0xFC, 0x00, 0xF8, 0xF8, 0x00, 0xF8, 0xF8, 0x03,
0xF8, 0xFC, 0x0F, 0xFE, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0x3F, 0xFF,
0xFF, 0x1F, 0xFE, 0xFE, 0x07, 0xF0, 0x00, 0x7F, 0x00, 0x00, 0x1F, 0xE0,
0x00, 0x03, 0xFC, 0x00, 0x00, 0x7F, 0x80, 0x00, 0x07, 0xF0, 0x00, 0x00,
0x3E, 0x00, 0x00, 0x07, 0xC0, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x1F, 0x0F,
0xE0, 0x03, 0xEF, 0xFF, 0x00, 0x7F, 0xFF, 0xF8, 0x0F, 0xFF, 0xFF, 0x81,
0xFF, 0xFF, 0xF8, 0x3F, 0xE0, 0x7F, 0x07, 0xF0, 0x03, 0xF0, 0xFC, 0x00,
0x3E, 0x1F, 0x80, 0x07, 0xE3, 0xE0, 0x00, 0x7C, 0x7C, 0x00, 0x0F, 0x8F,
0x80, 0x01, 0xF1, 0xF0, 0x00, 0x3E, 0x3E, 0x00, 0x07, 0xC7, 0xE0, 0x01,
0xF8, 0xFC, 0x00, 0x3E, 0x1F, 0xC0, 0x0F, 0xCF, 0xFE, 0x07, 0xF3, 0xFF,
0xFF, 0xFE, 0x7F, 0xFF, 0xFF, 0x8F, 0xFF, 0xFF, 0xE0, 0xFE, 0x7F, 0xF0,
0x00, 0x03, 0xF8, 0x00, 0x00, 0xFF, 0x18, 0x03, 0xFF, 0xFC, 0x0F, 0xFF,
0xFC, 0x1F, 0xFF, 0xFC, 0x3F, 0xFF, 0xFC, 0x3F, 0x81, 0xFC, 0x7E, 0x00,
0x7C, 0x7C, 0x00, 0x7C, 0xFC, 0x00, 0x3C, 0xF8, 0x00, 0x38, 0xF8, 0x00,
0x00, 0xF8, 0x00, 0x00, 0xF8, 0x00, 0x00, 0xF8, 0x00, 0x00, 0xFC, 0x00,
0x00, 0x7C, 0x00, 0x06, 0x7E, 0x00, 0x1F, 0x7F, 0x80, 0x7F, 0x3F, 0xFF,
0xFF, 0x1F, 0xFF, 0xFE, 0x0F, 0xFF, 0xFC, 0x07, 0xFF, 0xF8, 0x00, 0xFF,
0xC0, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x7F, 0x80, 0x00, 0x1F, 0xE0, 0x00,
0x07, 0xF8, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x03, 0xE0,
0x00, 0x00, 0xF8, 0x00, 0xFE, 0x3E, 0x00, 0xFF, 0xEF, 0x80, 0xFF, 0xFF,
0xE0, 0x7F, 0xFF, 0xF8, 0x3F, 0xFF, 0xFE, 0x1F, 0xE0, 0xFF, 0x87, 0xE0,
0x0F, 0xE1, 0xF0, 0x01, 0xF8, 0xFC, 0x00, 0x7E, 0x3E, 0x00, 0x0F, 0x8F,
0x80, 0x03, 0xE3, 0xE0, 0x00, 0xF8, 0xF8, 0x00, 0x3E, 0x3E, 0x00, 0x0F,
0x8F, 0xC0, 0x07, 0xE1, 0xF0, 0x01, 0xF8, 0x7E, 0x00, 0xFE, 0x0F, 0xE0,
0x7F, 0xE3, 0xFF, 0xFF, 0xFC, 0x7F, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0xC0,
0xFF, 0xEF, 0xE0, 0x0F, 0xC0, 0x00, 0x00, 0xFE, 0x00, 0x03, 0xFF, 0xC0,
0x0F, 0xFF, 0xE0, 0x1F, 0xFF, 0xF0, 0x3F, 0xFF, 0xF8, 0x7F, 0x81, 0xFC,
0x7E, 0x00, 0x7E, 0xFC, 0x00, 0x3E, 0xF8, 0x00, 0x3E, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xF8, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x7F, 0x80, 0x7E,
0x3F, 0xFF, 0xFF, 0x1F, 0xFF, 0xFF, 0x0F, 0xFF, 0xFE, 0x07, 0xFF, 0xF8,
0x00, 0xFF, 0x80, 0x00, 0x3F, 0xE0, 0x03, 0xFF, 0xE0, 0x1F, 0xFF, 0xC0,
0xFF, 0xFF, 0x07, 0xFF, 0xF8, 0x1F, 0x80, 0x00, 0x7C, 0x00, 0x01, 0xF0,
0x00, 0x07, 0xC0, 0x01, 0xFF, 0xFF, 0x0F, 0xFF, 0xFE, 0x3F, 0xFF, 0xF8,
0xFF, 0xFF, 0xE1, 0xFF, 0xFF, 0x00, 0x7C, 0x00, 0x01, 0xF0, 0x00, 0x07,
0xC0, 0x00, 0x1F, 0x00, 0x00, 0x7C, 0x00, 0x01, 0xF0, 0x00, 0x07, 0xC0,
0x00, 0x1F, 0x00, 0x00, 0x7C, 0x00, 0x01, 0xF0, 0x00, 0x07, 0xC0, 0x01,
0xFF, 0xFF, 0x0F, 0xFF, 0xFE, 0x3F, 0xFF, 0xF8, 0xFF, 0xFF, 0xE1, 0xFF,
0xFF, 0x00, 0x00, 0xFC, 0x00, 0x03, 0xFF, 0xBF, 0x83, 0xFF, 0xFF, 0xE3,
0xFF, 0xFF, 0xF3, 0xFF, 0xFF, 0xFB, 0xFC, 0x3F, 0xF9, 0xF8, 0x07, 0xF0,
0xF8, 0x01, 0xF8, 0xFC, 0x00, 0xFC, 0x7C, 0x00, 0x3E, 0x3E, 0x00, 0x1F,
0x1F, 0x00, 0x0F, 0x8F, 0x80, 0x07, 0xC7, 0xC0, 0x03, 0xE3, 0xF0, 0x03,
0xF0, 0xF8, 0x01, 0xF8, 0x7E, 0x01, 0xFC, 0x3F, 0xC3, 0xFE, 0x0F, 0xFF,
0xFF, 0x03, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xC0, 0x3F, 0xFB, 0xE0, 0x07,
0xF1, 0xF0, 0x00, 0x00, 0xF8, 0x00, 0x00, 0xFC, 0x00, 0x00, 0xFE, 0x00,
0xFF, 0xFE, 0x00, 0xFF, 0xFF, 0x00, 0x7F, 0xFF, 0x00, 0x3F, 0xFE, 0x00,
0x0F, 0xFC, 0x00, 0x7F, 0x00, 0x00, 0x3F, 0xC0, 0x00, 0x0F, 0xF0, 0x00,
0x03, 0xFC, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x07, 0xC0, 0x00, 0x01, 0xF0,
0x00, 0x00, 0x7C, 0x00, 0x00, 0x1F, 0x0F, 0xC0, 0x07, 0xCF, 0xFC, 0x01,
0xF7, 0xFF, 0x80, 0x7F, 0xFF, 0xF0, 0x1F, 0xFF, 0xFC, 0x07, 0xFC, 0x1F,
0x81, 0xFC, 0x03, 0xE0, 0x7E, 0x00, 0xF8, 0x1F, 0x00, 0x3E, 0x07, 0xC0,
0x0F, 0x81, 0xF0, 0x03, 0xE0, 0x7C, 0x00, 0xF8, 0x1F, 0x00, 0x3E, 0x07,
0xC0, 0x0F, 0x81, 0xF0, 0x03, 0xE0, 0x7C, 0x00, 0xF8, 0x1F, 0x00, 0x3E,
0x1F, 0xF0, 0x3F, 0xEF, 0xFE, 0x1F, 0xFF, 0xFF, 0x87, 0xFF, 0xFF, 0xE1,
0xFF, 0xDF, 0xF0, 0x3F, 0xE0, 0x01, 0xF0, 0x00, 0x0F, 0x80, 0x00, 0x7C,
0x00, 0x03, 0xE0, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x1F, 0xF8, 0x01, 0xFF, 0xC0, 0x0F, 0xFE, 0x00, 0x7F, 0xF0,
0x01, 0xFF, 0x80, 0x00, 0x7C, 0x00, 0x03, 0xE0, 0x00, 0x1F, 0x00, 0x00,
0xF8, 0x00, 0x07, 0xC0, 0x00, 0x3E, 0x00, 0x01, 0xF0, 0x00, 0x0F, 0x80,
0x00, 0x7C, 0x00, 0x03, 0xE0, 0x00, 0x1F, 0x00, 0x7F, 0xFF, 0xF7, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0xFF, 0xFF, 0x00, 0x00, 0x7C,
0x00, 0x3E, 0x00, 0x1F, 0x00, 0x0F, 0x80, 0x07, 0xC0, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7,
0xFF, 0xF8, 0x00, 0x7C, 0x00, 0x3E, 0x00, 0x1F, 0x00, 0x0F, 0x80, 0x07,
0xC0, 0x03, 0xE0, 0x01, 0xF0, 0x00, 0xF8, 0x00, 0x7C, 0x00, 0x3E, 0x00,
0x1F, 0x00, 0x0F, 0x80, 0x07, 0xC0, 0x03, 0xE0, 0x01, 0xF0, 0x00, 0xF8,
0x00, 0x7C, 0x00, 0x3E, 0x00, 0x3F, 0x00, 0x3F, 0xBF, 0xFF, 0xBF, 0xFF,
0x9F, 0xFF, 0xCF, 0xFF, 0x83, 0xFF, 0x00, 0x7F, 0x00, 0x00, 0x7F, 0x80,
0x00, 0x3F, 0xC0, 0x00, 0x1F, 0xE0, 0x00, 0x07, 0xF0, 0x00, 0x00, 0xF8,
0x00, 0x00, 0x7C, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x0F,
0x87, 0xFC, 0x07, 0xC7, 0xFF, 0x03, 0xE3, 0xFF, 0x81, 0xF1, 0xFF, 0xC0,
0xF8, 0x7F, 0xC0, 0x7C, 0xFE, 0x00, 0x3E, 0xFE, 0x00, 0x1F, 0xFE, 0x00,
0x0F, 0xFE, 0x00, 0x07, 0xFE, 0x00, 0x03, 0xFF, 0x80, 0x01, 0xFF, 0xE0,
0x00, 0xFF, 0xF8, 0x00, 0x7C, 0xFE, 0x00, 0x3E, 0x3F, 0x80, 0x1F, 0x0F,
0xE0, 0x3F, 0x81, 0xFF, 0xBF, 0xC1, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xF0,
0x7F, 0xFB, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x01, 0xFF, 0xC0, 0x0F, 0xFE,
0x00, 0x7F, 0xF0, 0x01, 0xFF, 0x80, 0x00, 0x7C, 0x00, 0x03, 0xE0, 0x00,
0x1F, 0x00, 0x00, 0xF8, 0x00, 0x07, 0xC0, 0x00, 0x3E, 0x00, 0x01, 0xF0,
0x00, 0x0F, 0x80, 0x00, 0x7C, 0x00, 0x03, 0xE0, 0x00, 0x1F, 0x00, 0x00,
0xF8, 0x00, 0x07, 0xC0, 0x00, 0x3E, 0x00, 0x01, 0xF0, 0x00, 0x0F, 0x80,
0x00, 0x7C, 0x00, 0x03, 0xE0, 0x00, 0x1F, 0x00, 0x00, 0xF8, 0x03, 0xFF,
0xFF, 0xBF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBF, 0xFF, 0xF8,
0x00, 0x3C, 0x1F, 0x00, 0xFD, 0xFC, 0xFF, 0x07, 0xFF, 0xFF, 0xFE, 0x1F,
0xFF, 0xFF, 0xF8, 0x7F, 0xFF, 0xFF, 0xF0, 0xFF, 0x1F, 0x87, 0xC1, 0xF8,
0x7E, 0x1F, 0x07, 0xC1, 0xF0, 0x7C, 0x1F, 0x07, 0xC1, 0xF0, 0x7C, 0x1F,
0x07, 0xC1, 0xF0, 0x7C, 0x1F, 0x07, 0xC1, 0xF0, 0x7C, 0x1F, 0x07, 0xC1,
0xF0, 0x7C, 0x1F, 0x07, 0xC1, 0xF0, 0x7C, 0x1F, 0x07, 0xC1, 0xF0, 0x7C,
0x1F, 0x07, 0xC1, 0xF1, 0xFE, 0x1F, 0x87, 0xEF, 0xFC, 0x7F, 0x1F, 0xFF,
0xF1, 0xFC, 0x7F, 0xFF, 0xC7, 0xF1, 0xFD, 0xFE, 0x1F, 0x87, 0xE0, 0x00,
0x1F, 0x80, 0x1F, 0x9F, 0xF8, 0x1F, 0xDF, 0xFE, 0x0F, 0xFF, 0xFF, 0x87,
0xFF, 0xFF, 0xC1, 0xFF, 0x07, 0xF0, 0x7F, 0x01, 0xF8, 0x3F, 0x00, 0x7C,
0x1F, 0x00, 0x3E, 0x0F, 0x80, 0x1F, 0x07, 0xC0, 0x0F, 0x83, 0xE0, 0x07,
0xC1, 0xF0, 0x03, 0xE0, 0xF8, 0x01, 0xF0, 0x7C, 0x00, 0xF8, 0x3E, 0x00,
0x7C, 0x1F, 0x00, 0x3E, 0x3F, 0xE0, 0x7F, 0xBF, 0xF8, 0x7F, 0xFF, 0xFC,
0x3F, 0xFF, 0xFE, 0x1F, 0xFB, 0xFE, 0x07, 0xF8, 0x00, 0x7F, 0x00, 0x01,
0xFF, 0xF0, 0x01, 0xFF, 0xFC, 0x03, 0xFF, 0xFF, 0x83, 0xFF, 0xFF, 0xC1,
0xFE, 0x0F, 0xF1, 0xFC, 0x01, 0xFC, 0xFC, 0x00, 0x7E, 0xFC, 0x00, 0x1F,
0xFC, 0x00, 0x07, 0xFE, 0x00, 0x03, 0xFF, 0x00, 0x01, 0xFF, 0x80, 0x00,
0xFF, 0xC0, 0x00, 0x7F, 0xF0, 0x00, 0x7E, 0xF8, 0x00, 0x7E, 0x7F, 0x00,
0x7F, 0x1F, 0xC0, 0xFF, 0x07, 0xFF, 0xFF, 0x03, 0xFF, 0xFF, 0x80, 0x7F,
0xFF, 0x00, 0x1F, 0xFF, 0x00, 0x01, 0xFC, 0x00, 0x00, 0x07, 0xE0, 0x03,
0xF9, 0xFF, 0xC0, 0x7F, 0xBF, 0xFE, 0x07, 0xFF, 0xFF, 0xF8, 0x7F, 0xFF,
0xFF, 0xC3, 0xFF, 0x83, 0xFC, 0x0F, 0xE0, 0x0F, 0xE0, 0xFC, 0x00, 0x7E,
0x0F, 0xC0, 0x03, 0xF0, 0xF8, 0x00, 0x1F, 0x0F, 0x80, 0x01, 0xF0, 0xF8,
0x00, 0x1F, 0x0F, 0x80, 0x01, 0xF0, 0xF8, 0x00, 0x3F, 0x0F, 0xC0, 0x03,
0xF0, 0xFE, 0x00, 0x7E, 0x0F, 0xF8, 0x1F, 0xE0, 0xFF, 0xFF, 0xFC, 0x0F,
0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xF0, 0x0F, 0x9F, 0xFC, 0x00, 0xF8, 0x7F,
0x00, 0x0F, 0x80, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x00,
0xF8, 0x00, 0x00, 0x7F, 0xF8, 0x00, 0x0F, 0xFF, 0xC0, 0x00, 0xFF, 0xFC,
0x00, 0x0F, 0xFF, 0xC0, 0x00, 0x7F, 0xF8, 0x00, 0x00, 0x00, 0x7E, 0x00,
0x00, 0x3F, 0xF9, 0xFC, 0x0F, 0xFF, 0xDF, 0xE1, 0xFF, 0xFF, 0xFE, 0x3F,
0xFF, 0xFF, 0xE3, 0xF8, 0x1F, 0xFC, 0x7F, 0x00, 0x7F, 0x07, 0xC0, 0x03,
0xF0, 0xFC, 0x00, 0x3F, 0x0F, 0x80, 0x01, 0xF0, 0xF8, 0x00, 0x1F, 0x0F,
0x80, 0x01, 0xF0, 0xF8, 0x00, 0x1F, 0x0F, 0xC0, 0x01, 0xF0, 0xFC, 0x00,
0x3F, 0x07, 0xE0, 0x07, 0xF0, 0x7F, 0x81, 0xFF, 0x03, 0xFF, 0xFF, 0xF0,
0x1F, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xF0, 0x03, 0xFF, 0x9F, 0x00, 0x0F,
0xE1, 0xF0, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x01, 0xF0, 0x00, 0x00, 0x1F,
0x00, 0x00, 0x01, 0xF0, 0x00, 0x01, 0xFF, 0xE0, 0x00, 0x3F, 0xFF, 0x00,
0x03, 0xFF, 0xF0, 0x00, 0x3F, 0xFF, 0x00, 0x01, 0xFF, 0xE0, 0x00, 0x01,
0xF0, 0x3F, 0xC7, 0xFC, 0x7F, 0xCF, 0xFE, 0x7F, 0xDF, 0xFF, 0x7F, 0xFF,
0xFF, 0x3F, 0xFF, 0x0E, 0x07, 0xFC, 0x00, 0x07, 0xF8, 0x00, 0x07, 0xF0,
0x00, 0x07, 0xE0, 0x00, 0x07, 0xC0, 0x00, 0x07, 0xC0, 0x00, 0x07, 0xC0,
0x00, 0x07, 0xC0, 0x00, 0x07, 0xC0, 0x00, 0x07, 0xC0, 0x00, 0x07, 0xC0,
0x00, 0x7F, 0xFF, 0xC0, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF,
0xE0, 0x7F, 0xFF, 0xC0, 0x03, 0xFC, 0x60, 0x7F, 0xFF, 0x87, 0xFF, 0xFC,
0x7F, 0xFF, 0xE7, 0xFF, 0xFF, 0x3F, 0x01, 0xF9, 0xF0, 0x07, 0xCF, 0xC0,
0x1C, 0x7F, 0xF0, 0x03, 0xFF, 0xF8, 0x0F, 0xFF, 0xF0, 0x3F, 0xFF, 0xC0,
0x3F, 0xFF, 0x00, 0x0F, 0xFD, 0xC0, 0x07, 0xFE, 0x00, 0x1F, 0xF8, 0x00,
0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xFD, 0xFF, 0xFF, 0xEF, 0xFF, 0xFE, 0x3F,
0xFF, 0xC0, 0x07, 0xF8, 0x00, 0x07, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x3E,
0x00, 0x00, 0x7C, 0x00, 0x00, 0xF8, 0x00, 0x01, 0xF0, 0x00, 0x1F, 0xFF,
0xF8, 0x7F, 0xFF, 0xF8, 0xFF, 0xFF, 0xF1, 0xFF, 0xFF, 0xE1, 0xFF, 0xFF,
0x80, 0x7C, 0x00, 0x00, 0xF8, 0x00, 0x01, 0xF0, 0x00, 0x03, 0xE0, 0x00,
0x07, 0xC0, 0x00, 0x0F, 0x80, 0x00, 0x1F, 0x00, 0x00, 0x3E, 0x00, 0x00,
0x7C, 0x00, 0x00, 0xF8, 0x00, 0x01, 0xF0, 0x03, 0x83, 0xF0, 0x1F, 0x87,
0xFF, 0xFF, 0x07, 0xFF, 0xFE, 0x0F, 0xFF, 0xF8, 0x07, 0xFF, 0xC0, 0x03,
0xFC, 0x00, 0x7F, 0x01, 0xFE, 0x7F, 0x81, 0xFF, 0x3F, 0xC0, 0xFF, 0x9F,
0xE0, 0x7F, 0xC7, 0xF0, 0x1F, 0xE0, 0xF8, 0x01, 0xF0, 0x7C, 0x00, 0xF8,
0x3E, 0x00, 0x7C, 0x1F, 0x00, 0x3E, 0x0F, 0x80, 0x1F, 0x07, 0xC0, 0x0F,
0x83, 0xE0, 0x07, 0xC1, 0xF0, 0x03, 0xE0, 0xF8, 0x01, 0xF0, 0x7C, 0x01,
0xF8, 0x3F, 0x01, 0xFC, 0x1F, 0xC1, 0xFF, 0x07, 0xFF, 0xFF, 0xC3, 0xFF,
0xFF, 0xE0, 0xFF, 0xF7, 0xF0, 0x3F, 0xF3, 0xF0, 0x03, 0xF0, 0x00, 0x7F,
0xE0, 0x7F, 0xEF, 0xFF, 0x0F, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xFF, 0x0F,
0xFF, 0x7F, 0xE0, 0x7F, 0xE0, 0xF8, 0x01, 0xF0, 0x0F, 0xC0, 0x1F, 0x00,
0x7C, 0x03, 0xE0, 0x07, 0xE0, 0x3E, 0x00, 0x3E, 0x07, 0xC0, 0x03, 0xF0,
0x7C, 0x00, 0x1F, 0x0F, 0x80, 0x01, 0xF8, 0xF8, 0x00, 0x0F, 0x9F, 0x00,
0x00, 0xFD, 0xF0, 0x00, 0x07, 0xFE, 0x00, 0x00, 0x7F, 0xE0, 0x00, 0x03,
0xFC, 0x00, 0x00, 0x3F, 0xC0, 0x00, 0x01, 0xFC, 0x00, 0x00, 0x1F, 0x80,
0x00, 0x7F, 0x80, 0x1F, 0xEF, 0xFC, 0x03, 0xFF, 0xFF, 0xC0, 0x3F, 0xFF,
0xFC, 0x03, 0xFF, 0x7F, 0x80, 0x1F, 0xE1, 0xF0, 0xF8, 0x7C, 0x1F, 0x1F,
0x87, 0xC1, 0xF1, 0xF8, 0xFC, 0x1F, 0x1F, 0xCF, 0x80, 0xFB, 0xFC, 0xF8,
0x0F, 0xBF, 0xDF, 0x80, 0xFB, 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, 0x00, 0x7F,
0xDF, 0xF0, 0x07, 0xF9, 0xFF, 0x00, 0x7F, 0x9F, 0xE0, 0x07, 0xF0, 0xFE,
0x00, 0x3F, 0x0F, 0xE0, 0x03, 0xF0, 0x7E, 0x00, 0x3E, 0x07, 0xC0, 0x03,
0xE0, 0x3C, 0x00, 0x3F, 0xC0, 0xFF, 0x1F, 0xF8, 0x7F, 0xE7, 0xFE, 0x1F,
0xF9, 0xFF, 0x87, 0xFE, 0x3F, 0xC0, 0xFF, 0x03, 0xF8, 0x7F, 0x00, 0x7F,
0x3F, 0x80, 0x0F, 0xFF, 0xC0, 0x01, 0xFF, 0xE0, 0x00, 0x3F, 0xE0, 0x00,
0x07, 0xF8, 0x00, 0x07, 0xFF, 0x00, 0x03, 0xFF, 0xE0, 0x01, 0xFF, 0xFE,
0x00, 0xFE, 0x1F, 0xC0, 0x7F, 0x03, 0xF8, 0x7F, 0xC0, 0xFF, 0xBF, 0xF8,
0x7F, 0xFF, 0xFE, 0x1F, 0xFF, 0xFF, 0x87, 0xFF, 0x7F, 0xC0, 0xFF, 0x80,
0x7F, 0x80, 0x7F, 0xBF, 0xF0, 0x3F, 0xFF, 0xFC, 0x0F, 0xFF, 0xFF, 0x03,
0xFF, 0x7F, 0x80, 0x7F, 0x8F, 0xC0, 0x07, 0x81, 0xF0, 0x03, 0xE0, 0x7E,
0x01, 0xF0, 0x0F, 0x80, 0x7C, 0x03, 0xF0, 0x3E, 0x00, 0x7C, 0x0F, 0x80,
0x0F, 0x87, 0xC0, 0x03, 0xE1, 0xF0, 0x00, 0x7C, 0xF8, 0x00, 0x1F, 0xFE,
0x00, 0x03, 0xFF, 0x00, 0x00, 0xFF, 0xC0, 0x00, 0x1F, 0xE0, 0x00, 0x07,
0xF0, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x1F, 0x80, 0x00,
0x07, 0xC0, 0x00, 0x03, 0xF0, 0x00, 0x00, 0xF8, 0x00, 0x1F, 0xFF, 0x80,
0x0F, 0xFF, 0xF0, 0x03, 0xFF, 0xFC, 0x00, 0xFF, 0xFF, 0x00, 0x1F, 0xFF,
0x80, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xF0, 0x3F, 0xBE, 0x0F, 0xC3, 0x83, 0xF0, 0x00, 0xFC, 0x00,
0x3F, 0x00, 0x0F, 0xC0, 0x03, 0xF0, 0x00, 0xFC, 0x00, 0x3F, 0x00, 0x0F,
0xC0, 0x3B, 0xF0, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x78, 0x03, 0xF0, 0x1F, 0xC0, 0xFF, 0x07,
0xF8, 0x1F, 0x80, 0x7C, 0x01, 0xF0, 0x07, 0xC0, 0x1F, 0x00, 0x7C, 0x01,
0xF0, 0x07, 0xC0, 0x1F, 0x00, 0x7C, 0x01, 0xF0, 0x0F, 0x81, 0xFE, 0x0F,
0xF0, 0x3F, 0x80, 0xFF, 0x01, 0xFE, 0x00, 0xFC, 0x01, 0xF0, 0x07, 0xC0,
0x1F, 0x00, 0x7C, 0x01, 0xF0, 0x07, 0xC0, 0x1F, 0x00, 0x7C, 0x01, 0xF8,
0x07, 0xF8, 0x0F, 0xF0, 0x3F, 0xC0, 0x7F, 0x00, 0x78, 0x77, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xE0, 0x78, 0x03, 0xF0, 0x0F,
0xE0, 0x3F, 0xC0, 0x7F, 0x00, 0x7E, 0x00, 0xF8, 0x03, 0xE0, 0x0F, 0x80,
0x3E, 0x00, 0xF8, 0x03, 0xE0, 0x0F, 0x80, 0x3E, 0x00, 0xF8, 0x03, 0xE0,
0x07, 0xC0, 0x1F, 0xE0, 0x3F, 0xC0, 0x7F, 0x03, 0xFC, 0x1F, 0xE0, 0xFC,
0x03, 0xE0, 0x0F, 0x80, 0x3E, 0x00, 0xF8, 0x03, 0xE0, 0x0F, 0x80, 0x3E,
0x00, 0xF8, 0x07, 0xE0, 0x7F, 0x83, 0xFC, 0x0F, 0xF0, 0x3F, 0x80, 0x78,
0x00, 0x07, 0x80, 0x00, 0x7F, 0x80, 0x03, 0xFF, 0x03, 0x9F, 0xFE, 0x1F,
0xFF, 0xFC, 0xFF, 0xF3, 0xFF, 0xFF, 0x87, 0xFF, 0x9C, 0x0F, 0xFC, 0x00,
0x0F, 0xE0, 0x00, 0x1F, 0x00};
const GFXglyph FreeMonoBold24pt7bGlyphs[] PROGMEM = {
{0, 0, 0, 28, 0, 1}, // 0x20 ' '
{0, 7, 31, 28, 10, -29}, // 0x21 '!'
{28, 15, 14, 28, 6, -28}, // 0x22 '"'
{55, 22, 34, 28, 3, -30}, // 0x23 '#'
{149, 19, 38, 28, 5, -31}, // 0x24 '$'
{240, 21, 30, 28, 4, -28}, // 0x25 '%'
{319, 21, 28, 28, 4, -26}, // 0x26 '&'
{393, 6, 14, 28, 11, -28}, // 0x27 '''
{404, 10, 37, 28, 12, -29}, // 0x28 '('
{451, 10, 37, 28, 6, -29}, // 0x29 ')'
{498, 21, 19, 28, 4, -28}, // 0x2A '*'
{548, 23, 26, 28, 3, -25}, // 0x2B '+'
{623, 9, 14, 28, 7, -6}, // 0x2C ','
{639, 24, 5, 28, 2, -15}, // 0x2D '-'
{654, 7, 6, 28, 11, -4}, // 0x2E '.'
{660, 20, 38, 28, 4, -32}, // 0x2F '/'
{755, 21, 31, 28, 4, -29}, // 0x30 '0'
{837, 20, 29, 28, 4, -28}, // 0x31 '1'
{910, 21, 30, 28, 3, -29}, // 0x32 '2'
{989, 21, 31, 28, 4, -29}, // 0x33 '3'
{1071, 20, 28, 28, 4, -27}, // 0x34 '4'
{1141, 21, 31, 28, 4, -29}, // 0x35 '5'
{1223, 20, 31, 28, 5, -29}, // 0x36 '6'
{1301, 20, 30, 28, 4, -29}, // 0x37 '7'
{1376, 20, 31, 28, 4, -29}, // 0x38 '8'
{1454, 20, 31, 28, 5, -29}, // 0x39 '9'
{1532, 7, 22, 28, 11, -20}, // 0x3A ':'
{1552, 10, 28, 28, 6, -20}, // 0x3B ';'
{1587, 24, 21, 28, 2, -23}, // 0x3C '<'
{1650, 24, 14, 28, 2, -19}, // 0x3D '='
{1692, 23, 22, 28, 3, -23}, // 0x3E '>'
{1756, 20, 29, 28, 5, -27}, // 0x3F '?'
{1829, 19, 36, 28, 4, -28}, // 0x40 '@'
{1915, 29, 27, 28, -1, -26}, // 0x41 'A'
{2013, 26, 27, 28, 1, -26}, // 0x42 'B'
{2101, 25, 29, 28, 2, -27}, // 0x43 'C'
{2192, 25, 27, 28, 1, -26}, // 0x44 'D'
{2277, 25, 27, 28, 1, -26}, // 0x45 'E'
{2362, 25, 27, 28, 1, -26}, // 0x46 'F'
{2447, 25, 29, 28, 2, -27}, // 0x47 'G'
{2538, 26, 27, 28, 1, -26}, // 0x48 'H'
{2626, 19, 27, 28, 5, -26}, // 0x49 'I'
{2691, 25, 28, 28, 3, -26}, // 0x4A 'J'
{2779, 27, 27, 28, 1, -26}, // 0x4B 'K'
{2871, 25, 27, 28, 2, -26}, // 0x4C 'L'
{2956, 31, 27, 28, -1, -26}, // 0x4D 'M'
{3061, 28, 27, 28, 0, -26}, // 0x4E 'N'
{3156, 27, 29, 28, 1, -27}, // 0x4F 'O'
{3254, 24, 27, 28, 1, -26}, // 0x50 'P'
{3335, 27, 35, 28, 1, -27}, // 0x51 'Q'
{3454, 28, 27, 28, 0, -26}, // 0x52 'R'
{3549, 22, 29, 28, 3, -27}, // 0x53 'S'
{3629, 25, 27, 28, 2, -26}, // 0x54 'T'
{3714, 28, 28, 28, 0, -26}, // 0x55 'U'
{3812, 30, 27, 28, -1, -26}, // 0x56 'V'
{3914, 28, 27, 28, 0, -26}, // 0x57 'W'
{4009, 26, 27, 28, 1, -26}, // 0x58 'X'
{4097, 26, 27, 28, 1, -26}, // 0x59 'Y'
{4185, 21, 27, 28, 4, -26}, // 0x5A 'Z'
{4256, 10, 37, 28, 12, -29}, // 0x5B '['
{4303, 20, 38, 28, 4, -32}, // 0x5C '\'
{4398, 10, 37, 28, 6, -29}, // 0x5D ']'
{4445, 20, 15, 28, 4, -29}, // 0x5E '^'
{4483, 28, 5, 28, 0, 5}, // 0x5F '_'
{4501, 9, 8, 28, 8, -30}, // 0x60 '`'
{4510, 24, 23, 28, 2, -21}, // 0x61 'a'
{4579, 27, 31, 28, 0, -29}, // 0x62 'b'
{4684, 24, 23, 28, 3, -21}, // 0x63 'c'
{4753, 26, 31, 28, 2, -29}, // 0x64 'd'
{4854, 24, 23, 28, 2, -21}, // 0x65 'e'
{4923, 22, 30, 28, 4, -29}, // 0x66 'f'
{5006, 25, 31, 28, 2, -21}, // 0x67 'g'
{5103, 26, 30, 28, 1, -29}, // 0x68 'h'
{5201, 21, 29, 28, 4, -28}, // 0x69 'i'
{5278, 17, 38, 28, 5, -28}, // 0x6A 'j'
{5359, 25, 30, 28, 2, -29}, // 0x6B 'k'
{5453, 21, 30, 28, 4, -29}, // 0x6C 'l'
{5532, 30, 22, 28, -1, -21}, // 0x6D 'm'
{5615, 25, 22, 28, 1, -21}, // 0x6E 'n'
{5684, 25, 23, 28, 2, -21}, // 0x6F 'o'
{5756, 28, 31, 28, 0, -21}, // 0x70 'p'
{5865, 28, 31, 28, 1, -21}, // 0x71 'q'
{5974, 24, 22, 28, 3, -21}, // 0x72 'r'
{6040, 21, 23, 28, 4, -21}, // 0x73 's'
{6101, 23, 28, 28, 1, -26}, // 0x74 't'
{6182, 25, 22, 28, 1, -20}, // 0x75 'u'
{6251, 28, 21, 28, 0, -20}, // 0x76 'v'
{6325, 28, 21, 28, 0, -20}, // 0x77 'w'
{6399, 26, 21, 28, 1, -20}, // 0x78 'x'
{6468, 26, 30, 28, 1, -20}, // 0x79 'y'
{6566, 19, 21, 28, 5, -20}, // 0x7A 'z'
{6616, 14, 37, 28, 7, -29}, // 0x7B '{'
{6681, 5, 36, 28, 12, -28}, // 0x7C '|'
{6704, 14, 37, 28, 8, -29}, // 0x7D '}'
{6769, 22, 10, 28, 3, -17}}; // 0x7E '~'
const GFXfont FreeMonoBold24pt7b PROGMEM = {
(uint8_t *)FreeMonoBold24pt7bBitmaps, (GFXglyph *)FreeMonoBold24pt7bGlyphs,
0x20, 0x7E, 47};
// Approx. 7469 bytes

View File

@@ -0,0 +1,191 @@
#pragma once
#include <Adafruit_GFX.h>
const uint8_t FreeMonoBold9pt7bBitmaps[] PROGMEM = {
0xFF, 0xFF, 0xD2, 0x1F, 0x80, 0xEC, 0x89, 0x12, 0x24, 0x40, 0x36, 0x36,
0x36, 0x7F, 0x7F, 0x36, 0xFF, 0xFF, 0x3C, 0x3C, 0x3C, 0x00, 0x18, 0xFF,
0xFE, 0x3C, 0x1F, 0x1F, 0x83, 0x46, 0x8D, 0xF0, 0xC1, 0x83, 0x00, 0x61,
0x22, 0x44, 0x86, 0x67, 0x37, 0x11, 0x22, 0x4C, 0x70, 0x3C, 0x7E, 0x60,
0x60, 0x30, 0x7B, 0xDF, 0xCE, 0xFF, 0x7F, 0xC9, 0x24, 0x37, 0x66, 0xCC,
0xCC, 0xCC, 0x66, 0x31, 0xCE, 0x66, 0x33, 0x33, 0x33, 0x66, 0xC8, 0x18,
0x18, 0xFF, 0xFF, 0x3C, 0x3C, 0x66, 0x18, 0x18, 0x18, 0xFF, 0xFF, 0x18,
0x18, 0x18, 0x18, 0x6B, 0x48, 0xFF, 0xFF, 0xC0, 0xF0, 0x02, 0x0C, 0x18,
0x60, 0xC3, 0x06, 0x0C, 0x30, 0x61, 0x83, 0x0C, 0x18, 0x20, 0x00, 0x38,
0xFB, 0xBE, 0x3C, 0x78, 0xF1, 0xE3, 0xC7, 0xDD, 0xF1, 0xC0, 0x38, 0xF3,
0x60, 0xC1, 0x83, 0x06, 0x0C, 0x18, 0xFD, 0xF8, 0x3C, 0xFE, 0xC7, 0x03,
0x03, 0x06, 0x0C, 0x18, 0x70, 0xE3, 0xFF, 0xFF, 0x7C, 0xFE, 0x03, 0x03,
0x03, 0x1E, 0x1E, 0x07, 0x03, 0x03, 0xFE, 0x7C, 0x1C, 0x38, 0xB1, 0x64,
0xD9, 0xBF, 0xFF, 0x3E, 0x7C, 0x7E, 0x3F, 0x18, 0x0F, 0xC7, 0xF3, 0x1C,
0x06, 0x03, 0xC3, 0xFF, 0x9F, 0x80, 0x0F, 0x3F, 0x30, 0x60, 0x60, 0xDC,
0xFE, 0xE3, 0xC3, 0x63, 0x7E, 0x3C, 0xFF, 0xFF, 0xC3, 0x03, 0x06, 0x06,
0x06, 0x0C, 0x0C, 0x0C, 0x18, 0x38, 0xFB, 0x1E, 0x3C, 0x6F, 0x9F, 0x63,
0xC7, 0x8F, 0xF1, 0xC0, 0x3C, 0x7E, 0xE6, 0xC3, 0xC3, 0xE7, 0x7F, 0x3B,
0x06, 0x0E, 0xFC, 0xF0, 0xF0, 0x0F, 0x6C, 0x00, 0x1A, 0xD2, 0x00, 0x01,
0x83, 0x87, 0x0E, 0x0F, 0x80, 0xE0, 0x1C, 0x03, 0xFF, 0xFF, 0xC0, 0x00,
0x0F, 0xFF, 0xFC, 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0xF9, 0xE3, 0xC1, 0x80,
0x7C, 0xFE, 0xC7, 0x03, 0x0E, 0x1C, 0x00, 0x00, 0x00, 0x30, 0x30, 0x1E,
0x1F, 0x1C, 0xDC, 0x6C, 0x76, 0x7B, 0x6D, 0xB6, 0xDB, 0x6F, 0xF3, 0xFC,
0x06, 0x33, 0xF8, 0x78, 0x3C, 0x07, 0xC0, 0x38, 0x05, 0x81, 0xB0, 0x36,
0x0F, 0xE1, 0xFC, 0x71, 0xDF, 0x7F, 0xEF, 0x80, 0xFF, 0x3F, 0xE6, 0x19,
0x86, 0x7F, 0x1F, 0xE6, 0x1D, 0x83, 0x60, 0xFF, 0xFF, 0xF0, 0x1F, 0xBF,
0xD8, 0xF8, 0x3C, 0x06, 0x03, 0x01, 0x80, 0x61, 0xBF, 0xC7, 0xC0, 0xFE,
0x3F, 0xE6, 0x19, 0x83, 0x60, 0xD8, 0x36, 0x0D, 0x83, 0x61, 0xBF, 0xEF,
0xE0, 0xFF, 0xFF, 0xD8, 0x6D, 0xB7, 0xC3, 0xE1, 0xB0, 0xC3, 0x61, 0xFF,
0xFF, 0xE0, 0xFF, 0xFF, 0xD8, 0x6D, 0xB7, 0xC3, 0xE1, 0xB0, 0xC0, 0x60,
0x7C, 0x3E, 0x00, 0x1F, 0x9F, 0xE6, 0x1B, 0x06, 0xC0, 0x30, 0x0C, 0x7F,
0x1F, 0xE1, 0x9F, 0xE3, 0xF0, 0xF7, 0xFB, 0xD8, 0xCC, 0x66, 0x33, 0xF9,
0xFC, 0xC6, 0x63, 0x7B, 0xFD, 0xE0, 0xFF, 0xF3, 0x0C, 0x30, 0xC3, 0x0C,
0x33, 0xFF, 0xC0, 0x1F, 0xC7, 0xF0, 0x30, 0x0C, 0x03, 0x00, 0xCC, 0x33,
0x0C, 0xC7, 0x3F, 0x87, 0xC0, 0xF7, 0xBD, 0xE6, 0x61, 0xB0, 0x78, 0x1F,
0x06, 0xE1, 0x98, 0x63, 0x3C, 0xFF, 0x3C, 0xFC, 0x7E, 0x0C, 0x06, 0x03,
0x01, 0x80, 0xC6, 0x63, 0x31, 0xFF, 0xFF, 0xE0, 0xE0, 0xFE, 0x3D, 0xC7,
0x3D, 0xE7, 0xBC, 0xD7, 0x9B, 0xB3, 0x76, 0x60, 0xDE, 0x3F, 0xC7, 0x80,
0xE1, 0xFE, 0x3D, 0xE3, 0x3C, 0x66, 0xCC, 0xDD, 0x99, 0xB3, 0x1E, 0x63,
0xDE, 0x3B, 0xC3, 0x00, 0x1F, 0x07, 0xF1, 0xC7, 0x70, 0x7C, 0x07, 0x80,
0xF0, 0x1F, 0x07, 0x71, 0xC7, 0xF0, 0x7C, 0x00, 0xFE, 0x7F, 0x98, 0x6C,
0x36, 0x1B, 0xF9, 0xF8, 0xC0, 0x60, 0x7C, 0x3E, 0x00, 0x1F, 0x07, 0xF1,
0xC7, 0x70, 0x7C, 0x07, 0x80, 0xF0, 0x1F, 0x07, 0x71, 0xC7, 0xF0, 0x7C,
0x0C, 0x33, 0xFE, 0x7F, 0x80, 0xFC, 0x7F, 0x18, 0xCC, 0x66, 0x73, 0xF1,
0xF0, 0xCC, 0x63, 0x7D, 0xFE, 0x60, 0x3F, 0xBF, 0xF0, 0x78, 0x0F, 0x03,
0xF8, 0x3F, 0x83, 0xC3, 0xFF, 0xBF, 0x80, 0xFF, 0xFF, 0xF6, 0x7B, 0x3D,
0x98, 0xC0, 0x60, 0x30, 0x18, 0x3F, 0x1F, 0x80, 0xF1, 0xFE, 0x3D, 0x83,
0x30, 0x66, 0x0C, 0xC1, 0x98, 0x33, 0x06, 0x60, 0xC7, 0xF0, 0x7C, 0x00,
0xFB, 0xFF, 0x7D, 0xC3, 0x18, 0xC3, 0x18, 0x36, 0x06, 0xC0, 0x50, 0x0E,
0x01, 0xC0, 0x10, 0x00, 0xFB, 0xFE, 0xF6, 0x0D, 0x93, 0x6E, 0xDB, 0xB7,
0xAD, 0xEE, 0x7B, 0x8E, 0xE3, 0x18, 0xF3, 0xFC, 0xF7, 0x38, 0xFC, 0x1E,
0x03, 0x01, 0xE0, 0xCC, 0x73, 0xBC, 0xFF, 0x3C, 0xF3, 0xFC, 0xF7, 0x38,
0xCC, 0x1E, 0x07, 0x80, 0xC0, 0x30, 0x0C, 0x0F, 0xC3, 0xF0, 0xFE, 0xFE,
0xC6, 0xCC, 0x18, 0x18, 0x30, 0x63, 0xC3, 0xFF, 0xFF, 0xFF, 0xCC, 0xCC,
0xCC, 0xCC, 0xCC, 0xFF, 0x01, 0x03, 0x06, 0x06, 0x0C, 0x0C, 0x18, 0x18,
0x30, 0x30, 0x60, 0x60, 0xC0, 0x80, 0xFF, 0x33, 0x33, 0x33, 0x33, 0x33,
0xFF, 0x10, 0x71, 0xE3, 0x6C, 0x70, 0x40, 0xFF, 0xFF, 0xFC, 0x88, 0x80,
0x7E, 0x3F, 0x8F, 0xCF, 0xEE, 0x36, 0x1B, 0xFE, 0xFF, 0xE0, 0x38, 0x06,
0x01, 0xBC, 0x7F, 0x9C, 0x76, 0x0D, 0x83, 0x71, 0xFF, 0xEE, 0xF0, 0x3F,
0xBF, 0xF8, 0x78, 0x3C, 0x07, 0x05, 0xFE, 0x7E, 0x03, 0x80, 0xE0, 0x18,
0xF6, 0x7F, 0xB8, 0xEC, 0x1B, 0x06, 0xE3, 0x9F, 0xF3, 0xFC, 0x3E, 0x3F,
0xB0, 0xFF, 0xFF, 0xFE, 0x01, 0xFE, 0x7E, 0x1F, 0x3F, 0x30, 0x7E, 0x7E,
0x30, 0x30, 0x30, 0x30, 0xFE, 0xFE, 0x3F, 0xBF, 0xF9, 0xD8, 0x6C, 0x37,
0x39, 0xFC, 0x76, 0x03, 0x01, 0x8F, 0xC7, 0xC0, 0xE0, 0x70, 0x18, 0x0D,
0xC7, 0xF3, 0x99, 0x8C, 0xC6, 0x63, 0x7B, 0xFD, 0xE0, 0x18, 0x18, 0x00,
0x78, 0x78, 0x18, 0x18, 0x18, 0x18, 0xFF, 0xFF, 0x18, 0x60, 0x3F, 0xFC,
0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0F, 0xFF, 0x80, 0xE0, 0x70, 0x18, 0x0D,
0xE6, 0xF3, 0xE1, 0xE0, 0xF8, 0x6E, 0x73, 0xF9, 0xE0, 0x78, 0x78, 0x18,
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xFF, 0xFF, 0xFD, 0x9F, 0xF9, 0x9B,
0x33, 0x66, 0x6C, 0xCD, 0xBD, 0xFF, 0xBF, 0xEE, 0x7F, 0x98, 0xCC, 0x66,
0x33, 0x1B, 0xDF, 0xEF, 0x3E, 0x3F, 0xB8, 0xF8, 0x3C, 0x1F, 0x1D, 0xFC,
0x7C, 0xEF, 0x1F, 0xF9, 0xC3, 0xB0, 0x36, 0x06, 0xE1, 0xDF, 0xF3, 0x78,
0x60, 0x0C, 0x03, 0xE0, 0x7C, 0x00, 0x1E, 0xEF, 0xFF, 0x87, 0x60, 0x6C,
0x0D, 0xC3, 0x9F, 0xF0, 0xF6, 0x00, 0xC0, 0x18, 0x0F, 0x81, 0xF0, 0x77,
0xBF, 0xCF, 0x06, 0x03, 0x01, 0x83, 0xF9, 0xFC, 0x3F, 0xFF, 0xC3, 0xFC,
0x3F, 0xC3, 0xFF, 0xFC, 0x60, 0x60, 0x60, 0xFE, 0xFE, 0x60, 0x60, 0x60,
0x61, 0x7F, 0x3E, 0xE7, 0x73, 0x98, 0xCC, 0x66, 0x33, 0x19, 0xFE, 0x7F,
0xFB, 0xFF, 0x7C, 0xC6, 0x18, 0xC1, 0xB0, 0x36, 0x03, 0x80, 0x70, 0xF1,
0xFE, 0x3D, 0xBB, 0x37, 0x63, 0xF8, 0x77, 0x0E, 0xE1, 0x8C, 0xF7, 0xFB,
0xCD, 0x83, 0x83, 0xC3, 0xBB, 0xDF, 0xEF, 0xF3, 0xFC, 0xF6, 0x18, 0xCC,
0x33, 0x07, 0x81, 0xE0, 0x30, 0x0C, 0x06, 0x0F, 0xC3, 0xF0, 0xFF, 0xFF,
0x30, 0xC3, 0x0C, 0x7F, 0xFF, 0x37, 0x66, 0x66, 0xCC, 0x66, 0x66, 0x73,
0xFF, 0xFF, 0xFF, 0xF0, 0xCE, 0x66, 0x66, 0x33, 0x66, 0x66, 0xEC, 0x70,
0x7C, 0xF3, 0xC0, 0xC0};
const GFXglyph FreeMonoBold9pt7bGlyphs[] PROGMEM = {
{0, 0, 0, 11, 0, 1}, // 0x20 ' '
{0, 3, 11, 11, 4, -10}, // 0x21 '!'
{5, 7, 5, 11, 2, -10}, // 0x22 '"'
{10, 8, 12, 11, 1, -10}, // 0x23 '#'
{22, 7, 14, 11, 2, -11}, // 0x24 '$'
{35, 7, 11, 11, 2, -10}, // 0x25 '%'
{45, 8, 10, 11, 1, -9}, // 0x26 '&'
{55, 3, 5, 11, 4, -10}, // 0x27 '''
{57, 4, 14, 11, 5, -10}, // 0x28 '('
{64, 4, 14, 11, 2, -10}, // 0x29 ')'
{71, 8, 7, 11, 2, -10}, // 0x2A '*'
{78, 8, 9, 11, 2, -8}, // 0x2B '+'
{87, 3, 5, 11, 3, -1}, // 0x2C ','
{89, 9, 2, 11, 1, -5}, // 0x2D '-'
{92, 2, 2, 11, 4, -1}, // 0x2E '.'
{93, 7, 15, 11, 2, -12}, // 0x2F '/'
{107, 7, 12, 11, 2, -11}, // 0x30 '0'
{118, 7, 11, 11, 2, -10}, // 0x31 '1'
{128, 8, 12, 11, 1, -11}, // 0x32 '2'
{140, 8, 12, 11, 2, -11}, // 0x33 '3'
{152, 7, 10, 11, 2, -9}, // 0x34 '4'
{161, 9, 11, 11, 1, -10}, // 0x35 '5'
{174, 8, 12, 11, 2, -11}, // 0x36 '6'
{186, 8, 11, 11, 1, -10}, // 0x37 '7'
{197, 7, 12, 11, 2, -11}, // 0x38 '8'
{208, 8, 12, 11, 2, -11}, // 0x39 '9'
{220, 2, 8, 11, 4, -7}, // 0x3A ':'
{222, 3, 11, 11, 3, -7}, // 0x3B ';'
{227, 9, 8, 11, 1, -8}, // 0x3C '<'
{236, 9, 6, 11, 1, -7}, // 0x3D '='
{243, 9, 8, 11, 1, -8}, // 0x3E '>'
{252, 8, 11, 11, 2, -10}, // 0x3F '?'
{263, 9, 15, 11, 1, -11}, // 0x40 '@'
{280, 11, 11, 11, 0, -10}, // 0x41 'A'
{296, 10, 11, 11, 1, -10}, // 0x42 'B'
{310, 9, 11, 11, 1, -10}, // 0x43 'C'
{323, 10, 11, 11, 0, -10}, // 0x44 'D'
{337, 9, 11, 11, 1, -10}, // 0x45 'E'
{350, 9, 11, 11, 1, -10}, // 0x46 'F'
{363, 10, 11, 11, 1, -10}, // 0x47 'G'
{377, 9, 11, 11, 1, -10}, // 0x48 'H'
{390, 6, 11, 11, 3, -10}, // 0x49 'I'
{399, 10, 11, 11, 1, -10}, // 0x4A 'J'
{413, 10, 11, 11, 1, -10}, // 0x4B 'K'
{427, 9, 11, 11, 1, -10}, // 0x4C 'L'
{440, 11, 11, 11, 0, -10}, // 0x4D 'M'
{456, 11, 11, 11, 0, -10}, // 0x4E 'N'
{472, 11, 11, 11, 0, -10}, // 0x4F 'O'
{488, 9, 11, 11, 1, -10}, // 0x50 'P'
{501, 11, 14, 11, 0, -10}, // 0x51 'Q'
{521, 9, 11, 11, 1, -10}, // 0x52 'R'
{534, 9, 11, 11, 1, -10}, // 0x53 'S'
{547, 9, 11, 11, 1, -10}, // 0x54 'T'
{560, 11, 11, 11, 0, -10}, // 0x55 'U'
{576, 11, 11, 11, 0, -10}, // 0x56 'V'
{592, 10, 11, 11, 0, -10}, // 0x57 'W'
{606, 10, 11, 11, 0, -10}, // 0x58 'X'
{620, 10, 11, 11, 0, -10}, // 0x59 'Y'
{634, 8, 11, 11, 2, -10}, // 0x5A 'Z'
{645, 4, 14, 11, 5, -10}, // 0x5B '['
{652, 7, 15, 11, 2, -12}, // 0x5C '\'
{666, 4, 14, 11, 2, -10}, // 0x5D ']'
{673, 7, 6, 11, 2, -11}, // 0x5E '^'
{679, 11, 2, 11, 0, 3}, // 0x5F '_'
{682, 3, 3, 11, 3, -11}, // 0x60 '`'
{684, 9, 8, 11, 1, -7}, // 0x61 'a'
{693, 10, 11, 11, 0, -10}, // 0x62 'b'
{707, 9, 8, 11, 1, -7}, // 0x63 'c'
{716, 10, 11, 11, 1, -10}, // 0x64 'd'
{730, 9, 8, 11, 1, -7}, // 0x65 'e'
{739, 8, 11, 11, 2, -10}, // 0x66 'f'
{750, 9, 12, 11, 1, -7}, // 0x67 'g'
{764, 9, 11, 11, 1, -10}, // 0x68 'h'
{777, 8, 11, 11, 2, -10}, // 0x69 'i'
{788, 6, 15, 11, 2, -10}, // 0x6A 'j'
{800, 9, 11, 11, 1, -10}, // 0x6B 'k'
{813, 8, 11, 11, 2, -10}, // 0x6C 'l'
{824, 11, 8, 11, 0, -7}, // 0x6D 'm'
{835, 9, 8, 11, 1, -7}, // 0x6E 'n'
{844, 9, 8, 11, 1, -7}, // 0x6F 'o'
{853, 11, 12, 11, 0, -7}, // 0x70 'p'
{870, 11, 12, 11, 0, -7}, // 0x71 'q'
{887, 9, 8, 11, 1, -7}, // 0x72 'r'
{896, 8, 8, 11, 2, -7}, // 0x73 's'
{904, 8, 11, 11, 1, -10}, // 0x74 't'
{915, 9, 8, 11, 1, -7}, // 0x75 'u'
{924, 11, 8, 11, 0, -7}, // 0x76 'v'
{935, 11, 8, 11, 0, -7}, // 0x77 'w'
{946, 9, 8, 11, 1, -7}, // 0x78 'x'
{955, 10, 12, 11, 0, -7}, // 0x79 'y'
{970, 7, 8, 11, 2, -7}, // 0x7A 'z'
{977, 4, 14, 11, 3, -10}, // 0x7B '{'
{984, 2, 14, 11, 5, -10}, // 0x7C '|'
{988, 4, 14, 11, 4, -10}, // 0x7D '}'
{995, 9, 4, 11, 1, -6}}; // 0x7E '~'
const GFXfont FreeMonoBold9pt7b PROGMEM = {(uint8_t *)FreeMonoBold9pt7bBitmaps,
(GFXglyph *)FreeMonoBold9pt7bGlyphs,
0x20, 0x7E, 18};
// Approx. 1672 bytes

View File

@@ -0,0 +1,271 @@
#pragma once
#include <Adafruit_GFX.h>
const uint8_t FreeMonoBoldOblique12pt7bBitmaps[] PROGMEM = {
0x1C, 0xF3, 0xCE, 0x38, 0xE7, 0x1C, 0x61, 0x86, 0x00, 0x63, 0x8C, 0x00,
0xE7, 0xE7, 0xE6, 0xC6, 0xC6, 0xC4, 0x84, 0x03, 0x30, 0x19, 0x81, 0xDC,
0x0C, 0xE0, 0x66, 0x1F, 0xFC, 0xFF, 0xE1, 0x98, 0x0C, 0xC0, 0xEE, 0x06,
0x70, 0xFF, 0xCF, 0xFE, 0x1D, 0xC0, 0xCC, 0x06, 0x60, 0x77, 0x03, 0x30,
0x00, 0x01, 0x00, 0x70, 0x0C, 0x07, 0xF1, 0xFE, 0x71, 0xCC, 0x11, 0x80,
0x3F, 0x03, 0xF0, 0x0F, 0x20, 0x6E, 0x0D, 0xC3, 0x3F, 0xE7, 0xF8, 0x1C,
0x03, 0x00, 0x60, 0x0C, 0x00, 0x0E, 0x03, 0xE0, 0xC4, 0x10, 0x82, 0x30,
0x7C, 0x07, 0x78, 0x7C, 0x7F, 0x19, 0xF0, 0x62, 0x08, 0x41, 0x18, 0x3E,
0x03, 0x80, 0x07, 0xC1, 0xF8, 0x62, 0x0C, 0x01, 0x80, 0x38, 0x0F, 0x03,
0xF7, 0x6F, 0xD8, 0xF3, 0x1E, 0x7F, 0xE7, 0xF8, 0xFF, 0x6D, 0x20, 0x06,
0x1C, 0x70, 0xC3, 0x06, 0x18, 0x30, 0xC1, 0x83, 0x06, 0x0C, 0x18, 0x30,
0x70, 0x60, 0xC1, 0x00, 0x0C, 0x18, 0x38, 0x30, 0x60, 0xC1, 0x83, 0x06,
0x0C, 0x30, 0x61, 0xC3, 0x0E, 0x38, 0x61, 0xC2, 0x00, 0x06, 0x00, 0xC0,
0x18, 0x3F, 0x7F, 0xFE, 0xFF, 0x07, 0x81, 0xF8, 0x77, 0x0C, 0x60, 0x03,
0x00, 0x70, 0x07, 0x00, 0x60, 0x06, 0x0F, 0xFF, 0xFF, 0xF0, 0xE0, 0x0C,
0x00, 0xC0, 0x0C, 0x01, 0xC0, 0x18, 0x00, 0x1C, 0xE3, 0x1C, 0x63, 0x08,
0x00, 0x7F, 0xFF, 0xFF, 0xC0, 0x7F, 0x00, 0x00, 0x08, 0x00, 0x70, 0x01,
0x80, 0x0E, 0x00, 0x70, 0x03, 0x80, 0x0C, 0x00, 0x70, 0x03, 0x80, 0x0C,
0x00, 0x70, 0x03, 0x80, 0x0C, 0x00, 0x70, 0x03, 0x80, 0x0C, 0x00, 0x70,
0x03, 0x80, 0x0C, 0x00, 0x20, 0x00, 0x07, 0x83, 0xF8, 0xE3, 0x98, 0x37,
0x06, 0xC0, 0xD8, 0x1B, 0x03, 0xE0, 0xF8, 0x1B, 0x03, 0x60, 0xEE, 0x38,
0xFE, 0x0F, 0x00, 0x03, 0xC1, 0xF0, 0x7E, 0x0C, 0xC0, 0x38, 0x07, 0x00,
0xC0, 0x18, 0x07, 0x00, 0xE0, 0x18, 0x03, 0x00, 0x61, 0xFF, 0xFF, 0xF0,
0x03, 0xE0, 0x3F, 0x83, 0x8E, 0x38, 0x31, 0x81, 0x80, 0x18, 0x01, 0xC0,
0x1C, 0x01, 0xC0, 0x38, 0x03, 0x80, 0x38, 0x47, 0x87, 0x3F, 0xF3, 0xFF,
0x80, 0x07, 0xC1, 0xFF, 0x18, 0x70, 0x03, 0x00, 0x30, 0x06, 0x07, 0xC0,
0x7C, 0x00, 0xE0, 0x06, 0x00, 0x60, 0x06, 0xC1, 0xCF, 0xF8, 0x7E, 0x00,
0x01, 0xE0, 0x3C, 0x0F, 0x03, 0x60, 0xCC, 0x3B, 0x8E, 0x63, 0x8C, 0x61,
0x9F, 0xFB, 0xFF, 0x01, 0x81, 0xF8, 0x3F, 0x00, 0x0F, 0xF1, 0xFE, 0x18,
0x01, 0x80, 0x18, 0x03, 0xF8, 0x3F, 0xC3, 0x8E, 0x00, 0x60, 0x06, 0x00,
0x60, 0x0C, 0xC1, 0xCF, 0xF8, 0x7E, 0x00, 0x03, 0xE1, 0xFC, 0x70, 0x1C,
0x03, 0x00, 0xC0, 0x1B, 0xC7, 0xFC, 0xF3, 0x98, 0x33, 0x06, 0x60, 0xCE,
0x30, 0xFC, 0x0F, 0x00, 0xFF, 0xFF, 0xFB, 0x07, 0x60, 0xC0, 0x38, 0x06,
0x01, 0xC0, 0x30, 0x0E, 0x01, 0x80, 0x70, 0x1C, 0x03, 0x80, 0x60, 0x08,
0x00, 0x07, 0x83, 0xF8, 0xE3, 0xB0, 0x36, 0x06, 0xC0, 0xDC, 0x31, 0xFC,
0x3F, 0x8C, 0x3B, 0x03, 0x60, 0x6C, 0x39, 0xFE, 0x1F, 0x00, 0x07, 0x81,
0xF8, 0x63, 0x98, 0x33, 0x06, 0x60, 0xCE, 0x79, 0xFF, 0x1E, 0xC0, 0x18,
0x06, 0x01, 0xC0, 0x71, 0xFC, 0x3E, 0x00, 0x19, 0xCC, 0x00, 0x00, 0x00,
0x67, 0x30, 0x06, 0x1C, 0x30, 0x00, 0x00, 0x00, 0x00, 0x38, 0x71, 0xC3,
0x0E, 0x18, 0x20, 0x00, 0x00, 0x18, 0x03, 0xC0, 0x7C, 0x1F, 0x03, 0xE0,
0x3E, 0x00, 0x7C, 0x01, 0xF0, 0x03, 0xE0, 0x07, 0x80, 0x08, 0x7F, 0xFB,
0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFB, 0xFF, 0xC0, 0x30, 0x01,
0xE0, 0x07, 0xC0, 0x0F, 0x00, 0x3E, 0x00, 0x7C, 0x1F, 0x03, 0xE0, 0x7C,
0x07, 0x80, 0x20, 0x00, 0x3E, 0x7F, 0xB0, 0xF8, 0x30, 0x18, 0x1C, 0x1C,
0x3C, 0x38, 0x18, 0x00, 0x06, 0x07, 0x03, 0x00, 0x03, 0xC0, 0x7E, 0x0C,
0x71, 0x83, 0x30, 0x33, 0x0F, 0x33, 0xE6, 0x76, 0x6C, 0x66, 0xC6, 0x6C,
0x6C, 0xFC, 0xC7, 0xEC, 0x00, 0xC0, 0x0C, 0x00, 0xE3, 0x07, 0xF0, 0x3C,
0x00, 0x07, 0xF0, 0x1F, 0xE0, 0x07, 0xC0, 0x1F, 0x80, 0x3B, 0x00, 0xE7,
0x01, 0x8E, 0x07, 0x1C, 0x1F, 0xF8, 0x3F, 0xF0, 0xE0, 0x71, 0x80, 0xEF,
0xC7, 0xFF, 0x8F, 0xC0, 0x3F, 0xF1, 0xFF, 0xC3, 0x06, 0x38, 0x31, 0xC1,
0x8C, 0x18, 0x7F, 0xC3, 0xFE, 0x38, 0x39, 0xC0, 0xCC, 0x06, 0x60, 0x6F,
0xFF, 0x7F, 0xE0, 0x03, 0xEC, 0x3F, 0xF1, 0xC3, 0x8C, 0x06, 0x60, 0x19,
0x80, 0x0C, 0x00, 0x30, 0x00, 0xC0, 0x03, 0x00, 0x0C, 0x03, 0x3C, 0x1C,
0x7F, 0xE0, 0x7E, 0x00, 0x3F, 0xE1, 0xFF, 0x87, 0x0C, 0x30, 0x31, 0x81,
0x8C, 0x0C, 0xE0, 0x67, 0x03, 0x30, 0x31, 0x81, 0x8C, 0x0C, 0xE1, 0xCF,
0xFC, 0x7F, 0x80, 0x1F, 0xFE, 0x3F, 0xFC, 0x38, 0x38, 0x70, 0x70, 0xCC,
0xC1, 0x98, 0x03, 0xF0, 0x0F, 0xE0, 0x1D, 0x80, 0x31, 0x18, 0x60, 0x70,
0xC0, 0xE7, 0xFF, 0x9F, 0xFF, 0x00, 0x1F, 0xFF, 0x1F, 0xFE, 0x0E, 0x06,
0x0C, 0x0E, 0x0C, 0xC4, 0x0C, 0xC0, 0x1F, 0xC0, 0x1F, 0xC0, 0x19, 0xC0,
0x19, 0x80, 0x18, 0x00, 0x38, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x07, 0xEC,
0x7F, 0xF3, 0x83, 0x9C, 0x06, 0x60, 0x19, 0x80, 0x0C, 0x00, 0x30, 0xFE,
0xC3, 0xFB, 0x01, 0xCC, 0x07, 0x3C, 0x38, 0x7F, 0xE0, 0x7E, 0x00, 0x0F,
0xBF, 0x1F, 0xBE, 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x1C, 0x0C, 0x1C, 0x1F,
0xF8, 0x1F, 0xF8, 0x18, 0x18, 0x18, 0x38, 0x18, 0x38, 0x38, 0x30, 0x7C,
0xFC, 0xFC, 0xF8, 0x3F, 0xF3, 0xFF, 0x03, 0x00, 0x70, 0x07, 0x00, 0x60,
0x06, 0x00, 0x60, 0x0E, 0x00, 0xE0, 0x0E, 0x00, 0xC0, 0xFF, 0xCF, 0xFC,
0x03, 0xFF, 0x03, 0xFF, 0x00, 0x38, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30,
0x00, 0x70, 0x20, 0x70, 0x60, 0x60, 0x60, 0x60, 0x60, 0xE0, 0xE1, 0xC0,
0xFF, 0x80, 0x3F, 0x00, 0x1F, 0x9F, 0x1F, 0x9E, 0x0E, 0x38, 0x0C, 0x70,
0x0C, 0xE0, 0x0F, 0xC0, 0x1F, 0xC0, 0x1F, 0xE0, 0x1C, 0xE0, 0x18, 0x60,
0x18, 0x70, 0x38, 0x70, 0xFE, 0x3C, 0xFC, 0x3C, 0x3F, 0xC1, 0xFE, 0x01,
0x80, 0x1C, 0x00, 0xE0, 0x06, 0x00, 0x30, 0x01, 0x80, 0x1C, 0x18, 0xE0,
0xC6, 0x06, 0x30, 0x7F, 0xFF, 0xFF, 0xF8, 0x1E, 0x07, 0x87, 0x81, 0xE0,
0xF0, 0xF0, 0x7C, 0x7C, 0x1F, 0x1F, 0x06, 0xCF, 0x81, 0xBF, 0x60, 0xEF,
0x98, 0x3B, 0xEE, 0x0C, 0x73, 0x83, 0x1C, 0xC0, 0xC0, 0x30, 0xFC, 0x7E,
0x3F, 0x1F, 0x80, 0x3C, 0x3F, 0x3E, 0x3F, 0x1E, 0x0C, 0x1F, 0x1C, 0x1F,
0x1C, 0x1B, 0x98, 0x3B, 0x98, 0x3B, 0x98, 0x31, 0xF8, 0x31, 0xF8, 0x30,
0xF0, 0x70, 0xF0, 0xFC, 0x70, 0xF8, 0x70, 0x03, 0xE0, 0x3F, 0xE1, 0xC3,
0x8C, 0x07, 0x60, 0x0D, 0x80, 0x3C, 0x00, 0xF0, 0x03, 0xC0, 0x1B, 0x00,
0x6E, 0x03, 0x1C, 0x38, 0x7F, 0xC0, 0x7C, 0x00, 0x3F, 0xE1, 0xFF, 0x83,
0x0E, 0x38, 0x31, 0xC1, 0x8C, 0x0C, 0x60, 0xC3, 0xFC, 0x3F, 0xC1, 0xC0,
0x0C, 0x00, 0x60, 0x0F, 0xF0, 0x7F, 0x80, 0x03, 0xE0, 0x3F, 0xE1, 0xC3,
0x8C, 0x07, 0x60, 0x0D, 0x80, 0x3C, 0x00, 0xF0, 0x03, 0xC0, 0x1B, 0x00,
0x6E, 0x03, 0x1C, 0x38, 0x7F, 0xC0, 0xFC, 0x03, 0x02, 0x1F, 0xFC, 0xFF,
0xE0, 0x1F, 0xF0, 0x3F, 0xF0, 0x38, 0x70, 0x60, 0x60, 0xC0, 0xC1, 0x87,
0x07, 0xFC, 0x0F, 0xF0, 0x18, 0xF0, 0x30, 0xE0, 0x60, 0xC1, 0xC1, 0xCF,
0xE1, 0xFF, 0xC3, 0xC0, 0x0F, 0xB1, 0xFF, 0x30, 0xE6, 0x06, 0x60, 0x67,
0x80, 0x7F, 0x01, 0xFC, 0x01, 0xC4, 0x0C, 0xC0, 0xCE, 0x18, 0xFF, 0x8B,
0xE0, 0x7F, 0xFB, 0xFF, 0xD9, 0xCF, 0xCE, 0x7C, 0x63, 0x63, 0x18, 0x18,
0x01, 0xC0, 0x0E, 0x00, 0x60, 0x03, 0x00, 0x18, 0x0F, 0xF8, 0x7F, 0xC0,
0x7E, 0xFF, 0xF3, 0xF3, 0x03, 0x1C, 0x0C, 0x60, 0x31, 0x81, 0xC6, 0x06,
0x38, 0x18, 0xE0, 0x63, 0x03, 0x8C, 0x0C, 0x30, 0x70, 0x7F, 0x80, 0xF8,
0x00, 0xFC, 0x7F, 0xF8, 0xFD, 0xC0, 0x61, 0x81, 0xC3, 0x87, 0x07, 0x0C,
0x0E, 0x38, 0x0C, 0x60, 0x19, 0xC0, 0x3F, 0x00, 0x7C, 0x00, 0xF8, 0x00,
0xE0, 0x01, 0x80, 0x00, 0x7E, 0x7E, 0xFC, 0xFD, 0xC0, 0x73, 0x9C, 0xE7,
0x79, 0x8E, 0xF7, 0x1B, 0xEE, 0x36, 0xD8, 0x7D, 0xF0, 0xF3, 0xE1, 0xE7,
0x83, 0x8F, 0x07, 0x1E, 0x1C, 0x38, 0x00, 0x1F, 0x1F, 0x1F, 0x1F, 0x0E,
0x1C, 0x07, 0x38, 0x07, 0x70, 0x03, 0xE0, 0x03, 0xC0, 0x03, 0xC0, 0x07,
0xE0, 0x0E, 0xE0, 0x1C, 0x70, 0x38, 0x70, 0xFC, 0xFC, 0xFC, 0xFC, 0xF8,
0xFF, 0xC7, 0xCC, 0x38, 0x73, 0x83, 0x9C, 0x0F, 0xC0, 0x7C, 0x01, 0xC0,
0x0C, 0x00, 0x60, 0x03, 0x00, 0x38, 0x0F, 0xF8, 0x7F, 0x80, 0x0F, 0xF8,
0x7F, 0xE1, 0xC7, 0x86, 0x1C, 0x18, 0xE0, 0x07, 0x00, 0x38, 0x01, 0xC0,
0x0E, 0x00, 0x70, 0xC3, 0x83, 0x1C, 0x1C, 0x7F, 0xF3, 0xFF, 0x80, 0x0F,
0x87, 0xC3, 0x03, 0x81, 0xC0, 0xC0, 0x60, 0x30, 0x38, 0x1C, 0x0C, 0x06,
0x03, 0x03, 0x81, 0xC0, 0xC0, 0x60, 0x3E, 0x3F, 0x00, 0x41, 0xC3, 0x83,
0x07, 0x0E, 0x1C, 0x18, 0x38, 0x70, 0xE0, 0xC1, 0xC3, 0x83, 0x06, 0x0E,
0x1C, 0x18, 0x20, 0x1F, 0x0F, 0x80, 0xC0, 0xE0, 0x70, 0x30, 0x18, 0x0C,
0x0E, 0x07, 0x03, 0x01, 0x80, 0xC0, 0xE0, 0x70, 0x30, 0x18, 0x7C, 0x3E,
0x00, 0x02, 0x01, 0x80, 0xF0, 0x7E, 0x3B, 0x9C, 0x7E, 0x1F, 0x03, 0xFF,
0xFF, 0xFF, 0xFC, 0xCE, 0x73, 0x1F, 0xC3, 0xFE, 0x00, 0x60, 0x06, 0x0F,
0xE3, 0xFE, 0x70, 0xCC, 0x0C, 0xC3, 0xCF, 0xFF, 0x7F, 0xF0, 0x1E, 0x00,
0x3C, 0x00, 0x38, 0x00, 0x70, 0x00, 0xDF, 0x81, 0xFF, 0x83, 0xC3, 0x8F,
0x03, 0x1C, 0x06, 0x38, 0x0C, 0x70, 0x18, 0xE0, 0x63, 0xE1, 0x9F, 0xFE,
0x3D, 0xF8, 0x00, 0x0F, 0xF3, 0xFF, 0x30, 0x76, 0x07, 0xE0, 0x6C, 0x00,
0xC0, 0x0C, 0x00, 0xE0, 0x67, 0xFE, 0x3F, 0x80, 0x00, 0x3C, 0x00, 0xF0,
0x01, 0xC0, 0x06, 0x07, 0xD8, 0x7F, 0xE3, 0x0F, 0x98, 0x1E, 0x60, 0x73,
0x01, 0xCC, 0x07, 0x30, 0x3C, 0xE1, 0xF1, 0xFF, 0xE3, 0xF7, 0x80, 0x0F,
0xC1, 0xFE, 0x78, 0x76, 0x03, 0xFF, 0xFF, 0xFF, 0xC0, 0x0C, 0x00, 0xE0,
0xE7, 0xFE, 0x1F, 0x80, 0x00, 0xFC, 0x07, 0xF8, 0x0C, 0x00, 0x38, 0x01,
0xFF, 0x07, 0xFE, 0x01, 0x80, 0x07, 0x00, 0x0E, 0x00, 0x18, 0x00, 0x30,
0x00, 0x60, 0x01, 0xC0, 0x1F, 0xF8, 0x3F, 0xF0, 0x00, 0x0F, 0xBC, 0x7F,
0xF3, 0x0F, 0x18, 0x1C, 0xC0, 0x73, 0x01, 0x8C, 0x0E, 0x30, 0x38, 0xE3,
0xE1, 0xFF, 0x83, 0xEC, 0x00, 0x30, 0x01, 0xC0, 0x06, 0x07, 0xF0, 0x1F,
0x80, 0x1E, 0x01, 0xF0, 0x03, 0x00, 0x18, 0x00, 0xDE, 0x0F, 0xF8, 0x78,
0xC3, 0x86, 0x18, 0x30, 0xC1, 0x8E, 0x1C, 0x70, 0xE3, 0x06, 0x7E, 0xFF,
0xE7, 0xE0, 0x03, 0x80, 0x70, 0x00, 0x0F, 0xC1, 0xF0, 0x06, 0x00, 0xC0,
0x38, 0x07, 0x00, 0xC0, 0x18, 0x03, 0x0F, 0xFF, 0xFF, 0xC0, 0x00, 0x70,
0x07, 0x00, 0x00, 0xFF, 0x1F, 0xF0, 0x07, 0x00, 0x70, 0x06, 0x00, 0x60,
0x06, 0x00, 0xE0, 0x0E, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x1C, 0x03, 0x87,
0xF0, 0xFE, 0x00, 0x1E, 0x00, 0x78, 0x00, 0xE0, 0x03, 0x80, 0x0C, 0xFC,
0x33, 0xE0, 0xDE, 0x07, 0xE0, 0x1F, 0x00, 0x7C, 0x01, 0xF8, 0x06, 0xF0,
0x39, 0xC3, 0xE7, 0xEF, 0x1F, 0x80, 0x0F, 0x81, 0xF0, 0x06, 0x01, 0xC0,
0x38, 0x06, 0x00, 0xC0, 0x18, 0x07, 0x00, 0xE0, 0x18, 0x03, 0x00, 0x61,
0xFF, 0xFF, 0xF8, 0x3F, 0xBC, 0x7F, 0xFC, 0xF3, 0x98, 0xC6, 0x33, 0x9C,
0xE7, 0x39, 0xCC, 0x63, 0x18, 0xC6, 0x31, 0x8D, 0xF7, 0xBF, 0xEF, 0x78,
0x3D, 0xE1, 0xFF, 0x8F, 0x8C, 0x38, 0x61, 0x83, 0x0C, 0x18, 0xE1, 0xC7,
0x0E, 0x30, 0x67, 0xEF, 0xFE, 0x7E, 0x07, 0xC1, 0xFE, 0x38, 0x76, 0x03,
0xC0, 0x3C, 0x03, 0xC0, 0x3C, 0x06, 0xE1, 0xC7, 0xF8, 0x3E, 0x00, 0x1E,
0xFC, 0x1F, 0xFE, 0x0F, 0x87, 0x0F, 0x03, 0x0E, 0x03, 0x0E, 0x03, 0x0E,
0x07, 0x0E, 0x06, 0x1F, 0x0C, 0x1F, 0xF8, 0x19, 0xF0, 0x18, 0x00, 0x18,
0x00, 0x38, 0x00, 0xFE, 0x00, 0xFE, 0x00, 0x0F, 0xDE, 0x3F, 0xFC, 0xC3,
0xE3, 0x03, 0x84, 0x07, 0x18, 0x0E, 0x30, 0x1C, 0x60, 0x78, 0xE1, 0xE0,
0xFF, 0xC0, 0xF9, 0x80, 0x03, 0x00, 0x0E, 0x00, 0x1C, 0x01, 0xFC, 0x03,
0xF8, 0x1E, 0x78, 0x7F, 0xF0, 0x7C, 0xC3, 0xC0, 0x0E, 0x00, 0x30, 0x00,
0xC0, 0x03, 0x00, 0x1C, 0x03, 0xFF, 0x0F, 0xFC, 0x00, 0x07, 0xF1, 0xFF,
0x30, 0x73, 0x86, 0x3F, 0x81, 0xFE, 0x03, 0xE6, 0x06, 0xE0, 0xEF, 0xFC,
0xFF, 0x00, 0x0C, 0x07, 0x01, 0x83, 0xFF, 0xFF, 0xCE, 0x03, 0x00, 0xC0,
0x30, 0x1C, 0x07, 0x01, 0x83, 0x7F, 0xCF, 0xC0, 0xF0, 0xFF, 0x1F, 0x60,
0x76, 0x07, 0x60, 0x76, 0x06, 0x60, 0x66, 0x0E, 0x61, 0xE7, 0xFF, 0x3E,
0xF0, 0x7E, 0x7E, 0xFC, 0xFC, 0xE0, 0xC0, 0xC3, 0x81, 0x86, 0x03, 0x98,
0x07, 0x70, 0x06, 0xC0, 0x0F, 0x80, 0x1E, 0x00, 0x38, 0x00, 0xF8, 0x7F,
0xE3, 0xE6, 0x63, 0x1B, 0xDC, 0x6F, 0x61, 0xFF, 0x87, 0xFC, 0x1E, 0xF0,
0x73, 0x81, 0xCE, 0x06, 0x38, 0x00, 0x3E, 0x7C, 0xF9, 0xF1, 0xE7, 0x03,
0xF8, 0x07, 0xC0, 0x1F, 0x01, 0xFC, 0x0F, 0x38, 0x78, 0xFB, 0xF7, 0xEF,
0x9F, 0x80, 0x1F, 0x1F, 0x3E, 0x1F, 0x1C, 0x1C, 0x0C, 0x18, 0x0E, 0x38,
0x0E, 0x70, 0x06, 0x60, 0x07, 0xE0, 0x07, 0xC0, 0x07, 0xC0, 0x03, 0x80,
0x07, 0x00, 0x07, 0x00, 0x0E, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x1F, 0xF1,
0xFF, 0x38, 0xE3, 0x1C, 0x03, 0x80, 0x70, 0x0E, 0x01, 0xC6, 0x38, 0x67,
0xFE, 0x7F, 0xE0, 0x01, 0xC0, 0xF0, 0x70, 0x18, 0x06, 0x03, 0x80, 0xE0,
0x30, 0x1C, 0x3E, 0x0F, 0x00, 0x60, 0x18, 0x06, 0x03, 0x80, 0xC0, 0x30,
0x0F, 0x01, 0xC0, 0x0C, 0x71, 0xC7, 0x18, 0x63, 0x8E, 0x30, 0xC3, 0x1C,
0x71, 0x86, 0x38, 0xE3, 0x04, 0x00, 0x0E, 0x07, 0x80, 0xC0, 0x60, 0x70,
0x30, 0x18, 0x0C, 0x06, 0x01, 0xC1, 0xE1, 0xC0, 0xC0, 0xE0, 0x70, 0x30,
0x38, 0x78, 0x38, 0x00, 0x3C, 0x27, 0xE6, 0xEF, 0xCC, 0x38};
const GFXglyph FreeMonoBoldOblique12pt7bGlyphs[] PROGMEM = {
{0, 0, 0, 14, 0, 1}, // 0x20 ' '
{0, 6, 15, 14, 6, -14}, // 0x21 '!'
{12, 8, 7, 14, 6, -13}, // 0x22 '"'
{19, 13, 18, 14, 2, -15}, // 0x23 '#'
{49, 11, 20, 14, 3, -16}, // 0x24 '$'
{77, 11, 15, 14, 3, -14}, // 0x25 '%'
{98, 11, 13, 14, 2, -12}, // 0x26 '&'
{116, 3, 7, 14, 8, -13}, // 0x27 '''
{119, 7, 19, 14, 7, -14}, // 0x28 '('
{136, 7, 19, 14, 2, -14}, // 0x29 ')'
{153, 11, 10, 14, 4, -14}, // 0x2A '*'
{167, 12, 13, 14, 3, -12}, // 0x2B '+'
{187, 6, 7, 14, 3, -2}, // 0x2C ','
{193, 13, 2, 14, 2, -7}, // 0x2D '-'
{197, 3, 3, 14, 6, -2}, // 0x2E '.'
{199, 14, 20, 14, 2, -16}, // 0x2F '/'
{234, 11, 15, 14, 3, -14}, // 0x30 '0'
{255, 11, 15, 14, 2, -14}, // 0x31 '1'
{276, 13, 15, 14, 1, -14}, // 0x32 '2'
{301, 12, 15, 14, 2, -14}, // 0x33 '3'
{324, 11, 14, 14, 3, -13}, // 0x34 '4'
{344, 12, 15, 14, 2, -14}, // 0x35 '5'
{367, 11, 15, 14, 4, -14}, // 0x36 '6'
{388, 11, 15, 14, 4, -14}, // 0x37 '7'
{409, 11, 15, 14, 3, -14}, // 0x38 '8'
{430, 11, 15, 14, 3, -14}, // 0x39 '9'
{451, 5, 11, 14, 5, -10}, // 0x3A ':'
{458, 7, 15, 14, 3, -10}, // 0x3B ';'
{472, 13, 11, 14, 2, -11}, // 0x3C '<'
{490, 13, 7, 14, 2, -9}, // 0x3D '='
{502, 13, 11, 14, 2, -11}, // 0x3E '>'
{520, 9, 14, 14, 5, -13}, // 0x3F '?'
{536, 12, 19, 14, 2, -14}, // 0x40 '@'
{565, 15, 14, 14, 0, -13}, // 0x41 'A'
{592, 13, 14, 14, 1, -13}, // 0x42 'B'
{615, 14, 14, 14, 2, -13}, // 0x43 'C'
{640, 13, 14, 14, 1, -13}, // 0x44 'D'
{663, 15, 14, 14, 0, -13}, // 0x45 'E'
{690, 16, 14, 14, 0, -13}, // 0x46 'F'
{718, 14, 14, 14, 1, -13}, // 0x47 'G'
{743, 16, 14, 14, 0, -13}, // 0x48 'H'
{771, 12, 14, 14, 2, -13}, // 0x49 'I'
{792, 16, 14, 14, 0, -13}, // 0x4A 'J'
{820, 16, 14, 14, 0, -13}, // 0x4B 'K'
{848, 13, 14, 14, 1, -13}, // 0x4C 'L'
{871, 18, 14, 14, 0, -13}, // 0x4D 'M'
{903, 16, 14, 14, 1, -13}, // 0x4E 'N'
{931, 14, 14, 14, 1, -13}, // 0x4F 'O'
{956, 13, 14, 14, 1, -13}, // 0x50 'P'
{979, 14, 17, 14, 1, -13}, // 0x51 'Q'
{1009, 15, 14, 14, 0, -13}, // 0x52 'R'
{1036, 12, 14, 14, 3, -13}, // 0x53 'S'
{1057, 13, 14, 14, 2, -13}, // 0x54 'T'
{1080, 14, 14, 14, 2, -13}, // 0x55 'U'
{1105, 15, 14, 14, 1, -13}, // 0x56 'V'
{1132, 15, 14, 14, 1, -13}, // 0x57 'W'
{1159, 16, 14, 14, 0, -13}, // 0x58 'X'
{1187, 13, 14, 14, 2, -13}, // 0x59 'Y'
{1210, 14, 14, 14, 1, -13}, // 0x5A 'Z'
{1235, 9, 19, 14, 5, -14}, // 0x5B '['
{1257, 7, 20, 14, 5, -16}, // 0x5C '\'
{1275, 9, 19, 14, 3, -14}, // 0x5D ']'
{1297, 10, 8, 14, 4, -15}, // 0x5E '^'
{1307, 15, 2, 14, -1, 4}, // 0x5F '_'
{1311, 4, 4, 14, 7, -15}, // 0x60 '`'
{1313, 12, 11, 14, 2, -10}, // 0x61 'a'
{1330, 15, 15, 14, -1, -14}, // 0x62 'b'
{1359, 12, 11, 14, 2, -10}, // 0x63 'c'
{1376, 14, 15, 14, 2, -14}, // 0x64 'd'
{1403, 12, 11, 14, 2, -10}, // 0x65 'e'
{1420, 15, 15, 14, 2, -14}, // 0x66 'f'
{1449, 14, 16, 14, 2, -10}, // 0x67 'g'
{1477, 13, 15, 14, 1, -14}, // 0x68 'h'
{1502, 11, 14, 14, 2, -13}, // 0x69 'i'
{1522, 12, 19, 14, 1, -13}, // 0x6A 'j'
{1551, 14, 15, 14, 1, -14}, // 0x6B 'k'
{1578, 11, 15, 14, 2, -14}, // 0x6C 'l'
{1599, 15, 11, 14, 0, -10}, // 0x6D 'm'
{1620, 13, 11, 14, 1, -10}, // 0x6E 'n'
{1638, 12, 11, 14, 2, -10}, // 0x6F 'o'
{1655, 16, 16, 14, -1, -10}, // 0x70 'p'
{1687, 15, 16, 14, 1, -10}, // 0x71 'q'
{1717, 14, 11, 14, 1, -10}, // 0x72 'r'
{1737, 12, 11, 14, 2, -10}, // 0x73 's'
{1754, 10, 14, 14, 2, -13}, // 0x74 't'
{1772, 12, 11, 14, 2, -10}, // 0x75 'u'
{1789, 15, 11, 14, 1, -10}, // 0x76 'v'
{1810, 14, 11, 14, 2, -10}, // 0x77 'w'
{1830, 14, 11, 14, 1, -10}, // 0x78 'x'
{1850, 16, 16, 14, 0, -10}, // 0x79 'y'
{1882, 12, 11, 14, 2, -10}, // 0x7A 'z'
{1899, 10, 19, 14, 4, -14}, // 0x7B '{'
{1923, 6, 19, 14, 5, -14}, // 0x7C '|'
{1938, 9, 19, 14, 3, -14}, // 0x7D '}'
{1960, 12, 4, 14, 3, -7}}; // 0x7E '~'
const GFXfont FreeMonoBoldOblique12pt7b PROGMEM = {
(uint8_t *)FreeMonoBoldOblique12pt7bBitmaps,
(GFXglyph *)FreeMonoBoldOblique12pt7bGlyphs, 0x20, 0x7E, 24};
// Approx. 2638 bytes

Some files were not shown because too many files have changed in this diff Show More