Sitemap / Advertise

Introduction

Detect keychains to inform emergency contacts via WhatsApp / SMS. Display results via BLE. Let contacts request location info from Maps API.


Tags

Share

AI-driven BLE Travel Emergency Assistant w/ Twilio

Advertisement:


read_later

Read Later



read_later

Read Later

Introduction

Detect keychains to inform emergency contacts via WhatsApp / SMS. Display results via BLE. Let contacts request location info from Maps API.

Tags

Share





Advertisement

Advertisement




    Components :
  • [1]Seeed Studio XIAO ESP32S3 Sense
  • [1]Seeed Studio XIAO Round Display
  • [1]MicroSD Card
  • [1]Anycubic Kobra 2
  • [1]Xiaomi 10000 mAh Ultra Compact Pro 3 Powerbank

Description

Heartbreakingly and unfortunately, people with disabilities are more likely to be victims of violence, theft, verbal abuse, and neglect while traveling, especially travelers with mobility impairments. In overall crime estimations, people with disabilities have a higher risk, at least four to ten times, of being a victim[1]. Considering the discouragement of these heinous crimes hurting vacation plans of people with mobility impairments, it has become necessary to provide them with state-of-the-art assistive devices so as to preclude offenders from committing crimes against people with disabilities.

While traveling alone and feeling in danger, one of the most crucial steps to prevent a potential crime is to let your emergency contacts know your whereabouts with a brief explanation of your situation. Although smartphones provide various features regarding location tracking and wireless communication, they might still be not suitable since reaching and utilizing a smartphone may be time-consuming and arduous in a time of crisis for people with mobility impairments. In light of recent developments in machine learning and IoT, there is a surge in devices enhancing smartphone features in the form of automated notifications and additional sensors, e.g. smartwatches and fitness wearables. Thus, in this project, I focused on developing an AIoT assistive device that improves smartphone features to inform emergency contacts automatically and instantly of the user's situation.

Approximately 15% of the population is affected by some kind of disability, and this number is rising exponentially due to aging populations and the spread of chronic diseases, according to WHO reports[2]. In this regard, budget-friendly and accessible AIoT assistive devices should be versatile and provide various features in a broader spectrum, considering people with disabilities and special needs.

After inspecting recent research papers on assistive devices, I noticed there are nearly no wearable appliances focusing on detecting personalized items to execute some predefined functions covertly, such as automated notifications, by utilizing smartphone features. Therefore, I decided to build a user-friendly and accessible assistive device to detect customized keychains (tokens) with object detection and inform emergency contacts of the user's situation automatically.

Since XIAO ESP32S3 Sense is an ultra-small-sized IoT development board providing a built-in OV2640 camera and a microSD card module on its expansion board, I decided to utilize XIAO ESP32S3 in this project. Thanks to the integrated modules on the expansion board, I was able to capture images and save them to the SD card as samples without requiring any additional procedures. Furthermore, XIAO ESP32S3 comes with integrated Wi-Fi/BLE connectivity and 8MB PSRAM. Therefore, I was also able to run my object detection model consecutively. Then, I connected the XIAO round display to XIAO ESP32S3 in order to notify the user of the current saved sample numbers on the SD card and the ongoing operation by showing assigned icons.

Since I wanted to capitalize on smartphone features (e.g., GPS, GPRS, BLE) to build a capable assistive device, I decided to develop an Android application from scratch with the MIT APP Inventor. As the user interface of the assistive device, the Android application can utilize the celluar network connection to transfer data packets to a web application via GPRS, obtain precise location data via GPS, and communicate with XIAO ESP32S3 via BLE so as to get model detection results and transmit commands for data collection.

After developing my Android application, I designed various keychains (tokens) denoting different emergencies and printed them with my 3D printer. Then, I utilized the Android application to transfer commands to XIAO ESP32S3 via BLE to capture images of these customized keychains so as to construct a notable data set.

After completing my data set, I built my object detection model with Edge Impulse to detect customized keychains (tokens) denoting different emergencies. I utilized Edge Impulse FOMO (Faster Objects, More Objects) algorithm to train my model, which is a novel machine learning algorithm that brings object detection to highly constrained devices. Since Edge Impulse is nearly compatible with all microcontrollers and development boards, I have not encountered any issues while uploading and running my model on XIAO ESP32S3. As labels, I utilized the names of emergency situations represented by customized keychains:

After training and testing my object detection (FOMO) model, I deployed and uploaded the model on XIAO ESP32S3 as an Arduino library. Therefore, this assistive device is capable of detecting keychains (tokens) by running the model independently without any additional procedures or latency.

After running the object detection model successfully, I employed XIAO ESP32S3 to transfer the model detection results to the Android application via BLE. Since I focused on building a full-fledged AIoT assistive device, supporting only BLE data transmission with an Android application was not suitable. Therefore, I decided to develop a versatile web application from scratch and utilize the Android application to transmit the model detection results, the current location parameters (GPS data), and the current date to the web application via an HTTP GET request (cellular network connectivity). After receiving a data packet from the Android application, the web application saves the model detection results, location parameters (latitude, longitude, and altitude), and the current date to the MySQL database for further usage.

Then, I utilized the web application to inform the emergency contacts selected by the user of detected emergency classes via WhatsApp or SMS immediately. In this regard, I needed to utilize Twilio's WhatsApp and SMS APIs simultaneously. Also, I employed the web application to obtain inquiries from emergency contacts over WhatsApp in order to send thorough location inspections generated by Google Maps with the location information stored in the database table as feedback.

As shown below, the assistive device allows the user to apply the Fine emergency class to save location parameters as breadcrumbs to the database table. Therefore, the web application can generate travel itineraries with different methods of travel related to previously visited destinations, depending on the inquiries (commands) requested by emergency contacts through WhatsApp.

Considering harsh operating conditions, I designed a smartwatch-inspired case with a modular part (3D printable) that allows the user to attach the assistive device to various mobility aids, such as wheelchairs, scooters, walkers, canes, etc. The modular part is specifically designed to contain XIAO ESP32S3, its expansion board, and the XIAO round display.

So, this is my project in a nutshell ๐Ÿ˜ƒ

In the following steps, you can find more detailed information on coding, capturing customized keychain images, building an object detection model with Edge Impulse, running the model on XIAO ESP32S3, and developing full-fledged Android and web applications to inform emergency contacts via WhatsApp or SMS.

๐ŸŽ๐ŸŽจ Huge thanks to Seeed Studio for sponsoring these products:

โญ XIAO ESP32S3 Sense | Inspect

โญ XIAO Round Display | Inspect

๐ŸŽ๐ŸŽจ Also, huge thanks to Anycubic for sponsoring a brand-new Anycubic Kobra 2.

project-image
Figure - 92.1


project-image
Figure - 92.2


project-image
Figure - 92.3


project-image
Figure - 92.4


project-image
Figure - 92.5


project-image
Figure - 92.6


project-image
Figure - 92.7


project-image
Figure - 92.8


project-image
Figure - 92.9


project-image
Figure - 92.10


project-image
Figure - 92.11


project-image
Figure - 92.12


project-image
Figure - 92.13


project-image
Figure - 92.14


project-image
Figure - 92.15


project-image
Figure - 92.16


project-image
Figure - 92.17


project-image
Figure - 92.18


project-image
Figure - 92.19


project-image
Figure - 92.20


project-image
Figure - 92.21


project-image
Figure - 92.22


project-image
Figure - 92.23


project-image
Figure - 92.24


project-image
Figure - 92.25


project-image
Figure - 92.26


project-image
Figure - 92.27

Step 1: Designing and printing a smartwatch-inspired case

Since I focused on building a budget-friendly and accessible assistive device that enables the user to inform emergency contacts effortlessly via WhatsApp or SMS, I decided to design a robust and compact case that allows the user to attach the mechanism to various mobility aids, such as wheelchairs, scooters, walkers, canes, etc. Since I wanted to make the main case compatible with different battery options, I designed the main case as two parts connected with snap-fit joints. To avoid overexposure to dust and prevent loose wire connections, I added a modular part specifically designed for XIAO ESP32S3 Sense and XIAO round display. Then, I added dents on the main case and the modular part, which lets the user connect the modular part to the main case or position the built-in camera freely while scanning keychains or collecting samples. Also, I decided to inscribe the Seeed Studio logo, the Twilio logo, and the traveling airplane icon on the main case to highlight the capabilities of this assistive device.

Since I needed unique keychains (tokens) for each feature I wanted to add to this assistive device, I decided to design customized keychains in addition to the 3D parts of the main case. For each keychain, I utilized different icons related to their assigned features.

I designed the main case, its modular part, and the customized keychains in Autodesk Fusion 360. You can download their STL files below.

project-image
Figure - 92.28


project-image
Figure - 92.29


project-image
Figure - 92.30


project-image
Figure - 92.31


project-image
Figure - 92.32


project-image
Figure - 92.33


project-image
Figure - 92.34


project-image
Figure - 92.35


project-image
Figure - 92.36


project-image
Figure - 92.37


project-image
Figure - 92.38


project-image
Figure - 92.39

Then, I sliced all 3D models (STL files) in Ultimaker Cura.

project-image
Figure - 92.40


project-image
Figure - 92.41


project-image
Figure - 92.42


project-image
Figure - 92.43


project-image
Figure - 92.44


project-image
Figure - 92.45


project-image
Figure - 92.46


project-image
Figure - 92.47


project-image
Figure - 92.48

Since I wanted to create a metallic structure for the main case and apply a unique flashy theme representing a smartwatch case due to the round display, I utilized this PLA filament:

I decided to give each keychain a unique color to make them easily recognizable by my object detection model. Thus, I utilized these PLA filaments:

Finally, I printed all parts (models) with my brand-new Anycubic Kobra 2 3D Printer.

project-image
Figure - 92.49

Since Anycubic Kobra 2 is budget-friendly and specifically designed for high-speed printing, I highly recommend Anycubic Kobra 2 if you are a maker or hobbyist needing to print multiple prototypes before finalizing a complex project.

Thanks to its upgraded direct extruder, Anycubic Kobra 2 provides 150mm/s recommended print speed (up to 250mm/s) and dual-gear filament feeding. Also, it provides a cooling fan with an optimized dissipation design to support rapid cooling complementing the fast printing experience. Since the Z-axis has a double-threaded rod structure, it flattens the building platform and reduces the printing layers, even at a higher speed.

Furthermore, Anycubic Kobra 2 provides a magnetic suction platform on the heated bed for the scratch-resistant spring steel build plate allowing the user to remove prints without any struggle. Most importantly, you can level the bed automatically via its user-friendly LeviQ 2.0 automatic bed leveling system. Also, it has a smart filament runout sensor and the resume printing function for power failures.

#๏ธโƒฃ First of all, install the gantry and the spring steel build plate.

project-image
Figure - 92.50


project-image
Figure - 92.51

#๏ธโƒฃ Install the print head, the touch screen, and the filament runout sensor.

project-image
Figure - 92.52


project-image
Figure - 92.53

#๏ธโƒฃ Connect the stepper, switch, screen, and print head cables. Then, attach the filament tube.

project-image
Figure - 92.54

#๏ธโƒฃ If the print head is shaking, adjust the hexagonal isolation column under the print head.

project-image
Figure - 92.55

#๏ธโƒฃ Go to Prepareโžก Leveling โžก Auto-leveling to initiate the LeviQ 2.0 automatic bed leveling system.

#๏ธโƒฃ After preheating and wiping the nozzle, Anycubic Kobra 2 probes the predefined points to level the bed.

project-image
Figure - 92.56


project-image
Figure - 92.57


project-image
Figure - 92.58


project-image
Figure - 92.59


project-image
Figure - 92.60

#๏ธโƒฃ Finally, fix the filament tube with the cable clips, install the filament holder, and insert the filament into the extruder.

project-image
Figure - 92.61

#๏ธโƒฃ Since Anycubic Kobra 2 is not officially supported by Cura yet, download the latest PrusaSlicer version and import the printer profile (configuration) file provided by Anycubic.

#๏ธโƒฃ Then, create a custom printer profile on Cura for Anycubic Kobra 2 and change Start G-code and End G-code.

#๏ธโƒฃ Based on the provided Start G-code and End G-code in the configuration file, I modified new Start G-code and End G-code compatible with Cura.


Start G-code:

G90 ; use absolute coordinates
M83 ; extruder relative mode
G28 ; move X/Y/Z to min endstops
G1 Z2.0 F3000 ; lift nozzle a bit 
G92 E0 ; Reset Extruder
G1 X10.1 Y20 Z0.28 F5000.0 ; Move to start position
G1 X10.1 Y200.0 Z0.28 F1500.0 E15 ; Draw the first line
G1 X10.4 Y200.0 Z0.28 F5000.0 ; Move to side a little
G1 X10.4 Y20 Z0.28 F1500.0 E30 ; Draw the second line
G92 E0 ; zero the extruded length again 
G1 E-2 F500 ; Retract a little 
M117
G21 ; set units to millimeters
G90 ; use absolute coordinates
M82 ; use absolute distances for extrusion
G92 E0
M107

End G-code:

M104 S0 ; Extruder off 
M140 S0 ; Heatbed off 
M107    ; Fan off 
G91     ; relative positioning 
G1 E-5 F3000  
G1 Z+0.3 F3000 ; lift print head 
G28 X0  F3000
M84            ; disable stepper motors

#๏ธโƒฃ Finally, adjust the official printer settings depending on the filament type while copying them from PrusaSlicer to Cura.

project-image
Figure - 92.62


project-image
Figure - 92.63


project-image
Figure - 92.64


project-image
Figure - 92.65


project-image
Figure - 92.66


project-image
Figure - 92.67


project-image
Figure - 92.68

Step 1.1: Assembling the case and making connections & adjustments


// Connections
// XIAO ESP32S3 (Sense) :
//                                XIAO Round Display 
// https://wiki.seeedstudio.com/seeedstudio_round_display_usage/#getting-started

Since I utilized XIAO ESP32S3 Sense and the XIAO round display compatible with XIAO development boards out of the box, I did not need to use a breadboard to test my prototype's wire connections. I just made some adjustments before proceeding with the following steps.

#๏ธโƒฃ First of all, I soldered male pin headers to XIAO ESP32S3. Then, I installed the expansion board (for Sense) to XIAO ESP32S3 via the B2B connector on the development board.

#๏ธโƒฃ After installing the expansion board, I connected the XIAO round display to XIAO ESP32S3 via the built-in female headers on the round display.

#๏ธโƒฃ Then, I inserted a microSD card into the SD card reader on the expansion board. Since the round display also has an SD card reader, I modified the pin configuration on the code file to avoid any conflict between the modules.

#๏ธโƒฃ Finally, I attached the antenna via the built-in WiFi/BT antenna connector on XIAO ESP32S3.

project-image
Figure - 92.69


project-image
Figure - 92.70


project-image
Figure - 92.71

After printing all parts (models), I fastened the battery into the right part of the main case via a hot glue gun. I decided to utilize a Xiaomi 10000 mAh power bank to supply this assistive device since it is designed to accompany the user during long travels without requiring recharging.

Then, I aligned the right and left parts of the main case on an assistive cane via their extended hollow cylindrical joints. After aligning the parts, I connected them via their snap-fit joints. I used a walking cane since it was the only available mobility aid to me, but this assistive device can be connected to various mobility aids.

Finally, I attached XIAO ESP32S3 Sense and the round display to the modular part via the hot glue gun.

project-image
Figure - 92.72


project-image
Figure - 92.73


project-image
Figure - 92.74


project-image
Figure - 92.75


project-image
Figure - 92.76


project-image
Figure - 92.77


project-image
Figure - 92.78


project-image
Figure - 92.79


project-image
Figure - 92.80


project-image
Figure - 92.81


project-image
Figure - 92.82


project-image
Figure - 92.83


project-image
Figure - 92.84


project-image
Figure - 92.85


project-image
Figure - 92.86


project-image
Figure - 92.87

Thanks to the dents on the main case, the modular part can be removed from the main case to position the built-in camera at different angles while scanning keychains.

Since I connected XIAO ESP32S3 to the power bank via a long USB Type-C cable, the modular part can move in a 40 cm diameter.

project-image
Figure - 92.88


project-image
Figure - 92.89


project-image
Figure - 92.90


project-image
Figure - 92.91


project-image
Figure - 92.92

Step 2: Developing a GPS, GPRS, and BLE-enabled Android application w/ the MIT APP Inventor

Since I wanted to make this assistive device operate without requiring a Wi-Fi connection to transfer data packets to the web application, I decided to develop an Android application from scratch with the MIT APP Inventor. As the user interface of this assistive device, the Android application can utilize the celluar network connection to transfer data packets to the web application via GPRS, obtain precise location data via GPS, and communicate with XIAO ESP32S3 via BLE so as to get model detection results and transmit commands for data collection.

MIT App Inventor is an intuitive, visual programming environment that allows developers to build fully functional Android applications. Its blocks-based tool (drag-and-drop) facilitates the creation of complex, high-impact apps in significantly less time than the traditional programming environments.

After developing my application, named BLE Travel Emergency Assistant, I published it on Google Play. So, you can install this application on any compatible Android device via Google Play.

๐Ÿ“ฒ Install BLE Emergency Assistant on Google Play

Also, you can download the application's APK file directly below.

Nevertheless, if you want to replicate or modify this Android application on the MIT App Inventor, follow the steps below.

#๏ธโƒฃ First of all, create an account on the MIT App Inventor.

#๏ธโƒฃ Download the BLE Travel Emergency Assistant app's project file in the AIA format (BLE_Emergency_Assistant.aia) and import the AIA file into the MIT App Inventor.

project-image
Figure - 92.93

#๏ธโƒฃ Since the MIT App Inventor does not support BLE connectivity by default, download the latest version of the BluetoothLE extension and import the BluetoothLE extension into the BLE Emergency Assistant project.

#๏ธโƒฃ In this tutorial, you can get more information regarding enabling BLE connectivity on the MIT App Inventor.

project-image
Figure - 92.94

#๏ธโƒฃ In the Blocks editor, you can inspect the functions I programmed with the drag-and-drop menu components.

#๏ธโƒฃ In the following steps, you can get more information regarding all features of this Android application working in conjunction with XIAO ESP32S3 and the web application.

project-image
Figure - 92.95


project-image
Figure - 92.96


project-image
Figure - 92.97


project-image
Figure - 92.98

After installing this Android application on a compatible mobile phone, you can start communicating with XIAO ESP32S3 over BLE immediately.

project-image
Figure - 92.99

Step 3: Creating an account to utilize Twilio's WhatsApp & SMS APIs

Since I decided to inform the user's emergency contacts of the latest detected keychain (token) by the object recognition model over WhatsApp and SMS, I needed to utilize Twilio's WhatsApp and SMS APIs simultaneously. In this regard, I was also able to obtain commands from emergency contacts over WhatsApp in order to send thorough location inspections generated by Google Maps as feedback via the web application.

Twilio gives the user a simple and reliable way to communicate with a Twilio-verified phone over WhatsApp via a webhook free of charge for trial accounts. Also, Twilio provides a trial text messaging service to transfer an SMS from a virtual phone number to a verified phone number internationally. Furthermore, Twilio supports official helper libraries for different programming languages, including PHP, enforcing its APIs.

#๏ธโƒฃ First of all, sign up for Twilio and navigate to the default (first) trial account (project).

I noticed that creating a new free trial account (project) more than once may lead to the suspension of your Twilio user account. So, I recommend using the default trial account (project).

project-image
Figure - 92.100

#๏ธโƒฃ After verifying a phone number for the default account (project), set the account settings for WhatsApp in PHP initially.

project-image
Figure - 92.101

#๏ธโƒฃ Go to Twilio Sandbox for WhatsApp and verify your device by sending the given code over WhatsApp, which activates a WhatsApp session.

project-image
Figure - 92.102


project-image
Figure - 92.103

#๏ธโƒฃ After verifying your phone number, download the Twilio PHP Helper Library to receive commands and send updates over WhatsApp via the web application.

project-image
Figure - 92.104

#๏ธโƒฃ Finally, go to WhatsApp sandbox settings and change the receiving endpoint URL under WHEN A MESSAGE COMES IN with the requested webhook URL.

https://www.theamplituhedron.com/AIoT_Travel_Emergency_Assistant/

You can get more information regarding the web application in Step 4.

project-image
Figure - 92.105

#๏ธโƒฃ To configure the SMS settings, go to Messaging โžก Send an SMS.

#๏ธโƒฃ Since a virtual phone number is required to transfer an SMS via Twilio, click Get a Twilio number.

project-image
Figure - 92.106

#๏ธโƒฃ Since Twilio provides a trial (free) 10DLC phone number for each trial account, it lets the user utilize the text messaging service immediately after assigning a virtual phone number to the given account.

project-image
Figure - 92.107

#๏ธโƒฃ Finally, go to Geo permissions to adjust the allowed recipients depending on your region.

project-image
Figure - 92.108

#๏ธโƒฃ After configuring WhatsApp and SMS settings, go to Account โžก API keys & tokens to get the account SID and the auth token under Live credentials so as to employ Twilio's WhatsApp and SMS APIs to communicate with the verified phone numbers.

project-image
Figure - 92.109

Step 4: Developing a web application to communicate w/ the Android app and process requests from WhatsApp

Since I needed to obtain the model detection results from XIAO ESP32S3 through the Android application so as to inform emergency contacts, I decided to develop a basic web application (webhook) to utilize Twilio's WhatsApp and SMS APIs. In addition to working as a proxy server between the Android application and emergency contacts, the web application provides the user with various features.

First of all, the web application allows the user to change the emergency contact information in the database with a single HTTP GET request. With the stored emergency contact information, the web application informs the given contacts via WhatsApp or SMS automatically, depending on the model detection results transferred by the Android application. Also, thanks to Twilio's APIs, the web application can receive commands through WhatsApp so as to send thorough location inspections generated by Google Maps as feedback to the primary emergency contact.

Since Twilio requires a publicly available URL to redirect the incoming WhatsApp messages to a given webhook, I utilized my SSL-enabled server to host this web application. However, you can employ an HTTP tunneling tool like ngrok to set up a public URL for the webhook.

As shown below, the web application consists of two folders and two code files:

project-image
Figure - 92.110

๐Ÿ“ class.php

In the class.php file, I created a class named assistant to bundle the following functions under a specific structure.

โญ Include the Twilio PHP Helper Library.


require_once 'twilio-php-main/src/Twilio/autoload.php';
use Twilio\Rest\Client;

โญ Define the assistant class and its functions.

โญ In the __init__ function, define the Twilio account information and object.


