Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • 89-apps-should-be-able-to-specify-if-they-want-wifi-to-be-disabled-when-entering-them
  • 9Rmain
  • allow-reloading-sunmenu
  • always-have-a-wifi-instance
  • anon/gpndemo
  • anon/update-sim
  • anon/webflasher
  • app_text_viewer
  • audio_input
  • audio_io
  • blm_dev_chan
  • ch3/bl00mbox_docs
  • ci-1690580595
  • dev_p4
  • dev_p4-iggy
  • dev_p4-iggy-rebased
  • dx/dldldld
  • dx/fb-save-restore
  • dx/hint-hint
  • dx/jacksense-headset-mic-only
  • events
  • fil3s-limit-filesize
  • fil3s-media
  • fpletz/flake
  • gr33nhouse-improvements
  • history-rewrite
  • icon-flower
  • iggy/stemming
  • iggy/stemming_merge
  • led_fix_fix
  • main
  • main+schneider
  • media_has_video_has_audio
  • micropython_api
  • mixer2
  • moon2_demo_temp
  • moon2_migrate_apps
  • more-accurate-battery
  • pippin/ctx_sprite_sheet_support
  • pippin/display-python-errors-on-display
  • pippin/make_empty_drawlists_skip_render_and_blit
  • pippin/more-accurate-battery
  • pippin/tcp_redirect_hack
  • pippin/tune_ctx_config_update_from_upstream
  • pippin/uhm_flash_access_bust
  • pressable_bugfix
  • py_only_update_fps_overlay_when_changing
  • q3k/doom-poc
  • q3k/render-to-texture
  • rahix/flow3rseeds
  • raw_captouch_new
  • raw_captouch_old
  • release/1.0.0
  • release/1.1.0
  • release/1.1.1
  • release/1.2.0
  • release/1.3.0
  • release/1.4.0
  • restore_blit
  • return_of_melodic_demo
  • rev4_micropython
  • schneider/application-remove-name
  • schneider/bhi581
  • schneider/factory_test
  • schneider/recovery
  • scope_hack
  • sdkconfig-spiram-tinyusb
  • sec/auto-nick
  • sec/blinky
  • sector_size_512
  • shoegaze-fps
  • smaller_gradient_lut
  • store_delta_ms_and_ins_as_class_members
  • task_cleanup
  • uctx-wip
  • w1f1-in-sim
  • widgets_draw
  • wifi-json-error-handling
  • wip-docs
  • wip-tinyusb
  • v1.0.0
  • v1.0.0+rc1
  • v1.0.0+rc2
  • v1.0.0+rc3
  • v1.0.0+rc4
  • v1.0.0+rc5
  • v1.0.0+rc6
  • v1.1.0
  • v1.1.0+rc1
  • v1.1.1
  • v1.2.0
  • v1.2.0+rc1
  • v1.3.0
  • v1.4.0
94 results

Target

Select target project
  • flow3r/flow3r-firmware
  • Vespasian/flow3r-firmware
  • alxndr42/flow3r-firmware
  • pl/flow3r-firmware
  • Kari/flow3r-firmware
  • raimue/flow3r-firmware
  • grandchild/flow3r-firmware
  • mu5tach3/flow3r-firmware
  • Nervengift/flow3r-firmware
  • arachnist/flow3r-firmware
  • TheNewCivilian/flow3r-firmware
  • alibi/flow3r-firmware
  • manuel_v/flow3r-firmware
  • xeniter/flow3r-firmware
  • maxbachmann/flow3r-firmware
  • yGifoom/flow3r-firmware
  • istobic/flow3r-firmware
  • EiNSTeiN_/flow3r-firmware
  • gnudalf/flow3r-firmware
  • 999eagle/flow3r-firmware
  • toerb/flow3r-firmware
  • pandark/flow3r-firmware
  • teal/flow3r-firmware
  • x42/flow3r-firmware
  • alufers/flow3r-firmware
  • dos/flow3r-firmware
  • yrlf/flow3r-firmware
  • LuKaRo/flow3r-firmware
  • ThomasElRubio/flow3r-firmware
  • ai/flow3r-firmware
  • T_X/flow3r-firmware
  • highTower/flow3r-firmware
  • beanieboi/flow3r-firmware
  • Woazboat/flow3r-firmware
  • gooniesbro/flow3r-firmware
  • marvino/flow3r-firmware
  • kressnerd/flow3r-firmware
  • quazgar/flow3r-firmware
  • aoid/flow3r-firmware
  • jkj/flow3r-firmware
  • naomi/flow3r-firmware
41 results
Select Git revision
  • 89-apps-should-be-able-to-specify-if-they-want-wifi-to-be-disabled-when-entering-them
  • 9Rmain
  • allow-reloading-sunmenu
  • always-have-a-wifi-instance
  • anon/gpndemo
  • anon/update-sim
  • anon/webflasher
  • app_text_viewer
  • audio_input
  • audio_io
  • blm_dev_chan
  • ch3/bl00mbox_docs
  • ci-1690580595
  • dev_p4
  • dev_p4-iggy
  • dev_p4-iggy-rebased
  • dx/dldldld
  • dx/fb-save-restore
  • dx/hint-hint
  • dx/jacksense-headset-mic-only
  • events
  • fil3s-limit-filesize
  • fil3s-media
  • fpletz/flake
  • gr33nhouse-improvements
  • history-rewrite
  • icon-flower
  • iggy/stemming
  • iggy/stemming_merge
  • led_fix_fix
  • main
  • main+schneider
  • media_has_video_has_audio
  • micropython_api
  • mixer2
  • moon2_demo_temp
  • moon2_migrate_apps
  • more-accurate-battery
  • pippin/ctx_sprite_sheet_support
  • pippin/display-python-errors-on-display
  • pippin/make_empty_drawlists_skip_render_and_blit
  • pippin/more-accurate-battery
  • pippin/tcp_redirect_hack
  • pippin/tune_ctx_config_update_from_upstream
  • pippin/uhm_flash_access_bust
  • pressable_bugfix
  • py_only_update_fps_overlay_when_changing
  • q3k/doom-poc
  • q3k/render-to-texture
  • rahix/flow3rseeds
  • raw_captouch_new
  • raw_captouch_old
  • release/1.0.0
  • release/1.1.0
  • release/1.1.1
  • release/1.2.0
  • release/1.3.0
  • release/1.4.0
  • restore_blit
  • return_of_melodic_demo
  • rev4_micropython
  • schneider/application-remove-name
  • schneider/bhi581
  • schneider/factory_test
  • schneider/recovery
  • scope_hack
  • sdkconfig-spiram-tinyusb
  • sec/auto-nick
  • sec/blinky
  • sector_size_512
  • shoegaze-fps
  • smaller_gradient_lut
  • store_delta_ms_and_ins_as_class_members
  • task_cleanup
  • uctx-wip
  • w1f1-in-sim
  • widgets_draw
  • wifi-json-error-handling
  • wip-docs
  • wip-tinyusb
  • v1.0.0
  • v1.0.0+rc1
  • v1.0.0+rc2
  • v1.0.0+rc3
  • v1.0.0+rc4
  • v1.0.0+rc5
  • v1.0.0+rc6
  • v1.1.0
  • v1.1.0+rc1
  • v1.1.1
  • v1.2.0
  • v1.2.0+rc1
  • v1.3.0
  • v1.4.0
94 results
Show changes
Showing
with 8335 additions and 3397 deletions
#include "sequencer.h"
radspa_descriptor_t sequencer_desc = {
.name = "_sequencer",
.name = "sequencer",
.id = 56709,
.description = "sequencer that can output triggers or general control signals, best enjoyed through the "
"'sequencer' patch.\ninit_var: 1st byte (lsb): number of tracks, 2nd byte: number of steps"
......@@ -31,18 +31,13 @@ static uint64_t target(uint64_t step_len, uint64_t bpm, uint64_t beat_div){
void sequencer_run(radspa_t * sequencer, uint16_t num_samples, uint32_t render_pass_id){
bool output_request = false;
sequencer_data_t * data = sequencer->plugin_data;
sequencer_track_data_t * tracks = (void *) (&data[1]);
radspa_signal_t * track_sigs[data->num_tracks];
for(uint8_t j = 0; j < data->num_tracks; j++){
track_sigs[j] = radspa_signal_get_by_index(sequencer, SEQUENCER_OUTPUT+j);
if(track_sigs[j]->buffer != NULL) output_request = true;
}
radspa_signal_t * step_sig = radspa_signal_get_by_index(sequencer, SEQUENCER_STEP);
if(step_sig->buffer != NULL) output_request = true;
radspa_signal_t * sync_out_sig = radspa_signal_get_by_index(sequencer, SEQUENCER_SYNC_OUT);
if(sync_out_sig->buffer != NULL) output_request = true;
if(!output_request) return;
radspa_signal_t * sync_in_sig = radspa_signal_get_by_index(sequencer, SEQUENCER_SYNC_IN);
radspa_signal_t * start_step_sig = radspa_signal_get_by_index(sequencer, SEQUENCER_START_STEP);
......@@ -50,104 +45,175 @@ void sequencer_run(radspa_t * sequencer, uint16_t num_samples, uint32_t render_p
radspa_signal_t * bpm_sig = radspa_signal_get_by_index(sequencer, SEQUENCER_BPM);
radspa_signal_t * beat_div_sig = radspa_signal_get_by_index(sequencer, SEQUENCER_BEAT_DIV);
for(uint8_t j = 0; j < data->num_tracks; j++){
track_sigs[j] = radspa_signal_get_by_index(sequencer, SEQUENCER_OUTPUT+j);
if(track_sigs[j]->buffer != NULL) output_request = true;
}
if(!output_request) return;
int16_t * table = sequencer->plugin_table;
int16_t s1 = radspa_signal_get_value(end_step_sig, 0, num_samples, render_pass_id);
int16_t s1 = radspa_signal_get_value(end_step_sig, 0, render_pass_id);
int16_t s2 = data->track_step_len - 1;
data->step_end = s1 > 0 ? (s1 > s2 ? s2 : s1) : 1;
data->step_start = radspa_signal_get_value(start_step_sig, 0, num_samples, render_pass_id);
data->step_end = s1 > 0 ? (s1 > s2 ? s2 : s1) : 0;
data->step_start = radspa_signal_get_value(start_step_sig, 0, render_pass_id);
int16_t bpm = radspa_signal_get_value(bpm_sig, 0, render_pass_id);
int16_t beat_div = radspa_signal_get_value(beat_div_sig, 0, render_pass_id);
int16_t bpm = bpm_sig->get_value(bpm_sig, 0, num_samples, render_pass_id);
int16_t beat_div = beat_div_sig->get_value(beat_div_sig, 0, num_samples, render_pass_id);
if((bpm != data->bpm_prev) || (beat_div != data->beat_div_prev)){
data->counter_target = target(data->track_step_len, bpm, beat_div);
data->bpm_prev = bpm;
data->beat_div_prev = beat_div;
}
if(data->counter_target){
for(uint16_t i = 0; i < num_samples; i++){
data->counter++;
if(data->counter >= data->counter_target){
int16_t sync_in = radspa_trigger_get(radspa_signal_get_value(sync_in_sig, i, render_pass_id),
&(data->sync_in_hist));
if(sync_in){
data->counter = 0;
data->step++;
if(data->step > data->step_end){
data->step = data->step_start;
data->sync_out = -data->sync_out;
bool start = sync_in > 0;
data->is_stopped = !start;
data->sync_out_start = start;
data->sync_out_stop = !start;
if(!start){
for(uint8_t j = 0; j < data->num_tracks; j++){
int16_t type = table[j * (data->track_step_len + 1)];
int16_t stage_val = table[data->step + 1 + (1 + data->track_step_len) * j];
if(type == -32767) stage_val = -1;
if((!tracks[j].changed) && (tracks[j].stage_val_prev != stage_val)){
tracks[j].changed = true;
tracks[j].stage_val_prev = stage_val;
for(uint16_t k = 0; k < i; k++){
radspa_signal_set_value(track_sigs[j], k, tracks[j].track_fill);
}
}
if(type == 32767){
tracks[j].track_fill = stage_val;
} else if(type == -32767){
if(stage_val > 0){
radspa_trigger_start(stage_val, &(tracks[j].track_fill));
} else if(stage_val < 0){
radspa_trigger_stop(&(tracks[j].track_fill));
}
}
tracks[j].stage_val_prev = stage_val;
}
}
} else {
data->sync_out_start = false;
data->sync_out_stop = false;
}
int16_t sync_in = sync_in_sig->get_value(sync_in_sig, i, num_samples, render_pass_id);
if(((sync_in > 0) && (data->sync_in_prev <= 0)) || ((sync_in > 0) && (data->sync_in_prev <= 0))){
if(!data->is_stopped && data->counter_target){
if(data->counter >= data->counter_target){
data->counter = 0;
data->step++;
if(data->step > data->step_end){
data->step = data->step_start;
data->sync_out = -data->sync_out;
data->sync_out_start = true;
}
}
data->sync_in_prev = sync_in;
if(!data->counter){ //event just happened
for(uint8_t j = 0; j < data->num_tracks; j++){
int16_t type = table[j * (data->track_step_len + 1)];
int16_t stage_val = table[data->step + 1 + (1 + data->track_step_len) * j];
if((!tracks[j].changed) && (tracks[j].stage_val_prev != stage_val)){
tracks[j].changed = true;
tracks[j].stage_val_prev = stage_val;
for(uint16_t k = 0; k < i; k++){
radspa_signal_set_value(track_sigs[j], k, tracks[j].track_fill);
}
}
if(type == 32767){
data->tracks[j].track_fill = stage_val;
tracks[j].track_fill = stage_val;
} else if(type == -32767){
if(stage_val > 0) data->tracks[j].track_fill = radspa_trigger_start(stage_val, &(data->tracks[j].trigger_hist));
if(stage_val < 0) data->tracks[j].track_fill = radspa_trigger_stop(&(data->tracks[j].trigger_hist));
if(stage_val > 0){
radspa_trigger_start(stage_val, &(tracks[j].track_fill));
} else if(stage_val < 0){
radspa_trigger_stop(&(tracks[j].track_fill));
}
}
tracks[j].stage_val_prev = stage_val;
}
}
data->counter++;
}
for(uint8_t j = 0; j < data->num_tracks; j++){
if(track_sigs[j]->buffer != NULL) (track_sigs[j]->buffer)[i] = data->tracks[j].track_fill;
if(tracks[j].changed) radspa_signal_set_value(track_sigs[j], i, tracks[j].track_fill);
}
if(sync_out_sig->buffer != NULL) (sync_out_sig->buffer)[i] = data->sync_out;
if(step_sig->buffer != NULL) (step_sig->buffer)[i] = data->step;
int16_t sync_out = 0;
if(data->sync_out_start){
sync_out = radspa_trigger_start(sync_in, &(data->sync_out_hist));
} else if(data->sync_out_stop){
sync_out = radspa_trigger_stop(&(data->sync_out_hist));
}
radspa_signal_set_value(sync_out_sig, i, sync_out);
}
for(uint8_t j = 0; j < data->num_tracks; j++){
track_sigs[j]->value = data->tracks[j].track_fill;
if(!tracks[j].changed){
int16_t type = table[j * (data->track_step_len + 1)];
if(type == 32767){
tracks[j].track_fill = table[data->step + 1 + (1 + data->track_step_len) * j];
tracks[j].stage_val_prev = tracks[j].track_fill;
}
radspa_signal_set_const_value(track_sigs[j], tracks[j].track_fill);
} else {
tracks[j].changed = false;
}
}
sync_out_sig->value = data->sync_out;
step_sig->value = data->step;
radspa_signal_set_const_value(step_sig, data->step);
}
radspa_t * sequencer_create(uint32_t init_var){
uint32_t num_tracks = 4;
uint32_t num_pixels = 16;
uint32_t num_steps = 16;
if(init_var){
num_tracks = init_var & 0xFF;
num_pixels = (init_var>>8) & 0xFF;
num_steps = (init_var>>8) & 0xFF;
}
if(!num_tracks) return NULL;
if(!num_pixels) return NULL;
if(!num_steps) return NULL;
uint32_t table_size = num_tracks * (num_pixels + 1);
uint32_t table_size = num_tracks * (num_steps + 1);
uint32_t num_signals = num_tracks + SEQUENCER_NUM_SIGNALS; //one for each channel output
size_t data_size = sizeof(sequencer_data_t) + sizeof(sequencer_track_data_t) * (num_tracks - 1);
size_t data_size = sizeof(sequencer_data_t) + sizeof(sequencer_track_data_t) * num_tracks;
radspa_t * sequencer = radspa_standard_plugin_create(&sequencer_desc, num_signals, data_size, table_size);
if(sequencer == NULL) return NULL;
sequencer->render = sequencer_run;
sequencer_data_t * data = sequencer->plugin_data;
data->track_step_len = num_pixels;
data->track_step_len = num_steps;
data->num_tracks = num_tracks;
data->bpm_prev = 120;
data->beat_div_prev = 16;
data->counter_target = target(data->track_step_len, data->bpm_prev, data->beat_div_prev);
radspa_signal_set(sequencer, SEQUENCER_STEP, "step", RADSPA_SIGNAL_HINT_OUTPUT, 0);
radspa_signal_set(sequencer, SEQUENCER_SYNC_OUT, "sync_out", RADSPA_SIGNAL_HINT_OUTPUT, 0);
radspa_signal_set(sequencer, SEQUENCER_SYNC_IN, "sync_in", RADSPA_SIGNAL_HINT_INPUT | RADSPA_SIGNAL_HINT_TRIGGER, 0);
radspa_signal_set(sequencer, SEQUENCER_SYNC_IN, "sync_in", RADSPA_SIGNAL_HINT_INPUT | RADSPA_SIGNAL_HINT_TRIGGER, 32767);
radspa_signal_set(sequencer, SEQUENCER_START_STEP, "step_start", RADSPA_SIGNAL_HINT_INPUT, 0);
radspa_signal_set(sequencer, SEQUENCER_END_STEP, "step_end", RADSPA_SIGNAL_HINT_INPUT, num_pixels-1);
radspa_signal_set(sequencer, SEQUENCER_END_STEP, "step_end", RADSPA_SIGNAL_HINT_INPUT, num_steps-1);
radspa_signal_set(sequencer, SEQUENCER_BPM, "bpm", RADSPA_SIGNAL_HINT_INPUT, data->bpm_prev);
radspa_signal_set(sequencer, SEQUENCER_BEAT_DIV, "beat_div", RADSPA_SIGNAL_HINT_INPUT, data->beat_div_prev);
radspa_signal_set_group(sequencer, data->num_tracks, 1, SEQUENCER_OUTPUT, "track",
RADSPA_SIGNAL_HINT_OUTPUT | RADSPA_SIGNAL_HINT_TRIGGER, 0);
data->counter = 0;
data->sync_in_prev = 0;
data->sync_out = 32767;
data->sync_in_hist = 0;
data->sync_out_hist = 0;
data->sync_out_start = false;
data->sync_out_stop = false;
data->is_stopped = true;
sequencer_track_data_t * tracks = (void *) (&data[1]);
for(uint8_t j = 0; j < data->num_tracks; j++){
tracks[j].changed = false;
tracks[j].track_fill = 0;
tracks[j].stage_val_prev = 0;
}
return sequencer;
}
......@@ -5,7 +5,8 @@
typedef struct {
int16_t track_fill;
int16_t trigger_hist;
int16_t stage_val_prev;
bool changed;
} sequencer_track_data_t;
typedef struct {
......@@ -16,11 +17,13 @@ typedef struct {
uint8_t step;
uint64_t counter;
uint64_t counter_target;
int16_t sync_in_prev;
int16_t sync_out;
int16_t sync_in_hist;
int16_t sync_out_hist;
bool sync_out_start;
bool sync_out_stop;
bool is_stopped;
int16_t bpm_prev;
int16_t beat_div_prev;
sequencer_track_data_t tracks[];
} sequencer_data_t;
......
#include "slew_rate_limiter.h"
static inline int16_t waveshaper(int16_t saw, int16_t shape);
radspa_descriptor_t slew_rate_limiter_desc = {
.name = "slew_rate_limiter",
.id = 23,
......@@ -34,8 +32,8 @@ void slew_rate_limiter_run(radspa_t * slew_rate_limiter, uint16_t num_samples, u
int32_t ret = 0;
for(uint16_t i = 0; i < num_samples; i++){
int32_t input = input_sig->get_value(input_sig, i, num_samples, render_pass_id);
int32_t slew_rate = (uint16_t) slew_rate_sig->get_value(slew_rate_sig, i, num_samples, render_pass_id);
int32_t input = radspa_signal_get_value(input_sig, i, render_pass_id);
int32_t slew_rate = (uint16_t) radspa_signal_get_value(slew_rate_sig, i, render_pass_id);
ret = data->prev;
if(input - ret > slew_rate){
ret += slew_rate;
......@@ -44,8 +42,7 @@ void slew_rate_limiter_run(radspa_t * slew_rate_limiter, uint16_t num_samples, u
} else {
ret = input;
}
(output_sig->buffer)[i] = ret;
radspa_signal_set_value(output_sig, i, ret);
}
output_sig->value = ret;
}
#include "trigger_merge.h"
#include <stdio.h>
radspa_descriptor_t trigger_merge_desc = {
.name = "trigger_merge",
.id = 38,
.description = "merges multiple trigger inputs together. lazy. if a start and a stop "
"collide the stop is preferred."
"\ninit_var: number of inputs, default 0, max 127",
.create_plugin_instance = trigger_merge_create,
.destroy_plugin_instance = radspa_standard_plugin_destroy
};
typedef struct {
int16_t trigger_out_prev;
int16_t blocked_stop;
int16_t trigger_in_prev[];
} trigger_merge_data_t;
void trigger_merge_run(radspa_t * plugin, uint16_t num_samples, uint32_t render_pass_id){
int num_inputs = plugin->len_signals - 1;
trigger_merge_data_t * data = plugin->plugin_data;
bool block_stop_events = plugin->plugin_table[0];
int16_t i;
int16_t merged_trigger = 0;
int16_t last_timestamp = -1;
for(uint8_t j = 0; j < num_inputs; j++){
int16_t trigger_in = radspa_trigger_get_const(&plugin->signals[j], &data->trigger_in_prev[j], (uint16_t *) &i, num_samples, render_pass_id);
if((last_timestamp > i) || (!trigger_in)) continue;
if((trigger_in > 0) && (last_timestamp == i)){
if(merged_trigger != -1){
merged_trigger = merged_trigger > trigger_in ? merged_trigger : trigger_in;
}
} else {
merged_trigger = trigger_in;
}
last_timestamp = i;
}
if(merged_trigger > 0){
radspa_trigger_start(merged_trigger, &(data->trigger_out_prev));
data->blocked_stop = false;
} else if(data->blocked_stop && (!block_stop_events)){
radspa_trigger_stop(&(data->trigger_out_prev));
data->blocked_stop = false;
} else if(merged_trigger < 0){
if(!block_stop_events){
radspa_trigger_stop(&(data->trigger_out_prev));
} else {
data->blocked_stop = true;
}
}
radspa_signal_set_const_value(&plugin->signals[num_inputs], data->trigger_out_prev);
}
radspa_t * trigger_merge_create(uint32_t init_var){
if(init_var > 127) init_var = 127;
if(!init_var) init_var = 1;
uint32_t size = sizeof(trigger_merge_data_t) + init_var * sizeof(int16_t);
radspa_t * plugin = radspa_standard_plugin_create(&trigger_merge_desc, init_var + 1, size, 1);
if(plugin == NULL) return NULL;
plugin->render = trigger_merge_run;
radspa_signal_set_group(plugin, init_var, 1, 0, "input", RADSPA_SIGNAL_HINT_INPUT | RADSPA_SIGNAL_HINT_TRIGGER, 0);
radspa_signal_set(plugin, init_var, "output", RADSPA_SIGNAL_HINT_OUTPUT | RADSPA_SIGNAL_HINT_TRIGGER, 0);
return plugin;
}
#pragma once
#include <radspa.h>
#include <radspa_helpers.h>
extern radspa_descriptor_t trigger_merge_desc;
radspa_t * trigger_merge_create(uint32_t init_var);
void trigger_merge_run(radspa_t * osc, uint16_t num_samples, uint32_t render_pass_id);
Checks: '-clang-analyzer-core.CallAndMessage'
Source diff could not be displayed: it is too large. Options to address this: view the blob.
......@@ -10,69 +10,81 @@
#ifndef __clang__
#if CONFIG_FLOW3R_CTX_FLAVOUR_FULL
#pragma GCC optimize("O2")
#pragma GCC optimize("Oz")
#else
#pragma GCC optimize("Oz")
#endif
#endif
#define CTX_TINYVG 1
#define CTX_TVG_STDIO 0
#define CTX_DITHER 1
// set this to 1 for faster 8bpp mode - with some glitching
#define CTX_NATIVE_GRAYA8 0
// this might also limit max texture sizes, increasing it
// causes performance drop, so kept just above what we need
#define CTX_PDF 0
#define CTX_DITHER 1
#define CTX_PROTOCOL_U8_COLOR 1
#define CTX_AVOID_CLIPPED_SUBDIVISION 0
#define CTX_LIMIT_FORMATS 1
#define CTX_ENABLE_FLOAT 0
#define CTX_32BIT_SEGMENTS 0
#define CTX_ENABLE_RGBA8 1
#define CTX_ENABLE_RGB332 0
#define CTX_ENABLE_GRAY1 0
#define CTX_ENABLE_GRAY2 0
#define CTX_ENABLE_GRAY4 0
#define CTX_RASTERIZER 1
#define CTX_RASTERIZER_AA 3
#define CTX_ENABLE_RGB565 1
#define CTX_ENABLE_RGB565_BYTESWAPPED 1
#define CTX_ENABLE_CBRLE 0
#define CTX_ENABLE_CM 0
#define CTX_BITPACK_PACKER 0
#define CTX_COMPOSITING_GROUPS 0
#define CTX_RENDERSTREAM_STATIC 0
#define CTX_GRADIENT_CACHE 1
#define CTX_MIN_JOURNAL_SIZE 512 // grows dynamically
#define CTX_MIN_EDGE_LIST_SIZE 512 // is also max and limits complexity
#define CTX_ALWAYS_USE_NEAREST_FOR_SCALE1 1
#define CTX_EVENTS 0
#define CTX_THREADS 0
#define CTX_TILED 0
#define CTX_BAREMETAL 1
#define CTX_ONE_FONT_ENGINE 1
#define CTX_MAX_SCANLINE_LENGTH 960
#define CTX_MAX_JOURNAL_SIZE (1024*512)
// is also max and limits complexity
// of paths that can be filled
#define CTX_STATIC_OPAQUE 1
#define CTX_MAX_SCANLINE_LENGTH 256
#define CTX_1BIT_CLIP 1
#define CTX_MIN_EDGE_LIST_SIZE 1024
#define CTX_MAX_DASHES 10
#define CTX_MAX_DASHES 32
#define CTX_MAX_GRADIENT_STOPS 10
#define CTX_CM 0
#define CTX_SHAPE_CACHE 0
#define CTX_SHAPE_CACHE_DEFAULT 0
#define CTX_MAX_STATES 10
#define CTX_MAX_EDGES 255
#define CTX_MAX_PENDING 64
#define CTX_GRADIENT_CACHE_ELEMENTS 128
#define CTX_RASTERIZER_MAX_CIRCLE_SEGMENTS 64
#define CTX_NATIVE_GRAYA8 0
#define CTX_ENABLE_SHADOW_BLUR 0
#define CTX_FONTS_FROM_FILE 0
#define CTX_MAX_KEYDB 16
#define CTX_MAX_TEXTURES 32
#define CTX_PARSER_MAXLEN 512
#define CTX_PARSER_FIXED_TEMP 1
#define CTX_CURRENT_PATH 1
#define CTX_STRINGPOOL_SIZE 256
#define CTX_AUDIO 0
#define CTX_CLIENTS 0
#define CTX_MAX_DEVICES 1
#define CTX_MAX_KEYBINDINGS 16
#define CTX_MAX_CBS 8
#define CTX_MAX_LISTEN_FDS 1
#define CTX_HASH_COLS 5
#define CTX_HASH_ROWS 5
#define CTX_STROKE_1PX 1
#if defined(CONFIG_FLOW3R_CTX_FLAVOUR_FULL)
#define CTX_ENABLE_CLIP 1
#define CTX_COMPOSITE_O3 1
#define CTX_RASTERIZER_O2 0
#define CTX_GSTATE_PROTECT 1
#define CTX_FORCE_INLINES 1
#define CTX_FRAGMENT_SPECIALIZE 1
#define CTX_FAST_FILL_RECT 1
#define CTX_BLENDING_AND_COMPOSITING 1
#define CTX_ENABLE_YUV420 1
#define CTX_ENABLE_RGBA8 1
#define CTX_ENABLE_RGB332 1
#define CTX_ENABLE_RGB8 1
#define CTX_ENABLE_GRAY8 1
#define CTX_ENABLE_GRAYA8 1
#define CTX_ENABLE_GRAY1 1
#define CTX_ENABLE_GRAY2 1
#define CTX_ENABLE_GRAY4 1
#define CTX_STB_IMAGE 1
#define STBI_ONLY_PNG
#define STBI_ONLY_GIF
#define STBI_ONLY_JPEG
#else
......@@ -80,33 +92,13 @@
#define CTX_FRAGMENT_SPECIALIZE 0
#define CTX_FAST_FILL_RECT 0
#define CTX_BLENDING_AND_COMPOSITING 0
#define CTX_FORCE_INLINES 0
#define CTX_INLINED_GRADIENTS 0
#define CTX_FORMATTER 0
#define CTX_PARSER 0
#endif
#define CTX_RAW_KB_EVENTS 0
#define CTX_MATH 1
#define CTX_TERMINAL_EVENTS 0 // gets rid of posix bits and bobs
#define CTX_THREADS 0
#define CTX_TILED 0
#define CTX_FORMATTER 0 // we want these eventually
#define CTX_PARSER 0 // enabled
#define CTX_BRAILLE_TEXT 0
#define CTX_BAREMETAL 1
#define CTX_EVENTS 0
#define CTX_MAX_DEVICES 1
#define CTX_MAX_KEYBINDINGS 16
#define CTX_RASTERIZER 1
#define CTX_MAX_STATES 5
#define CTX_MAX_EDGES 127
#define CTX_MAX_PENDING 64
#define CTX_MAX_CBS 8
#define CTX_MAX_LISTEN_FDS 1
#define CTX_ONE_FONT_ENGINE 1
#define CTX_STATIC_FONT(font) \
ctx_load_font_ctx(ctx_font_##font##_name, \
......@@ -139,4 +131,7 @@
#include "MaterialIcons.h"
#define CTX_FONT_7 CTX_STATIC_FONT(MaterialIcons)
#include "Comic-Mono.h"
#define CTX_FONT_8 CTX_STATIC_FONT(Comic_Mono)
#endif
#ifndef CTX_FONT_Comic_Mono
/* glyph index:
!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghi
jklmnopqrstuvwxyz{|}~ */
/*
Comic Mono
MIT License
Original work Copyright (c) 2018 Shannon Miwa
Modified work Copyright (c) 2019 dtinth
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
static const struct __attribute__ ((packed)) {uint8_t code; uint32_t a; uint32_t b;}
ctx_font_Comic_Mono[]={
{15, 0x0000a008, 0x00000d94},/* length:3476 CTX_SUBDIV:8 CTX_BAKE_FONT_SIZE:160 */
{'(', 0x0000000c, 0x00000002},/* Comic Mono*/
{32, 0x696d6f43, 0x6f4d2063},
{'n', 0x0000006f, 0x00000000},
{')', 0x0000000c, 0x00000002},
{'@', 0x00000020, 0x00004e50},/* x-advance: 78.312500 */
{'@', 0x00000021, 0x00004e50},/* ! x-advance: 78.312500 */
{'M', 0x423e98b4, 0xc2d435e5},
{'q', 0x00000000, 0x3faaaac0},
{0, 0xbf21af40, 0x41979434},
{'q', 0xbf0fb800, 0x418ce98c},
{0, 0xbe8fb800, 0x41e59d32},
{'8', 0x67005602, 0x35ff10fe},
{'8', 0x27ec19fe, 0x0cd70eef},
{'8', 0xf1da00e9, 0xd5f4f1f2},
{'8', 0xdf04f001, 0xe503f002},
{'8', 0xcd01f501, 0x97ffd801},
{'8', 0xa2fed4ff, 0xad00ce00},
{'8', 0xb502df01, 0xc801d601},
{'8', 0xd110e101, 0xf127f110},
{'8', 0x0d27ff18, 0x2d0e0e0e},
{'m', 0xc1000000, 0x42db3a63},
{'8', 0xe9bb04d6, 0xbee6e4e6},
{'8', 0xc41dde00, 0xe642e71d},
{'8', 0x1741ff28, 0x3e191919},
{'8', 0x3de82400, 0x1dbe18e8},
{'@', 0x00000022, 0x00004e50},/* " x-advance: 78.312500 */
{'M', 0x420ce98b, 0xc2d435e5},
{'q', 0x3e0fb800, 0x40bca1b0},
{0, 0xbe579400, 0x419af288},
{'q', 0xbe8fb800, 0x415674c0},
{0, 0xbf698b40, 0x4193a62c},
{'8', 0x22ec17fd, 0x0ade0bf0},
{'8', 0xf2d7ffe9, 0xdaf1f3ef},
{'q', 0x3efb8240, 0xc0e98b30},
{0, 0x3eb3a640, 0xc195e50c},
{'q', 0xbe0fb800, 0xc13823f0},
{0, 0xbefb8240, 0xc1979438},
{'8', 0xe805f2ff, 0xf210f606},
{'8', 0xfa14fc0a, 0xff15ff0a},
{'8', 0x0213000a, 0x07110209},
{'8', 0x0f0e0508, 0x19060a05},
{'m', 0x41b823ee, 0x00000000},
{'q', 0x3e0fb800, 0x40ba62d0},
{0, 0xbe0fb800, 0x419a62d0},
{'q', 0xbe8fb800, 0x41579430},
{0, 0xbf698b40, 0x419435e4},
{'8', 0x22ec17fd, 0x0add0bf0},
{'8', 0xf2d8ffea, 0xdaf1f3ef},
{'q', 0x3ed79480, 0xc0e98b30},
{0, 0x3e8fb880, 0xc195e50c},
{'q', 0xbe0fb900, 0xc13823f0},
{0, 0xbefb8280, 0xc1979438},
{'8', 0xe805f200, 0xf210f606},
{'8', 0xfa14fc0a, 0xff14ff0a},
{'8', 0x0213000a, 0x07110208},
{'8', 0x0f0e0508, 0x19050a05},
{'@', 0x00000023, 0x00004e50},/* # x-advance: 78.312500 */
{'M', 0x41b9d317, 0xc0bee090},
{'8', 0x27df18f8, 0x07d20fe8},
{'8', 0xe3e0fceb, 0xcaffe8f6},
{'9', 0xffe20008, 0xff7a0020},
{'l', 0xc088fb82, 0x00000000},
{'8', 0xf5d400e3, 0xe2f2f5f2},
{'8', 0xde0cecff, 0xf12bf20e},
{'8', 0xff1c0008, 0xff1c0013},
{'l', 0x409d3168, 0xc1c62cea},
{'8', 0x00e700f7, 0x00eb00f1},
{'8', 0xf4d501e4, 0xdff1f3f1},
{'8', 0xde0decff, 0xf12cf20e},
{'q', 0x402f286c, 0xbe0fb800},
{0, 0x4106bca3, 0xbe0fb800},
{'q', 0x40823ee0, 0xc1ae08fc},
{0, 0x40847dc0, 0xc1b286bc},
{'8', 0xd81ce308, 0xfa28f513},
{'8', 0x17250518, 0x2f06110c},
{'4', 0x0097ffe2, 0x00000082},
{'l', 0x40770470, 0xc1a74c5c},
{'8', 0xd71ce208, 0xfb2af513},
{'8', 0x17260519, 0x3005110c},
{'9', 0x002ffff4, 0x008dffe4},
{'l', 0x3fd79440, 0x00000000},
{'8', 0x0f2e001c, 0x21130f12},
{'8', 0x23f21400, 0x0fd70ef3},
{'4', 0x0000ffd6, 0x00c4ffdf},
{'l', 0x40bca1b0, 0x00000000},
{'8', 0x0b25001a, 0x1f0b0b0a},
{'9', 0x00320000, 0x0032ffd0},
{'l', 0xc1000004, 0x00000000},
{'q', 0xc03823e0, 0x4182ce98},
{0, 0xc0847dc0, 0x41b1f704},
{'8', 0x25df18f7, 0x05d20ce9},
{'8', 0xe6e0fceb, 0xcdfee9f6},
{'q', 0x3fbca1c0, 0xc0b823ee},
{0, 0x406e0900, 0xc18d7944},
{'8', 0x00bb00e9, 0x00bd00d2},
{'9', 0x007dffe7, 0x00abffdd},
{'m', 0x413a62ce, 0xc267dc12},
{'l', 0xc09d3168, 0x41c47dc2},
{'q', 0x40ba62d0, 0xbe0fb900},
{0, 0x41874c5a, 0xbe0fb900},
{'q', 0x401435e0, 0xc13b823c},
{0, 0x408fb820, 0xc1c35e50},
{'l', 0xc183ee08, 0x00000000},
{'@', 0x00000024, 0x00004e50},/* $ x-advance: 78.312500 */
{'M', 0x4239d317, 0x4162ce99},
{'8', 0x27ec19fe, 0x0dd80ef0},
{'8', 0xf1e000eb, 0xd5f9f1f6},
{'9', 0xffe50002, 0xffb60002},
{'l', 0xbf0fb800, 0x35000000},
{'8', 0xf6b300d8, 0xe6c2f6dd},
{'8', 0xdbd3efe6, 0xd6e2ecee},
{'8', 0xcef7e2f2, 0xe318ed04},
{'8', 0xf915fa0d, 0xff11fe08},
{'8', 0x0813010a, 0x17140709},
{'8', 0x38342317, 0x144a141d},
{'l', 0x3eb3a680, 0x00000000},
{'q', 0x3e8fb800, 0xc1c00000},
{0, 0x3e8fb800, 0xc22b823f},
{'8', 0xfeec00fa, 0xfeebfef3},
{'8', 0xebb6fcd8, 0xd7c9efdf},
{'8', 0xcce0e8ec, 0xcaf5e5f5},
{'8', 0xb10cd700, 0xba26da0c},
{'8', 0xc843e019, 0xdf60e92a},
{'8', 0xbe01e501, 0xc22ec201},
{'9', 0xffff0033, 0x003b0033},
{'l', 0x00000000, 0x40f4c5a0},
{'8', 0x0c460119, 0x12430a2d},
{'8', 0x191f0715, 0x2506110a},
{'8', 0x15f70dff, 0x08ee07f9},
{'8', 0x00ec01f6, 0xfdedfff7},
{'8', 0xf7e6fef6, 0xf3ddf9f1},
{'q', 0xc01d3160, 0xbf33a600},
{0, 0xc0bee090, 0xbf579400},
{'q', 0xbe579400, 0x413823e8},
{0, 0xbefb8200, 0x41f3a62c},
{'8', 0x195d0734, 0x28421129},
{'8', 0x34291719, 0x3a171d10},
{'8', 0x3c061c06, 0x63ee3400},
{'8', 0x51cf2eef, 0x3cb622e0},
{'8', 0x25a418d6, 0x5c014500},
{'m', 0xc1ca1af4, 0xc2b4e98b},
{'8', 0x401c2400, 0x274f1b1d},
{'q', 0x3e0fb800, 0xc11f704c},
{0, 0x3e0fb800, 0xc1dd316a},
{'8', 0x2db10ecf, 0x48e31ee3},
{'m', 0x422435e5, 0x4239d316},
{'8', 0xd8fbeb00, 0xdaefeefb},
{'8', 0xdbdaecf4, 0xe2c0efe7},
{'q', 0xbd8fb800, 0x40cc59d0},
{0, 0xbe0fb800, 0x4198b3a6},
{'q', 0xbd8fba00, 0x414a1af2},
{0, 0xbe579500, 0x4193a62d},
{'8', 0xc25be937, 0xa624d824},
{'@', 0x00000025, 0x00004e50},/* % x-advance: 78.312500 */
{'M', 0x4199d317, 0xc2786bca},
{'8', 0xeab900d8, 0xc9d2ebe2},
{'q', 0xbff286bc, 0xc088fb80},
{0, 0xbfe98b38, 0xc1131678},
{'q', 0x00000000, 0xc10d7940},
{0, 0x409d3167, 0xc1686bc8},
{'q', 0x409f7048, 0xc0b823f0},
{0, 0x41608fb8, 0xc0b823f0},
{'8', 0x0935001c, 0x1d2c0918},
{'8', 0x351e1314, 0x4e07210a},
{'q', 0xbefb8280, 0x410c59d0},
{0, 0xc0a3ee10, 0x41555558},
{'9', 0x0024ffdc, 0x0023ff90},
{'m', 0xc150d795, 0x426d7943},
{'q', 0x40411f70, 0xc0c59d30},
{0, 0x4163ee09, 0xc1cf286b},
{'q', 0x4134c59e, 0xc19e50d9},
{0, 0x41b4c59d, 0xc21fb824},
{'q', 0x4135e50c, 0xc1a11f70},
{0, 0x4173a62c, 0xc1e62cec},
{'8', 0xe723ec0d, 0x062afb16},
{'8', 0x1b170914, 0x2af51103},
{'q', 0xc0aaaab0, 0x410c59d8},
{0, 0xc1cb3a64, 0x4232ce9a},
{'q', 0xc1a08fb8, 0x420fb824},
{0, 0xc1d435e5, 0x424286bc},
{'8', 0x23ba37e3, 0xb5edebd2},
{'m', 0x41698b3b, 0xc28c35e5},
{'8', 0xef2b001c, 0xcf11ee0f},
{'8', 0xc7f0d901, 0xeed1eef0},
{'8', 0x14d600e5, 0x37ef14f2},
{'8', 0x310b20ff, 0x1333100d},
{'m', 0x4213a62d, 0x4299af28},
{'8', 0xeab900d8, 0xc9d2ebe2},
{'q', 0xbff286c0, 0xc088fb82},
{0, 0xbfe98b40, 0xc1131675},
{'q', 0x00000000, 0xc10d7944},
{0, 0x409d3168, 0xc1686bca},
{'8', 0xd26fd227, 0x0935001d},
{'8', 0x1d2c0918, 0x351e1314},
{'8', 0x4e06210a, 0x6bd846fd},
{'9', 0x0024ffdc, 0x0023ff90},
{'m', 0x3fbca1a0, 0xc12f286c},
{'8', 0xef2b011c, 0xd011ed0f},
{'8', 0xb5c2b501, 0x14d600e6},
{'8', 0x35f014f1, 0x300b1fff},
{'q', 0x3fd79440, 0x4006bca2},
{0, 0x40c59d30, 0x401435e4},
{'@', 0x00000026, 0x00004e50},/* & x-advance: 78.312500 */
{'M', 0x428fdc12, 0x40a1af28},
{'8', 0x00d10cec, 0xd2d4f3e6},
{'8', 0xdff2fbfe, 0xd7f0e4f6},
{'8', 0x13f204fd, 0x15f00ef5},
{'8', 0x14ee06fb, 0x15ea0ef4},
{'8', 0x11e707f7, 0x0fe20af1},
{'8', 0x08de05f2, 0x03d803ed},
{'q', 0xc1011f72, 0x00000000},
{0, 0xc16bca1c, 0xc0823ee1},
{'q', 0xc0d55556, 0xc0847dc1},
{0, 0xc1274c5a, 0xc12e08fc},
{'q', 0xc06e08fb, 0xc0d9d316},
{0, 0xc06e08fb, 0xc16aaaaa},
{'q', 0x00000000, 0xc1d9435f},
{0, 0x41b3a62d, 0xc21435e6},
{'8', 0xd8e7eff6, 0xdfebe9f1},
{'8', 0xe7f2f6fa, 0xe6f6f1f9},
{'8', 0xe4fbf5fe, 0xdcfef0fe},
{'8', 0xd805ec00, 0xd813ec05},
{'8', 0xdb21eb0d, 0xe634f014},
{'8', 0xf648f620, 0x0a410021},
{'8', 0x1e3a0a20, 0x342a131a},
{'8', 0x480f200f, 0x44f72400},
{'8', 0x34e81ff7, 0x28dd15f2},
{'8', 0x1ed813eb, 0x17d60bef},
{'8', 0x69462314, 0x5c404631},
{'8', 0xdb11f107, 0xde0feb09},
{'8', 0xed0af306, 0xdb26e214},
{'8', 0x0328f912, 0x22180913},
{'8', 0x37f61804, 0x2ede0afb},
{'8', 0x41d123e4, 0x3e23150c},
{'8', 0x301b2817, 0x3d0d1c10},
{'9', 0x0020fffd, 0x002affec},
{'m', 0xc22e08fc, 0xc2ae98b4},
{'8', 0x3f0f1c00, 0x3c25220f},
{'8', 0xf02bf919, 0xea21f811},
{'8', 0xdf17f30f, 0xd007ec07},
{'8', 0xc0e6d600, 0xeac2eae7},
{'9', 0x0000ffb9, 0x0053ffb9},
{'m', 0xc13ca1b0, 0x4264c59d},
{'8', 0x64213c00, 0x27542721},
{'8', 0xfe1f0010, 0xfa1afd0f},
{'8', 0xf517fd0b, 0xf312f80b},
{'8', 0xf110fb06, 0xf10cf509},
{'8', 0xf00cfc03, 0xf20af408},
{'8', 0xbaded4ec, 0xaac8e6f2},
{'8', 0xa8c5c5d7, 0x25c60fde},
{'8', 0x30db15e8, 0x36ee1af4},
{'q', 0xbf21af40, 0x405c1200},
{0, 0xbf21af40, 0x40f286c0},
{'@', 0x00000027, 0x00004e50},/* ' x-advance: 78.312500 */
{'M', 0x423e08fc, 0xc2d11f70},
{'q', 0x3e0fb800, 0x40b5e500},
{0, 0xbe0fb900, 0x418d7940},
{'q', 0xbe8fb800, 0x41400000},
{0, 0xbf698b00, 0x41886bcc},
{'8', 0x23ec17fd, 0x0add0bf0},
{'8', 0xf2d8ffe9, 0xdaf1f3ef},
{'q', 0x3efb8280, 0xc0f047e0},
{0, 0x3eb3a680, 0xc1898b3c},
{'q', 0xbe0fb800, 0xc11c11f8},
{0, 0xbefb8280, 0xc18b3a64},
{'8', 0xe805f200, 0xf210f606},
{'8', 0xfa14fc0a, 0xff15ff0a},
{'8', 0x0213000a, 0x07120209},
{'8', 0x0f0e0508, 0x19060a05},
{'@', 0x00000028, 0x00004e50},/* ( x-advance: 78.312500 */
{'M', 0x42786bca, 0x415674c6},
{'8', 0x1ff11200, 0x0ce10cf1},
{'q', 0xc119d314, 0x00000000},
{0, 0xc18bca1a, 0xc0dc11f8},
{'q', 0xc0f94360, 0xc0de50d8},
{0, 0xc14b3a64, 0xc199435e},
{'q', 0xc09d3168, 0xc1447dc2},
{0, 0xc0ce98b4, 0xc1e1af28},
{'q', 0xbf86bca0, 0xc1286bcc},
{0, 0x3ed79440, 0xc1da62d0},
{'q', 0x3fbca1b0, 0xc186bca2},
{0, 0x40b3a62c, 0xc1ddc11e},
{'8', 0xb527da0e, 0xbd38db19},
{'8', 0xce47e120, 0xed4eed27},
{'8', 0x2e2e002e, 0x23f21800},
{'8', 0x0ade0af2, 0x11c900e3},
{'8', 0x2fd311e7, 0x41de1ded},
{'q', 0xbfe08fa0, 0x408d7950},
{0, 0xc03ca1b0, 0x4118b3a8},
{'q', 0xbfe98b20, 0x40f047e0},
{0, 0xc0262ce0, 0x41a47dc2},
{'q', 0xbf33a640, 0x4150d794},
{0, 0x00000000, 0x41aa1af2},
{'q', 0x3f33a600, 0x410b3a64},
{0, 0x40459d30, 0x41886bcb},
{'q', 0x4018b3a0, 0x41047dc0},
{0, 0x40b16748, 0x4163ee08},
{'8', 0x4c372f19, 0x1c381c1d},
{'8', 0x0b220016, 0x290c0b0c},
{'@', 0x00000029, 0x00004e50},/* ) x-advance: 78.312500 */
{'M', 0x426e08fc, 0xc20d7943},
{'q', 0xbfc59d40, 0x417ee08e},
{0, 0xc0ce98b8, 0x41e1af28},
{'q', 0xc09d3168, 0x41435e50},
{0, 0xc14c59d4, 0x4199435e},
{'q', 0xc0f94358, 0x40dc11f8},
{0, 0xc18b3a62, 0x40dc11f8},
{'8', 0xf4e100f0, 0xe1f1f4f1},
{'8', 0xd70be200, 0xf522f50c},
{'8', 0xe438001a, 0xb437e31d},
{'q', 0x404a1af0, 0xc0bee092},
{0, 0x40b16748, 0xc163ee09},
{'q', 0x4018b3b0, 0xc1059d32},
{0, 0x40459d40, 0xc1886bcb},
{'q', 0x3f459d00, 0xc1035e50},
{0, 0x00000000, 0xc1aa1af2},
{'q', 0xbf459d40, 0xc150d794},
{0, 0xc0262cf0, 0xc1a47dc2},
{'8', 0xb4e8d8f7, 0xbfdfddf2},
{'8', 0xd1d3e3ed, 0xefc9efe7},
{'8', 0xf6dd00eb, 0xddf2f5f2},
{'8', 0xe804f200, 0xf20bf604},
{'8', 0xfa0ffc07, 0xff0fff07},
{'8', 0x134e0027, 0x32461327},
{'8', 0x43381e20, 0x4b272519},
{'q', 0x40847dc0, 0x412e08f8},
{0, 0x40b3a628, 0x41ddc11e},
{'q', 0x3fbca1c0, 0x41862cea},
{0, 0x3ed79480, 0x41da62d0},
{'@', 0x0000002a, 0x00004e50},/* * x-advance: 78.312500 */
{'M', 0x41fe50d8, 0xc1a00000},
{'8', 0x14f10dfc, 0x08e807f5},
{'8', 0xffe700f4, 0xf9ecfef5},
{'8', 0xf0effaf6, 0xe6f7f5f9},
{'9', 0xfff1fffe, 0xffdf0007},
{'l', 0x4118b3a6, 0xc17a62ce},
{'q', 0xc13ca1ae, 0x3f459d40},
{0, 0xc18b3a62, 0x3f459d40},
{'8', 0xefd500e5, 0xd9f1eef1},
{'8', 0xec02f600, 0xec08f602},
{'8', 0xf111f606, 0xfc1afb0b},
{'q', 0x40d55556, 0x3f0fb800},
{0, 0x419c11f8, 0x3fb3a620},
{'q', 0xc0c59d34, 0xc1274c58},
{0, 0xc122ce9a, 0xc1800000},
{'8', 0xcdf3e6f0, 0xde15e703},
{'8', 0xf91af90a, 0x0820000f},
{'q', 0x40023ee0, 0x3f8fb800},
{0, 0x404a1af0, 0x405c1200},
{'q', 0x3fce98c0, 0x40608fa0},
{0, 0x4106bca4, 0x4183ee08},
{'q', 0x40b5e508, 0xc11d3168},
{0, 0x410a1af0, 0xc182ce98},
{'8', 0xe617ef08, 0xf81df70f},
{'8', 0x0719000e, 0x1212050b},
{'8', 0x1e070c07, 0x21f51100},
{'q', 0xc091f708, 0x40d79430},
{0, 0xc121af28, 0x41862cea},
{'q', 0x4148fb80, 0x00000000},
{0, 0x418e98b4, 0xbfc59d40},
{'8', 0x082cf919, 0x24131012},
{'8', 0x14fe0a00, 0x15f90afe},
{'8', 0x0ff00afb, 0x02e805f6},
{'9', 0xfff9ffda, 0xfffbff67},
{'l', 0x411af288, 0x41850d79},
{'8', 0x2f0a1a0c, 0x1def14fe},
{'8', 0x07e306f5, 0xfadd01ef},
{'q', 0xc00b3a70, 0xbf7b8240},
{0, 0xc03823f0, 0xc04e98b8},
{'q', 0xbfe98b40, 0xc0b823ec},
{0, 0xc0f047e0, 0xc1850d7a},
{'q', 0xc0d79438, 0x415435e6},
{0, 0xc1059d30, 0x418c59d4},
{'@', 0x0000002b, 0x00004e50},/* + x-advance: 78.312500 */
{'M', 0x4231af29, 0xc2100000},
{'8', 0x25f51a00, 0x0be10af5},
{'9', 0x0000ffcf, 0xffcfffcf},
{'l', 0x00000000, 0xc175e50c},
{'8', 0x00c200e9, 0x00cb00da},
{'8', 0xf2d600e4, 0xdef2f2f2},
{'8', 0xdc0cebff, 0xf22bf10e},
{'q', 0x4121af2a, 0x3e8fb880},
{0, 0x41698b3c, 0x3e8fb880},
{'q', 0x00000000, 0xc0e74c58},
{0, 0xbeb3a680, 0xc17823f4},
{'8', 0xcf31cffe, 0x0925ff16},
{'q', 0x3ff286c0, 0x3fa1af40},
{0, 0x3fd79440, 0x409af280},
{'9', 0x0042fffd, 0x007efffd},
{'l', 0x417dc11c, 0x00000000},
{'8', 0x0b25001a, 0x1e0b0b0a},
{'8', 0x13fe0a00, 0x10fa08ff},
{'8', 0x0bf107fb, 0x02e803f6},
{'q', 0xc07286b0, 0xbed79400},
{0, 0xc1800000, 0xbe0fb800},
{'8', 0x4a001f00, 0x33002a00},
{'@', 0x0000002c, 0x00004e50},/* , x-advance: 78.312500 */
{'M', 0x424a62cf, 0xc15d3167},
{'q', 0xbfbca1c0, 0x40e08fb7},
{0, 0xc0c7dc18, 0x41ad7943},
{'q', 0xc09674c0, 0x416aaaab},
{0, 0xc0e98b38, 0x4190d794},
{'8', 0x23d218ee, 0x02d10ae4},
{'8', 0xf3ebfdf5, 0xe8f5f6f7},
{'q', 0xbe8fb800, 0xbff286c0},
{0, 0x3f8fb830, 0xc0800000},
{'q', 0x403ca1b0, 0xc088fb84},
{0, 0x41035e50, 0xc197047e},
{'q', 0x40aaaaac, 0xc16aaaaa},
{0, 0x40d0d794, 0xc1a3ee09},
{'8', 0xe80ff103, 0xf71af70c},
{'8', 0x021b000e, 0x151d0511},
{'q', 0x3fc59d20, 0x3ffb8240},
{0, 0x3f86bca0, 0x409af286},
{'@', 0x0000002d, 0x00004e50},/* - x-advance: 78.312500 */
{'M', 0x41b7047e, 0xc23d7943},
{'q', 0x41023ee0, 0x00000000},
{0, 0x419b823e, 0xbe579500},
{'8', 0xff67ff5a, 0x0b25001a},
{'8', 0x1e0b0b0a, 0x32d03200},
{'q', 0xbff286c0, 0x00000000},
{0, 0xc1686bc8, 0x3f21af00},
{'q', 0xc148fb84, 0x3f21af40},
{0, 0xc18ce98c, 0x3f21af40},
{'8', 0xcfcf00cf, 0xce2fcefe},
{'@', 0x0000002e, 0x00004e50},/* . x-advance: 78.312500 */
{'M', 0x421e98b4, 0x3ffb823f},
{'8', 0xe9bb04d6, 0xbee6e4e6},
{'8', 0xc41ddd00, 0xe642e71d},
{'8', 0x1741ff28, 0x3e191919},
{'8', 0x3de82400, 0x1dbe18e8},
{'@', 0x0000002f, 0x00004e50},/* / x-advance: 78.312500 */
{'M', 0x4292f287, 0xc2c262cf},
{'q', 0xc06e0900, 0x40ebca20},
{0, 0xc1a7dc12, 0x421047dd},
{'q', 0xc18a1af4, 0x41e50d78},
{0, 0xc1a7dc13, 0x420e50d8},
{'q', 0xc01435e8, 0x408fb820},
{0, 0xc0f047dc, 0x4171674a},
{'8', 0x67cd54d8, 0x2cd120ee},
{'8', 0x00d00ce4, 0xd6ecf7ef},
{'q', 0xbed79438, 0xc0847dc1},
{0, 0x3fd79436, 0xc0f4c59d},
{'q', 0x41a86bca, 0xc20a1af3},
{0, 0x420fb824, 0xc2755555},
{'q', 0x411674c4, 0xc183ee08},
{0, 0x419ee090, 0xc2159d32},
{'8', 0xe519ef09, 0xf71ef60f},
{'8', 0x061d000f, 0x201a0a14},
{'q', 0x3f33a680, 0x40262ce0},
{0, 0xbf7b8200, 0x40c7dc10},
{'@', 0x00000030, 0x00004e50},/* 0 x-advance: 78.312500 */
{'M', 0x421435e5, 0x40608fb8},
{'8', 0xed9d00cb, 0xcab2edd3},
{'q', 0xc0823ee2, 0xc08b3a62},
{0, 0xc0ca1af4, 0xc12bca1b},
{'q', 0xc00fb822, 0xc0ce98b4},
{0, 0xc006bca0, 0xc163ee0a},
{'8', 0xc800f500, 0xb800d300},
{'8', 0xb602e600, 0xaf05d101},
{'8', 0xb60bde03, 0xba13d908},
{'q', 0x40608fb8, 0xc111f708},
{0, 0x413b823f, 0xc15d3168},
{'q', 0x41047dc2, 0xc098b3b0},
{0, 0x41a08fb8, 0xc098b3b0},
{'8', 0x1057002e, 0x2e490f28},
{'q', 0x40847dc8, 0x40770480},
{0, 0x40d9d318, 0x4121af28},
{'q', 0x402aaaa0, 0x40c59d30},
{0, 0x40579440, 0x4162ce98},
{'q', 0x3f0fb800, 0x40e50d80},
{0, 0x3f21af00, 0x41823ee2},
{'q', 0x3e0fb800, 0x4111f704},
{0, 0xbefb8200, 0x4193a62e},
{'q', 0xbf0fb800, 0x41155554},
{0, 0xbff286c0, 0x4162ce98},
{'8', 0x44e926f6, 0x33e61df4},
{'8', 0x25df15f2, 0x18db0fee},
{'8', 0x0ed408ed, 0x06cd05e7},
{'9', 0x0001ffe7, 0x0001ffc5},
{'m', 0xc1850d79, 0xc2123ee0},
{'8', 0x0e000500, 0x0c010801},
{'q', 0x4199d317, 0xc1d286bd},
{0, 0x420af286, 0xc2586bca},
{'8', 0xd3cde3ec, 0xf0bff0e3},
{'q', 0xc1000000, 0x00000000},
{0, 0xc147dc12, 0x408d7940},
{'q', 0xc08d7944, 0x408d7950},
{0, 0xc0d79438, 0x41662cf0},
{'8', 0x43f61cf9, 0x5dfe26fe},
{'8', 0x4c013600, 0x4f021600},
{'m', 0x4216bca2, 0x410e98b4},
{'q', 0x3f0fb840, 0xbfe08fc0},
{0, 0x3f98b3a0, 0xc1179438},
{'q', 0x3f33a640, 0xc0f70478},
{0, 0x3f7b8240, 0xc18e08fa},
{'q', 0x3e8fb880, 0xc1208fbc},
{0, 0xbefb8200, 0xc199d316},
{'q', 0xc1770480, 0x41fd3166},
{0, 0xc211af28, 0x425435e4},
{'8', 0x476d471f, 0xfb37001f},
{'8', 0xef2efb18, 0xda26f316},
{'q', 0x4006bca0, 0xc04a1af0},
{0, 0x40608fb0, 0xc0f9435c},
{'@', 0x00000031, 0x00004e50},/* 1 x-advance: 78.312500 */
{'M', 0x429608fc, 0xc0ace98b},
{'8', 0x26f41701, 0x0fd10ff3},
{'q', 0xbfe98b40, 0x00000000},
{0, 0xc1cc59d4, 0xbe579430},
{'q', 0xc1bd3167, 0xbe8fb824},
{0, 0xc1f5e50e, 0xbe8fb824},
{'8', 0xf2db00e7, 0xddf5f2f5},
{'8', 0xda0ae9ff, 0xf127f10c},
{'q', 0x40ce98b4, 0x00000000},
{0, 0x41b1674d, 0x3e8fb820},
{'8', 0xb6ffd300, 0xc400f7ff},
{'8', 0xb600cd00, 0xab02e900},
{'8', 0xa403c202, 0xa003e201},
{'q', 0x3eb3a600, 0xc1047dc0},
{0, 0x3f0fb800, 0xc1435e50},
{'q', 0xc12aaaaa, 0x410d7940},
{0, 0xc179435e, 0x412bca18},
{'8', 0xf5d208ea, 0xd7eaece9},
{'8', 0xe008ef00, 0xe21df208},
{'8', 0xc845e721, 0xd534e224},
{'8', 0xe921f210, 0xf61ef611},
{'8', 0x14320018, 0x23191419},
{'q', 0xbd8fb800, 0x40579440},
{0, 0xbf698b40, 0x41bc11f8},
{'q', 0xbf459d40, 0x41a11f70},
{0, 0xbf459d40, 0x41bca1ae},
{'q', 0x00000000, 0x41650d78},
{0, 0x3e0fb800, 0x41c00000},
{'q', 0x00000000, 0x40aaaaac},
{0, 0x3eb3a600, 0x417823ee},
{'8', 0x01460021, 0x013d0025},
{'8', 0x00200017, 0x0c2c0020},
{'q', 0x3fc59d40, 0x3fc59d34},
{0, 0x3fd79440, 0x40800001},
{'@', 0x00000032, 0x00004e50},/* 2 x-advance: 78.312500 */
{'M', 0x42888fb8, 0x3fd79436},
{'q', 0xc0bee090, 0x00000000},
{0, 0xc17047dc, 0x3e8fb824},
{'q', 0xc10fb824, 0x3e8fb824},
{0, 0xc17ee090, 0x3f0fb822},
{'q', 0xc0dc11f4, 0x3e8fb828},
{0, 0xc161af26, 0x3e8fb828},
{'8', 0xfda600c7, 0xe1dcfee7},
{'8', 0xadf6e4f6, 0x9915cf00},
{'8', 0x993ecb15, 0xaf60ce2a},
{'q', 0x4177047e, 0xc10a1af4},
{0, 0x419ee091, 0xc1411f70},
{'8', 0xb23bdc2f, 0xc506e806},
{'8', 0xaadec500, 0xe69ee6de},
{'8', 0x1bab00d4, 0x3dc21ad8},
{'8', 0x17ec0ff6, 0x08ed07f8},
{'8', 0xffef01f7, 0xf9ebfef8},
{'8', 0xe3e8f6ed, 0xcd0aedfc},
{'8', 0xd521eb0b, 0xd735ea17},
{'8', 0xe146ed1e, 0xf450f427},
{'q', 0x417823f0, 0x00000000},
{0, 0x41bca1b0, 0x40e74c60},
{'q', 0x41011f74, 0x40e50d70},
{0, 0x41011f74, 0x41ac59d0},
{'q', 0x00000000, 0x413dc124},
{0, 0xc0c35e50, 0x4198b3a8},
{'q', 0xc08fb828, 0x40aaaaa8},
{0, 0xc1800002, 0x413ca1b0},
{'8', 0x2bb10de9, 0x40ad1acf},
{'8', 0x4ed026df, 0x57ef28f2},
{'q', 0x41000000, 0x3ed79440},
{0, 0x4177047e, 0x3efb8240},
{'8', 0xff5d003c, 0xfb4cfe21},
{'8', 0xfc3afd2b, 0x000a0001},
{'8', 0x000c0009, 0x000b0003},
{'8', 0x020c0008, 0x05090204},
{'8', 0x08080205, 0x0d030502},
{'8', 0x1dff0d01, 0x1cf40ffe},
{'q', 0xbf98b3c0, 0x3fce98b4},
{0, 0xc0411f80, 0x3fce98b4},
{'@', 0x00000033, 0x00004e50},/* 3 x-advance: 78.312500 */
{'M', 0x4293ee09, 0xc1e47dc1},
{'q', 0x00000000, 0x416bca1b},
{0, 0xc111f708, 0x41bb823f},
{'q', 0xc111f700, 0x410a1af2},
{0, 0xc1cbca1a, 0x410a1af2},
{'8', 0xf5b000d8, 0xe1baf4d9},
{'8', 0xd7cbede2, 0xd4dfeaea},
{'8', 0xd0f8e6f3, 0xe117eb04},
{'8', 0xfb29f516, 0x1d250513},
{'8', 0x3d402219, 0x1a541a27},
{'q', 0x4108fb84, 0x00000000},
{0, 0x4161af28, 0xc09d3166},
{'8', 0x9c2cd92c, 0xbff5db00},
{'8', 0xd0dce4f5, 0xe0bbebe7},
{'8', 0xf699f6d5, 0xeed800e9},
{'8', 0xd6f0edf0, 0xd90ce800},
{'q', 0x3fc59d30, 0xbff286c0},
{0, 0x4091f704, 0xbff286c0},
{'q', 0x41411f70, 0x00000000},
{0, 0x4197047e, 0xc098b3b0},
{'8', 0x9135da37, 0xb4ddcc01},
{'8', 0xe795e7db, 0x02e600f2},
{'8', 0x05ec02f5, 0x0aef02f8},
{'8', 0x0bf107f7, 0x0ef303fb},
{'8', 0x0ef50af8, 0x10f503fe},
{'8', 0x1edb19ee, 0xfad704ed},
{'8', 0xe2e9f7ed, 0xcf08ebfc},
{'8', 0xd61cea0b, 0xdc2aed11},
{'8', 0xe63bef18, 0xf64bf622},
{'q', 0x41847dc0, 0x00000000},
{0, 0x41c6bca2, 0x40de50d0},
{'q', 0x41047dc4, 0x40dc1200},
{0, 0x41011f6c, 0x41a35e54},
{'8', 0x3cf82100, 0x2de81af8},
{'8', 0x21db12f1, 0x16d50eeb},
{'8', 0x0cd107ea, 0x19500a2f},
{'8', 0x26390e21, 0x3b241718},
{'q', 0x3fc59d40, 0x408d7940},
{0, 0x3fc59d40, 0x41298b3a},
{'@', 0x00000034, 0x00004e50},/* 4 x-advance: 78.312500 */
{'M', 0x4280d794, 0xc0fb823f},
{'8', 0x3ffa2507, 0x1ad91af3},
{'8', 0xf0d600eb, 0xdeebf0ec},
{'8', 0xd400f300, 0xa800e200},
{'q', 0x3d8fb800, 0xc0e74c58},
{0, 0x3d8fb800, 0xc146bca0},
{'q', 0xc1d1674d, 0xbeb3a680},
{0, 0xc2111f70, 0x3fe98b30},
{'8', 0xffdf03ef, 0xf0e9fbf2},
{'8', 0xe7f3f5f8, 0xe1fcf1fc},
{'8', 0xe205f000, 0x983de00b},
{'q', 0x40ca1af4, 0xc111f704},
{0, 0x41823ee1, 0xc1b435e6},
{'q', 0x411f7048, 0xc1579430},
{0, 0x4162ce98, 0xc19ca1ac},
{'8', 0xe021eb0f, 0xf523f513},
{'8', 0x082afe17, 0x23170a13},
{'q', 0x3f579440, 0x40a1af20},
{0, 0x3faaaaa0, 0x417823e8},
{'q', 0x3f0fb840, 0x41274c60},
{0, 0x3f33a640, 0x418e08fc},
{'q', 0x3e0fb800, 0x40e74c60},
{0, 0x3ed79400, 0x41afb824},
{'8', 0x012b0113, 0x0b25001a},
{'8', 0x1f0b0b0a, 0x32cf3200},
{'q', 0xc03823e0, 0x00000000},
{0, 0xc0aaaaa0, 0xbe0fb880},
{'9', 0x00a80002, 0x00bf0007},
{'m', 0xc16bca18, 0xc29d5555},
{'q', 0xc1aaaaab, 0x41dee08e},
{0, 0xc1e74c5a, 0x422d3167},
{'q', 0x4133a62c, 0xbf33a640},
{0, 0x41efb824, 0xbed79480},
{'q', 0x00000000, 0xc1d79434},
{0, 0xbf86bca0, 0xc22b823e},
{'@', 0x00000035, 0x00004e50},/* 5 x-advance: 78.312500 */
{'M', 0x42953167, 0xc22a62cf},
{'q', 0x00000000, 0x412aaaac},
{0, 0xc02aaaa0, 0x4199d317},
{'q', 0xc02aaaa0, 0x4108fb83},
{0, 0xc0f047e0, 0x4163ee09},
{'q', 0xc09af280, 0x40b5e50e},
{0, 0xc139435c, 0x410b3a63},
{'q', 0xc0d55558, 0x40411f72},
{0, 0xc16bca1c, 0x40411f72},
{'8', 0xf6a300ce, 0xe4b9f6d6},
{'8', 0xdad0efe4, 0xd6e1eced},
{'8', 0xcef7e1f2, 0xe318ed04},
{'8', 0xf915fb0c, 0xff12fe08},
{'8', 0x0913010a, 0x17130708},
{'q', 0x40d0d794, 0x411f7048},
{0, 0x418c59d3, 0x411f7048},
{'q', 0x412ce98c, 0x00000000},
{0, 0x4188fb82, 0xc107dc12},
{'q', 0x40cc59d0, 0xc107dc12},
{0, 0x40cc59d0, 0xc1b7047e},
{'q', 0x00000000, 0xc10e98b4},
{0, 0xc0800000, 0xc162ce98},
{'8', 0xd69fd6e0, 0x02df00ef},
{'8', 0x05e502f1, 0x08e802f5},
{'8', 0x09ec05f4, 0x0cef03fa},
{'8', 0x0cf108f5, 0x0ef203fd},
{'8', 0x0df20af5, 0x0eea08f7},
{'8', 0x07e405f4, 0xfbe001f0},
{'8', 0xdde3f8ed, 0xbdf5e5f7},
{'8', 0xb300d8ff, 0xb004db01},
{'8', 0xc503d603, 0xdff5f2f7},
{'8', 0xdd01edfe, 0xe510f004},
{'q', 0x3fbca1b0, 0xbfbca180},
{0, 0x40608fb8, 0xbfbca180},
{'q', 0x40aaaaac, 0x00000000},
{0, 0x41c8fb82, 0x3eb3a600},
{'q', 0x419e50d8, 0x3e8fb800},
{0, 0x41f0d794, 0x3e8fb800},
{'8', 0x0c18000e, 0x1d0c0c0a},
{'8', 0x1d010f02, 0x0efd07ff},
{'8', 0x08f805fe, 0x05f702fb},
{'8', 0x02f401fd, 0x00f500f9},
{'8', 0x00f400fd, 0xfff6fff7},
{'8', 0xfdc700f0, 0xfbb6fdd7},
{'q', 0xc0800000, 0xbe8fb800},
{0, 0xc133a62c, 0xbe8fb800},
{'q', 0xc0e50d7c, 0x00000000},
{0, 0xc17047de, 0x3efb8200},
{'8', 0x42fe0b00, 0x4ffe37ff},
{'8', 0x46011800, 0xc657dd20},
{'q', 0x40dc11f8, 0xc0382400},
{0, 0x417b8240, 0xc0382400},
{'8', 0x135c0033, 0x34431328},
{'8', 0x4d28211a, 0x600e2c0e},
{'@', 0x00000036, 0x00004e50},/* 6 x-advance: 78.312500 */
{'M', 0x42953167, 0xc20d7943},
{'q', 0x00000000, 0x40fffffc},
{0, 0xc02aaaa0, 0x417286bc},
{'8', 0x62c739eb, 0x41a828dc},
{'q', 0xc0cc59d8, 0x40411f70},
{0, 0xc158b3a8, 0x40411f70},
{'q', 0xc10d7942, 0x00000000},
{0, 0xc17823ee, 0xc05c11f7},
{'q', 0xc0d55554, 0xc05c11f7},
{0, 0xc12e08fb, 0xc11d3167},
{'q', 0xc086bca2, 0xc0cc59d4},
{0, 0xc0ca1af2, 0xc173a62e},
{'q', 0xc0023ee2, 0xc10e98b2},
{0, 0xbff286c0, 0xc1a08fb7},
{'q', 0x3e0fb840, 0xc146bca4},
{0, 0x401d3168, 0xc1b1f706},
{'q', 0x4018b3a8, 0xc11e50d8},
{0, 0x40ce98b4, 0xc1850d78},
{'8', 0xa550ca21, 0xc867db30},
{'q', 0x40de50d8, 0xc01d3180},
{0, 0x417823ec, 0xc04a1b00},
{'8', 0x072efe1a, 0x1f170914},
{'8', 0x1ef30e01, 0x15df10f1},
{'8', 0x08da03f4, 0x0bd405e6},
{'8', 0x0fd505ef, 0x1dcf0ae8},
{'8', 0x2fd013e8, 0x51d21ee7},
{'8', 0x5be633eb, 0xc15cd623},
{'q', 0x40e50d78, 0xc02aaac0},
{0, 0x417ee090, 0xc02aaac0},
{'8', 0x0f5e0035, 0x2f470f29},
{'q', 0x40770480, 0x40800000},
{0, 0x40ba62d0, 0x41298b3c},
{'9', 0x00340010, 0x007b0010},
{'m', 0xc25f7047, 0x401435e0},
{'8', 0x330a1902, 0x34161907},
{'8', 0x2e21190e, 0x202f1313},
{'8', 0x0b3a0b1b, 0xe350002a},
{'8', 0xb53ce326, 0xa315d215},
{'8', 0xa6f7cb00, 0xc8e3dcf7},
{'8', 0xe5d3edec, 0xf9c3f9e7},
{'8', 0x1d9400c7, 0x4baf1dce},
{'q', 0x00000000, 0x40c59d30},
{0, 0x3e8fb840, 0x4122ce98},
{'@', 0x00000037, 0x00004e50},/* 7 x-advance: 78.312500 */
{'M', 0x41d0d794, 0xc06e08fc},
{'8', 0x2ddd1ef3, 0x0ad50eeb},
{'8', 0xe4defbe8, 0xd002eaf7},
{'q', 0x40ebca1a, 0xc16ce98a},
{0, 0x417b823f, 0xc1eb3a63},
{'q', 0x41059d30, 0xc16aaaa8},
{0, 0x415d3168, 0xc1baf286},
{'q', 0x40b16748, 0xc10b3a64},
{0, 0x4122ce98, 0xc1874c5a},
{'q', 0x409674c8, 0xc1047dc0},
{0, 0x40cc59d0, 0xc1555558},
{'q', 0xc147dc10, 0xbed79400},
{0, 0xc1d55555, 0xbd8fb800},
{'q', 0xc161af28, 0x3eb3a600},
{0, 0xc1931674, 0x3fbca1c0},
{'8', 0xffe803f3, 0xf3effcf6},
{'8', 0xecf6f7fa, 0xecfdf6fd},
{'8', 0xe00aec00, 0xef26f40a},
{'q', 0x40aaaaaa, 0xbf7b8200},
{0, 0x416bca1b, 0xbfa1af00},
{'q', 0x411674c4, 0xbe8fb800},
{0, 0x418a1af2, 0x00000000},
{'q', 0x40fb8240, 0x3e579400},
{0, 0x41770480, 0x3f0fb800},
{'8', 0x0241023d, 0x0517000b},
{'8', 0x1015050c, 0x1d0a0b0a},
{'8', 0x2bf61100, 0x68c622f0},
{'q', 0xc0a86bc8, 0x410a1af0},
{0, 0xc12f286c, 0x418e08fa},
{'q', 0xc0b5e508, 0x4111f704},
{0, 0xc15d3164, 0x41c23ee0},
{'q', 0xc1023ee4, 0x4171674e},
{0, 0xc1770480, 0x41f79436},
{'@', 0x00000038, 0x00004e50},/* 8 x-advance: 78.312500 */
{'M', 0x42957943, 0xc1eaaaab},
{'8', 0x49f62500, 0x47e024f7},
{'8', 0x3dc823e9, 0x2bac1adf},
{'q', 0xc0ce98b8, 0x40023ee0},
{0, 0xc1662cec, 0x40023ee0},
{'8', 0xf19800c7, 0xd8b4f1d2},
{'8', 0xc5cfe7e3, 0xbbe4deed},
{'8', 0xb9f9def9, 0xad13d900},
{'8', 0xad39d413, 0xcb53da25},
{'8', 0xb6a1e4c3, 0xa2dfd2df},
{'8', 0xe302f200, 0xdc08f102},
{'8', 0xd811eb06, 0xda1ded0a},
{'8', 0xdf2bed13, 0xea3cf218},
{'8', 0xf84ff824, 0x0850002c},
{'8', 0x163d0824, 0x212b0e18},
{'8', 0x261d1313, 0x2811130a},
{'8', 0x26081506, 0x20021002},
{'8', 0x1bfd0e00, 0x18f80dfd},
{'8', 0x16f20afb, 0x13ef0bf7},
{'8', 0x11ec07f9, 0x0fec0af4},
{'8', 0x0eec05f9, 0x0cee08f3},
{'8', 0x294a112a, 0x2d331720},
{'8', 0x2f1e1613, 0x2d0f190b},
{'9', 0x00140003, 0x00290003},
{'m', 0xc2555554, 0xc2400000},
{'q', 0xb6000000, 0x4098b3b0},
{0, 0x408b3a60, 0x4107dc18},
{'q', 0x408d7940, 0x40698b20},
{0, 0x41686bc8, 0x40ebca10},
{'8', 0xcc54ed30, 0xc225de25},
{'8', 0xc2eee000, 0xcccde1ef},
{'8', 0xecbaecdf, 0x26a300cb},
{'9', 0x0026ffd9, 0x0055ffd9},
{'m', 0x41847dc1, 0x428a1af3},
{'8', 0xf7420021, 0xe43cf621},
{'8', 0xd02bed1a, 0xc010e310},
{'8', 0xdefdee00, 0xdaf3f0fe},
{'8', 0xd8e3ebf6, 0xdaceeeef},
{'q', 0xc0823ee0, 0xc021af30},
{0, 0xc119d314, 0xc091f708},
{'q', 0xc1262cea, 0x402f2870},
{0, 0xc186bca2, 0x41179438},
{'q', 0xc0cc59d4, 0x40d79438},
{0, 0xc0cc59d4, 0x41662ce8},
{'8', 0x4d192a00, 0x34402219},
{'q', 0x409d3168, 0x400b3a64},
{0, 0x4123ee08, 0x400fb824},
{'@', 0x00000039, 0x00004e50},/* 9 x-advance: 78.312500 */
{'M', 0x41baf287, 0x404e98b4},
{'8', 0xf9d202e6, 0xe1eaf6ed},
{'8', 0xe20df2ff, 0xeb21f00f},
{'8', 0xf728fd0c, 0xf533fa1c},
{'8', 0xf032fa16, 0xe436f61c},
{'8', 0xd530ee1a, 0xb333df1c},
{'8', 0xb01dd416, 0x32af24e0},
{'q', 0xc0c59d30, 0x3fd79440},
{0, 0xc177047c, 0x3fd79440},
{'8', 0xe9a000ce, 0xc2b2e9d3},
{'8', 0xa7cddae0, 0x98edcded},
{'q', 0x00000000, 0xc1000000},
{0, 0x402aaaaa, 0xc16f2870},
{'8', 0xa139c815, 0xc357d925},
{'q', 0x40cc59d0, 0xc033a620},
{0, 0x4159d318, 0xc033a620},
{'q', 0x418ce98a, 0x00000000},
{0, 0x41d1f704, 0x415674c0},
{'q', 0x410a1af0, 0x415674c8},
{0, 0x41059d30, 0x42198b3b},
{'q', 0xbe0fb800, 0x41370480},
{0, 0xc03823e0, 0x41a62cea},
{'q', 0xc02aaac0, 0x411435e6},
{0, 0xc0e98b40, 0x417b8240},
{'8', 0x58a833dc, 0x379224cd},
{'9', 0x0013ffc6, 0x0019ff82},
{'m', 0xc0847dc0, 0xc293a62d},
{'q', 0x00000000, 0x413ca1ac},
{0, 0x40a3ee08, 0x418f286a},
{'q', 0x40a3ee08, 0x40c35e50},
{0, 0x417286be, 0x40c35e50},
{'8', 0xe9620032, 0xc24ce930},
{'8', 0x9bfddf01, 0xcdf6e7fe},
{'8', 0xcceae6f9, 0xd2dee6f2},
{'8', 0xe0d2eced, 0xf5c6f4e5},
{'8', 0x1bb000d6, 0x46c41adb},
{'q', 0xc02f2868, 0x40ace990},
{0, 0xc02f2868, 0x4133a630},
{'@', 0x0000003a, 0x00004e50},/* : x-advance: 78.312500 */
{'M', 0x4243a62d, 0xc26fb824},
{'8', 0x50f82502, 0x22e817fb},
{'8', 0x0adb0bed, 0xccb6fdbb},
{'8', 0xb1ffe1fe, 0xe808f200},
{'8', 0xf214f608, 0xfb18fc0c},
{'8', 0xff17ff0b, 0x0214000a},
{'8', 0x0715020a, 0x0f12050b},
{'9', 0x000a0007, 0x00190008},
{'m', 0x3e0fb800, 0x42198b3a},
{'8', 0x52fb2706, 0x22e416fb},
{'8', 0x0ad60bea, 0xf2d4ffe9},
{'8', 0xdae8f2eb, 0xe2ffe8ff},
{'8', 0xe901fa00, 0xe602ef01},
{'8', 0xe807f200, 0xf214f607},
{'8', 0xfa17fc0c, 0xff15ff0b},
{'8', 0x041b000e, 0x101a030d},
{'q', 0x3fce98c0, 0x3fc59d30},
{0, 0x40023ee0, 0x40770480},
{'@', 0x0000003b, 0x00004e50},/* ; x-advance: 78.312500 */
{'M', 0x424a62cf, 0xc257dc12},
{'8', 0x51f82602, 0x22e817fb},
{'8', 0x0adb0bed, 0xfae2fff2},
{'8', 0xefe4fbf1, 0xe3f1f4f3},
{'8', 0xb1ffe1fe, 0xe808f200},
{'8', 0xf214f608, 0xfa18fc0c},
{'8', 0xff16ff0b, 0x0214000a},
{'8', 0x0715020a, 0x1012050b},
{'9', 0x000a0007, 0x00190008},
{'m', 0xc033a630, 0x422d7944},
{'q', 0xbeb3a600, 0x4091f700},
{0, 0xc1155554, 0x4215e50d},
{'8', 0x22e917fa, 0x09dd0af0},
{'8', 0xf2d7ffe9, 0xdaf1f3ef},
{'q', 0x3e8fb840, 0xc05c11f8},
{0, 0x403ca1b0, 0xc1862cea},
{'q', 0x402f2868, 0xc15674c6},
{0, 0x408d7944, 0xc1a35e51},
{'8', 0xe50aef03, 0xf30ef606},
{'8', 0xfc11fd08, 0x0012ff09},
{'8', 0x0215000a, 0x0717020b},
{'8', 0x0f13050c, 0x19050a07},
{'@', 0x0000003c, 0x00004e50},/* < x-advance: 78.312500 */
{'M', 0x429823ee, 0xbffb823f},
{'8', 0x13ef0bfb, 0x0ae207f5},
{'8', 0xfad202ed, 0xd9b9f8e4},
{'8', 0xb6a5e1d6, 0xa89fd5d0},
{'8', 0xa49bd4d0, 0xb6a6d1cb},
{'8', 0xe2edf6f2, 0xda01ecfc},
{'q', 0x3f33a630, 0xc018b3b0},
{0, 0x401d3168, 0xc05c1200},
{'q', 0x41023ee0, 0xc0c11f70},
{0, 0x4199435e, 0xc17286b8},
{'q', 0x413047dc, 0xc1131678},
{0, 0x41a11f70, 0xc1847dc4},
{'q', 0x41131674, 0xc0ebca10},
{0, 0x4182ce9a, 0xc13a62d0},
{'8', 0xf421f511, 0x051bff10},
{'8', 0x0f13060b, 0x130c0807},
{'8', 0x27fe130a, 0x2fcd14f4},
{'q', 0xc0fffff8, 0x40b3a630},
{0, 0xc1c35e50, 0x4193a62c},
{'q', 0xc1835e51, 0x414c59d4},
{0, 0xc1a74c5a, 0x41811f70},
{'8', 0x5363222c, 0x59613137},
{'8', 0x50592729, 0x40542830},
{'8', 0x2a301825, 0x2503110c},
{'@', 0x0000003d, 0x00004e50},/* = x-advance: 78.312500 */
{'M', 0x4191674c, 0xc297dc12},
{'q', 0x41035e52, 0x3e8fb800},
{0, 0x4186bca2, 0x3e8fb800},
{'q', 0x410a1af4, 0x00000000},
{0, 0x41811f70, 0xbe0fb800},
{'8', 0xff48ff3c, 0x0b25001a},
{'8', 0x1e0b0b0a, 0x13fe0a00},
{'8', 0x10fa08ff, 0x0cf107fb},
{'8', 0x02e803f6, 0x00a9ffd7},
{'q', 0xc0b5e508, 0x3e0fb800},
{0, 0xc17b823c, 0x3ed79400},
{'q', 0xc1208fba, 0x3e8fb800},
{0, 0xc16bca1c, 0x3e8fb800},
{'8', 0xf2d400e4, 0xdff0f2f0},
{'8', 0xdc0cebff, 0xf22bf10e},
{'m', 0x3ed79440, 0x41e47dc2},
{'q', 0x4135e50e, 0x3e579400},
{0, 0x41d31675, 0xbd8fba00},
{'q', 0x4171674c, 0xbeb3a600},
{0, 0x4174c59c, 0xbeb3a600},
{'8', 0x0b25001a, 0x1e0b0b0a},
{'8', 0x13fe0a00, 0x10fa08ff},
{'8', 0x0cf107fb, 0x02e803f6},
{'q', 0xc0a62ce8, 0xbe579400},
{0, 0xc131674c, 0xbd8fb800},
{'q', 0xc0ba62d0, 0x3d8fb800},
{0, 0xc1808fb8, 0x3ed79400},
{'q', 0xc122ce98, 0x3e8fb800},
{0, 0xc16ce98a, 0x3e8fb800},
{'8', 0xf2d600e4, 0xddf2f2f2},
{'8', 0xe00eedff, 0xf42cf30f},
{'@', 0x0000003e, 0x00004e50},/* > x-advance: 78.312500 */
{'M', 0x418fb824, 0xbf459d32},
{'8', 0x0cdf0aef, 0xfbe401f0},
{'8', 0xf1edfaf5, 0xedf4f8f9},
{'8', 0xd902edf6, 0xd133ec0c},
{'q', 0x41000000, 0xc0b3a62e},
{0, 0x41c35e52, 0xc1931676},
{'q', 0x41835e50, 0xc14d7944},
{0, 0x41a7dc12, 0xc181af28},
{'8', 0xad9cded4, 0xa8a0cfc9},
{'8', 0xb0a7d9d7, 0xbfacd7d0},
{'8', 0xd6cfe8db, 0xdafdeef5},
{'8', 0xed10f505, 0xf61ff90b},
{'8', 0x062efe13, 0x2747081c},
{'8', 0x4a5b1e2b, 0x58612b30},
{'8', 0x5c652c30, 0x4a5b2f35},
{'8', 0x1e120a0e, 0x27001405},
{'q', 0xbf33a600, 0x401435f0},
{0, 0xc01d3160, 0x40579440},
{'q', 0xc1023ee0, 0x40bee090},
{0, 0xc199435e, 0x417286bc},
{'q', 0xc13047dc, 0x41131674},
{0, 0xc1a1af2a, 0x41847dc1},
{'q', 0xc111f704, 0x40e98b3b},
{0, 0xc1823ee0, 0x413a62cf},
{'@', 0x0000003f, 0x00004e50},/* ? x-advance: 78.312500 */
{'M', 0x4236bca2, 0xc216bca2},
{'8', 0x2eeb1dfc, 0x08d10ff0},
{'8', 0xe3d6f8e0, 0xc6ffebf6},
{'8', 0xc617e107, 0xd121e50f},
{'8', 0xdb26ed11, 0xdf26ef14},
{'8', 0xe121f112, 0xdd18f00f},
{'8', 0xd808ed08, 0xaadec500},
{'8', 0xe69ee6de, 0x07e000f0},
{'8', 0x10e407f0, 0x18e708f5},
{'8', 0x1aec0ff3, 0x19ef0af9},
{'8', 0x17ed0ff6, 0x08ed07f8},
{'8', 0xffee01f6, 0xf9ebfef9},
{'8', 0xe3e8f6ed, 0xcd0aedfc},
{'8', 0xd21ee90c, 0xd32ce912},
{'8', 0xdd3eea1a, 0xf24bf223},
{'q', 0x417823f0, 0x00000000},
{0, 0x41bca1b0, 0x40e74c60},
{'q', 0x41011f74, 0x40e50d70},
{0, 0x41011f74, 0x41ac59d0},
{'8', 0x38f61e00, 0x2be719f7},
{'8', 0x22dc11f0, 0x20d80fed},
{'8', 0x21d90fec, 0x2ae011ef},
{'9', 0x0019fff3, 0x0037ffef},
{'m', 0xc0ebca20, 0x421e98b4},
{'8', 0xe9bb04d6, 0xbee6e4e6},
{'8', 0xc41ddd00, 0xe642e71d},
{'8', 0x1741ff27, 0x3e191919},
{'8', 0x3de72400, 0x1dbf18e8},
{'@', 0x00000040, 0x00004e50},/* @ x-advance: 78.312500 */
{'M', 0x428a62cf, 0xbf459d32},
{'8', 0x1cf410fa, 0x1def0cfa},
{'8', 0x1ee911f6, 0x19e00cf4},
{'8', 0x15d70ded, 0x0ecb08ea},
{'q', 0xc0770480, 0x3f21af20},
{0, 0xc1059d34, 0x3f0fb820},
{'q', 0xc0f286b8, 0x00000000},
{0, 0xc163ee08, 0xc06e08f8},
{'q', 0xc0d31674, 0xc07286c0},
{0, 0xc137047d, 0xc1274c5a},
{'q', 0xc098b3a7, 0xc0d55556},
{0, 0xc0f286be, 0xc1823ee1},
{'q', 0xc02f286b, 0xc119d316},
{0, 0xc02f286b, 0xc1a74c5a},
{'q', 0x00000000, 0xc14a1af0},
{0, 0x3ffb823e, 0xc1bca1ae},
{'q', 0x3ffb8240, 0xc12f2870},
{0, 0x40b1674c, 0xc19823f0},
{'8', 0x9143bf1c, 0xbb55d226},
{'8', 0xe962e92f, 0x06460026},
{'8', 0x143c051f, 0x26340e1d},
{'8', 0x3c281716, 0x541e2313},
{'q', 0x3fc59d00, 0x40c35e50},
{0, 0x4018b3a0, 0x41650d74},
{'q', 0x3f579400, 0x41023ee4},
{0, 0x3f579400, 0x419286be},
{'8', 0x4efa2900, 0x46ee25fb},
{'8', 0x34dd20f4, 0x13ca13e9},
{'8', 0x9fa300ad, 0x4e9d4ee6},
{'q', 0xc107dc12, 0x00000000},
{0, 0xc15435e4, 0xc0aaaaac},
{'q', 0xc09674c8, 0xc0aaaaa8},
{0, 0xc09674c8, 0xc181af29},
{'8', 0xb009d500, 0xc21adb09},
{'8', 0xd527e710, 0xe730ef16},
{'8', 0xfa36f91a, 0x0b37011c},
{'8', 0x1c2a0a1a, 0x1e08100f},
{'8', 0x0ff608fc, 0x08f205fb},
{'8', 0x03f202f9, 0xffef00fa},
{'8', 0xfef0fff6, 0xfcf0fffb},
{'8', 0xffe3fef2, 0x0ae401f2},
{'8', 0x15e808f3, 0x23ef0df6},
{'8', 0x30fa15fa, 0x1c010e00},
{'8', 0x1d060d01, 0x1a0f1005},
{'8', 0x0a1b0a0b, 0xe4330024},
{'8', 0xa310e40f, 0xe31def00},
{'8', 0xfd35f420, 0x160d060f},
{'8', 0x5ffd3dfa, 0x2e0b2103},
{'8', 0x0c170c08, 0xf1100009},
{'8', 0xda09f106, 0xd603e802},
{'8', 0xdc01ed01, 0x95fbc600},
{'8', 0xacf4cffb, 0xc1ecddf9},
{'8', 0xd2e8e4f4, 0xe2e5eff5},
{'8', 0xede5f4f1, 0xf7e5faf5},
{'8', 0xfde9fdf1, 0x00ed00f9},
{'8', 0x1cab00d3, 0x50ba1cd8},
{'q', 0xc06e0900, 0x40cc59d0},
{0, 0xc0bee090, 0x417dc11c},
{'q', 0xc00b3a64, 0x41179438},
{0, 0xc00b3a64, 0x41a50d7a},
{'q', 0x00000000, 0x411d3168},
{0, 0x3fbca1a8, 0x418ce98b},
{'8', 0x651e3e0b, 0x412d2613},
{'8', 0x24331919, 0x0a360a1a},
{'8', 0xfb37001e, 0xf329fb19},
{'8', 0xeb1ef810, 0xe717f20f},
{'8', 0xe313f508, 0xf407f804},
{'8', 0xf507fb03, 0xf807fa04},
{'8', 0xfb08fe03, 0xfe0afe05},
{'8', 0x020b0005, 0x080f0309},
{'8', 0x0d090506, 0x16010803},
{'q', 0xbe579400, 0x3fe08fb8},
{0, 0xbf8fb800, 0x40823ee1},
{'@', 0x00000041, 0x00004e50},/* A x-advance: 78.312500 */
{'M', 0x416f286c, 0xc0ba62cf},
{'8', 0x2fe023f5, 0x01d60bec},
{'q', 0xc0a1af28, 0xc00fb824},
{0, 0xc0459d31, 0xc12e08fb},
{'q', 0x3f698b3c, 0xc09435e6},
{0, 0x41047dc1, 0xc1b3a62d},
{'8', 0xdfecf3ec, 0xe20ef1ff},
{'q', 0x40023ee0, 0xbff286c0},
{0, 0x40a3ee08, 0xc033a630},
{'q', 0x418ce98c, 0xc2247dc2},
{0, 0x41d9435e, 0xc25bca1a},
{'8', 0xdf1de910, 0xf61df60d},
{'8', 0x0827fe15, 0x23150a11},
{'q', 0x403ca1b0, 0x418e98b0},
{0, 0x4121af2c, 0x424a1af2},
{'q', 0x40e50d70, 0x4202ce98},
{0, 0x411e50d8, 0x421674c6},
{'8', 0x2709150b, 0x1ef511fe},
{'8', 0x11ea0bf8, 0xffd509eb},
{'q', 0xc02f2860, 0xbfb3a62d},
{0, 0xc08d7940, 0xc0bca1b0},
{'q', 0xbfe98b20, 0xc08fb823},
{0, 0xc0e74c58, 0xc1f286bc},
{'9', 0x0006ff6d, 0x0018fef9},
{'6', 0x00d9ffb6, 0xfd7b00ff},
{'q', 0xc0ca1af0, 0x4119d310},
{0, 0xc18fb824, 0x42235e50},
{'q', 0x41698b3c, 0xbfd79420},
{0, 0x41cfb824, 0xbffb8240},
{'l', 0xc1000000, 0xc21b823e},
{'@', 0x00000042, 0x00004e50},/* B x-advance: 78.312500 */
{'M', 0x41f4c59d, 0x3ffb823f},
{'8', 0x03d501ed, 0x03d902e8},
{'8', 0x02e201f2, 0x01e501f1},
{'9', 0x0000fff5, 0xfffeffeb},
{'l', 0xbefb8240, 0x00000000},
{'8', 0xf1da00e9, 0xd5f4f1f2},
{'q', 0x3efb8240, 0xc0bee090},
{0, 0x3e8fb828, 0xc1b79436},
{'q', 0xbe0fb830, 0xc187dc12},
{0, 0xbf579438, 0xc20c11f7},
{'8', 0x99feb3fe, 0xba01e600},
{'8', 0xc302d402, 0xd210e201},
{'9', 0xfff00010, 0xfff00027},
{'l', 0x3f21af30, 0x00000000},
{'8', 0xf826fb11, 0xfb25fd14},
{'8', 0xfe23fe10, 0xff1dff13},
{'8', 0x0017000a, 0x000c000c},
{'q', 0x411c11f8, 0x00000000},
{0, 0x418aaaaa, 0x40698b40},
{'q', 0x40f4c5a0, 0x40650d80},
{0, 0x41411f74, 0x41262ce8},
{'q', 0x408d7948, 0x40d9d310},
{0, 0x4091f708, 0x417dc120},
{'q', 0x3e0fb800, 0x41059d30},
{0, 0xc07286d0, 0x41650d78},
{'8', 0x45ab2fe1, 0x254b0c26},
{'8', 0x373e1825, 0x38191e19},
{'8', 0x57ea2b00, 0x4ec02aea},
{'q', 0xc0a86bc8, 0x408d7944},
{0, 0xc1579434, 0x40f286be},
{'9', 0x0019ffbf, 0x0020ff70},
{'m', 0x400b3a68, 0xc2b8fb82},
{'q', 0xc0f70480, 0x00000000},
{0, 0xc171674e, 0x3fe98b40},
{'8', 0x46fe1500, 0x66fe30ff},
{'8', 0x6e0035ff, 0x02660235},
{'8', 0xfb3f0022, 0xf230fb1c},
{'8', 0xe922f713, 0xe617f30f},
{'8', 0xe20df208, 0xe307f005},
{'8', 0xe402f302, 0xc9f5e200},
{'8', 0xd8e3e7f5, 0xe6d8f1ef},
{'8', 0xf2d4f6e9, 0xfcd8fceb},
{'m', 0xbff286c0, 0x423f286b},
{'q', 0xc1274c5a, 0x00000000},
{0, 0xc15af288, 0x3e0fb800},
{'q', 0x3f21af40, 0x41b9435f},
{0, 0x3f7b8240, 0x4203a62d},
{'8', 0xff29000c, 0xff2c001d},
{'8', 0xef63fe34, 0xda4bf12e},
{'8', 0xd12ee91d, 0xd310e810},
{'8', 0xe3f4f200, 0xe1dbf1f4},
{'8', 0xe3baf1e7, 0xea9af2d4},
{'@', 0x00000043, 0x00004e50},/* C x-advance: 78.312500 */
{'M', 0x4291af28, 0xc1131675},
{'q', 0xc1447dbc, 0x41608fb8},
{0, 0xc217dc11, 0x415af287},
{'8', 0xf1a800d1, 0xd5b9f0d7},
{'8', 0xc3cce6e2, 0xb6dfddeb},
{'q', 0xbfaaaaac, 0xc09d3168},
{0, 0xbfaaaaac, 0xc11e50d8},
{'q', 0x00000000, 0xc1274c58},
{0, 0x400b3a62, 0xc1a23ee0},
{'q', 0x400b3a64, 0xc11e50d8},
{0, 0x40ba62cf, 0xc18e08fc},
{'q', 0x40698b3c, 0xc0fb8240},
{0, 0x4108fb83, 0xc1674c58},
{'8', 0xa953cc27, 0xca59dd2b},
{'8', 0xed59ed2e, 0x094d002a},
{'8', 0xe511f004, 0xf41df50d},
{'8', 0x0825fd12, 0x23190b13},
{'8', 0x21061003, 0x20021002},
{'8', 0x1a010f01, 0x18000a00},
{'8', 0x11000e00, 0x31ef1800},
{'8', 0x1add18ef, 0xf6d603ec},
{'8', 0xdaebf2eb, 0xd002f800},
{'8', 0xf9f5ffff, 0xf7f2faf7},
{'8', 0xf9f3fdfc, 0xfaf0fcf8},
{'8', 0xfef0fef9, 0x17b400dd},
{'8', 0x41b217d8, 0x61bd2adb},
{'q', 0xc07286c0, 0x40dc11f8},
{0, 0xc0c35e50, 0x41794360},
{'q', 0xc00fb828, 0x410b3a64},
{0, 0xc00fb828, 0x418bca1a},
{'8', 0x62143300, 0x4e382f14},
{'8', 0x1e4f1e24, 0xf9480025},
{'8', 0xec3ff923, 0xe830f41c},
{'8', 0xe625f414, 0xf119f60e},
{'8', 0xfb18fb0b, 0x0718000c},
{'q', 0x40a86bc0, 0x40800000},
{0, 0xbf21af80, 0x412aaaab},
{'@', 0x00000044, 0x00004e50},/* D x-advance: 78.312500 */
{'M', 0x42355555, 0x408fb824},
{'q', 0xc0e50d78, 0x3d8fb840},
{0, 0xc1608fb6, 0xbf0fb824},
{'8', 0xf4a9fbca, 0xf4c8f9e0},
{'8', 0xfae4fae8, 0xf1da00e9},
{'q', 0xbfe98b38, 0xbffb823f},
{0, 0xbfc59d30, 0xc0af286c},
{'q', 0x3efb8240, 0xc0dc11f7},
{0, 0x3e8fb828, 0xc1c3ee09},
{'q', 0xbe0fb830, 0xc18ce98c},
{0, 0xbf579438, 0xc2186bca},
{'8', 0xacffc0ff, 0xc101ec00},
{'8', 0xcd02d602, 0xd210e201},
{'8', 0xf127f110, 0x0225000f},
{'8', 0x093b0217, 0x134a0725},
{'8', 0x21510b26, 0x3253152c},
{'8', 0x474c1c27, 0x5e402a25},
{'q', 0x40579440, 0x40cc59d8},
{0, 0x40aaaab0, 0x4173a630},
{'q', 0x40023ee0, 0x410d7944},
{0, 0x40023ee0, 0x419823ee},
{'8', 0x51f52700, 0x50df29f6},
{'8', 0x46cc27eb, 0x31b91ee3},
{'9', 0x0012ffd7, 0x0012ffa8},
{'m', 0xc1e23ee0, 0xc259d316},
{'q', 0x3e579480, 0x40c7dc10},
{0, 0x3efb8240, 0x41955555},
{'q', 0x3eb3a640, 0x41459d32},
{0, 0x3f21af20, 0x41955556},
{'q', 0x40bca1b0, 0x40262ce8},
{0, 0x41459d32, 0x406e08f8},
{'q', 0x40ce98b4, 0x3f86bca4},
{0, 0x416aaaaa, 0x3f86bca4},
{'8', 0xeb3c0020, 0xc92feb1c},
{'8', 0xb61dde12, 0xb10bd80b},
{'q', 0x00000000, 0xc1d823ee},
{0, 0xc1b0d794, 0xc2250d79},
{'9', 0xffd9ffc2, 0xffadff4c},
{'0', 0x00000000, 0x00000000},
{'0', 0x00000000, 0x00000000},
{'0', 0x00000000, 0x00000000},
{'0', 0x00000000, 0x00ff0000},
{'0', 0x00000000, 0x00000000},
{'0', 0x00000000, 0x00000000},
{'0', 0x00000000, 0x00000000},
{'q', 0xbefb8240, 0x4195e510},
{0, 0x3e0fb800, 0x421ce98c},
{'@', 0x00000045, 0x00004e50},/* E x-advance: 78.312500 */
{'M', 0x4285c120, 0x3f698b3a},
{'q', 0xc021af40, 0xbe579434},
{0, 0xc148fb88, 0x3ed79438},
{'q', 0xc11f7048, 0x3f21af28},
{0, 0xc1ae98b2, 0x3f98b3a5},
{'q', 0xc13dc122, 0x3f0fb828},
{0, 0xc19435e6, 0x3d8fb840},
{'8', 0xe6cbffe6, 0xc5e2e8e7},
{'q', 0xbefb8240, 0xc06e08fc},
{0, 0xbefb8240, 0xc1579435},
{'q', 0x3d8fb840, 0xc11c11f8},
{0, 0x3e579440, 0xc1a50d79},
{'q', 0x3e0fb820, 0xc12f286c},
{0, 0xbe8fb828, 0xc1c50d7c},
{'8', 0xa5ffbbff, 0xbf01ea00},
{'8', 0xca02d502, 0xd210e201},
{'8', 0xf027f010, 0x132eff1e},
{'q', 0x41023ee2, 0xbf8fb840},
{0, 0x4198b3a6, 0xbfb3a640},
{'q', 0x413047dc, 0xbeb3a600},
{0, 0x419c11f8, 0xbd8fb800},
{'8', 0x076c0244, 0x0e25031b},
{'8', 0x1c0b0a0a, 0x13fe0a00},
{'8', 0x10fa08ff, 0x0cf107fb},
{'q', 0xbfa1af40, 0x3efb8200},
{0, 0xc0411f80, 0x3e8fb800},
{'q', 0xc158b3a4, 0xbf7b8200},
{0, 0xc1d9d316, 0xbf21af00},
{'q', 0xc15af286, 0x3eb3a600},
{0, 0xc1bc11f7, 0x3fe08fc0},
{'q', 0xbf21af20, 0x417047d8},
{0, 0xbf21af20, 0x41eaaaaa},
{'q', 0x41286bca, 0xbd8fb800},
{0, 0x41e50d7a, 0xbf8fb820},
{'q', 0x4191674c, 0xbf86bca0},
{0, 0x41a35e50, 0xbf86bca0},
{'8', 0x0b25001a, 0x1f0b0b0a},
{'q', 0x00000000, 0x40ca1af0},
{0, 0xc0c35e50, 0x40ca1af0},
{'q', 0xc0262cf0, 0x00000000},
{0, 0xc1b1674c, 0x3fb3a640},
{'q', 0xc19ca1af, 0x3fb3a620},
{0, 0xc1d5e50e, 0x3fbca1a0},
{'8', 0x42011900, 0x45002800},
{'8', 0x3c011d00, 0x33021e01},
{'q', 0x3e8fb800, 0x4021af28},
{0, 0x3f33a620, 0x40650d7c},
{'q', 0x406e08f8, 0x3f86bca0},
{0, 0x41b31675, 0x3e8fb820},
{'q', 0x4195e50e, 0xbf459d30},
{0, 0x41c08fba, 0xbfe98b40},
{'8', 0xfe1cfe10, 0x0414000b},
{'8', 0x080d0408, 0x0b070405},
{'8', 0x0c040703, 0x0c010501},
{'8', 0x27f11500, 0x0ed411f2},
{'@', 0x00000046, 0x00004e50},/* F x-advance: 78.312500 */
{'M', 0x419286bd, 0xc0608fb8},
{'8', 0x27e918fe, 0x0dd40eec},
{'8', 0xf1da00e9, 0xd5f4f1f2},
{'q', 0x3efb8240, 0xc0ca1af2},
{0, 0x3e8fb828, 0xc1c1af28},
{'q', 0xbe0fb830, 0xc18f286c},
{0, 0xbf579438, 0xc2135e52},
{'8', 0x99feb3fe, 0xba01e600},
{'8', 0xc302d402, 0xd210e201},
{'8', 0xf127f110, 0x132ffe1f},
{'q', 0x4161af28, 0xbf86bcc0},
{0, 0x41e35e51, 0xbfa1af40},
{'q', 0x41662ce8, 0xbe579400},
{0, 0x41bca1ae, 0x3f21af00},
{'8', 0x0d25021a, 0x1d0b0a0a},
{'8', 0x25f41500, 0x0ed80ff4},
{'q', 0xc1b9435e, 0xbf8fb800},
{0, 0xc2486bca, 0x3f86bcc0},
{'8', 0x3efe1300, 0x57fe2bff},
{'q', 0xbd8fb800, 0x40b16750},
{0, 0x00000000, 0x4134c5a0},
{'q', 0x40f286bc, 0xbf698b40},
{0, 0x4187dc12, 0xbf33a640},
{'q', 0x41179434, 0x3e579500},
{0, 0x41886bca, 0x3f579440},
{'8', 0x0b60053c, 0x0f26051c},
{'8', 0x1c0b0a0a, 0x13fe0a00},
{'8', 0x10f908fe, 0x0bf107fb},
{'8', 0x02e803f6, 0xf79efbdd},
{'q', 0xc0f94360, 0xbf0fb800},
{0, 0xc18c59d4, 0xbf0fb800},
{'q', 0xc11c11f6, 0xbd8fb800},
{0, 0xc1811f70, 0x3f579400},
{'q', 0x3f8fb820, 0x42186bcb},
{0, 0x3fa1af30, 0x4227dc12},
{'@', 0x00000047, 0x00004e50},/* G x-advance: 78.312500 */
{'M', 0x42921af3, 0xc20c59d3},
{'8', 0x38f218fe, 0x43e220f5},
{'8', 0x46d223ee, 0x3dc522e5},
{'8', 0x2cb91be1, 0x0fae10d8},
{'8', 0xf1a800d1, 0xd5b9f0d7},
{'8', 0xc3cce6e2, 0xb6dfddeb},
{'q', 0xbfaaaaac, 0xc09d3168},
{0, 0xbfaaaaac, 0xc11e50d8},
{'q', 0x00000000, 0xc12aaaac},
{0, 0x400b3a62, 0xc1a59d32},
{'q', 0x400b3a64, 0xc121af28},
{0, 0x40ba62cf, 0xc190d792},
{'q', 0x40698b3c, 0xc1011f70},
{0, 0x4108fb83, 0xc16ce990},
{'8', 0xa753cb27, 0xc959dd2b},
{'8', 0xed59ed2e, 0x166b002f},
{'8', 0x264c163c, 0x410c1919},
{'8', 0x15eb0efc, 0x00de06f0},
{'8', 0xefe0fef9, 0xe6cdf1e7},
{'8', 0xf5d1f5e7, 0x18b400dd},
{'8', 0x43b217d8, 0x64bd2bdb},
{'q', 0xc07286c0, 0x40e08fb8},
{0, 0xc0c35e50, 0x417ee08c},
{'q', 0xc00fb828, 0x410e98b4},
{0, 0xc00fb828, 0x418fb824},
{'8', 0x62143300, 0x4e382f14},
{'8', 0x1e4f1e24, 0xef38001c},
{'8', 0xd333ef1c, 0xc22ce417},
{'8', 0xbe22de14, 0xc415e00e},
{'q', 0xc110d794, 0x3ed79400},
{0, 0xc18d7944, 0x3fce98c0},
{'8', 0x18a009bb, 0x00db0aed},
{'8', 0xe1ecf5ef, 0xbd2cd5fa},
{'q', 0x40823edc, 0xc0023ee0},
{0, 0x418bca1b, 0xc04a1af0},
{'q', 0x41579434, 0xbf8fb820},
{0, 0x41aa1af2, 0xbf33a640},
{'8', 0x0a27011c, 0x1a0e080b},
{'8', 0x34e82a05, 0x13fe0300},
{'q', 0xbe579400, 0x3fe98b40},
{0, 0xbe8fb800, 0x403ca1b0},
{'@', 0x00000048, 0x00004e50},/* H x-advance: 78.312500 */
{'M', 0x429023ee, 0xc0608fb8},
{'8', 0x27ea18fe, 0x0dd40eec},
{'8', 0xf1da00e9, 0xd5f4f1f2},
{'q', 0x3fb3a640, 0xc19f7048},
{0, 0x3fa1af40, 0xc233a62d},
{'q', 0xc018b3b0, 0x3e0fb800},
{0, 0xc18ce98c, 0x401435e0},
{'q', 0xc17286bc, 0x4006bca0},
{0, 0xc1ace98b, 0x4006bca0},
{'8', 0x0c000300, 0x0b000700},
{'q', 0xbf579440, 0x4163ee0a},
{0, 0x00000000, 0x4219435e},
{'8', 0x27e918fe, 0x0dd40eec},
{'8', 0xf1db00ea, 0xd5f4f1f1},
{'8', 0xcd01f001, 0xa000dd00},
{'8', 0x9401c400, 0x9102da00},
{'8', 0x9402b802, 0x9800dd00},
{'8', 0xbeffcdff, 0xd901f200},
{'8', 0xda01e701, 0xd210e201},
{'8', 0xf127f110, 0x0d2aff19},
{'8', 0x2d100e10, 0x31fd0b00},
{'8', 0x46fe25fe, 0x5a011d00},
{'q', 0x3e0fb800, 0x40f4c5a8},
{0, 0x3e0fb800, 0x413b8244},
{'q', 0x40f047dc, 0xbd8fb800},
{0, 0x4177047e, 0xbf579440},
{'q', 0x40fdc120, 0xbf579440},
{0, 0x41662cec, 0xbfe08fc0},
{'8', 0xf847f933, 0xe9fff900},
{'8', 0xe800f000, 0xa2ffb9ff},
{'8', 0xb901e900, 0xc602d001},
{'8', 0xd210e200, 0xf127f110},
{'8', 0x0d2aff19, 0x2d100e10},
{'q', 0x00000000, 0x402f2880},
{0, 0xbe579600, 0x4133a630},
{'q', 0xbe0fb800, 0x4106bca0},
{0, 0xbe579400, 0x416e08f8},
{'q', 0x00000000, 0x40cc59d8},
{0, 0x3e579400, 0x4193a62e},
{'q', 0x3e8fb900, 0x41208fb8},
{0, 0xbe8fb800, 0x41d31675},
{'q', 0xbf0fb800, 0x4182ce99},
{0, 0xbefb8200, 0x41a6bca2},
{'@', 0x00000049, 0x00004e50},/* I x-advance: 78.312500 */
{'M', 0x4289af28, 0x3fc59d32},
{'q', 0xc07286a0, 0xbf0fb825},
{0, 0xc1435e4c, 0xbf0fb825},
{'q', 0xc106bca4, 0xbd8fb828},
{0, 0xc1847dc2, 0x3e579434},
{'q', 0xc1011f70, 0x3e579438},
{0, 0xc1898b3a, 0x3efb8240},
{'8', 0x029c02b8, 0xf5d400e3},
{'8', 0xe2f2f5f2, 0xde0cecff},
{'q', 0x3fe08fb8, 0xbfe98b38},
{0, 0x40af286c, 0xc0023ee0},
{'q', 0x40c35e50, 0xbe8fb820},
{0, 0x41aa1af3, 0xbf21af30},
{'q', 0x3fc59d30, 0xc1c47dc2},
{0, 0x3f459d20, 0xc25047dc},
{'8', 0xb2fed8ff, 0xcc00db00},
{'8', 0xcf02f100, 0xd902de02},
{'q', 0xc151f704, 0xbe8fb800},
{0, 0xc1a74c59, 0x00000000},
{'8', 0xf4d500e4, 0xdff1f3f1},
{'8', 0xde0decff, 0xf12cf10e},
{'q', 0x42100000, 0xbf86bcc0},
{0, 0x4263a62d, 0x3f86bcc0},
{'8', 0x2e340432, 0x14fd0a00},
{'8', 0x13f80afe, 0x0eef08fa},
{'q', 0xbfb3a640, 0x3f0fb800},
{0, 0xc04e98c0, 0x3e579400},
{'q', 0xc088fb80, 0xbf33a600},
{0, 0xc1a86bca, 0xbfc59d40},
{'8', 0x33ff0800, 0x43ff2aff},
{'8', 0x47001800, 0x5d012f00},
{'q', 0x3e8fb800, 0x4122ce98},
{0, 0xbe8fb880, 0x41cb3a63},
{'q', 0xbefb8200, 0x417286bd},
{0, 0xbefb8200, 0x4190d794},
{'q', 0x40c7dc10, 0x35800000},
{0, 0x41650d78, 0x3d8fb880},
{'8', 0x00450040, 0x0b25001a},
{'8', 0x1f0b0b0a, 0x13fe0a00},
{'8', 0x10fa08ff, 0x0cf108fb},
{'q', 0xbfa1af40, 0x3efb823c},
{0, 0xc0459d40, 0x3e579438},
{'@', 0x0000004a, 0x00004e50},/* J x-advance: 78.312500 */
{'M', 0x4259d317, 0xc1f7047e},
{'q', 0xbf8fb840, 0x414fb824},
{0, 0xc05c1200, 0x41a86bca},
{'8', 0x5bd440ef, 0x1bc11be6},
{'8', 0xf2b400d9, 0xdcbff2db},
{'8', 0xcfcce9e4, 0xcbd8e6e8},
{'8', 0xd0e7e6f1, 0xdef6ebf8},
{'8', 0xe8fff6fe, 0xe605f201},
{'8', 0xea0ef403, 0xf41cf60a},
{'8', 0x0a28fc19, 0x240f0e0f},
{'8', 0x1e030c00, 0x280f1104},
{'8', 0x2a1b170b, 0x202c1310},
{'q', 0x40650d78, 0x3fce98b8},
{0, 0x40fdc120, 0x3fce98b8},
{'q', 0x40a3ee08, 0x00000000},
{0, 0x40bca1b0, 0xc1c74c5b},
{'q', 0x3d8fb800, 0xc04a1af0},
{0, 0xbe8fb880, 0xc1a1af28},
{'q', 0xbe8fb800, 0xc188fb82},
{0, 0xbd8fb800, 0xc20bca1b},
{'q', 0xc1808fb7, 0xbefb8200},
{0, 0xc1e35e50, 0xbe0fb800},
{'8', 0xf4d500e4, 0xdff1f3f1},
{'8', 0xde0decff, 0xf12cf10e},
{'q', 0x42100000, 0xbf86bcc0},
{0, 0x42635e51, 0x3f86bcc0},
{'8', 0x2e350432, 0x14fd0a00},
{'8', 0x13f80afe, 0x0eef08fa},
{'q', 0xbfb3a600, 0x3f0fb800},
{0, 0xc04e98a0, 0x3e579400},
{'q', 0xc09f7050, 0xbf459d00},
{0, 0xc17823f0, 0xbfa1af40},
{'q', 0x00000000, 0x4086bca0},
{0, 0x3e8fb800, 0x414a1af8},
{'q', 0x3eb3a680, 0x4106bca0},
{0, 0x3f0fb840, 0x4175e50c},
{'q', 0x3e8fb800, 0x40de50d8},
{0, 0x3e579400, 0x417823ec},
{'q', 0x00000000, 0x4108fb84},
{0, 0xbed79400, 0x416ce98c},
{'@', 0x0000004b, 0x00004e50},/* K x-advance: 78.312500 */
{'M', 0x419286bd, 0xc0608fb8},
{'8', 0x27e918fe, 0x0dd40eec},
{'8', 0xf1da00e9, 0xd5f4f1f2},
{'q', 0x3efb8240, 0xc0ca1af2},
{0, 0x3e8fb828, 0xc1c1af28},
{'q', 0xbe0fb830, 0xc18f286c},
{0, 0xbf579438, 0xc2135e52},
{'8', 0x9dfeb7fe, 0xb502e600},
{'8', 0xc302cf02, 0xd210e201},
{'8', 0xf127f110, 0x0d2aff19},
{'q', 0x4006bca0, 0x3fe08fc0},
{0, 0x4006bca0, 0x40b5e510},
{'q', 0x00000000, 0x405c1200},
{0, 0xbeb3a600, 0x41716750},
{'q', 0xbeb3a640, 0x413a62d0},
{0, 0xbed79440, 0x419a62ce},
{'q', 0x40a62ce8, 0xc09f7048},
{0, 0x417a62d0, 0xc173a62c},
{'q', 0x41274c58, 0xc123ee08},
{0, 0x41847dc0, 0xc1811f70},
{'8', 0xc43fd131, 0xec1ef10f},
{'8', 0xff19fb0f, 0x0c14020b},
{'q', 0x406e0900, 0x40800000},
{0, 0xbfa1af00, 0x411f7048},
{'q', 0xc00b3a70, 0x40262d00},
{0, 0xc173a630, 0x417ca1b0},
{'q', 0xc150d794, 0x41531678},
{0, 0xc1b9435e, 0x41b79438},
{'q', 0x409af288, 0x40a3ee08},
{0, 0x41847dc2, 0x41811f70},
{'q', 0x413b823c, 0x412f286c},
{0, 0x41a23ee0, 0x419a62ce},
{'8', 0x544c4245, 0x26001506},
{'8', 0x1aec11fa, 0xedb41ada},
{'q', 0xbfbca1a0, 0xbfe98b3a},
{0, 0xc1250d78, 0xc11d3168},
{'q', 0xc10c59d4, 0xc1011f70},
{0, 0xc19823ee, 0xc18e08fc},
{'9', 0xffb2ffaf, 0xff85ff89},
{'l', 0x00000000, 0x403823f0},
{'q', 0x3d8fb800, 0x401435e0},
{0, 0x3fa1af30, 0x42150d7a},
{'@', 0x0000004c, 0x00004e50},/* L x-advance: 78.312500 */
{'M', 0x42891f70, 0xbfb3a62d},
{'q', 0xc11d3164, 0x3ff286bd},
{0, 0xc1ed7942, 0x402f286c},
{'q', 0xc19e50d8, 0x3f579436},
{0, 0xc1e86bca, 0x3f579436},
{'8', 0xf1da00e9, 0xd5f4f1f2},
{'q', 0x3d8fb820, 0xbf8fb824},
{0, 0x3fd79438, 0xc1835e50},
{'q', 0x3fce98b4, 0xc175e510},
{0, 0x401435e4, 0xc1ece98c},
{'q', 0x3ed79440, 0xc0ce98b8},
{0, 0x3e0fb820, 0xc1bd316a},
{'q', 0xbe8fb820, 0xc18a1af0},
{0, 0xbe8fb820, 0xc195e50c},
{'8', 0xd111e101, 0xf127f110},
{'8', 0x0d2aff19, 0x2d100e10},
{'q', 0x00000000, 0x40847dc0},
{0, 0xbe8fb840, 0x4135e510},
{'q', 0xbe579400, 0x40e50d70},
{0, 0xbf21af20, 0x4190d794},
{'q', 0xbeb3a640, 0x412f2868},
{0, 0xbf21af20, 0x41979434},
{'q', 0xbe579480, 0x40bee090},
{0, 0xbf8fb830, 0x418bca1b},
{'q', 0xbf579420, 0x413823f0},
{0, 0xbf579420, 0x418f286c},
{'q', 0x41423ee0, 0x3e0fb840},
{0, 0x41e08fb7, 0xbfb3a628},
{'q', 0x417ee090, 0xbfc59d30},
{0, 0x41aa1af4, 0xc03823ec},
{'8', 0x0118fd0d, 0x0d11030b},
{'8', 0x140a0906, 0x14040a03},
{'8', 0x21f61400, 0x11da0cf6},
{'@', 0x0000004d, 0x00004e50},/* M x-advance: 78.312500 */
{'M', 0x415674c6, 0xc106bca2},
{'8', 0x39f12401, 0x14d915f0},
{'8', 0xacd7ffd7, 0xd102f200},
{'8', 0xa908df03, 0xa208cb05},
{'q', 0x3e0fb820, 0xbfd79440},
{0, 0x3ed79430, 0xc0a86bc8},
{'q', 0x3f579438, 0xc12aaaac},
{0, 0x3faaaaac, 0xc1850d7a},
{'q', 0x3f0fb828, 0xc0bee090},
{0, 0x3fbca1b0, 0xc16ce988},
{'q', 0x3f698b40, 0xc10e98b8},
{0, 0x3fe98b38, 0xc1608fb8},
{'8', 0xc80fd707, 0xde23e90b},
{'8', 0xf72ef518, 0x2a3e0033},
{'q', 0x3fd79440, 0x40ca1af0},
{0, 0x406e0900, 0x41a74c58},
{'q', 0x40023ee0, 0x41698b3c},
{0, 0x4086bca0, 0x42055556},
{'q', 0x400b3a60, 0x4195e50e},
{0, 0x40411f70, 0x41c62cea},
{'q', 0x3fbca1c0, 0xc1a23ee0},
{0, 0x404e98b0, 0xc2123ee1},
{'q', 0x3fa1af40, 0xc1400000},
{0, 0x40608fc0, 0xc1c00000},
{'q', 0x400fb820, 0xc1400000},
{0, 0x40770480, 0xc193a62c},
{'8', 0xe513ef04, 0xf41ef60f},
{'8', 0xff1efe0f, 0x00040001},
{'8', 0x000f0009, 0x02100006},
{'8', 0x0610020a, 0x0e0c0406},
{'q', 0x3f459d00, 0x3f98b380},
{0, 0x3f86bc80, 0x403ca1a0},
{'q', 0x3f0fb800, 0x408b3a70},
{0, 0x40531680, 0x42286bcb},
{'q', 0x4033a620, 0x4217047e},
{0, 0x407b8240, 0x422af287},
{'8', 0x57e8450f, 0xfed508eb},
{'q', 0xc0262ce0, 0xbfb3a62d},
{0, 0xc0800000, 0xc0bca1af},
{'q', 0xc0411f60, 0xc119d317},
{0, 0xc0aaaaa8, 0xc2a7dc12},
{'q', 0xc0847dc0, 0x41a62cec},
{0, 0xc0ace988, 0x42174c5a},
{'q', 0xbfaaaaa0, 0x41835e52},
{0, 0xc0608fb0, 0x41f9d317},
{'q', 0xc00b3a70, 0x416bca1b},
{0, 0xc0650d80, 0x418fb824},
{'8', 0x1cc01cf4, 0xf9db01ea},
{'q', 0xbff286c0, 0xbf86bca2},
{0, 0xc018b3a0, 0xc03823ee},
{'q', 0xbfd79440, 0xc0de50d8},
{0, 0xc0b5e510, 0xc1fd3166},
{'q', 0xc07b8240, 0xc1c62cea},
{0, 0xc0e74c58, 0xc23e50d8},
{'8', 0x53f924fd, 0x50fa2efd},
{'8', 0x64fa21fe, 0x64fa42fc},
{'8', 0x63f92ffe, 0x51f933fc},
{'q', 0xbe8fb840, 0x40698b3c},
{0, 0xbe579440, 0x40aaaaaa},
{'@', 0x0000004e, 0x00004e50},/* N x-advance: 78.312500 */
{'M', 0x427fb824, 0x3ffb823f},
{'8', 0xf9dd01eb, 0xe9ecf8f2},
{'q', 0xbfaaaaa0, 0xc03823ef},
{0, 0xc0de50d8, 0xc14b3a63},
{'q', 0xc0b16748, 0xc11d3168},
{0, 0xc13823ec, 0xc1a2ce99},
{'q', 0xc0bee090, 0xc1286bc8},
{0, 0xc147dc14, 0xc1bca1b0},
{'q', 0xc0d0d794, 0xc151f704},
{0, 0xc11d3168, 0xc1b31672},
{'q', 0x3f579440, 0x417a62c8},
{0, 0x3f21af40, 0x41e98b38},
{'q', 0xbe579480, 0x4158b3a8},
{0, 0xbf33a640, 0x41dca1b0},
{'q', 0xbed79420, 0x415f7048},
{0, 0xbe579400, 0x4187dc12},
{'8', 0x35f22401, 0x10d911f0},
{'8', 0xede000e9, 0xc8f8edf8},
{'q', 0x00000000, 0xc033a630},
{0, 0x3ed79430, 0xc1b1f704},
{'q', 0x3ed79440, 0xc19c11f8},
{0, 0x3f0fb828, 0xc20823ee},
{'q', 0x3e579420, 0xc1686bc8},
{0, 0xbe579440, 0xc1de50d8},
{'8', 0xda05e9ff, 0xe813f007},
{'8', 0xf61af90c, 0xff1dfe0e},
{'q', 0x40c7dc12, 0x00000000},
{0, 0x40fb823e, 0x40a86bd0},
{'q', 0x40411f70, 0x41179438},
{0, 0x41850d79, 0x420bca1b},
{'q', 0x415af288, 0x41cbca1a},
{0, 0x41b94360, 0x42247dc1},
{'q', 0x3f0fb800, 0xc158b3a4},
{0, 0x3e8fb800, 0xc21d3167},
{'q', 0xbe8fb800, 0xc1ce08fe},
{0, 0xbfaaaac0, 0xc20823ef},
{'8', 0xd20ae5fd, 0xed25ed0e},
{'8', 0x0215000c, 0x060e0208},
{'8', 0x0d080305, 0x10050803},
{'q', 0x3e579400, 0x3f698b00},
{0, 0x3efb8200, 0x403823e0},
{'q', 0x3eb3a600, 0x401435e0},
{0, 0x3ed79400, 0x41b94360},
{'q', 0x3e0fb800, 0x41a62ce8},
{0, 0xbefb8200, 0x422c11f6},
{'q', 0xbf21af00, 0x41b1f706},
{0, 0xc006bca0, 0x41ce08fd},
{'q', 0xbfc59d40, 0x40608fb8},
{0, 0xc1000000, 0x40608fb8},
{'@', 0x0000004f, 0x00004e50},/* O x-advance: 78.312500 */
{'M', 0x420a62cf, 0x40608fb8},
{'q', 0xc10d7944, 0xbe0fb820},
{0, 0xc17dc120, 0xc0ace98b},
{'q', 0xc0e08fba, 0xc0a86bca},
{0, 0xc12ce98c, 0xc161af28},
{'q', 0xc07286be, 0xc10d7944},
{0, 0xc0698b3c, 0xc19af286},
{'8', 0xed00fa00, 0xae00cd00},
{'8', 0xad04e101, 0x9f0dcd03},
{'q', 0x3fa1af28, 0xc0ba62d0},
{0, 0x404e98b2, 0xc1316750},
{'q', 0x40698b3c, 0xc11674c8},
{0, 0x414b3a63, 0xc175e510},
{'q', 0x4110d794, 0xc0bee090},
{0, 0x41a3ee09, 0xc0bee090},
{'8', 0x1158002e, 0x334b112a},
{'q', 0x4086bca0, 0x40847dc0},
{0, 0x40de50d0, 0x41298b38},
{'q', 0x4033a640, 0x40ce98b0},
{0, 0x40608fc0, 0x41674c58},
{'q', 0x3f0fb800, 0x40e50d80},
{0, 0x3f21af00, 0x41770480},
{'q', 0x3e0fb800, 0x41035e50},
{0, 0xbefb8200, 0x41850d7a},
{'8', 0x6af243fc, 0x5ddc35f2},
{'8', 0x3fd026eb, 0x27c318e6},
{'8', 0x14b90ede, 0x05ad05dc},
{'m', 0x00000000, 0xc1423ee1},
{'8', 0xf93b001e, 0xe836f91c},
{'8', 0xd52ff01a, 0xc020e414},
{'q', 0x3f0fb800, 0xbfe98b40},
{0, 0x3f98b3a0, 0xc108fb84},
{'q', 0x3f21af40, 0xc0d9d318},
{0, 0x3f698b40, 0xc1811f70},
{'q', 0x3eb3a600, 0xc11674c4},
{0, 0xbed79400, 0xc19435e6},
{'q', 0xbf579440, 0xc1179430},
{0, 0xc0c59d38, 0xc17ca1b0},
{'8', 0xcd99cdd6, 0x2d9900c2},
{'q', 0xc0a62cec, 0x40b5e510},
{0, 0xc0f286bc, 0x417dc120},
{'q', 0xc04e98b8, 0x4159d318},
{0, 0xc01d3168, 0x42011f70},
{'8', 0x43052401, 0x3e0e1f04},
{'8', 0x34181e0a, 0x2323150e},
{'q', 0x4033a628, 0x3fd79430},
{0, 0x40ca1af4, 0x3fd79430},
{'@', 0x00000050, 0x00004e50},/* P x-advance: 78.312500 */
{'M', 0x41a86bca, 0xc0608fb8},
{'8', 0x25ed1801, 0x0cd30dec},
{'8', 0xf2d900e8, 0xd7f4f2f1},
{'8', 0xc901ee01, 0xa700dc00},
{'q', 0xbd8fb800, 0xc0d55554},
{0, 0xbe579420, 0xc14e98b2},
{'q', 0xbe0fb840, 0xc0ca1af8},
{0, 0xbeb3a630, 0xc174c5a0},
{'q', 0xbe579440, 0xc110d794},
{0, 0xbe8fb830, 0xc171674c},
{'q', 0xbe579420, 0xc11674c8},
{0, 0x3e0fb840, 0xc1c62ce8},
{'8', 0xfafafafa, 0xe4faf2f8},
{'8', 0xe70cf202, 0xf215f50a},
{'q', 0x40a62cea, 0xbf98b3c0},
{0, 0x4173a62d, 0xbff286c0},
{'q', 0x41208fba, 0xbf33a600},
{0, 0x41608fba, 0xbf33a600},
{'q', 0x411d3164, 0x00000000},
{0, 0x418b3a62, 0x40608fc0},
{'q', 0x40f4c5a0, 0x405c11e0},
{0, 0x41423ee4, 0x41274c58},
{'q', 0x4091f700, 0x40de50d0},
{0, 0x409674c0, 0x41850d78},
{'q', 0x00000000, 0x41000000},
{0, 0xc0262ce0, 0x4171674c},
{'8', 0x62c738ec, 0x41a729dc},
{'q', 0xc0d31678, 0x40411f70},
{0, 0xc1650d78, 0x40411f70},
{'q', 0xc133a62e, 0x00000000},
{0, 0xc18d7944, 0xbfc59d40},
{'8', 0x5c053002, 0x5b072b03},
{'9', 0x002f0003, 0x00400005},
{'m', 0x4183ee0a, 0xc2ae08fb},
{'q', 0xc09f7048, 0x00000000},
{0, 0xc191674d, 0x3f98b380},
{'q', 0xbd8fb800, 0x40382400},
{0, 0xbeb3a640, 0x41298b40},
{'q', 0xbe579400, 0x40f70470},
{0, 0xbeb3a640, 0x417ee08c},
{'q', 0xbe0fb800, 0x41023ee0},
{0, 0xbd8fb800, 0x417ee090},
{'8', 0x106d102e, 0xfb3c0021},
{'8', 0xf42ffb1b, 0xeb23f814},
{'8', 0xe61af310, 0xe211f40a},
{'8', 0xe00bef07, 0xdf06f203},
{'8', 0xe102ed02, 0xe300f400},
{'8', 0xc6f5e000, 0xd8e3e7f5},
{'8', 0xe7d8f1ef, 0xf2d4f6e9},
{'q', 0xc02aaab0, 0xbefb8200},
{0, 0xc0a62ce8, 0xbefb8200},
{'@', 0x00000051, 0x00004e50},/* Q x-advance: 78.312500 */
{'M', 0x4290d794, 0x41ec59d3},
{'8', 0x05d90bef, 0xe7dbfbeb},
{'q', 0xc0023ee0, 0xc0262ce8},
{0, 0xc0dc11f8, 0xc119d316},
{'q', 0xc098b3a8, 0xc0e2ce98},
{0, 0xc11674c4, 0xc1686bca},
{'8', 0x04be04e3, 0xf0a200cd},
{'8', 0xd4b5f0d5, 0xbccae3e1},
{'8', 0xacded9ea, 0xa0f2d2f5},
{'q', 0xbf86bca0, 0xc1df7048},
{0, 0x40b5e50e, 0xc2374c5b},
{'q', 0x406e08fc, 0xc1179430},
{0, 0x414b3a62, 0xc17b8240},
{'q', 0x4110d796, 0xc0c7dc10},
{0, 0x41a2ce99, 0xc0c7dc10},
{'8', 0x0f57002f, 0x2f4a0f28},
{'q', 0x4086bca8, 0x407b8240},
{0, 0x40e08fb8, 0x41286bd0},
{'q', 0x4033a640, 0x40d31670},
{0, 0x406e0900, 0x4174c598},
{'q', 0x3f86bcc0, 0x411f7048},
{0, 0x3f459d00, 0x41c23ee2},
{'q', 0xbe8fb800, 0x41650d78},
{0, 0xbff286c0, 0x41ae98b3},
{'q', 0xc0459d20, 0x417823ee},
{0, 0xc161af24, 0x41b0d794},
{'8', 0x43302117, 0x40312219},
{'8', 0x28201e18, 0x1b060c08},
{'8', 0x1bf60efe, 0x13f00cf9},
{'m', 0xc2586bca, 0xc28674c6},
{'q', 0x3efb8280, 0x41023ee2},
{0, 0x40459d38, 0x416bca1c},
{'8', 0x53383415, 0x1e4f1e23},
{'l', 0x3fbca1c0, 0x00000000},
{'8', 0xb0d9cde4, 0xa00bbde7},
{'8', 0xf715f80a, 0x0617ff0b},
{'q', 0x3fb3a620, 0x3f7b8240},
{0, 0x400fb820, 0x404e98b0},
{'q', 0x40262cf0, 0x40e50d7c},
{0, 0x40f047e0, 0x4179435f},
{'8', 0x9641df31, 0xbb07f003},
{'q', 0x3efb8200, 0xc0d31678},
{0, 0x3f21af00, 0xc1835e52},
{'q', 0x3e0fb900, 0xc11d3168},
{0, 0xbf698b00, 0xc195e50e},
{'q', 0xbf98b3c0, 0xc122ce98},
{0, 0xc0ca1af8, 0xc1811f70},
{'8', 0xd09ad0d8, 0x2c9800c2},
{'q', 0xc0a86bcc, 0x40b16750},
{0, 0xc0f286c0, 0x417a62d0},
{'q', 0xc0650d78, 0x416f286c},
{0, 0xc01435e0, 0x42023ee0},
{'@', 0x00000052, 0x00004e50},/* R x-advance: 78.312500 */
{'M', 0x41a35e51, 0xc0608fb8},
{'8', 0x25ed1801, 0x0cd20dec},
{'8', 0xf2d900e9, 0xd7f4f2f1},
{'q', 0x3f0fb820, 0xc0ee08fc},
{0, 0x3f21af28, 0xc14b3a63},
{'q', 0x3d8fb800, 0xc0aaaaac},
{0, 0xbe0fb820, 0xc1cf286c},
{'q', 0xbd8fb840, 0xc02f2870},
{0, 0x3e579420, 0xc13a62d0},
{'q', 0x3eb3a630, 0xc10fb824},
{0, 0x3d8fb840, 0xc187dc12},
{'8', 0x96fad9ff, 0xb0fbbdfb},
{'l', 0x00000000, 0xbf459d00},
{'8', 0xda0febff, 0xef29ef0e},
{'q', 0x4033a62c, 0x00000000},
{0, 0x408fb822, 0x3f98b380},
{'q', 0x413dc120, 0x3f0fb800},
{0, 0x41ace98b, 0x404a1b00},
{'q', 0x411d3168, 0x4021af20},
{0, 0x41823ee2, 0x40c7dc10},
{'8', 0x43571d33, 0x4b322523},
{'8', 0x4c0f260f, 0x35f91d00},
{'8', 0x29eb17f9, 0x20dd11f2},
{'8', 0x17d20eeb, 0x10c609e8},
{'8', 0x0bbe07df, 0x07b504df},
{'q', 0x41686bc8, 0x40f047d8},
{0, 0x41cc59d2, 0x418bca1a},
{'q', 0x41316750, 0x411e50d9},
{0, 0x41698b38, 0x4187dc12},
{'8', 0x26001406, 0x1aeb11fa},
{'8', 0x07db0cf0, 0xe5dafcec},
{'8', 0xc6cce8ee, 0xb2afdddf},
{'q', 0xc0bee090, 0xc0ace98c},
{0, 0xc159d318, 0xc1298b3c},
{'q', 0xc0f286b8, 0xc0a86bc8},
{0, 0xc16bca1a, 0xc106bca0},
{'q', 0x3ed79440, 0x41047dc0},
{0, 0x3fc59d30, 0x419d3167},
{'9', 0x005a0009, 0x0070000a},
{'m', 0xbf86bca0, 0xc2880000},
{'8', 0x21ff0c00, 0x25fe14ff},
{'8', 0x2efd10ff, 0x29fd1dfe},
{'8', 0x01480418, 0xfb4ffe2e},
{'8', 0xf941fe20, 0xf535fb20},
{'8', 0xef26f915, 0xe818f610},
{'8', 0xdf07f207, 0xc2e8e000},
{'8', 0xccc4e2e9, 0xd7afe9dd},
{'8', 0xe2a8edd2, 0xefb1f5d7},
{'q', 0x3e8fb800, 0x41286bc8},
{0, 0x3f21af20, 0x4190d794},
{'@', 0x00000053, 0x00004e50},/* S x-advance: 78.312500 */
{'M', 0x409d3167, 0xc118b3a6},
{'8', 0xcef6e2f2, 0xe318ed05},
{'8', 0xf915fa0d, 0xff11fe08},
{'8', 0x0813010a, 0x17140709},
{'8', 0x32381f14, 0x12531224},
{'8', 0xf939001b, 0xe93af91e},
{'8', 0xdc33f11c, 0xd024ec17},
{'8', 0xc60ee40e, 0xe2fef000},
{'8', 0xe2f8f2ff, 0xe3eff0fa},
{'8', 0xe6e2f3f6, 0xe9d3f3ed},
{'8', 0xeec0f6e6, 0xf2abf8da},
{'8', 0xebb6fcd8, 0xd7c9efdf},
{'8', 0xcce0e8ec, 0xcaf5e5f5},
{'8', 0xb50dda00, 0xbc28dc0d},
{'8', 0xc942e01c, 0xdb5de826},
{'q', 0x40d9d318, 0xbfe08fc0},
{0, 0x416aaaa8, 0xbfe08fc0},
{'8', 0x0554001e, 0x0c4a0535},
{'8', 0x191f0715, 0x25061109},
{'8', 0x15f70dff, 0x09ee07f9},
{'8', 0x00ec01f5, 0xfdecfff7},
{'8', 0xfefa00fe, 0xf9e0fbec},
{'8', 0xfbdafef5, 0xfec4fee6},
{'8', 0x0f9d00cc, 0x2eb40fd2},
{'8', 0x45e21ee2, 0x4b262c00},
{'q', 0x409d3168, 0x407286b0},
{0, 0x415c11f8, 0x4086bc98},
{'q', 0x41000000, 0x3ed79480},
{0, 0x4162ce98, 0x401d3170},
{'8', 0x27501031, 0x3731171e},
{'8', 0x3e1a1f13, 0x41071e07},
{'8', 0x63ef3400, 0x51cf2eef},
{'8', 0x3cb622e1, 0x26a419d6},
{'q', 0xc0c7dc10, 0x3fc59d30},
{0, 0xc14d7940, 0x3fc59d30},
{'q', 0xc121af2a, 0x00000000},
{0, 0xc18f286c, 0xc0800000},
{'q', 0xc0f94361, 0xc0800000},
{0, 0xc12bca1c, 0xc11af286},
{'@', 0x00000054, 0x00004e50},/* T x-advance: 78.312500 */
{'M', 0x42423ee1, 0xc098b3a6},
{'8', 0x27e918fe, 0x0dd40eec},
{'8', 0xf1da00e9, 0xd5f4f1f1},
{'q', 0x3efb8200, 0xc0d0d794},
{0, 0xbf21af40, 0xc22047dc},
{'q', 0xbf86bca0, 0xc20674c6},
{0, 0xbf698b40, 0xc22e50d8},
{'q', 0xc19674c5, 0xbf698b00},
{0, 0xc1ad7943, 0xbfaaaa80},
{'8', 0xd3c6f8c6, 0xda0eebff},
{'q', 0x3ff286bc, 0xc006bca0},
{0, 0x40af286c, 0xbfbca180},
{'q', 0x40fdc120, 0x3faaaa80},
{0, 0x42698b3a, 0x3fe98b40},
{'8', 0x0d27001b, 0x210d0d0c},
{'8', 0x27f21600, 0x0fd711f2},
{'q', 0xbf8fb800, 0xbd8fb800},
{0, 0xc1ae98b2, 0xbf459d00},
{'q', 0x3e579400, 0x41eaaaaa},
{0, 0x3fe98b40, 0x42a7dc12},
{'@', 0x00000055, 0x00004e50},/* U x-advance: 78.312500 */
{'M', 0x4298d794, 0xc2155555},
{'8', 0x61f334ff, 0x4ee22cf5},
{'8', 0x3cd621ef, 0x2ccc1ae8},
{'8', 0x1dc811e6, 0x10c70be3},
{'8', 0x05c905e4, 0xf8bd00df},
{'8', 0xe1baf8de, 0xc8c0e9dd},
{'q', 0xc05c11f4, 0xc088fb82},
{0, 0xc0ba62ce, 0xc13047dc},
{'q', 0xc01435e6, 0xc0d9d318},
{0, 0xc0262cea, 0xc174c59c},
{'q', 0xbf8fb824, 0xc22ee090},
{0, 0xbed79430, 0xc26dc120},
{'8', 0xd011e200, 0xef28ef11},
{'q', 0x40bee090, 0x00000000},
{0, 0x40bee090, 0x40ee0900},
{'q', 0x00000000, 0x4242ce98},
{0, 0x3f459d20, 0x426b823e},
{'8', 0x3c072001, 0x39121c06},
{'8', 0x311f1c0c, 0x212f1412},
{'q', 0x40650d70, 0x3fce98b0},
{0, 0x41011f70, 0x3fce98b0},
{'q', 0x41250d78, 0x00000000},
{0, 0x41859d32, 0xc0d9d316},
{'q', 0x40cc59d0, 0xc0dc11f6},
{0, 0x40e98b38, 0xc1a6bca2},
{'q', 0x3ed79400, 0xc0c35e50},
{0, 0x3f0fb840, 0xc173a62c},
{'q', 0x3e579400, 0xc1131674},
{0, 0x3e0fb800, 0xc1823ee0},
{'q', 0xbd8fb800, 0xc0e50d80},
{0, 0xbe0fb800, 0xc1716750},
{'8', 0xb500c100, 0xd603e700},
{'8', 0xe90cf003, 0xf810f908},
{'8', 0xfe14fe07, 0x11230015},
{'q', 0x3fe98b40, 0x4006bca0},
{0, 0x3ffb8240, 0x40ba62d0},
{'q', 0x3f8fb840, 0x41b3a62c},
{0, 0x00000000, 0x42631675},
{'@', 0x00000056, 0x00004e50},/* V x-advance: 78.312500 */
{'M', 0x423e98b4, 0xc077047e},
{'8', 0x2cc330f4, 0xd7be00cf},
{'q', 0xc0bee090, 0xc177047e},
{0, 0xc186bca2, 0xc23f286c},
{'q', 0xc12ce98a, 0xc201af28},
{0, 0xc1459d30, 0xc21dc11e},
{'8', 0xa918bbf1, 0x012af715},
{'8', 0x2f200b15, 0x4a160601},
{'q', 0x40262ce8, 0x41059d30},
{0, 0x40a1af28, 0x41835e50},
{'q', 0x4021af28, 0x41000000},
{0, 0x40b5e50c, 0x4190d794},
{'q', 0x404a1af0, 0x41208fb8},
{0, 0x40bee094, 0x4197047e},
{'q', 0x403823e0, 0x410d7944},
{0, 0x4098b3a0, 0x41650d7a},
{'q', 0x40af2870, 0xc17ee08e},
{0, 0x4174c5a0, 0xc2398b3a},
{'q', 0x411d3164, 0xc1f3a630},
{0, 0x411e50d4, 0xc1f4c5a0},
{'8', 0xd122dd0b, 0xfe2cf516},
{'8', 0x1115050c, 0x1d0b0b08},
{'q', 0x3e8fb800, 0x400b3a60},
{0, 0xbf7b8200, 0x409d3170},
{'q', 0xc04e98c0, 0x40ee08f0},
{0, 0xc16e08fc, 0x422435e4},
{'q', 0xc13a62d0, 0x420674c6},
{0, 0xc16ce98c, 0x42374c5a},
{'@', 0x00000057, 0x00004e50},/* W x-advance: 78.312500 */
{'M', 0x41f0d794, 0xc06e08fc},
{'8', 0x1ced11fc, 0x0ce20af1},
{'8', 0x01e202f1, 0x00fc00ff},
{'8', 0x00f100f7, 0xfef000fa},
{'8', 0xfaeffef6, 0xf2f4fbfa},
{'8', 0xe8f8f6fa, 0xb9f5ff00},
{'q', 0xbfbca1b4, 0xc10c59d2},
{0, 0xc00b3a64, 0xc17a62ce},
{'q', 0xbfd79438, 0xc183ee0a},
{0, 0xc0b5e50e, 0xc2774c5b},
{'8', 0xa721b8fb, 0xfd15fb09},
{'8', 0x0615010b, 0x1110040a},
{'q', 0x3f579430, 0x3fce98c0},
{0, 0x3f459d30, 0x40770480},
{'q', 0xbe579440, 0x41035e50},
{0, 0x409435e6, 0x4274c59d},
{'8', 0x6b0b2703, 0x52094307},
{'q', 0x3f0fb820, 0xc08b3a62},
{0, 0x40023ee0, 0xc1859d32},
{'q', 0x3fbca1b0, 0xc1459d30},
{0, 0x402aaaa8, 0xc1b1f704},
{'q', 0x3fa1af30, 0xc11f7048},
{0, 0x402f2870, 0xc1a98b3c},
{'q', 0x3fbca1b0, 0xc134c598},
{0, 0x402aaaa8, 0xc194c59c},
{'8', 0xb610c60a, 0xe440e40c},
{'8', 0x0725ff17, 0x1713080f},
{'8', 0x450b1305, 0x5f0c3007},
{'q', 0x3f459d40, 0x40ba62d0},
{0, 0x3ffb8240, 0x41847dc2},
{'q', 0x3fa1af40, 0x412bca18},
{0, 0x40023ee0, 0x4183ee08},
{'q', 0x3f7b8240, 0x4107dc14},
{0, 0x4088fb88, 0x41e11f71},
{'q', 0x401d3160, 0xc1a23ee1},
{0, 0x409435e0, 0xc258fb84},
{'q', 0x3f8fb840, 0xc188fb80},
{0, 0x3f698b80, 0xc1ae98b0},
{'8', 0xc60edbff, 0xec27eb10},
{'q', 0x40a86bd0, 0x3e0fb800},
{0, 0x40a86bd0, 0x41298b38},
{'q', 0x00000000, 0x40ee0900},
{0, 0xbfb3a640, 0x41b3a62c},
{'q', 0xbf98b3c0, 0x415f7048},
{0, 0xbfe08fc0, 0x41a11f72},
{'q', 0xbf0fb800, 0x40c59d30},
{0, 0xbfe98b40, 0x4191674c},
{'q', 0xbf98b380, 0x41400000},
{0, 0xc01435e0, 0x4193a62c},
{'8', 0x45ef33f8, 0x23dc18f5},
{'8', 0x08d20be8, 0xd6c200cd},
{'q', 0xc0608fb0, 0xc15af287},
{0, 0xc0b16748, 0xc212ce98},
{'q', 0xbf0fb840, 0xc0c7dc18},
{0, 0xbffb8240, 0xc1b047de},
{'q', 0xbfaaaaa0, 0xc17ca1ac},
{0, 0xc0023ee0, 0xc1ace98a},
{'q', 0xc00b3a60, 0x41b9435e},
{0, 0xc09f7048, 0x424047dc},
{'q', 0xc02f2870, 0x41c74c5a},
{0, 0xc09674c8, 0x42011f70},
{'@', 0x00000058, 0x00004e50},/* X x-advance: 78.312500 */
{'M', 0x41698b3a, 0x00000000},
{'8', 0x18e312f2, 0x01e505f1},
{'8', 0xf1e9fcf5, 0xadfee1df},
{'q', 0x3f8fb824, 0xbfe98b40},
{0, 0x413ee08f, 0xc19286bd},
{'9', 0xff7c0056, 0xff3e007a},
{'l', 0xc1c62cea, 0xc214c59e},
{'8', 0xaaffc8db, 0xf419f70b},
{'8', 0x0220fd0e, 0x1a220612},
{'q', 0x409435e8, 0x40c11f70},
{0, 0x41b4c59e, 0x420e98b4},
{'q', 0x41859d32, 0xc1efb824},
{0, 0x41a98b3a, 0xc2108fb8},
{'8', 0xe71cef0c, 0xfb1cf90f},
{'8', 0x0a18020d, 0x130f070a},
{'8', 0x1a030a05, 0x20f60fff},
{'q', 0xbf86bcc0, 0x3fe08fc0},
{0, 0xc13047e0, 0x418d7944},
{'q', 0xc11e50d8, 0x417ee094},
{0, 0xc1579434, 0x41b1674e},
{'8', 0x02fe0000, 0x03fe02ff},
{'q', 0x40608fc0, 0x40b16748},
{0, 0x414b3a64, 0x41a98b3a},
{'q', 0x411435e4, 0x4179435e},
{0, 0x41459d34, 0x419d3167},
{'8', 0x2313140e, 0x19030f05},
{'8', 0x13f70aff, 0x10e90bf6},
{'8', 0xffe004f4, 0xe5dafaed},
{'q', 0xc02f2870, 0xc03ca1af},
{0, 0xc0d55558, 0xc11435e5},
{'q', 0xc0770480, 0xc0cc59d4},
{0, 0xc1155554, 0xc1823ee1},
{'q', 0xc0af2870, 0xc11e50d6},
{0, 0xc0fb8240, 0xc15f7046},
{'q', 0xc09435e8, 0x40d55550},
{0, 0xc15e50d8, 0x41b55555},
{'q', 0xc11435e4, 0x41800000},
{0, 0xc1286bca, 0x418ce98b},
{'@', 0x00000059, 0x00004e50},/* Y x-advance: 78.312500 */
{'M', 0x41f0d794, 0x3fd79436},
{'8', 0x1ddf15f6, 0xf8d307ea},
{'8', 0xedeff8f5, 0xe6f9f5fa},
{'9', 0xfff1ffff, 0xffe10008},
{'l', 0x417047dc, 0xc1ee98b3},
{'8', 0x96c5d7eb, 0xa7cdbfdb},
{'8', 0xb2d3e5f1, 0xa9cfcee3},
{'8', 0xb8dfdbed, 0xd3f9e6f6},
{'8', 0xe20aed02, 0xef15f508},
{'8', 0xfb15fb0a, 0x0318ff0b},
{'8', 0x1117030c, 0x22110d0b},
{'8', 0x2e0f1606, 0x260f1709},
{'8', 0x2a150e06, 0x22111b0e},
{'8', 0x26160603, 0x21132013},
{'q', 0x409d3164, 0x4107dc10},
{0, 0x4107dc12, 0x41862cea},
{'q', 0x3efb8280, 0xbf698b40},
{0, 0x402f2870, 0xc0ba62d0},
{'q', 0x40023ee0, 0xc08fb828},
{0, 0x40e08fb8, 0xc1686bcc},
{'q', 0x409f7048, 0xc1208fb8},
{0, 0x40e98b38, 0xc17a62d0},
{'8', 0xd613f205, 0xd514e40e},
{'8', 0xe011ed07, 0xef15f40a},
{'8', 0xfb16fb0b, 0x0415000b},
{'8', 0x0c100408, 0x130c0707},
{'8', 0x1c050b05, 0x23f81000},
{'8', 0x2fe90efa, 0x35e720f0},
{'8', 0x55d618f6, 0x63ce3ce0},
{'8', 0x63d12aed, 0x5cd439e5},
{'q', 0xc006bcb0, 0x4088fb84},
{0, 0xc1047dc4, 0x41835e52},
{'q', 0xc0c35e50, 0x41423edf},
{0, 0xc1011f70, 0x417fffff},
{'@', 0x0000005a, 0x00004e50},/* Z x-advance: 78.312500 */
{'M', 0x42979436, 0xc0ace98b},
{'8', 0x26f41701, 0x0fd10ff3},
{'q', 0xbf7b8200, 0x00000000},
{0, 0xc158b3a4, 0xbe8fb822},
{'q', 0xc147dc14, 0xbeb3a62e},
{0, 0xc1b7047e, 0xbed79436},
{'q', 0xc1250d7a, 0xbe0fb824},
{0, 0xc1af286c, 0x3e579438},
{'8', 0xebdd00ec, 0xd4f2e9f2},
{'q', 0x00000000, 0xc05c11f8},
{0, 0x40bee090, 0xc162ce98},
{'q', 0x409435e4, 0xc1035e52},
{0, 0x41a74c5a, 0xc201674c},
{'q', 0x41823ee0, 0xc1c1af28},
{0, 0x41c50d78, 0xc20ca1b0},
{'q', 0xc0ebca18, 0x3e579400},
{0, 0xc1b7047e, 0x3ed79500},
{'q', 0xc177047c, 0x3e0fb800},
{0, 0xc1a3ee08, 0x3eb3a600},
{'8', 0xf3db01e7, 0xddf5f2f5},
{'8', 0xd913ebff, 0xee31ee14},
{'8', 0x06460019, 0x0649062d},
{'q', 0x40ca1af8, 0x3d8fb800},
{0, 0x414b3a64, 0xbe0fb800},
{'q', 0x40cc59d0, 0xbe8fb800},
{0, 0x41674c5c, 0xbf459d80},
{'8', 0xfb48fc40, 0x1021ff13},
{'8', 0x2a0f110e, 0x1bf20800},
{'8', 0x28dd11f2, 0x23e416ec},
{'q', 0xc08d7948, 0x40e50d80},
{0, 0xc15c11fc, 0x41a3ee0a},
{'q', 0xc11435e4, 0x41555558},
{0, 0xc18fb824, 0x41d31676},
{'q', 0xc10a1af2, 0x4150d792},
{0, 0xc15f7046, 0x41b9d316},
{'q', 0x41808fb7, 0xbf7b8240},
{0, 0x41ebca1b, 0xbf7b8240},
{'q', 0x41579434, 0xbd8fb880},
{0, 0x419ee08e, 0x3f579430},
{'8', 0x112c0620, 0x1d0d0b0c},
{'@', 0x0000005b, 0x00004e50},/* [ x-advance: 78.312500 */
{'M', 0x4274c59d, 0x41447dc1},
{'8', 0xfdb8fde2, 0x01b200d6},
{'8', 0x03ae01dd, 0x02b502d2},
{'8', 0xf5d400e3, 0xe2f2f5f2},
{'9', 0xfff60000, 0xffeb0003},
{'l', 0x00000000, 0xbfb3a62c},
{'q', 0x3f21af30, 0xc0ebca1b},
{0, 0x3f7b8230, 0xc1d674c6},
{'q', 0x3ed79440, 0xc19b823f},
{0, 0x00000000, 0xc21b3a62},
{'8', 0xaefedcff, 0xa100d200},
{'8', 0xab01cf00, 0xb001dc00},
{'9', 0xffd40001, 0xffcd0001},
{'l', 0x00000000, 0xbf698b00},
{'8', 0xebfbf7fb, 0xde0decff},
{'q', 0x3ff286c0, 0xbff286c0},
{0, 0x40b1674c, 0xbffb8240},
{'q', 0x4133a62e, 0xbeb3a600},
{0, 0x41a23ee1, 0xbe8fb800},
{'q', 0x4110d794, 0x00000000},
{0, 0x41850d7a, 0xbe579400},
{'8', 0x0d27001a, 0x210d0d0c},
{'8', 0x13fd0900, 0x13f80afe},
{'8', 0x0eef08fa, 0x02e704f5},
{'q', 0xc107dc10, 0xbf98b380},
{0, 0xc1eb3a62, 0xbf21af00},
{'q', 0x00000000, 0x40459d20},
{0, 0xbed79440, 0x41794360},
{'q', 0xbeb3a640, 0x4147dc10},
{0, 0xbefb8240, 0x41a6bca0},
{'q', 0xbe0fb880, 0x41047dc0},
{0, 0x00000000, 0x419ee090},
{'q', 0x3e8fb800, 0x4108fb84},
{0, 0x00000000, 0x41ee08fc},
{'q', 0xbe579480, 0x41a98b3a},
{0, 0xbe0fb880, 0x41cbca1b},
{'q', 0x410a1af2, 0x3e0fb810},
{0, 0x419c11f7, 0xbe8fb830},
{'8', 0xfd60fd57, 0x0b25001a},
{'8', 0x1e0b0b0a, 0x13fe0a00},
{'8', 0x11f908fe, 0x0bf107fb},
{'q', 0xbfa1af20, 0x3efb8240},
{0, 0xc0459d30, 0x3e579440},
{'@', 0x0000005c, 0x00004e50},/* \ x-advance: 78.312500 */
{'M', 0x42386bca, 0xc1cc59d3},
{'q', 0xc0698b30, 0xc0de50dc},
{0, 0xc1a7dc12, 0xc20e50d8},
{'q', 0xc18a1af2, 0xc1e59d30},
{0, 0xc1a7dc12, 0xc21047dc},
{'8', 0xcff9e3f3, 0xe01aeb05},
{'8', 0xfa1dfa0e, 0x091f000f},
{'q', 0x3ffb8238, 0x3f98b3c0},
{0, 0x40459d2c, 0x405c1200},
{'q', 0x41274c5a, 0x41a74c5c},
{0, 0x419ee090, 0x42159d32},
{'q', 0x416f286c, 0x41d674c4},
{0, 0x42100001, 0x42755555},
{'8', 0x3d0c1c10, 0x2aec20fe},
{'8', 0x00cf0dec, 0xd4d2f4e4},
{'q', 0xbfaaaaa0, 0xc01435e6},
{0, 0xc0d0d790, 0xc14e98b4},
{'q', 0xc0a3ee08, 0xc1298b3a},
{0, 0xc0f047e0, 0xc171674c},
{'@', 0x0000005d, 0x00004e50},/* ] x-advance: 78.312500 */
{'M', 0x428650d8, 0x40f047dc},
{'8', 0x1ef21300, 0x0bd40bf2},
{'8', 0xfeb400e3, 0xfdaffed2},
{'8', 0xffb3fedd, 0x03b800d6},
{'8', 0xffe802f2, 0xf5f1fdf6},
{'8', 0xeff9f8fb, 0xedfff8ff},
{'8', 0xe20bed01, 0xf525f50a},
{'q', 0x3f86bcb0, 0x00000000},
{0, 0x41400000, 0x3efb8240},
{'q', 0x412f286c, 0x3ed79438},
{0, 0x419c11f8, 0x3e8fb824},
{'q', 0x3d8fb800, 0xc088fb82},
{0, 0xbe579400, 0xc1cbca1b},
{'q', 0xbe579500, 0xc1a98b3a},
{0, 0x3d8fb800, 0xc1ee08fc},
{'q', 0x3e0fb800, 0xc1394360},
{0, 0x00000000, 0xc19ee090},
{'q', 0xbe0fb800, 0xc1059d30},
{0, 0xbefb8280, 0xc1a6bca0},
{'q', 0xbeb3a600, 0xc147dc18},
{0, 0xbed79400, 0xc1794360},
{'q', 0xc1a74c5a, 0xbf0fb800},
{0, 0xc1eaaaab, 0x3f21af00},
{'8', 0xfee702f2, 0xf2effbf5},
{'8', 0xedf7f8fa, 0xedfef6fe},
{'8', 0xdf0dec01, 0xf327f20c},
{'q', 0x40f047dc, 0x3e579400},
{0, 0x41859d32, 0x3e579400},
{'q', 0x41131674, 0xbd8fb800},
{0, 0x41a1af28, 0x3e8fb800},
{'8', 0x0f2c001d, 0x220d0e0e},
{'9', 0x000c0000, 0x0015fffb},
{'l', 0x00000000, 0x3f698b00},
{'8', 0x33010700, 0x50012c01},
{'8', 0x55012300, 0x5f003101},
{'q', 0xbd8fb800, 0x40b823f0},
{0, 0xbe579400, 0x41250d78},
{'q', 0xbefb8200, 0x419af286},
{0, 0xbe0fb800, 0x421b3a62},
{'9', 0x009b0003, 0x00d60008},
{'l', 0x00000000, 0x3fb3a628},
{'q', 0x3ed79500, 0x3fb3a630},
{0, 0x3ed79500, 0x402f286c},
{'@', 0x0000005e, 0x00004e50},/* ^ x-advance: 78.312500 */
{'M', 0x41850d79, 0xc2b91f70},
{'8', 0x0cf504fc, 0x26d91de6},
{'8', 0x01e408f4, 0xf4effcf7},
{'8', 0xecf1f8f8, 0xe4fbf4fa},
{'8', 0xe00ff002, 0xb93ce316},
{'q', 0x4098b3a6, 0xc0aaaab0},
{0, 0x41274c59, 0xc1400000},
{'q', 0x40b5e510, 0xc0d55560},
{0, 0x4135e50e, 0xc1662ce8},
{'8', 0xed1ef20a, 0x0027fb14},
{'8', 0x131b0513, 0x624b3a2b},
{'8', 0x3a312720, 0x35321210},
{'8', 0x413d2221, 0x1e0f0f0d},
{'8', 0x1cfb0f02, 0x15ef0cf9},
{'8', 0x0cec08f7, 0x00e208f1},
{'8', 0xd8d4f8f2, 0xf4f5f9f9},
{'8', 0x9ea3bcbd, 0xa2b8e2e7},
{'8', 0x46c92ae2, 0x29da1ce8},
{'8', 0x25d90df2, 0x33cf17e8},
{'@', 0x0000005f, 0x00004e50},/* _ x-advance: 78.312500 */
{'M', 0x4118b3a6, 0x400b3a63},
{'q', 0x417823ee, 0x3e579430},
{0, 0x41c62ce9, 0x3e579430},
{'q', 0x411435e8, 0xbd8fb820},
{0, 0x41a50d7a, 0xbe579430},
{'8', 0xff6fff5a, 0x0c25001a},
{'8', 0x210b0c0a, 0x31cf3100},
{'q', 0xc0531660, 0x00000000},
{0, 0xc1d435e4, 0x3e579440},
{'q', 0xc1b9435e, 0x3e0fb800},
{0, 0xc20286bc, 0x3e0fb800},
{'8', 0xcfcf00cf, 0xd130cffe},
{'@', 0x00000060, 0x00004e50},/* ` x-advance: 78.312500 */
{'M', 0x422c11f7, 0xc2b650d8},
{'8', 0xeedefefd, 0xe7d2f0e2},
{'8', 0xe7d8f7f1, 0xe4d7f1e8},
{'8', 0xe7ecf6f4, 0xe3faf1fa},
{'8', 0xe805f300, 0xea25ef0b},
{'8', 0x082ffb19, 0x19200303},
{'8', 0x2027161c, 0x1822090c},
{'8', 0x17270e16, 0x25250e19},
{'8', 0x2601170b, 0x13df10f6},
{'q', 0xc03823f0, 0x3ed79400},
{0, 0xc0ce98b8, 0xbfb3a640},
{'@', 0x00000061, 0x00004e50},/* a x-advance: 78.312500 */
{'M', 0x42879436, 0x40b5e50e},
{'8', 0xf7d602e8, 0xd1e5f5ef},
{'8', 0xddfaf5ff, 0xdafae7fd},
{'q', 0xc110d794, 0x4173a62d},
{0, 0xc1b94360, 0x4173a62d},
{'8', 0xf0b5ffd9, 0xd9c3f1dd},
{'8', 0xc8d4e7e7, 0xc0e3e1ed},
{'q', 0xbf98b3a8, 0xc086bca4},
{0, 0xbf98b3a8, 0xc1023ee2},
{'q', 0x00000000, 0xc0fdc120},
{0, 0x3f98b3a8, 0xc1698b38},
{'8', 0xa319cb09, 0xba28d910},
{'8', 0xcd33e118, 0xdf3dec1c},
{'8', 0xed43f321, 0xfa47fa22},
{'8', 0x1668003d, 0x4959152b},
{'q', 0xc021af20, 0x41931676},
{0, 0xc00fb820, 0x41f674c6},
{'q', 0x3e8fb800, 0x41459d32},
{0, 0x407b8240, 0x41e7dc12},
{'8', 0x33fa2308, 0x11d80ff2},
{'m', 0xc2386bca, 0xc2108fb8},
{'8', 0x3a061c00, 0x38121d06},
{'8', 0x2c211a0c, 0x112f1115},
{'8', 0xf137001c, 0xd830f11b},
{'8', 0xcb25e715, 0xc71ae410},
{'q', 0x00000000, 0xc15435e8},
{0, 0x3fc59d40, 0xc1dee090},
{'8', 0xe3d1ece7, 0xf8c7f8eb},
{'8', 0x07d500ec, 0x19d107ea},
{'8', 0x2ed412e7, 0x47e01aed},
{'q', 0xbfce98c0, 0x40b3a630},
{0, 0xbfce98c0, 0x4147dc12},
{'@', 0x00000062, 0x00004e50},/* b x-advance: 78.312500 */
{'M', 0x42953167, 0xc21e98b4},
{'q', 0x3e0fb800, 0x40fdc120},
{0, 0xbfc59d00, 0x416bca1c},
{'8', 0x5ddb36f3, 0x42c826e8},
{'8', 0x28bc1be0, 0x0db60ddc},
{'q', 0xc14e98b2, 0x00000000},
{0, 0xc1ae98b3, 0xc0d79436},
{'8', 0x26f01bfe, 0x0bde0af3},
{'q', 0xc0e2ce98, 0x3e8fb820},
{0, 0xc0e2ce98, 0xc0fb8240},
{'q', 0xbe0fb840, 0xc18d7943},
{0, 0xbd8fb880, 0xc24af286},
{'q', 0x3e0fb840, 0xc20435e6},
{0, 0x3f0fb830, 0xc2355556},
{'8', 0xd00cdd00, 0xf123f20d},
{'8', 0x0c2bfe1a, 0x33100e11},
{'q', 0x00000000, 0x3f98b380},
{0, 0xbe0fb880, 0x4150d790},
{'q', 0xbd8fb800, 0x413dc120},
{0, 0xbd8fb800, 0x41a74c5c},
{'q', 0x41179436, 0xc0ce98c0},
{0, 0x41b286be, 0xc0ce98c0},
{'q', 0x411674c4, 0x3e0fba00},
{0, 0x4182ce98, 0x409674d0},
{'q', 0x40de50d8, 0x4091f700},
{0, 0x41274c5c, 0x4147dc10},
{'9', 0x003e001c, 0x0090001a},
{'m', 0xc2059d31, 0xc1baf286},
{'q', 0xc1208fb8, 0xbed79480},
{0, 0xc199d316, 0x40f047d8},
{'q', 0x00000000, 0x4193a62e},
{0, 0xbe8fb840, 0x421c59d4},
{'8', 0x253c1a19, 0x0b510b22},
{'q', 0x41250d7c, 0x00000000},
{0, 0x417dc120, 0xc0f286be},
{'q', 0x40b3a630, 0xc0f4c59c},
{0, 0x40af2870, 0xc1a47dc2},
{'8', 0xa1edccff, 0xb9cbd5ef},
{'q', 0xc08d7948, 0xc0608fc0},
{0, 0xc1274c5c, 0xc06e0900},
{'@', 0x00000063, 0x00004e50},/* c x-advance: 78.312500 */
{'M', 0x428aaaab, 0xc264c59d},
{'8', 0x57dd4111, 0x05e904f4},
{'8', 0xfeeb00f6, 0xf2ecfdf6},
{'8', 0xe3f2f5f8, 0xeefbfbff},
{'8', 0xedfaf4fd, 0xf0fafafe},
{'8', 0xf1f7f6fc, 0xf5f4fbfb},
{'8', 0xf9eefbf9, 0xfee8fef6},
{'8', 0x07d600ec, 0x19d406eb},
{'8', 0x2dd611e9, 0x47df1aed},
{'q', 0xbfd79430, 0x40b16748},
{0, 0xc006bca0, 0x4147dc12},
{'q', 0xbf98b3a0, 0x41b1674c},
{0, 0x4183ee0a, 0x41b8b3a6},
{'8', 0xf165023d, 0xd930ef27},
{'8', 0xe211ed07, 0xf115f50a},
{'8', 0xfe15fd0b, 0x0515010a},
{'8', 0x53141533, 0x28e214f6},
{'8', 0x26cd13ec, 0x1cb111e1},
{'8', 0x0a980ad0, 0xea9affc8},
{'8', 0xc8b6ebd3, 0xb1d4dde4},
{'q', 0xbff286c0, 0xc0b1674e},
{0, 0xbfe08fbc, 0xc137047f},
{'q', 0x3e0fb820, 0xc11d3168},
{0, 0x4018b3a6, 0xc18fb824},
{'8', 0x9230bf11, 0xb446d31e},
{'8', 0xd257e128, 0xf161f12e},
{'8', 0x2c6d003d, 0x68402c30},
{'@', 0x00000064, 0x00004e50},/* d x-advance: 78.312500 */
{'M', 0x4289af28, 0x3fa1af28},
{'8', 0xf0cc06de, 0xbdebe9ef},
{'8', 0x21e612f4, 0x1cde0ef2},
{'8', 0x14d00dec, 0x07c407e5},
{'8', 0xf4b500da, 0xd9b9f4db},
{'8', 0xbfc6e5df, 0xa4d9dae7},
{'q', 0xbfe08fb8, 0xc0dc11f8},
{0, 0xbfce98b4, 0xc16ce98a},
{'q', 0xbe0fb820, 0xc119d318},
{0, 0x40698b3c, 0xc18aaaac},
{'q', 0x407286bc, 0xc0f70478},
{0, 0x412f286b, 0xc1435e4c},
{'q', 0x40e74c5c, 0xc091f710},
{0, 0x41850d79, 0xc09674d0},
{'q', 0x4150d794, 0x00000000},
{0, 0x41b1674c, 0x40c35e50},
{'q', 0x3e579500, 0xc1d4c59c},
{0, 0x3f698b40, 0xc208fb82},
{'8', 0xb93db905, 0x10250118},
{'q', 0x3fd79440, 0x3fe98b40},
{0, 0x3fb3a640, 0x40dc11f0},
{'q', 0xbefb8200, 0x4108fb80},
{0, 0xbf98b3c0, 0x41fdc120},
{'q', 0xbf33a600, 0x41b8b3a6},
{0, 0xbf33a600, 0x420c11f7},
{'q', 0x3e579400, 0x41011f70},
{0, 0x3f459d00, 0x4161af28},
{'8', 0x430a3005, 0x22071305},
{'8', 0x19010f03, 0x30cd26fb},
{'m', 0xc1e98b38, 0xc1400000},
{'8', 0xfd230013, 0xf91dfd10},
{'8', 0xf218fb0c, 0xf013f70b},
{'8', 0xec10f907, 0xed0cf408},
{'8', 0xec0cf904, 0xfb03fd02},
{'8', 0xdd00f400, 0xd500e900},
{'8', 0xda00ec00, 0xda00f400},
{'8', 0xda00e700, 0xb9bcd5e6},
{'8', 0xe6a8e4d7, 0x1cac02d0},
{'8', 0x42cb19dd, 0x58ee28ef},
{'q', 0xbe0fb800, 0x414d7944},
{0, 0x40a1af28, 0x41a08fb8},
{'q', 0x40a86bc8, 0x40e74c5a},
{0, 0x416bca1c, 0x40e50d7a},
{'@', 0x00000065, 0x00004e50},/* e x-advance: 78.312500 */
{'M', 0x428d3167, 0xc10a1af3},
{'8', 0x29db18ef, 0x20cf10ed},
{'8', 0x15b60ee3, 0x059b06d5},
{'q', 0xc1662cea, 0xbe579430},
{0, 0xc1b286bd, 0xc1250d7a},
{'q', 0xc0fdc120, 0xc121af28},
{0, 0xc0f4c59e, 0xc1de50d7},
{'q', 0x3e0fb820, 0xc119d318},
{0, 0x40411f70, 0xc18aaaac},
{'8', 0x9a3ec217, 0xc25cd827},
{'q', 0x40d55558, 0xc02f2880},
{0, 0x41674c5c, 0xc02f2880},
{'8', 0x134e0023, 0x384f132a},
{'8', 0x4f332425, 0x3ef11c06},
{'8', 0x33d421eb, 0x20cb0feb},
{'8', 0x21b610e0, 0x1bba10d8},
{'8', 0x1ab60be3, 0x13c90fd4},
{'8', 0x310c1c04, 0x28181508},
{'8', 0x1c26110f, 0x0b370a17},
{'8', 0xfa3d011e, 0xeb33f81e},
{'8', 0xe921f314, 0xf110f60c},
{'8', 0xe358c52c, 0x5906212f},
{'m', 0xc1e86bc8, 0xc25c11f7},
{'8', 0x06d900ed, 0x17d806ec},
{'8', 0x26dc0fec, 0x39e416f0},
{'q', 0xbfb3a630, 0x408b3a60},
{0, 0xbfd79440, 0x4119d318},
{'q', 0x41dc11f7, 0xc0d9d318},
{0, 0x420b8240, 0xc159d318},
{'8', 0xb8c9cce6, 0xecc0ece4},
{'@', 0x00000066, 0x00004e50},/* f x-advance: 78.312500 */
{'M', 0x426435e5, 0x401435e5},
{'q', 0xbe579400, 0x00000000},
{0, 0xc11c11f8, 0x3e0fb820},
{'q', 0xc1179434, 0x3e0fb830},
{0, 0xc18e98b3, 0x3d8fb820},
{'8', 0xfc95ffbe, 0xf0d400e2},
{'8', 0xdbf4f1f3, 0xdd0deb00},
{'8', 0xf32cf20d, 0x0125010c},
{'8', 0x01250019, 0xd9feec01},
{'8', 0xd4feedfe, 0xbffeeb00},
{'q', 0xbe8fb800, 0xc0af286c},
{0, 0xbf579420, 0xc1698b3a},
{'q', 0xbefb8240, 0xc111f704},
{0, 0xbf33a640, 0xc162ce98},
{'8', 0x01c801eb, 0xcfcf00cf},
{'9', 0xffcffffe, 0xffcf0030},
{'l', 0x40dc11f8, 0x00000000},
{'8', 0xcbffeeff, 0x9d11c900},
{'8', 0xb62fd411, 0xce46e21d},
{'8', 0xe358ec29, 0xf862f82e},
{'8', 0x0b270018, 0x210f0b0f},
{'8', 0x26f41700, 0x0fe20ff4},
{'q', 0xc14d7940, 0x00000000},
{0, 0xc1a47dc0, 0x40c11f70},
{'q', 0xc0f70480, 0x40c11f70},
{0, 0xc0f70480, 0x417ca1b0},
{'q', 0x00000000, 0x403ca1c0},
{0, 0x3e0fb800, 0x40a1af30},
{'q', 0x41b5e50e, 0xbe8fb900},
{0, 0x41cd7944, 0xbe8fb900},
{'8', 0x0b25001a, 0x1f0b0b0a},
{'8', 0x32cf3200, 0x01d500f4},
{'8', 0x02b200e2, 0x02b001d1},
{'q', 0x3e0fb800, 0x407286c0},
{0, 0x3f459d40, 0x41955556},
{'q', 0x3f21af00, 0x416ce98c},
{0, 0x3f698b40, 0x41b4c59e},
{'q', 0x3e579400, 0x40ce98b2},
{0, 0x3e8fb800, 0x40dc11f6},
{'q', 0x4147dc10, 0x3efb8240},
{0, 0x4194c59c, 0x3efb8240},
{'8', 0x0c2a001d, 0x200e0c0e},
{'8', 0x25f21500, 0x0fd40ff2},
{'@', 0x00000067, 0x00004e50},/* g x-advance: 78.312500 */
{'M', 0x428ba62d, 0x40bee090},
{'8', 0x68e739fb, 0x51cd2fec},
{'8', 0x38bb21e2, 0x22af17da},
{'8', 0x0aa70ad5, 0xf6b900dd},
{'8', 0xebc6f6dd, 0xfcf8ffff},
{'8', 0xfdf9fdfa, 0xfdfaffff},
{'8', 0xfcfbfdfc, 0xfcfcffff},
{'8', 0xfbfdfdfd, 0xfafefe00},
{'8', 0xf9fefdff, 0xf700fc00},
{'8', 0xdb0fea00, 0xf521f10f},
{'8', 0x0a180108, 0x10250810},
{'8', 0x07270714, 0xe86e003a},
{'8', 0xba56e834, 0x992ad322},
{'q', 0x3efb8280, 0xc0411f71},
{0, 0x3f459d40, 0xc1298b3a},
{'q', 0xc0e50d78, 0x411e50d7},
{0, 0xc1b823ee, 0x411e50d7},
{'q', 0xc161af28, 0xbe8fb820},
{0, 0xc1a47dc1, 0xc1179436},
{'q', 0xc0cc59d2, 0xc1131675},
{0, 0xc0cc59d2, 0xc1da62ce},
{'q', 0x3e0fb800, 0xc10a1af4},
{0, 0x4018b3a4, 0xc1794360},
{'8', 0xa330c812, 0xc247db1e},
{'8', 0xdd57e729, 0xf561f52e},
{'8', 0x0557003d, 0x1334051a},
{'8', 0x110f050a, 0x16030b04},
{'8', 0x13fb0b00, 0x03fe0100},
{'8', 0x03fe02ff, 0x2c1c071c},
{'q', 0x00000000, 0x3eb3a600},
{0, 0x3e0fba00, 0x41811f70},
{'q', 0x3e579400, 0x417b823e},
{0, 0xbd8fbc00, 0x41d55555},
{'9', 0x0057ffff, 0x009bfff9},
{'m', 0xc2400000, 0xc22b823f},
{'8', 0x460024ff, 0x3f082101},
{'8', 0x33151d08, 0x2224150d},
{'8', 0x0a350b17, 0xf53dff21},
{'8', 0xe72ef61c, 0xdd21f113},
{'8', 0xd815ec0e, 0xd80aec07},
{'q', 0x3d8fb800, 0xc086bca0},
{0, 0x3e0fb800, 0xc15af286},
{'q', 0x3d8fb800, 0xc118b3a8},
{0, 0x3e0fb800, 0xc1674c5c},
{'9', 0xfff20000, 0xffe60007},
{'l', 0xbf698b40, 0xbe0fb800},
{'8', 0xf091efc4, 0x08d101e8},
{'8', 0x15d106e9, 0x24d60fe9},
{'8', 0x35e115ee, 0x48f120f4},
{'@', 0x00000068, 0x00004e50},/* h x-advance: 78.312500 */
{'M', 0x428ebca2, 0xc0ba62cf},
{'8', 0x36ee2300, 0x11d613ef},
{'8', 0xeed8ffeb, 0xd4eeefee},
{'q', 0x00000000, 0xc0823ee1},
{0, 0x3e8fb800, 0xc17a62d0},
{'q', 0x3e8fb800, 0xc13a62ce},
{0, 0x3e579400, 0xc1979435},
{'q', 0xbe0fb800, 0xc11d3168},
{0, 0xc018b3a0, 0xc17047dc},
{'8', 0xd6ccd6ef, 0x0bc000de},
{'8', 0x1cd00be4, 0x27de10ed},
{'8', 0x2be915f1, 0x29f314f9},
{'8', 0x20fa14fb, 0x12ff0bff},
{'l', 0x00000000, 0xbe579400},
{'8', 0x16000600, 0x17000f00},
{'8', 0x37001500, 0x32002100},
{'8', 0x28ff1100, 0x2afd17ff},
{'8', 0x27e918fe, 0x0dd40eec},
{'8', 0xf1da00e9, 0xd5f4f1f2},
{'q', 0x3ed79440, 0xc0bca1b0},
{0, 0x3f86bca0, 0xc1a62cea},
{'q', 0x3f33a630, 0xc16e08fc},
{0, 0x3efb8240, 0xc1a35e52},
{'q', 0xbf86bca0, 0xc1c11f70},
{0, 0xbe8fb820, 0xc26435e4},
{'8', 0xd110e100, 0xf127f110},
{'8', 0x0d2aff19, 0x2d100e10},
{'q', 0x00000000, 0x41800000},
{0, 0x3e8fb840, 0x42323ee1},
{'8', 0xd61eea0c, 0xdb2ded12},
{'8', 0xe541ef1a, 0xf655f627},
{'8', 0x11410026, 0x302b111c},
{'8', 0x45161e0f, 0x53062607},
{'q', 0xbd8fb800, 0x410a1af4},
{0, 0x3f21af00, 0x41ae98b4},
{'q', 0x3f459d80, 0x41531675},
{0, 0x3f459d80, 0x419047dc},
{'@', 0x00000069, 0x00004e50},/* i x-advance: 78.312500 */
{'M', 0x42208fb8, 0xc2a023ee},
{'8', 0xe9bb03d6, 0xbee6e4e6},
{'8', 0xc41dde00, 0xe542e71d},
{'8', 0x1741ff28, 0x3e191919},
{'8', 0x3de72400, 0x1dbf18e8},
{'m', 0x41d823f0, 0x42a3823f},
{'q', 0xc01d3180, 0xb5a00000},
{0, 0xc1c74c5c, 0x3ed79410},
{'q', 0xc1b31674, 0x3eb3a628},
{0, 0xc1e98b3a, 0x3eb3a628},
{'8', 0xf2da00e5, 0xdbf7f1f6},
{'8', 0xde0aeb00, 0xf326f30a},
{'l', 0x41b286be, 0x00000000},
{'8', 0xa7ffcb00, 0xc7ffe3ff},
{'8', 0xbf00e400, 0xcc01db01},
{'8', 0xc002f100, 0xc802cf02},
{'8', 0x00bffef3, 0x00b201cd},
{'8', 0xf4df00eb, 0xe2f5f4f5},
{'8', 0xdd0aecff, 0xf122f10b},
{'q', 0x4158b3a6, 0xbf86bcc0},
{0, 0x41c23ee0, 0xbf459d00},
{'8', 0x071e0011, 0x1412070c},
{'8', 0x15070c05, 0x10020902},
{'q', 0xbf33a640, 0x4111f704},
{0, 0xbf579440, 0x41931674},
{'q', 0xbe0fb800, 0x41131674},
{0, 0x3d8fb800, 0x417ca1b0},
{'9', 0x00340001, 0x00900006},
{'l', 0x419047dc, 0x00000000},
{'8', 0x0c24001a, 0x210a0c0a},
{'q', 0xbe8fb800, 0x40bee090},
{0, 0xc0c59d30, 0x40bee090},
{'@', 0x0000006a, 0x00004e50},/* j x-advance: 78.312500 */
{'M', 0x4255e50e, 0xc29f047e},
{'8', 0xe3bd00d5, 0xbbe8e2e8},
{'8', 0xc91ade00, 0xea41ec1a},
{'8', 0x1741ff28, 0x3e191919},
{'8', 0x40e72500, 0x1abf1ae7},
{'m', 0xc0aaaab0, 0x42a2f287},
{'q', 0x00000000, 0xbf98b3a7},
{0, 0xbf0fb800, 0xc12f286c},
{'q', 0xbefb8280, 0xc11d3168},
{0, 0xbf33a640, 0xc19ee090},
{'q', 0xbe0fb800, 0xc121af28},
{0, 0x3efb8200, 0xc1e1af28},
{'8', 0x01c201f0, 0x009900d3},
{'8', 0x00ba00c7, 0xefd600e6},
{'8', 0xd9f1eff0, 0xe30ff000},
{'q', 0x3ffb8240, 0xbfce98c0},
{0, 0x40a3ee08, 0xbfd79440},
{'q', 0x409f7048, 0xbeb3a600},
{0, 0x418ce98b, 0xbf21af00},
{'q', 0x414b3a64, 0xbeb3a600},
{0, 0x41994360, 0xbe0fb800},
{'8', 0x071d0011, 0x1412070c},
{'8', 0x15070b05, 0x10020902},
{'8', 0x1ffb0bff, 0x20fd13fe},
{'q', 0xbe0fb800, 0x3fc59d20},
{0, 0xbe0fb800, 0x40608fb0},
{'q', 0x00000000, 0x40650d80},
{0, 0x3ed79400, 0x41bb8240},
{'q', 0x3efb8280, 0x419ee090},
{0, 0x3efb8280, 0x41f7047e},
{'8', 0x5af53000, 0x47e029f5},
{'8', 0x35cf1dec, 0x26c317e3},
{'8', 0x19ba0fe0, 0x0eb60adb},
{'8', 0x03b603dd, 0xf5d900e8},
{'8', 0xdff1f5f1, 0xd90fea00},
{'8', 0xef21ef0f, 0xf951002a},
{'8', 0xe94af927, 0xd83df023},
{'8', 0xc528e819, 0xb10fdd0f},
{'@', 0x0000006b, 0x00004e50},/* k x-advance: 78.312500 */
{'M', 0x41bee090, 0xc09435e5},
{'8', 0x32ed23ff, 0x0cd20eef},
{'8', 0xf1d9ffea, 0xd4f2f2f0},
{'q', 0x3f0fb820, 0xc0d0d794},
{0, 0x3f459d30, 0xc1a74c5a},
{'q', 0x3e579440, 0xc1674c5c},
{0, 0x3e579440, 0xc1d8b3a6},
{'q', 0x00000000, 0xc14b3a68},
{0, 0xbe0fb840, 0xc1ed7944},
{'q', 0xbd8fb800, 0xc1886bcc},
{0, 0xbd8fb800, 0xc1a98b3c},
{'8', 0xd511e300, 0xf22bf211},
{'8', 0x0e270017, 0x2a0f0d0f},
{'q', 0x00000000, 0x4194c5a0},
{0, 0xbf698b40, 0x426a1af3},
{'q', 0x41011f70, 0xc0e98b38},
{0, 0x41a1af29, 0xc18b3a62},
{'8', 0xa56baf61, 0xec1ef10f},
{'8', 0xff19fb0f, 0x0c14030b},
{'q', 0x406e0900, 0x40800000},
{0, 0xbfa1af00, 0x411f7048},
{'q', 0xc033a630, 0x40531680},
{0, 0xc1a59d32, 0x41979438},
{'q', 0x403823f0, 0x40a62ce8},
{0, 0x41250d78, 0x416f286c},
{'q', 0x40ee0900, 0x411af286},
{0, 0x41531674, 0x4188fb82},
{'8', 0x432e3a2e, 0x39e72703},
{'8', 0x0ae808f4, 0xfbe601f4},
{'8', 0xe8e7f9f3, 0xd1dbf8fa},
{'8', 0xb3c2dae1, 0xa9c1dae2},
{'9', 0xffd0ffe0, 0xffafffd2},
{'l', 0xc13b823e, 0x4123ee08},
{'8', 0x01fe01ff, 0x65022aff},
{'q', 0x3f0fb820, 0x40e74c5a},
{0, 0x3ed79440, 0x4119d316},
{'@', 0x0000006c, 0x00004e50},/* l x-advance: 78.312500 */
{'M', 0x429608fc, 0xc0ace98b},
{'8', 0x26f41701, 0x0fd10ff3},
{'q', 0xbfe98b40, 0x00000000},
{0, 0xc1cc59d4, 0xbe579430},
{'q', 0xc1bd3167, 0xbe8fb824},
{0, 0xc1f5e50e, 0xbe8fb824},
{'8', 0xf2db00e7, 0xddf5f2f5},
{'8', 0xda0ae9ff, 0xf127f10c},
{'q', 0x40ce98b4, 0x00000000},
{0, 0x41b1674d, 0x3e8fb820},
{'q', 0x00000000, 0xc0b5e50c},
{0, 0xbe579500, 0xc1155554},
{'q', 0xbe8fb800, 0xc14c59d4},
{0, 0x00000000, 0xc20c11f7},
{'q', 0x3e8fb880, 0xc1b1f704},
{0, 0x3f459d40, 0xc220d794},
{'q', 0xc091f704, 0x3eb3a600},
{0, 0xc1874c5a, 0x3eb3a600},
{'8', 0xf0da00e8, 0xdaf5f0f4},
{'8', 0xe00ced00, 0xf324f30c},
{'q', 0x4121af28, 0x00000000},
{0, 0x41823ee0, 0xbe8fb900},
{'8', 0xff56fe31, 0x1014000f},
{'q', 0x3fe98b40, 0x3f33a680},
{0, 0x3fe98b40, 0x40143600},
{'q', 0xbf459d40, 0x4091f700},
{0, 0xbfa1af40, 0x41c23ee0},
{'q', 0xbed79400, 0x419d3166},
{0, 0xbed79400, 0x41eb3a62},
{'q', 0x00000000, 0x41650d78},
{0, 0x3e0fb800, 0x41c00000},
{'q', 0x00000000, 0x40aaaaac},
{0, 0x3eb3a600, 0x417823ee},
{'8', 0x01460021, 0x013d0025},
{'8', 0x00200017, 0x0c2c0020},
{'q', 0x3fc59d40, 0x3fc59d34},
{0, 0x3fd79440, 0x40800001},
{'@', 0x0000006d, 0x00004e50},/* m x-advance: 78.312500 */
{'M', 0x418c59d3, 0xc088fb82},
{'8', 0x1ffb1200, 0x13f30cfc},
{'8', 0x08ef06f8, 0x02ed02f8},
{'8', 0xf3ddffea, 0xd1f4f4f4},
{'8', 0xe2fff600, 0xcdfeecff},
{'q', 0xbe579430, 0xc07b8240},
{0, 0xbe8fb820, 0xc0d55554},
{'q', 0xbf33a630, 0xc19047dc},
{0, 0x00000000, 0xc233a62d},
{'8', 0xc713d900, 0xef2cee13},
{'8', 0x11240017, 0x3808110e},
{'8', 0x1cfb09ff, 0x1dfd13fe},
{'q', 0x40dc11f4, 0xc1650d7c},
{0, 0x4198b3a5, 0xc1650d7c},
{'8', 0x1f280017, 0x541d1e11},
{'q', 0x40fb8240, 0xc1674c5c},
{0, 0x41ae98b4, 0xc1674c5c},
{'8', 0x212b001b, 0x5913210f},
{'q', 0x3f0fb800, 0x40de50d8},
{0, 0x3f33a600, 0x417ca1b0},
{'q', 0x3e0fb800, 0x410d7944},
{0, 0xbe0fb800, 0x4190d794},
{'q', 0xbe579400, 0x41131674},
{0, 0x3e579400, 0x4190d794},
{'8', 0x26fe1700, 0x16f60ffd},
{'8', 0x0af207fa, 0x02ef02f9},
{'8', 0xffec00f5, 0xf7edfef8},
{'8', 0xe9f1f9f7, 0xd9faf1fb},
{'q', 0xbeb3a600, 0xc09d3168},
{0, 0xbe579400, 0xc139435e},
{'q', 0x3e0fb800, 0xc0d55558},
{0, 0x3e579400, 0xc161af28},
{'8', 0x9301c501, 0xaefccf00},
{'8', 0xdff2dffc, 0x21c5ffe0},
{'q', 0xc0531680, 0x4088fb88},
{0, 0xc0b3a630, 0x413286bc},
{'q', 0x3ed79400, 0x41011f74},
{0, 0xbe579400, 0x41abca1c},
{'q', 0xbf0fb840, 0x41555555},
{0, 0xbe8fb880, 0x419047dc},
{'8', 0x22fe1401, 0x14f40dfd},
{'8', 0x08f006f9, 0x01ed02f8},
{'8', 0xf4dd00eb, 0xccf0f3f4},
{'q', 0xbe8fb800, 0xc09435e5},
{0, 0x3efb8280, 0xc1808fb8},
{'q', 0x3f459d40, 0xc13823f0},
{0, 0x3f459d40, 0xc18f286c},
{'q', 0x00000000, 0xbfa1af20},
{0, 0x00000000, 0xc05c11f0},
{'q', 0x00000000, 0xc12ce98c},
{0, 0xbefb8280, 0xc161af2c},
{'8', 0xe6ebe6fd, 0x26c700e5},
{'q', 0xc07286c0, 0x409674c8},
{0, 0xc0ce98b4, 0x4133a62c},
{'q', 0xbe0fb880, 0x409435e8},
{0, 0x3e0fb800, 0x41874c5a},
{'8', 0x67022800, 0x4c023e02},
{'@', 0x0000006e, 0x00004e50},/* n x-advance: 78.312500 */
{'M', 0x41b823ee, 0xc088fb82},
{'8', 0x30ee2100, 0x0bd40eef},
{'8', 0xf1deffec, 0xd4f1f2f2},
{'8', 0xc8fbf700, 0xb1fad2fb},
{'q', 0xbed79430, 0xc11674c6},
{0, 0x3f21af28, 0xc1cc59d4},
{'q', 0x3f8fb828, 0xc1811f70},
{0, 0x3f98b3a8, 0xc195e50e},
{'8', 0xcc14dd00, 0xf12ef014},
{'8', 0x0f270018, 0x330b0f0e},
{'8', 0x25fd18fe, 0xba4dd61b},
{'q', 0x40c7dc10, 0xc0650d80},
{0, 0x416f286c, 0xc0650d80},
{'q', 0x411f7048, 0x00000000},
{0, 0x417047dc, 0x40e98b40},
{'q', 0x40a1af28, 0x40e74c58},
{0, 0x40ace988, 0x41a2ce98},
{'q', 0x3e8fb800, 0x410c59d4},
{0, 0x400b3a60, 0x41b31675},
{'q', 0x3ff286c0, 0x4158b3a7},
{0, 0x400b3a60, 0x418f286c},
{'8', 0x34f42301, 0x10db10f2},
{'8', 0xf1d401e7, 0xcbecf0ee},
{'q', 0xbe0fb800, 0xbfaaaaac},
{0, 0xbfc59d20, 0xc159d316},
{'q', 0xbfaaaaa0, 0xc1459d32},
{0, 0xbfd79440, 0xc1a1af28},
{'q', 0xbf21af00, 0xc1447dc4},
{0, 0xc018b3a0, 0xc183ee0a},
{'8', 0xdfc9dff3, 0x09c900e4},
{'8', 0x17d108e6, 0x22da0eec},
{'8', 0x25e213ee, 0x25ea11f5},
{'q', 0xbefb8240, 0x41035e50},
{0, 0xbe8fb800, 0x4173a62c},
{'8', 0x65062700, 0x4f063d06},
{'m', 0xc0770480, 0xc1f79436},
{'l', 0x00000000, 0xbe8fb880},
{'l', 0x00000000, 0x3e8fb880},
{'@', 0x0000006f, 0x00004e50},/* o x-advance: 78.312500 */
{'M', 0x42108fb8, 0x4077047e},
{'8', 0xe699ffc8, 0xbdb3e7d2},
{'q', 0xc07286bc, 0xc0aaaaaa},
{0, 0xc0bca1af, 0xc1423ee0},
{'q', 0xc006bca2, 0xc0dc11f8},
{0, 0xbffb823c, 0xc1650d7c},
{'q', 0x00000000, 0xc10a1af0},
{0, 0x400fb824, 0xc1800000},
{'8', 0x9934c512, 0xbb57d422},
{'q', 0x40d55554, 0xc04a1b00},
{0, 0x417047da, 0xc04a1b00},
{'8', 0x0b4e0029, 0x25470b25},
{'8', 0x41381921, 0x61232617},
{'q', 0x3fc59d40, 0x40ebca20},
{0, 0x3f7b8280, 0x4183ee0a},
{'q', 0xbf0fb800, 0x410c59d2},
{0, 0xc033a640, 0x4174c59c},
{'8', 0x5acd34ef, 0x39ab26df},
{'9', 0x0012ffcc, 0x0011ff84},
{'m', 0x40459d30, 0xc1423ee0},
{'8', 0xf33d0122, 0xd42cf11b},
{'8', 0xbd1ae310, 0xab0bda09},
{'q', 0x3f0fb840, 0xc173a62c},
{0, 0xc08fb820, 0xc1b1f704},
{'q', 0xc09f7048, 0xc0e2ce98},
{0, 0xc163ee08, 0xc0e2ce98},
{'q', 0xc106bca4, 0x00000000},
{0, 0xc14d7946, 0x40f70480},
{'q', 0xc08d7944, 0x40f4c598},
{0, 0xc0a62ce8, 0x41abca1a},
{'8', 0x430125ff, 0x380c1d03},
{'8', 0x2c1a1a0a, 0x1d2b1110},
{'q', 0x405c1200, 0x3fb3a630},
{0, 0x41023ee0, 0x3fd79438},
{'@', 0x00000070, 0x00004e50},/* p x-advance: 78.312500 */
{'M', 0x41b8b3a6, 0x420d7943},
{'8', 0x2bf21c00, 0x0fdb0ff1},
{'q', 0xc0dc11f6, 0xbeb3a680},
{0, 0xc0e74c58, 0xc0f047e0},
{'q', 0xbf21af30, 0xc150d794},
{0, 0xbf86bca8, 0xc232ce98},
{'q', 0xbeb3a620, 0xc1fd3168},
{0, 0xbe579400, 0xc2479436},
{'q', 0x00000000, 0xc1447dc4},
{0, 0x3fb3a628, 0xc17047dc},
{'8', 0xe41bee08, 0xfa24f712},
{'8', 0x111f0212, 0x1e080e0d},
{'q', 0xbf21af20, 0x401d3160},
{0, 0xbf698b40, 0x40d31670},
{'q', 0x4123ee0a, 0xc0e2cea0},
{0, 0x41a47dc1, 0xc0e2cea0},
{'8', 0x084f002c, 0x20400822},
{'8', 0x3c31171d, 0x601e2513},
{'q', 0x3fbca1c0, 0x40e98b40},
{0, 0x3fce98c0, 0x4188fb83},
{'8', 0x4ef82600, 0x4ce327f8},
{'8', 0x42d125ed, 0x2fbe1de5},
{'q', 0xc09af288, 0x400fb824},
{0, 0xc1274c5c, 0x4018b3a6},
{'q', 0xc15af286, 0x3e579440},
{0, 0xc19d3167, 0xbfe08fb8},
{'q', 0x3d8fb800, 0x40dc11f8},
{0, 0x3e8fb840, 0x4191f704},
{'9', 0x005a0001, 0x00730001},
{'m', 0xbfc59d30, 0xc2ac7dc1},
{'q', 0x00000000, 0x4021af30},
{0, 0x3e0fb800, 0x41274c5c},
{'q', 0x3e579480, 0x40fb8238},
{0, 0x3eb3a640, 0x4181af27},
{'q', 0x3e579480, 0x41059d32},
{0, 0x3e8fb840, 0x417ca1b0},
{'8', 0x093e0816, 0xfe530028},
{'8', 0xea3eff23, 0xcb29ec1a},
{'8', 0xb914df0e, 0xb105da06},
{'8', 0xacf6d0fe, 0xc7efddf9},
{'8', 0xdde6ebf6, 0xefe1f3f1},
{'8', 0xfbddfbf1, 0x13ad00da},
{'q', 0xc0b16750, 0x401d3170},
{0, 0xc11af288, 0x40c11f70},
{'l', 0x00000000, 0x3fd79440},
{'@', 0x00000071, 0x00004e50},/* q x-advance: 78.312500 */
{'M', 0x42874c5a, 0x4209d317},
{'8', 0x30eb1ffd, 0x10d810ee},
{'8', 0xf0dc00eb, 0xd0f4f0f1},
{'q', 0x3f579440, 0xc12bca1c},
{0, 0x3fc59d20, 0xc20286bd},
{'q', 0xc0d55550, 0x403823ec},
{0, 0xc193a62c, 0x402aaaa8},
{'8', 0xefacffd4, 0xd4beefda},
{'8', 0xc1d1e4e5, 0xb7e3dded},
{'q', 0xbf8fb824, 0xc098b3a8},
{0, 0xbf86bca0, 0xc1155556},
{'q', 0x3e0fb820, 0xc11d3168},
{0, 0x4018b3a8, 0xc18c59d2},
{'8', 0x9a30c212, 0xbe47d81d},
{'8', 0xda57e62a, 0xf561f52d},
{'8', 0x136f003d, 0x314b1332},
{'8', 0x1c0f0d0b, 0x18030e05},
{'8', 0x11fa0aff, 0x0fe90af8},
{'q', 0x00000000, 0x3fd79420},
{0, 0xbd8fb800, 0x41898b3a},
{'q', 0x00000000, 0x4177047c},
{0, 0xbe0fb800, 0x41ad7943},
{'q', 0xbd8fb800, 0x40c59d32},
{0, 0xbe8fb800, 0x4191674c},
{'q', 0xbe0fb800, 0x413ee091},
{0, 0xbf0fb880, 0x419d3168},
{'9', 0x003dfffe, 0x0068fff9},
{'m', 0xc1e98b3a, 0xc227dc12},
{'q', 0x41298b38, 0x3ed793f0},
{0, 0x41898b3a, 0xc0459d38},
{'q', 0x3e8fb800, 0xc10e98b4},
{0, 0x3f86bca0, 0xc243a62e},
{'8', 0xf1d9f5ec, 0xfdc6fded},
{'8', 0x06d600ec, 0x16d306eb},
{'8', 0x27d50fe8, 0x3ee017ee},
{'8', 0x57f126f3, 0x4b0526ff},
{'8', 0x43152306, 0x33291f0e},
{'q', 0x40579438, 0x401d3168},
{0, 0x40fb8244, 0x402aaaac},
{'@', 0x00000072, 0x00004e50},/* r x-advance: 78.312500 */
{'M', 0x41ce98b4, 0xc04e98b4},
{'8', 0x34c73701, 0xf4dbffe9},
{'8', 0xd8f1f5f3, 0xc8f9fd00},
{'q', 0xbf459d30, 0xc0d31676},
{0, 0xbf698b30, 0xc12e08fb},
{'q', 0xbeb3a640, 0xc1131676},
{0, 0x3f459d30, 0xc1c62cea},
{'q', 0x3f8fb820, 0xc1794360},
{0, 0x3f98b3a8, 0xc19d3168},
{'8', 0xcd14dd01, 0xf12cf112},
{'8', 0x0f260018, 0x310c0f0e},
{'l', 0xbf698b40, 0x410c59d4},
{'8', 0xd527eb0c, 0xd842eb1b},
{'q', 0x409d3168, 0xc01d3160},
{0, 0x413b8240, 0xc0770480},
{'q', 0x40d9d318, 0xbfb3a640},
{0, 0x4163ee0c, 0xbf98b380},
{'8', 0x1815020c, 0x320e150a},
{'8', 0x39051c04, 0x2ffc1d01},
{'8', 0x20f014fd, 0x0fe10af4},
{'8', 0xf8db04ec, 0xdeecf3ef},
{'8', 0xe2fef5fe, 0xe0feed00},
{'8', 0xe9f5f4fe, 0x0eb600db},
{'8', 0x23c10edc, 0x2ecf14e6},
{'8', 0x2edd19ea, 0x22ef14f4},
{'q', 0xbe8fb840, 0x40f047d8},
{0, 0xbe0fb880, 0x4137047c},
{'q', 0x00000000, 0x40aaaaac},
{0, 0x3f459d40, 0x41608fb9},
{'q', 0x3f579440, 0x410b3a62},
{0, 0x3f698b40, 0x4119d316},
{'@', 0x00000073, 0x00004e50},/* s x-advance: 78.312500 */
{'M', 0x41000000, 0xc118b3a6},
{'8', 0xac18c0f0, 0xfa21fa10},
{'8', 0x0b200010, 0x20190b10},
{'8', 0x170a0f06, 0x100b0703},
{'8', 0x0c0f0807, 0x06160308},
{'8', 0x0221020e, 0xf14c0020},
{'8', 0xd54ff12b, 0xc927e523},
{'8', 0xe5f3f101, 0xebd5f4f2},
{'8', 0xf0c5f8e4, 0xefb6f9e2},
{'8', 0xecb6f6d6, 0xd1a7ebbe},
{'q', 0xc03823f0, 0xc04e98b0},
{0, 0xc03823f0, 0xc1155554},
{'q', 0x00000000, 0xc1370480},
{0, 0x414d7943, 0xc19047dc},
{'q', 0x414d7944, 0xc0d31670},
{0, 0x421823ee, 0xc0d31670},
{'8', 0x2119000d, 0x3e10200b},
{'8', 0x2b061d05, 0x1b000e00},
{'8', 0x18f80c00, 0x10ea0bf9},
{'8', 0xfdd607e9, 0xe5e7f5ed},
{'8', 0xb5e7dcf1, 0x06ba00df},
{'8', 0x10b905db, 0x1ec90bde},
{'q', 0xc0262ce8, 0x4018b3a0},
{0, 0xc00fb828, 0x40aaaaa8},
{'q', 0x3efb8240, 0x40579430},
{0, 0x4171674e, 0x40ca1af0},
{'8', 0x1353082e, 0x19480a25},
{'8', 0x21390f23, 0x2b221116},
{'q', 0x3fbca1c0, 0x404a1af0},
{0, 0x3f7b8200, 0x40dc11f8},
{'q', 0xbf86bc80, 0x41035e50},
{0, 0xc0d9d310, 0x41662ce9},
{'q', 0xc0b5e510, 0x40c59d31},
{0, 0xc1674c58, 0x411435e5},
{'q', 0xc10b3a64, 0x40459d30},
{0, 0xc1994360, 0x40459d30},
{'8', 0xf5ad00d4, 0xdabbf5da},
{'q', 0xc0770480, 0xc05c11f9},
{0, 0xc0a3ee0a, 0xc1047dc1},
{'@', 0x00000074, 0x00004e50},/* t x-advance: 78.312500 */
{'M', 0x427e08fc, 0x3fa1af28},
{'q', 0xc0fdc120, 0x40411f70},
{0, 0xc199d318, 0x402f286c},
{'8', 0xf1afffd5, 0xdabef2db},
{'8', 0xc0d2e7e3, 0xa8eed9ef},
{'8', 0xc8ffefff, 0xcc00da01},
{'8', 0xd002f300, 0xd202dd02},
{'8', 0xd402f500, 0xd603df02},
{'l', 0xc0e2ce98, 0x00000000},
{'8', 0xced000ce, 0xcf31cf00},
{'q', 0x409435e6, 0x00000000},
{0, 0x40f047da, 0x3e579400},
{'q', 0x3efb8240, 0xc122ce98},
{0, 0xbf0fb820, 0xc1ad7944},
{'8', 0xde08effe, 0xf01ff00b},
{'8', 0x0e2c0014, 0x1e1a0e18},
{'q', 0x3f0fb840, 0x40a86bd0},
{0, 0x00000000, 0x41b5e510},
{'8', 0x025a0125, 0x02570135},
{'8', 0x002f0021, 0x32310031},
{'8', 0x1ff513ff, 0x0bdb0bf6},
{'q', 0xc0579430, 0x00000000},
{0, 0xc1e50d78, 0xbe8fb800},
{'8', 0x45fe1400, 0x42fe30fe},
{'8', 0x3bfe1100, 0x31ff2aff},
{'8', 0x23000700, 0x53213302},
{'q', 0x407b8240, 0x407b8240},
{0, 0x412bca1c, 0x4086bca2},
{'q', 0x410fb824, 0x3e8fb820},
{0, 0x41886bca, 0xc04e98b4},
{'8', 0x021ff911, 0x2013090e},
{'8', 0x28f51503, 0x1bd911f1},
{'@', 0x00000075, 0x00004e50},/* u x-advance: 78.312500 */
{'M', 0x428262cf, 0x40579436},
{'8', 0xf4d202e5, 0xceeff2ef},
{'l', 0x00000000, 0xc07b8240},
{'8', 0x2bc018e3, 0x20ae13de},
{'8', 0x09a40dd1, 0xe3b6fdd9},
{'8', 0xc1cae6de, 0xb8ecdced},
{'q', 0xbf459d38, 0xc11f7048},
{0, 0xbf459d38, 0xc1b8b3a7},
{'8', 0x9a02db00, 0xa701bf02},
{'8', 0xd70fe400, 0xf226f20f},
{'8', 0x0e2a0018, 0x29110e11},
{'8', 0x4bfe0a00, 0x6efe40fe},
{'q', 0x00000000, 0x416bca1a},
{0, 0x3f8fb820, 0x41b4c59d},
{'8', 0x25081602, 0x15100e06},
{'8', 0x0815060a, 0x021d020b},
{'8', 0xe9650031, 0xc95fe934},
{'q', 0x3e579500, 0xc1155554},
{0, 0x00000000, 0xc1aaaaaa},
{'q', 0x00000000, 0xc17ee090},
{0, 0xbf21af00, 0xc1bc11f8},
{'8', 0xda0ee800, 0xf123f20f},
{'8', 0x0e2a0017, 0x27120e12},
{'8', 0x4a031102, 0x43023801},
{'q', 0x3ed79400, 0x414a1af4},
{0, 0x3ed79400, 0x422ca1af},
{'8', 0x30f12100, 0x0fdb0ef2},
{'@', 0x00000076, 0x00004e50},/* v x-advance: 78.312500 */
{'M', 0x42386bca, 0x3f86bca2},
{'8', 0x14e50ffa, 0xffd805ec},
{'q', 0xc021af30, 0xbf459d30},
{0, 0xc0650d80, 0xc021af28},
{'q', 0xc18bca1b, 0xc201af28},
{0, 0xc1e00000, 0xc2711f70},
{'8', 0xddf9edfa, 0xe505f000},
{'8', 0xee0cf505, 0xf511f907},
{'8', 0xfb15fb0a, 0x0518000b},
{'8', 0x1317050c, 0x23110e0b},
{'8', 0x38111b08, 0x33111c0a},
{'8', 0x35141608, 0x2f131e0c},
{'8', 0x31141006, 0x2b13200e},
{'8', 0x2d140b05, 0x2811210f},
{'q', 0x416bca18, 0xc1e3ee08},
{0, 0x41ab3a62, 0xc246bca2},
{'8', 0xcf22da0b, 0xfe2cf417},
{'8', 0x1113050c, 0x1e0a0b07},
{'8', 0x2efa1302, 0x63da2ef2},
{'q', 0xc03ca1c0, 0x40d31678},
{0, 0xc122ce9c, 0x41ace98c},
{'q', 0xc0e50d78, 0x416f286b},
{0, 0xc14d7944, 0x41d9435e},
{'@', 0x00000077, 0x00004e50},/* w x-advance: 78.312500 */
{'M', 0x41e11f70, 0x3efb823f},
{'8', 0x1ceb11fa, 0x09e209f1},
{'8', 0xf6de00ef, 0xdde9f6f0},
{'q', 0xc131674c, 0xc2111f71},
{0, 0xc1531675, 0xc27c11f8},
{'8', 0xd508e4fd, 0xef23f10c},
{'8', 0x0829fd17, 0x29160b12},
{'q', 0x3fe08fb8, 0x4190d796},
{0, 0x40fb823e, 0x42559d32},
{'q', 0x3f698b40, 0xc09af284},
{0, 0x404e98b8, 0xc18e98b3},
{'q', 0x4018b3a8, 0xc14fb822},
{0, 0x4088fb80, 0xc1b4c59d},
{'q', 0x3ff286c0, 0xc119d318},
{0, 0x404e98b0, 0xc162ce98},
{'8', 0xd43cd20c, 0x0a200112},
{'8', 0x2216090e, 0x540e0501},
{'q', 0x3fce98a0, 0x411e50d8},
{0, 0x40800000, 0x41b823f0},
{'q', 0x4018b3a0, 0x4151f702},
{0, 0x408d7940, 0x41a98b3a},
{'q', 0x4033a630, 0xc15d3168},
{0, 0x40ebca20, 0xc256bca3},
{'8', 0xd614e103, 0xfa27f511},
{'q', 0x40b16750, 0x3f8fb840},
{0, 0x4098b3b0, 0x410c59d8},
{'q', 0xbfd79440, 0x41674c58},
{0, 0xc0a62cf0, 0x420435e5},
{'q', 0xc05c11e0, 0x419435e4},
{0, 0xc0d31670, 0x41de50d7},
{'8', 0x2ab82cf2, 0xf8d900e9},
{'q', 0xc0023ee0, 0xbf8fb824},
{0, 0xc04e98b0, 0xc0823ee0},
{'q', 0xc01435f0, 0xc0c11f70},
{0, 0xc07b8240, 0xc1698b3b},
{'q', 0xbfce98c0, 0xc10a1af2},
{0, 0xc0411f70, 0xc1a3ee08},
{'q', 0xbfb3a640, 0xc13dc120},
{0, 0xbfe98b40, 0xc1662cec},
{'q', 0xbfaaaaa0, 0x40aaaab0},
{0, 0xc0459d30, 0x416bca1c},
{'q', 0xbfe08fc0, 0x411674c6},
{0, 0xc0770480, 0x4197047e},
{'q', 0xc0023ee0, 0x411674c5},
{0, 0xc09674c8, 0x418ce98b},
{'@', 0x00000078, 0x00004e50},/* x x-advance: 78.312500 */
{'M', 0x41823ee1, 0x00000000},
{'8', 0x18e312f2, 0x01e505f1},
{'8', 0xf1e9fcf5, 0xadfee1df},
{'8', 0xc730eb0d, 0xb04edc23},
{'8', 0xad46d42b, 0x98a2d4dd},
{'8', 0xb1b6c5c6, 0xddefedf2},
{'8', 0xe300effd, 0xeb10f505},
{'8', 0xf518f80b, 0x0320fd0e},
{'8', 0x18230612, 0x52471a19},
{'8', 0x6753372e, 0xc829ed0e},
{'8', 0xc929dc1a, 0xd620ed0e},
{'8', 0xdd1ee911, 0xe42ce917},
{'8', 0x0824fc15, 0x1410080a},
{'8', 0x1b040b06, 0x1df30fff},
{'4', 0x00d2ff56, 0x0003fffd},
{'8', 0x4e41271d, 0x47432623},
{'8', 0x3731201f, 0x2313140e},
{'8', 0x19030f05, 0x13f70aff},
{'8', 0x10e90bf6, 0xffe004f4},
{'q', 0xc018b3b0, 0xbf579438},
{0, 0xc09af288, 0xc05c11f8},
{'q', 0xc14c59d4, 0xc15c11f7},
{0, 0xc1afb824, 0xc1cc59d3},
{'q', 0xc086bca8, 0x40a86bcc},
{0, 0xc147dc14, 0x416ce98c},
{'q', 0xc1035e50, 0x4118b3a6},
{0, 0xc11af286, 0x413823ee},
{'@', 0x00000079, 0x00004e50},/* y x-advance: 78.312500 */
{'M', 0x41caaaab, 0x4226bca2},
{'8', 0x1ddf15f6, 0xf8d307ea},
{'8', 0xedeff8f5, 0xe6f9f5fa},
{'9', 0xfff1ffff, 0xffe10008},
{'l', 0x4194c59d, 0xc211af29},
{'q', 0xc18d7944, 0xc2050d79},
{0, 0xc1d8b3a6, 0xc269d316},
{'8', 0xd3f9e6f6, 0xe20aed02},
{'8', 0xf015f508, 0xfa15fb0a},
{'8', 0x0318ff0b, 0x1117040c},
{'q', 0x3fb3a630, 0x3fd79440},
{0, 0x400b3a68, 0x408d7940},
{'q', 0x4018b3a8, 0x40f70480},
{0, 0x40cc59d4, 0x418bca1c},
{'q', 0x40800000, 0x411c11f8},
{0, 0x40d79434, 0x417b8240},
{'q', 0x4033a630, 0x40bca1ac},
{0, 0x40f047e0, 0x417a62cc},
{'q', 0x417047dc, 0xc1f286bc},
{0, 0x41b4c59c, 0xc2474c59},
{'8', 0xe011ed07, 0xef15f40a},
{'8', 0xfc16fc0b, 0x0415000b},
{'8', 0x0c100408, 0x130c0707},
{'8', 0x1c050b05, 0x22f81000},
{'q', 0xc05c1200, 0x41035e50},
{0, 0xc123ee08, 0x41b286bc},
{'q', 0xc0d9d318, 0x4161af2a},
{0, 0xc151f704, 0x41d55556},
{'q', 0xc0ca1af8, 0x4148fb82},
{0, 0xc1a11f72, 0x422047dc},
{'q', 0xc091f700, 0x410e98b4},
{0, 0xc0de50d4, 0x415af288},
{'@', 0x0000007a, 0x00004e50},/* z x-advance: 78.312500 */
{'M', 0x428e50d8, 0xc0ace98b},
{'8', 0x26f41701, 0x0fd10ff4},
{'q', 0xbf8fb820, 0x00000000},
{0, 0xc13823f0, 0xbe8fb822},
{'q', 0xc1262ce8, 0xbeb3a62e},
{0, 0xc199435e, 0xbed79436},
{'q', 0xc10c59d2, 0xbe0fb824},
{0, 0xc19f7048, 0x3e579438},
{'8', 0xebdd00ec, 0xd4f2e9f2},
{'8', 0xf002f800, 0xe511f803},
{'8', 0xd12aed0e, 0xab58ee11},
{'q', 0x410d7946, 0xc106bca2},
{0, 0x41886bcb, 0xc1847dc1},
{'q', 0x41035e50, 0xc1035e50},
{0, 0x413ca1b0, 0xc146bca4},
{'q', 0xc1e7dc13, 0x3f98b3a0},
{0, 0xc21e08fc, 0xbf0fb800},
{'8', 0xcfcff8cf, 0xd90ae9ff},
{'q', 0x3fc59d38, 0xc006bca0},
{0, 0x409f7048, 0xbfe08fc0},
{'q', 0x41ca1af2, 0x40262ce0},
{0, 0x42435e51, 0x3f98b380},
{'8', 0x1121ff13, 0x290f110e},
{'8', 0x51da1401, 0x61b331df},
{'8', 0x50b02fd5, 0x4ea920dc},
{'q', 0xc0cc59d4, 0x40b5e50e},
{0, 0xc12bca1c, 0x4122ce99},
{'q', 0x41df7048, 0xbfe08fb8},
{0, 0x422047dc, 0x00000000},
{'8', 0x112c0620, 0x1d0c0b0c},
{'@', 0x0000007b, 0x00004e50},/* { x-advance: 78.312500 */
{'M', 0x428e50d8, 0x40fb823f},
{'8', 0x23f41300, 0x0fd80ff4},
{'8', 0xf69800c9, 0xe2a7f6cf},
{'8', 0xcbc2ecd9, 0xb6e9dfe9},
{'8', 0xc306e000, 0xcb11e207},
{'8', 0xd213e80a, 0xd010e90a},
{'8', 0xce07e707, 0xf6f9fd00},
{'8', 0xf2e9faf9, 0xf2dbf9f1},
{'8', 0xf6cdfaec, 0xfcc2fce3},
{'8', 0xedd800e9, 0xd6f0edf0},
{'8', 0xda0ce900, 0xf124f10c},
{'8', 0xff37001e, 0xfb30ff18},
{'8', 0xf629fd19, 0xef1bfa10},
{'8', 0xe50af50a, 0xe6f7f800},
{'8', 0xdceceff7, 0xc9ecedf5},
{'q', 0xbf98b3a0, 0xc08fb820},
{0, 0xbf98b3a0, 0xc119d310},
{'q', 0x00000000, 0xc158b3a8},
{0, 0x41155556, 0xc1ac59d4},
{'q', 0x41155554, 0xc1000000},
{0, 0x41ce08fa, 0xc1000000},
{'8', 0x0c270017, 0x1d100c10},
{'8', 0x25eb1300, 0x11d911ec},
{'q', 0xc11d3168, 0x00000000},
{0, 0xc175e50c, 0x408b3a60},
{'8', 0x5cd422d4, 0x3e0a1c00},
{'8', 0x3b17220a, 0x3017190c},
{'8', 0x210a170a, 0x2af21600},
{'8', 0x22dc14f3, 0x19d00ee9},
{'8', 0x10cb0ae7, 0x316c1341},
{'8', 0x392b1e2b, 0x34fa1900},
{'8', 0x30f019fa, 0x2eed16f7},
{'8', 0x35f017f7, 0x3cfa1dfa},
{'8', 0x230f1300, 0x19280f10},
{'8', 0x0e350918, 0x0538051c},
{'8', 0x0c280017, 0x20110c11},
{'@', 0x0000007c, 0x00004e50},/* | x-advance: 78.312500 */
{'M', 0x423d7943, 0xc2e1f705},
{'q', 0x00000000, 0x3f8fb840},
{0, 0xbf33a600, 0x427286be},
{'q', 0xbf21af40, 0x426e08fb},
{0, 0xbe579400, 0x4291435e},
{'8', 0x27ec19fe, 0x0cd80ef0},
{'8', 0xf2e000eb, 0xd4f9f1f6},
{'q', 0x3efb8200, 0xc0b5e50e},
{0, 0x3f33a640, 0xc206bca2},
{'q', 0x3e579400, 0xc1e08fb7},
{0, 0x3e8fb800, 0xc2700000},
{'q', 0x3e0fb800, 0xc1ff7048},
{0, 0x3e8fb800, 0xc2198b3a},
{'8', 0xc22ec201, 0x3a33fe33},
{'@', 0x0000007d, 0x00004e50},/* } x-advance: 78.312500 */
{'M', 0x42474c5a, 0xc173a62d},
{'q', 0x00000000, 0x4158b3a6},
{0, 0xc1155554, 0x41ac59d3},
{'q', 0xc1155558, 0x41000000},
{0, 0xc1ce08fc, 0x41000000},
{'8', 0xf4da00ea, 0xe3f0f4f0},
{'8', 0xdb14ed00, 0xef27ef14},
{'q', 0x411e50d8, 0x00000000},
{0, 0x4175e50e, 0xc08b3a63},
{'8', 0xa42cde2c, 0xc1f6e400},
{'8', 0xc1eaddf6, 0xcbe9e4f4},
{'8', 0xddf6e7f6, 0xd60dea00},
{'8', 0xde24ec0e, 0xe730f117},
{'8', 0xf035f619, 0xcf94edbf},
{'8', 0xc8d5e2d5, 0xcd06e600},
{'8', 0xd210e706, 0xd613ec09},
{'8', 0xcf10eb09, 0xc606e406},
{'8', 0xddf1ed00, 0xe7d8f1f1},
{'8', 0xf2cbf7e8, 0xfbc8fbe4},
{'8', 0xf4d700e9, 0xdfeff4ef},
{'8', 0xdd0ced00, 0xf028f00c},
{'8', 0x0a680037, 0x1e590a31},
{'8', 0x343e1327, 0x4a172117},
{'8', 0x3df92000, 0x32f01cfa},
{'8', 0x2bed15f7, 0x2cef14f6},
{'8', 0x30fa18fa, 0x0a070400},
{'8', 0x0e170607, 0x0d250710},
{'8', 0x0a330614, 0x033e031e},
{'8', 0x13280017, 0x2a111311},
{'8', 0x26f41700, 0x0fdb0ff4},
{'8', 0x01c900e2, 0x05cf01e8},
{'8', 0x0ad703e8, 0x12e606f0},
{'8', 0x1af60bf6, 0x1c090800},
{'8', 0x28141309, 0x3b14150b},
{'q', 0x3f98b3a0, 0x409674c4},
{0, 0x3f98b3a0, 0x411d3167},
{'@', 0x0000007e, 0x00004e50},/* ~ x-advance: 78.312500 */
{'M', 0x429262cf, 0xc292f287},
{'8', 0x0f0f040a, 0x1a020a04},
{'8', 0x1efa0fff, 0x22f50ffd},
{'q', 0xc10e98b8, 0x41afb824},
{0, 0xc1aa1af4, 0x41afb824},
{'8', 0xf9d400e8, 0xe8dbf9ec},
{'8', 0xdee3f0f0, 0xd4e4eff4},
{'8', 0xeef5fbfd, 0xeff6f3f9},
{'8', 0xf4f8fdfe, 0xf5f7f8fb},
{'8', 0xf9f7fefd, 0xfbf5fcfb},
{'8', 0xfff3fffb, 0x02f000f8},
{'8', 0x0bf202f9, 0x0ff507fa},
{'8', 0x18f507fc, 0x1ef511fa},
{'8', 0x26f30cfc, 0x28df17f8},
{'8', 0x0dd611e8, 0xebebfdf4},
{'q', 0xbf8fb824, 0xc018b3a0},
{0, 0xbed79438, 0xc0a3ee08},
{'q', 0x40698b3a, 0xc15d3168},
{0, 0x411d3167, 0xc1ad7942},
{'8', 0xc261c231, 0x01200013},
{'8', 0x071b010c, 0x0f1a050e},
{'8', 0x1c180a0b, 0x2b1a110d},
{'8', 0x140a0703, 0x130a0c06},
{'8', 0x10080603, 0x0e0a0906},
{'8', 0x0a0a0404, 0x070c0506},
{'8', 0x010d0106, 0x00050001},
{'8', 0x000e000a, 0xfe0c0005},
{'8', 0xf90cfe07, 0xf10cfb05},
{'8', 0xe70ef607, 0xdb11f107},
{'8', 0xe40df205, 0xe513f208},
{'8', 0xed18f30b, 0x001afb0e},
};
#define ctx_font_Comic_Mono_name "Comic Mono"
#endif
......@@ -831,7 +831,7 @@ static void stbi__start_mem(stbi__context *s, stbi_uc const *buffer, int len)
}
// initialize a callback-based context
static void stbi__start_callbacks(stbi__context *s, stbi_io_callbacks *c, void *user)
void stbi__start_callbacks(stbi__context *s, stbi_io_callbacks *c, void *user)
{
s->io = *c;
s->io_user_data = user;
......@@ -6774,7 +6774,7 @@ static stbi_uc *stbi__process_gif_raster(stbi__context *s, stbi__gif *g)
// this function is designed to support animated gifs, although stb_image doesn't support it
// two back is the image from two frames ago, used for a very specific disposal format
static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, int req_comp, stbi_uc *two_back)
stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, int req_comp, stbi_uc *two_back)
{
int dispose;
int first_frame;
......
......@@ -21,4 +21,5 @@ idf_component_register(
vfs
bmi270
bmp581
esp_timer
)
......@@ -23,7 +23,11 @@ void flow3r_bsp_display_init(void);
// This must not be called if another transfer is alraedy being performed. The
// user code should sequence access and make sure not more than one transfer is
// performed simultaneously.
void flow3r_bsp_display_send_fb(uint16_t *fb_data);
void flow3r_bsp_display_send_fb(void *fb_data, int bits);
void flow3r_bsp_display_send_fb_osd(void *fb_data, int bits, int scale,
void *osd_data, int osd_x0, int osd_y0,
int osd_x1, int osd_y1);
// Set display backlight, as integer percent value (from 0 to 100, clamped).
// No-op if display hasn't been succesfully initialized.
......@@ -47,7 +51,7 @@ typedef enum {
// Headset microphone on left jack.
flow3r_bsp_audio_input_source_headset_mic = 2,
// Onboard microphone (enabled red LED).
flow3r_bsp_audio_input_source_onboard_mic = 3
flow3r_bsp_audio_input_source_onboard_mic = 3,
} flow3r_bsp_audio_input_source_t;
// Initialize the audio subsystem of the badge, including the codec and I2S data
......@@ -70,7 +74,7 @@ float flow3r_bsp_audio_speaker_set_volume(bool mute, float dB);
//
// TODO: figure out if int/float inconsistency is a good thing here compared to
// all other _dB functions.
void flow3r_bsp_audio_headset_set_gain_dB(uint8_t gain_dB);
int8_t flow3r_bsp_audio_headset_set_gain_dB(int8_t gain_dB);
typedef struct {
bool headphones;
......@@ -127,6 +131,12 @@ esp_err_t flow3r_bsp_audio_write(const void *src, size_t size,
// Write audio codec register. Obviously very unsafe. Have fun.
void flow3r_bsp_audio_register_poke(uint8_t reg, uint8_t data);
// Configure audio codec DRC. For testing purposes, not stable api.
void flow3r_bsp_max98091_configure_dynamic_range_control(
bool enable, uint8_t attack, uint8_t release, uint8_t make_up_gain_dB,
uint8_t comp_ratio, uint8_t comp_threshold_dB, uint8_t exp_ratio,
uint8_t exp_threshold_dB);
#define FLOW3R_BSP_LED_COUNT 40
// Initialize LEDs.
......
#include "flow3r_bsp_ad7147.h"
#include "flow3r_bsp_ad7147_hw.h"
#include "flow3r_bsp_captouch.h"
#include "flow3r_bsp_i2c.h"
#include "esp_err.h"
#include "esp_log.h"
......@@ -10,252 +11,1624 @@
#include <stdint.h>
#include <string.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "freertos/semphr.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "esp_timer.h"
// #define FLOW3R_BSP_CAPTOUCH_DEBUG_PROFILING
// #define FLOW3R_BSP_CAPTOUCH_DEBUG_CURSED_PROFILING
// #define FLOW3R_BSP_CAPTOUCH_DEBUG_SEQUENCING
// #define FLOW3R_BSP_CAPTOUCH_DEBUG_CALIBRATION
// #define FLOW3R_BSP_CAPTOUCH_DEBUG_PETAL 2
/*
時折誰かが問う
いつまでどこまで向かう気かと
BABYどこまででも
*/
#define MAX_POS_AFE (63)
#define MAX_NEG_AFE (63)
#define MAX_AFE (MAX_POS_AFE + MAX_NEG_AFE)
static ad7147_chip_t _top = {
.name = "top",
.is_bot = false,
.num_petals = 4,
.petals = { 0, 4, 6, 8 },
};
static ad7147_chip_t _bot = {
.name = "bot",
.is_bot = true,
.num_petals = 6,
.petals = { 1, 2, 3, 5, 7, 9 },
};
// callback function for the logging feature
static flow3r_bsp_data_callback_t _on_data = NULL;
void flow3r_bsp_ad7147_set_data_callback(flow3r_bsp_data_callback_t fun) {
_on_data = fun;
}
// modes that the petals are supposed to be in (excl. calibration and
// transients)
static flow3r_bsp_captouch_petal_mode_t _petal_modes[10] = {
PETAL_MODE_2D, PETAL_MODE_1D, PETAL_MODE_2D, PETAL_MODE_1D, PETAL_MODE_2D,
PETAL_MODE_1D, PETAL_MODE_2D, PETAL_MODE_1D, PETAL_MODE_2D, PETAL_MODE_1D,
};
static const char *TAG = "flow3r-bsp-ad7147";
// output data that gets continuously written to and
// memcpy'd when the user requests.
static flow3r_bsp_captouch_data_t captouch_data;
// user-facing calibration data
static ad7147_petal_calib_t calibration_data[10];
// lock for calibration_data
static SemaphoreHandle_t calibration_lock = NULL;
// calibration data used internally by the chip tasks
static ad7147_petal_calib_t _chip_calibration_data[10];
// if you want both locks it's important to always take/free them in the
// same order to avoid deadlock. use these functions to avoid such bugs.
// xTicksToWait is implemented very halfassed and is the wait time for each
// lock, i.e. you might wait twice as long
static BaseType_t xSemaphoreTakeCaptouchOutput(TickType_t xTicksToWait) {
if (xSemaphoreTake(_top.output_lock, xTicksToWait) == pdFALSE)
return pdFALSE;
if (xSemaphoreTake(_bot.output_lock, xTicksToWait) == pdTRUE) return pdTRUE;
xSemaphoreGive(_top.output_lock);
return pdFALSE;
}
static BaseType_t xSemaphoreGiveCaptouchOutput() {
bool ret = true;
ret = (xSemaphoreGive(_bot.output_lock) == pdTRUE) && ret;
ret = (xSemaphoreGive(_top.output_lock) == pdTRUE) && ret;
return ret ? pdTRUE : pdFALSE;
}
// we just want a function with that name really
static BaseType_t xSemaphoreBonk(SemaphoreHandle_t handle,
TickType_t xTicksToWait) {
if (xSemaphoreTake(handle, xTicksToWait) == pdFALSE) return pdFALSE;
return xSemaphoreGive(handle);
}
// tasks that generate captouch_data
static TaskHandle_t _top_task_handle = NULL;
static TaskHandle_t _bot_task_handle = NULL;
// notifications for _*_task_handle
// chip gpio interrupt
#define NOTIF_GPIO 1
// send this if you have written new target modes to ad7147_chip_t.user_modes to
// apply them.
#define NOTIF_MODE_CHANGE 2
// send this to start a calibration.
#define NOTIF_CALIB_START 4
// send this to stop a calibration. note: this does not restore previous
// calibration data. use this only for restarting calibration or applying
// external calibration, else you might end up with poor performance.
#define NOTIF_CALIB_STOP 8
// send this to if you have written new data to calibration_data to apply it.
#define NOTIF_CALIB_CHANGE 16
// used internally to synchronize calibration stages between chips for
// consistent EMI, don't send externally.
#define NOTIF_INTERNAL_CALIB_NEXT_STAGE 32
// used internally to iterate over calibrations.
#define NOTIF_INTERNAL_CALIB_CHANGE 64
#define NOTIF_CLEAR_MASK 127
// container for unprocessed petal data.
// 10 petals, 4 potential pad positions according to
// petal_kind_t. some fields are never used.
static uint16_t raw_petals[10][4];
typedef struct {
size_t petal_number;
petal_kind_t pad_kind;
} pad_mapping_t;
typedef struct {
bool press_event_new;
bool fresh;
} press_latch_t;
static press_latch_t latches[10];
static void petal_process(int index, uint32_t timestamp, int mode,
SemaphoreHandle_t lock);
static void petals_process(ad7147_chip_t *chip, uint32_t timestamp) {
for (int i = 0; i < chip->num_petals; i++) {
int petal = chip->petals[i];
petal_process(petal, timestamp, chip->modes[petal], chip->output_lock);
}
}
static void petals_clear(ad7147_chip_t *chip, uint32_t timestamp) {
for (int i = 0; i < chip->num_petals; i++) {
int petal = chip->petals[i];
petal_process(petal, timestamp, 0, chip->output_lock);
}
}
// DATASHEET VIOLATION 1
// target value that we ideally wanna see from an idle petal.
// this chip was designed for some sort of (plastic) case
// between electrode and finger so our signal is coming in
// super hot and we need the extended headroom. datasheet
// suggests to set this to halfpoint (32k).
static const int32_t _calib_target = 6000;
// this is what we assume one step in the chip's AFE
// parameter does to the output reading. this value is used
// in an iterative process so it doesn't have to be super
// precise but it helps to be in the ballpark. we thiink
// the real value is more like 970 but not sure how linear
// this is. anyways, calibration works reasonably well with
// this, let's never touch it again :D
static const int32_t _calib_incr_cap = 1000;
#define COMPLAIN(c, ...) \
do { \
if (!c->failed) { \
ESP_LOGE(TAG, __VA_ARGS__); \
c->failed = true; \
} \
} while (0)
// Length of sequence, assuming sequence is right-padded with -1.
static size_t _captouch_sequence_length(int8_t *sequence) {
for (size_t i = 0; i < 12; i++) {
if (sequence[i] == -1) {
#if defined(CONFIG_FLOW3R_HW_GEN_P3)
static const pad_mapping_t _map_top[12] = {
{ 0, petal_pad_tip }, // 0
{ 0, petal_pad_ccw }, // 1
{ 0, petal_pad_cw }, // 2
{ 8, petal_pad_cw }, // 3
{ 8, petal_pad_ccw }, // 4
{ 8, petal_pad_tip }, // 5
{ 4, petal_pad_tip }, // 6
{ 4, petal_pad_ccw }, // 7
{ 4, petal_pad_cw }, // 8
{ 6, petal_pad_cw }, // 9
{ 6, petal_pad_ccw }, // 10
{ 6, petal_pad_tip }, // 11
};
static const pad_mapping_t _map_bot[13] = {
{ 9, petal_pad_base }, // 0
{ 9, petal_pad_tip }, // 1
{ 7, petal_pad_base }, // 2
{ 7, petal_pad_tip }, // 3
{ 5, petal_pad_base }, // 4
{ 5, petal_pad_tip }, // 5
{ 3, petal_pad_tip }, // 6
{ 3, petal_pad_base }, // 7
{ 1, petal_pad_tip }, // 8
{ 1, petal_pad_base }, // 9
{ 2, petal_pad_tip }, // 10
{ 2, petal_pad_cw }, // 11
{ 2, petal_pad_ccw }, // 12
};
static gpio_num_t _interrupt_gpio_top = GPIO_NUM_15;
static gpio_num_t _interrupt_gpio_bot = GPIO_NUM_15;
static bool _interrupt_shared = true;
#elif defined(CONFIG_FLOW3R_HW_GEN_P4) || defined(CONFIG_FLOW3R_HW_GEN_C23)
static const pad_mapping_t _map_top[12] = {
{ 0, petal_pad_ccw }, // 0
{ 0, petal_pad_base }, // 1
{ 0, petal_pad_cw }, // 2
{ 8, petal_pad_cw }, // 3
{ 8, petal_pad_base }, // 4
{ 8, petal_pad_ccw }, // 5
{ 4, petal_pad_ccw }, // 6
{ 4, petal_pad_base }, // 7
{ 4, petal_pad_cw }, // 8
{ 6, petal_pad_ccw }, // 9
{ 6, petal_pad_base }, // 10
{ 6, petal_pad_cw }, // 11
};
static const pad_mapping_t _map_bot[13] = {
{ 9, petal_pad_base }, // 0
{ 9, petal_pad_tip }, // 1
{ 7, petal_pad_base }, // 2
{ 7, petal_pad_tip }, // 3
{ 5, petal_pad_base }, // 4
{ 5, petal_pad_tip }, // 5
{ 3, petal_pad_tip }, // 6
{ 3, petal_pad_base }, // 7
{ 1, petal_pad_tip }, // 8
{ 1, petal_pad_base }, // 9
{ 2, petal_pad_ccw }, // 10
{ 2, petal_pad_cw }, // 11
{ 2, petal_pad_base }, // 12
};
#if defined(CONFIG_FLOW3R_HW_GEN_P4)
static gpio_num_t _interrupt_gpio_top = GPIO_NUM_15;
static gpio_num_t _interrupt_gpio_bot = GPIO_NUM_15;
static bool _interrupt_shared = true;
#else
static gpio_num_t _interrupt_gpio_top = GPIO_NUM_15;
static gpio_num_t _interrupt_gpio_bot = GPIO_NUM_16;
static bool _interrupt_shared = false;
#endif
#else
#error "captouch not implemented for this badge generation"
#endif
static uint8_t get_petal_pad_ch(uint8_t petal, petal_kind_t kind) {
// returns the channel but not the chip. defaults to channel 0.
// pretty bad function but does the trick for now.
static uint8_t cache[40] = {
0,
};
int index = kind + 4 * petal;
if (cache[index]) return cache[index] - 1;
int len;
len = sizeof(_map_bot) / sizeof(pad_mapping_t);
for (int i = 0; i < len; i++) {
if (_map_bot[i].petal_number == petal && _map_bot[i].pad_kind == kind) {
cache[index] = i + 1;
return i;
}
}
len = sizeof(_map_top) / sizeof(pad_mapping_t);
for (int i = 0; i < len; i++) {
if (_map_top[i].petal_number == petal && _map_top[i].pad_kind == kind) {
cache[index] = i + 1;
return i;
}
}
return 12;
return 0; // should never be reached
}
// Request current sequence from captouch chip.
static esp_err_t _sequence_request(ad7147_chip_t *chip, bool reprogram) {
int8_t *seq = chip->sequences[chip->seq_position];
ad7147_sequence_t seq_out = {
.len = _captouch_sequence_length(seq),
};
for (size_t i = 0; i < seq_out.len; i++) {
int8_t channel = seq[i];
int8_t offset = chip->channels[channel].afe_offset;
seq_out.channels[i] = channel;
seq_out.pos_afe_offsets[i] = offset;
void _write_petal_mode_seq(uint16_t **write_head, uint8_t petal,
flow3r_bsp_captouch_petal_mode_t mode) {
if (petal & 1) {
switch (mode) {
case PETAL_MODE_OFF: // c is a clown language
break;
case PETAL_MODE_0D:
**write_head = 1 << get_petal_pad_ch(petal, petal_pad_base);
**write_head |= 1 << get_petal_pad_ch(petal, petal_pad_tip);
*write_head += 1;
break;
case PETAL_MODE_1D:
case PETAL_MODE_2D:
**write_head = 1 << get_petal_pad_ch(petal, petal_pad_base);
*write_head += 1; // the * is its little clown nose
**write_head = 1 << get_petal_pad_ch(petal, petal_pad_tip);
*write_head += 1;
break;
}
} else {
switch (mode) {
case PETAL_MODE_OFF:
break;
case PETAL_MODE_0D:
**write_head = 1 << get_petal_pad_ch(petal, petal_pad_base);
**write_head |= 1 << get_petal_pad_ch(petal, petal_pad_cw);
**write_head |= 1 << get_petal_pad_ch(petal, petal_pad_ccw);
*write_head += 1;
break; // it's good for when you want to
case PETAL_MODE_1D:
**write_head = 1 << get_petal_pad_ch(petal, petal_pad_base);
*write_head += 1;
**write_head = 1 << get_petal_pad_ch(petal, petal_pad_cw);
**write_head |= 1 << get_petal_pad_ch(petal, petal_pad_ccw);
*write_head += 1;
break;
case PETAL_MODE_2D: // be silly
**write_head = 1 << get_petal_pad_ch(petal, petal_pad_base);
*write_head += 1;
**write_head = 1 << get_petal_pad_ch(petal, petal_pad_cw);
*write_head += 1;
**write_head = 1 << get_petal_pad_ch(petal, petal_pad_ccw);
*write_head += 1;
break;
}
}
}
esp_err_t ret;
if ((ret = ad7147_hw_configure_stages(&chip->dev, &seq_out, reprogram)) !=
ESP_OK) {
return ret;
// hardcoding this one.
// first and last must be >= 7 bc i2c golf reasons.
// keeping petal 2 away from the swap helps w noise and/or our ocd a bit.
static const uint16_t _cursed_seq[] = { 1 << 8, 1 << 0, 1 << 1, 1 << 2,
1 << 3, 1 << 10, 1 << 11, 1 << 12,
1 << 4, 1 << 5, 1 << 6, 1 << 7,
1 << 9 };
static int _petal_modes_to_sequence(ad7147_chip_t *chip) {
uint16_t *write_head = chip->sequence;
for (int j = 0; j < chip->num_petals; j++) { // go thru bot chip petals
int petal = chip->petals[j];
_write_petal_mode_seq(&write_head, petal, chip->modes[petal]);
}
int len = write_head - chip->sequence;
assert(len < 14 || len >= 0);
memset(write_head, 0, (13 - len) * sizeof(uint16_t));
chip->cursed_active = len == 13;
if (chip->cursed_active) {
memcpy(chip->sequence, _cursed_seq, 13 * sizeof(uint16_t));
}
#ifdef FLOW3R_BSP_CAPTOUCH_DEBUG_SEQUENCING
write_head = chip->sequence;
printf("%s: applying %d-sequence: ", chip->name, len);
while ((write_head - chip->sequence) < 13)
printf("%d ", (int)(*write_head)), write_head++;
if (chip->cursed_active) printf(" (cursed sequence)");
printf("\n");
#endif
return len;
}
static ad7147_sequence_stage_t _cursed_swap_stage;
static inline int _mode_num_channels(flow3r_bsp_captouch_petal_mode_t mode) {
switch (mode) {
case PETAL_MODE_0D:
return 1;
case PETAL_MODE_1D:
return 2;
case PETAL_MODE_2D:
return 3;
default:
return 0;
}
return ESP_OK;
}
// Advance internal sequence pointer to next sequence. Returns true if advance
// occurred (in other words, false when there is only one sequence).
static bool _sequence_advance(ad7147_chip_t *chip) {
// Advance to next sequence.
size_t start = chip->seq_position;
chip->seq_position++;
if (chip->seq_position >= _AD7147_SEQ_MAX) {
chip->seq_position = 0;
static int _get_calib_data_index(ad7147_chip_t *chip, int i, int *petal_ret,
int *index_ret) {
assert(chip == &_top || chip == &_bot);
bool top = chip == &_top;
const pad_mapping_t *map = top ? _map_top : _map_bot;
int step = chip->sequence[i];
for (int j = 0; j < 13; j++) {
if (step & (1 << j)) {
int petal = map[j].petal_number;
int calib_index = _mode_num_channels(chip->modes[petal]) - 1;
if (calib_index < 0) continue;
if (calib_index) {
int offset = map[j].pad_kind;
if (petal & 1) {
if (offset == 3) offset = 1;
} else { // treat tip and base as same bc bw compat
if (offset == 3) offset = 0;
}
if (calib_index == 1 && offset > 1) offset = 1;
if (calib_index == 2) calib_index = 3;
calib_index += offset;
}
*petal_ret = petal;
*index_ret = calib_index;
return true;
}
}
return false;
}
void get_stage_hw_config(ad7147_chip_t *chip, ad7147_sequence_t *seq_out,
uint8_t i, uint16_t channel_mask) {
int offset = chip->stages[i].afe_offset;
offset = offset > (MAX_AFE) ? (MAX_AFE) : offset;
seq_out->stages[i].channel_mask = channel_mask;
// DATASHEET VIOLATION 2
// the datasheet recommends to connect captouch pads to the internal bias
// while they are not being measured. here's why we're not doing that:
//
// there was a strong cross talk issue on the bottom chip petals that
// varied with grounding setup (e.g., plugging in a usb cable and putting
// the other end in ur pocket changed behavior). we suspected that this
// might be due to a capacitive interaction between device ground, chip bias
// and chip shield driver. our wild theories were rewarded, and while
// introducing a bit of noise (well within budget, mind you) this resolved
// the issue.
//
// a few months later, a rare edge case was brought to our attention: when
// many channels on the top chip petals were saturated, similar cross talk
// could be generated. we applied the fix to the top chip too, and sure
// enough it resolved the issue. which makes sense except for fact that the
// top chip petals don't couple to a shield driver.
//
// we currently have no fully sensical mental model for why this works but
// that's okay.
// datasheet recommendation-ish (13-seq has hardcoded bits that violate
// this, change manually!)
// seq_out->stages[i].idle_to_bias = true;
// experiment A: only top pads
// seq_out->stages[i].idle_to_bias = !(chip->is_bot && (channel < 10));
// experiment B: only top chip pads
// seq_out->stages[i].idle_to_bias = !chip->is_bot;
// experiment C: none (winner)
seq_out->stages[i].idle_to_bias = false;
if (offset <= MAX_NEG_AFE) {
seq_out->stages[i].neg_afe_offset = offset;
seq_out->stages[i].pos_afe_offset = 0;
} else {
if (_captouch_sequence_length(chip->sequences[chip->seq_position]) ==
0) {
chip->seq_position = 0;
seq_out->stages[i].neg_afe_offset = MAX_NEG_AFE;
seq_out->stages[i].pos_afe_offset = offset - MAX_NEG_AFE;
}
}
return start != chip->seq_position;
static void _notify_from_isr(uint32_t mask, TaskHandle_t handle) {
if (handle == NULL) return;
BaseType_t xHigherPriorityTaskWoken;
xTaskNotifyFromISR(handle, mask, eSetBits, &xHigherPriorityTaskWoken);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
// Queue a calibration request until the next _chip_process call picks it up.
static void _calibration_request(ad7147_chip_t *chip) {
chip->calibration_pending = true;
static void _notify(uint32_t mask, TaskHandle_t handle) {
if (handle == NULL) return;
xTaskNotify(handle, mask, eSetBits);
portYIELD();
}
static int _uint16_sort(const void *va, const void *vb) {
uint16_t a = *((uint16_t *)va);
uint16_t b = *((uint16_t *)vb);
if (a < b) {
return -1;
static void _notify_both(uint32_t mask) {
_notify(mask, _top.task);
_notify(mask, _bot.task);
}
if (a > b) {
return 1;
// bad hack, see below
static esp_err_t _cursed_sequence_request(ad7147_chip_t *chip) {
uint16_t *seq = chip->sequence;
ad7147_sequence_t seq_out;
int petal, calib_index;
if (_get_calib_data_index(chip, 12, &petal, &calib_index)) {
chip->stages[12].amb = _chip_calibration_data[petal].amb[calib_index];
chip->stages[12].afe_offset =
_chip_calibration_data[petal].afe[calib_index];
chip->stages[0].amb = _chip_calibration_data[petal].amb[calib_index];
chip->stages[0].afe_offset =
_chip_calibration_data[petal].afe[calib_index];
}
return 0;
get_stage_hw_config(chip, &seq_out, 0, seq[12]);
memcpy(&_cursed_swap_stage, &(seq_out.stages[0]),
sizeof(ad7147_sequence_stage_t));
return ESP_OK;
}
// This takes a sequence of stages from the chip config, gets
// the configuration data for the individual stages
// and writes it to the respective captouch chip.
// In case of the bottom chip we request a 13-sequence, so that's
// not possible, so we use a hardcoded hack to save the 13th
// sequence step configuration data for later use.
static void _sequence_request(ad7147_chip_t *chip, bool new_modes) {
if (new_modes) {
chip->len_sequence = _petal_modes_to_sequence(chip);
#ifdef FLOW3R_BSP_CAPTOUCH_DEBUG_PROFILING
} else {
uint16_t prev_seq[13];
memcpy(prev_seq, chip->sequence, sizeof(chip->sequence));
_petal_modes_to_sequence(chip);
if (memcmp(prev_seq, chip->sequence, sizeof(chip->sequence))) {
printf("sequence mismatch!\n");
}
#endif
}
int len = chip->len_sequence;
uint16_t *seq = chip->sequence;
// Calculate median of 16 measurements.
static uint16_t _average_calib_measurements(uint16_t *measurements) {
qsort(measurements, _AD7147_CALIB_CYCLES, sizeof(uint16_t), _uint16_sort);
size_t ix = _AD7147_CALIB_CYCLES / 2;
return measurements[ix];
if (chip->cursed_active) {
_cursed_sequence_request(chip);
len = 12;
}
ad7147_sequence_t seq_out = {
.len = len,
.interrupt_stage = 0,
};
for (int i = 0; i < len; i++) {
int petal, calib_index;
assert(_get_calib_data_index(chip, i, &petal, &calib_index));
chip->stages[i].amb = _chip_calibration_data[petal].amb[calib_index];
chip->stages[i].afe_offset =
_chip_calibration_data[petal].afe[calib_index];
}
for (size_t i = 0; i < seq_out.len; i++) {
get_stage_hw_config(chip, &seq_out, i, seq[i]);
}
static size_t _channel_from_readout(const ad7147_chip_t *chip, size_t ix) {
size_t six = chip->seq_position;
const int8_t *seq = chip->sequences[six];
assert(seq[ix] >= 0);
return seq[ix];
esp_err_t ret;
if ((ret = ad7147_hw_configure_stages(&chip->dev, &seq_out)) != ESP_OK) {
ESP_LOGE(TAG, "%s: requesting next sequence failed: %s", chip->name,
esp_err_to_name(ret));
}
if (!len) {
petals_clear(chip, esp_timer_get_time());
}
}
// Check if a channel's AFE offset can be tweaked to reach a wanted amb value.
// True is returned if a tweak was performed, false otherwise.
static bool _channel_afe_tweak(ad7147_chip_t *chip, size_t cix) {
int32_t cur = chip->channels[cix].amb;
static bool _stage_afe_tweak(ad7147_chip_t *chip, size_t cix) {
int32_t cur = chip->stages[cix].amb;
int32_t target = _calib_target;
int32_t diff = (cur - target) / _calib_incr_cap;
if (diff < 1 && diff > -1) {
// Close enough.
return false;
}
int32_t offset = chip->channels[cix].afe_offset;
int32_t offset = chip->stages[cix].afe_offset;
if (offset <= 0 && diff < 0) {
// Saturated, can't do anything.
return false;
}
if (offset >= 63 && diff > 0) {
// Saturated, can't do anything.
if (offset >= (MAX_AFE) && diff > 0) {
return false;
}
offset += diff;
if (offset < 0) {
offset = 0;
}
if (offset > 63) {
offset = 63;
if (offset > (MAX_AFE)) {
offset = (MAX_AFE);
}
chip->channels[cix].afe_offset = offset;
chip->stages[cix].afe_offset = offset;
return true;
}
// Called when a sequence is completed by the low-level layer.
static void _on_data(void *user, uint16_t *data, size_t len) {
ad7147_chip_t *chip = (ad7147_chip_t *)user;
// Takes data from captouch chip readout, looks up which petal pad
// it belongs to according to the chip map and puts it there.
// May need to take lock for raw_petals access depending on circumstances
// (atm just for bottom chip).
// Should maybe get a proper name someday. Sorry. Only used by
// raw_data_to_petal_pads atm, maybe it should just absorb it, it's
// not that big.
static void _on_chip_data(ad7147_chip_t *chip, uint16_t *values, int len) {
assert(chip == &_top || chip == &_bot);
bool top = chip == &_top;
const pad_mapping_t *map = top ? _map_top : _map_bot;
if (chip->calibration_cycles > 0) {
// We're doing a calibration cycle on our channels. Instead of writing
// the data to channel->cdc, write it to channel->amb_meas.
size_t j = chip->calibration_cycles - 1;
for (size_t i = 0; i < len; i++) {
chip->channels[_channel_from_readout(chip, i)].amb_meas[j] =
data[i];
for (int i = 0; i < len; i++) {
int step = chip->sequence[i];
int num_fields = 0;
int fields[3];
for (int j = 0; j < (top ? 12 : 13); j++) {
if (step & (1 << j)) {
fields[num_fields] = j;
num_fields++;
if (num_fields == 3) break;
}
}
if (!num_fields) continue;
int value = values[i] / num_fields;
for (int k = 0; k < num_fields; k++) {
int petal = map[fields[k]].petal_number;
int pad = map[fields[k]].pad_kind;
if (petal >= 10 || petal < 0 || pad >= 4 || pad < 0) {
ESP_LOGE(TAG, "out of bounds at petal %d pad %d stage %d\n",
petal, pad, i);
} else {
// Normal measurement, apply to channel->cdc.
for (size_t i = 0; i < len; i++) {
chip->channels[_channel_from_readout(chip, i)].cdc = data[i];
raw_petals[petal][pad] = value;
}
}
}
}
bool reprogram = _sequence_advance(chip);
bool tweak = false;
// Synchronize on beginning of sequence for calibration logic.
if (chip->seq_position == 0) {
// Deal with calibration pending flag, possibly starting calibration.
if (chip->calibration_pending) {
if (chip->calibration_cycles == 0) {
ESP_LOGI(TAG, "%s: calibration starting...", chip->name);
chip->calibration_cycles = _AD7147_CALIB_CYCLES;
// lazy copypasta code :3
static void _on_chip_calib_data(ad7147_chip_t *chip, uint16_t *amb,
uint16_t *afe, size_t len) {
for (int i = 0; i < len; i++) {
int petal, calib_index;
assert(_get_calib_data_index(chip, i, &petal, &calib_index));
_chip_calibration_data[petal].amb[calib_index] = amb[i];
_chip_calibration_data[petal].afe[calib_index] = afe[i];
}
chip->calibration_pending = false;
}
static void raw_data_to_calib(ad7147_chip_t *chip, uint16_t *data, size_t len) {
if (chip->calibration_cycles > 0) {
// We're doing a calibration cycle on our channels. Instead of
// writing the data to channel->cdc, write it to channel->amb_meas.
int cycle = chip->calibration_cycles - 1;
if (cycle < _AD7147_CALIB_CYCLES) { // throw away first few points
for (int i = 0; i < len; i++) {
chip->stages[i].amb_meas[cycle] = data[i];
}
}
}
// Deal with active calibration.
chip->calibration_cycles--;
if (chip->calibration_cycles == 0) {
if (chip->calibration_cycles <= 0) {
// Calibration measurements done. Calculate average amb data for
// each channel.
for (size_t i = 0; i < chip->nchannels; i++) {
uint16_t avg =
_average_calib_measurements(chip->channels[i].amb_meas);
chip->channels[i].amb = avg;
}
char msg[256];
char *wr = msg;
for (size_t i = 0; i < chip->nchannels; i++) {
if (wr != msg) {
wr += snprintf(wr, 256 - (wr - msg), ", ");
}
wr += snprintf(wr, 256 - (wr - msg), "%04d/%02d",
chip->channels[i].amb,
chip->channels[i].afe_offset);
uint16_t amb[13];
uint16_t afe[13];
uint16_t rerun = 0;
for (size_t i = 0; i < len; i++) {
uint32_t avg = 0;
for (uint8_t j = 0; j < _AD7147_CALIB_CYCLES; j++) {
avg += chip->stages[i].amb_meas[j];
}
ESP_LOGD(TAG, "%s: calibration: %s.", chip->name, msg);
chip->stages[i].amb = avg / _AD7147_CALIB_CYCLES;
// Can we tweak the AFE to get a better measurement?
uint16_t rerun = 0;
for (size_t i = 0; i < chip->nchannels; i++) {
tweak = _channel_afe_tweak(chip, i);
if (tweak) {
if (_stage_afe_tweak(chip, i)) {
rerun |= (1 << i);
}
amb[i] = chip->stages[i].amb;
afe[i] = chip->stages[i].afe_offset;
}
_on_chip_calib_data(chip, amb, afe, len);
if (rerun != 0) {
// Rerun calibration again,
ESP_LOGI(TAG,
"%s: calibration done, but can do better (%04x). "
"Retrying.",
chip->name, rerun);
chip->calibration_cycles = _AD7147_CALIB_CYCLES;
} else {
ESP_LOGI(TAG, "%s: calibration done.", chip->name);
chip->calibration_cycles = _AD7147_CALIB_CYCLES + 5;
_notify(NOTIF_INTERNAL_CALIB_CHANGE, chip->task);
#ifdef FLOW3R_BSP_CAPTOUCH_DEBUG_CALIBRATION
printf("%s calibration stage %d: repeating ", chip->name,
chip->calibration_stage);
for (int i = 0; i < 13; i++) {
if (rerun & 1 << i) {
printf("%d, ", i);
}
}
printf(" (%d, %d)\n", (int)rerun, (int)len);
for (int i = 0; i < 13; i++) {
if (rerun & 1 << i) {
printf(" %s stage %d: amb %d, afe %d\n", chip->name, i,
(int)chip->stages[i].amb,
(int)chip->stages[i].afe_offset);
}
}
#endif
} else {
#ifdef FLOW3R_BSP_CAPTOUCH_DEBUG_CALIBRATION
printf("%s calibration stage %d: done\n", chip->name,
chip->calibration_stage);
for (int i = 0; i < len; i++) {
printf(" %s stage %d: amb %d, afe %d\n", chip->name, i,
(int)chip->stages[i].amb,
(int)chip->stages[i].afe_offset);
}
#endif
chip->calibration_stage_active = false;
ad7147_chip_t *other = chip == &_top ? &_bot : &_top;
_notify(NOTIF_INTERNAL_CALIB_NEXT_STAGE, other->task);
ESP_LOGI(TAG, "%s: calibration stage done.", chip->name);
}
}
}
static void raw_data_to_petal_pads(ad7147_chip_t *chip, uint16_t *data,
size_t len) {
// Normal measurement, apply to channel->cdc.
for (size_t i = 0; i < len; i++) {
chip->stages[i].cdc = data[i];
}
// Submit data to higher level for processing.
if (chip->callback != NULL) {
uint16_t val[13];
for (size_t i = 0; i < chip->nchannels; i++) {
int32_t cdc = chip->channels[i].cdc;
int32_t amb = chip->channels[i].amb;
for (size_t i = 0; i < len; i++) {
int32_t cdc = chip->stages[i].cdc;
int32_t amb = chip->stages[i].amb;
int32_t diff = cdc - amb;
if (diff < 0) {
val[i] = 0;
} else if (diff > 65535) {
val[i] = 65535;
val[i] = diff < 0 ? 0 : (diff > 65535 ? 65535 : diff);
}
_on_chip_data(chip, val, len);
}
// (sunshine emoji) tell the captouch task that top chip data is available :D
static void _top_isr(void *data) {
_notify_from_isr(NOTIF_GPIO, _top_task_handle);
}
// (dark cloud emoji) tell the cursed task that it is time for THE PROCEDURE
static void _bot_isr(void *data) {
_notify_from_isr(NOTIF_GPIO, _bot_task_handle);
}
typedef struct {
uint16_t buffer[13];
uint16_t buffer_len;
uint16_t reject;
// normal process only
uint16_t previously_filled;
uint16_t interrupt_stage;
// cursed process only
uint16_t step;
} _chip_process_data_t;
static void _chip_process_reset(_chip_process_data_t *process_data) {
process_data->previously_filled = 0;
process_data->interrupt_stage = 0;
process_data->step = 0;
process_data->buffer_len = 0;
process_data->reject = 2;
}
#ifdef FLOW3R_BSP_CAPTOUCH_DEBUG_CURSED_PROFILING
static int64_t _cursed_step_time = 0;
static uint32_t _cursed_step_to_step_time[4];
static uint32_t _cursed_step_execution_time[4];
#endif
// THE PROCEDURE
// we need to reconfigure the bottom chip on the fly to read all 13 channels.
// this here is pretty much a shim between the bottom chip isr and the main
// captouch task that manages the i2c traffic to the bottom chip as well as
// poking the main captouch task when data is ready.
// this is kinda sensitive and overall weird so we keep our lil crappy profiler
// hooked up for now, we're sure we'll need it in the future again.
static bool _cursed_chip_process(ad7147_chip_t *chip, uint32_t *timestamp,
_chip_process_data_t *process_data) {
ad7147_hw_t *device = &chip->dev;
uint16_t st = 0;
#ifdef FLOW3R_BSP_CAPTOUCH_DEBUG_CURSED_PROFILING
int64_t time = esp_timer_get_time();
#endif
// this boi clears the interrupt flag of the captouch chip so it must
// run _every time_ we receive an interrupt. &st tells us which stages
// have been completed since the last call.
if (!ad7147_hw_get_and_clear_completed(device, &st)) {
return false;
}
// let's pretend for fun that channel0 is read by stage0 and so forth.
// makes describing this a lot easier.
// also i2c traffic functions are highly golfed, pls don't tear them apart
// it saves like 1% cpu so be cool~
switch (process_data->step) {
case 0:
// read all 12 "regular" channels into the array
if (!ad7147_hw_get_cdc_data(device, process_data->buffer, 12)) {
return false;
}
process_data->buffer_len = 12;
// reconfigures stage0 to channel 13 config, set up sequencer
// to loop only stage0 (<-actually a lie but dw abt it~)
if (!ad7147_hw_modulate_stage0_and_reset(device,
&_cursed_swap_stage)) {
return false;
}
// clear stray freertos interrupts, then clear hw interrupts.
// must be done in that order.
xTaskNotifyStateClear(NULL);
if (!ad7147_hw_get_and_clear_completed(device, &st)) {
return false;
}
break;
// case 1: the data right after reconfiguration might be junk
// so we wait for another cycle.
case 2:
// grab data for channel 13
if (!ad7147_hw_get_cdc_data(device, &(process_data->buffer[12]),
1)) {
return false;
}
*timestamp = esp_timer_get_time();
// reconfigure stage0 to channel 0 config, set up sequencer
// to loop all stages
if (!ad7147_hw_modulate_stage0_and_reset(device, NULL)) {
return false;
}
// clear stray freertos interrupts, then clear hw interrupts.
// must be done in that order.
xTaskNotifyStateClear(NULL);
if (!ad7147_hw_get_and_clear_completed(device, &st)) {
return false;
}
if (process_data->buffer_len != 12) {
process_data->step = 0;
return false;
}
process_data->buffer_len = 13;
break;
// case 3:
// "whoa whoa whoa if you do the same here as with case 1
// you'd wait for the whole 12-sequence without any good
// reason!"
// observant, but there's a hidden trick! both case2->case3 and
// case 3->case0 have the sequencer configure to 12 steps but
// consider: case 2 resets to stage0 (only stage we can reset to,
// remember?), and the next interrupt is triggered once that is
// complete! that is the magic of ISR trigger reconf laziness!
}
#ifdef FLOW3R_BSP_CAPTOUCH_DEBUG_CURSED_PROFILING
_cursed_step_to_step_time[process_data->step] = time - _cursed_step_time;
_cursed_step_time = esp_timer_get_time();
_cursed_step_execution_time[process_data->step] = _cursed_step_time - time;
#endif
process_data->step = (process_data->step + 1) % 4;
return !process_data->step;
}
static bool _chip_process(ad7147_chip_t *chip, uint32_t *timestamp,
_chip_process_data_t *process_data) {
if (chip->cursed_active)
return _cursed_chip_process(chip, timestamp, process_data);
ad7147_hw_t *device = &chip->dev;
// Read complete status register. This acknowledges interrupts.
uint16_t st = 0;
if (!ad7147_hw_get_and_clear_completed(device, &st)) {
return false;
}
// Nothing to do if no stages are expected to be read.
if (device->num_stages < 1) {
return false;
}
int count = device->num_stages;
process_data->previously_filled |= st;
if (process_data->previously_filled < (1 << count) - 1) {
return false;
}
if (!ad7147_hw_get_cdc_data(device, process_data->buffer, count)) {
return false;
}
*timestamp = esp_timer_get_time();
// so here's another curveball: we can't really lock on the output register
// of the captouch driver, it just keeps writing to it, so we get FUTURE
// DATA, whoa! this is actually bad because you may receive the same NO MORE
// FUTURE BUT NOW PRESENT DATA in the next round, because if you do any sort
// of velocity calculation this will bite u ^w^.
// we'd love to use the reset trick from the cursed sequence here, but turns
// out the jank behaves slightly different and procudes twitches on the
// 11th/last channel. so we're chasing st instead by moving around the
// interrupt stage. fun :3. this is actually faster than the reset sequence.
// and yeeeah for some applications future data is fine, and then we're
// sacrificing precious cycles here. but it's typically less than a ms. it's
// okay. it's the better default. also it's silly code :3
if (!ad7147_hw_get_and_clear_completed(device, &st)) return false;
st = st & ((1 << count) - 1); // sanitize
if (st) {
int new_interrupt_stage = -1;
for (int i = 0; i < count; i++) {
int stage = (count + process_data->interrupt_stage - i) % count;
if (st & 1 << stage) {
new_interrupt_stage = stage;
break;
}
}
if (new_interrupt_stage < 0) {
ESP_LOGE(TAG, "bad stage vector");
}
// there is a question to be asked if we gain anything by not setting
// the interrupt to "slice apart" petals. due to random timing between
// isr receive and us grabbing the data it's a bit unpredictable, but
// we'd definitely catch much less ~positional data temporal
// dyslocation~ phenomena :3. but it'd be slower. and probably not super
// duper reliable. we think we wanna be lazy here and argue that we care
// most about the minimum data quality, which does not change from
// adding this. we get some datarate++ in return. yay datarate!
if (new_interrupt_stage != process_data->interrupt_stage) {
if (!ad7147_hw_override_interrupt_stage(
device, process_data->interrupt_stage))
return false;
process_data->interrupt_stage = new_interrupt_stage;
}
if (!ad7147_hw_get_and_clear_completed(device, &st)) return false;
if (st >= (1 << count) - 1) _notify(NOTIF_GPIO, chip->task);
}
process_data->buffer_len = count;
process_data->previously_filled = st;
return true;
}
static bool _chip_process_kickstart(ad7147_chip_t *chip) {
ad7147_hw_t *device = &chip->dev;
uint16_t st = 0;
if (!ad7147_hw_get_and_clear_completed(device, &st)) {
ESP_LOGE(TAG, "kickstart failed");
return false;
}
return true;
}
#ifdef FLOW3R_BSP_CAPTOUCH_DEBUG_PROFILING
typedef struct {
uint32_t timestamps[100];
uint32_t index;
ad7147_chip_t *chip;
} _profiler_t;
#ifdef FLOW3R_BSP_CAPTOUCH_DEBUG_CURSED_PROFILING
static void _cursed_profiler_run() {
for (uint16_t i = 0; i < 4; i++) {
uint16_t k = (i + 3) % 4;
printf("last bot step %u to step %u time: %luus\n", k, i,
_cursed_step_to_step_time[i]);
}
for (uint16_t i = 0; i < 4; i++) {
printf("last bot step %u execution time: %luus\n", i,
_cursed_step_execution_time[i]);
}
}
#endif
static void _profiler_run(_profiler_t *self, uint32_t timestamp) {
if (self->index < 100) {
self->timestamps[self->index] = timestamp;
self->index++;
} else {
uint32_t avg = self->timestamps[99] - self->timestamps[3];
avg /= (99 - 3);
uint32_t min = UINT32_MAX;
uint32_t max = 0;
for (int i = 3; i < 99; i++) {
uint32_t time = self->timestamps[i + 1] - self->timestamps[i];
if (time > max) max = time;
if (time < min) min = time;
}
if (chip->is_bot) {
printf(
"cycle time bot [us]: | %5lu %5lu "
"%5lu\n",
min, avg, max);
#ifdef FLOW3R_BSP_CAPTOUCH_DEBUG_CURSED_PROFILING
if (chip->cursed_active) {
_cursed_profiler_run();
}
#endif
} else {
printf("cycle time top [us]: %5lu %5lu %5lu |\n", min, avg,
max);
}
self->index = 0;
}
}
#endif
static void _calibration_init_next_stage(ad7147_chip_t *chip,
_chip_process_data_t *process_data) {
chip->calibration_proceed = false;
int stage = chip->calibration_stage - 1;
if (stage > 0) {
#ifdef FLOW3R_BSP_CAPTOUCH_DEBUG_CALIBRATION
printf("%s: calibration stage %d\n", chip->name, stage);
#endif
chip->calibration_active = true;
flow3r_bsp_captouch_petal_mode_t modes[10];
for (int i = 0; i < 10; i++) {
int limit = 3 - (i & 1);
modes[i] = stage > limit ? limit : stage;
}
chip->calibration_stage = stage;
chip->calibration_stage_active = true;
chip->calibration_cycles = _AD7147_CALIB_CYCLES + 5;
memcpy(chip->modes, modes, sizeof(chip->modes));
_sequence_request(chip, true);
_chip_process_reset(process_data);
_chip_process_kickstart(chip);
} else {
if (stage < 0) {
// restore previous calibration
_notify(NOTIF_CALIB_CHANGE, chip->task);
#ifdef FLOW3R_BSP_CAPTOUCH_DEBUG_CALIBRATION
printf("%s: calibration stopped\n", chip->name);
#endif
} else {
// need to hold the lock for checking notifs
xSemaphoreTake(calibration_lock, portMAX_DELAY);
uint32_t notif;
// it's okay, we're not clearing any and make it pending later with
// NOTIF_MODE_CHANGE
if ((xTaskNotifyWait(0, 0, &notif, 0) == pdTRUE) &&
(notif & NOTIF_CALIB_CHANGE)) {
#ifdef FLOW3R_BSP_CAPTOUCH_DEBUG_CALIBRATION
printf(
"%s: calibration data ignored because of pending user "
"data\n",
chip->name);
#endif
} else {
memcpy(&calibration_data, &_chip_calibration_data,
sizeof(ad7147_petal_calib_t) * 10);
#ifdef FLOW3R_BSP_CAPTOUCH_DEBUG_CALIBRATION
printf("%s: calibration done\n", chip->name);
#endif
}
xSemaphoreGive(calibration_lock);
}
chip->calibration_stage = 0;
chip->calibration_stage_active = false;
chip->calibration_cycles = 0;
chip->calibration_active = false;
_chip_process_reset(process_data);
_notify(NOTIF_MODE_CHANGE, chip->task);
}
}
static void _task(ad7147_chip_t *chip) {
assert(chip == &_bot || chip == &_top);
uint32_t timestamp = 0;
_chip_process_data_t process_data;
_chip_process_reset(&process_data);
#ifdef FLOW3R_BSP_CAPTOUCH_DEBUG_PROFILING
_profiler_t profiler = { index = 0, chip = chip };
#endif
for (;;) {
uint32_t notif;
if (xTaskNotifyWait(0, NOTIF_CLEAR_MASK, &notif, portMAX_DELAY) ==
pdFALSE) {
ESP_LOGE(TAG, "%s: Notification receive failed", chip->name);
continue;
}
if (notif & NOTIF_CALIB_CHANGE) {
xSemaphoreTake(calibration_lock, portMAX_DELAY);
memcpy(&_chip_calibration_data, &calibration_data,
sizeof(ad7147_petal_calib_t) * 10);
xSemaphoreGive(calibration_lock);
}
if (notif & (NOTIF_CALIB_STOP | NOTIF_CALIB_CHANGE)) {
if (chip->calibration_active) {
chip->calibration_stage = -1;
_calibration_init_next_stage(chip, &process_data);
}
// drop NOTIF_CALIB_START if _STOP or _CHANGE have been received in
// the same notif
} else if (notif & NOTIF_CALIB_START) {
chip->calibration_active = true;
// we just wanna bonk the lock to make sure nobody is holding it
xSemaphoreBonk(calibration_lock, portMAX_DELAY);
petals_clear(chip, esp_timer_get_time());
#ifdef FLOW3R_BSP_CAPTOUCH_DEBUG_CALIBRATION
printf("%s: starting calibration stage\n", chip->name);
#endif
chip->calibration_stage = 4;
_calibration_init_next_stage(chip, &process_data);
// drop _NEXT_STAGE if (see above)
} else if (notif & NOTIF_INTERNAL_CALIB_NEXT_STAGE) {
chip->calibration_proceed = true;
}
if (chip->calibration_proceed && (!chip->calibration_stage_active)) {
_calibration_init_next_stage(chip, &process_data);
}
if (notif & NOTIF_GPIO) {
bool new_data = _chip_process(chip, &timestamp, &process_data);
if (new_data) {
if (process_data.reject > 0) {
process_data.reject -= 1;
new_data = false;
}
}
if (new_data) {
if (chip->calibration_stage_active) {
raw_data_to_calib(chip, process_data.buffer,
process_data.buffer_len);
}
if (!chip->calibration_active) {
raw_data_to_petal_pads(chip, process_data.buffer,
process_data.buffer_len);
petals_process(chip, timestamp);
#ifdef FLOW3R_BSP_CAPTOUCH_DEBUG_PROFILING
// not running this during calibration bc it's annoying
_profiler_run(&profiler, timestamp);
#endif
}
process_data.buffer_len = 0;
}
}
if (notif & (NOTIF_MODE_CHANGE | NOTIF_CALIB_CHANGE |
NOTIF_INTERNAL_CALIB_CHANGE)) {
bool new_modes = notif & NOTIF_MODE_CHANGE;
if (new_modes) {
xSemaphoreTake(chip->user_lock, portMAX_DELAY);
new_modes =
memcmp(chip->modes, chip->user_modes, sizeof(chip->modes));
if (new_modes) {
memcpy(chip->modes, chip->user_modes, sizeof(chip->modes));
}
xSemaphoreGive(chip->user_lock);
}
_sequence_request(chip, new_modes);
_chip_process_reset(&process_data);
_chip_process_kickstart(chip);
}
}
}
static void _bot_task(void *data) {
(void)data;
_task(&_bot);
}
static void _top_task(void *data) {
(void)data;
_task(&_top);
}
void flow3r_bsp_ad7147_get_petal_modes(flow3r_bsp_captouch_petal_mode_t *data) {
memcpy(data, _petal_modes, sizeof(_petal_modes));
}
static void _set_petal_modes(flow3r_bsp_captouch_petal_mode_t *data) {
for (int i = 0; i < 2; i++) {
ad7147_chip_t *chip = i ? &_bot : &_top;
xSemaphoreTake(chip->user_lock, portMAX_DELAY);
memcpy(chip->user_modes, data, sizeof(chip->user_modes));
xSemaphoreGive(chip->user_lock);
_notify(NOTIF_MODE_CHANGE, chip->task);
}
}
void flow3r_bsp_ad7147_set_petal_modes(flow3r_bsp_captouch_petal_mode_t *data) {
memcpy(_petal_modes, data, sizeof(_petal_modes));
_set_petal_modes(_petal_modes);
}
void flow3r_bsp_ad7147_calibrate() {
// the notification would set them as soon as it is processed
// but we do want those flags earlier
// would be nice if we could just read the notification vector
_bot.calibration_active = true;
_top.calibration_active = true;
_notify_both(NOTIF_CALIB_START);
}
int flow3r_bsp_ad7147_calibrating() {
if (_bot.calibration_active || _top.calibration_active) {
return _bot.calibration_stage > _top.calibration_stage
? _bot.calibration_stage
: _top.calibration_stage;
}
return 0;
}
bool flow3r_bsp_ad7147_get_calibration_data(int32_t *data) {
if (_top.calibration_active || _bot.calibration_active) return false;
xSemaphoreTake(calibration_lock, portMAX_DELAY);
for (int petal = 0; petal < 10; petal++) {
for (int calib_index = 0; calib_index < 6; calib_index++) {
int data_index = petal * 12 + calib_index * 2;
if ((petal & 1) && calib_index >= 3) {
data[data_index] = 0;
data[data_index + 1] = 0;
} else {
val[i] = diff;
data[data_index] = calibration_data[petal].amb[calib_index];
data[data_index + 1] = calibration_data[petal].afe[calib_index];
}
}
}
xSemaphoreGive(calibration_lock);
return true;
}
static uint16_t amb_limit(int32_t data) {
return data > 65535 ? 65535 : (data < 0 ? 0 : data);
}
static uint8_t afe_limit(int32_t data) {
return data > (MAX_AFE) ? (MAX_AFE) : (data < 0 ? 0 : data);
}
void flow3r_bsp_ad7147_set_calibration_data(int32_t *data) {
xSemaphoreTake(calibration_lock, portMAX_DELAY);
for (int petal = 0; petal < 10; petal++) {
for (int calib_index = 0; calib_index < 6; calib_index++) {
int data_index = petal * 12 + calib_index * 2;
if (!((petal & 1) && calib_index >= 3)) {
calibration_data[petal].amb[calib_index] =
amb_limit(data[data_index]);
calibration_data[petal].afe[calib_index] =
afe_limit(data[data_index + 1]);
}
}
chip->callback(chip->user, val, chip->nchannels);
}
// we must notify while holding the lock so if the calibration has
// not stopped yet it will not write its results to calibration_data
_notify_both(NOTIF_CALIB_CHANGE);
xSemaphoreGive(calibration_lock);
}
void flow3r_bsp_ad7147_get(flow3r_bsp_captouch_data_t *dest) {
xSemaphoreTakeCaptouchOutput(portMAX_DELAY);
memcpy(dest, &captouch_data, sizeof(captouch_data));
xSemaphoreGiveCaptouchOutput();
}
// _sequence_request also writes the AFE registers which just got tweaked
if (reprogram || tweak) {
void flow3r_bsp_ad7147_refresh_events() {
xSemaphoreTakeCaptouchOutput(portMAX_DELAY);
for (uint8_t i = 0; i < 10; i++) {
captouch_data.petals[i].press_event = latches[i].press_event_new;
latches[i].fresh = true;
}
xSemaphoreGiveCaptouchOutput();
}
esp_err_t flow3r_bsp_ad7147_chip_init(ad7147_chip_t *chip) {
esp_err_t ret;
if ((ret = _sequence_request(chip, reprogram)) != ESP_OK) {
COMPLAIN(chip, "%s: requesting next sequence failed: %s",
chip->name, esp_err_to_name(ret));
for (size_t i = 0; i < 13; i++) {
chip->stages[i].amb = 0;
}
if ((ret = ad7147_hw_init(&chip->dev)) != ESP_OK) {
return ret;
}
return ESP_OK;
}
esp_err_t _gpio_interrupt_setup(gpio_num_t num, gpio_isr_t isr) {
esp_err_t ret;
gpio_config_t io_conf = {
.intr_type = GPIO_INTR_NEGEDGE,
.mode = GPIO_MODE_INPUT,
.pull_up_en = true,
.pin_bit_mask = (1 << num),
};
if ((ret = gpio_config(&io_conf)) != ESP_OK) {
return ret;
}
if ((ret = gpio_isr_handler_add(num, isr, NULL)) != ESP_OK) {
return ret;
}
return ESP_OK;
}
void assertSemaphoreCreateMutex(SemaphoreHandle_t *target) {
assert(*target == NULL);
*target = xSemaphoreCreateMutex();
assert(*target != NULL);
}
esp_err_t flow3r_bsp_ad7147_init() {
assertSemaphoreCreateMutex(&calibration_lock);
for (int i = 0; i < 2; i++) {
ad7147_chip_t *chip = i ? &_top : &_bot;
assertSemaphoreCreateMutex(&chip->output_lock);
assertSemaphoreCreateMutex(&chip->user_lock);
chip->dev.dev_config.decimation = 0b10;
memcpy(chip->user_modes, _petal_modes, sizeof(chip->user_modes));
}
esp_err_t flow3r_bsp_ad7147_chip_init(ad7147_chip_t *chip,
flow3r_i2c_address address) {
esp_err_t ret;
for (size_t i = 0; i < chip->nchannels; i++) {
chip->channels[i].amb = 0;
for (int i = 0; i < 10; i++) {
captouch_data.petals[i].index = i;
}
if ((ret = ad7147_hw_init(&chip->dev, address, _on_data, chip)) != ESP_OK) {
_top.dev.addr = flow3r_i2c_addresses.touch_top;
_bot.dev.addr = flow3r_i2c_addresses.touch_bottom;
xTaskCreate(&_top_task, "captouch-top", 4096, NULL,
configMAX_PRIORITIES - 2, &_top_task_handle);
xTaskCreate(&_bot_task, "captouch-bot", 4096, NULL,
configMAX_PRIORITIES - 2, &_bot_task_handle);
_top.task = _top_task_handle;
_bot.task = _bot_task_handle;
if ((ret = flow3r_bsp_ad7147_chip_init(&_top)) != ESP_OK) {
return ret;
}
_calibration_request(chip);
if ((ret = _sequence_request(chip, false)) != ESP_OK) {
if ((ret = flow3r_bsp_ad7147_chip_init(&_bot)) != ESP_OK) {
return ret;
}
if ((ret = gpio_install_isr_service(ESP_INTR_FLAG_SHARED |
ESP_INTR_FLAG_LOWMED)) != ESP_OK) {
ESP_LOGE(TAG, "Failed to install GPIO ISR service");
return ret;
}
if ((ret = _gpio_interrupt_setup(_interrupt_gpio_bot, _bot_isr)) !=
ESP_OK) {
ESP_LOGE(TAG, "Failed to add bottom captouch ISR");
return ret;
}
if (!_interrupt_shared) {
// On badges with shared interrupts, only install the 'bot' ISR as a
// shared ISR.
if ((ret = _gpio_interrupt_setup(_interrupt_gpio_top, _top_isr)) !=
ESP_OK) {
ESP_LOGE(TAG, "Failed to add top captouch ISR");
return ret;
}
}
flow3r_bsp_ad7147_calibrate();
ESP_LOGI(TAG, "Captouch initialized");
return ESP_OK;
}
esp_err_t flow3r_bsp_ad7147_chip_process(ad7147_chip_t *chip) {
return ad7147_hw_process(&chip->dev);
// roughly matches the behavior of the legacy api. someday we should have more
// meaningful output units.
#define TOP_PETAL_THRESHOLD 8000
#define BOTTOM_PETAL_THRESHOLD 12000
#define PETAL_HYSTERESIS 1000
#define PETAL_TOP_GAIN 5300
#define PETAL_TOP_2_GAIN 6000
#define PETAL_BOT_GAIN 6500
static inline int16_t clip_to_int16(int32_t num) {
return (num > 32767 ? 32767 : (num < -32768 ? -32768 : num));
}
static int32_t top_petal_filter[10];
static int32_t petal_pos_gain[10] = {
PETAL_TOP_GAIN, PETAL_BOT_GAIN, PETAL_TOP_2_GAIN, PETAL_BOT_GAIN,
PETAL_TOP_GAIN, PETAL_BOT_GAIN, PETAL_TOP_GAIN, PETAL_BOT_GAIN,
PETAL_TOP_GAIN, PETAL_BOT_GAIN,
};
static inline void pos_calc_top(int index, int mode, int *rad, int *phi,
int *raw_sum, uint16_t *raw_petal) {
int32_t cw = raw_petal[petal_pad_cw];
int32_t ccw = raw_petal[petal_pad_ccw];
int32_t base = raw_petal[petal_pad_base];
int32_t tip = ((cw + ccw) * 3) >> 2;
*raw_sum = base + ccw + cw;
if (mode > 1) {
int rad_calc = tip - base;
rad_calc *= petal_pos_gain[index];
rad_calc /= ((tip + base) >> 2) + 1;
if (mode > 2) {
int phi_calc = cw - ccw;
phi_calc *= petal_pos_gain[index];
phi_calc /= ((cw + ccw) >> 2) + 1;
phi_calc = (phi_calc * 10) / 6;
int phi_sq = (phi_calc * phi_calc) >> 15;
int phi_qb = (phi_sq * phi_calc) >> 15;
int blend = (rad_calc + (18 << 10)) >> 3;
phi_calc = (phi_calc * blend + phi_qb * ((1 << 12) - blend)) >> 12;
phi_calc = (phi_calc * 6) / 10;
*phi = phi_calc;
} else {
*phi = 0;
}
rad_calc -= 4096;
rad_calc += rad_calc >> 3;
*rad = rad_calc;
} else {
*rad = 0;
}
}
static inline void pos_calc_bot(int index, int mode, int *rad, int *raw_sum,
uint16_t *raw_petal) {
int32_t tip = raw_petal[petal_pad_tip];
int32_t base = raw_petal[petal_pad_base];
*raw_sum = base + tip;
if (mode > 1) {
base += ((base * 3) >> 2); // tiny gain correction
int rad_calc = tip - base;
rad_calc *= petal_pos_gain[index];
rad_calc /= ((tip + base) >> 2) + 1;
rad_calc = 16384 - rad_calc;
int rad_calc_gain = rad_calc > 0 ? rad_calc : 0;
rad_calc_gain = (rad_calc_gain + 32768) >> 5;
rad_calc_gain = (rad_calc_gain * rad_calc_gain) >> 12;
rad_calc = (rad_calc * rad_calc_gain) >> 10;
rad_calc = 16384 - rad_calc;
*rad = rad_calc;
} else {
*rad = 0;
}
}
#ifdef FLOW3R_BSP_CAPTOUCH_SECONDARY_OUTPUT
static int32_t top_petal_filter2[10];
static inline void pos_calc_top2(int index, int mode, int *rad, int *phi,
int *raw_sum, uint16_t *raw_petal) {
int32_t cw = raw_petal[petal_pad_cw];
int32_t ccw = raw_petal[petal_pad_ccw];
int32_t base = raw_petal[petal_pad_base];
int32_t tip = (ccw + cw) >> 1;
*raw_sum = base + ccw + cw;
if (mode > 1) {
int rad_calc = tip - base;
rad_calc *= petal_pos_gain[index];
rad_calc /= ((tip + base) >> 2) + 1;
*rad = rad_calc;
if (mode > 2) {
int phi_calc = cw - ccw;
phi_calc *= petal_pos_gain[index];
phi_calc /= ((cw + ccw) >> 2) + 1;
*phi = phi_calc;
} else {
*phi = 0;
}
} else {
*rad = 0;
}
}
static inline void pos_calc_bot2(int index, int mode, int *rad, int *raw_sum,
uint16_t *raw_petal) {
int32_t tip = raw_petal[petal_pad_tip];
int32_t base = raw_petal[petal_pad_base];
*raw_sum = base + tip;
if (mode > 1) {
base += ((base * 3) >> 2); // tiny gain correction
int rad_calc = tip - base;
rad_calc *= petal_pos_gain[index];
rad_calc /= ((tip + base) >> 2) + 1;
*rad = rad_calc;
} else {
*rad = 0;
}
}
#endif
static void petal_process(int index, uint32_t timestamp, int mode,
SemaphoreHandle_t lock) {
// lock only locks multiple readers and one writer.
// for multiple writers you need to lock around this function.
flow3r_bsp_captouch_petal_data_t *petal = &(captouch_data.petals[index]);
if (!mode) {
if (!petal->mode) return;
if (lock) xSemaphoreTake(lock, portMAX_DELAY);
petal->mode = 0;
petal->pressed = false;
petal->coverage = 0;
petal->rad = 0;
petal->phi = 0;
#ifdef FLOW3R_BSP_CAPTOUCH_SECONDARY_OUTPUT
petal->rad2 = 0;
petal->phi2 = 0;
#endif
if (lock) xSemaphoreGive(lock);
return;
}
bool top = (index % 2) == 0;
int rad = 0;
int phi = 0;
int raw_sum = 0;
if (top) {
pos_calc_top(index, mode, &rad, &phi, &raw_sum, raw_petals[index]);
#if defined(CONFIG_FLOW3R_HW_GEN_P3)
rad = -rad;
#endif
phi = clip_to_int16(phi);
} else {
pos_calc_bot(index, mode, &rad, &raw_sum, raw_petals[index]);
}
rad = clip_to_int16(rad);
raw_sum = (raw_sum * 1024) /
(top ? (TOP_PETAL_THRESHOLD) : (BOTTOM_PETAL_THRESHOLD));
bool pressed_prev = petal->pressed;
bool pressed = raw_sum > (pressed_prev ? 896 : 1024);
bool reset_filters = pressed && (!pressed_prev) && (mode > 1);
if ((!latches[index].press_event_new) || latches[index].fresh) {
latches[index].press_event_new = pressed;
latches[index].fresh = false;
}
raw_sum = raw_sum > 65535 ? 65535 : raw_sum;
#ifdef FLOW3R_BSP_CAPTOUCH_SECONDARY_OUTPUT
int rad2 = rad;
int phi2 = phi;
int raw_sum2 = 0;
if (top) {
pos_calc_top2(index, mode, &rad2, &phi2, &raw_sum2, raw_petals[index]);
phi2 = clip_to_int16(phi2);
} else {
pos_calc_bot2(index, mode, &rad2, &raw_sum2, raw_petals[index]);
}
rad2 = clip_to_int16(rad2);
#endif
#ifdef FLOW3R_BSP_CAPTOUCH_DEBUG_PETAL
static int print_petal_counter = 0;
int base = raw_petals[index][petal_pad_base];
int tip = raw_petals[index][petal_pad_tip];
int cw = raw_petals[index][petal_pad_cw];
int ccw = raw_petals[index][petal_pad_ccw];
bool print_data = pressed;
bool print_data_prev = pressed_prev;
if (index == (FLOW3R_BSP_CAPTOUCH_DEBUG_PETAL)) {
if (print_data) {
if (!print_data_prev)
printf("data = [\n # cw, ccw/tip, base, rad, phi\n");
if (!print_petal_counter) {
if (top) {
printf(" (%d, %d, ", cw, ccw);
} else {
printf(" (0, %d, ", tip);
}
printf("%d, %d, %d", base, rad, phi);
#ifdef FLOW3R_BSP_CAPTOUCH_SECONDARY_OUTPUT
printf(", %d, %d", rad2, phi2);
#endif
printf("),\n");
}
print_petal_counter++;
print_petal_counter %= 6;
} else if (print_data_prev) {
printf("]\n");
print_petal_counter = 0;
}
}
#endif
if (_on_data) _on_data(index, mode, pressed, timestamp, rad, phi, raw_sum);
if (mode > 1) {
// filter settings
const int32_t f_div_pow = 4;
const int32_t f_mult_old = 9;
const int32_t f_mult_new = (1 << f_div_pow) - f_mult_old;
if (reset_filters) {
if (top) {
top_petal_filter[index] = rad;
top_petal_filter[index + 1] = phi;
}
} else {
if (top) {
top_petal_filter[index] =
(f_mult_old * top_petal_filter[index] + f_mult_new * rad) >>
f_div_pow;
top_petal_filter[index + 1] =
(f_mult_old * top_petal_filter[index + 1] +
f_mult_new * phi) >>
f_div_pow;
rad = (f_mult_old * petal->rad +
f_mult_new * top_petal_filter[index]) >>
f_div_pow;
phi = (f_mult_old * petal->phi +
f_mult_new * top_petal_filter[index + 1]) >>
f_div_pow;
} else {
rad = (f_mult_old * petal->rad + f_mult_new * rad) >> f_div_pow;
}
}
#ifdef FLOW3R_BSP_CAPTOUCH_SECONDARY_OUTPUT
if (reset_filters) {
if (top) {
top_petal_filter2[index] = rad2;
top_petal_filter2[index + 1] = phi2;
}
} else {
if (top) {
top_petal_filter2[index] =
(f_mult_old * top_petal_filter2[index] +
f_mult_new * rad2) >>
f_div_pow;
top_petal_filter2[index + 1] =
(f_mult_old * top_petal_filter2[index + 1] +
f_mult_new * phi2) >>
f_div_pow;
rad2 = (f_mult_old * petal->rad2 +
f_mult_new * top_petal_filter2[index]) >>
f_div_pow;
phi2 = (f_mult_old * petal->phi2 +
f_mult_new * top_petal_filter2[index + 1]) >>
f_div_pow;
} else {
rad2 =
(f_mult_old * petal->rad2 + f_mult_new * rad2) >> f_div_pow;
}
}
#endif
}
if (lock) xSemaphoreTake(lock, portMAX_DELAY);
petal->mode = mode;
petal->pressed = pressed;
petal->coverage = raw_sum;
petal->rad = rad;
petal->phi = phi;
#ifdef FLOW3R_BSP_CAPTOUCH_SECONDARY_OUTPUT
petal->rad2 = rad2;
petal->phi2 = phi2;
#endif
if (lock) xSemaphoreGive(lock);
}
#pragma once
// High-level AD7147 captouch functions. Includes support for switching
// sequences and has basic software calibration routines.
//
// Only takes care of one captouch controller at once. Both captouch controllers
// are put together into a single view in flow3r_bsp_captouch.
// Highest-level driver for captouch on the flow3r badge. Uses 2x AD7147.
// The AD7147 captouch chip is weird.
// The flow3r has 10 touch petals. 5 petals on the top layer, 5 petals on the
// bottom layer.
//
// Top petals have three capacitive pads. Bottom petals have two capacitive
// pads.
//
// The petals are numbered from 0 to 9 (inclusive). Petal 0 is next to the USB
// port, and is a top petal. Petal 1 is a bottom petal to its right. Petal 2 is
// a top petal to its right, and the rest continue clockwise accordingly.
// It has 13 input channels, and can perform arbitrarily sequenced reads from
// these channels (then report the results of that sequence at once), but the
// maximum sequence length is 12 stages.
//
// That means getting 13 independent captouch channel readouts is tricky, as you
// need to change these sequences around to get all channels.
// One of the two chips only reads 12 channels so all is well, however the other
// must get data for all of its 13 channels. This means the chip needs to be
// dynamically reconfigured during operation. There is however the oddity that
// everytime a channel is reconfigured the first reading has a small likelyhood
// to be glitchy. This could be a locking issue that grabs stale data but we
// couldn't find anything the like and ran some experiments with very barebones
// code so we accept it as fact for now.
// To account for this we therefore need to throw away data. The most optimal
// sequence therefore only reconfigures one stage. As we can only reset the
// sequencer to stage 0 we use stage 0 for dynamic operations. This gives us
// an effective 15-step sequence (13 usable, 2 for throwing away after reconf).
// There's some overhead so we're running a bit slower than that.
#include <stdbool.h>
#include "esp_err.h"
#include "flow3r_bsp_ad7147_hw.h"
#include "flow3r_bsp_captouch.h"
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#define _AD7147_SEQ_MAX 2
#define _AD7147_CALIB_CYCLES 16
typedef struct {
uint16_t amb[6];
uint16_t afe[6];
} ad7147_petal_calib_t;
// State of an AD7147 channel. Each AD7147 has 13 channels, but can only access
// 12 of them at once in a single sequence.
typedef struct {
// Positive AFE offset currently programmed. [0,64).
int8_t afe_offset;
// Positive AFE offset currently programmed. [0,126].
volatile int8_t afe_offset;
// Last measurement.
uint16_t cdc;
// Ambient value used for offset when checking for touch presence. Written
// by calibration, and attempts to reach a preset calibration setpoint.
uint16_t amb;
volatile uint16_t amb;
// Calibration samples gathered during the calibraiton process.
uint16_t amb_meas[_AD7147_CALIB_CYCLES];
} ad7147_channel_t;
} ad7147_stage_t;
// State and configuration of an AD7147 chip. Wraps the low-level structure in
// everything required to manage multiple sequences and perform calibration.
typedef struct {
// Opaque name used to prefix log messages.
const char *name;
// True for bottom chip, false for top
bool is_bot;
// [0, n_channels) are the expected connected channels to the inputs of the
// chip.
size_t nchannels;
ad7147_channel_t channels[13];
ad7147_stage_t stages[13];
// Sequences to be handled by this chip. Each sequence is a -1 right-padded
// list of channel numbers that the sequence will be programmed to. If a
// sequence is all -1, it will be skipped.
int8_t sequences[_AD7147_SEQ_MAX][12];
// modes that the petals are supposed to be in
flow3r_bsp_captouch_petal_mode_t user_modes[10];
// take this lock to change user_modes, then send a NOTIF_MODE
SemaphoreHandle_t user_lock;
// Current position within the sequences list.
size_t seq_position;
// Called when all sequences have scanned through.
ad7147_data_callback_t callback;
void *user;
// actual modes that the petals are in.
flow3r_bsp_captouch_petal_mode_t modes[10];
// Sequence to be handled by this chip as a 0 right-padded
// list of channel bitmasks that the chip will read
uint16_t sequence[13];
int len_sequence;
// Whether or not the cursed sequence is active.
bool cursed_active;
// Task that processes the chip
TaskHandle_t task;
// underlying hardware device
ad7147_hw_t dev;
bool failed;
// number of petals this chip supplies
size_t num_petals;
// list of petal indices, num_petals long
uint8_t petals[6];
// True if calibration is running
bool calibration_active;
bool calibration_pending;
size_t calibration_cycles;
// internal flags used for calibration
bool calibration_stage_active;
bool calibration_proceed;
int calibration_stage;
int calibration_cycles;
SemaphoreHandle_t output_lock;
} ad7147_chip_t;
// Call to initialize the chip at a given address. Structure must be zeroed, and
// callback must be configured.
//
// The chip will be configured to pull its interrupt line low when a sequence
// has finished and thus when _chip_process should be called.
esp_err_t flow3r_bsp_ad7147_chip_init(ad7147_chip_t *chip,
flow3r_i2c_address address);
// Call to poll the chip and perform any necessary actions. Can be called from
// an interrupt.
esp_err_t flow3r_bsp_ad7147_chip_process(ad7147_chip_t *chip);
\ No newline at end of file
// One of the four possible touch points (pads) on a petal. Top petals have
// base/cw/ccw. Bottom petals have base/tip.
typedef enum {
// Pad away from centre of badge.
petal_pad_tip = 0,
// Pad going counter-clockwise around the badge.
petal_pad_ccw = 1,
// Pad going clockwise around the badge.
petal_pad_cw = 2,
// Pad going towards the centre of the badge.
petal_pad_base = 3,
} petal_pad_kind_t;
// Each petal can be either top or bottom.
typedef enum {
// Petal on the top layer. Has base, cw, ccw pads.
petal_top = 0,
// petal on the bottom layer. Has base and tip fields.
petal_bottom = 1,
} petal_kind_t;
// State of a petal's pad.
typedef struct {
// Is it a top or bottom petal?
petal_pad_kind_t kind;
// Raw value, compensated for ambient value.
uint16_t raw;
// Configured threshold for touch detection.
uint16_t threshold;
} flow3r_bsp_ad7147_petal_pad_state_t;
// State of a petal. Only the fields relevant to the petal kind (tip/base or
// base/cw/ccw) are present.
typedef struct {
petal_kind_t kind;
flow3r_bsp_ad7147_petal_pad_state_t tip;
flow3r_bsp_ad7147_petal_pad_state_t ccw;
flow3r_bsp_ad7147_petal_pad_state_t cw;
flow3r_bsp_ad7147_petal_pad_state_t base;
} flow3r_bsp_ad7147_petal_state_t;
// State of all petals of the badge.
typedef struct {
flow3r_bsp_ad7147_petal_state_t petals[10];
} flow3r_bsp_ad7147_state_t;
// Get a given petal's pad data for a given petal kind.
const flow3r_bsp_ad7147_petal_pad_state_t *
flow3r_bsp_ad7147_pad_for_petal_const(
const flow3r_bsp_ad7147_petal_state_t *petal, petal_pad_kind_t kind);
flow3r_bsp_ad7147_petal_pad_state_t *flow3r_bsp_ad7147_pad_for_petal(
flow3r_bsp_ad7147_petal_state_t *petal, petal_pad_kind_t kind);
// Request captouch calibration.
void flow3r_bsp_ad7147_calibrate();
// Returns true if captouch is currently calibrating.
int flow3r_bsp_ad7147_calibrating();
// Set/get calibration data. data[] should be at least 120 entries long.
bool flow3r_bsp_ad7147_get_calibration_data(int32_t *data);
void flow3r_bsp_ad7147_set_calibration_data(int32_t *data);
#pragma once
void flow3r_bsp_ad7147_get(flow3r_bsp_captouch_data_t *dest);
void flow3r_bsp_ad7147_refresh_events();
esp_err_t flow3r_bsp_ad7147_init();
void flow3r_bsp_ad7147_set_data_callback(flow3r_bsp_data_callback_t fun);
void flow3r_bsp_ad7147_set_petal_modes(flow3r_bsp_captouch_petal_mode_t *data);
void flow3r_bsp_ad7147_get_petal_modes(flow3r_bsp_captouch_petal_mode_t *data);
#include "flow3r_bsp_ad7147_hw.h"
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "freertos/task.h"
#include "esp_err.h"
#include "esp_log.h"
......@@ -7,7 +10,7 @@
#define TIMEOUT_MS 1000
#define CIN CDC_NONE 0
#define CIN_CDC_NONE 0
#define CIN_CDC_NEG 1
#define CIN_CDC_POS 2
#define CIN_BIAS 3
......@@ -22,6 +25,8 @@
#define AD7147_REG_DEVICE_ID 0x17
#define AD7147_REG_STAGE0_CONNECTION 0x80
static const char *TAG = "flow3r-bsp-ad7147-hw";
// Write single register at `reg`.
static esp_err_t _i2c_write(const ad7147_hw_t *dev, uint16_t reg,
uint16_t data) {
......@@ -33,8 +38,7 @@ static esp_err_t _i2c_write(const ad7147_hw_t *dev, uint16_t reg,
// Write continuous `len`-long register range starting at `reg`.
static esp_err_t _i2c_write_multiple(const ad7147_hw_t *dev, uint16_t reg,
const uint16_t *data, size_t len) {
uint8_t *tx = malloc(len * 2 + 2);
assert(tx != NULL);
uint8_t tx[len * 2 + 2];
tx[0] = reg >> 8;
tx[1] = reg & 0xff;
for (size_t i = 0; i < len; i++) {
......@@ -43,7 +47,6 @@ static esp_err_t _i2c_write_multiple(const ad7147_hw_t *dev, uint16_t reg,
}
esp_err_t ret = flow3r_bsp_i2c_write_to_device(
dev->addr, tx, len * 2 + 2, TIMEOUT_MS / portTICK_PERIOD_MS);
free(tx);
return ret;
}
......@@ -110,26 +113,26 @@ static esp_err_t _configure_high_int_en(const ad7147_hw_t *dev) {
static esp_err_t _configure_complete_int_en(const ad7147_hw_t *dev) {
const ad7147_device_config_t *config = &dev->dev_config;
const uint16_t val =
((config->stageX_complete_int_enable[0] ? 1 : 0) << 11) |
((config->stageX_complete_int_enable[1] ? 1 : 0) << 10) |
((config->stageX_complete_int_enable[2] ? 1 : 0) << 9) |
((config->stageX_complete_int_enable[3] ? 1 : 0) << 8) |
((config->stageX_complete_int_enable[4] ? 1 : 0) << 7) |
((config->stageX_complete_int_enable[5] ? 1 : 0) << 6) |
((config->stageX_complete_int_enable[6] ? 1 : 0) << 5) |
((config->stageX_complete_int_enable[6] ? 1 : 0) << 4) |
((config->stageX_complete_int_enable[8] ? 1 : 0) << 3) |
((config->stageX_complete_int_enable[9] ? 1 : 0) << 2) |
((config->stageX_complete_int_enable[10] ? 1 : 0) << 1) |
((config->stageX_complete_int_enable[11] ? 1 : 0) << 0);
((config->stageX_complete_int_enable[11] ? 1 : 0) << 11) |
((config->stageX_complete_int_enable[10] ? 1 : 0) << 10) |
((config->stageX_complete_int_enable[9] ? 1 : 0) << 9) |
((config->stageX_complete_int_enable[8] ? 1 : 0) << 8) |
((config->stageX_complete_int_enable[7] ? 1 : 0) << 7) |
((config->stageX_complete_int_enable[6] ? 1 : 0) << 6) |
((config->stageX_complete_int_enable[5] ? 1 : 0) << 5) |
((config->stageX_complete_int_enable[4] ? 1 : 0) << 4) |
((config->stageX_complete_int_enable[3] ? 1 : 0) << 3) |
((config->stageX_complete_int_enable[2] ? 1 : 0) << 2) |
((config->stageX_complete_int_enable[1] ? 1 : 0) << 1) |
((config->stageX_complete_int_enable[0] ? 1 : 0) << 0);
// ESP_LOGE(TAG, "int val config: %u", val);
return _i2c_write(dev, AD7147_REG_STAGE_COMPLETE_INT_ENABLE, val);
}
// Configure stage per stage_config.
static esp_err_t _configure_stage(const ad7147_hw_t *dev, uint8_t stage) {
const ad7147_stage_config_t *config = &dev->stage_config[stage];
const uint16_t connection_6_0 = (config->cinX_connection_setup[6] << 12) |
(config->cinX_connection_setup[5] << 10) |
(config->cinX_connection_setup[4] << 8) |
......@@ -161,7 +164,14 @@ static esp_err_t _configure_stage(const ad7147_hw_t *dev, uint8_t stage) {
afe_offset,
sensitivity,
};
return _i2c_write_multiple(dev, reg, tx, 4);
esp_err_t ret = _i2c_write_multiple(dev, reg, tx, 4);
#if 0
printf("stage %u config: %u %u %u %u\n", stage, tx[0], tx[1], tx[2], tx[3]);
//uint16_t rx[4];
//_i2c_read(dev, reg, rx, 4);
//printf("read stage config: %u %u %u %u\n", rx[0], rx[1], rx[2], rx[3]);
#endif
return ret;
}
// Configure entire device per stage_config and dev_config.
......@@ -187,7 +197,7 @@ static esp_err_t _configure_full(const ad7147_hw_t *dev) {
return ESP_OK;
}
// Force stage sequencer to reset. Glitchy.
// Force stage sequencer to reset.
static esp_err_t _reset_sequencer(const ad7147_hw_t *dev) {
uint16_t val = (0x0 << 0) | // FF_SKIP_CNT
(0xf << 4) | // FP_PROXIMITY_CNT
......@@ -195,68 +205,10 @@ static esp_err_t _reset_sequencer(const ad7147_hw_t *dev) {
(0x0 << 12) | // PWR_DOWN_TIMEOUT
(0x0 << 14) | // FORCED_CAL
(0x1 << 15); // CONV_RESET
esp_err_t res;
if ((res = _i2c_write(dev, AD7147_REG_AMB_COMP_CTRL0, val)) != ESP_OK) {
return res;
}
return ESP_OK;
}
// Read completed conversion data and call user callback on it.
static esp_err_t _process_complete(ad7147_hw_t *device) {
uint16_t data[12];
size_t count = device->num_stages;
esp_err_t res;
if ((res = _i2c_read(device, AD7147_REG_CDC_RESULT_S0, data, count)) !=
ESP_OK) {
return res;
}
if (device->callback != NULL) {
device->callback(device->user, data, count);
return _i2c_write(dev, AD7147_REG_AMB_COMP_CTRL0, val);
}
return ESP_OK;
}
esp_err_t ad7147_hw_process(ad7147_hw_t *device) {
// Read complete status register. This acknowledges interrupts.
uint16_t st = 0;
esp_err_t res =
_i2c_read(device, AD7147_REG_STAGE_COMPLETE_INT_STATUS, &st, 1);
if (res != ESP_OK) {
return res;
}
// Nothing to do if no stages are expected to be read.
if (device->num_stages < 1) {
return ESP_OK;
}
// Bit indicating the conversion has been complete for the requested number
// of stages.
uint16_t complete_bit = (1 << (device->num_stages - 1));
if (st & complete_bit) {
res = _process_complete(device);
if (res != ESP_OK) {
return res;
}
} else {
// Spurious hw_process call, nothing to do...
}
return ESP_OK;
}
esp_err_t ad7147_hw_init(ad7147_hw_t *device, flow3r_i2c_address addr,
ad7147_data_callback_t callback, void *user) {
memset(device, 0, sizeof(ad7147_hw_t));
device->addr = addr;
device->callback = callback;
device->user = user;
// device->dev_config.decimation = 0b10; // Decimation: 64, lowest possible.
device->dev_config.decimation = 0b01;
esp_err_t ad7147_hw_init(ad7147_hw_t *device) {
for (size_t i = 0; i < 12; i++) {
for (size_t j = 0; j < 13; j++) {
device->stage_config[i].cinX_connection_setup[j] = CIN_BIAS;
......@@ -266,33 +218,51 @@ esp_err_t ad7147_hw_init(ad7147_hw_t *device, flow3r_i2c_address addr,
return _configure_full(device);
}
static inline uint8_t afe_limit(int8_t offset) {
return offset < 0 ? 0 : (offset > 63 ? 63 : offset);
}
esp_err_t ad7147_hw_configure_stages(ad7147_hw_t *device,
const ad7147_sequence_t *seq,
bool reprogram) {
const ad7147_sequence_t *seq) {
// Reset all stage/channel configuration.
for (size_t i = 0; i < 12; i++) {
uint8_t idle_con =
seq->stages[i].idle_to_bias ? CIN_BIAS : CIN_CDC_NONE;
for (int8_t j = 0; j < 13; j++) {
device->stage_config[i].cinX_connection_setup[j] = CIN_BIAS;
device->stage_config[i].cinX_connection_setup[j] = idle_con;
}
device->dev_config.stageX_complete_int_enable[i] = false;
}
// Configure stages as requested.
for (size_t i = 0; i < seq->len; i++) {
int8_t channel = seq->channels[i];
int8_t offset = seq->pos_afe_offsets[i];
device->stage_config[i].cinX_connection_setup[channel] = CIN_CDC_POS;
unsigned int pos_offset = offset < 0 ? 0 : (offset > 63 ? 63 : offset);
device->stage_config[i].pos_afe_offset = pos_offset;
uint16_t channel_mask = seq->stages[i].channel_mask;
for (uint8_t j = 0; j < 13; j++) {
if (channel_mask & (1 << j)) {
device->stage_config[i].cinX_connection_setup[j] = CIN_CDC_POS;
}
}
device->stage_config[i].pos_afe_offset =
afe_limit(seq->stages[i].pos_afe_offset);
device->stage_config[i].neg_afe_offset =
afe_limit(seq->stages[i].neg_afe_offset);
device->stage_config[i].neg_afe_offset_swap = true;
device->stage_config[i].pos_afe_offset_swap = false;
}
if (seq->len) {
device->dev_config.sequence_stage_num = seq->len - 1;
device->dev_config.stageX_complete_int_enable[seq->len - 1] = true;
device->dev_config.stageX_complete_int_enable[seq->interrupt_stage] =
true;
device->dev_config.power_mode = 0;
} else {
device->dev_config.power_mode = 1; // shutdown
}
// For our own record (more precisely, for the interrupt handler).
device->num_stages = seq->len;
// Submit changes over I2C.
esp_err_t ret;
// Submit changes over I2C.
if ((ret = _configure_pwr_control(device)) != ESP_OK) {
return ret;
}
......@@ -301,13 +271,186 @@ esp_err_t ad7147_hw_configure_stages(ad7147_hw_t *device,
return ret;
}
}
if ((ret = _configure_complete_int_en(device)) != ESP_OK) {
if ((ret = _reset_sequencer(device)) != ESP_OK) {
return ret;
}
if (reprogram) {
if ((ret = _reset_sequencer(device)) != ESP_OK) {
if ((ret = _configure_complete_int_en(device)) != ESP_OK) {
return ret;
}
uint16_t st; // throwaway
if ((ret = _i2c_read(device, AD7147_REG_STAGE_COMPLETE_INT_STATUS, &st,
1)) != ESP_OK) {
return ret;
}
return ESP_OK;
}
bool ad7147_hw_get_and_clear_completed(ad7147_hw_t *device, uint16_t *st) {
esp_err_t res =
_i2c_read(device, AD7147_REG_STAGE_COMPLETE_INT_STATUS, st, 1);
if (res != ESP_OK) {
ESP_LOGE(TAG, "captouch i2c failed: %s", esp_err_to_name(res));
return false;
}
return true;
}
bool ad7147_hw_get_cdc_data(ad7147_hw_t *device, uint16_t *data,
uint8_t stages) {
esp_err_t res = _i2c_read(device, AD7147_REG_CDC_RESULT_S0, data, stages);
if (res != ESP_OK) {
ESP_LOGE(TAG, "captouch i2c failed: %s", esp_err_to_name(res));
return false;
}
return true;
}
bool ad7147_hw_reset_sequencer(ad7147_hw_t *device) {
esp_err_t res = _reset_sequencer(device);
if (res != ESP_OK) {
ESP_LOGE(TAG, "captouch i2c failed: %s", esp_err_to_name(res));
return false;
}
return true;
}
// suuuuper duper flow3r specific stuff. shouldn't actually be here but putting
// it in _ad7147.c would require exposing a bunch of stuff to global
// namespace/duplicating/whatevs and we feel like putting it here is the better
// of two bad options. anyways:
bool ad7147_hw_override_interrupt_stage(ad7147_hw_t *device,
uint8_t interrupt_stage) {
const uint16_t val = 1 << interrupt_stage;
esp_err_t res =
_i2c_write(device, AD7147_REG_STAGE_COMPLETE_INT_ENABLE, val);
if (res != ESP_OK) {
ESP_LOGE(TAG, "captouch i2c failed: %s", esp_err_to_name(res));
return false;
}
return true;
}
// Configure stage. Defaults to stage_config if config is NULL.
static esp_err_t _i2c_golf_override_stage(ad7147_hw_t *dev, uint8_t stage,
ad7147_stage_config_t *config) {
if (config == NULL) {
config = &dev->stage_config[stage];
}
const uint16_t connection_12_7 = (config->pos_afe_offset_disable << 15) |
(config->neg_afe_offset_disable << 14) |
(config->se_connection_setup << 12) |
(config->cinX_connection_setup[12] << 10) |
(config->cinX_connection_setup[11] << 8) |
(config->cinX_connection_setup[10] << 6) |
(config->cinX_connection_setup[9] << 4) |
(config->cinX_connection_setup[8] << 2) |
(config->cinX_connection_setup[7] << 0);
const uint16_t afe_offset =
(config->pos_afe_offset_swap << 15) | (config->pos_afe_offset << 8) |
(config->neg_afe_offset_swap << 7) | (config->neg_afe_offset << 0);
const uint8_t reg = AD7147_REG_STAGE0_CONNECTION + stage * 8;
uint16_t tx[2] = {
connection_12_7,
afe_offset,
};
esp_err_t ret = _i2c_write_multiple(dev, reg + 1, tx, 2);
#if 0
printf("stage %u config: %u %u\n", stage, tx[0], tx[1]);
#endif
return ret;
}
// helper function for ad7147_hw_modulate_stage0_and_reset
static bool _i2c_golf_override_lower_registers(ad7147_hw_t *dev,
int num_stages) {
esp_err_t res;
if (num_stages >= 0) dev->dev_config.sequence_stage_num = num_stages;
#if 0
// writing to 0x00: AD7147_REG_PWR_CONTROL
if ((res = _configure_pwr_control(dev)) != ESP_OK) {
ESP_LOGE(TAG, "captouch i2c failed: %s", esp_err_to_name(res));
return false;
}
// writing to 0x02: AD7147_REG_AMB_COMP_CTRL0
if(!ad7147_hw_reset_sequencer(dev)) {return false;}
#else
// ^^ this would be our code in an ideal world. however, we can make it a
// tiny bit faster by writing to both in a single... uh... protocol session?
// you catch the dorifto :D bunch of copypasta from the following functions,
// keep in sync-ish ideally:
// _configure_pwr_control
const ad7147_device_config_t *config = &dev->dev_config;
const uint16_t val0 =
(config->cdc_bias << 14) | (config->ext_source << 12) |
(config->int_pol << 11) | (config->sw_reset << 10) |
(config->decimation << 8) | (config->sequence_stage_num << 4) |
(config->lp_conv_delay << 2) | (config->power_mode << 0);
// _configure_stage_cal_en
const uint16_t val1 =
(config->avg_lp_skip << 14) | (config->avg_fp_skip << 12) |
(config->stage11_cal_en << 11) | (config->stage10_cal_en << 10) |
(config->stage9_cal_en << 9) | (config->stage8_cal_en << 8) |
(config->stage7_cal_en << 7) | (config->stage6_cal_en << 6) |
(config->stage5_cal_en << 5) | (config->stage4_cal_en << 4) |
(config->stage3_cal_en << 3) | (config->stage2_cal_en << 2) |
(config->stage1_cal_en << 1) | (config->stage0_cal_en << 0);
// _reset_sequencer
uint16_t val2 = (0x0 << 0) | // FF_SKIP_CNT
(0xf << 4) | // FP_PROXIMITY_CNT
(0xf << 8) | // LP_PROXIMITY_CNT
(0x0 << 12) | // PWR_DOWN_TIMEOUT
(0x0 << 14) | // FORCED_CAL
(0x1 << 15); // CONV_RESET
uint16_t val[3] = { val0, val1, val2 };
if ((res = _i2c_write_multiple(dev, AD7147_REG_PWR_CONTROL, val, 3)) !=
ESP_OK) {
ESP_LOGE(TAG, "captouch i2c failed: %s", esp_err_to_name(res));
return false;
}
#endif
return true;
}
// this one is used for dynamic reconfiguration. it's a mouthful to explain,
// check _ad7147.c for usage. be careful about ur locks and isr clears. good
// luck.
bool ad7147_hw_modulate_stage0_and_reset(ad7147_hw_t *dev,
ad7147_sequence_stage_t *s_conf) {
esp_err_t res;
// writing to 0x80 + stage * 8: AD7147_REG_STAGE0_CONNECTION + stage * 8;
uint8_t num_stages;
if (s_conf == NULL) {
num_stages = 11;
res = _i2c_golf_override_stage(dev, 0, NULL);
} else {
num_stages = 0;
ad7147_stage_config_t config = { 0 };
for (uint8_t j = 0; j < 13; j++) {
if (s_conf->channel_mask & (1 << j)) {
config.cinX_connection_setup[j] = CIN_CDC_POS;
} else {
config.cinX_connection_setup[j] = CIN_CDC_NONE;
}
}
config.pos_afe_offset = afe_limit(s_conf->pos_afe_offset);
config.neg_afe_offset = afe_limit(s_conf->neg_afe_offset);
config.neg_afe_offset_swap = true;
config.pos_afe_offset_swap = false;
config.se_connection_setup = 0b01;
res = _i2c_golf_override_stage(dev, 0, &config);
}
if (res != ESP_OK) {
ESP_LOGE(TAG, "captouch i2c failed: %s", esp_err_to_name(res));
return false;
}
return _i2c_golf_override_lower_registers(dev, num_stages);
}
......@@ -7,6 +7,9 @@
#include "esp_err.h"
#include "flow3r_bsp_i2c.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include <stdint.h>
// 'Global' configuration for the AD7147 captouch controller.
......@@ -67,8 +70,6 @@ typedef struct {
unsigned int pos_peak_detect : 3;
} ad7147_stage_config_t;
typedef void (*ad7147_data_callback_t)(void *user, uint16_t *data, size_t len);
// AD7147 low level configuration/access structure. Doesn't know anything about
// calibration or high-level sequencing, just talks to a chip to configure
// stages and can be called to poll the chip for new CDC data.
......@@ -78,38 +79,46 @@ typedef struct {
// Function and user-controlled argument that will be called when the
// sequence has finished and new data is available.
ad7147_data_callback_t callback;
void *user;
ad7147_stage_config_t stage_config[12];
ad7147_device_config_t dev_config;
uint8_t num_stages;
} ad7147_hw_t;
// Initialize the AD7147 captouch controller with a given callback. This
// callback will be called when new data has been acquired.
esp_err_t ad7147_hw_init(ad7147_hw_t *device, flow3r_i2c_address addr,
ad7147_data_callback_t callback, void *user);
// Initialize the AD7147 captouch controller. Expects the following fields:
// device.dev_config.decimation
// device.addr
// Does not set up stages, use ad7147_hw_configure_stages afterwards
esp_err_t ad7147_hw_init(ad7147_hw_t *device);
// Sequencer configuration, high-level.
typedef struct {
// Number of sequencer stages, [1, 12].
size_t len;
// For each sequencer stage, channel number that this stage should sample.
int8_t channels[12];
// For each sequencer stage, AFE offset that this stage should use when
// sampling the configured channel.
int8_t pos_afe_offsets[12];
uint16_t channel_mask; // typically one bit set
// Whether idle pads are supposed to be connected to bias. Awful hack.
bool idle_to_bias;
int8_t pos_afe_offset;
int8_t neg_afe_offset;
} ad7147_sequence_stage_t;
typedef struct {
uint16_t interrupt_stage; // at which stage's completion the interrupt is
// to be sent, [0..11]
uint8_t len; // Number of sequencer stages, [1, 12].
ad7147_sequence_stage_t stages[13];
} ad7147_sequence_t;
// Configure sequencer stages.
//
// If reprogram is true, the sequencer will be restarted. This should be true if
// the sequence channels/lengths changed from the previous call.
esp_err_t ad7147_hw_configure_stages(ad7147_hw_t *device,
const ad7147_sequence_t *seq,
bool reprogram);
const ad7147_sequence_t *seq);
// Polls sequencer status from the chip and calls the user callback if new data
// is available / the sequence finished.
esp_err_t ad7147_hw_process(ad7147_hw_t *device);
// helpers
bool ad7147_hw_get_and_clear_completed(ad7147_hw_t *device, uint16_t *st);
bool ad7147_hw_get_cdc_data(ad7147_hw_t *device, uint16_t *data,
uint8_t stages);
bool ad7147_hw_reset_sequencer(ad7147_hw_t *device);
bool ad7147_hw_modulate_stage0_and_reset(ad7147_hw_t *dev,
ad7147_sequence_stage_t *s_conf);
bool ad7147_hw_override_interrupt_stage(ad7147_hw_t *device,
uint8_t interrupt_stage);
......@@ -45,8 +45,8 @@ float flow3r_bsp_audio_speaker_set_volume(bool mute, float dB) {
return flow3r_bsp_max98091_speaker_set_volume(mute, dB);
}
void flow3r_bsp_audio_headset_set_gain_dB(uint8_t gain_dB) {
flow3r_bsp_max98091_headset_set_gain_dB(gain_dB);
int8_t flow3r_bsp_audio_headset_set_gain_dB(int8_t gain_dB) {
return flow3r_bsp_max98091_headset_set_gain_dB(gain_dB);
}
void flow3r_bsp_audio_read_jacksense(flow3r_bsp_audio_jacksense_state_t *st) {
......
#include "flow3r_bsp_captouch.h"
#include "flow3r_bsp_ad7147.h"
#include "flow3r_bsp_i2c.h"
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include <math.h>
#include "esp_err.h"
#include "esp_log.h"
static const char *TAG = "flow3r-bsp-captouch";
typedef struct {
size_t petal_number;
petal_kind_t pad_kind;
} pad_mapping_t;
#if defined(CONFIG_FLOW3R_HW_GEN_P3)
static const pad_mapping_t _map_top[12] = {
{ 0, petal_pad_tip }, // 0
{ 0, petal_pad_ccw }, // 1
{ 0, petal_pad_cw }, // 2
{ 8, petal_pad_cw }, // 3
{ 8, petal_pad_ccw }, // 4
{ 8, petal_pad_tip }, // 5
{ 4, petal_pad_tip }, // 6
{ 4, petal_pad_ccw }, // 7
{ 4, petal_pad_cw }, // 8
{ 6, petal_pad_cw }, // 9
{ 6, petal_pad_ccw }, // 10
{ 6, petal_pad_tip }, // 11
};
static const pad_mapping_t _map_bot[13] = {
{ 9, petal_pad_base }, // 0
{ 9, petal_pad_tip }, // 1
{ 7, petal_pad_base }, // 2
{ 7, petal_pad_tip }, // 3
{ 5, petal_pad_base }, // 4
{ 5, petal_pad_tip }, // 5
{ 3, petal_pad_tip }, // 6
{ 3, petal_pad_base }, // 7
{ 1, petal_pad_tip }, // 8
{ 1, petal_pad_base }, // 9
{ 2, petal_pad_tip }, // 10
{ 2, petal_pad_cw }, // 11
{ 2, petal_pad_ccw }, // 12
};
static gpio_num_t _interrupt_gpio_top = GPIO_NUM_15;
static gpio_num_t _interrupt_gpio_bot = GPIO_NUM_15;
static bool _interrupt_shared = true;
#elif defined(CONFIG_FLOW3R_HW_GEN_P4) || defined(CONFIG_FLOW3R_HW_GEN_C23)
static const pad_mapping_t _map_top[12] = {
{ 0, petal_pad_ccw }, // 0
{ 0, petal_pad_base }, // 1
{ 0, petal_pad_cw }, // 2
{ 8, petal_pad_cw }, // 3
{ 8, petal_pad_base }, // 4
{ 8, petal_pad_ccw }, // 5
{ 4, petal_pad_ccw }, // 6
{ 4, petal_pad_base }, // 7
{ 4, petal_pad_cw }, // 8
{ 6, petal_pad_ccw }, // 9
{ 6, petal_pad_base }, // 10
{ 6, petal_pad_cw }, // 11
};
static const pad_mapping_t _map_bot[13] = {
{ 9, petal_pad_base }, // 0
{ 9, petal_pad_tip }, // 1
{ 7, petal_pad_base }, // 2
{ 7, petal_pad_tip }, // 3
{ 5, petal_pad_base }, // 4
{ 5, petal_pad_tip }, // 5
{ 3, petal_pad_tip }, // 6
{ 3, petal_pad_base }, // 7
{ 1, petal_pad_tip }, // 8
{ 1, petal_pad_base }, // 9
{ 2, petal_pad_ccw }, // 10
{ 2, petal_pad_cw }, // 11
{ 2, petal_pad_base }, // 12
};
#if defined(CONFIG_FLOW3R_HW_GEN_P4)
static gpio_num_t _interrupt_gpio_top = GPIO_NUM_15;
static gpio_num_t _interrupt_gpio_bot = GPIO_NUM_15;
static bool _interrupt_shared = true;
#else
static gpio_num_t _interrupt_gpio_top = GPIO_NUM_15;
static gpio_num_t _interrupt_gpio_bot = GPIO_NUM_16;
static bool _interrupt_shared = false;
#endif
#else
#error "captouch not implemented for this badge generation"
#endif
static ad7147_chip_t _top = {
.name = "top",
.nchannels = 12,
.sequences = {
{
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
},
{
-1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1,
},
},
};
static ad7147_chip_t _bot = {
.name = "bot",
.nchannels = 13,
.sequences = {
/// This is the ideal sequence we want. First, all the bottom sensors.
/// Then the top petal.
//{
// 0, 1, 2, 3, 4, 5,
// 6, 7, 8, 9, -1, -1,
//},
//{
// 10, 11, 12, -1, -1, -1,
// -1, -1, -1, -1, -1, -1
//},
/// However, that causes extreme glitches. This seems to make it
/// slightly better:
//{
// 0, 1, 2, 3, 4, 5,
// 9, -1, -1, -1, -1, -1,
//},
//{
// 10, 11, 12, 6, 7, 8,
// 9, -1, -1, -1, -1, -1
//},
/// However again, that's still too glitchy for my taste. So we end up
/// just ignoring one of the bottom petal pads and hope to figure this
/// out later (tm).
/// BUG(q3k): whyyyyyyyyyyyyyyy
{
0, 1, 2, 3, 5, 6, 7, 8, 9, 10, 11, 12
},
{
-1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1,
},
},
};
static flow3r_bsp_captouch_callback_t _callback = NULL;
static flow3r_bsp_captouch_state_t _state = {};
static bool _processed = false;
static void _on_chip_data(void *user, uint16_t *data, size_t len) {
ad7147_chip_t *chip = (ad7147_chip_t *)user;
assert(chip == &_top || chip == &_bot);
bool top = chip == &_top;
const pad_mapping_t *map = top ? _map_top : _map_bot;
for (size_t i = 0; i < len; i++) {
flow3r_bsp_captouch_petal_state_t *petal =
&_state.petals[map[i].petal_number];
flow3r_bsp_captouch_petal_pad_state_t *pad =
flow3r_bsp_captouch_pad_for_petal(petal, map[i].pad_kind);
pad->raw = data[i];
}
_processed = true;
}
static QueueHandle_t _q = NULL;
static void _bot_isr(void *data) {
(void)data;
bool bot = true;
xQueueSendFromISR(_q, &bot, NULL);
}
static void _top_isr(void *data) {
(void)data;
bool bot = false;
xQueueSendFromISR(_q, &bot, NULL);
}
static void _kickstart(void) {
bool bot = false;
xQueueSend(_q, &bot, portMAX_DELAY);
bot = true;
xQueueSend(_q, &bot, portMAX_DELAY);
}
static void _task(void *data) {
(void)data;
// no other drivers around for now...
#define FLOW3R_BSP_CAPTOUCH_AD7147
bool top_ok = true;
bool bot_ok = true;
esp_err_t ret;
for (;;) {
#if defined(CONFIG_FLOW3R_HW_GEN_P4)
bool top = true, bot = true;
vTaskDelay(10 / portTICK_PERIOD_MS);
#else
bool bot = false;
if (xQueueReceive(_q, &bot, portMAX_DELAY) == pdFALSE) {
ESP_LOGE(TAG, "Queue receive failed");
return;
}
bool top = !bot;
if (_interrupt_shared) {
// No way to know which captouch chip triggered the interrupt, so
// process both.
top = true;
bot = true;
}
#endif
if (bot) {
if ((ret = flow3r_bsp_ad7147_chip_process(&_bot)) != ESP_OK) {
if (bot_ok) {
ESP_LOGE(TAG,
"Bottom captouch processing failed: %s (silencing "
"future warnings)",
esp_err_to_name(ret));
bot_ok = false;
#ifdef FLOW3R_BSP_CAPTOUCH_AD7147
#include "flow3r_bsp_ad7147.h"
void flow3r_bsp_captouch_set_calibration_data(int32_t *data) {
flow3r_bsp_ad7147_set_calibration_data(data);
}
} else {
bot_ok = true;
bool flow3r_bsp_captouch_get_calibration_data(int32_t *data) {
return flow3r_bsp_ad7147_get_calibration_data(data);
}
int flow3r_bsp_captouch_calibrating() {
return flow3r_bsp_ad7147_calibrating();
}
if (top) {
if ((ret = flow3r_bsp_ad7147_chip_process(&_top)) != ESP_OK) {
if (top_ok) {
ESP_LOGE(TAG,
"Top captouch processing failed: %s (silencing "
"future warnings)",
esp_err_to_name(ret));
top_ok = false;
void flow3r_bsp_captouch_calibration_request() {
flow3r_bsp_ad7147_calibrate();
}
} else {
top_ok = true;
void flow3r_bsp_captouch_get(flow3r_bsp_captouch_data_t *dest) {
flow3r_bsp_ad7147_get(dest);
}
void flow3r_bsp_captouch_refresh_events() {
flow3r_bsp_ad7147_refresh_events();
}
_callback(&_state);
void flow3r_bsp_captouch_init() {
esp_err_t ret = flow3r_bsp_ad7147_init();
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Captouch init failed: %s", esp_err_to_name(ret));
}
}
esp_err_t _gpio_interrupt_setup(gpio_num_t num, gpio_isr_t isr) {
esp_err_t ret;
gpio_config_t io_conf = {
.intr_type = GPIO_INTR_NEGEDGE,
.mode = GPIO_MODE_INPUT,
.pull_up_en = true,
.pin_bit_mask = (1 << num),
void flow3r_bsp_captouch_set_data_callback(flow3r_bsp_data_callback_t fun) {
flow3r_bsp_ad7147_set_data_callback(fun);
};
if ((ret = gpio_config(&io_conf)) != ESP_OK) {
return ret;
}
if ((ret = gpio_isr_handler_add(num, isr, NULL)) != ESP_OK) {
return ret;
}
return ESP_OK;
}
esp_err_t flow3r_bsp_captouch_init(flow3r_bsp_captouch_callback_t callback) {
assert(_callback == NULL);
assert(callback != NULL);
_callback = callback;
_q = xQueueCreate(2, sizeof(bool));
assert(_q != NULL);
esp_err_t ret;
for (size_t i = 0; i < 10; i++) {
bool top = (i % 2) == 0;
_state.petals[i].kind = top ? petal_top : petal_bottom;
_state.petals[i].ccw.kind = petal_pad_ccw;
_state.petals[i].ccw.threshold = top ? 8000 : 12000;
_state.petals[i].cw.kind = petal_pad_cw;
_state.petals[i].cw.threshold = top ? 8000 : 12000;
_state.petals[i].tip.kind = petal_pad_tip;
_state.petals[i].tip.threshold = top ? 8000 : 12000;
_state.petals[i].base.kind = petal_pad_base;
_state.petals[i].base.threshold = top ? 8000 : 12000;
}
_top.callback = _on_chip_data;
_top.user = &_top;
_bot.callback = _on_chip_data;
_bot.user = &_bot;
if ((ret = flow3r_bsp_ad7147_chip_init(
&_top, flow3r_i2c_addresses.touch_top)) != ESP_OK) {
return ret;
}
if ((ret = flow3r_bsp_ad7147_chip_init(
&_bot, flow3r_i2c_addresses.touch_bottom)) != ESP_OK) {
return ret;
}
ESP_LOGI(TAG, "Captouch initialized");
if ((ret = gpio_install_isr_service(ESP_INTR_FLAG_SHARED |
ESP_INTR_FLAG_LOWMED)) != ESP_OK) {
ESP_LOGE(TAG, "Failed to install GPIO ISR service");
return ret;
}
if ((ret = _gpio_interrupt_setup(_interrupt_gpio_bot, _bot_isr)) !=
ESP_OK) {
ESP_LOGE(TAG, "Failed to add bottom captouch ISR");
return ret;
}
if (!_interrupt_shared) {
// On badges with shared interrupts, only install the 'bot' ISR as a
// shared ISR.
if ((ret = _gpio_interrupt_setup(_interrupt_gpio_top, _top_isr)) !=
ESP_OK) {
ESP_LOGE(TAG, "Failed to add top captouch ISR");
return ret;
}
}
xTaskCreate(&_task, "captouch", 4096, NULL, configMAX_PRIORITIES - 1, NULL);
_kickstart();
return ESP_OK;
}
const flow3r_bsp_captouch_petal_pad_state_t *
flow3r_bsp_captouch_pad_for_petal_const(
const flow3r_bsp_captouch_petal_state_t *petal, petal_pad_kind_t kind) {
switch (kind) {
case petal_pad_tip:
return &petal->tip;
case petal_pad_base:
return &petal->base;
case petal_pad_cw:
return &petal->cw;
case petal_pad_ccw:
return &petal->ccw;
}
assert(0);
}
flow3r_bsp_captouch_petal_pad_state_t *flow3r_bsp_captouch_pad_for_petal(
flow3r_bsp_captouch_petal_state_t *petal, petal_pad_kind_t kind) {
switch (kind) {
case petal_pad_tip:
return &petal->tip;
case petal_pad_base:
return &petal->base;
case petal_pad_cw:
return &petal->cw;
case petal_pad_ccw:
return &petal->ccw;
}
assert(0);
}
void flow3r_bsp_captouch_calibrate() {
_bot.calibration_pending = true;
_top.calibration_pending = true;
}
bool flow3r_bsp_captouch_calibrating() {
bool bot = _bot.calibration_pending || _bot.calibration_cycles > 0;
bool top = _top.calibration_pending || _top.calibration_cycles > 0;
return bot || top;
}
void flow3r_bsp_captouch_set_petal_modes(
flow3r_bsp_captouch_petal_mode_t *data) {
flow3r_bsp_ad7147_set_petal_modes(data);
};
void flow3r_bsp_captouch_get_petal_modes(
flow3r_bsp_captouch_petal_mode_t *data) {
flow3r_bsp_ad7147_get_petal_modes(data);
};
#endif
......@@ -12,77 +12,78 @@
// port, and is a top petal. Petal 1 is a bottom petal to its right. Petal 2 is
// a top petal to its right, and the rest continue clockwise accordingly.
#include "esp_err.h"
#include <stdbool.h>
#include <stdint.h>
// One of the four possible touch points (pads) on a petal. Top petals have
// base/cw/ccw. Bottom petals have base/tip.
typedef enum {
// Pad away from centre of badge.
petal_pad_tip = 0,
// Pad going counter-clockwise around the badge.
petal_pad_ccw = 1,
// Pad going clockwise around the badge.
petal_pad_cw = 2,
// Pad going towards the centre of the badge.
petal_pad_base = 3,
} petal_pad_kind_t;
// Each petal can be either top or bottom.
typedef enum {
// Petal on the top layer. Has base, cw, ccw pads.
petal_top = 0,
// petal on the bottom layer. Has base and tip fields.
petal_bottom = 1,
} petal_kind_t;
#define FLOW3R_BSP_CAPTOUCH_RAD_UNIT (16384.)
#define FLOW3R_BSP_CAPTOUCH_PHI_UNIT (16384.)
#define FLOW3R_BSP_CAPTOUCH_COVERAGE_UNIT (1024.)
// allows to compare two different positional algorithms.
// unlocks the "._pos2" attribute on regular captouch output (but not on log
// frames) #define FLOW3R_BSP_CAPTOUCH_SECONDARY_OUTPUT
// State of a petal's pad.
typedef struct {
// Is it a top or bottom petal?
petal_pad_kind_t kind;
// Raw value, compensated for ambient value.
uint16_t raw;
// Configured threshold for touch detection.
uint16_t threshold;
} flow3r_bsp_captouch_petal_pad_state_t;
// State of a petal. Only the fields relevant to the petal kind (tip/base or
// base/cw/ccw) are present.
typedef struct {
petal_kind_t kind;
flow3r_bsp_captouch_petal_pad_state_t tip;
flow3r_bsp_captouch_petal_pad_state_t ccw;
flow3r_bsp_captouch_petal_pad_state_t cw;
flow3r_bsp_captouch_petal_pad_state_t base;
} flow3r_bsp_captouch_petal_state_t;
// State of all petals of the badge.
typedef struct {
flow3r_bsp_captouch_petal_state_t petals[10];
} flow3r_bsp_captouch_state_t;
int16_t rad;
int16_t phi;
#ifdef FLOW3R_BSP_CAPTOUCH_SECONDARY_OUTPUT
int16_t rad2;
int16_t phi2;
#endif
uint16_t coverage;
uint8_t index : 4;
uint8_t mode : 2;
uint8_t press_event : 1;
uint8_t pressed : 1;
} flow3r_bsp_captouch_petal_data_t;
typedef void (*flow3r_bsp_captouch_callback_t)(
const flow3r_bsp_captouch_state_t *state);
typedef struct {
flow3r_bsp_captouch_petal_data_t petals[10];
} flow3r_bsp_captouch_data_t;
// Initialize captouch subsystem with a given callback. This callback will be
// called any time new captouch data is available. The given data will be valid
// for the lifetime of the function, so should be copied by users.
//
// An interrupt and task will be set up to handle the data processing.
esp_err_t flow3r_bsp_captouch_init(flow3r_bsp_captouch_callback_t callback);
void flow3r_bsp_captouch_get(flow3r_bsp_captouch_data_t *dest);
void flow3r_bsp_captouch_refresh_events();
// Get a given petal's pad data for a given petal kind.
const flow3r_bsp_captouch_petal_pad_state_t *
flow3r_bsp_captouch_pad_for_petal_const(
const flow3r_bsp_captouch_petal_state_t *petal, petal_pad_kind_t kind);
flow3r_bsp_captouch_petal_pad_state_t *flow3r_bsp_captouch_pad_for_petal(
flow3r_bsp_captouch_petal_state_t *petal, petal_pad_kind_t kind);
// Initialize captouch subsystem.
void flow3r_bsp_captouch_init();
// Request captouch calibration.
void flow3r_bsp_captouch_calibrate();
void flow3r_bsp_captouch_calibration_request();
// Returns true if captouch is currently calibrating.
//
// TODO(q3k): this seems glitchy, investigate.
bool flow3r_bsp_captouch_calibrating();
int flow3r_bsp_captouch_calibrating();
// Set/get calibration data. data[] should be at least 120 entries long.
bool flow3r_bsp_captouch_get_calibration_data(int32_t *data);
void flow3r_bsp_captouch_set_calibration_data(int32_t *data);
// experiments
float flow3r_bsp_captouch_get_rad(flow3r_bsp_captouch_petal_data_t *petal,
uint8_t smooth, uint8_t drop_first,
uint8_t drop_last);
float flow3r_bsp_captouch_get_phi(flow3r_bsp_captouch_petal_data_t *petal,
uint8_t smooth, uint8_t drop_first,
uint8_t drop_last);
void flow3r_bsp_captouch_get_rad_raw(flow3r_bsp_captouch_petal_data_t *petal,
float *ret);
void flow3r_bsp_captouch_get_phi_raw(flow3r_bsp_captouch_petal_data_t *petal,
float *ret);
// uint8_t petal, bool pressed, uint32_t time_us, int32_t rad, int32_t phi,
// int32_t coverage
typedef void (*flow3r_bsp_data_callback_t)(uint8_t, uint8_t, bool, uint32_t,
int32_t, int32_t, int32_t);
void flow3r_bsp_captouch_set_data_callback(flow3r_bsp_data_callback_t fun);
typedef enum {
PETAL_MODE_OFF = 0,
PETAL_MODE_0D = 1,
PETAL_MODE_1D = 2,
PETAL_MODE_2D = 3,
} flow3r_bsp_captouch_petal_mode_t;
void flow3r_bsp_captouch_set_petal_modes(
flow3r_bsp_captouch_petal_mode_t *data);
void flow3r_bsp_captouch_get_petal_modes(
flow3r_bsp_captouch_petal_mode_t *data);