class assistant {
	public $conn;
	private $twilio;
	
	public function __init__($conn){
		$this->conn = $conn;
		// Define the Twilio account information and object.
		$_sid    = "<_SID_>";
        $token  = "<_TOKEN_>";
        $this->twilio = new Client($_sid, $token);
	}

โญ In the update_user_info function, depending on the given action parameter, add the given emergency contact information to the entries database table for the first time or update the stored contact information in the database table.


	public function update_user_info($action, $to_phone, $from_phone, $emergency_phone){
		if($action == "new"){
			// Add the given user information to the database table.
			$sql_insert = "INSERT INTO `entries`(`to_phone`, `from_phone`, `emergency_phone`, `date`, `location`, `class`) 
						   VALUES ('$to_phone', '$from_phone', '$emergency_phone', 'X', 'X', 'X')"
					      ;
			if(mysqli_query($this->conn, $sql_insert)) echo("User information added to the database successfully!");			
		}else if($action == "update"){
			// Update the given user information in the database table.
			$sql_update = "UPDATE `entries` SET `to_phone`='$to_phone', `from_phone`='$from_phone', `emergency_phone`='$emergency_phone'
			               WHERE `id`=1"
						  ;
			if(mysqli_query($this->conn, $sql_update)) echo("User information updated successfully!");

		}
	}

โญ In the save_results function:

โญ First, fetch the stored emergency contact information.

โญ Then, with the retrieved contact information, save the latest model detection results, the current date, and the current device location data transferred by the Android application to the entries database table as the new data record.


	public function save_results($action, $date, $location, $class){
		if($action == "save"){
			// Fetch the stored user information to add to the new data record.
			$sql_insert = "INSERT INTO `entries`(`to_phone`, `from_phone`, `emergency_phone`, `date`, `location`, `class`) 
						   SELECT `to_phone`, `from_phone`, `emergency_phone`, '$date', '$location', '$class'
						   FROM `entries` WHERE id=1"
			              ;
			if(mysqli_query($this->conn, $sql_insert)) echo("New data record inserted successfully!");
		}
	}

โญ In the get_user_info function, retrieve the stored emergency contact information from the database table.


	private function get_user_info(){
		$sql = "SELECT * FROM `entries` WHERE id=1";
		$result = mysqli_query($this->conn, $sql);
		$check = mysqli_num_rows($result);
		if($check > 0 && $row = mysqli_fetch_assoc($result)){
			return $row;
		}
	}

โญ In the get_loc_vars function, obtain the stored location variables (latitude, longitude, and altitude) for each data record in the database table and return them in descending order as a list.


	private function get_loc_vars(){
		$loc_vars = [];
		$sql = "SELECT * FROM `entries` WHERE id!=1 ORDER BY `id` DESC";
		$result = mysqli_query($this->conn, $sql);
		$check = mysqli_num_rows($result);
		while($check > 0 && $row = mysqli_fetch_assoc($result)){
			array_push($loc_vars, $row);
		}
		return $loc_vars;
	}

โญ In the Twilio_send_whatsapp function:

โญ Get the stored emergency contact information from the database table.

โญ Configure the Twilio WhatsApp object with the given message.

โญ Then, send a WhatsApp message to the registered primary emergency contact via Twilio.


	private function Twilio_send_whatsapp($body){
		// Get user information.
		$info = $this->get_user_info();
		// Configure the WhatsApp object.
		$whatsapp_message = $this->twilio->messages
			->create("whatsapp:".$info["to_phone"],
				array(
					   "from" => "whatsapp:+14155238886",
					   "body" => $body
                     )
				);
		// Send the WhatsApp message.
        echo(" WhatsApp SID: ".$whatsapp_message->sid);
	}

โญ In the Twilio_send_SMS function:

โญ Get the stored emergency contact information from the database table.

โญ Configure the Twilio SMS object with the given message.

โญ Then, send an SMS to the registered secondary emergency contact via Twilio.


	private function Twilio_send_SMS($body){
		// Get user information.
		$info = $this->get_user_info();
		// Configure the SMS object.
        $sms_message = $this->twilio->messages
			->create($info["emergency_phone"],
				array(
					   "from" => $info["from_phone"],
                       "body" => $body
                     )
                );
		// Send the SMS.
		echo(" SMS SID: ".$sms_message->sid);	  
	}

โญ In the notify_contacts function:

โญ Obtain the model detection results (command), the current date, and the current device location data transferred by the Android application.

โญ Decode the received location parameters (latitude, longitude, altitude).

โญ Notify the user's emergency contacts via SMS or WhatsApp, depending on the given command.


	public function notify_contacts($command, $date, $location){
		// Decode the received location parameters.
		$loc_vars = explode(",", $location);
		$lat = $loc_vars[0]; $long = $loc_vars[1]; $alt = $loc_vars[2];
		// Notify the emergency contacts.
		if($command == "fine"){
			$message_body = "๐Ÿ˜„ ๐Ÿ‘ I am doing well. I just wanted to add this location as a breadcrumb ๐Ÿ˜„ ๐Ÿ‘"
			                ."\n\r\n\rโฐ Date: ".$date
							."\n\r\n\rโœˆ๏ธ Altitude: ".$alt
							."\n\r\n\r๐Ÿ“Œ Current Location:\n\rhttps://www.google.com/maps/search/?api=1&query=".$lat."%2C".$long;
			$this->Twilio_send_whatsapp($message_body);
		}
		else if($command == "danger"){
			$message_body = "โš ๏ธ โš ๏ธ โš ๏ธ I do not feel safe and may be in peril โš ๏ธ โš ๏ธ โš ๏ธ"
			                ."\n\r\n\rโฐ Date: ".$date
							."\n\r\n\rโœˆ๏ธ Altitude: ".$alt
							."\n\r\n\r๐Ÿ“Œ Current Location:\n\rhttps://www.google.com/maps/search/?api=1&query=".$lat."%2C".$long;
			$this->Twilio_send_whatsapp($message_body);
		}
		else if($command == "assist"){
			$message_body = "โ™ฟ โ™ฟ โ™ฟ I may need your assistance due to restrictive layouts โ™ฟ โ™ฟ โ™ฟ"
			                ."\n\r\n\rโฐ Date: ".$date
							."\n\r\n\rโœˆ๏ธ Altitude: ".$alt
							."\n\r\n\r๐Ÿ“Œ Current Location:\n\rhttps://www.google.com/maps/search/?api=1&query=".$lat."%2C".$long;
			$this->Twilio_send_whatsapp($message_body);
		}
		else if($command == "stolen"){
			$message_body = "๐Ÿ’ฐ ๐Ÿ‘ฎ๐Ÿป ๐Ÿ’ฐ Someone managed to purloin my valuables near this location ๐Ÿ’ฐ ๐Ÿ‘ฎ๐Ÿป ๐Ÿ’ฐ"
			                ."\n\r\n\rโฐ Date: ".$date
							."\n\r\n\rโœˆ๏ธ Altitude: ".$alt
							."\n\r\n\r๐Ÿ“Œ Current Location:\n\rhttps://www.google.com/maps/search/?api=1&query=".$lat."%2C".$long;
			$this->Twilio_send_whatsapp($message_body);
		}
		else if($command == "call"){
			$message_body = "๐Ÿ“ž โ˜Ž๏ธ ๐Ÿ“ž Please inform my first emergency contact that I am near this location ๐Ÿ“ž โ˜Ž๏ธ ๐Ÿ“ž"
			                ."\n\r\n\rโฐ Date: ".$date
							."\n\r\n\rโœˆ๏ธ Altitude: ".$alt
							."\n\r\n\r๐Ÿ“Œ Current Location:\n\r\n\rhttps://www.google.com/maps/search/?api=1&query=".$lat."%2C".$long;
			$this->Twilio_send_SMS($message_body);
		}
	}

โญ In the generate_feedback function:

โญ Get the stored location variables (latitude, longitude, and altitude) for each data record in the database table in descending order.

โญ When requested by the primary emergency contact via WhatsApp, generate a thorough location inspection with the retrieved location parameters by utilizing Google Maps URL API, according to the requested inquiry.

โญ Then, transfer the generated feedback to the emergency contact as feedback.

You can get more detailed information regarding the inquirable feedback in the following steps.


	public function generate_feedback($command){
		// Obtain the latest location variables in the database table.
		$loc_vars = $this->get_loc_vars();
		// Generate the requested feedback via Google Maps.
		$message_body = "";
		switch($command){
			case "Route Walking":
				if(count($loc_vars) >= 2){
					$message_body = "๐Ÿšถ Estimated Walking Path:\n\r\n\r"
									."๐Ÿ“Œ Origin โžก๏ธ\n\r"
									."๐Ÿ•œ ".$loc_vars[1]["date"]
									."\n\r๐Ÿ”Ž ".$loc_vars[1]["class"]
									."\n\r\n\r๐Ÿ“Œ Destination โžก๏ธ\n\r"
									."๐Ÿ•œ ".$loc_vars[0]["date"]
									."\n\r๐Ÿ”Ž ".$loc_vars[0]["class"]
									."\n\r\n\rhttps://www.google.com/maps/dir/?api=1&origin="
									.explode(",", $loc_vars[1]["location"])[0]."%2C"
									.explode(",", $loc_vars[1]["location"])[1]."&destination="
									.explode(",", $loc_vars[0]["location"])[0]."%2C"
									.explode(",", $loc_vars[0]["location"])[1]
									."&travelmode=walking";
				}else{
					$message_body = "โ›” Insufficient data for the requested analysis.";
				}
				break;
			case "Route Bicycling":
				if(count($loc_vars) >= 2){
					$message_body = "๐Ÿšด Estimated Bicycling Path:\n\r\n\r"
									."๐Ÿ“Œ Origin โžก๏ธ\n\r"
									."๐Ÿ•œ ".$loc_vars[1]["date"]
									."\n\r๐Ÿ”Ž ".$loc_vars[1]["class"]
									."\n\r\n\r๐Ÿ“Œ Destination โžก๏ธ\n\r"
									."๐Ÿ•œ ".$loc_vars[0]["date"]
									."\n\r๐Ÿ”Ž ".$loc_vars[0]["class"]
									."\n\r\n\rhttps://www.google.com/maps/dir/?api=1&origin="
									.explode(",", $loc_vars[1]["location"])[0]."%2C"
									.explode(",", $loc_vars[1]["location"])[1]."&destination="
									.explode(",", $loc_vars[0]["location"])[0]."%2C"
									.explode(",", $loc_vars[0]["location"])[1]
									."&travelmode=bicycling";
				}else{
					$message_body = "โ›” Insufficient data for the requested analysis.";
				}
				break;
			case "Route Driving":
				if(count($loc_vars) >= 2){
					$message_body = "๐Ÿš— Estimated Driving Path:\n\r\n\r"
									."๐Ÿ“Œ Origin โžก๏ธ\n\r"
									."๐Ÿ•œ ".$loc_vars[1]["date"]
									."\n\r๐Ÿ”Ž ".$loc_vars[1]["class"]
									."\n\r\n\r๐Ÿ“Œ Destination โžก๏ธ\n\r"
									."๐Ÿ•œ ".$loc_vars[0]["date"]
									."\n\r๐Ÿ”Ž ".$loc_vars[0]["class"]
									."\n\r\n\rhttps://www.google.com/maps/dir/?api=1&origin="
									.explode(",", $loc_vars[1]["location"])[0]."%2C"
									.explode(",", $loc_vars[1]["location"])[1]."&destination="
									.explode(",", $loc_vars[0]["location"])[0]."%2C"
									.explode(",", $loc_vars[0]["location"])[1]
									."&travelmode=driving";
				}else{
					$message_body = "โ›” Insufficient data for the requested analysis.";
				}
				break;
			case "Show Waypoints":
				if(count($loc_vars) >= 4){
					$message_body = "๐Ÿ›ฃ๏ธ ๐Ÿ“ Estimated Driving Path w/ Waypoints:\n\r\n\r"
									."๐Ÿ“Œ Origin โžก๏ธ\n\r"
									."๐Ÿ•œ ".$loc_vars[3]["date"]
									."\n\r๐Ÿ”Ž ".$loc_vars[3]["class"]
									."\n\r\n\r๐Ÿ“Œ Destination โžก๏ธ\n\r"
									."๐Ÿ•œ ".$loc_vars[0]["date"]
									."\n\r๐Ÿ”Ž ".$loc_vars[0]["class"]
									."\n\r\n\rhttps://www.google.com/maps/dir/?api=1&origin="
									.explode(",", $loc_vars[3]["location"])[0]."%2C"
									.explode(",", $loc_vars[3]["location"])[1]."&waypoints="
									.explode(",", $loc_vars[2]["location"])[0]."%2C"
									.explode(",", $loc_vars[2]["location"])[1]."%7C"
									.explode(",", $loc_vars[1]["location"])[0]."%2C"
									.explode(",", $loc_vars[1]["location"])[1]."&destination="
									.explode(",", $loc_vars[0]["location"])[0]."%2C"
									.explode(",", $loc_vars[0]["location"])[1]
									."&travelmode=driving";
				}else{
					$message_body = "โ›” Insufficient data for the requested analysis.";
				}
				break;
			case "Terrain View":
				if(count($loc_vars) >= 1){
					$message_body = "โ›ฐ๏ธ Terrain View of the Latest Location:\n\r\n\r"
									."๐Ÿ“Œ Latest โžก๏ธ\n\r"
									."๐Ÿ•œ ".$loc_vars[0]["date"]
									."\n\r๐Ÿ”Ž ".$loc_vars[0]["class"]
									."\n\r\n\rhttps://www.google.com/maps/@?api=1&map_action=map¢er="
									.explode(",", $loc_vars[0]["location"])[0]."%2C"
									.explode(",", $loc_vars[0]["location"])[1]
									."&zoom=12&basemap=terrain&layer=bicycling";
				}else{
					$message_body = "โ›” Insufficient data for the requested analysis.";
				}
				break;
			case "Satellite View":
				if(count($loc_vars) >= 1){
					$message_body = "๐Ÿ›ฐ๏ธ Satellite View of the Latest Location:\n\r\n\r"
									."๐Ÿ“Œ Latest โžก๏ธ\n\r"
									."๐Ÿ•œ ".$loc_vars[0]["date"]
									."\n\r๐Ÿ”Ž ".$loc_vars[0]["class"]
									."\n\r\n\rhttps://www.google.com/maps/@?api=1&map_action=map¢er="
									.explode(",", $loc_vars[0]["location"])[0]."%2C"
									.explode(",", $loc_vars[0]["location"])[1]
									."&zoom=12&basemap=satellite&layer=traffic";
				}else{
					$message_body = "โ›” Insufficient data for the requested analysis.";
				}
				break;
			case "Street View":
				if(count($loc_vars) >= 1){
					$message_body = "๐Ÿš€ ๐ŸŒŽ Wander through the streets near the latest location:\n\r\n\r"
									."๐Ÿ“Œ Center โžก๏ธ\n\r"
									."๐Ÿ•œ ".$loc_vars[0]["date"]
									."\n\r๐Ÿ”Ž ".$loc_vars[0]["class"]
									."\n\r\n\rhttps://www.google.com/maps/@?api=1&map_action=pano&viewpoint="
									.explode(",", $loc_vars[0]["location"])[0]."%2C"
									.explode(",", $loc_vars[0]["location"])[1]
									."&heading=90";
				}else{
					$message_body = "โ›” Insufficient data for the requested analysis.";
				}
				break;
			default:
				$message_body = "๐Ÿค– ๐Ÿ‘‰ Please utilize the supported commands:\n\r\n\rโžก๏ธ Route Walking\n\r\n\rโžก๏ธ Route Bicycling\n\r\n\rโžก๏ธ Route Driving\n\r\n\rโžก๏ธ Show Waypoints\n\r\n\rโžก๏ธ Terrain View\n\r\n\rโžก๏ธ Satellite View\n\r\n\rโžก๏ธ Street View";
				break;
		}
		// Transmit the generated feedback.
		$this->Twilio_send_whatsapp($message_body);
	}

โญ Define the required MySQL database connection settings for the given server.


$server = array(
	"name" => "localhost",
	"username" => "root",
	"password" => "",
	"database" => "emergency_assistant"
);


$conn = mysqli_connect($server["name"], $server["username"], $server["password"], $server["database"]);

๐Ÿ“ index.php

โญ Include the class.php file.

โญ Define the _assistant object of the assistant class.


include_once "assets/class.php";

ini_set('display_errors',1);

// Define the new '_assistant' object:
$_assistant = new assistant();
$_assistant->__init__($conn);

โญ If requested by the user via an HTTP GET request, add or update the emergency contact information in the entries database table.


if(isset($_GET["action"]) && isset($_GET["to_phone"]) && isset($_GET["from_phone"]) && isset($_GET["emergency_phone"])){
	$_assistant->update_user_info($_GET["action"], $_GET["to_phone"], $_GET["from_phone"], $_GET["emergency_phone"]);
}

โญ Get the emergency class detected by XIAO ESP32S3, the current date, and the current device location data through the Android application.

โญ Insert a new data record with the received information into the database table.

โญ Then, notify the user's emergency contacts via SMS or WhatsApp, depending on the received class (command).


if(isset($_GET["action"]) && isset($_GET["date"]) && isset($_GET["location"]) && isset($_GET["class"])){
	// Insert the latest data record into the database table.
	$_assistant->save_results($_GET["action"], $_GET["date"], $_GET["location"], $_GET["class"]);
	// Notify the user's emergency contacts via SMS or WhatsApp, depending on the received class (command).
	$_assistant->notify_contacts($_GET["class"], $_GET["date"], $_GET["location"]);
}

โญ If the primary emergency contact transfers a message (inquiry) to the web application over WhatsApp via Twilio, generate and send thorough location inspections (via Google Maps) as feedback, depending on the inquired command.


if(isset($_POST["Body"])){
	// Generate and transfer thorough location inspections (from Google Maps) as feedback, depending on the given command.
	$_assistant->generate_feedback($_POST["Body"]);
}

project-image
Figure - 92.111


project-image
Figure - 92.112


project-image
Figure - 92.113


project-image
Figure - 92.114


project-image
Figure - 92.115

Step 4.1: Setting and running the web application

As explained earlier, Twilio requires a publicly available URL to redirect the incoming WhatsApp messages to a given webhook. Therefore, I employed my SSL-enabled server to host the web application. Since I needed to set a specific database table for the web application, you can follow my process to configure your database regardless of the selected hosting option.

#๏ธโƒฃ Open the phpMyAdmin tool to create a new database named emergency_assistant.

project-image
Figure - 92.116

#๏ธโƒฃ After adding the database successfully, go to the SQL section to create a MySQL database table named entries with the required data fields.


CREATE TABLE `entries`(		
	id int AUTO_INCREMENT PRIMARY KEY NOT NULL,
	to_phone varchar(255) NOT NULL,
	from_phone varchar(255) NOT NULL,
    emergency_phone varchar(255) NOT NULL,
    `date` varchar(255) NOT NULL,
    location varchar(255) NOT NULL,
	class varchar(255) NOT NULL
);

project-image
Figure - 92.117


project-image
Figure - 92.118


project-image
Figure - 92.119

After setting up and running the web application successfully:

๐Ÿ“ฒ โ™ฟ ๐ŸŒŽ The web application lets the user add or update emergency contact information via HTTP GET requests.

?action=new&to_phone=+905521111111&from_phone=+12566673691&emergency_phone=+90552111111

?action=update&to_phone=+90552111111&from_phone=+12566673691&emergency_phone=+90552111111

project-image
Figure - 92.120


project-image
Figure - 92.121


project-image
Figure - 92.122


project-image
Figure - 92.123

๐Ÿ“ฒ โ™ฟ ๐ŸŒŽ When the web application gets the model detection results and the current device location data with the date from the Android application via an HTTP GET request, it saves the received information to the database table and notifies the emergency contacts via WhatsApp or SMS (Twilio), depending on the received command.

?action=save&date=10/03/2023_06:19:27&location=40.20534,28.9602,144.06914&class=fine

project-image
Figure - 92.124


project-image
Figure - 92.125


project-image
Figure - 92.126

Step 5: Setting up XIAO ESP32S3 Sense and Round Display on Arduino IDE

Since the expansion board of XIAO ESP32S3 Sense supports reading and writing information from/to files on a microSD card, I decided to capture images with the built-in OV2640 camera on the expansion board and save them directly to the SD card without applying any additional procedures. Also, I employed XIAO ESP32S3 to communicate with the Android application over BLE to obtain user commands and transfer the model detection results.

Since I utilized XIAO ESP32S3 in combination with the XIAO round display, I needed to set XIAO ESP32S3 on the Arduino IDE, install the required libraries, and configure some default settings before proceeding with the following steps.

#๏ธโƒฃ To add the XIAO ESP32S3 board package to the Arduino IDE, navigate to File โžก Preferences and paste the URL below under Additional Boards Manager URLs.

https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json

project-image
Figure - 92.127

#๏ธโƒฃ Then, to install the required core, navigate to Tools โžก Board โžก Boards Manager and search for esp32.

project-image
Figure - 92.128

#๏ธโƒฃ After installing the core, navigate to Tools โžก Board โžก ESP32 Arduino and select XIAO_ESP32S3.

project-image
Figure - 92.129

#๏ธโƒฃ To ensure the built-in camera works properly without memory allocation errors, turn on the PSRAM function of the Arduino IDE โ€” the external PSRAM on the ESP32 chip.

project-image
Figure - 92.130

#๏ธโƒฃ Download and inspect the required libraries for XIAO ESP32S3 Sense and the XIAO round display:

ArduinoBLE | Download

TFT_eSPI | Download

lvgl | Download

#๏ธโƒฃ To configure the TFT_eSPI library for the XIAO round display, go to the TFT_eSPI folder in the root directory of the Arduino IDE (libraries).

#๏ธโƒฃ Then, open the User_Setup_Select.h file and change the default screen configuration to Seeed XIAO:

C:\Users\${UserName}\Documents\Arduino\libraries\TFT_eSPI\User_Setup_Select.h


(comment) #include <User_Setup.h> 
(uncomment) #include <User_Setups/Setup66_Seeed_XIAO_Round.h>

project-image
Figure - 92.131


project-image
Figure - 92.132

#๏ธโƒฃ To configure the lvgl library for the XIAO round display, download the official lv_conf.h file from here.

#๏ธโƒฃ Then, copy the lv_conf.h file to the root directory of the Arduino IDE (libraries).

C:\Users\${UserName}\Documents\Arduino\libraries

project-image
Figure - 92.133


project-image
Figure - 92.134

#๏ธโƒฃ Since the built-in microSD card module on the expansion board supports FAT32 microSD cards up to 32GB, format the microSD card to FAT32 format if not compatible.

project-image
Figure - 92.135

#๏ธโƒฃ To be able to display images on the round display, convert image files to a C/C++ array format. I decided to utilize an online converter to save image files in the XBM format, a monochrome bitmap format in which data is stored as a C data array.

#๏ธโƒฃ Then, save all the converted C arrays in the XBM format to the logo.h file.

project-image
Figure - 92.136


project-image
Figure - 92.137

Step 6: Capturing customized keychain (token) images w/ the built-in OV2640 camera

After setting XIAO ESP32S3 with the round display and installing the required libraries, I programmed XIAO ESP32S3 to capture raw image buffers, convert the captured buffers to JPG files, and save them as samples to the SD card on the expansion board.

Since I needed to add emergency classes as labels to the file names of each sample while collecting data to create a valid data set for the object detection model, I decided to utilize the Android application to transfer user commands to XIAO ESP32S3 over BLE to capture a sample and save it to the SD card with the selected class. In this regard, I was able to obviate the need for adding extra components to the assistive device, enlarging the main case dimensions. You can get more detailed information regarding the features of the Android application in the following steps.

Since different UUID sets, a 128-bit value used to specifically identify an object or entity, are required to assign services and characteristics for a stable BLE connection, it is crucial to generate individualized UUIDs with an online UUID generator. After generating your UUIDs, you can update the given UUIDs, as shown below.

You can download the AI_driven_BLE_Travel_Emergency_Assistant.ino file to try and inspect the code for capturing images (samples) and saving them to the SD card with unique sample numbers.

โญ Include the required libraries.


#include <Arduino.h>
#include <ArduinoBLE.h>
#include <TFT_eSPI.h>
#include <SPI.h>
#include "esp_camera.h"
#include "FS.h"
#include "SD.h"
#include "SPI.h"

โญ Add the logo.h file, consisting of all the converted icons (C arrays) to be shown on the XIAO round display.


#include "logo.h"

โญ Create the BLE service and data characteristics. Then, allow the remote device (central) to read, write, and notify.


BLEService Emergency_Assistant("23bc2b0f-3081-402e-8ba2-300280c91740");

// Create data characteristics and allow the remote device (central) to write, read, and notify:
BLEFloatCharacteristic detection_Characteristic("23bc2b0f-3081-402e-8ba2-300280c91741", BLERead | BLENotify);
BLEByteCharacteristic class_Characteristic("23bc2b0f-3081-402e-8ba2-300280c91742", BLERead | BLEWrite);

โญ Define the pin configuration of the built-in OV2640 camera on the XIAO ESP32S3 Sense expansion board.


#define PWDN_GPIO_NUM     -1
#define RESET_GPIO_NUM    -1
#define XCLK_GPIO_NUM     10
#define SIOD_GPIO_NUM     40
#define SIOC_GPIO_NUM     39
#define Y9_GPIO_NUM       48
#define Y8_GPIO_NUM       11
#define Y7_GPIO_NUM       12
#define Y6_GPIO_NUM       14
#define Y5_GPIO_NUM       16
#define Y4_GPIO_NUM       18
#define Y3_GPIO_NUM       17
#define Y2_GPIO_NUM       15
#define VSYNC_GPIO_NUM    38
#define HREF_GPIO_NUM     47
#define PCLK_GPIO_NUM     13
#define LED_GPIO_NUM      21

โญ Utilize the SD card reader on the expansion board without cutting the J3 solder bridge.


#define SD_CS_PIN 21 // #define SD_CS_PIN D2 // XIAO Round Display SD Card Reader

โญ Define the XIAO round display object and the screen dimensions.


TFT_eSPI tft = TFT_eSPI();
const int img_width = 240;
const int img_height = 240;

โญ Assign the configured pins of the built-in OV2640 camera and define the frame (buffer) settings.


  camera_config_t config;
  config.ledc_channel = LEDC_CHANNEL_0;
  config.ledc_timer = LEDC_TIMER_0;
  config.pin_d0 = Y2_GPIO_NUM;
  config.pin_d1 = Y3_GPIO_NUM;
  config.pin_d2 = Y4_GPIO_NUM;
  config.pin_d3 = Y5_GPIO_NUM;
  config.pin_d4 = Y6_GPIO_NUM;
  config.pin_d5 = Y7_GPIO_NUM;
  config.pin_d6 = Y8_GPIO_NUM;
  config.pin_d7 = Y9_GPIO_NUM;
  config.pin_xclk = XCLK_GPIO_NUM;
  config.pin_pclk = PCLK_GPIO_NUM;
  config.pin_vsync = VSYNC_GPIO_NUM;
  config.pin_href = HREF_GPIO_NUM;
  config.pin_sscb_sda = SIOD_GPIO_NUM;
  config.pin_sscb_scl = SIOC_GPIO_NUM;
  config.pin_pwdn = PWDN_GPIO_NUM;
  config.pin_reset = RESET_GPIO_NUM;
  config.xclk_freq_hz = 10000000; // Set XCLK_FREQ_HZ as 10KHz to avoid the EV-VSYNC-OVF error.
  config.frame_size = FRAMESIZE_240X240; // FRAMESIZE_UXGA, FRAMESIZE_SVGA
  config.pixel_format = PIXFORMAT_RGB565; // PIXFORMAT_JPEG
  config.grab_mode = CAMERA_GRAB_WHEN_EMPTY;
  config.fb_location = CAMERA_FB_IN_PSRAM;
  config.jpeg_quality = 12;
  config.fb_count = 2;

โญ Initialize the OV2640 camera.


  esp_err_t err = esp_camera_init(&config);
  if (err != ESP_OK) {
    Serial.printf("Camera init failed with error 0x%x", err);
    return;
  }
  // If successful:
  Serial.println("OV2640 camera initialized successfully!");
  camera_activated = true;

#๏ธโƒฃ Note: Do not forget to initialize the round display (TFT screen) object before the SD card object to avoid compiling errors on the Arduino IDE.

โญ Initialize the XIAO round display (TFT screen).


  tft.init();
  tft.setRotation(2);
  tft.fillScreen(TFT_WHITE);

โญ Initialize the built-in microSD card module on the expansion board.


  if(!SD.begin(SD_CS_PIN)){
    Serial.println("SD Card => No module found!");
    return;
  }
  // If successful:
  Serial.println("SD card initialized successfully!");
  sd_activated = true;

โญ Check the BLE initialization status and print the XIAO ESP32S3 address information on the serial monitor.


  while(!BLE.begin()){
    Serial.println("BLE initialization is failed!");
  }
  Serial.println("\nBLE initialization is successful!\n");
  // Print this peripheral device's address information:
  Serial.print("MAC Address: "); Serial.println(BLE.address());
  Serial.print("Service UUID Address: "); Serial.println(Emergency_Assistant.uuid()); Serial.println();

โญ Set the local name (BLE Emergency Assistant) for XIAO ESP32S3 and the UUID for the advertised (transmitted) service.

โญ Add the given data characteristics to the service. Then, add the given service to the advertising device.

โญ Assign event handlers for connected and disconnected devices to/from XIAO ESP32S3.

โญ Assign event handlers for the data characteristics modified (written) by the central device (via the Android application). In this regard, obtain the transferred (written) commands from the Android application over BLE.

โญ Finally, start advertising (broadcasting) information.


  BLE.setLocalName("BLE Emergency Assistant");
  // Set the UUID for the service this peripheral advertises:
  BLE.setAdvertisedService(Emergency_Assistant);

  // Add the given data characteristics to the service:
  Emergency_Assistant.addCharacteristic(detection_Characteristic);
  Emergency_Assistant.addCharacteristic(class_Characteristic);

  // Add the given service to the advertising device:
  BLE.addService(Emergency_Assistant);

  // Assign event handlers for connected and disconnected devices to/from this peripheral:
  BLE.setEventHandler(BLEConnected, blePeripheralConnectHandler);
  BLE.setEventHandler(BLEDisconnected, blePeripheralDisconnectHandler);

  // Assign event handlers for the data characteristics modified (written) by the central device (via the Android application).
  // In this regard, obtain the transferred (written) commands from the Android application over BLE.
  class_Characteristic.setEventHandler(BLEWritten, get_selected_class);

  // Start advertising:
  BLE.advertise();
  Serial.println("Bluetooth device active, waiting for connections...");

โญ If the built-in OV2640 camera and the microSD card module on the expansion board are initialized successfully:

โญ Capture a frame (RGB565 buffer) with the OV2640 camera.

โญ Display the captured frame on the XIAO round display.


  if(camera_activated && sd_activated){
    // Capture a frame (RGB565 buffer) with the OV2640 camera.
    camera_fb_t *fb = esp_camera_fb_get();
    if(!fb){ Serial.println("Camera => Cannot capture the frame!"); return; }

    // Display the captured frame on the XIAO round display.
    tft.startWrite();
    tft.setAddrWindow(0, 0, img_width, img_height);
    tft.pushColors(fb->buf, fb->len);
    tft.endWrite();
	
	...
	

โญ If the user touches the XIAO round display, show the current sample numbers for each emergency class on the SD card.


	...

    if(display_is_pressed()){
      String f_n = "Fine: " + String(sample_number[0]);
      String d_n = "Danger: " + String(sample_number[1]);
      String a_n = "Assist: " + String(sample_number[2]);
      String s_n = "Stolen: " + String(sample_number[3]);
      String c_n = "Call: " + String(sample_number[4]);
      int x = 75, y = 25, d = 40;
      tft.setTextSize(2);
      tft.setTextColor(TFT_WHITE, TFT_GREEN, false);
      tft.drawString(f_n.c_str(), x, y, 2);
      tft.setTextColor(TFT_WHITE, TFT_ORANGE, false);
      tft.drawString(d_n.c_str(), x, y+d, 2);
      tft.setTextColor(TFT_WHITE, TFT_SILVER, false);
      tft.drawString(a_n.c_str(), x, y+(2*d), 2);
      tft.setTextColor(TFT_WHITE, TFT_NAVY, false);
      tft.drawString(s_n.c_str(), x, y+(3*d), 2);
      tft.setTextColor(TFT_WHITE, TFT_GREENYELLOW, false);
      tft.drawString(c_n.c_str(), x, y+(4*d), 2);
      delay(1000);
    }
	
	...
	

โญ In the save_image function:

โญ Create a new file with the given file name on the SD card.

โญ Save the passed image buffer to the created file.


void save_image(fs::FS &fs, const char *file_name, uint8_t *data, size_t len){
  // Create a new file on the SD card.
  File file = fs.open(file_name, FILE_WRITE);
  if(!file){ Serial.println("SD Card => Cannot create file!"); return; }
  // Save the given image buffer to the created file on the SD card.
  if(file.write(data, len) == len){
      Serial.printf("SD Card => IMG saved: %s\n", file_name);
  }else{
      Serial.println("SD Card => Cannot save the given image!");
  }
  file.close();    
}

โญ In the get_selected_class function:

โญ Get the recently transferred commands over BLE.

โญ Capture a new frame (RGB565 buffer) with the OV2640 camera.

โญ Convert the captured RGB565 buffer to a JPEG buffer by executing the built-in frame2jpg function.

โญ Depending on the selected emergency class:

โญ Generate the file name with the current sample number of the given class.

โญ Save the converted frame as a sample to the SD card.

โญ Notify the user on the XIAO round display.

โญ Then, increase the sample number of the given class.

โญ Finally, release the image buffers.


void get_selected_class(BLEDevice central, BLECharacteristic characteristic){
  // Get the recently transferred commands over BLE.
  if(characteristic.uuid() == class_Characteristic.uuid()){
    Serial.print("\nSelected Class => "); Serial.println(class_Characteristic.value());
    // Capture a new frame (RGB565 buffer) with the OV2640 camera.
    camera_fb_t *fb = esp_camera_fb_get();
    if(!fb){ Serial.println("Camera => Cannot capture the frame!"); return; }
    // Convert the captured RGB565 buffer to JPEG buffer.
    size_t con_len;
    uint8_t *con_buf = NULL;
    if(!frame2jpg(fb, 10, &con_buf, &con_len)){ Serial.println("Camera => Cannot convert the RGB565 buffer to JPEG!"); return; }
    // Depending on the selected emergency class, save the converted frame as a sample to the SD card.
    String file_name = "";
    switch(class_Characteristic.value()){
      case 0:
        // Save the given frame as an image file.
        file_name = "/" + classes[0] + "_" + String(sample_number[0]) + ".jpg";
        save_image(SD, file_name.c_str(), con_buf, con_len);
        // Notify the user on the XIAO round display.
        tft.drawXBitmap((img_width/2)-(save_width/2), 2, save_bits, save_width, save_height, TFT_BLACK);
        tft.drawXBitmap((img_width/2)-(fine_width/2), (img_height/2)-(fine_height/2), fine_bits, fine_width, fine_height, TFT_GREEN);
        // Increase the sample number.
        sample_number[0]+=1;
        delay(2000);
      break;
      case 1:
        // Save the given frame as an image file.
        file_name = "/" + classes[1] + "_" + String(sample_number[1]) + ".jpg";
        save_image(SD, file_name.c_str(), con_buf, con_len);
        // Notify the user on the XIAO round display.
        tft.drawXBitmap((img_width/2)-(save_width/2), 2, save_bits, save_width, save_height, TFT_BLACK);
        tft.drawXBitmap((img_width/2)-(danger_width/2), (img_height/2)-(danger_height/2), danger_bits, danger_width, danger_height, TFT_ORANGE);
        // Increase the sample number.
        sample_number[1]+=1;
        delay(2000);
      break;
      case 2:
        // Save the given frame as an image file.
        file_name = "/" + classes[2] + "_" + String(sample_number[2]) + ".jpg";
        save_image(SD, file_name.c_str(), con_buf, con_len);
        // Notify the user on the XIAO round display.
        tft.drawXBitmap((img_width/2)-(save_width/2), 2, save_bits, save_width, save_height, TFT_BLACK);
        tft.drawXBitmap((img_width/2)-(assist_width/2), (img_height/2)-(assist_height/2), assist_bits, assist_width, assist_height, TFT_SILVER);
        // Increase the sample number.
        sample_number[2]+=1;
        delay(2000);
      break;
      case 3:
        // Save the given frame as an image file.
        file_name = "/" + classes[3] + "_" + String(sample_number[3]) + ".jpg";
        save_image(SD, file_name.c_str(), con_buf, con_len);
        // Notify the user on the XIAO round display.
        tft.drawXBitmap((img_width/2)-(save_width/2), 2, save_bits, save_width, save_height, TFT_BLACK);
        tft.drawXBitmap((img_width/2)-(stolen_width/2), (img_height/2)-(stolen_height/2), stolen_bits, stolen_width, stolen_height, TFT_NAVY);
        // Increase the sample number.
        sample_number[3]+=1;
        delay(2000);
      break;
      case 4:
        // Save the given frame as an image file.
        file_name = "/" + classes[4] + "_" + String(sample_number[4]) + ".jpg";
        save_image(SD, file_name.c_str(), con_buf, con_len);
        // Notify the user on the XIAO round display.
        tft.drawXBitmap((img_width/2)-(save_width/2), 2, save_bits, save_width, save_height, TFT_BLACK);
        tft.drawXBitmap((img_width/2)-(call_width/2), (img_height/2)-(call_height/2), call_bits, call_width, call_height, TFT_GREENYELLOW);
        // Increase the sample number.
        sample_number[4]+=1;
        delay(2000);
      break;
    }
    // Release the image buffers.
    free(con_buf);
    esp_camera_fb_return(fb);
  }
}

project-image
Figure - 92.138


project-image
Figure - 92.139


project-image
Figure - 92.140


project-image
Figure - 92.141


project-image
Figure - 92.142

Step 6.1: Saving the captured images as samples via the Android application

In any Bluetoothยฎ Low Energy (also referred to as Bluetoothยฎ LE or BLE) connection, devices can have one of these two roles: the central and the peripheral. A peripheral device (also called a client) advertises or broadcasts information about itself to devices in its range, while a central device (also called a server) performs scans to listen for devices broadcasting information. You can get more information regarding BLE connections and procedures, such as services and characteristics, from here.

As explained earlier, to avoid latency or packet loss while advertising (transmitting) model detection results and receiving user commands from the Android application over BLE, I utilized an individual float data characteristic for the advertised information and a byte data characteristic for the incoming information.

After executing the AI_driven_BLE_Travel_Emergency_Assistant.ino file on XIAO ESP32S3:

๐Ÿ“ฒ โ™ฟ ๐ŸŒŽ The Android application (BLE Travel Emergency Assistant) allows the user to scan BLE devices and communicate with XIAO ESP32S3, named BLE Emergency Assistant, over BLE.

๐Ÿ“ฒ โ™ฟ ๐ŸŒŽ If the Scan button is pressed, the Android application searches for compatible BLE devices and shows them as a list.

๐Ÿ“ฒ โ™ฟ ๐ŸŒŽ If the Stop button is pressed, the Android application halts the scanning process.

project-image
Figure - 92.143


project-image
Figure - 92.144

๐Ÿ“ฒ โ™ฟ ๐ŸŒŽ If the Connect button is pressed, the Android application attempts to connect to the selected BLE device.

project-image
Figure - 92.145


project-image
Figure - 92.146

๐Ÿ“ฒ โ™ฟ ๐ŸŒŽ When the GPS information is available, the Android application updates and displays location variables (latitude, longitude, altitude) automatically.

project-image
Figure - 92.147

๐Ÿ“ฒ โ™ฟ ๐ŸŒŽ After connecting to XIAO ESP32S3 over BLE successfully, the Android application lets the user select an emergency class via the spinner:

project-image
Figure - 92.148

๐Ÿ“ฒ โ™ฟ ๐ŸŒŽ When the user selects the Fine emergency class via the spinner and clicks the Capture Sample button, the Android application transmits the selected class (byte characteristic) to XIAO ESP32S3.

๐Ÿ“ฒ โ™ฟ ๐ŸŒŽ When XIAO ESP32S3 receives the selected class (Fine), it shows the assigned class icon and the Save logo on the XIAO round display to notify the user.

๐Ÿ“ฒ โ™ฟ ๐ŸŒŽ Then, XIAO ESP32S3 captures an image via the built-in OV2640 camera on the expansion board and saves the captured image, by adding the current sample number to the file name, to the SD card.

๐Ÿ“ฒ โ™ฟ ๐ŸŒŽ Finally, XIAO ESP32S3 updates the sample number of the selected class.

project-image
Figure - 92.149


project-image
Figure - 92.150

๐Ÿ“ฒ โ™ฟ ๐ŸŒŽ When the user selects the Danger emergency class via the spinner and clicks the Capture Sample button, the Android application transmits the selected class (byte characteristic) to XIAO ESP32S3.

๐Ÿ“ฒ โ™ฟ ๐ŸŒŽ When XIAO ESP32S3 receives the selected class (Danger), it shows the assigned class icon and the Save logo on the XIAO round display to notify the user.

๐Ÿ“ฒ โ™ฟ ๐ŸŒŽ Then, XIAO ESP32S3 captures an image via the built-in OV2640 camera on the expansion board and saves the captured image, by adding the current sample number to the file name, to the SD card.

๐Ÿ“ฒ โ™ฟ ๐ŸŒŽ Finally, XIAO ESP32S3 updates the sample number of the selected class.

project-image
Figure - 92.151


project-image
Figure - 92.152

๐Ÿ“ฒ โ™ฟ ๐ŸŒŽ When the user selects the Assist emergency class via the spinner and clicks the Capture Sample button, the Android application transmits the selected class (byte characteristic) to XIAO ESP32S3.

๐Ÿ“ฒ โ™ฟ ๐ŸŒŽ When XIAO ESP32S3 receives the selected class (Assist), it shows the assigned class icon and the Save logo on the XIAO round display to notify the user.

๐Ÿ“ฒ โ™ฟ ๐ŸŒŽ Then, XIAO ESP32S3 captures an image via the built-in OV2640 camera on the expansion board and saves the captured image, by adding the current sample number to the file name, to the SD card.

๐Ÿ“ฒ โ™ฟ ๐ŸŒŽ Finally, XIAO ESP32S3 updates the sample number of the selected class.

project-image
Figure - 92.153


project-image
Figure - 92.154

๐Ÿ“ฒ โ™ฟ ๐ŸŒŽ When the user selects the Stolen emergency class via the spinner and clicks the Capture Sample button, the Android application transmits the selected class (byte characteristic) to XIAO ESP32S3.

๐Ÿ“ฒ โ™ฟ ๐ŸŒŽ When XIAO ESP32S3 receives the selected class (Stolen), it shows the assigned class icon and the Save logo on the XIAO round display to notify the user.

๐Ÿ“ฒ โ™ฟ ๐ŸŒŽ Then, XIAO ESP32S3 captures an image via the built-in OV2640 camera on the expansion board and saves the captured image, by adding the current sample number to the file name, to the SD card.

๐Ÿ“ฒ โ™ฟ ๐ŸŒŽ Finally, XIAO ESP32S3 updates the sample number of the selected class.

project-image
Figure - 92.155


project-image
Figure - 92.156

๐Ÿ“ฒ โ™ฟ ๐ŸŒŽ When the user selects the Call emergency class via the spinner and clicks the Capture Sample button, the Android application transmits the selected class (byte characteristic) to XIAO ESP32S3.

๐Ÿ“ฒ โ™ฟ ๐ŸŒŽ When XIAO ESP32S3 receives the selected class (Call), it shows the assigned class icon and the Save logo on the XIAO round display to notify the user.

๐Ÿ“ฒ โ™ฟ ๐ŸŒŽ Then, XIAO ESP32S3 captures an image via the built-in OV2640 camera on the expansion board and saves the captured image, by adding the current sample number to the file name, to the SD card.

๐Ÿ“ฒ โ™ฟ ๐ŸŒŽ Finally, XIAO ESP32S3 updates the sample number of the selected class.

project-image
Figure - 92.157


project-image
Figure - 92.158

๐Ÿ“ฒ โ™ฟ ๐ŸŒŽ The color schemes of the assigned icons of the emergency classes are compatible with the actual color codes of the printed keychains (tokens).

๐Ÿ“ฒ โ™ฟ ๐ŸŒŽ If the user touches the XIAO round display, XIAO ESP32S3 shows the current sample numbers for each emergency class on the SD card individually.

project-image
Figure - 92.159


project-image
Figure - 92.160

๐Ÿ“ฒ โ™ฟ ๐ŸŒŽ Also, XIAO ESP32S3 prints notifications and reports on the serial monitor for debugging.

project-image
Figure - 92.161


project-image
Figure - 92.162


project-image
Figure - 92.163

๐Ÿ“ฒ โ™ฟ ๐ŸŒŽ If the Disconnect button is pressed, the Android application disconnects from the connected BLE device and stops the data transfer.

project-image
Figure - 92.164

After employing the Android application to capture images of specific keychains (tokens) and save them to the SD card, I constructed my data set for the object detection model.

project-image
Figure - 92.165


project-image
Figure - 92.166

Step 7: Building an object detection (FOMO) model with Edge Impulse

When I completed capturing images of customized keychains (tokens) and storing the captured samples on the SD card, I started to work on my object detection (FOMO) model to detect keychains individually so as to inform emergency contacts via WhatsApp or SMS immediately.

Since Edge Impulse supports almost every microcontroller and development board due to its model deployment options, I decided to utilize Edge Impulse to build my object detection model. Also, Edge Impulse provides an elaborate machine learning algorithm (FOMO) for running more accessible and faster object detection models on edge devices such as XIAO ESP32S3.

Edge Impulse FOMO (Faster Objects, More Objects) is a novel machine learning algorithm that brings object detection to highly constrained devices. FOMO models can count objects, find the location of the detected objects in an image, and track multiple objects in real time, requiring up to 30x less processing power and memory than MobileNet SSD or YOLOv5.

Even though Edge Impulse supports JPG or PNG files to upload as samples directly, each target object in a training or testing sample needs to be labeled manually. Therefore, I needed to follow the steps below to format my data set so as to train my object detection model accurately:

Since I added emergency classes and assigned sample numbers to the file names while capturing images of customized keychains, I preprocessed my data set effortlessly to label each target object on an image sample on Edge Impulse by utilizing the given emergency classes:

Plausibly, Edge Impulse allows building predictive models optimized in size and accuracy automatically and deploying the trained model as a supported firmware (Arduino library) for XIAO ESP32S3. Therefore, after scaling (resizing) and preprocessing my data set to label target objects, I was able to build an accurate object detection model to recognize customized keychains (tokens), which runs on XIAO ESP32S3 without any additional requirements.

You can inspect my object detection (FOMO) model on Edge Impulse as a public project.

Step 7.1: Uploading images (samples) to Edge Impulse and labeling objects

After collecting training and testing image samples, I uploaded them to my project on Edge Impulse. Then, I labeled each target object on the image samples.

#๏ธโƒฃ First of all, sign up for Edge Impulse and create a new project.

project-image
Figure - 92.167

#๏ธโƒฃ To be able to label image samples manually on Edge Impulse for object detection models, go to Dashboard โžก Project info โžก Labeling method and select Bounding boxes (object detection).

project-image
Figure - 92.168

#๏ธโƒฃ Navigate to the Data acquisition page and click the Upload data icon.

project-image
Figure - 92.169

#๏ธโƒฃ Then, choose the data category (training or testing), select image files, and click the Upload data button.

project-image
Figure - 92.170


project-image
Figure - 92.171


project-image
Figure - 92.172


project-image
Figure - 92.173

After uploading my data set successfully, I labeled each target object on the image samples by utilizing the emergency classes. In Edge Impulse, labeling an object is as easy as dragging a box around it and entering a class. Also, Edge Impulse runs a tracking algorithm in the background while labeling objects, so it moves the bounding boxes automatically for the same target objects in different images.

#๏ธโƒฃ Go to Data acquisition โžก Labeling queue (Object detection labeling). It shows all unlabeled items (training and testing) remaining in the given data set.

#๏ธโƒฃ Finally, select an unlabeled item, drag bounding boxes around target objects, click the Save labels button, and repeat this process until all samples have at least one labeled target object.

project-image
Figure - 92.174


project-image
Figure - 92.175


project-image
Figure - 92.176


project-image
Figure - 92.177


project-image
Figure - 92.178


project-image
Figure - 92.179


project-image
Figure - 92.180


project-image
Figure - 92.181


project-image
Figure - 92.182


project-image
Figure - 92.183


project-image
Figure - 92.184


project-image
Figure - 92.185


project-image
Figure - 92.186


project-image
Figure - 92.187


project-image
Figure - 92.188


project-image
Figure - 92.189


project-image
Figure - 92.190


project-image
Figure - 92.191


project-image
Figure - 92.192

Step 7.2: Training the FOMO model on the customized keychain images

After labeling target objects on my training and testing samples successfully, I designed an impulse and trained it on detecting different keychains (tokens).

An impulse is a custom neural network model in Edge Impulse. I created my impulse by employing the Image preprocessing block and the Object Detection (Images) learning block.

The Image preprocessing block optionally turns the input image format to grayscale and generates a features array from the raw image.

The Object Detection (Images) learning block represents a machine learning algorithm that detects objects on the given image, distinguished between model labels.

#๏ธโƒฃ Go to the Create impulse page and set image width and height parameters to 120. Then, select the resize mode parameter as Fit shortest axis so as to scale (resize) given training and testing image samples.

#๏ธโƒฃ Select the Image preprocessing block and the Object Detection (Images) learning block. Finally, click Save Impulse.

project-image
Figure - 92.193

#๏ธโƒฃ Before generating features for the object detection model, go to the Image page and set the Color depth parameter as Grayscale. Then, click Save parameters.

project-image
Figure - 92.194

#๏ธโƒฃ After saving parameters, click Generate features to apply the Image preprocessing block to training image samples.

project-image
Figure - 92.195


project-image
Figure - 92.196

#๏ธโƒฃ After generating features successfully, navigate to the Object detection page and click Start training.

project-image
Figure - 92.197


project-image
Figure - 92.198

According to my experiments with my object detection model, I modified the neural network settings and architecture to build an object detection model with high accuracy and validity:

๐Ÿ“Œ Neural network settings:

๐Ÿ“Œ Neural network architecture:

After generating features and training my FOMO model with training samples, Edge Impulse evaluated the F1 score (accuracy) as 100%.

The F1 score (accuracy) is approximately 100% due to the modest volume of training samples of unique keychains (tokens) with distinct color schemes, depending on the selected filament colors. Since the model can recognize these individual colors precisely, it performs excellently with a small validation set. Therefore, I am still collecting samples to improve my data set.

project-image
Figure - 92.199

Step 7.3: Evaluating the model accuracy and deploying the model

After building and training my object detection model, I tested its accuracy and validity by utilizing testing image samples.

The evaluated accuracy of the model is 73.33%.

#๏ธโƒฃ To validate the trained model, go to the Model testing page and click Classify all.

project-image
Figure - 92.200


project-image
Figure - 92.201


project-image
Figure - 92.202

After validating my object detection model, I deployed it as a fully optimized and customizable Arduino library.

#๏ธโƒฃ To deploy the validated model as an Arduino library, navigate to the Deployment page and search for Arduino library.

#๏ธโƒฃ Then, choose the Quantized (int8) optimization option to get the best performance possible while running the deployed model.

#๏ธโƒฃ Finally, click Build to download the model as an Arduino library.

project-image
Figure - 92.203


project-image
Figure - 92.204


project-image
Figure - 92.205

Step 8: Setting up the Edge Impulse FOMO model on XIAO ESP32S3 Sense

After building, training, and deploying my object detection model as an Arduino library on Edge Impulse, I needed to upload the generated Arduino library to XIAO ESP32S3 to run the model directly so as to create an accessible assistive device operating with minimal latency, memory usage, and power consumption.

Since Edge Impulse optimizes and formats signal processing, configuration, and learning blocks into a single package while deploying models as Arduino libraries, I was able to import my model effortlessly to run inferences.

#๏ธโƒฃ After downloading the model as an Arduino library in the ZIP file format, go to Sketch โžก Include Library โžก Add .ZIP Library...

#๏ธโƒฃ Then, include the AI-driven_BLE_Travel_Emergency_Assistant_inferencing.h file to import the Edge Impulse object detection model.


#include <AI-driven_BLE_Travel_Emergency_Assistant_inferencing.h>

After importing my model successfully to the Arduino IDE, I programmed XIAO ESP32S3 to run inferences to detect customized keychains (tokens) every 30 seconds automatically.

Then, I employed XIAO ESP32S3 to transfer the model detection result (emergency class) to the Android application via BLE after running an inference successfully.

Also, as explained earlier, XIAO ESP32S3 can receive commands from the Android application via BLE to collect and save image samples simultaneously.

Since I utilized the same code file to execute all device features consecutively, you can inspect the overlapping functions and instructions in Step 6.

You can download the AI_driven_BLE_Travel_Emergency_Assistant.ino file to try and inspect the code for running an Edge Impulse object detection model and sending the model detection results via BLE.

โญ Include the built-in Edge Impulse image functions.

โญ Define the required parameters to run an inference with the Edge Impulse FOMO model.


#include "edge-impulse-sdk/dsp/image/image.hpp"

// Define the required parameters to run an inference with the Edge Impulse FOMO model.
#define CAPTURED_IMAGE_BUFFER_COLS        240
#define CAPTURED_IMAGE_BUFFER_ROWS        240
#define EI_CAMERA_FRAME_BYTE_SIZE         3
uint8_t *ei_camera_capture_out;

โญ Define the emergency class names.


String classes[] = {"Fine", "Danger", "Assist", "Stolen", "Call"};

โญ In the run_inference_to_make_predictions function:

โญ Summarize the Edge Impulse FOMO model inference settings and print them on the serial monitor.

โญ Convert the passed RGB565 raw image buffer to an RGB888 image buffer by utilizing the built-in fmt2rgb888 function.

โญ Depending on the given model, resize the converted RGB888 buffer by utilizing built-in Edge Impulse image functions.

โญ Create a signal object from the converted and resized image buffer.

โญ Run an inference.

โญ Print the inference timings on the serial monitor.

โญ Obtain labels (classes) and bounding box measurements for each detected target object on the given image buffer.

โญ Print the model detection results on the serial monitor.

โญ Get the imperative predicted label (class).

โญ Print inference anomalies on the serial monitor, if any.

โญ Release the image buffers.


void run_inference_to_make_predictions(camera_fb_t *fb){
  // Summarize the Edge Impulse FOMO model inference settings (from model_metadata.h):
  ei_printf("\nInference settings:\n");
  ei_printf("\tImage resolution: %dx%d\n", EI_CLASSIFIER_INPUT_WIDTH, EI_CLASSIFIER_INPUT_HEIGHT);
  ei_printf("\tFrame size: %d\n", EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE);
  ei_printf("\tNo. of classes: %d\n", sizeof(ei_classifier_inferencing_categories) / sizeof(ei_classifier_inferencing_categories[0]));
  
  if(fb){
    // Convert the captured RGB565 buffer to RGB888 buffer.
    ei_camera_capture_out = (uint8_t*)malloc(CAPTURED_IMAGE_BUFFER_COLS * CAPTURED_IMAGE_BUFFER_ROWS * EI_CAMERA_FRAME_BYTE_SIZE);
    if(!fmt2rgb888(fb->buf, fb->len, PIXFORMAT_RGB565, ei_camera_capture_out)){ Serial.println("Camera => Cannot convert the RGB565 buffer to RGB888!"); return; }

    // Depending on the given model, resize the converted RGB888 buffer by utilizing built-in Edge Impulse functions.
    ei::image::processing::crop_and_interpolate_rgb888(
      ei_camera_capture_out, // Output image buffer, can be same as input buffer
      CAPTURED_IMAGE_BUFFER_COLS,
      CAPTURED_IMAGE_BUFFER_ROWS,
      ei_camera_capture_out,
      EI_CLASSIFIER_INPUT_WIDTH,
      EI_CLASSIFIER_INPUT_HEIGHT);

    // Run inference:
    ei::signal_t signal;
    // Create a signal object from the converted and resized image buffer.
    signal.total_length = EI_CLASSIFIER_INPUT_WIDTH * EI_CLASSIFIER_INPUT_HEIGHT;
    signal.get_data = &ei_camera_cutout_get_data;
    // Run the classifier:
    ei_impulse_result_t result = { 0 };
    EI_IMPULSE_ERROR _err = run_classifier(&signal, &result, false);
    if(_err != EI_IMPULSE_OK){
      ei_printf("ERR: Failed to run classifier (%d)\n", _err);
      return;
    }

    // Print the inference timings on the serial monitor.
    ei_printf("\nPredictions (DSP: %d ms., Classification: %d ms., Anomaly: %d ms.): \n",
        result.timing.dsp, result.timing.classification, result.timing.anomaly);

    // Obtain the object detection results and bounding boxes for the detected labels (classes). 
    bool bb_found = result.bounding_boxes[0].value > 0;
    for(size_t ix = 0; ix < EI_CLASSIFIER_OBJECT_DETECTION_COUNT; ix++){
      auto bb = result.bounding_boxes[ix];
      if(bb.value == 0) continue;
      // Print the calculated bounding box measurements on the serial monitor.
      ei_printf("    %s (", bb.label);
      ei_printf_float(bb.value);
      ei_printf(") [ x: %u, y: %u, width: %u, height: %u ]\n", bb.x, bb.y, bb.width, bb.height);
      // Get the predicted label (class).
      if(bb.label == "fine") predicted_class = 0;
      if(bb.label == "danger") predicted_class = 1;
      if(bb.label == "assist") predicted_class = 2;
      if(bb.label == "stolen") predicted_class = 3;
      if(bb.label == "call") predicted_class = 4;
      Serial.print("\nPredicted Class: "); Serial.println(bb.label);
    }
    if(!bb_found) ei_printf("    No objects found!\n");

    // Detect anomalies, if any:
    #if EI_CLASSIFIER_HAS_ANOMALY == 1
      ei_printf("Anomaly: ");
      ei_printf_float(result.anomaly);
      ei_printf("\n");
    #endif 

    // Release the image buffers.
    free(ei_camera_capture_out);
  }
}

โญ In the ei_camera_cutout_get_data function:

โญ Convert the passed image data (buffer) to the out_ptr format required by the Edge Impulse FOMO model.

โญ Since the given image data is already converted to an RGB888 buffer and resized, directly recalculate the given offset into pixel index.


static int ei_camera_cutout_get_data(size_t offset, size_t length, float *out_ptr){
  // Convert the given image data (buffer) to the out_ptr format required by the Edge Impulse FOMO model.
  size_t pixel_ix = offset * 3;
  size_t pixels_left = length;
  size_t out_ptr_ix = 0;
  // Since the image data is converted to an RGB888 buffer, directly recalculate offset into pixel index.
  while(pixels_left != 0){  
    out_ptr[out_ptr_ix] = (ei_camera_capture_out[pixel_ix] << 16) + (ei_camera_capture_out[pixel_ix + 1] << 8) + ei_camera_capture_out[pixel_ix + 2];
    // Move to the next pixel.
    out_ptr_ix++;
    pixel_ix+=3;
    pixels_left--;
  }
  return 0;
}

โญ In the update_characteristics function, update the float data characteristic to transmit (advertise) the detected emergency class over BLE.


void update_characteristics(float detection){
  // Update the detection characteristic.
  detection_Characteristic.writeValue(detection);
  Serial.println("\n\nBLE: Data Characteristics Updated Successfully!\n");
}

โญ If the built-in OV2640 camera and the microSD card module on the expansion board are initialized successfully:

โญ Capture a frame (RGB565 buffer) with the OV2640 camera.

โญ Every 30 seconds, run an inference with the Edge Impulse FOMO model to make predictions on the emergency classes.

โญ If the Edge Impulse FOMO model detects a class successfully, transfer the model detection results to the Android application via BLE.

โญ Then, notify the user by showing the assigned class icon and the AI logo on the XIAO round display.

โญ Clear the predicted class (label).

โญ Finally, update the timer and release the image buffers.


  if(camera_activated && sd_activated){
    // Capture a frame (RGB565 buffer) with the OV2640 camera.
    camera_fb_t *fb = esp_camera_fb_get();
    if(!fb){ Serial.println("Camera => Cannot capture the frame!"); return; }

	...

    // Every 30 seconds, run the Edge Impulse FOMO model to make predictions on the emergency classes.
    if(millis() - timer > 30*1000){
      // Run inference.
      run_inference_to_make_predictions(fb);
      // If the Edge Impulse FOMO model detects an emergency class (keychain) successfully:
      if(predicted_class > -1){
        // Update the detection characteristic via BLE.
        update_characteristics(predicted_class);
        // Notify the user on the XIAO round display depending on the detected class.
        tft.drawXBitmap((img_width/2)-(detect_width/2), 2, detect_bits, detect_width, detect_height, TFT_BLACK);
        if(predicted_class == 0) tft.drawXBitmap((img_width/2)-(fine_width/2), (img_height/2)-(fine_height/2), fine_bits, fine_width, fine_height, TFT_GREEN);
        if(predicted_class == 1) tft.drawXBitmap((img_width/2)-(danger_width/2), (img_height/2)-(danger_height/2), danger_bits, danger_width, danger_height, TFT_ORANGE);
        if(predicted_class == 2) tft.drawXBitmap((img_width/2)-(assist_width/2), (img_height/2)-(assist_height/2), assist_bits, assist_width, assist_height, TFT_SILVER);
        if(predicted_class == 3) tft.drawXBitmap((img_width/2)-(stolen_width/2), (img_height/2)-(stolen_height/2), stolen_bits, stolen_width, stolen_height, TFT_NAVY);
        if(predicted_class == 4) tft.drawXBitmap((img_width/2)-(call_width/2), (img_height/2)-(call_height/2), call_bits, call_width, call_height, TFT_GREENYELLOW);
        delay(2000);
        // Clear the predicted class (label).
        predicted_class = -1;
      }
      // Update the timer:
      timer = millis();
    }
	
	...
	
    // Release the image buffers.
    esp_camera_fb_return(fb);
    delay(10);
  }

project-image
Figure - 92.206


project-image
Figure - 92.207

Step 9: Running the model and informing emergency contacts via WhatsApp & SMS

My Edge Impulse object detection (FOMO) model scans a captured image buffer and predicts possibilities of trained labels to recognize a target object on the given picture. The prediction result (score) represents the model's "confidence" that the detected object corresponds to each of the five different labels (classes) [0 - 4], as shown in Step 7:

You can inspect overlapping Android application features, such as BLE device scanning, in Step 6.1.

After setting up and running the Edge Impulse object detection (FOMO) model on XIAO ESP32S3:

๐Ÿ“ฒ โ™ฟ ๐ŸŒŽ After connecting to XIAO ESP32S3 over BLE via the Android application successfully, the user can utilize the assistive device to detect customized keychains (tokens) representing an emergency class (label).

project-image
Figure - 92.208


project-image
Figure - 92.209

๐Ÿ“ฒ โ™ฟ ๐ŸŒŽ Every 30 seconds, XIAO ESP32S3 runs an inference with the object detection model. If XIAO ESP32S3 detects an emergency class successfully, it notifies the user by showing the assigned class icon and the AI logo on the XIAO round display.

project-image
Figure - 92.210


project-image
Figure - 92.211


project-image
Figure - 92.212


project-image
Figure - 92.213


project-image
Figure - 92.214

๐Ÿ“ฒ โ™ฟ ๐ŸŒŽ After detecting an emergency class, XIAO ESP32S3 transfers the model detection results to the Android application via BLE.

๐Ÿ“ฒ โ™ฟ ๐ŸŒŽ When the Android application obtains a data packet from XIAO ESP32S3, it displays the model detection results on its interface. Then, the Android application transfers the model detection results, the current location parameters (latitude, longitude, and altitude โ€” GPS), and the current date to the web application via an HTTP GET request (cellular network connectivity โ€” GPRS).

project-image
Figure - 92.215


project-image
Figure - 92.216


project-image
Figure - 92.217


project-image
Figure - 92.218


project-image
Figure - 92.219

๐Ÿ“ฒ โ™ฟ ๐ŸŒŽ After receiving a data packet from the Android application, the web application decodes the received location information to generate a Google Maps URL with the location parameters.

๐Ÿ“ฒ โ™ฟ ๐ŸŒŽ Then, depending on the detected emergency class, the web application notifies emergency contacts via WhatsApp or SMS by utilizing Twilio's APIs.

๐Ÿ“ฒ โ™ฟ ๐ŸŒŽ The web application sends a notification message to the primary emergency contact via WhatsApp for these emergency classes:

๐Ÿ˜„ ๐Ÿ‘ I am doing well. I just wanted to add this location as a breadcrumb ๐Ÿ˜„ ๐Ÿ‘

โš ๏ธ โš ๏ธ โš ๏ธ I do not feel safe and may be in peril โš ๏ธ โš ๏ธ โš ๏ธ

โ™ฟ โ™ฟ โ™ฟ I may need your assistance due to restrictive layouts โ™ฟ โ™ฟ โ™ฟ

๐Ÿ’ฐ ๐Ÿ‘ฎ๐Ÿป ๐Ÿ’ฐ Someone managed to purloin my valuables near this location ๐Ÿ’ฐ ๐Ÿ‘ฎ๐Ÿป ๐Ÿ’ฐ

project-image
Figure - 92.220


project-image
Figure - 92.221


project-image
Figure - 92.222


project-image
Figure - 92.223


project-image
Figure - 92.224

๐Ÿ“ฒ โ™ฟ ๐ŸŒŽ The web application sends a notification message to the secondary emergency contact via SMS for this emergency class:

๐Ÿ“ž โ˜Ž๏ธ ๐Ÿ“ž Please inform my first emergency contact that I am near this location ๐Ÿ“ž โ˜Ž๏ธ ๐Ÿ“ž

project-image
Figure - 92.225

๐Ÿ“ฒ โ™ฟ ๐ŸŒŽ When the web application informs the emergency contact of the detected emergency class successfully, the Android application shows the server response, including SMS or WhatsApp message SID assigned by Twilio.

๐Ÿ“ฒ โ™ฟ ๐ŸŒŽ Also, XIAO ESP32S3 prints notifications and detection results on the serial monitor for debugging.

project-image
Figure - 92.226


project-image
Figure - 92.227


project-image
Figure - 92.228


project-image
Figure - 92.229

As far as my experiments go, the assistive device detects emergency classes accurately, transmits the model detection results to the Android application via BLE, and informs emergency contacts of the latest detection results over WhatsApp or SMS via the web application flawlessly :)

project-image
Figure - 92.230

Step 9.1: Providing emergency contacts w/ thorough location inspections generated by Google Maps via WhatsApp

As explained in Step 4.1, the web application saves the data packets transferred by the Android application to a MySQL database table. In this regard, I decided to utilize the stored location data in the database table to provide emergency contacts with thorough location inspections generated by Google Maps so as to comprehend the user's travel route until the latest notification message (database entry).

๐Ÿ“ฒ โ™ฟ ๐ŸŒŽ The web application allows the primary emergency contact to send inquiries (requests) over WhatsApp via Twilio's WhatsApp API.

project-image
Figure - 92.231

๐Ÿ“ฒ โ™ฟ ๐ŸŒŽ If the stored data records in the database table are insufficient to generate the requested analysis, the web application notifies the primary emergency contact over WhatsApp.

project-image
Figure - 92.232

๐Ÿ“ฒ โ™ฟ ๐ŸŒŽ According to the received supported command (request), the web application generates thorough location inspections with the stored location parameters by utilizing Google Maps URL API.

๐Ÿ“ฒ โ™ฟ ๐ŸŒŽ Then, the web application sends the generated location inspection as feedback to the primary emergency contact over WhatsApp.

project-image
Figure - 92.233


project-image
Figure - 92.234


project-image
Figure - 92.235


project-image
Figure - 92.236


project-image
Figure - 92.237


project-image
Figure - 92.238


project-image
Figure - 92.239


project-image
Figure - 92.240


project-image
Figure - 92.241


project-image
Figure - 92.242


project-image
Figure - 92.243


project-image
Figure - 92.244


project-image
Figure - 92.245


project-image
Figure - 92.246


project-image
Figure - 92.247

Videos and Conclusion



Further Discussions

By applying object detection models trained on customized keychains (tokens) in detecting emergencies covertly to assistive devices, we can achieve to:

๐Ÿ“ฒ โ™ฟ ๐ŸŒŽ preclude offenders from committing crimes against people with disabilities,

๐Ÿ“ฒ โ™ฟ ๐ŸŒŽ help people with mobility impairments to capitalize on smartphone features during emergencies,

๐Ÿ“ฒ โ™ฟ ๐ŸŒŽ provide versatile notification options specialized for mobility aids,

๐Ÿ“ฒ โ™ฟ ๐ŸŒŽ inform emergency contacts of potential emergencies with location data immediately,

๐Ÿ“ฒ โ™ฟ ๐ŸŒŽ generate a travel itinerary related to previously visited destinations if requested by emergency contacts.

project-image
Figure - 92.248


project-image
Figure - 92.249


project-image
Figure - 92.250

References

[1] Disability Rights California, Abuse, Neglect, and Crimes Against People with Disabilities, https://www.disabilityrightsca.org/what-we-do/programs/abuse-neglect-and-crimes-against-people-with-disabilities

[2] Zaล‚uska U, Kwiatkowska-Ciotucha D, Grzeล›kowiak A., Travelling from Perspective of Persons with Disability: Results of an International Survey, International journal of environmental research and public health, vol. 19,17 10575, 25 Aug. 2022, https://doi.org/10.3390/ijerph191710575

Code

AI_driven_BLE_Travel_Emergency_Assistant.ino

Download



         /////////////////////////////////////////////  
        //   AI-driven BLE Travel Emergency        //
       //          Assistant w/ Twilio            //
      //             ---------------             //
     //          (XIAO ESP32S3 (Sense))         //           
    //             by Kutluhan Aktar           // 
   //                                         //
  /////////////////////////////////////////////

//
// Detect keychains to inform emergency contacts via WhatsApp / SMS. Display results via BLE. Let contacts request location info from Maps API.
//
// For more information:
// https://www.theamplituhedron.com/projects/AI_driven_BLE_Travel_Emergency_Assistant
//
//
// Connections
// XIAO ESP32S3 (Sense) :
//                                XIAO Round Display 
// https://wiki.seeedstudio.com/seeedstudio_round_display_usage/#getting-started                  


// Include the required libraries:
#include <Arduino.h>
#include <ArduinoBLE.h>
#include <TFT_eSPI.h>
#include <SPI.h>
#include "esp_camera.h"
#include "FS.h"
#include "SD.h"
#include "SPI.h"

// Add the icons to be shown on the XIAO round display.
#include "logo.h"

// Include the Edge Impulse FOMO model converted to an Arduino library:
#include <AI-driven_BLE_Travel_Emergency_Assistant_inferencing.h>
#include "edge-impulse-sdk/dsp/image/image.hpp"

// Define the required parameters to run an inference with the Edge Impulse FOMO model.
#define CAPTURED_IMAGE_BUFFER_COLS        240
#define CAPTURED_IMAGE_BUFFER_ROWS        240
#define EI_CAMERA_FRAME_BYTE_SIZE         3
uint8_t *ei_camera_capture_out;

// Define the emergency class names:
String classes[] = {"Fine", "Danger", "Assist", "Stolen", "Call"};

// Create the BLE service:
BLEService Emergency_Assistant("23bc2b0f-3081-402e-8ba2-300280c91740");

// Create data characteristics and allow the remote device (central) to write, read, and notify:
BLEFloatCharacteristic detection_Characteristic("23bc2b0f-3081-402e-8ba2-300280c91741", BLERead | BLENotify);
BLEByteCharacteristic class_Characteristic("23bc2b0f-3081-402e-8ba2-300280c91742", BLERead | BLEWrite);

// Define the OV2640 camera pin configuration on the XIAO ESP32S3 Sense expansion board.
#define PWDN_GPIO_NUM     -1
#define RESET_GPIO_NUM    -1
#define XCLK_GPIO_NUM     10
#define SIOD_GPIO_NUM     40
#define SIOC_GPIO_NUM     39
#define Y9_GPIO_NUM       48
#define Y8_GPIO_NUM       11
#define Y7_GPIO_NUM       12
#define Y6_GPIO_NUM       14
#define Y5_GPIO_NUM       16
#define Y4_GPIO_NUM       18
#define Y3_GPIO_NUM       17
#define Y2_GPIO_NUM       15
#define VSYNC_GPIO_NUM    38
#define HREF_GPIO_NUM     47
#define PCLK_GPIO_NUM     13
#define LED_GPIO_NUM      21

// Utilize the SD card reader on the expansion board without cutting the J3 solder bridge.
#define SD_CS_PIN 21 // #define SD_CS_PIN D2 // XIAO Round Display SD Card Reader

// Define the XIAO round display object and image dimensions.
TFT_eSPI tft = TFT_eSPI();
const int img_width = 240;
const int img_height = 240;

// Define the data holders:
#define TOUCH_INT D7
int predicted_class = -1;
volatile boolean camera_activated = false;
volatile boolean sd_activated = false;
volatile boolean _connected = false;
int sample_number[5] = {0, 0, 0, 0, 0};
long timer;


void setup(){
  Serial.begin(115200);

  // Define the OV2640 camera pin and frame settings.
  camera_config_t config;
  config.ledc_channel = LEDC_CHANNEL_0;
  config.ledc_timer = LEDC_TIMER_0;
  config.pin_d0 = Y2_GPIO_NUM;
  config.pin_d1 = Y3_GPIO_NUM;
  config.pin_d2 = Y4_GPIO_NUM;
  config.pin_d3 = Y5_GPIO_NUM;
  config.pin_d4 = Y6_GPIO_NUM;
  config.pin_d5 = Y7_GPIO_NUM;
  config.pin_d6 = Y8_GPIO_NUM;
  config.pin_d7 = Y9_GPIO_NUM;
  config.pin_xclk = XCLK_GPIO_NUM;
  config.pin_pclk = PCLK_GPIO_NUM;
  config.pin_vsync = VSYNC_GPIO_NUM;
  config.pin_href = HREF_GPIO_NUM;
  config.pin_sscb_sda = SIOD_GPIO_NUM;
  config.pin_sscb_scl = SIOC_GPIO_NUM;
  config.pin_pwdn = PWDN_GPIO_NUM;
  config.pin_reset = RESET_GPIO_NUM;
  config.xclk_freq_hz = 10000000; // Set XCLK_FREQ_HZ as 10KHz to avoid the EV-VSYNC-OVF error.
  config.frame_size = FRAMESIZE_240X240; // FRAMESIZE_UXGA, FRAMESIZE_SVGA
  config.pixel_format = PIXFORMAT_RGB565; // PIXFORMAT_JPEG
  config.grab_mode = CAMERA_GRAB_WHEN_EMPTY;
  config.fb_location = CAMERA_FB_IN_PSRAM;
  config.jpeg_quality = 12;
  config.fb_count = 2;

  // Initialize the OV2640 camera.
  esp_err_t err = esp_camera_init(&config);
  if (err != ESP_OK) {
    Serial.printf("Camera init failed with error 0x%x", err);
    return;
  }
  // If successful:
  Serial.println("OV2640 camera initialized successfully!");
  camera_activated = true;

  // Initialize the XIAO round display.
  tft.init();
  tft.setRotation(2);
  tft.fillScreen(TFT_WHITE);

  // Initialize the SD card module on the expansion board.
  if(!SD.begin(SD_CS_PIN)){
    Serial.println("SD Card => No module found!");
    return;
  }
  // If successful:
  Serial.println("SD card initialized successfully!");
  sd_activated = true;

  // Check the BLE initialization status:
  while(!BLE.begin()){
    Serial.println("BLE initialization is failed!");
  }
  Serial.println("\nBLE initialization is successful!\n");
  // Print this peripheral device's address information:
  Serial.print("MAC Address: "); Serial.println(BLE.address());
  Serial.print("Service UUID Address: "); Serial.println(Emergency_Assistant.uuid()); Serial.println();

  // Set the local name this peripheral advertises: 
  BLE.setLocalName("BLE Emergency Assistant");
  // Set the UUID for the service this peripheral advertises:
  BLE.setAdvertisedService(Emergency_Assistant);

  // Add the given data characteristics to the service:
  Emergency_Assistant.addCharacteristic(detection_Characteristic);
  Emergency_Assistant.addCharacteristic(class_Characteristic);

  // Add the given service to the advertising device:
  BLE.addService(Emergency_Assistant);

  // Assign event handlers for connected and disconnected devices to/from this peripheral:
  BLE.setEventHandler(BLEConnected, blePeripheralConnectHandler);
  BLE.setEventHandler(BLEDisconnected, blePeripheralDisconnectHandler);

  // Assign event handlers for the data characteristics modified (written) by the central device (via the Android application).
  // In this regard, obtain the transferred (written) commands from the Android application over BLE.
  class_Characteristic.setEventHandler(BLEWritten, get_selected_class);

  // Start advertising:
  BLE.advertise();
  Serial.println("Bluetooth device active, waiting for connections...");

  delay(5000);
  
  timer = millis();
}

void loop(){
  // Poll for BLE events:
  BLE.poll();

  if(camera_activated && sd_activated){
    // Capture a frame (RGB565 buffer) with the OV2640 camera.
    camera_fb_t *fb = esp_camera_fb_get();
    if(!fb){ Serial.println("Camera => Cannot capture the frame!"); return; }

    // Display the captured frame on the XIAO round display.
    tft.startWrite();
    tft.setAddrWindow(0, 0, img_width, img_height);
    tft.pushColors(fb->buf, fb->len);
    tft.endWrite();

    // Every 30 seconds, run the Edge Impulse FOMO model to make predictions on the emergency classes.
    if(millis() - timer > 30*1000){
      // Run inference.
      run_inference_to_make_predictions(fb);
      // If the Edge Impulse FOMO model detects an emergency class (keychain) successfully:
      if(predicted_class > -1){
        // Update the detection characteristic via BLE.
        update_characteristics(predicted_class);
        // Notify the user on the XIAO round display depending on the detected class.
        tft.drawXBitmap((img_width/2)-(detect_width/2), 2, detect_bits, detect_width, detect_height, TFT_BLACK);
        if(predicted_class == 0) tft.drawXBitmap((img_width/2)-(fine_width/2), (img_height/2)-(fine_height/2), fine_bits, fine_width, fine_height, TFT_GREEN);
        if(predicted_class == 1) tft.drawXBitmap((img_width/2)-(danger_width/2), (img_height/2)-(danger_height/2), danger_bits, danger_width, danger_height, TFT_ORANGE);
        if(predicted_class == 2) tft.drawXBitmap((img_width/2)-(assist_width/2), (img_height/2)-(assist_height/2), assist_bits, assist_width, assist_height, TFT_SILVER);
        if(predicted_class == 3) tft.drawXBitmap((img_width/2)-(stolen_width/2), (img_height/2)-(stolen_height/2), stolen_bits, stolen_width, stolen_height, TFT_NAVY);
        if(predicted_class == 4) tft.drawXBitmap((img_width/2)-(call_width/2), (img_height/2)-(call_height/2), call_bits, call_width, call_height, TFT_GREENYELLOW);
        delay(2000);
        // Clear the predicted class (label).
        predicted_class = -1;
      }
      // Update the timer:
      timer = millis();
    }

    // If the user touches the XIAO round display, show the current sample numbers for each emergency class on the SD card.
    if(display_is_pressed()){
      String f_n = "Fine: " + String(sample_number[0]);
      String d_n = "Danger: " + String(sample_number[1]);
      String a_n = "Assist: " + String(sample_number[2]);
      String s_n = "Stolen: " + String(sample_number[3]);
      String c_n = "Call: " + String(sample_number[4]);
      int x = 75, y = 25, d = 40;
      tft.setTextSize(2);
      tft.setTextColor(TFT_WHITE, TFT_GREEN, false);
      tft.drawString(f_n.c_str(), x, y, 2);
      tft.setTextColor(TFT_WHITE, TFT_ORANGE, false);
      tft.drawString(d_n.c_str(), x, y+d, 2);
      tft.setTextColor(TFT_WHITE, TFT_SILVER, false);
      tft.drawString(a_n.c_str(), x, y+(2*d), 2);
      tft.setTextColor(TFT_WHITE, TFT_NAVY, false);
      tft.drawString(s_n.c_str(), x, y+(3*d), 2);
      tft.setTextColor(TFT_WHITE, TFT_GREENYELLOW, false);
      tft.drawString(c_n.c_str(), x, y+(4*d), 2);
      delay(1000);
    }

    // Release the image buffers.
    esp_camera_fb_return(fb);
    delay(10);
  }
}

void run_inference_to_make_predictions(camera_fb_t *fb){
  // Summarize the Edge Impulse FOMO model inference settings (from model_metadata.h):
  ei_printf("\nInference settings:\n");
  ei_printf("\tImage resolution: %dx%d\n", EI_CLASSIFIER_INPUT_WIDTH, EI_CLASSIFIER_INPUT_HEIGHT);
  ei_printf("\tFrame size: %d\n", EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE);
  ei_printf("\tNo. of classes: %d\n", sizeof(ei_classifier_inferencing_categories) / sizeof(ei_classifier_inferencing_categories[0]));
  
  if(fb){
    // Convert the captured RGB565 buffer to RGB888 buffer.
    ei_camera_capture_out = (uint8_t*)malloc(CAPTURED_IMAGE_BUFFER_COLS * CAPTURED_IMAGE_BUFFER_ROWS * EI_CAMERA_FRAME_BYTE_SIZE);
    if(!fmt2rgb888(fb->buf, fb->len, PIXFORMAT_RGB565, ei_camera_capture_out)){ Serial.println("Camera => Cannot convert the RGB565 buffer to RGB888!"); return; }

    // Depending on the given model, resize the converted RGB888 buffer by utilizing built-in Edge Impulse functions.
    ei::image::processing::crop_and_interpolate_rgb888(
      ei_camera_capture_out, // Output image buffer, can be same as input buffer
      CAPTURED_IMAGE_BUFFER_COLS,
      CAPTURED_IMAGE_BUFFER_ROWS,
      ei_camera_capture_out,
      EI_CLASSIFIER_INPUT_WIDTH,
      EI_CLASSIFIER_INPUT_HEIGHT);

    // Run inference:
    ei::signal_t signal;
    // Create a signal object from the converted and resized image buffer.
    signal.total_length = EI_CLASSIFIER_INPUT_WIDTH * EI_CLASSIFIER_INPUT_HEIGHT;
    signal.get_data = &ei_camera_cutout_get_data;
    // Run the classifier:
    ei_impulse_result_t result = { 0 };
    EI_IMPULSE_ERROR _err = run_classifier(&signal, &result, false);
    if(_err != EI_IMPULSE_OK){
      ei_printf("ERR: Failed to run classifier (%d)\n", _err);
      return;
    }

    // Print the inference timings on the serial monitor.
    ei_printf("\nPredictions (DSP: %d ms., Classification: %d ms., Anomaly: %d ms.): \n",
        result.timing.dsp, result.timing.classification, result.timing.anomaly);

    // Obtain the object detection results and bounding boxes for the detected labels (classes). 
    bool bb_found = result.bounding_boxes[0].value > 0;
    for(size_t ix = 0; ix < EI_CLASSIFIER_OBJECT_DETECTION_COUNT; ix++){
      auto bb = result.bounding_boxes[ix];
      if(bb.value == 0) continue;
      // Print the calculated bounding box measurements on the serial monitor.
      ei_printf("    %s (", bb.label);
      ei_printf_float(bb.value);
      ei_printf(") [ x: %u, y: %u, width: %u, height: %u ]\n", bb.x, bb.y, bb.width, bb.height);
      // Get the predicted label (class).
      if(bb.label == "fine") predicted_class = 0;
      if(bb.label == "danger") predicted_class = 1;
      if(bb.label == "assist") predicted_class = 2;
      if(bb.label == "stolen") predicted_class = 3;
      if(bb.label == "call") predicted_class = 4;
      Serial.print("\nPredicted Class: "); Serial.println(bb.label);
    }
    if(!bb_found) ei_printf("    No objects found!\n");

    // Detect anomalies, if any:
    #if EI_CLASSIFIER_HAS_ANOMALY == 1
      ei_printf("Anomaly: ");
      ei_printf_float(result.anomaly);
      ei_printf("\n");
    #endif 

    // Release the image buffers.
    free(ei_camera_capture_out);
  }
}

static int ei_camera_cutout_get_data(size_t offset, size_t length, float *out_ptr){
  // Convert the given image data (buffer) to the out_ptr format required by the Edge Impulse FOMO model.
  size_t pixel_ix = offset * 3;
  size_t pixels_left = length;
  size_t out_ptr_ix = 0;
  // Since the image data is converted to an RGB888 buffer, directly recalculate offset into pixel index.
  while(pixels_left != 0){  
    out_ptr[out_ptr_ix] = (ei_camera_capture_out[pixel_ix] << 16) + (ei_camera_capture_out[pixel_ix + 1] << 8) + ei_camera_capture_out[pixel_ix + 2];
    // Move to the next pixel.
    out_ptr_ix++;
    pixel_ix+=3;
    pixels_left--;
  }
  return 0;
}

void update_characteristics(float detection){
  // Update the detection characteristic.
  detection_Characteristic.writeValue(detection);
  Serial.println("\n\nBLE: Data Characteristics Updated Successfully!\n");
}

void get_selected_class(BLEDevice central, BLECharacteristic characteristic){
  // Get the recently transferred commands over BLE.
  if(characteristic.uuid() == class_Characteristic.uuid()){
    Serial.print("\nSelected Class => "); Serial.println(class_Characteristic.value());
    // Capture a new frame (RGB565 buffer) with the OV2640 camera.
    camera_fb_t *fb = esp_camera_fb_get();
    if(!fb){ Serial.println("Camera => Cannot capture the frame!"); return; }
    // Convert the captured RGB565 buffer to JPEG buffer.
    size_t con_len;
    uint8_t *con_buf = NULL;
    if(!frame2jpg(fb, 10, &con_buf, &con_len)){ Serial.println("Camera => Cannot convert the RGB565 buffer to JPEG!"); return; }
    // Depending on the selected emergency class, save the converted frame as a sample to the SD card.
    String file_name = "";
    switch(class_Characteristic.value()){
      case 0:
        // Save the given frame as an image file.
        file_name = "/" + classes[0] + "_" + String(sample_number[0]) + ".jpg";
        save_image(SD, file_name.c_str(), con_buf, con_len);
        // Notify the user on the XIAO round display.
        tft.drawXBitmap((img_width/2)-(save_width/2), 2, save_bits, save_width, save_height, TFT_BLACK);
        tft.drawXBitmap((img_width/2)-(fine_width/2), (img_height/2)-(fine_height/2), fine_bits, fine_width, fine_height, TFT_GREEN);
        // Increase the sample number.
        sample_number[0]+=1;
        delay(2000);
      break;
      case 1:
        // Save the given frame as an image file.
        file_name = "/" + classes[1] + "_" + String(sample_number[1]) + ".jpg";
        save_image(SD, file_name.c_str(), con_buf, con_len);
        // Notify the user on the XIAO round display.
        tft.drawXBitmap((img_width/2)-(save_width/2), 2, save_bits, save_width, save_height, TFT_BLACK);
        tft.drawXBitmap((img_width/2)-(danger_width/2), (img_height/2)-(danger_height/2), danger_bits, danger_width, danger_height, TFT_ORANGE);
        // Increase the sample number.
        sample_number[1]+=1;
        delay(2000);
      break;
      case 2:
        // Save the given frame as an image file.
        file_name = "/" + classes[2] + "_" + String(sample_number[2]) + ".jpg";
        save_image(SD, file_name.c_str(), con_buf, con_len);
        // Notify the user on the XIAO round display.
        tft.drawXBitmap((img_width/2)-(save_width/2), 2, save_bits, save_width, save_height, TFT_BLACK);
        tft.drawXBitmap((img_width/2)-(assist_width/2), (img_height/2)-(assist_height/2), assist_bits, assist_width, assist_height, TFT_SILVER);
        // Increase the sample number.
        sample_number[2]+=1;
        delay(2000);
      break;
      case 3:
        // Save the given frame as an image file.
        file_name = "/" + classes[3] + "_" + String(sample_number[3]) + ".jpg";
        save_image(SD, file_name.c_str(), con_buf, con_len);
        // Notify the user on the XIAO round display.
        tft.drawXBitmap((img_width/2)-(save_width/2), 2, save_bits, save_width, save_height, TFT_BLACK);
        tft.drawXBitmap((img_width/2)-(stolen_width/2), (img_height/2)-(stolen_height/2), stolen_bits, stolen_width, stolen_height, TFT_NAVY);
        // Increase the sample number.
        sample_number[3]+=1;
        delay(2000);
      break;
      case 4:
        // Save the given frame as an image file.
        file_name = "/" + classes[4] + "_" + String(sample_number[4]) + ".jpg";
        save_image(SD, file_name.c_str(), con_buf, con_len);
        // Notify the user on the XIAO round display.
        tft.drawXBitmap((img_width/2)-(save_width/2), 2, save_bits, save_width, save_height, TFT_BLACK);
        tft.drawXBitmap((img_width/2)-(call_width/2), (img_height/2)-(call_height/2), call_bits, call_width, call_height, TFT_GREENYELLOW);
        // Increase the sample number.
        sample_number[4]+=1;
        delay(2000);
      break;
    }
    // Release the image buffers.
    free(con_buf);
    esp_camera_fb_return(fb);
  }
}

void save_image(fs::FS &fs, const char *file_name, uint8_t *data, size_t len){
  // Create a new file on the SD card.
  File file = fs.open(file_name, FILE_WRITE);
  if(!file){ Serial.println("SD Card => Cannot create file!"); return; }
  // Save the given image buffer to the created file on the SD card.
  if(file.write(data, len) == len){
      Serial.printf("SD Card => IMG saved: %s\n", file_name);
  }else{
      Serial.println("SD Card => Cannot save the given image!");
  }
  file.close();    
}

// Detect when the user touches the XIAO round display.
bool display_is_pressed(){
  if(digitalRead(TOUCH_INT) != LOW){
    delay(10);
    if(digitalRead(TOUCH_INT) != LOW) return false;
  }
  return true;
}

void blePeripheralConnectHandler(BLEDevice central){
  // Central connected event handler:
  Serial.print("\nConnected event, central: ");
  Serial.println(central.address());
  _connected = true;
}

void blePeripheralDisconnectHandler(BLEDevice central){
  // Central disconnected event handler:
  Serial.print("\nDisconnected event, central: ");
  Serial.println(central.address());
  _connected = false;
}


class.php

Download



<?php

// Include the Twilio PHP Helper Library. 
require_once 'twilio-php-main/src/Twilio/autoload.php';
use Twilio\Rest\Client;

// Define the assistant class and its functions:
class assistant {
	public $conn;
	private $twilio;
	
	public function __init__($conn){
		$this->conn = $conn;
		// Define the Twilio account information and object.
		$_sid    = "<_SID_>";
        $token  = "<_TOKEN_>";
        $this->twilio = new Client($_sid, $token);
	}
	
	// Database -> Update the database table
	public function update_user_info($action, $to_phone, $from_phone, $emergency_phone){
		if($action == "new"){
			// Add the given user information to the database table.
			$sql_insert = "INSERT INTO `entries`(`to_phone`, `from_phone`, `emergency_phone`, `date`, `location`, `class`) 
						   VALUES ('$to_phone', '$from_phone', '$emergency_phone', 'X', 'X', 'X')"
					      ;
			if(mysqli_query($this->conn, $sql_insert)) echo("User information added to the database successfully!");			
		}else if($action == "update"){
			// Update the given user information in the database table.
			$sql_update = "UPDATE `entries` SET `to_phone`='$to_phone', `from_phone`='$from_phone', `emergency_phone`='$emergency_phone'
			               WHERE `id`=1"
						  ;
			if(mysqli_query($this->conn, $sql_update)) echo("User information updated successfully!");

		}
	}
	
	// Save the latest model detection results and the device location to the database table.
	public function save_results($action, $date, $location, $class){
		if($action == "save"){
			// Fetch the stored user information to add to the new data record.
			$sql_insert = "INSERT INTO `entries`(`to_phone`, `from_phone`, `emergency_phone`, `date`, `location`, `class`) 
						   SELECT `to_phone`, `from_phone`, `emergency_phone`, '$date', '$location', '$class'
						   FROM `entries` WHERE id=1"
			              ;
			if(mysqli_query($this->conn, $sql_insert)) echo("New data record inserted successfully!");
		}
	}
	
	// Obtain the required user information from the database table. 
	private function get_user_info(){
		$sql = "SELECT * FROM `entries` WHERE id=1";
		$result = mysqli_query($this->conn, $sql);
		$check = mysqli_num_rows($result);
		if($check > 0 && $row = mysqli_fetch_assoc($result)){
			return $row;
		}
	}
	
    // Retrieve the required location variables from the database table.
	private function get_loc_vars(){
		$loc_vars = [];
		$sql = "SELECT * FROM `entries` WHERE id!=1 ORDER BY `id` DESC";
		$result = mysqli_query($this->conn, $sql);
		$check = mysqli_num_rows($result);
		while($check > 0 && $row = mysqli_fetch_assoc($result)){
			array_push($loc_vars, $row);
		}
		return $loc_vars;
	}

	// Transfer a WhatsApp message to the registered primary emergency contact via Twilio.
	private function Twilio_send_whatsapp($body){
		// Get user information.
		$info = $this->get_user_info();
		// Configure the WhatsApp object.
		$whatsapp_message = $this->twilio->messages
			->create("whatsapp:".$info["to_phone"],
				array(
					   "from" => "whatsapp:+14155238886",
					   "body" => $body
                     )
				);
		// Send the WhatsApp message.
        echo(" WhatsApp SID: ".$whatsapp_message->sid);
	}
	
	// Send an SMS to the registered secondary emergency contact via Twilio.
	private function Twilio_send_SMS($body){
		// Get user information.
		$info = $this->get_user_info();
		// Configure the SMS object.
        $sms_message = $this->twilio->messages
			->create($info["emergency_phone"],
				array(
					   "from" => $info["from_phone"],
                       "body" => $body
                     )
                );
		// Send the SMS.
		echo(" SMS SID: ".$sms_message->sid);	  
	}
	
	// Inform the user's emergency contacts via SMS or WhatsApp, depending on the given command.
	public function notify_contacts($command, $date, $location){
		// Decode the received location parameters.
		$loc_vars = explode(",", $location);
		$lat = $loc_vars[0]; $long = $loc_vars[1]; $alt = $loc_vars[2];
		// Notify the emergency contacts.
		if($command == "fine"){
			$message_body = "๐Ÿ˜„ ๐Ÿ‘ I am doing well. I just wanted to add this location as a breadcrumb ๐Ÿ˜„ ๐Ÿ‘"
			                ."\n\r\n\rโฐ Date: ".$date
							."\n\r\n\rโœˆ๏ธ Altitude: ".$alt
							."\n\r\n\r๐Ÿ“Œ Current Location:\n\rhttps://www.google.com/maps/search/?api=1&query=".$lat."%2C".$long;
			$this->Twilio_send_whatsapp($message_body);
		}
		else if($command == "danger"){
			$message_body = "โš ๏ธ โš ๏ธ โš ๏ธ I do not feel safe and may be in peril โš ๏ธ โš ๏ธ โš ๏ธ"
			                ."\n\r\n\rโฐ Date: ".$date
							."\n\r\n\rโœˆ๏ธ Altitude: ".$alt
							."\n\r\n\r๐Ÿ“Œ Current Location:\n\rhttps://www.google.com/maps/search/?api=1&query=".$lat."%2C".$long;
			$this->Twilio_send_whatsapp($message_body);
		}
		else if($command == "assist"){
			$message_body = "โ™ฟ โ™ฟ โ™ฟ I may need your assistance due to restrictive layouts โ™ฟ โ™ฟ โ™ฟ"
			                ."\n\r\n\rโฐ Date: ".$date
							."\n\r\n\rโœˆ๏ธ Altitude: ".$alt
							."\n\r\n\r๐Ÿ“Œ Current Location:\n\rhttps://www.google.com/maps/search/?api=1&query=".$lat."%2C".$long;
			$this->Twilio_send_whatsapp($message_body);
		}
		else if($command == "stolen"){
			$message_body = "๐Ÿ’ฐ ๐Ÿ‘ฎ๐Ÿป ๐Ÿ’ฐ Someone managed to purloin my valuables near this location ๐Ÿ’ฐ ๐Ÿ‘ฎ๐Ÿป ๐Ÿ’ฐ"
			                ."\n\r\n\rโฐ Date: ".$date
							."\n\r\n\rโœˆ๏ธ Altitude: ".$alt
							."\n\r\n\r๐Ÿ“Œ Current Location:\n\rhttps://www.google.com/maps/search/?api=1&query=".$lat."%2C".$long;
			$this->Twilio_send_whatsapp($message_body);
		}
		else if($command == "call"){
			$message_body = "๐Ÿ“ž โ˜Ž๏ธ ๐Ÿ“ž Please inform my first emergency contact that I am near this location ๐Ÿ“ž โ˜Ž๏ธ ๐Ÿ“ž"
			                ."\n\r\n\rโฐ Date: ".$date
							."\n\r\n\rโœˆ๏ธ Altitude: ".$alt
							."\n\r\n\r๐Ÿ“Œ Current Location:\n\r\n\rhttps://www.google.com/maps/search/?api=1&query=".$lat."%2C".$long;
			$this->Twilio_send_SMS($message_body);
		}
	}
	
	// Transfer thorough location inspections generated by Google Maps to emergency contacts when requested via WhatsApp.
	public function generate_feedback($command){
		// Obtain the latest location variables in the database table.
		$loc_vars = $this->get_loc_vars();
		// Generate the requested feedback via Google Maps.
		$message_body = "";
		switch($command){
			case "Route Walking":
				if(count($loc_vars) >= 2){
					$message_body = "๐Ÿšถ Estimated Walking Path:\n\r\n\r"
									."๐Ÿ“Œ Origin โžก๏ธ\n\r"
									."๐Ÿ•œ ".$loc_vars[1]["date"]
									."\n\r๐Ÿ”Ž ".$loc_vars[1]["class"]
									."\n\r\n\r๐Ÿ“Œ Destination โžก๏ธ\n\r"
									."๐Ÿ•œ ".$loc_vars[0]["date"]
									."\n\r๐Ÿ”Ž ".$loc_vars[0]["class"]
									."\n\r\n\rhttps://www.google.com/maps/dir/?api=1&origin="
									.explode(",", $loc_vars[1]["location"])[0]."%2C"
									.explode(",", $loc_vars[1]["location"])[1]."&destination="
									.explode(",", $loc_vars[0]["location"])[0]."%2C"
									.explode(",", $loc_vars[0]["location"])[1]
									."&travelmode=walking";
				}else{
					$message_body = "โ›” Insufficient data for the requested analysis.";
				}
				break;
			case "Route Bicycling":
				if(count($loc_vars) >= 2){
					$message_body = "๐Ÿšด Estimated Bicycling Path:\n\r\n\r"
									."๐Ÿ“Œ Origin โžก๏ธ\n\r"
									."๐Ÿ•œ ".$loc_vars[1]["date"]
									."\n\r๐Ÿ”Ž ".$loc_vars[1]["class"]
									."\n\r\n\r๐Ÿ“Œ Destination โžก๏ธ\n\r"
									."๐Ÿ•œ ".$loc_vars[0]["date"]
									."\n\r๐Ÿ”Ž ".$loc_vars[0]["class"]
									."\n\r\n\rhttps://www.google.com/maps/dir/?api=1&origin="
									.explode(",", $loc_vars[1]["location"])[0]."%2C"
									.explode(",", $loc_vars[1]["location"])[1]."&destination="
									.explode(",", $loc_vars[0]["location"])[0]."%2C"
									.explode(",", $loc_vars[0]["location"])[1]
									."&travelmode=bicycling";
				}else{
					$message_body = "โ›” Insufficient data for the requested analysis.";
				}
				break;
			case "Route Driving":
				if(count($loc_vars) >= 2){
					$message_body = "๐Ÿš— Estimated Driving Path:\n\r\n\r"
									."๐Ÿ“Œ Origin โžก๏ธ\n\r"
									."๐Ÿ•œ ".$loc_vars[1]["date"]
									."\n\r๐Ÿ”Ž ".$loc_vars[1]["class"]
									."\n\r\n\r๐Ÿ“Œ Destination โžก๏ธ\n\r"
									."๐Ÿ•œ ".$loc_vars[0]["date"]
									."\n\r๐Ÿ”Ž ".$loc_vars[0]["class"]
									."\n\r\n\rhttps://www.google.com/maps/dir/?api=1&origin="
									.explode(",", $loc_vars[1]["location"])[0]."%2C"
									.explode(",", $loc_vars[1]["location"])[1]."&destination="
									.explode(",", $loc_vars[0]["location"])[0]."%2C"
									.explode(",", $loc_vars[0]["location"])[1]
									."&travelmode=driving";
				}else{
					$message_body = "โ›” Insufficient data for the requested analysis.";
				}
				break;
			case "Show Waypoints":
				if(count($loc_vars) >= 4){
					$message_body = "๐Ÿ›ฃ๏ธ ๐Ÿ“ Estimated Driving Path w/ Waypoints:\n\r\n\r"
									."๐Ÿ“Œ Origin โžก๏ธ\n\r"
									."๐Ÿ•œ ".$loc_vars[3]["date"]
									."\n\r๐Ÿ”Ž ".$loc_vars[3]["class"]
									."\n\r\n\r๐Ÿ“Œ Destination โžก๏ธ\n\r"
									."๐Ÿ•œ ".$loc_vars[0]["date"]
									."\n\r๐Ÿ”Ž ".$loc_vars[0]["class"]
									."\n\r\n\rhttps://www.google.com/maps/dir/?api=1&origin="
									.explode(",", $loc_vars[3]["location"])[0]."%2C"
									.explode(",", $loc_vars[3]["location"])[1]."&waypoints="
									.explode(",", $loc_vars[2]["location"])[0]."%2C"
									.explode(",", $loc_vars[2]["location"])[1]."%7C"
									.explode(",", $loc_vars[1]["location"])[0]."%2C"
									.explode(",", $loc_vars[1]["location"])[1]."&destination="
									.explode(",", $loc_vars[0]["location"])[0]."%2C"
									.explode(",", $loc_vars[0]["location"])[1]
									."&travelmode=driving";
				}else{
					$message_body = "โ›” Insufficient data for the requested analysis.";
				}
				break;
			case "Terrain View":
				if(count($loc_vars) >= 1){
					$message_body = "โ›ฐ๏ธ Terrain View of the Latest Location:\n\r\n\r"
									."๐Ÿ“Œ Latest โžก๏ธ\n\r"
									."๐Ÿ•œ ".$loc_vars[0]["date"]
									."\n\r๐Ÿ”Ž ".$loc_vars[0]["class"]
									."\n\r\n\rhttps://www.google.com/maps/@?api=1&map_action=map¢er="
									.explode(",", $loc_vars[0]["location"])[0]."%2C"
									.explode(",", $loc_vars[0]["location"])[1]
									."&zoom=12&basemap=terrain&layer=bicycling";
				}else{
					$message_body = "โ›” Insufficient data for the requested analysis.";
				}
				break;
			case "Satellite View":
				if(count($loc_vars) >= 1){
					$message_body = "๐Ÿ›ฐ๏ธ Satellite View of the Latest Location:\n\r\n\r"
									."๐Ÿ“Œ Latest โžก๏ธ\n\r"
									."๐Ÿ•œ ".$loc_vars[0]["date"]
									."\n\r๐Ÿ”Ž ".$loc_vars[0]["class"]
									."\n\r\n\rhttps://www.google.com/maps/@?api=1&map_action=map¢er="
									.explode(",", $loc_vars[0]["location"])[0]."%2C"
									.explode(",", $loc_vars[0]["location"])[1]
									."&zoom=12&basemap=satellite&layer=traffic";
				}else{
					$message_body = "โ›” Insufficient data for the requested analysis.";
				}
				break;
			case "Street View":
				if(count($loc_vars) >= 1){
					$message_body = "๐Ÿš€ ๐ŸŒŽ Wander through the streets near the latest location:\n\r\n\r"
									."๐Ÿ“Œ Center โžก๏ธ\n\r"
									."๐Ÿ•œ ".$loc_vars[0]["date"]
									."\n\r๐Ÿ”Ž ".$loc_vars[0]["class"]
									."\n\r\n\rhttps://www.google.com/maps/@?api=1&map_action=pano&viewpoint="
									.explode(",", $loc_vars[0]["location"])[0]."%2C"
									.explode(",", $loc_vars[0]["location"])[1]
									."&heading=90";
				}else{
					$message_body = "โ›” Insufficient data for the requested analysis.";
				}
				break;
			default:
				$message_body = "๐Ÿค– ๐Ÿ‘‰ Please utilize the supported commands:\n\r\n\rโžก๏ธ Route Walking\n\r\n\rโžก๏ธ Route Bicycling\n\r\n\rโžก๏ธ Route Driving\n\r\n\rโžก๏ธ Show Waypoints\n\r\n\rโžก๏ธ Terrain View\n\r\n\rโžก๏ธ Satellite View\n\r\n\rโžก๏ธ Street View";
				break;
		}
		// Transmit the generated feedback.
		$this->Twilio_send_whatsapp($message_body);
	}

}

// Define database and server settings:
$server = array(
	"name" => "localhost",
	"username" => "root",
	"password" => "",
	"database" => "emergency_assistant"
);


$conn = mysqli_connect($server["name"], $server["username"], $server["password"], $server["database"]);

?>


index.php

Download



<?php

include_once "assets/class.php";

ini_set('display_errors',1);

// Define the new '_assistant' object:
$_assistant = new assistant();
$_assistant->__init__($conn);


// If requested, add or update the user information.
if(isset($_GET["action"]) && isset($_GET["to_phone"]) && isset($_GET["from_phone"]) && isset($_GET["emergency_phone"])){
	$_assistant->update_user_info($_GET["action"], $_GET["to_phone"], $_GET["from_phone"], $_GET["emergency_phone"]);
}

// Obtain the emergency class detected by XIAO ESP32S3 and the current location data through the BLE Android application.
if(isset($_GET["action"]) && isset($_GET["date"]) && isset($_GET["location"]) && isset($_GET["class"])){
	// Insert the latest data record into the database table.
	$_assistant->save_results($_GET["action"], $_GET["date"], $_GET["location"], $_GET["class"]);
	// Notify the user's emergency contacts via SMS or WhatsApp, depending on the received class (command).
	$_assistant->notify_contacts($_GET["class"], $_GET["date"], $_GET["location"]);
}

// If the primary emergency contact transfers a message (command) to this webhook via WhatsApp:
if(isset($_POST["Body"])){
	// Generate and transfer thorough location inspections (from Google Maps) as feedback, depending on the given command.
	$_assistant->generate_feedback($_POST["Body"]);
}

?>


logo.h

Download



#define save_width 35
#define save_height 35
PROGMEM const unsigned char save_bits[] = {
  0xDE, 0x01, 0x00, 0x3E, 0x00, 0xFF, 0x01, 0x78, 0x7E, 0x00, 0xFF, 0x01, 
  0x78, 0xFE, 0x00, 0xFE, 0x01, 0x78, 0xFE, 0x01, 0xFF, 0x01, 0xF8, 0xFE, 
  0x03, 0xFF, 0x01, 0x78, 0xFE, 0x03, 0xFF, 0x01, 0xF8, 0xFE, 0x03, 0xFE, 
  0x01, 0x78, 0xFE, 0x03, 0xFF, 0x01, 0x78, 0xFE, 0x03, 0xFF, 0x01, 0xF8, 
  0xFE, 0x03, 0xFF, 0x01, 0x00, 0xFE, 0x03, 0xFF, 0xDB, 0xBA, 0xFF, 0x03, 
  0xFE, 0xFF, 0xFF, 0xFF, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0xFF, 0xFF, 
  0xFF, 0xFF, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 
  0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0xFE, 
  0x00, 0x00, 0xF8, 0x03, 0x7F, 0x00, 0x00, 0xF8, 0x03, 0x7F, 0x00, 0x00, 
  0xF8, 0x03, 0x7F, 0x00, 0x00, 0xF8, 0x03, 0x7F, 0x00, 0x00, 0xF8, 0x03, 
  0x7E, 0x00, 0x00, 0xF8, 0x03, 0x7F, 0x00, 0x00, 0xF8, 0x03, 0x7F, 0x00, 
  0x00, 0xF8, 0x03, 0x7F, 0x00, 0x00, 0xF8, 0x03, 0x7F, 0x00, 0x00, 0xF8, 
  0x03, 0x7F, 0x00, 0x00, 0xF8, 0x03, 0x7F, 0x00, 0x00, 0xF8, 0x03, 0xFE, 
  0x49, 0x92, 0xFC, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0xFF, 0xFF, 0xFF, 
  0xFF, 0x03, 0x40, 0x24, 0x42, 0x22, 0x00, };

#define detect_width 35
#define detect_height 35
PROGMEM const unsigned char detect_bits[] = {
  0x00, 0x80, 0x0F, 0x00, 0x00, 0x00, 0xC0, 0x1F, 0x00, 0x00, 0x00, 0xC0, 
  0x0F, 0x00, 0x00, 0x00, 0xC0, 0x1F, 0x08, 0x00, 0xC0, 0xF1, 0x7F, 0x1C, 
  0x00, 0xE0, 0xFF, 0xFF, 0x3F, 0x00, 0xF0, 0xFF, 0xFF, 0x7F, 0x00, 0xF0, 
  0xFF, 0xFF, 0x7F, 0x00, 0xF0, 0x7F, 0xF0, 0x7F, 0x00, 0xE0, 0x1F, 0xC0, 
  0x3F, 0x00, 0xE0, 0x07, 0x80, 0x1F, 0x00, 0xE0, 0x07, 0x00, 0x3F, 0x00, 
  0xF0, 0x03, 0x00, 0x3E, 0x00, 0xF0, 0x41, 0x70, 0x7C, 0x00, 0xFE, 0xC1, 
  0x38, 0xFC, 0x03, 0xFF, 0xC0, 0x30, 0xFC, 0x07, 0xFF, 0xE0, 0x20, 0xFC, 
  0x07, 0xFF, 0xA0, 0x31, 0xF8, 0x03, 0xFF, 0xE1, 0x21, 0xF8, 0x07, 0xFF, 
  0xF1, 0x31, 0xFC, 0x07, 0xFC, 0x31, 0x73, 0xFC, 0x00, 0xF0, 0x01, 0x20, 
  0x7C, 0x00, 0xE0, 0x03, 0x00, 0x3E, 0x00, 0xE0, 0x07, 0x00, 0x3F, 0x00, 
  0xE0, 0x0F, 0x80, 0x1F, 0x00, 0xE0, 0x1F, 0xC0, 0x3F, 0x00, 0xF0, 0xFF, 
  0xFE, 0x7F, 0x00, 0xF0, 0xFF, 0xFF, 0x7F, 0x00, 0xF0, 0xFF, 0xFF, 0x7F, 
  0x00, 0xE0, 0xFB, 0xFF, 0x3E, 0x00, 0xC0, 0xE1, 0x3F, 0x1C, 0x00, 0x00, 
  0xC0, 0x1F, 0x00, 0x00, 0x00, 0xC0, 0x1F, 0x00, 0x00, 0x00, 0x80, 0x0F, 
  0x00, 0x00, 0x00, 0x80, 0x09, 0x00, 0x00, };

#define fine_width 150
#define fine_height 150
PROGMEM const unsigned char fine_bits[] = {
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA0, 0x1B, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0xE0, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 
  0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 
  0x00, 0x80, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x07, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 
  0x00, 0x00, 0x00, 0xF0, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0xFC, 0xFF, 
  0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0x7F, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x80, 
  0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0xC0, 0xFF, 0xFF, 0x01, 0x00, 0x00, 
  0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 
  0x00, 0xF0, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 
  0xFF, 0x0F, 0x40, 0xFF, 0xFF, 0xFF, 0x1F, 0x00, 0xF8, 0xFF, 0x3F, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0xE0, 0xFF, 
  0xFF, 0x7F, 0x00, 0xFC, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 
  0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0x00, 0xFE, 0xFF, 
  0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0x3F, 0x00, 0x00, 0x00, 
  0x00, 0xF0, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0x3F, 0xC0, 
  0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x03, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0xFE, 0x1F, 0xE0, 0xFF, 0x7F, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0xE0, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 
  0x0F, 0xF0, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0x3F, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x07, 0xF8, 0xFF, 0x1F, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0xC0, 0x03, 0xFC, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 
  0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 
  0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0x01, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 
  0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x7F, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0x01, 0x00, 0x00, 
  0x00, 0x00, 0x80, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0xF0, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0x0F, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x7F, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0xFC, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 
  0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 
  0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0x01, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0xF8, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 
  0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x7F, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0xFF, 0x03, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0xFC, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0xE0, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x3F, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0x01, 
  0x03, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0x80, 0x03, 0x00, 0x00, 0x00, 0x00, 
  0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 
  0x7F, 0xC0, 0x07, 0x00, 0x00, 0x00, 0x80, 0xFF, 0x0F, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0x7F, 0xE0, 0x07, 0x00, 0x00, 
  0x00, 0x80, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0xFF, 0xFF, 0x3F, 0xF0, 0x0F, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0x03, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x1F, 0xF0, 0x0F, 
  0x00, 0x00, 0x00, 0xC0, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x80, 0xFF, 0xFF, 0x0F, 0xF8, 0x1F, 0x00, 0x00, 0x00, 0xE0, 0xFF, 
  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0xFF, 0x0F, 
  0xFC, 0x1F, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0x07, 0xFC, 0x3F, 0x00, 0x00, 0x00, 
  0xF0, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 
  0xFF, 0x03, 0xF8, 0x3F, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0x01, 0xF8, 0x7F, 0x00, 
  0x00, 0x00, 0xF0, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0xFC, 0xFF, 0xFF, 0x01, 0xF8, 0x7F, 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0x00, 0xF0, 
  0x7F, 0x00, 0x00, 0x00, 0xF8, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0xFF, 0xFF, 0x7F, 0x00, 0xF0, 0xFF, 0x00, 0x00, 0x00, 0xF8, 
  0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x7F, 
  0x00, 0xE0, 0xFF, 0x00, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0xC0, 0xFF, 0xFF, 0x3F, 0x00, 0xE0, 0xFF, 0x00, 0x00, 
  0x00, 0xFC, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 
  0xFF, 0x1F, 0x00, 0xC0, 0xFF, 0x01, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0x1F, 0x00, 0xC0, 0xFF, 
  0x01, 0x00, 0x00, 0xFE, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0xF0, 0xFF, 0xFF, 0x0F, 0x00, 0xC0, 0xFF, 0x01, 0x00, 0x00, 0xFE, 0x0F, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0x07, 0x00, 
  0x80, 0xFF, 0x01, 0x00, 0x00, 0xFE, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0xFC, 0xFF, 0xFF, 0x07, 0x00, 0x80, 0xFF, 0x03, 0x00, 0x00, 
  0xFE, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 
  0x03, 0x00, 0x80, 0xFF, 0x03, 0x00, 0x00, 0xFF, 0x07, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x80, 0xFF, 0x03, 
  0x00, 0x00, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 
  0xFF, 0xFF, 0x01, 0x00, 0x00, 0xFF, 0x03, 0x00, 0x00, 0xFF, 0x07, 0x00, 
  0x00, 0x70, 0x01, 0x00, 0x00, 0xC0, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 
  0xFF, 0x03, 0x00, 0x00, 0xFF, 0x03, 0x00, 0x80, 0xFF, 0x03, 0x00, 0x00, 
  0xE0, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0xFF, 0x07, 0x00, 0x00, 0xFF, 
  0x07, 0x00, 0xE0, 0xFF, 0x03, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0x7F, 0x00, 
  0x00, 0x00, 0xFF, 0x07, 0x00, 0x00, 0xFF, 0x03, 0x00, 0xF8, 0xFF, 0x07, 
  0x00, 0x00, 0xF0, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0xFF, 0x07, 0x00, 
  0x80, 0xFF, 0x03, 0x00, 0xFE, 0xFF, 0x0F, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 
  0x1F, 0x00, 0x00, 0x00, 0xFF, 0x07, 0x00, 0x80, 0xFF, 0x03, 0x00, 0xFF, 
  0xFF, 0x1F, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0xFE, 
  0x07, 0x00, 0x80, 0xFF, 0x03, 0x80, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0xFE, 
  0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0xFE, 0x07, 0x00, 0x80, 0xFF, 0x03, 
  0xC0, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 
  0x00, 0xFE, 0x07, 0x00, 0x80, 0xFF, 0x01, 0xC0, 0xFF, 0xFF, 0x7F, 0x00, 
  0x80, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0xFE, 0x07, 0x00, 0x80, 
  0xFF, 0x03, 0xE0, 0xFF, 0xFF, 0xFF, 0x00, 0xC0, 0xFF, 0xFF, 0xFF, 0x03, 
  0x00, 0x00, 0x00, 0xFE, 0x0F, 0x00, 0x80, 0xFF, 0x03, 0xF0, 0xFF, 0xFF, 
  0xFF, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0xFE, 0x0F, 
  0x00, 0x80, 0xFF, 0x01, 0xF0, 0xFF, 0xFF, 0xFF, 0x01, 0xF0, 0xFF, 0xFF, 
  0xFF, 0x01, 0x00, 0x00, 0x00, 0xFE, 0x07, 0x00, 0x80, 0xFF, 0x01, 0xF8, 
  0xFF, 0xFF, 0xFF, 0x03, 0xF0, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 
  0xFE, 0x0F, 0x00, 0x80, 0xFF, 0x03, 0xF0, 0xFF, 0xFF, 0xFF, 0x07, 0xF8, 
  0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x07, 0x00, 0x80, 0xFF, 
  0x01, 0xE0, 0xFF, 0xFF, 0xFF, 0x07, 0xFC, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 
  0x00, 0x00, 0xFE, 0x0F, 0x00, 0x80, 0xFF, 0x03, 0xC0, 0xFF, 0xFF, 0xFF, 
  0x0F, 0xFE, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x07, 0x00, 
  0x80, 0xFF, 0x03, 0x80, 0xFF, 0xFF, 0xFF, 0x1F, 0xFF, 0xFF, 0xFF, 0x3F, 
  0x00, 0x00, 0x00, 0x00, 0xFE, 0x07, 0x00, 0x80, 0xFF, 0x03, 0x00, 0xFF, 
  0xFF, 0xFF, 0xBF, 0xFF, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0xFE, 
  0x07, 0x00, 0x80, 0xFF, 0x03, 0x00, 0xFE, 0xFF, 0xFF, 0xBF, 0xFF, 0xFF, 
  0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x07, 0x00, 0x80, 0xFF, 0x03, 
  0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 
  0x00, 0xFE, 0x07, 0x00, 0x80, 0xFF, 0x03, 0x00, 0xF8, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x07, 0x00, 0x00, 
  0xFF, 0x03, 0x00, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 
  0x00, 0x00, 0x00, 0xFF, 0x07, 0x00, 0x00, 0xFF, 0x03, 0x00, 0xF0, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x07, 
  0x00, 0x00, 0xFF, 0x07, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0x03, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x07, 0x00, 0x00, 0xFF, 0x07, 0x00, 
  0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 
  0xFF, 0x03, 0x00, 0x00, 0xFF, 0x07, 0x00, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0x03, 0x00, 0x00, 0xFE, 
  0x07, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 
  0x00, 0x80, 0xFF, 0x03, 0x00, 0x00, 0xFE, 0x0F, 0x00, 0x80, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0x03, 0x00, 
  0x00, 0xFE, 0x0F, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 
  0x00, 0x00, 0x00, 0x80, 0xFF, 0x03, 0x00, 0x00, 0xFE, 0x0F, 0x00, 0x00, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, 
  0x01, 0x00, 0x00, 0xFE, 0x0F, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 
  0x1F, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0x01, 0x00, 0x00, 0xFC, 0x1F, 
  0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 
  0xC0, 0xFF, 0x01, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 
  0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x01, 0x00, 0x00, 
  0xFC, 0x3F, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x00, 
  0x00, 0x00, 0xE0, 0xFF, 0x00, 0x00, 0x00, 0xF8, 0x3F, 0x00, 0x00, 0xF8, 
  0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x00, 
  0x00, 0x00, 0xF8, 0x3F, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 
  0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 
  0x00, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0xF0, 
  0x7F, 0x00, 0x00, 0x00, 0xF0, 0x7F, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0xFF, 
  0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x00, 0x00, 0xF0, 
  0xFF, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0xF8, 0x3F, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x00, 0x00, 0xE0, 0xFF, 
  0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x3F, 0x00, 0x00, 
  0x00, 0xE0, 0xFF, 0x01, 0x00, 0xC0, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0xFC, 0x3F, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0x01, 0x00, 
  0xC0, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x1F, 
  0x00, 0x00, 0x00, 0xC0, 0xFF, 0x03, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0x1F, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x0F, 0x00, 0x00, 0x00, 0xC0, 0xFF, 
  0x07, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0xFF, 0x0F, 0x00, 0x00, 0x00, 0x80, 0xFF, 0x07, 0x00, 0x00, 0xFF, 0xFF, 
  0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0x0F, 0x00, 0x00, 0x00, 
  0x00, 0xFF, 0x0F, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 
  0x00, 0x80, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x1F, 0x00, 0x00, 
  0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0x03, 0x00, 
  0x00, 0x00, 0x00, 0xFE, 0x1F, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0x01, 0x00, 
  0x00, 0x00, 0x00, 0xE0, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x3F, 
  0x00, 0x00, 0xFE, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 
  0x01, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x7F, 0x00, 0x00, 0xFC, 0xFF, 0x3F, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 
  0xF8, 0xFF, 0x00, 0x00, 0xFC, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0xF8, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x01, 0x00, 0xFC, 
  0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x7F, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0xF0, 0xFF, 0x03, 0x00, 0xF8, 0xFF, 0x07, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0xFE, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x07, 
  0x00, 0xF8, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x3F, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x0F, 0x00, 0xF0, 0xFF, 0x01, 0x00, 
  0x00, 0x00, 0x00, 0x80, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 
  0xFF, 0x1F, 0x00, 0xF0, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, 
  0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0x3F, 0x00, 0xF0, 0x7F, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0xFF, 0x7F, 0x00, 0xE0, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0xF8, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0x01, 
  0xE0, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0x03, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0xFE, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 
  0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0x1F, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0xC0, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0xE0, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 
  0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0xFF, 0x01, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 
  0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0x03, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0x00, 0x00, 0x00, 
  0x00, 0xF8, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0xF8, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0x7F, 
  0x00, 0x00, 0xF8, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0xC0, 0xFF, 0xFF, 0xFF, 0xBF, 0xFD, 0xFF, 0xFF, 0xFF, 
  0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 
  0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, };

#define danger_width 150
#define danger_height 150
PROGMEM const unsigned char danger_bits[] = {
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF4, 0x7F, 0x13, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0xF0, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 
  0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xAF, 0x40, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 
  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0xFF, 0x7F, 
  0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0xF8, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0xF8, 0xFF, 
  0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 
  0xFF, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0xFE, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 
  0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0x3F, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0xE0, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 
  0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0x1F, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0x01, 0x00, 0x00, 
  0x00, 0x00, 0xF0, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0xF8, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 
  0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0x07, 
  0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0xC0, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xFE, 
  0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 
  0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00, 
  0x80, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0xFC, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x07, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x7F, 0x00, 
  0x00, 0x00, 0xC0, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 
  0x00, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 
  0x01, 0x00, 0x00, 0x00, 0x80, 0x7F, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 
  0xFF, 0x01, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xC0, 
  0xFF, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0xF0, 
  0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x01, 0x00, 0x00, 0x00, 
  0x80, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0xF8, 0xFF, 0x3F, 0x00, 0x00, 0x00, 
  0x00, 0xF0, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x07, 0x00, 
  0x00, 0xF8, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0x03, 0x00, 
  0x00, 0x00, 0x00, 0xFE, 0xFF, 0x07, 0x00, 0x00, 0xFC, 0xFF, 0x1F, 0x00, 
  0x00, 0x00, 0x00, 0xF8, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 
  0x0F, 0x00, 0x00, 0xFE, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 
  0x03, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0x1F, 0x00, 0x00, 0xFE, 0xFF, 
  0x07, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 
  0xF8, 0xFF, 0x1F, 0x00, 0x00, 0xFE, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 
  0xF8, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0x3F, 0x00, 0x00, 
  0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0x07, 0x00, 0x00, 
  0x00, 0x00, 0xF0, 0xFF, 0x3F, 0x00, 0x80, 0xFF, 0xFF, 0x01, 0x00, 0x00, 
  0x00, 0x00, 0xF8, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x3F, 
  0x00, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x03, 
  0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0x7F, 0x00, 0xC0, 0xFF, 0xFF, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0xC0, 
  0xFF, 0xFF, 0x00, 0xC0, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 
  0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0xC0, 0xFF, 
  0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x03, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0xFF, 0xFF, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0xF8, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x01, 
  0xE0, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x07, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0x01, 0xF0, 0xFF, 0x1F, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0xF0, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 
  0xFF, 0x03, 0xF0, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 
  0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0x03, 0xF0, 0xFF, 0x0F, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0xFC, 0xFF, 0x03, 0xF8, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0xF8, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0x07, 0xF8, 
  0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x03, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0xF8, 0xFF, 0x07, 0xF8, 0xFF, 0x07, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0xF0, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 
  0x07, 0xF8, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x03, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x07, 0xFC, 0xFF, 0x03, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0xF0, 0xFF, 0x0F, 0xFC, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 
  0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0x0F, 0xFC, 0xFF, 
  0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x07, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0xF0, 0xFF, 0x0F, 0xFC, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0xF8, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x0F, 
  0xFE, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x07, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x1F, 0xFE, 0xFF, 0x01, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0xF0, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 
  0xFF, 0x1F, 0xFE, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 
  0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x1F, 0xFE, 0xFF, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0xC0, 0xFF, 0x1F, 0xFE, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0xF8, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0x1F, 0xFE, 
  0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0x03, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0xC0, 0xFF, 0x1F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0xF8, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, 
  0x1F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x07, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0x3F, 0xFE, 0x7F, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0xC0, 0xFF, 0x3F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 
  0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0x3F, 0xFF, 0x7F, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0x07, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0xC0, 0xFF, 0x3F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0xF8, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0x3F, 
  0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x07, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0x3F, 0xFF, 0x7F, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0xF0, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 
  0xFF, 0x3F, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 
  0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0x3F, 0xFF, 0x7F, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x80, 0xFF, 0x3F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0xF8, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0x3F, 0xFF, 
  0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0x03, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x80, 0xFF, 0x3F, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0xF8, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, 
  0x3F, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x03, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0x3F, 0xFF, 0xFF, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0xC0, 0xFF, 0x3F, 0xFE, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 
  0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0x3F, 0xFF, 0xFF, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0x03, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0xC0, 0xFF, 0x3F, 0xFE, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0xE0, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0x1F, 
  0xFE, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0x1F, 0xFE, 0xFF, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x80, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 
  0xFF, 0x1F, 0xFE, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0x1F, 0xFE, 0xFF, 0x01, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0xE0, 0xFF, 0x1F, 0xFE, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x1F, 0xFE, 
  0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0xE0, 0xFF, 0x1F, 0xFC, 0xFF, 0x01, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 
  0x0F, 0xFC, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0x0F, 0xFC, 0xFF, 0x03, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0xF0, 0xFF, 0x0F, 0xFC, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0x0F, 0xF8, 0xFF, 
  0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0xF8, 0xFF, 0x07, 0xF8, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x07, 
  0xF8, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x07, 0xF8, 0xFF, 0x0F, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 
  0xFF, 0x07, 0xF0, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0x03, 0xF0, 0xFF, 0x1F, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0xFE, 0xFF, 0x03, 0xF0, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0x03, 0xE0, 
  0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0xFF, 0xFF, 0x01, 0xE0, 0xFF, 0x3F, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 
  0x01, 0xC0, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xC0, 0xFF, 0x7F, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 
  0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 
  0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0x7F, 0x00, 0x80, 0xFF, 
  0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x01, 0x00, 0x00, 0x00, 
  0x00, 0xC0, 0xFF, 0x7F, 0x00, 0x80, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 
  0x00, 0xF0, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x7F, 0x00, 
  0x00, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0x03, 0x00, 
  0x00, 0x00, 0x00, 0xF0, 0xFF, 0x3F, 0x00, 0x00, 0xFF, 0xFF, 0x03, 0x00, 
  0x00, 0x00, 0x00, 0xF0, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 
  0x3F, 0x00, 0x00, 0xFE, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 
  0x03, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x1F, 0x00, 0x00, 0xFC, 0xFF, 
  0x0F, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 
  0xFC, 0xFF, 0x0F, 0x00, 0x00, 0xFC, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 
  0xF0, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0x0F, 0x00, 0x00, 
  0xF8, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0x03, 0x00, 0x00, 
  0x00, 0x00, 0xFE, 0xFF, 0x07, 0x00, 0x00, 0xF8, 0xFF, 0x3F, 0x00, 0x00, 
  0x00, 0x00, 0xE0, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x07, 
  0x00, 0x00, 0xF0, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x01, 
  0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 
  0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, 
  0xFF, 0x01, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 
  0x3F, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0xC0, 
  0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0xF0, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x07, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x7F, 0x00, 0x00, 
  0x00, 0x80, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0xFC, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3F, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3F, 
  0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0xFC, 
  0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, 
  0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0x03, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 
  0x00, 0xF0, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0xF8, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0x1F, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0x03, 0x00, 
  0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, 
  0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0xFE, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 
  0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 
  0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0xF8, 
  0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 
  0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x9F, 0x00, 
  0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 
  0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD8, 0xFF, 0x07, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, };

#define assist_width 150
#define assist_height 150
PROGMEM const unsigned char assist_bits[] = {
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x01, 0x00, 0x00, 0x00, 0xF0, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0xF8, 0x07, 0x00, 0x00, 0x00, 0xFC, 0x07, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x0F, 0x00, 0x00, 
  0x00, 0xFE, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0x1F, 
  0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0xFF, 0xFF, 
  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 
  0xFF, 0x3F, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0x7F, 0x00, 0x00, 0xC0, 
  0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x80, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xC0, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0xFF, 0xFF, 0x00, 
  0x00, 0xE0, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0xF0, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, 
  0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 
  0xFF, 0x01, 0x00, 0xF0, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0xF0, 0xFF, 
  0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 
  0xFF, 0xFF, 0xFF, 0x03, 0x00, 0xF8, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 
  0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0xF8, 0xFF, 0xFF, 0xC7, 0xFF, 0x0F, 0x00, 0xFC, 0xFF, 0xFC, 0xFF, 0xFF, 
  0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xC3, 0xFF, 
  0x0F, 0x00, 0xFE, 0x7F, 0xF0, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xC0, 
  0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0xFF, 0x3F, 
  0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0x1F, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 
  0x3F, 0x00, 0xFE, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 
  0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0x00, 0xF8, 0xFF, 0xFF, 
  0x03, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0x01, 0x00, 0xFE, 0xFF, 
  0xFF, 0xFF, 0x1F, 0x00, 0xE0, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 
  0xF0, 0xFF, 0xFF, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x80, 
  0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x3F, 0x00, 0x00, 
  0xFC, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0xFF, 0xFF, 0x03, 0x00, 0x00, 
  0x00, 0x00, 0xF8, 0xFF, 0x0F, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0xFF, 0x07, 
  0x00, 0x00, 0xFC, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0x03, 
  0x00, 0x00, 0xF8, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0xF0, 0xFF, 0x03, 
  0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0x03, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 
  0xFF, 0x03, 0x00, 0x00, 0xF8, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0xE0, 
  0xFF, 0x07, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0xF8, 
  0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x07, 0x00, 0x00, 0xC0, 
  0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0xC0, 0xFF, 0x0F, 0x00, 0x00, 0x80, 0x0F, 0x00, 0x3E, 0x00, 0x00, 
  0x00, 0xFC, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0x0F, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x7F, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x80, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 
  0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x3F, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0xFE, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 
  0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x7F, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0x0F, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0xFC, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0xC0, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x07, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0xE0, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0xF8, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 
  0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0x03, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0xF0, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0xF0, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x01, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0x07, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0xE0, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 
  0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0xE0, 0xFF, 0x0F, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0xF8, 0x3F, 0x00, 0xC0, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0xFE, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x7F, 0x00, 0x80, 
  0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x3F, 0x00, 0x00, 
  0x00, 0x00, 0x80, 0xFF, 0x7F, 0x00, 0x80, 0xFF, 0x3F, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x80, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x1F, 
  0x00, 0x00, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0x1F, 
  0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0x1F, 0x00, 0x00, 0xFE, 0x7F, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xF8, 
  0xFF, 0x0F, 0x00, 0x00, 0xFC, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x40, 0xC0, 
  0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0x07, 0x00, 0x00, 0xFC, 
  0xFF, 0xFE, 0xFF, 0x03, 0xF8, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 
  0x00, 0xFC, 0xFF, 0x03, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0xFF, 0x07, 0xFC, 
  0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0x01, 0x00, 
  0x00, 0xF8, 0xFF, 0xFF, 0xFF, 0x1F, 0xFE, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 
  0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0xFF, 
  0x1F, 0xFE, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x7F, 
  0x00, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0xFF, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 
  0x01, 0x00, 0x00, 0x00, 0x80, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0xE0, 0xFF, 
  0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x80, 
  0xFF, 0x1F, 0x00, 0x00, 0x03, 0xE0, 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 
  0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0x0F, 0x00, 0x80, 0x03, 
  0xC0, 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 
  0x00, 0x80, 0xFF, 0x07, 0x00, 0xC0, 0x07, 0xC0, 0xFF, 0xFF, 0xFF, 0x3F, 
  0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0x07, 0x00, 
  0xE0, 0x07, 0xC0, 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 
  0x00, 0x00, 0x00, 0x80, 0xFF, 0x0F, 0x00, 0xF0, 0x07, 0x80, 0xFF, 0xFF, 
  0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, 
  0x0F, 0x00, 0xF8, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 
  0x0F, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0x0F, 0x00, 0xFC, 0x07, 0x00, 
  0xA8, 0x65, 0xFE, 0x3F, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0xC0, 0xFF, 0x1F, 0x00, 0xFE, 0x07, 0x00, 0x00, 0x00, 0xFC, 0x3F, 0xFF, 
  0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0x1F, 0x00, 0xFF, 
  0x07, 0x00, 0x00, 0x00, 0xFC, 0x3F, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x80, 0xFF, 0x3F, 0x80, 0xFF, 0x07, 0x00, 0x00, 0x00, 0xFC, 
  0x3F, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 
  0xC0, 0xFF, 0x03, 0x00, 0x00, 0x00, 0xFC, 0x3F, 0xFF, 0x0F, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0xE7, 0xFF, 0x03, 0x00, 0x00, 
  0x00, 0xFC, 0x3F, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 
  0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0xFC, 0x3F, 0xFF, 0x0F, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 
  0x00, 0x00, 0x00, 0xFC, 0x3F, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0xFC, 0x3F, 
  0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0xFF, 
  0xFF, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x3F, 0xFF, 0x0F, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 
  0xFC, 0x3F, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 
  0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x3F, 0xFF, 0x0F, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 
  0x00, 0x00, 0xFC, 0x3F, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x3F, 0xFF, 
  0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 
  0x00, 0x00, 0x00, 0x00, 0xFC, 0x3F, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0xFC, 
  0x3F, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, 
  0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x3F, 0xFF, 0x0F, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0xFC, 0x3F, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 
  0xFF, 0xE3, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x3F, 0xFF, 0x0F, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0xFC, 0x3F, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0xFE, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x3F, 
  0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x3F, 0xFF, 0x0F, 0x00, 0x00, 0x00, 
  0x00, 0x80, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0xFC, 0x3F, 0xFF, 0xDF, 0x59, 0x05, 0x00, 0x00, 0xC0, 0xFF, 0xFF, 0x1F, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 
  0x3F, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0xF0, 0xFF, 
  0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 
  0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 
  0x00, 0xC0, 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 
  0xFC, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0xFF, 0xFF, 
  0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0x01, 0x00, 
  0x00, 0x00, 0x00, 0xC0, 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 
  0x01, 0x00, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 
  0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x80, 0xFF, 0xFF, 0x7F, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, 0x3F, 0xFE, 0xFF, 
  0xFF, 0xFF, 0x03, 0xC0, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0xF0, 0xFF, 0xFF, 0xFF, 0x1F, 0xFE, 0xFF, 0xFF, 0xFF, 0x03, 0xE0, 0xFF, 
  0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0xFF, 0x1F, 
  0xFE, 0xFF, 0xFF, 0xFF, 0x07, 0xF0, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0xF8, 0xFF, 0xFF, 0xFF, 0x0F, 0xF8, 0xFF, 0xFF, 0xFF, 0x07, 
  0xF8, 0xE7, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 
  0xFF, 0x07, 0xE0, 0xFF, 0xF7, 0xFF, 0x0F, 0xF8, 0xC3, 0xFF, 0x03, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0x00, 0x10, 0x00, 0x00, 0x00, 0x80, 
  0xFF, 0x0F, 0xF8, 0x81, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 
  0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0x1F, 0xF8, 0x81, 0xFF, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x7F, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0xFF, 0x3F, 0xF0, 0xC1, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x7F, 0xF0, 
  0xC3, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0x3F, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0xFE, 0x7F, 0xE0, 0xFF, 0x1F, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x80, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 
  0xFF, 0xC0, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0x1F, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0x81, 0xFF, 0x07, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0xF8, 0xFF, 0x01, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 
  0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x03, 0xFE, 
  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0x07, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0xF0, 0xFF, 0x03, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0xF0, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 
  0x03, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0x03, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0xE0, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0xF0, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 
  0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x01, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0xFC, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0xC0, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0x1F, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0xFE, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x80, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 
  0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x3F, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x80, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0xFE, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0x1F, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0xC0, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x7E, 0x00, 
  0x00, 0x00, 0xFC, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0x0F, 
  0x00, 0x00, 0xC0, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0xF8, 0xFF, 0x01, 
  0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x07, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 
  0xFF, 0x01, 0x00, 0x00, 0xF8, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0xE0, 
  0xFF, 0x07, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0xF0, 
  0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0x03, 0x00, 0x00, 0xF0, 
  0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0xF8, 0xFF, 0x03, 0x00, 0x00, 0x00, 
  0x00, 0xF0, 0xFF, 0x0F, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 
  0x00, 0xFC, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0x3F, 0x00, 
  0x00, 0xF8, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0xFF, 0xFF, 0x07, 0x00, 
  0x00, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 
  0x0F, 0x00, 0x80, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 
  0xFF, 0x01, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x1F, 0x00, 0xE0, 0xFF, 0xFF, 
  0x03, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0x07, 0x00, 0xFE, 0xFF, 
  0xFF, 0xFF, 0x3F, 0x00, 0xF8, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 
  0xE0, 0xFF, 0xFF, 0x1F, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0xFE, 
  0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0xFF, 0x3F, 0x00, 
  0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 
  0xC0, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 
  0xFF, 0x83, 0xFF, 0x1F, 0x00, 0xFC, 0xFF, 0xF0, 0xFF, 0xFF, 0x0F, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0xCF, 0xFF, 0x0F, 0x00, 
  0xFC, 0xFF, 0xFC, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 
  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 
  0x07, 0x00, 0xF0, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0xF0, 0xFF, 0xFF, 
  0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 
  0xFF, 0xFF, 0x03, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0xE0, 
  0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0xC0, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0xC0, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0x00, 
  0x00, 0xC0, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0xFE, 0xFF, 0x7F, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x1F, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 
  0x7F, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0xFF, 
  0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0xC0, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x1F, 0x00, 0x00, 
  0x00, 0xFE, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0x00, 0xFC, 0x0F, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x0F, 
  0x00, 0x00, 0x00, 0xF8, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x03, 0x00, 0x00, 0x00, 0xE0, 0x01, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, };

#define stolen_width 128
#define stolen_height 150
PROGMEM const unsigned char stolen_bits[] = {
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 
  0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x60, 0x00, 0xF8, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x01, 0xFE, 0x7F, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x03, 0xF8, 0x07, 0xFF, 
  0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 
  0x07, 0xFC, 0x9F, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0xFE, 0x1F, 0xFC, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x3F, 0xFF, 0xFF, 0xFF, 
  0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 
  0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 
  0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 
  0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 
  0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x55, 0x2A, 0xE5, 0xFF, 0xFF, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 
  0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0x01, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x1F, 0x00, 0x00, 0x00, 0xF0, 0xFF, 
  0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x0F, 0x00, 
  0x00, 0x00, 0xE0, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0xC0, 0x07, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0x03, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x03, 0x00, 0x00, 0x00, 0xC0, 0xFF, 
  0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x01, 0x00, 
  0x00, 0x00, 0x80, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0xF8, 0x01, 0x00, 0x00, 0x00, 0x80, 0xBF, 0xC8, 0x1F, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x00, 0x10, 0x00, 0x3F, 
  0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, 
  0x00, 0x3C, 0x00, 0x3E, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x3E, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x3E, 0x00, 0x3C, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x7C, 
  0x00, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 
  0x80, 0xFF, 0x01, 0x7C, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x80, 0x0F, 0x00, 0x00, 0xC0, 0xFF, 0x03, 0xFC, 0x00, 0x1C, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x00, 0xC0, 0xFF, 0x0F, 0xF8, 
  0xB7, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x07, 0x00, 0x00, 
  0xE0, 0xFF, 0x3F, 0xFC, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x48, 0xF5, 
  0xFF, 0x03, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 
  0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0xFF, 
  0xFF, 0x0F, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 
  0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0x6F, 0xA0, 0x1F, 0x00, 0x00, 
  0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x00, 
  0x00, 0x1E, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0xF1, 0x00, 0x00, 0x00, 
  0xF8, 0x03, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 
  0xF1, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 
  0xFC, 0xFF, 0xFF, 0xFF, 0xF1, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x00, 
  0x00, 0x3C, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0xFF, 0xE1, 0x01, 0x00, 0x00, 
  0x3C, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0xFF, 
  0xE1, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 
  0xF0, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 
  0x00, 0x3E, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0xFF, 0xE1, 0x00, 0x00, 0x00, 
  0x78, 0x00, 0x00, 0x00, 0x80, 0x1F, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, 
  0xE1, 0x01, 0x00, 0x00, 0xF8, 0x00, 0x00, 0xF9, 0xFF, 0x1F, 0x00, 0x00, 
  0xE0, 0xFF, 0xFF, 0xFF, 0xE1, 0x00, 0x00, 0x00, 0xF8, 0xE7, 0xFF, 0xFF, 
  0xFF, 0x0F, 0x00, 0x00, 0xC0, 0xFF, 0xFF, 0xFF, 0xE1, 0x00, 0x00, 0x00, 
  0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0xC0, 0xFF, 0xFF, 0xFF, 
  0xE1, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 
  0x80, 0xFF, 0xFF, 0xFF, 0xE1, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0xFF, 
  0xFF, 0x01, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xE1, 0x01, 0x00, 0x00, 
  0xF8, 0xFF, 0x25, 0x00, 0xF8, 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 
  0xE1, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x00, 0xF0, 0x01, 0x00, 0x00, 
  0x00, 0xFF, 0xFF, 0xFF, 0xE1, 0x01, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x00, 
  0xE0, 0x01, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0xE1, 0x00, 0x00, 0x00, 
  0xF8, 0x00, 0x00, 0x00, 0xF0, 0x01, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 
  0xE1, 0x01, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x00, 0xF0, 0x01, 0x00, 0x00, 
  0x00, 0xFE, 0xFF, 0xFF, 0xE1, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x00, 
  0xF8, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xE1, 0x01, 0x00, 0x00, 
  0xF8, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 
  0xE1, 0x00, 0x00, 0x00, 0xF8, 0xA7, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00, 
  0x00, 0xF8, 0xFF, 0xFF, 0xE1, 0x01, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0xFF, 
  0x1F, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0xC1, 0x01, 0x00, 0x00, 
  0xF8, 0xFF, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 
  0xE1, 0x01, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 
  0x00, 0xF0, 0xFF, 0xFF, 0xC1, 0x01, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0xFF, 
  0x0F, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0xE3, 0x01, 0x00, 0x00, 
  0xFC, 0x27, 0x00, 0xE0, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 
  0xC1, 0x01, 0x00, 0x00, 0xFE, 0x01, 0x00, 0xC0, 0x07, 0x00, 0x00, 0x00, 
  0x00, 0xE0, 0xFF, 0xFF, 0xC1, 0x01, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x80, 
  0x07, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0xC3, 0x01, 0x00, 0x00, 
  0x7F, 0x00, 0x00, 0x80, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 
  0xC3, 0x01, 0x00, 0x80, 0x7F, 0x00, 0x00, 0x80, 0x1F, 0x00, 0x00, 0x00, 
  0x00, 0xC0, 0xFF, 0xFF, 0xC1, 0x01, 0x00, 0x80, 0xFF, 0x00, 0x00, 0xC0, 
  0x3F, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0xFF, 0xC1, 0x01, 0x00, 0xC0, 
  0xFF, 0x00, 0x90, 0xF7, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0xFF, 
  0xC3, 0x03, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 
  0x00, 0xC0, 0xFF, 0xFF, 0xC3, 0x01, 0x00, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0x03, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0xFF, 0xC3, 0x01, 0x00, 0xF8, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 
  0xC1, 0x03, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 
  0x00, 0x80, 0xFF, 0xFF, 0xC3, 0x03, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0x1F, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0xC3, 0x01, 0x00, 0xFE, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 
  0xC3, 0x1B, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 
  0x00, 0x80, 0xFF, 0xFF, 0xC3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0xC3, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 
  0xC3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 
  0x00, 0x80, 0xFF, 0xFF, 0xC3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC3, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0xFF, 0xFF, 
  0xC3, 0x5F, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 
  0x00, 0x00, 0xFF, 0xFF, 0xC7, 0x03, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x03, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0xFF, 0xFF, 
  0xFF, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 
  0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x83, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xC3, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0xFF, 0xFF, 
  0xFF, 0xC3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 
  0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xE3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0xFF, 0xFF, 0xBF, 0xF0, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xF3, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0xFF, 0xFF, 
  0x03, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xF3, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 
  0x00, 0x00, 0xFE, 0xFF, 0x03, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xF3, 0xFF, 
  0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0xFF, 0xFF, 0x03, 0xF8, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xF3, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0xFF, 0xFF, 
  0x03, 0xFC, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x07, 
  0x00, 0x00, 0xFE, 0xFF, 0x03, 0xFC, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0xF0, 
  0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0xFF, 0xFF, 0x03, 0xFC, 0xFF, 0xFF, 
  0xFF, 0x03, 0x00, 0xF0, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0xFF, 0xFF, 
  0x03, 0xFE, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0xF0, 0xFF, 0xFF, 0xFF, 0x1F, 
  0x00, 0x00, 0xFE, 0xFF, 0x03, 0xFE, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0xF0, 
  0xFF, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0xFF, 0xFF, 0x03, 0xFE, 0xFF, 0xFF, 
  0xFF, 0x00, 0x73, 0xF0, 0xFF, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0xFF, 0x3F, 
  0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0xF3, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0xE3, 0xFF, 
  0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xC0, 0xF3, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0xF3, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 
  0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xF2, 0xFF, 
  0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 
  0xFF, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 
  0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 
  0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0xF8, 
  0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 
  0xFF, 0x07, 0x00, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 
  0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0xF0, 0xFF, 0xFF, 0xFF, 0x7F, 
  0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0xE0, 
  0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0x01, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 
  0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x31, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x71, 0xC0, 
  0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0x71, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x79, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x71, 0xC0, 
  0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 
  0xFF, 0xF9, 0x31, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0xE0, 
  0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 
  0xFF, 0x01, 0x00, 0xF0, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0xF8, 0xFF, 0xFF, 0xFF, 0x7F, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0xFE, 
  0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 
  0xFF, 0x1F, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xF1, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xF1, 0xFF, 
  0xFF, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xF1, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 
  0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0xFC, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0xFB, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 
  };
  
#define call_width 150
#define call_height 150
PROGMEM const unsigned char call_bits[] = {
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0xE0, 0x1F, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0x3F, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x00, 0x00, 
  0x00, 0xF0, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0xFC, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0x1F, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 
  0x00, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0xF8, 0xFF, 
  0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 
  0xFF, 0x01, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 
  0xF8, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0xFC, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 
  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 
  0x00, 0x00, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x80, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 
  0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, 
  0x07, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 
  0x80, 0xFE, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 
  0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0xFF, 0xFF, 
  0x01, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 
  0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 
  0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 
  0x00, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0xFE, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0xFF, 0xFF, 
  0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x7F, 
  0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xE0, 0xFF, 
  0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 
  0xFF, 0xFF, 0x01, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x03, 0x00, 0x00, 
  0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0xFE, 0xFF, 0x07, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x07, 
  0x00, 0x00, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x80, 
  0x7F, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0x1F, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x0F, 0x00, 0x00, 0xE0, 
  0xFF, 0x1F, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 
  0x00, 0xF0, 0xFF, 0x7F, 0x00, 0x00, 0xC0, 0xFF, 0x3F, 0x00, 0x00, 0xF8, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0x03, 
  0x00, 0x80, 0xFF, 0x7F, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0x01, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0xFF, 0x7F, 0x00, 
  0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0xF8, 0xFF, 
  0xFF, 0x3F, 0x00, 0x00, 0xFE, 0xFF, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0x03, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFC, 
  0xFF, 0x01, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x00, 
  0xF8, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0xF8, 0xFF, 0x01, 0x00, 0xF8, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0xFF, 0x07, 
  0x00, 0xF0, 0xFF, 0x03, 0x00, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 
  0x00, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0xE0, 0xFF, 0x07, 0x00, 
  0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0xC0, 0xFF, 0xFF, 
  0xFF, 0x1F, 0x00, 0xE0, 0xFF, 0x07, 0x00, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0x0F, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0xC0, 0xFF, 
  0x0F, 0x00, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 
  0x00, 0xFF, 0xFF, 0x7F, 0x00, 0x80, 0xFF, 0x0F, 0x00, 0xF0, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0x00, 
  0x80, 0xFF, 0x1F, 0x00, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0x00, 
  0x00, 0x00, 0x00, 0xC0, 0xFF, 0xFF, 0x01, 0x00, 0xFF, 0x1F, 0x00, 0xF0, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 
  0xFF, 0x03, 0x00, 0xFE, 0x3F, 0x00, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0x07, 0x00, 0xFE, 0x3F, 
  0x00, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0xF8, 0xFF, 0x0F, 0x00, 0xFC, 0x7F, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0x0F, 0x00, 
  0xFC, 0x7F, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0xC0, 0xFF, 0x1F, 0x00, 0xF8, 0x7F, 0x00, 0xC0, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 
  0x3F, 0x00, 0xF8, 0xFF, 0x00, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0x3F, 0x00, 0xF0, 0xFF, 0x00, 
  0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0xFE, 0x7F, 0x00, 0xF0, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x7F, 0x00, 0xF0, 
  0xFF, 0x01, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0xC0, 
  0x3F, 0x00, 0x00, 0xFC, 0xFF, 0x00, 0xE0, 0xFF, 0x01, 0x80, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0xE0, 0xFF, 0x01, 0x00, 0xF8, 0xFF, 
  0x00, 0xE0, 0xFF, 0x01, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 
  0x00, 0xF0, 0xFF, 0x07, 0x00, 0xF0, 0xFF, 0x01, 0xC0, 0xFF, 0x03, 0x00, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0x0F, 0x00, 
  0xF0, 0xFF, 0x01, 0xC0, 0xFF, 0x03, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 
  0x00, 0x00, 0x00, 0xF8, 0xFF, 0x3F, 0x00, 0xE0, 0xFF, 0x01, 0xC0, 0xFF, 
  0x03, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0xF8, 0xFF, 
  0x7F, 0x00, 0xE0, 0xFF, 0x03, 0xC0, 0xFF, 0x03, 0x00, 0xFE, 0xFF, 0xFF, 
  0xFF, 0x3F, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0x00, 0xC0, 0xFF, 0x03, 
  0xC0, 0xFF, 0x03, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 
  0xF0, 0xFF, 0xFF, 0x00, 0xC0, 0xFF, 0x03, 0x80, 0xFF, 0x07, 0x00, 0xFC, 
  0xFF, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0x01, 0xC0, 
  0xFF, 0x07, 0x80, 0xFF, 0x07, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 
  0x00, 0x00, 0xE0, 0xFF, 0xFF, 0x03, 0x80, 0xFF, 0x07, 0x80, 0xFF, 0x07, 
  0x00, 0xF8, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0xFF, 
  0x03, 0x80, 0xFF, 0x07, 0x80, 0xFF, 0x07, 0x00, 0xF8, 0xFF, 0xFF, 0xFF, 
  0x0F, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0x07, 0x80, 0xFF, 0x07, 0x00, 
  0xFF, 0x07, 0x00, 0xF0, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 
  0xE0, 0xFF, 0x07, 0x80, 0xFF, 0x07, 0x80, 0xFF, 0x07, 0x00, 0xF0, 0xFF, 
  0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0x07, 0x00, 0xFF, 
  0x0F, 0x00, 0xFF, 0x07, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 
  0x00, 0x00, 0x80, 0xFF, 0x0F, 0x00, 0xFF, 0x0F, 0x00, 0xFF, 0x07, 0x00, 
  0xE0, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x0F, 
  0x00, 0xFF, 0x0F, 0x00, 0xFF, 0x0F, 0x00, 0xC0, 0xFF, 0xFF, 0xFF, 0x1F, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x0F, 0x00, 0xFF, 0x0F, 0x00, 0xFF, 
  0x07, 0x00, 0xC0, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0xFF, 0x0F, 0x00, 0xFF, 0x0F, 0x00, 0xFF, 0x0F, 0x00, 0x80, 0xFF, 0xFF, 
  0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x0F, 0x00, 0xFF, 0x0F, 
  0x00, 0xFF, 0x0F, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0xFF, 0x0F, 0x00, 0xFF, 0x0F, 0x00, 0xFF, 0x0F, 0x00, 0x00, 
  0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x0F, 0x00, 
  0xFE, 0x0F, 0x00, 0xFF, 0x07, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0xFE, 0x0F, 0x00, 0xFE, 0x07, 0x00, 0xFE, 0x07, 
  0x00, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0xFC, 
  0x07, 0x00, 0xFE, 0x07, 0x00, 0xFE, 0x03, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 
  0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x03, 0x00, 0xF8, 0x03, 0x00, 
  0xFC, 0x01, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 
  0x00, 0xE0, 0x00, 0x00, 0x50, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0xFC, 
  0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0xF0, 0xFF, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0xFF, 
  0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 
  0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 
  0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 
  0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0xFC, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0xFF, 0x7F, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 
  0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 
  0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 
  0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 
  0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 
  0x00, 0x00, 0xC0, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0xE0, 0xFF, 0x1F, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0xFF, 
  0xFF, 0x1F, 0x00, 0x00, 0xF8, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0xFC, 
  0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 
  0xC0, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 
  0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 
  0xFF, 0x0F, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 
  0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 
  0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x80, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB8, 
  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, };


Schematics

project-image
Schematic - 92.1


Downloads

BLE_Emergency_Assistant.apk

Download


BLE_Emergency_Assistant.aia

Download


Edge Impulse Model (Arduino Library)

Download


BLE_Travel_Emergency_Assistant_main_case_left.stl

Download


BLE_Travel_Emergency_Assistant_main_case_right.stl

Download


BLE_Travel_Emergency_Assistant_modular_part.stl

Download


fine_token.stl

Download


danger_token.stl

Download


assist_token.stl

Download


stolen_token.stl

Download


call_token.stl

Download