diff --git a/.github/workflows/githubci.yml b/.github/workflows/githubci.yml index 195ff8aa3..d42816007 100644 --- a/.github/workflows/githubci.yml +++ b/.github/workflows/githubci.yml @@ -7,8 +7,7 @@ jobs: strategy: fail-fast: false matrix: - arduino-platform: ["uno", "nrf52832", "cpx_ada", "pyportal", "protrinket_3v", "protrinket_5v", "metro_m0", "esp8266", "esp32", "trinket_3v", "gemma", "flora", "feather32u4", "feather_m0_express", "gemma_m0", "trinket_m0", "hallowing_m0", "monster_m4sk", "hallowing_m4", "hallowing_m4_tinyusb", "neotrellis_m4", "pybadge", "cpb", "cpc", "funhouse", "magtag"] - # "trinket_5v", was removed + arduino-platform: ["cpb", "cpc", "cpx_ada", "esp32", "esp8266", "feather32u4", "feather_m0_express", "feather_m4_express", "feather_rp2040", "flora", "funhouse", "gemma", "gemma_m0", "hallowing_m0", "hallowing_m4_tinyusb", "magtag", "metro_m0", "metro_m0_tinyusb", "metro_m4", "metro_m4_tinyusb", "monster_m4sk", "monster_m4sk_tinyusb", "neokeytrinkey_m0", "neotrellis_m4", "nrf52832", "nrf52840", "protrinket_5v", "proxlighttrinkey_m0", "pybadge", "pygamer", "pyportal", "qt2040_trinkey", "qtpy_m0", "rotarytrinkey_m0", "slidetrinkey_m0", "trinket_m0", "uno", "trinket_5v", "ledglasses_nrf52840" ] runs-on: ubuntu-18.04 steps: @@ -39,6 +38,34 @@ jobs: - name: test platforms run: python3 ci/build_platform.py ${{ matrix.arduino-platform }} + - name: Upload build artifacts + uses: actions/upload-artifact@v2 + with: + name: ${{ github.event.repository.name }}.${{ github.sha }} + path: | + build/*.hex + build/*.bin + build/*.uf2 + + - name: Zip release files + if: startsWith(github.ref, 'refs/tags/') + run: | + if [ -d build ]; then + ( + echo "Built from Adafruit Learning System Guides `git describe --tags` for ${{ matrix.arduino-platform }}" + echo "Source code: https://github.com/adafruit/" + echo "Adafruit Learning System: https://learn.adafruit.com/" + ) > build/README.txt + cd build && zip -9 -o ${{ matrix.arduino-platform }}.zip *.hex *.bin *.uf2 *.txt + fi + + - name: Create release + if: startsWith(github.ref, 'refs/tags/') + uses: softprops/action-gh-release@v1 + with: + files: build/${{ matrix.arduino-platform }}.zip + fail_on_unmatched_files: false + body: "Select the zip file corresponding to your board from the list below." pylint: runs-on: ubuntu-latest diff --git a/.pylintrc b/.pylintrc index c88a7fadc..7791f53d2 100644 --- a/.pylintrc +++ b/.pylintrc @@ -52,7 +52,7 @@ confidence= # no Warning level messages displayed, use"--disable=all --enable=classes # --disable=W" # disable=import-error,print-statement,parameter-unpacking,unpacking-in-except,old-raise-syntax,backtick,long-suffix,old-ne-operator,old-octal-literal,import-star-module-level,raw-checker-failed,bad-inline-option,locally-disabled,locally-enabled,file-ignored,suppressed-message,useless-suppression,deprecated-pragma,apply-builtin,basestring-builtin,buffer-builtin,cmp-builtin,coerce-builtin,execfile-builtin,file-builtin,long-builtin,raw_input-builtin,reduce-builtin,standarderror-builtin,unicode-builtin,xrange-builtin,coerce-method,delslice-method,getslice-method,setslice-method,no-absolute-import,old-division,dict-iter-method,dict-view-method,next-method-called,metaclass-assignment,indexing-exception,raising-string,reload-builtin,oct-method,hex-method,nonzero-method,cmp-method,input-builtin,round-builtin,intern-builtin,unichr-builtin,map-builtin-not-iterating,zip-builtin-not-iterating,range-builtin-not-iterating,filter-builtin-not-iterating,using-cmp-argument,eq-without-hash,div-method,idiv-method,rdiv-method,exception-message-attribute,invalid-str-codec,sys-max-int,bad-python3-import,deprecated-string-function,deprecated-str-translate-call -disable=too-many-instance-attributes,len-as-condition,too-few-public-methods,anomalous-backslash-in-string,no-else-return,simplifiable-if-statement,too-many-arguments,duplicate-code,no-name-in-module,no-member,print-statement,parameter-unpacking,unpacking-in-except,old-raise-syntax,backtick,long-suffix,old-ne-operator,old-octal-literal,import-star-module-level,raw-checker-failed,bad-inline-option,locally-disabled,locally-enabled,file-ignored,suppressed-message,useless-suppression,deprecated-pragma,apply-builtin,basestring-builtin,buffer-builtin,cmp-builtin,coerce-builtin,execfile-builtin,file-builtin,long-builtin,raw_input-builtin,reduce-builtin,standarderror-builtin,unicode-builtin,xrange-builtin,coerce-method,delslice-method,getslice-method,setslice-method,no-absolute-import,old-division,dict-iter-method,dict-view-method,next-method-called,metaclass-assignment,indexing-exception,raising-string,reload-builtin,oct-method,hex-method,nonzero-method,cmp-method,input-builtin,round-builtin,intern-builtin,unichr-builtin,map-builtin-not-iterating,zip-builtin-not-iterating,range-builtin-not-iterating,filter-builtin-not-iterating,using-cmp-argument,eq-without-hash,div-method,idiv-method,rdiv-method,exception-message-attribute,invalid-str-codec,sys-max-int,bad-python3-import,deprecated-string-function,deprecated-str-translate-call,import-error,missing-docstring,invalid-name,bad-whitespace,consider-using-enumerate,unexpected-keyword-arg +disable=too-many-instance-attributes,len-as-condition,too-few-public-methods,anomalous-backslash-in-string,no-else-return,simplifiable-if-statement,too-many-arguments,duplicate-code,no-name-in-module,no-member,print-statement,parameter-unpacking,unpacking-in-except,old-raise-syntax,backtick,long-suffix,old-ne-operator,old-octal-literal,import-star-module-level,raw-checker-failed,bad-inline-option,locally-disabled,locally-enabled,file-ignored,suppressed-message,useless-suppression,deprecated-pragma,apply-builtin,basestring-builtin,buffer-builtin,cmp-builtin,coerce-builtin,execfile-builtin,file-builtin,long-builtin,raw_input-builtin,reduce-builtin,standarderror-builtin,unicode-builtin,xrange-builtin,coerce-method,delslice-method,getslice-method,setslice-method,no-absolute-import,old-division,dict-iter-method,dict-view-method,next-method-called,metaclass-assignment,indexing-exception,raising-string,reload-builtin,oct-method,hex-method,nonzero-method,cmp-method,input-builtin,round-builtin,intern-builtin,unichr-builtin,map-builtin-not-iterating,zip-builtin-not-iterating,range-builtin-not-iterating,filter-builtin-not-iterating,using-cmp-argument,eq-without-hash,div-method,idiv-method,rdiv-method,exception-message-attribute,invalid-str-codec,sys-max-int,bad-python3-import,deprecated-string-function,deprecated-str-translate-call,import-error,missing-docstring,invalid-name,bad-whitespace,consider-using-enumerate,unexpected-keyword-arg,consider-using-f-string # Enable the message, report, category or checker with the given id(s). You can # either give multiple identifier separated by comma (,) or put this option diff --git a/2020_shake/.m4.test.only b/2020_shake/.metro_m4.test.only similarity index 100% rename from 2020_shake/.m4.test.only rename to 2020_shake/.metro_m4.test.only diff --git a/2020_shake/2020.h b/2020_shake/2020.h index dec83ee7f..fdfd4ec5f 100644 --- a/2020_shake/2020.h +++ b/2020_shake/2020.h @@ -1,6 +1,6 @@ -# SPDX-FileCopyrightText: 2020 Limor Fried for Adafruit Industries -# -# SPDX-License-Identifier: MIT +// SPDX-FileCopyrightText: 2020 Limor Fried for Adafruit Industries +// +// SPDX-License-Identifier: MIT #define BITMAP_WIDTH 64 #define BITMAP_HEIGHT 32 diff --git a/2020_shake/2020_shake.ino b/2020_shake/2020_shake.ino index 93cb37b6c..63047bcc5 100644 --- a/2020_shake/2020_shake.ino +++ b/2020_shake/2020_shake.ino @@ -1,6 +1,6 @@ -# SPDX-FileCopyrightText: 2020 Limor Fried for Adafruit Industries -# -# SPDX-License-Identifier: MIT +// SPDX-FileCopyrightText: 2020 Limor Fried for Adafruit Industries +// +// SPDX-License-Identifier: MIT #include // For accelerometer #include // For simulation diff --git a/2020_shake/2021.h b/2020_shake/2021.h index b1ae37afb..ef43651f1 100644 --- a/2020_shake/2021.h +++ b/2020_shake/2021.h @@ -1,6 +1,6 @@ -# SPDX-FileCopyrightText: 2020 Limor Fried for Adafruit Industries -# -# SPDX-License-Identifier: MIT +// SPDX-FileCopyrightText: 2020 Limor Fried for Adafruit Industries +// +// SPDX-License-Identifier: MIT const uint8_t PROGMEM bitmap_2021[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, diff --git a/3D_Printed_Bionic_Eye/.trinket5v.test.only b/3D_Printed_Bionic_Eye/.trinket_5v.test.only similarity index 100% rename from 3D_Printed_Bionic_Eye/.trinket5v.test.only rename to 3D_Printed_Bionic_Eye/.trinket_5v.test.only diff --git a/3D_Printed_Bionic_Eye/3D_Printed_Bionic_Eye.ino b/3D_Printed_Bionic_Eye/3D_Printed_Bionic_Eye.ino index 6a8a6d38f..b7de3a772 100644 --- a/3D_Printed_Bionic_Eye/3D_Printed_Bionic_Eye.ino +++ b/3D_Printed_Bionic_Eye/3D_Printed_Bionic_Eye.ino @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2018 Bill Earl and Mikey Sklar for Adafruit Industries +// +// SPDX-License-Identifier: MIT /******************************************************************* Bionic Eye sketch for Adafruit Trinket. diff --git a/3D_Printed_Bionic_Eye/code.py b/3D_Printed_Bionic_Eye/code.py index 3d0ee9657..c054b2922 100644 --- a/3D_Printed_Bionic_Eye/code.py +++ b/3D_Printed_Bionic_Eye/code.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2018 Bill Earl and Mikey Sklar for Adafruit Industries +# +# SPDX-License-Identifier: MIT +# # Bionic Eye sketch for Adafruit Trinket. # # written by Bill Earl for Arduino diff --git a/3D_Printed_Daft_Punk_Helmet/.trinket5v.test.only b/3D_Printed_Daft_Punk_Helmet/3D_Printed_Daft_Punk_Helmet-Front-Animation/.trinket_5v.test.only similarity index 100% rename from 3D_Printed_Daft_Punk_Helmet/.trinket5v.test.only rename to 3D_Printed_Daft_Punk_Helmet/3D_Printed_Daft_Punk_Helmet-Front-Animation/.trinket_5v.test.only diff --git a/3D_Printed_Daft_Punk_Helmet/3D_Printed_Daft_Punk_Helmet-Front-Animation.ino b/3D_Printed_Daft_Punk_Helmet/3D_Printed_Daft_Punk_Helmet-Front-Animation/3D_Printed_Daft_Punk_Helmet-Front-Animation.ino similarity index 97% rename from 3D_Printed_Daft_Punk_Helmet/3D_Printed_Daft_Punk_Helmet-Front-Animation.ino rename to 3D_Printed_Daft_Punk_Helmet/3D_Printed_Daft_Punk_Helmet-Front-Animation/3D_Printed_Daft_Punk_Helmet-Front-Animation.ino index 879b72aa3..f62334267 100644 --- a/3D_Printed_Daft_Punk_Helmet/3D_Printed_Daft_Punk_Helmet-Front-Animation.ino +++ b/3D_Printed_Daft_Punk_Helmet/3D_Printed_Daft_Punk_Helmet-Front-Animation/3D_Printed_Daft_Punk_Helmet-Front-Animation.ino @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: 2014 Phil Burgess for Adafruit Industries +// +// SPDX-License-Identifier: MIT +// // Fiery demon horns (rawr!) for Adafruit Trinket/Gemma. // Adafruit invests time and resources providing this open source code, // please support Adafruit and open-source hardware by purchasing @@ -26,7 +30,7 @@ struct { long fade; // Decreases brightness as wave moves // Gamma correction improves appearance of midrange colors -uint8_t gamma[] PROGMEM = { +const uint8_t gamma[] PROGMEM = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, diff --git a/3D_Printed_Daft_Punk_Helmet/3D_Printed_Daft_Punk_Helmet-Front-Animation/code.py b/3D_Printed_Daft_Punk_Helmet/3D_Printed_Daft_Punk_Helmet-Front-Animation/code.py index 0b0cf4e32..bcf959170 100644 --- a/3D_Printed_Daft_Punk_Helmet/3D_Printed_Daft_Punk_Helmet-Front-Animation/code.py +++ b/3D_Printed_Daft_Punk_Helmet/3D_Printed_Daft_Punk_Helmet-Front-Animation/code.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2014 Phil Burgess for Adafruit Industries +# +# SPDX-License-Identifier: MIT + # Fiery demon horns (rawr!) for Adafruit Trinket/Gemma. # Adafruit invests time and resources providing this open source code, # please support Adafruit and open-source hardware by purchasing diff --git a/3D_Printed_Guardian_Sword/.trinket5v.test.only b/3D_Printed_Daft_Punk_Helmet/3D_Printed_Daft_Punk_Helmet-Side-Animation/.trinket_5v.test.only similarity index 100% rename from 3D_Printed_Guardian_Sword/.trinket5v.test.only rename to 3D_Printed_Daft_Punk_Helmet/3D_Printed_Daft_Punk_Helmet-Side-Animation/.trinket_5v.test.only diff --git a/3D_Printed_Daft_Punk_Helmet/3D_Printed_Daft_Punk_Helmet-Side-Animation.ino b/3D_Printed_Daft_Punk_Helmet/3D_Printed_Daft_Punk_Helmet-Side-Animation/3D_Printed_Daft_Punk_Helmet-Side-Animation.ino similarity index 98% rename from 3D_Printed_Daft_Punk_Helmet/3D_Printed_Daft_Punk_Helmet-Side-Animation.ino rename to 3D_Printed_Daft_Punk_Helmet/3D_Printed_Daft_Punk_Helmet-Side-Animation/3D_Printed_Daft_Punk_Helmet-Side-Animation.ino index 6013f5ee3..55a75b748 100644 --- a/3D_Printed_Daft_Punk_Helmet/3D_Printed_Daft_Punk_Helmet-Side-Animation.ino +++ b/3D_Printed_Daft_Punk_Helmet/3D_Printed_Daft_Punk_Helmet-Side-Animation/3D_Printed_Daft_Punk_Helmet-Side-Animation.ino @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: 2014 Phil Burgess for Adafruit Industries +// +// SPDX-License-Identifier: MIT + // Adafruit Trinket+NeoPixel animation for Daft Punk-inspired helmet. // Contains some ATtiny85-specific stuff; won't run as-is on Uno, etc. diff --git a/3D_Printed_Daft_Punk_Helmet/3D_Printed_Daft_Punk_Helmet-Side-Animation/code.py b/3D_Printed_Daft_Punk_Helmet/3D_Printed_Daft_Punk_Helmet-Side-Animation/code.py index f9a21deec..998d4c432 100644 --- a/3D_Printed_Daft_Punk_Helmet/3D_Printed_Daft_Punk_Helmet-Side-Animation/code.py +++ b/3D_Printed_Daft_Punk_Helmet/3D_Printed_Daft_Punk_Helmet-Side-Animation/code.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2014 Phil Burgess for Adafruit Industries +# +# SPDX-License-Identifier: MIT + # Adafruit Trinket+NeoPixel animation for Daft Punk-inspired helmet. # Contains some ATtiny85-specific stuff; won't run as-is on Uno, etc. diff --git a/3D_Printed_LED-Animation_BMO/.trinket5v.test.only b/3D_Printed_Guardian_Sword/.trinket_5v.test.only similarity index 100% rename from 3D_Printed_LED-Animation_BMO/.trinket5v.test.only rename to 3D_Printed_Guardian_Sword/.trinket_5v.test.only diff --git a/3D_Printed_Guardian_Sword/3D_Printed_Guardian_Sword.ino b/3D_Printed_Guardian_Sword/3D_Printed_Guardian_Sword.ino index 6b6ac09ea..ae9d372b0 100644 --- a/3D_Printed_Guardian_Sword/3D_Printed_Guardian_Sword.ino +++ b/3D_Printed_Guardian_Sword/3D_Printed_Guardian_Sword.ino @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: 2018 Mikey Sklar for Adafruit Industries +// +// SPDX-License-Identifier: MIT + #include #ifdef __AVR__ #include diff --git a/3D_Printed_LED_Fire_Horns/.trinket5v.test.only b/3D_Printed_LED-Animation_BMO/.trinket_5v.test.only similarity index 100% rename from 3D_Printed_LED_Fire_Horns/.trinket5v.test.only rename to 3D_Printed_LED-Animation_BMO/.trinket_5v.test.only diff --git a/CPX_Compass/.ada_cpx.test.only b/3D_Printed_LED_Fire_Horns/.trinket_5v.test.only similarity index 100% rename from CPX_Compass/.ada_cpx.test.only rename to 3D_Printed_LED_Fire_Horns/.trinket_5v.test.only diff --git a/3D_Printed_LED_Fire_Horns/3D_Printed_LED_Fire_Horns.ino b/3D_Printed_LED_Fire_Horns/3D_Printed_LED_Fire_Horns.ino index 8054e3f4d..dc988a885 100644 --- a/3D_Printed_LED_Fire_Horns/3D_Printed_LED_Fire_Horns.ino +++ b/3D_Printed_LED_Fire_Horns/3D_Printed_LED_Fire_Horns.ino @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: 2017 Phil Burgess for Adafruit Industries +// +// SPDX-License-Identifier: MIT + // Fiery demon horns (rawr!) for Adafruit Trinket/Gemma. // Adafruit invests time and resources providing this open source code, // please support Adafruit and open-source hardware by purchasing diff --git a/3D_Printed_LED_Fire_Horns/code.py b/3D_Printed_LED_Fire_Horns/code.py index 0b0cf4e32..d6a665161 100644 --- a/3D_Printed_LED_Fire_Horns/code.py +++ b/3D_Printed_LED_Fire_Horns/code.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2018 Phil Burgess and Mikey Sklar for Adafruit Industries +# +# SPDX-License-Identifier: MIT + # Fiery demon horns (rawr!) for Adafruit Trinket/Gemma. # Adafruit invests time and resources providing this open source code, # please support Adafruit and open-source hardware by purchasing diff --git a/3D_Printed_LED_Microphone_Flag/.circuitpython.skip b/3D_Printed_LED_Microphone_Flag/.circuitpython.skip deleted file mode 100644 index 672652b69..000000000 --- a/3D_Printed_LED_Microphone_Flag/.circuitpython.skip +++ /dev/null @@ -1 +0,0 @@ -3D_Printed_LED_Microphone_Flag/3D_Printed_LED_Microphone_Flag.py 137: Consider using tuple unpacking for swapping variables (consider-swap-variables) diff --git a/Guitar_Hero_MIDI/.qtpy.test.only b/3D_Printed_LED_Microphone_Flag/.gemma_m0.generate similarity index 100% rename from Guitar_Hero_MIDI/.qtpy.test.only rename to 3D_Printed_LED_Microphone_Flag/.gemma_m0.generate diff --git a/3D_Printed_LED_Microphone_Flag/code.py b/3D_Printed_LED_Microphone_Flag/code.py index 33a55367f..8ef7ba723 100644 --- a/3D_Printed_LED_Microphone_Flag/code.py +++ b/3D_Printed_LED_Microphone_Flag/code.py @@ -120,9 +120,7 @@ def fscale(originalmin, originalmax, newbegin, newend, inputvalue, curve): def drawLine(fromhere, to): if fromhere > to: - fromheretemp = fromhere - fromhere = to - to = fromheretemp + to, fromhere = fromhere, to for index in range(fromhere, to): strip[index] = (0, 0, 0) diff --git a/Introducing_CircuitPlaygroundExpress/digitalio_lib/.ada_cpx.test.only b/3D_Printed_Unicorn_Horn/.gemma_m0.generate similarity index 100% rename from Introducing_CircuitPlaygroundExpress/digitalio_lib/.ada_cpx.test.only rename to 3D_Printed_Unicorn_Horn/.gemma_m0.generate diff --git a/Joy_of_Arcada/.pygamer.test.only b/3D_Printed_Unicorn_Horn/.gemma_m0.test.only similarity index 100% rename from Joy_of_Arcada/.pygamer.test.only rename to 3D_Printed_Unicorn_Horn/.gemma_m0.test.only diff --git a/ABC_Soundboards_for_NeoTrellis/code.py b/ABC_Soundboards_for_NeoTrellis/code.py index e85c97cd7..c3674d96d 100644 --- a/ABC_Soundboards_for_NeoTrellis/code.py +++ b/ABC_Soundboards_for_NeoTrellis/code.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2020 Anne Barela for Adafruit Industries +# +# SPDX-License-Identifier: MIT +# # Talking A, B, Cs Soundboards: Animal ABCs and "E is for Electronics" ABCs import time diff --git a/Keypad_4x4_Clocked/.qtpy.test.only b/ANO_Rotary_Encoder/ANO_Rotary_Encoder_NeoPixel_Arduino_Example/.feather_m4_express.test.only similarity index 100% rename from Keypad_4x4_Clocked/.qtpy.test.only rename to ANO_Rotary_Encoder/ANO_Rotary_Encoder_NeoPixel_Arduino_Example/.feather_m4_express.test.only diff --git a/ANO_Rotary_Encoder/ANO_Rotary_Encoder_NeoPixel_Arduino_Example/ANO_Rotary_Encoder_NeoPixel_Arduino_Example.ino b/ANO_Rotary_Encoder/ANO_Rotary_Encoder_NeoPixel_Arduino_Example/ANO_Rotary_Encoder_NeoPixel_Arduino_Example.ino new file mode 100644 index 000000000..2897d73e3 --- /dev/null +++ b/ANO_Rotary_Encoder/ANO_Rotary_Encoder_NeoPixel_Arduino_Example/ANO_Rotary_Encoder_NeoPixel_Arduino_Example.ino @@ -0,0 +1,88 @@ +// SPDX-FileCopyrightText: 2021 Kattni Rembor for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include +#include + +#define PIN_ENCODER_A 13 +#define PIN_ENCODER_B 12 +#define COM_A 11 +#define COM_B SDA +#define BUTTON_UP 5 +#define BUTTON_LEFT SCL +#define BUTTON_DOWN 9 +#define BUTTON_RIGHT 6 +#define BUTTON_IN 10 + +RotaryEncoder encoder(PIN_ENCODER_A, PIN_ENCODER_B, RotaryEncoder::LatchMode::TWO03); +// This interrupt will do our encoder reading/checking! +void checkPosition() { + encoder.tick(); // just call tick() to check the state. +} +int last_rotary = 0; + + +#define NUMPIXELS 12 +Adafruit_NeoPixel pixels(NUMPIXELS, A0, NEO_GRB + NEO_KHZ800); + + +void setup(void) { + Serial.begin(115200); + while (!Serial); + Serial.println("ANO Rotary Encoder Demo"); + + pinMode(COM_A, OUTPUT); + digitalWrite(COM_A, LOW); + pinMode(COM_B, OUTPUT); + digitalWrite(COM_B, LOW); + + attachInterrupt(PIN_ENCODER_A, checkPosition, CHANGE); + attachInterrupt(PIN_ENCODER_B, checkPosition, CHANGE); + + pinMode(BUTTON_UP, INPUT_PULLUP); + pinMode(BUTTON_DOWN, INPUT_PULLUP); + pinMode(BUTTON_LEFT, INPUT_PULLUP); + pinMode(BUTTON_RIGHT, INPUT_PULLUP); + pinMode(BUTTON_IN, INPUT_PULLUP); + pixels.begin(); + pixels.setBrightness(30); + pixels.show(); +} + + +void loop(void) { + // read encoder + int curr_rotary = encoder.getPosition(); + RotaryEncoder::Direction direction = encoder.getDirection(); + + pixels.clear(); + if (curr_rotary != last_rotary) { + Serial.print("Encoder value: "); + Serial.print(curr_rotary); + Serial.print(" direction: "); + Serial.println((int)direction); + } + last_rotary = curr_rotary; + + pixels.setPixelColor((curr_rotary + (1000*NUMPIXELS)) % NUMPIXELS, pixels.Color(0, 150, 0)); + + if (! digitalRead(BUTTON_UP)) { + pixels.setPixelColor(0, pixels.Color(150, 0, 0)); + } + if (! digitalRead(BUTTON_LEFT)) { + pixels.setPixelColor(NUMPIXELS/4, pixels.Color(150, 0, 0)); + } + if (! digitalRead(BUTTON_DOWN)) { + pixels.setPixelColor(NUMPIXELS/2, pixels.Color(150, 0, 0)); + } + if (! digitalRead(BUTTON_RIGHT)) { + pixels.setPixelColor(NUMPIXELS*3/4, pixels.Color(150, 0, 0)); + } + if (! digitalRead(BUTTON_IN)) { + pixels.fill(pixels.Color(50, 50, 50)); + } + pixels.show(); + + delay(20); +} diff --git a/ANO_Rotary_Encoder/ANO_Rotary_Encoder_NeoPixel_CircuitPython_Example/code.py b/ANO_Rotary_Encoder/ANO_Rotary_Encoder_NeoPixel_CircuitPython_Example/code.py new file mode 100644 index 000000000..d9ac3aa44 --- /dev/null +++ b/ANO_Rotary_Encoder/ANO_Rotary_Encoder_NeoPixel_CircuitPython_Example/code.py @@ -0,0 +1,78 @@ +# SPDX-FileCopyrightText: 2021 Kattni Rembor for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +""" +CircuitPython ANO Rotary Encoder and NeoPixel Ring example. +""" +import board +import digitalio +import rotaryio +import neopixel + +# The pin assignments for the breakout pins. Update this is you are not using a Feather. +ENCA = board.D13 +ENCB = board.D12 +COMA = board.D11 +SW1 = board.D10 +SW2 = board.D9 +SW3 = board.D6 +SW4 = board.D5 +SW5 = board.SCL +COMB = board.SDA + +# Rotary encoder setup +encoder = rotaryio.IncrementalEncoder(ENCA, ENCB) +last_position = None + +# NeoPixel ring setup. Update num_pixels if using a different ring. +num_pixels = 12 +pixels = neopixel.NeoPixel(board.A0, num_pixels, auto_write=False) + +# Set the COMA and COMB pins LOW. This is only necessary when using the direct-to-Feather or other +# GPIO-based wiring method. If connecting COMA and COMB to ground, you do not need to include this. +com_a = digitalio.DigitalInOut(COMA) +com_a.switch_to_output() +com_a = False +com_b = digitalio.DigitalInOut(COMB) +com_b.switch_to_output() +com_b = False + +# Button pin setup +button_pins = (SW1, SW2, SW3, SW4, SW5) +buttons = [] +for button_pin in button_pins: + pin = digitalio.DigitalInOut(button_pin) + pin.switch_to_input(digitalio.Pull.UP) + buttons.append(pin) + +while True: + position = encoder.position + if last_position is None or position != last_position: + print("Position: {}".format(position)) + last_position = position + + pixels.fill((0, 0, 0)) + pixels[position % num_pixels] = (0, 150, 0) + + if not buttons[0].value: + print("Center button!") + pixels.fill((100, 100, 100)) + + if not buttons[1].value: + print("Up button!") + pixels[0] = (150, 0 ,0) + + if not buttons[2].value: + print("Left button!") + pixels[3] = (150, 0, 0) + + if not buttons[3].value: + print("Down button!") + pixels[6] = (150, 0, 0) + + if not buttons[4].value: + print("Right button!") + pixels[9] = (150, 0, 0) + + pixels.show() diff --git a/Adafruit_Prop_Maker_FeatherWing/Prop_Maker_LED_Simpletest/Prop_Maker_LED_Simpletest.ino b/Adafruit_Prop_Maker_FeatherWing/Prop_Maker_LED_Simpletest/Prop_Maker_LED_Simpletest.ino index c00d07c11..ffcf5101c 100644 --- a/Adafruit_Prop_Maker_FeatherWing/Prop_Maker_LED_Simpletest/Prop_Maker_LED_Simpletest.ino +++ b/Adafruit_Prop_Maker_FeatherWing/Prop_Maker_LED_Simpletest/Prop_Maker_LED_Simpletest.ino @@ -5,7 +5,11 @@ * Rainbow swirl example for 3W LED. */ -#if defined(__SAMD21G18A__) || defined(__AVR_ATmega32U4__) +#ifdef USE_TINYUSB // For Serial when selecting TinyUSB +#include +#endif + +#if defined(__SAMD21G18A__) || defined(__AVR_ATmega32U4__) || defined(NRF52840_XXAA) // No green PWM on 32u4 #define POWER_PIN 10 #define RED_LED 11 diff --git a/Adafruit_Prop_Maker_FeatherWing/Prop_Maker_NeoPixel_Simpletest/Prop_Maker_NeoPixel_Simpletest.ino b/Adafruit_Prop_Maker_FeatherWing/Prop_Maker_NeoPixel_Simpletest/Prop_Maker_NeoPixel_Simpletest.ino index 9ab569e23..26e27ccca 100644 --- a/Adafruit_Prop_Maker_FeatherWing/Prop_Maker_NeoPixel_Simpletest/Prop_Maker_NeoPixel_Simpletest.ino +++ b/Adafruit_Prop_Maker_FeatherWing/Prop_Maker_NeoPixel_Simpletest/Prop_Maker_NeoPixel_Simpletest.ino @@ -6,10 +6,14 @@ */ #include +#ifdef USE_TINYUSB // For Serial when selecting TinyUSB +#include +#endif + // NeoPixel strip length, in pixels #define NUM_PIXELS 30 -#if defined(__SAMD21G18A__) || defined(__AVR_ATmega32U4__) +#if defined(__SAMD21G18A__) || defined(__AVR_ATmega32U4__) || defined(NRF52840_XXAA) #define NEOPIXEL_PIN 5 #define POWER_PIN 10 #elif defined(__AVR_ATmega328P__) diff --git a/Adafruit_Prop_Maker_FeatherWing/Prop_Maker_Switch_Simpletest/Prop_Maker_Switch_Simpletest.ino b/Adafruit_Prop_Maker_FeatherWing/Prop_Maker_Switch_Simpletest/Prop_Maker_Switch_Simpletest.ino index f1a2e3001..74ea1a395 100644 --- a/Adafruit_Prop_Maker_FeatherWing/Prop_Maker_Switch_Simpletest/Prop_Maker_Switch_Simpletest.ino +++ b/Adafruit_Prop_Maker_FeatherWing/Prop_Maker_Switch_Simpletest/Prop_Maker_Switch_Simpletest.ino @@ -5,7 +5,11 @@ * Print to the Serial Montior when a switch is pressed. */ -#if defined(__SAMD21G18A__) || defined(__AVR_ATmega32U4__) +#ifdef USE_TINYUSB // For Serial when selecting TinyUSB +#include +#endif + +#if defined(__SAMD21G18A__) || defined(__AVR_ATmega32U4__) || defined(NRF52840_XXAA) #define SWITCH_PIN 9 #elif defined(__AVR_ATmega328P__) #define SWITCH_PIN 9 diff --git a/All_Seeing_Skull/.teensy3.test.only b/All_Seeing_Skull/.none.test.only similarity index 100% rename from All_Seeing_Skull/.teensy3.test.only rename to All_Seeing_Skull/.none.test.only diff --git a/MIDI_FeatherWing/.funhouse.test.skip b/CPX_Compass/.cpx_ada.test.only similarity index 100% rename from MIDI_FeatherWing/.funhouse.test.skip rename to CPX_Compass/.cpx_ada.test.only diff --git a/CircuitPython_Display_Text/colormask_example/code.py b/CircuitPython_Display_Text/colormask_example/code.py index f4ffffa81..519c689ec 100644 --- a/CircuitPython_Display_Text/colormask_example/code.py +++ b/CircuitPython_Display_Text/colormask_example/code.py @@ -44,7 +44,7 @@ rainbow_bitmap = displayio.Bitmap( rainbow_palette = displayio.Palette(255) for i in range(0, 255): - rainbow_palette[i] = int("".join("%02x" % i for i in colorwheel(i)), 16) + rainbow_palette[i] = colorwheel(i) for y in range(rainbow_bitmap.height): for x in range(rainbow_bitmap.width): diff --git a/CircuitPython_Templates/i2c_find_pins/code.py b/CircuitPython_Templates/i2c_find_pins/code.py index ddb6bea8f..52bb1dd4b 100644 --- a/CircuitPython_Templates/i2c_find_pins/code.py +++ b/CircuitPython_Templates/i2c_find_pins/code.py @@ -29,6 +29,10 @@ def get_unique_pins(): "LED", "SWITCH", "BUTTON", + "ACCELEROMETER_INTERRUPT", + "VOLTAGE_MONITOR", + "MICROPHONE_CLOCK", + "MICROPHONE_DATA", ] if p in dir(board) ] diff --git a/Circuit_Playground_Express_IR_Treasure_Hunt/CPX_Treasure/code.py b/Circuit_Playground_Express_IR_Treasure_Hunt/CPX_Treasure/code.py index e414c9c25..d689760f1 100644 --- a/Circuit_Playground_Express_IR_Treasure_Hunt/CPX_Treasure/code.py +++ b/Circuit_Playground_Express_IR_Treasure_Hunt/CPX_Treasure/code.py @@ -1,6 +1,5 @@ import time import board -import pwmio import pulseio import adafruit_irremote import neopixel @@ -12,9 +11,8 @@ TRANSMIT_DELAY = 15 # change this as desired to affect game dynamics, or just l # Create NeoPixel object to indicate status pixels = neopixel.NeoPixel(board.NEOPIXEL, 10) -# Create a 'pwmio' output, to send infrared signals on the IR transmitter @ 38KHz -pwm = pwmio.PWMOut(board.IR_TX, frequency=38000, duty_cycle=2 ** 15) -pulseout = pulseio.PulseOut(pwm) +# Create a 'pulseio' output, to send infrared signals on the IR transmitter @ 38KHz +pulseout = pulseio.PulseOut(board.IR_TX, frequency=38000, duty_cycle=2 ** 15) # Create an encoder that will take numbers and turn them into IR pulses encoder = adafruit_irremote.GenericTransmit(header=[9500, 4500], diff --git a/Circuit_Playground_Express_IR_Zombie_Game/code.py b/Circuit_Playground_Express_IR_Zombie_Game/code.py index b80989a6d..3322d3b26 100755 --- a/Circuit_Playground_Express_IR_Zombie_Game/code.py +++ b/Circuit_Playground_Express_IR_Zombie_Game/code.py @@ -1,6 +1,5 @@ import time import pulseio -import pwmio import board import adafruit_irremote import digitalio @@ -22,9 +21,8 @@ pulsein = pulseio.PulseIn(board.IR_RX, maxlen=120, idle_state=True) # Create a decoder that will take pulses and turn them into numbers decoder = adafruit_irremote.GenericDecode() -# Create a 'pwmio' output, to send infrared signals on the IR transmitter @ 38KHz -pwm = pwmio.PWMOut(board.IR_TX, frequency=38000, duty_cycle=2 ** 15) -pulseout = pulseio.PulseOut(pwm) +# Create a 'pulseio' output, to send infrared signals on the IR transmitter @ 38KHz +pulseout = pulseio.PulseOut(board.IR_TX, frequency=38000, duty_cycle=2 ** 15) # Create an encoder that will take numbers and turn them into NEC IR pulses encoder = adafruit_irremote.GenericTransmit(header=[9500, 4500], one=[550, 550], zero=[550, 1700], trail=0) diff --git a/Circuit_Playground_Express_and_IR/CPX_IR_CPX_transmit/code.py b/Circuit_Playground_Express_and_IR/CPX_IR_CPX_transmit/code.py index db9a5b667..524c4d0e4 100644 --- a/Circuit_Playground_Express_and_IR/CPX_IR_CPX_transmit/code.py +++ b/Circuit_Playground_Express_and_IR/CPX_IR_CPX_transmit/code.py @@ -2,12 +2,10 @@ import time from adafruit_circuitplayground.express import cpx import adafruit_irremote import pulseio -import pwmio import board -# Create a 'pwmio' output, to send infrared signals on the IR transmitter @ 38KHz -pwm = pwmio.PWMOut(board.IR_TX, frequency=38000, duty_cycle=2 ** 15) -pulseout = pulseio.PulseOut(pwm) +# Create a 'pulseio' output, to send infrared signals on the IR transmitter @ 38KHz +pulseout = pulseio.PulseOut(board.IR_TX, frequency=38000, duty_cycle=2 ** 15) # Create an encoder that will take numbers and turn them into NEC IR pulses encoder = adafruit_irremote.GenericTransmit(header=[9500, 4500], one=[550, 550], zero=[550, 1700], trail=0) diff --git a/Custom_Magstripe_Swiper/code/.teensy2.test.only b/Custom_Magstripe_Swiper/code/.none.test.only similarity index 100% rename from Custom_Magstripe_Swiper/code/.teensy2.test.only rename to Custom_Magstripe_Swiper/code/.none.test.only diff --git a/MIDI_FeatherWing/.gemma.test.skip b/EyeLights_Accelerometer_Tap/EyeLights_Accelerometer_Tap/.ledglasses_nrf52840.generate similarity index 100% rename from MIDI_FeatherWing/.gemma.test.skip rename to EyeLights_Accelerometer_Tap/EyeLights_Accelerometer_Tap/.ledglasses_nrf52840.generate diff --git a/MIDI_FeatherWing/.magtag.test.skip b/EyeLights_Accelerometer_Tap/EyeLights_Accelerometer_Tap/.ledglasses_nrf52840.test.only similarity index 100% rename from MIDI_FeatherWing/.magtag.test.skip rename to EyeLights_Accelerometer_Tap/EyeLights_Accelerometer_Tap/.ledglasses_nrf52840.test.only diff --git a/EyeLights_Accelerometer_Tap/EyeLights_Accelerometer_Tap/EyeLights_Accelerometer_Tap.ino b/EyeLights_Accelerometer_Tap/EyeLights_Accelerometer_Tap/EyeLights_Accelerometer_Tap.ino new file mode 100644 index 000000000..ab8a762f0 --- /dev/null +++ b/EyeLights_Accelerometer_Tap/EyeLights_Accelerometer_Tap/EyeLights_Accelerometer_Tap.ino @@ -0,0 +1,136 @@ +// SPDX-FileCopyrightText: 2021 Phil Burgess for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +/* +ACCELEROMETER INPUT DEMO: while the LED Glasses Driver has a perfectly +good clicky button for input, this code shows how one might instead use +the onboard accelerometer for interactions*. + +Worn normally, the LED rings are simply lit a solid color. +TAP the eyeglass frames to cycle among a list of available colors. +LOOK DOWN to light the LED rings bright white -- for navigating steps +or finding the right key. LOOK BACK UP to return to solid color. +This uses only the rings, not the matrix portion. + +* Like, if you have big ol' monster hands, that little button can be + hard to click, y'know? +*/ + +#include // For LED driver +#include // For accelerometer +#include // For m/s^2 accel units + +Adafruit_LIS3DH accel; +Adafruit_EyeLights_buffered glasses; // Buffered for smooth animation + +// Here's a list of colors that we cycle through when tapped, specified +// as {R,G,B} values from 0-255. These are intentionally a bit dim -- +// both to save battery and to make the "ground light" mode more dramatic. +// Rather than primary color red/green/blue sequence which is just so +// over-done at this point, let's use some HALLOWEEN colors! +uint8_t colors[][3] = { + {27, 9, 0}, // Orange + {12, 0, 24}, // Purple + {5, 31, 0}, // Green +}; +#define NUM_COLORS (sizeof colors / sizeof colors[0]) // List length +uint8_t looking_down_color[] = {255, 255, 255}; // Max white + +uint8_t color_index = 0; // Begin at first color in list +uint8_t *target_color; // Pointer to color we're aiming for +float interpolated_color[] = {0.0, 0.0, 0.0}; // Current color along the way +float filtered_y; // De-noised accelerometer reading +bool looking_down; // Set true when glasses are oriented downward +sensors_event_t event; // For accelerometer conversion +uint32_t last_tap_time = 0; // For accelerometer tap de-noising + +// Crude error handler, prints message to Serial console, flashes LED +void err(char *str, uint8_t hz) { + Serial.println(str); + pinMode(LED_BUILTIN, OUTPUT); + for (;;) digitalWrite(LED_BUILTIN, (millis() * hz / 500) & 1); +} + +void setup() { // Runs once at program start... + + // Initialize hardware + Serial.begin(115200); + if (! accel.begin()) err("LIS3DH not found", 5); + if (! glasses.begin()) err("IS3741 not found", 2); + + // Configure accelerometer and get initial state + accel.setClick(1, 100); // Set threshold for single tap + accel.getEvent(&event); // Current accel in m/s^2 + // Check accelerometer to see if we've started in the looking-down state, + // set the target color (what we're aiming for) appropriately. Only the + // Y axis is needed for this. + filtered_y = event.acceleration.y; + looking_down = (filtered_y > 5.0); + // If initially looking down, aim for the look-down color, + // else aim for the first item in the color list. + target_color = looking_down ? looking_down_color : colors[color_index]; + + // Configure glasses for max brightness, enable output + glasses.setLEDscaling(0xFF); + glasses.setGlobalCurrent(0xFF); + glasses.enable(true); +} + +void loop() { // Repeat forever... + + // interpolated_color blends from the prior to the next ("target") + // LED ring colors, with a pleasant ease-out effect. + for(uint8_t i=0; i<3; i++) { // R, G, B + interpolated_color[i] = interpolated_color[i] * 0.97 + target_color[i] * 0.03; + } + // Convert separate red, green, blue to "packed" 24-bit RGB value + uint32_t rgb = ((int)interpolated_color[0] << 16) | + ((int)interpolated_color[1] << 8) | + (int)interpolated_color[2]; + // Fill both rings with packed color, then refresh the LEDs. + glasses.left_ring.fill(rgb); + glasses.right_ring.fill(rgb); + glasses.show(); + + // The look-down detection only needs the accelerometer's Y axis. + // This works with the Glasses Driver mounted on either temple, + // with the glasses arms "open" (as when worn). + accel.getEvent(&event); + // Smooth the accelerometer reading the same way RGB colors are + // interpolated. This avoids false triggers from jostling around. + filtered_y = filtered_y * 0.97 + event.acceleration.y * 0.03; + + // The threshold between "looking down" and "looking up" depends + // on which of those states we're currently in. This is an example + // of hysteresis in software...a change of direction requires a + // little extra push before it takes, which avoids oscillating if + // there was just a single threshold both ways. + if (looking_down) { // Currently in the looking-down state... + (void)accel.getClick(); // Discard any taps while looking down + if (filtered_y < 3.5) { // Have we crossed the look-up threshold? + target_color = colors[color_index]; // Back to list color + looking_down = false; // We're looking up now! + } + } else { // Currently in the looking-up state... + if (filtered_y > 5.0) { // Crossed the look-down threshold? + target_color = looking_down_color; // Aim for white + looking_down = true; // We're looking down now! + } else if (accel.getClick()) { + // No look up/down change, but the accelerometer registered + // a tap. Compare this against the last time we sensed one, + // and only do things if it's been more than half a second. + // This avoids spurious double-taps that can occur no matter + // how carefully the tap threshold was set. + uint32_t now = millis(); + uint32_t elapsed = now - last_tap_time; + if (elapsed > 500) { + // A good tap was detected. Cycle to the next color in + // the list and note the time of this tap. + color_index = (color_index + 1) % NUM_COLORS; + target_color = colors[color_index]; + last_tap_time = now; + } + } + } +} diff --git a/EyeLights_Accelerometer_Tap/code.py b/EyeLights_Accelerometer_Tap/EyeLights_Accelerometer_Tap_CircuitPython/code.py similarity index 93% rename from EyeLights_Accelerometer_Tap/code.py rename to EyeLights_Accelerometer_Tap/EyeLights_Accelerometer_Tap_CircuitPython/code.py index ed98bba4e..87647dfde 100644 --- a/EyeLights_Accelerometer_Tap/code.py +++ b/EyeLights_Accelerometer_Tap/EyeLights_Accelerometer_Tap_CircuitPython/code.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2021 Phil Burgess for Adafruit Industries +# +# SPDX-License-Identifier: MIT + """ ACCELEROMETER INPUT DEMO: while the LED Glasses Driver has a perfectly good clicky button for input, this code shows how one might instead use @@ -50,14 +54,6 @@ target_color = (255, 255, 255) if looking_down else colors[color_index] interpolated_color = (0, 0, 0) # LEDs off at startup, they'll ramp up -def fill_color(color): - """Given an (R,G,B) tuple, fill both LED rings with this color.""" - # Convert tuple to a 'packed' 24-bit value - packed = (int(color[0]) << 16) | (int(color[1]) << 8) | int(color[2]) - for i in range(24): - glasses.left_ring[i] = glasses.right_ring[i] = packed - - while True: # Loop forever... # The try/except here is because VERY INFREQUENTLY the I2C bus will @@ -75,7 +71,14 @@ while True: # Loop forever... interpolated_color[2] * 0.85 + target_color[2] * 0.15, ) # Fill both rings with interpolated_color, then refresh the LEDs. - fill_color(interpolated_color) + # fill_color(interpolated_color) + packed = ( + (int(interpolated_color[0]) << 16) + | (int(interpolated_color[1]) << 8) + | int(interpolated_color[2]) + ) + glasses.left_ring.fill(packed) + glasses.right_ring.fill(packed) glasses.show() # The look-down detection only needs the accelerometer's Y axis. diff --git a/MIDI_FeatherWing/.monster_m4sk.test.skip b/EyeLights_Audio_Spectrum/EyeLights_Audio_Spectrum/.ledglasses_nrf52840.generate similarity index 100% rename from MIDI_FeatherWing/.monster_m4sk.test.skip rename to EyeLights_Audio_Spectrum/EyeLights_Audio_Spectrum/.ledglasses_nrf52840.generate diff --git a/MIDI_FeatherWing/.trinket_3v.test.skip b/EyeLights_Audio_Spectrum/EyeLights_Audio_Spectrum/.ledglasses_nrf52840.test.only similarity index 100% rename from MIDI_FeatherWing/.trinket_3v.test.skip rename to EyeLights_Audio_Spectrum/EyeLights_Audio_Spectrum/.ledglasses_nrf52840.test.only diff --git a/EyeLights_Audio_Spectrum/EyeLights_Audio_Spectrum/EyeLights_Audio_Spectrum.ino b/EyeLights_Audio_Spectrum/EyeLights_Audio_Spectrum/EyeLights_Audio_Spectrum.ino new file mode 100644 index 000000000..729275af8 --- /dev/null +++ b/EyeLights_Audio_Spectrum/EyeLights_Audio_Spectrum/EyeLights_Audio_Spectrum.ino @@ -0,0 +1,239 @@ +// SPDX-FileCopyrightText: 2021 Phil Burgess for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +/* +AUDIO SPECTRUM LIGHT SHOW for Adafruit EyeLights (LED Glasses + Driver). +Uses onboard microphone and a lot of math to react to music. +REQUIRES Adafruit_ZeroFFT LIBRARY, install via Arduino Library manager. +*/ + +#include // For LED driver +#include // For microphone +#include // For math + +// FFT/SPECTRUM CONFIG ---- + +#define NUM_SAMPLES 512 // Audio & FFT buffer, MUST be a power of two +#define SPECTRUM_SIZE (NUM_SAMPLES / 2) // Output spectrum is 1/2 of FFT output +// Bottom of spectrum tends to be noisy, while top often exceeds musical +// range and is just harmonics, so clip both ends off: +#define LOW_BIN 5 // Lowest bin of spectrum that contributes to graph +#define HIGH_BIN 150 // Highest bin " + +// GLOBAL VARIABLES ------- + +Adafruit_EyeLights_buffered glasses; // LED matrix is buffered for smooth animation +extern PDMClass PDM; // Microphone +short audio_buf[3][NUM_SAMPLES]; // Audio input buffers, 16-bit signed +uint8_t active_buf = 0; // Buffer # into which audio is currently recording +volatile int samples_read = 0; // # of samples read into current buffer thus far +volatile bool mic_on = false; // true when reading from mic, false when full/stopped +float spectrum[SPECTRUM_SIZE]; // FFT results are stored & further processed here +float dynamic_level = 10.0; // For adapting to changing audio volume +int frames; // For frames-per-second calculation +uint32_t start_time; // Ditto + +struct { // Values associated with each column of the matrix + int first_bin; // First spectrum bin index affecting column + int num_bins; // Number of spectrum bins affecting column + float *bin_weights; // List of spectrum bin weightings + uint32_t color; // GFX-style 'RGB565' color for column + float top; // Current column top position + float dot; // Current column 'falling dot' position + float velocity; // Current velocity of falling dot +} column_table[18]; + +// Crude error handler, prints message to Serial console, flashes LED +void err(char *str, uint8_t hz) { + Serial.println(str); + pinMode(LED_BUILTIN, OUTPUT); + for (;;) digitalWrite(LED_BUILTIN, (millis() * hz / 500) & 1); +} + +void setup() { // Runs once at program start... + + Serial.begin(115200); + //while(!Serial); + if (! glasses.begin()) err("IS3741 not found", 2); + + // FFT/SPECTRUM SETUP ----- + + uint8_t spectrum_bits = (int)log2f((float)SPECTRUM_SIZE); // e.g. 8 = 256 bin spectrum + // Scale LOW_BIN and HIGH_BIN to 0.0 to 1.0 equivalent range in spectrum + float low_frac = log2f((float)LOW_BIN) / (float)spectrum_bits; + float frac_range = log2((float)HIGH_BIN) / (float)spectrum_bits - low_frac; + // Serial.printf("%d %f %f\n", spectrum_bits, low_frac, frac_range); + + // To keep the display lively, tables are precomputed where each column of + // the matrix (of which there are few) is the sum value and weighting of + // several bins from the FFT spectrum output (of which there are many). + // The tables also help visually linearize the output so octaves are evenly + // spaced, as on a piano keyboard, whereas the source spectrum data is + // spaced by frequency in Hz. + + for (int column=0; column<18; column++) { + // Determine the lower and upper frequency range for this column, as + // fractions within the scaled 0.0 to 1.0 spectrum range. 0.95 below + // creates slight frequency overlap between columns, looks nicer. + float lower = low_frac + frac_range * ((float)column / 18.0 * 0.95); + float upper = low_frac + frac_range * ((float)(column + 1) / 18.0); + float mid = (lower + upper) * 0.5; // Center of lower-to-upper range + float half_width = (upper - lower) * 0.5 + 1e-2; // 1/2 of lower-to-upper range + // Map fractions back to spectrum bin indices that contribute to column + int first_bin = int(pow(2, (float)spectrum_bits * lower) + 1e-4); + int last_bin = int(pow(2, (float)spectrum_bits * upper) + 1e-4); + //Serial.printf("%d %d %d\n", column, first_bin, last_bin); + float total_weight = 0.0; // Accumulate weight for this bin + int num_bins = last_bin - first_bin + 1; + // Allocate space for bin weights for column, stop everything if out of RAM. + column_table[column].bin_weights = (float *)malloc(num_bins * sizeof(float)); + if (column_table[column].bin_weights == NULL) err("Malloc fail", 10); + for (int bin_index = first_bin; bin_index <= last_bin; bin_index++) { + // Find distance from column's overall center to individual bin's + // center, expressed as 0.0 (bin at center) to 1.0 (bin at limit of + // lower-to-upper range). + float bin_center = log2f((float)bin_index + 0.5) / (float)spectrum_bits; + float dist = fabs(bin_center - mid) / half_width; + if (dist < 1.0) { // Filter out a few math stragglers at either end + // Bin weights have a cubic falloff curve within range: + dist = 1.0 - dist; // Invert dist so 1.0 is at center + float bin_weight = (((3.0 - (dist * 2.0)) * dist) * dist); + column_table[column].bin_weights[bin_index - first_bin] = bin_weight; + total_weight += bin_weight; + } + } + //Serial.println(column); + // Scale bin weights so total is 1.0 for each column, but then mute + // lower columns slightly and boost higher columns. It graphs better. + for (int i=0; i 0) ? log((float)audio_data[i]) : 0.0; + } + + // Find min & max range of spectrum bin values, with limits. + float lower = spectrum[LOW_BIN], upper = spectrum[LOW_BIN]; + for (int i=LOW_BIN+1; i<=HIGH_BIN; i++) { + if (spectrum[i] < lower) lower = spectrum[i]; + if (spectrum[i] > upper) upper = spectrum[i]; + } + //Serial.printf("%f %f\n", lower, upper); + if (upper < 2.5) upper = 2.5; + + // Adjust dynamic level to current spectrum output, keeps the graph + // 'lively' as ambient volume changes. Sparkle but don't saturate. + if (upper > dynamic_level) { + // Got louder. Move level up quickly but allow initial "bump." + dynamic_level = dynamic_level * 0.5 + upper * 0.5; + } else { + // Got quieter. Ease level down, else too many bumps. + dynamic_level = dynamic_level * 0.75 + lower * 0.25; + } + + // Apply vertical scale to spectrum data. Results may exceed + // matrix height...that's OK, adds impact! + float scale = 15.0 / (dynamic_level - lower); + for (int i=LOW_BIN; i<=HIGH_BIN; i++) { + spectrum[i] = (spectrum[i] - lower) * scale; + } + + // Clear screen, filter and draw each column of the display... + glasses.fill(0); + for(int column=0; column<18; column++) { + int first_bin = column_table[column].first_bin; + // Start BELOW matrix and accumulate bin weights UP, saves math + float column_top = 7.0; + for (int bin_offset=0; bin_offset= NUM_SAMPLES) { // Buffer full? + mic_on = false; // Stop and + samples_read = 0; // reset counter for next time + } + } else { + // Mic is off (code is busy) - must read but discard data. + // audio_buf[2] is a 'bit bucket' for this. + PDM.read(audio_buf[2], bytes_to_read); + } + } +} diff --git a/EyeLights_Audio_Spectrum/code.py b/EyeLights_Audio_Spectrum/EyeLights_Audio_Spectrum_CircuitPython/code.py similarity index 98% rename from EyeLights_Audio_Spectrum/code.py rename to EyeLights_Audio_Spectrum/EyeLights_Audio_Spectrum_CircuitPython/code.py index e3027f704..0ec5cb2a3 100755 --- a/EyeLights_Audio_Spectrum/code.py +++ b/EyeLights_Audio_Spectrum/EyeLights_Audio_Spectrum_CircuitPython/code.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2021 Phil Burgess for Adafruit Industries +# +# SPDX-License-Identifier: MIT + """ AUDIO SPECTRUM LIGHT SHOW for Adafruit EyeLights (LED Glasses + Driver). Uses onboard microphone and a lot of math to react to music. diff --git a/MIDI_FeatherWing/.trinket_5v.test.skip b/EyeLights_Blinky_Eyes/EyeLights_Blinky_Eyes/.ledglasses_nrf52840.test.only similarity index 100% rename from MIDI_FeatherWing/.trinket_5v.test.skip rename to EyeLights_Blinky_Eyes/EyeLights_Blinky_Eyes/.ledglasses_nrf52840.test.only diff --git a/EyeLights_Blinky_Eyes/EyeLights_Blinky_Eyes/EyeLights_Blinky_Eyes.ino b/EyeLights_Blinky_Eyes/EyeLights_Blinky_Eyes/EyeLights_Blinky_Eyes.ino new file mode 100644 index 000000000..f145a0ad0 --- /dev/null +++ b/EyeLights_Blinky_Eyes/EyeLights_Blinky_Eyes/EyeLights_Blinky_Eyes.ino @@ -0,0 +1,326 @@ +// SPDX-FileCopyrightText: 2021 Phil Burgess for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +/* +MOVE-AND-BLINK EYES for Adafruit EyeLights (LED Glasses + Driver). + +I'd written a very cool squash-and-stretch effect for the eye movement, +but unfortunately the resolution is such that the pupils just look like +circles regardless. I'm keeping it in despite the added complexity, +because this WILL look great later on a bigger matrix or a TFT/OLED, +and this way the hard parts won't require a re-write at such time. +It's a really adorable effect with enough pixels. +*/ + +#include // For LED driver + +// CONFIGURABLES ------------------------ + +#define RADIUS 3.4 // Size of pupil (3X because of downsampling later) + +uint8_t eye_color[3] = { 255, 128, 0 }; // Amber pupils +uint8_t ring_open_color[3] = { 75, 75, 75 }; // Color of LED rings when eyes open +uint8_t ring_blink_color[3] = { 50, 25, 0 }; // Color of LED ring "eyelid" when blinking + +// Some boards have just one I2C interface, but some have more... +TwoWire *i2c = &Wire; // e.g. change this to &Wire1 for QT Py RP2040 + +// GLOBAL VARIABLES --------------------- + +Adafruit_EyeLights_buffered glasses(true); // Buffered spex + 3X canvas +GFXcanvas16 *canvas; // Pointer to canvas object + +// Reading through the code, you'll see a lot of references to this "3X" +// space. This is referring to the glasses' optional "offscreen" drawing +// canvas that's 3 times the resolution of the LED matrix (i.e. 15 pixels +// tall instead of 5), which gets scaled down to provide some degree of +// antialiasing. It's why the pupils have soft edges and can make +// fractional-pixel motions. + +float cur_pos[2] = { 9.0, 7.5 }; // Current position of eye in canvas space +float next_pos[2] = { 9.0, 7.5 }; // Next position " +bool in_motion = false; // true = eyes moving, false = eyes paused +uint8_t blink_state = 0; // 0, 1, 2 = unblinking, closing, opening +uint32_t move_start_time = 0; // For animation timekeeping +uint32_t move_duration = 0; +uint32_t blink_start_time = 0; +uint32_t blink_duration = 0; +float y_pos[13]; // Coords of LED ring pixels in canvas space +uint32_t ring_open_color_packed; // ring_open_color[] as packed RGB integer +uint16_t eye_color565; // eye_color[] as a GFX packed '565' value +uint32_t frames = 0; // For frames-per-second calculation +uint32_t start_time; + +// These offsets position each pupil on the canvas grid and make them +// fixate slightly (converge on a point) so they're not always aligned +// the same on the pixel grid, which would be conspicuously pixel-y. +float x_offset[2] = { 5.0, 31.0 }; +// These help perform x-axis clipping on the rasterized ellipses, +// so they don't "bleed" outside the rings and require erasing. +int box_x_min[2] = { 3, 33 }; +int box_x_max[2] = { 21, 51 }; + +#define GAMMA 2.6 // For color correction, shouldn't need changing + + +// HELPER FUNCTIONS --------------------- + +// Crude error handler, prints message to Serial console, flashes LED +void err(char *str, uint8_t hz) { + Serial.println(str); + pinMode(LED_BUILTIN, OUTPUT); + for (;;) digitalWrite(LED_BUILTIN, (millis() * hz / 500) & 1); +} + +// Given an [R,G,B] color, apply gamma correction, return packed RGB integer. +uint32_t gammify(uint8_t color[3]) { + uint32_t rgb[3]; + for (uint8_t i=0; i<3; i++) { + rgb[i] = uint32_t(pow((float)color[i] / 255.0, GAMMA) * 255 + 0.5); + } + return (rgb[0] << 16) | (rgb[1] << 8) | rgb[2]; +} + +// Given two [R,G,B] colors and a blend ratio (0.0 to 1.0), interpolate between +// the two colors and return a gamma-corrected in-between color as a packed RGB +// integer. No bounds clamping is performed on blend value, be nice. +uint32_t interp(uint8_t color1[3], uint8_t color2[3], float blend) { + float inv = 1.0 - blend; // Weighting of second color + uint8_t rgb[3]; + for(uint8_t i=0; i<3; i++) { + rgb[i] = (int)((float)color1[i] * blend + (float)color2[i] * inv); + } + return gammify(rgb); +} + +// Rasterize an arbitrary ellipse into the offscreen 3X canvas, given +// foci point1 and point2 and with area determined by global RADIUS +// (when foci are same point; a circle). Foci and radius are all +// floating point values, which adds to the buttery impression. 'rect' +// is a bounding rect of which pixels are likely affected. Canvas is +// assumed cleared before arriving here. +void rasterize(float point1[2], float point2[2], int rect[4]) { + float perimeter, d; + float dx = point2[0] - point1[0]; + float dy = point2[1] - point1[1]; + float d2 = dx * dx + dy * dy; // Dist between foci, squared + if (d2 <= 0.0) { + // Foci are in same spot - it's a circle + perimeter = 2.0 * RADIUS; + d = 0.0; + } else { + // Foci are separated - it's an ellipse. + d = sqrt(d2); // Distance between foci + float c = d * 0.5; // Center-to-foci distance + // This is an utterly brute-force way of ellipse-filling based on + // the "two nails and a string" metaphor...we have the foci points + // and just need the string length (triangle perimeter) to yield + // an ellipse with area equal to a circle of 'radius'. + // c^2 = a^2 - b^2 <- ellipse formula + // a = r^2 / b <- substitute + // c^2 = (r^2 / b)^2 - b^2 + // b = sqrt(((c^2) + sqrt((c^4) + 4 * r^4)) / 2) <- solve for b + float c2 = c * c; + float b2 = (c2 + sqrt((c2 * c2) + 4 * (RADIUS * RADIUS * RADIUS * RADIUS))) * 0.5; + // By my math, perimeter SHOULD be... + // perimeter = d + 2 * sqrt(b2 + c2); + // ...but for whatever reason, working approach here is really... + perimeter = d + 2 * sqrt(b2); + } + + // Like I'm sure there's a way to rasterize this by spans rather than + // all these square roots on every pixel, but for now... + for (int y=rect[1]; ydrawPixel(x, y, eye_color565); + } + } + } +} + + +// ONE-TIME INITIALIZATION -------------- + +void setup() { + // Initialize hardware + Serial.begin(115200); + if (! glasses.begin(IS3741_ADDR_DEFAULT, i2c)) err("IS3741 not found", 2); + + canvas = glasses.getCanvas(); + if (!canvas) err("Can't allocate canvas", 5); + + i2c->setClock(1000000); // 1 MHz I2C for extra butteriness + + // Configure glasses for reduced brightness, enable output + glasses.setLEDscaling(0xFF); + glasses.setGlobalCurrent(20); + glasses.enable(true); + + // INITIALIZE TABLES & OTHER GLOBALS ---- + + // Pre-compute the Y position of 1/2 of the LEDs in a ring, relative + // to the 3X canvas resolution, so ring & matrix animation can be aligned. + for (uint8_t i=0; i<13; i++) { + float angle = (float)i / 24.0 * M_PI * 2.0; + y_pos[i] = 10.0 - cos(angle) * 12.0; + } + + // Convert some colors from [R,G,B] (easier to specify) to packed integers + ring_open_color_packed = gammify(ring_open_color); + eye_color565 = glasses.color565(eye_color[0], eye_color[1], eye_color[2]); + + start_time = millis(); // For frames-per-second math +} + +// MAIN LOOP ---------------------------- + +void loop() { + canvas->fillScreen(0); + + // The eye animation logic is a carry-over from like a billion + // prior eye projects, so this might be comment-light. + uint32_t now = micros(); // 'Snapshot' the time once per frame + + float upper, lower, ratio; + + // Blink logic + uint32_t elapsed = now - blink_start_time; // Time since start of blink event + if (elapsed > blink_duration) { // All done with event? + blink_start_time = now; // A new one starts right now + elapsed = 0; + blink_state++; // Cycle closing/opening/paused + if (blink_state == 1) { // Starting new blink... + blink_duration = random(60000, 120000); + } else if (blink_state == 2) { // Switching closing to opening... + blink_duration *= 2; // Opens at half the speed + } else { // Switching to pause in blink + blink_state = 0; + blink_duration = random(500000, 4000000); + } + } + if (blink_state) { // If currently in a blink... + float ratio = (float)elapsed / (float)blink_duration; // 0.0-1.0 as it closes + if (blink_state == 2) ratio = 1.0 - ratio; // 1.0-0.0 as it opens + upper = ratio * 15.0 - 4.0; // Upper eyelid pos. in 3X space + lower = 23.0 - ratio * 8.0; // Lower eyelid pos. in 3X space + } + + // Eye movement logic. Two points, 'p1' and 'p2', are the foci of an + // ellipse. p1 moves from current to next position a little faster + // than p2, creating a "squash and stretch" effect (frame rate and + // resolution permitting). When motion is stopped, the two points + // are at the same position. + float p1[2], p2[2]; + elapsed = now - move_start_time; // Time since start of move event + if (in_motion) { // Currently moving? + if (elapsed > move_duration) { // If end of motion reached, + in_motion = false; // Stop motion and + memcpy(&p1, &next_pos, sizeof next_pos); // set everything to new position + memcpy(&p2, &next_pos, sizeof next_pos); + memcpy(&cur_pos, &next_pos, sizeof next_pos); + move_duration = random(500000, 1500000); // Wait this long + } else { // Still moving + // Determine p1, p2 position in time + float delta[2]; + delta[0] = next_pos[0] - cur_pos[0]; + delta[1] = next_pos[1] - cur_pos[1]; + ratio = (float)elapsed / (float)move_duration; + if (ratio < 0.6) { // First 60% of move time, p1 is in motion + // Easing function: 3*e^2-2*e^3 0.0 to 1.0 + float e = ratio / 0.6; // 0.0 to 1.0 + e = 3 * e * e - 2 * e * e * e; + p1[0] = cur_pos[0] + delta[0] * e; + p1[1] = cur_pos[1] + delta[1] * e; + } else { // Last 40% of move time + memcpy(&p1, &next_pos, sizeof next_pos); // p1 has reached end position + } + if (ratio > 0.3) { // Last 70% of move time, p2 is in motion + float e = (ratio - 0.3) / 0.7; // 0.0 to 1.0 + e = 3 * e * e - 2 * e * e * e; // Easing func. + p2[0] = cur_pos[0] + delta[0] * e; + p2[1] = cur_pos[1] + delta[1] * e; + } else { // First 30% of move time + memcpy(&p2, &cur_pos, sizeof cur_pos); // p2 waits at start position + } + } + } else { // Eye is stopped + memcpy(&p1, &cur_pos, sizeof cur_pos); // Both foci at current eye position + memcpy(&p2, &cur_pos, sizeof cur_pos); + if (elapsed > move_duration) { // Pause time expired? + in_motion = true; // Start up new motion! + move_start_time = now; + move_duration = random(150000, 250000); + float angle = (float)random(1000) / 1000.0 * M_PI * 2.0; + float dist = (float)random(750) / 100.0; + next_pos[0] = 9.0 + cos(angle) * dist; + next_pos[1] = 7.5 + sin(angle) * dist * 0.8; + } + } + + // Draw the raster part of each eye... + for (uint8_t e=0; e<2; e++) { + // Each eye's foci are offset slightly, to fixate toward center + float p1a[2], p2a[2]; + p1a[0] = p1[0] + x_offset[e]; + p2a[0] = p2[0] + x_offset[e]; + p1a[1] = p2a[1] = p1[1]; + // Compute bounding rectangle (in 3X space) of ellipse + // (min X, min Y, max X, max Y). Like the ellipse rasterizer, + // this isn't optimal, but will suffice. + int bounds[4]; + bounds[0] = max(int(min(p1a[0], p2a[0]) - RADIUS), box_x_min[e]); + bounds[1] = max(max(int(min(p1a[1], p2a[1]) - RADIUS), 0), (int)upper); + bounds[2] = min(int(max(p1a[0], p2a[0]) + RADIUS + 1), box_x_max[e]); + bounds[3] = min(int(max(p1a[1], p2a[1]) + RADIUS + 1), 15); + rasterize(p1a, p2a, bounds); // Render ellipse into buffer + } + + // If the eye is currently blinking, and if the top edge of the eyelid + // overlaps the bitmap, draw lines across the bitmap as if eyelids. + if (blink_state and upper >= 0.0) { + int iu = (int)upper; + canvas->drawLine(box_x_min[0], iu, box_x_max[0] - 1, iu, eye_color565); + canvas->drawLine(box_x_min[1], iu, box_x_max[1] - 1, iu, eye_color565); + } + + glasses.scale(); // Smooth filter 3X canvas to LED grid + + // Matrix and rings share a few pixels. To make the rings take + // precedence, they're drawn later. So blink state is revisited now... + if (blink_state) { // In mid-blink? + for (uint8_t i=0; i<13; i++) { // Half an LED ring, top-to-bottom... + float a = min(max(y_pos[i] - upper + 1.0, 0.0), 3.0); + float b = min(max(lower - y_pos[i] + 1.0, 0.0), 3.0); + ratio = a * b / 9.0; // Proximity of LED to eyelid edges + uint32_t packed = interp(ring_open_color, ring_blink_color, ratio); + glasses.left_ring.setPixelColor(i, packed); + glasses.right_ring.setPixelColor(i, packed); + if ((i > 0) && (i < 12)) { + uint8_t j = 24 - i; // Mirror half-ring to other side + glasses.left_ring.setPixelColor(j, packed); + glasses.right_ring.setPixelColor(j, packed); + } + } + } else { + glasses.left_ring.fill(ring_open_color_packed); + glasses.right_ring.fill(ring_open_color_packed); + } + + glasses.show(); + + frames += 1; + elapsed = millis() - start_time; + Serial.println(frames * 1000 / elapsed); +} diff --git a/EyeLights_Blinky_Eyes/EyeLights_Blinky_Eyes_CircuitPython/code.py b/EyeLights_Blinky_Eyes/EyeLights_Blinky_Eyes_CircuitPython/code.py new file mode 100755 index 000000000..1925ef2bb --- /dev/null +++ b/EyeLights_Blinky_Eyes/EyeLights_Blinky_Eyes_CircuitPython/code.py @@ -0,0 +1,338 @@ +# SPDX-FileCopyrightText: 2021 Phil Burgess for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +""" +MOVE-AND-BLINK EYES for Adafruit EyeLights (LED Glasses + Driver). + +I'd written a very cool squash-and-stretch effect for the eye movement, +but unfortunately the resolution and frame rate are such that the pupils +just look like circles regardless. I'm keeping it in despite the added +complexity, because CircuitPython devices WILL get faster, LED matrix +densities WILL improve, and this way the code won't require a re-write +at such a later time. It's a really adorable effect with enough pixels. +""" + +import math +import random +import time +from supervisor import reload +import board +from busio import I2C +import adafruit_is31fl3741 +from adafruit_is31fl3741.adafruit_ledglasses import LED_Glasses + + +# CONFIGURABLES ------------------------ + +eye_color = (255, 128, 0) # Amber pupils +ring_open_color = (75, 75, 75) # Color of LED rings when eyes open +ring_blink_color = (50, 25, 0) # Color of LED ring "eyelid" when blinking + +radius = 3.4 # Size of pupil (3X because of downsampling later) + +# Reading through the code, you'll see a lot of references to this "3X" +# space. What it's referring to is a bitmap that's 3 times the resolution +# of the LED matrix (i.e. 15 pixels tall instead of 5), which gets scaled +# down to provide some degree of antialiasing. It's why the pupils have +# soft edges and can make fractional-pixel motions. +# Because of the way the downsampling is done, the eyelid edge when drawn +# across the eye will always be the same hue as the pupils, it can't be +# set independently like the ring blink color. + +gamma = 2.6 # For color adjustment. Leave as-is. + + +# CLASSES & FUNCTIONS ------------------ + + +class Eye: + """Holds per-eye positional data; each covers a different area of the + overall LED matrix.""" + + def __init__(self, left, xoff): + self.left = left # Leftmost column on LED matrix + self.x_offset = xoff # Horizontal offset (3X space) to fixate + + def smooth(self, data, rect): + """Scale bitmap (in 'data') to LED array, with smooth 1:3 + downsampling. 'rect' is a 4-tuple rect of which pixels get + filtered (anything outside is cleared to 0), saves a few cycles.""" + # Quantize bounds rect from 3X space to LED matrix space. + rect = ( + rect[0] // 3, # Left + rect[1] // 3, # Top + (rect[2] + 2) // 3, # Right + (rect[3] + 2) // 3, # Bottom + ) + for y in range(rect[1]): # Erase rows above top + for x in range(6): + glasses.pixel(self.left + x, y, 0) + for y in range(rect[1], rect[3]): # Each row, top to bottom... + pixel_sum = bytearray(6) # Initialize row of pixel sums to 0 + for y1 in range(3): # 3 rows of bitmap... + row = data[y * 3 + y1] # Bitmap data for current row + for x in range(rect[0], rect[2]): # Column, left to right + x3 = x * 3 + # Accumulate 3 pixels of bitmap into pixel_sum + pixel_sum[x] += row[x3] + row[x3 + 1] + row[x3 + 2] + # 'pixel_sum' will now contain values from 0-9, indicating the + # number of set pixels in the corresponding section of the 3X + # bitmap. 'colormap' expands the sum to 24-bit RGB space. + for x in range(rect[0]): # Erase any columns to left + glasses.pixel(self.left + x, y, 0) + for x in range(rect[0], rect[2]): # Column, left to right + glasses.pixel(self.left + x, y, colormap[pixel_sum[x]]) + for x in range(rect[2], 6): # Erase columns to right + glasses.pixel(self.left + x, y, 0) + for y in range(rect[3], 5): # Erase rows below bottom + for x in range(6): + glasses.pixel(self.left + x, y, 0) + + +# pylint: disable=too-many-locals +def rasterize(data, point1, point2, rect): + """Rasterize an arbitrary ellipse into the 'data' bitmap (3X pixel + space), given foci point1 and point2 and with area determined by global + 'radius' (when foci are same point; a circle). Foci and radius are all + floating point values, which adds to the buttery impression. 'rect' is + a 4-tuple rect of which pixels are likely affected. Data is assumed 0 + before arriving here; no clearing is performed.""" + + dx = point2[0] - point1[0] + dy = point2[1] - point1[1] + d2 = dx * dx + dy * dy # Dist between foci, squared + if d2 <= 0: + # Foci are in same spot - it's a circle + perimeter = 2 * radius + d = 0 + else: + # Foci are separated - it's an ellipse. + d = d2 ** 0.5 # Distance between foci + c = d * 0.5 # Center-to-foci distance + # This is an utterly brute-force way of ellipse-filling based on + # the "two nails and a string" metaphor...we have the foci points + # and just need the string length (triangle perimeter) to yield + # an ellipse with area equal to a circle of 'radius'. + # c^2 = a^2 - b^2 <- ellipse formula + # a = r^2 / b <- substitute + # c^2 = (r^2 / b)^2 - b^2 + # b = sqrt(((c^2) + sqrt((c^4) + 4 * r^4)) / 2) <- solve for b + b2 = ((c ** 2) + (((c ** 4) + 4 * (radius ** 4)) ** 0.5)) * 0.5 + # By my math, perimeter SHOULD be... + # perimeter = d + 2 * ((b2 + (c ** 2)) ** 0.5) + # ...but for whatever reason, working approach here is really... + perimeter = d + 2 * (b2 ** 0.5) + + # Like I'm sure there's a way to rasterize this by spans rather than + # all these square roots on every pixel, but for now... + for y in range(rect[1], rect[3]): # For each row... + y5 = y + 0.5 # Pixel center + dy1 = y5 - point1[1] # Y distance from pixel to first point + dy2 = y5 - point2[1] # " to second + dy1 *= dy1 # Y1^2 + dy2 *= dy2 # Y2^2 + for x in range(rect[0], rect[2]): # For each column... + x5 = x + 0.5 # Pixel center + dx1 = x5 - point1[0] # X distance from pixel to first point + dx2 = x5 - point2[0] # " to second + d1 = (dx1 * dx1 + dy1) ** 0.5 # 2D distance to first point + d2 = (dx2 * dx2 + dy2) ** 0.5 # " to second + if (d1 + d2 + d) <= perimeter: + data[y][x] = 1 # Point is inside ellipse + + +def gammify(color): + """Given an (R,G,B) color tuple, apply gamma correction and return + a packed 24-bit RGB integer.""" + rgb = [int(((color[x] / 255) ** gamma) * 255 + 0.5) for x in range(3)] + return (rgb[0] << 16) | (rgb[1] << 8) | rgb[2] + + +def interp(color1, color2, blend): + """Given two (R,G,B) color tuples and a blend ratio (0.0 to 1.0), + interpolate between the two colors and return a gamma-corrected + in-between color as a packed 24-bit RGB integer. No bounds clamping + is performed on blend value, be nice.""" + inv = 1.0 - blend # Weighting of second color + return gammify([color1[x] * blend + color2[x] * inv for x in range(3)]) + + +# HARDWARE SETUP ----------------------- + +# Manually declare I2C (not board.I2C() directly) to access 1 MHz speed... +i2c = I2C(board.SCL, board.SDA, frequency=1000000) + +# Initialize the IS31 LED driver, buffered for smoother animation +glasses = LED_Glasses(i2c, allocate=adafruit_is31fl3741.MUST_BUFFER) +glasses.show() # Clear any residue on startup +glasses.global_current = 20 # Just middlin' bright, please + + +# INITIALIZE TABLES & OTHER GLOBALS ---- + +# This table is for mapping 3x3 averaged bitmap values (0-9) to +# RGB colors. Avoids a lot of shift-and-or on every pixel. +colormap = [] +for n in range(10): + colormap.append(gammify([n / 9 * eye_color[x] for x in range(3)])) + +# Pre-compute the Y position of 1/2 of the LEDs in a ring, relative +# to the 3X bitmap resolution, so ring & matrix animation can be aligned. +y_pos = [] +for n in range(13): + angle = n / 24 * math.pi * 2 + y_pos.append(10 - math.cos(angle) * 12) + +# Pre-compute color of LED ring in fully open (unblinking) state +ring_open_color_packed = gammify(ring_open_color) + +# A single pre-computed scanline of "eyelid edge during blink" can be +# stuffed into the 3X raster as needed, avoids setting pixels manually. +eyelid = ( + b"\x01\x01\x00\x01\x01\x00\x01\x01\x00" b"\x01\x01\x00\x01\x01\x00\x01\x01\x00" +) # 2/3 of pixels set + +# Initialize eye position and move/blink animation timekeeping +cur_pos = next_pos = (9, 7.5) # Current, next eye position in 3X space +in_motion = False # True = eyes moving, False = eyes paused +blink_state = 0 # 0, 1, 2 = unblinking, closing, opening +move_start_time = move_duration = blink_start_time = blink_duration = 0 + +# Two eye objects. The first starts at column 1 of the matrix with its +# pupil offset by +2 (in 3X space), second at column 11 with -2 offset. +# The offsets make the pupils fixate slightly (converge on a point), so +# the two pupils aren't always aligned the same on the pixel grid, which +# would be conspicuously pixel-y. +eyes = [Eye(1, 2), Eye(11, -2)] + +frames, start_time = 0, time.monotonic() # For frames/second calculation + + +# MAIN LOOP ---------------------------- + +while True: + # The try/except here is because VERY INFREQUENTLY the I2C bus will + # encounter an error when accessing the LED driver, whether from bumping + # around the wires or sometimes an I2C device just gets wedged. To more + # robustly handle the latter, the code will restart if that happens. + try: + + # The eye animation logic is a carry-over from like a billion + # prior eye projects, so this might be comment-light. + now = time.monotonic() # 'Snapshot' the time once per frame + + # Blink logic + elapsed = now - blink_start_time # Time since start of blink event + if elapsed > blink_duration: # All done with event? + blink_start_time = now # A new one starts right now + elapsed = 0 + blink_state += 1 # Cycle closing/opening/paused + if blink_state == 1: # Starting new blink... + blink_duration = random.uniform(0.06, 0.12) + elif blink_state == 2: # Switching closing to opening... + blink_duration *= 2 # Opens at half the speed + else: # Switching to pause in blink + blink_state = 0 + blink_duration = random.uniform(0.5, 4) + if blink_state: # If currently in a blink... + ratio = elapsed / blink_duration # 0.0-1.0 as it closes + if blink_state == 2: + ratio = 1.0 - ratio # 1.0-0.0 as it opens + upper = ratio * 15 - 4 # Upper eyelid pos. in 3X space + lower = 23 - ratio * 8 # Lower eyelid pos. in 3X space + + # Eye movement logic. Two points, 'p1' and 'p2', are the foci of an + # ellipse. p1 moves from current to next position a little faster + # than p2, creating a "squash and stretch" effect (frame rate and + # resolution permitting). When motion is stopped, the two points + # are at the same position. + elapsed = now - move_start_time # Time since start of move event + if in_motion: # Currently moving? + if elapsed > move_duration: # If end of motion reached, + in_motion = False # Stop motion and + p1 = p2 = cur_pos = next_pos # Set to new position + move_duration = random.uniform(0.5, 1.5) # Wait this long + else: # Still moving + # Determine p1, p2 position in time + delta = (next_pos[0] - cur_pos[0], next_pos[1] - cur_pos[1]) + ratio = elapsed / move_duration + if ratio < 0.6: # First 60% of move time + # p1 is in motion + # Easing function: 3*e^2-2*e^3 0.0 to 1.0 + e = ratio / 0.6 # 0.0 to 1.0 + e = 3 * e * e - 2 * e * e * e + p1 = (cur_pos[0] + delta[0] * e, cur_pos[1] + delta[1] * e) + else: # Last 40% of move time + p1 = next_pos # p1 has reached end position + if ratio > 0.3: # Last 60% of move time + # p2 is in motion + e = (ratio - 0.3) / 0.7 # 0.0 to 1.0 + e = 3 * e * e - 2 * e * e * e # Easing func. + p2 = (cur_pos[0] + delta[0] * e, cur_pos[1] + delta[1] * e) + else: # First 40% of move time + p2 = cur_pos # p2 waits at start position + else: # Eye is stopped + p1 = p2 = cur_pos # Both foci at current eye position + if elapsed > move_duration: # Pause time expired? + in_motion = True # Start up new motion! + move_start_time = now + move_duration = random.uniform(0.15, 0.25) + angle = random.uniform(0, math.pi * 2) + dist = random.uniform(0, 7.5) + next_pos = ( + 9 + math.cos(angle) * dist, + 7.5 + math.sin(angle) * dist * 0.8, + ) + + # Draw the raster part of each eye... + for eye in eyes: + # Allocate/clear the 3X bitmap buffer + bitmap = [bytearray(6 * 3) for _ in range(5 * 3)] + # Each eye's foci are offset slightly, to fixate toward center + p1a = (p1[0] + eye.x_offset, p1[1]) + p2a = (p2[0] + eye.x_offset, p2[1]) + # Compute bounding rectangle (in 3X space) of ellipse + # (min X, min Y, max X, max Y). Like the ellipse rasterizer, + # this isn't optimal, but will suffice. + bounds = ( + max(int(min(p1a[0], p2a[0]) - radius), 0), + max(int(min(p1a[1], p2a[1]) - radius), 0, int(upper)), + min(int(max(p1a[0], p2a[0]) + radius + 1), 18), + min(int(max(p1a[1], p2a[1]) + radius + 1), 15, int(lower) + 1), + ) + rasterize(bitmap, p1a, p2a, bounds) # Render ellipse into buffer + # If the eye is currently blinking, and if the top edge of the + # eyelid overlaps the bitmap, draw a scanline across the bitmap + # and update the bounds rect so the whole width of the bitmap + # is scaled. + if blink_state and upper >= 0: + bitmap[int(upper)] = eyelid + bounds = (0, int(upper), 18, bounds[3]) + eye.smooth(bitmap, bounds) # 1:3 downsampling for eye + + # Matrix and rings share a few pixels. To make the rings take + # precedence, they're drawn later. So blink state is revisited now... + if blink_state: # In mid-blink? + for i in range(13): # Half an LED ring, top-to-bottom... + a = min(max(y_pos[i] - upper + 1, 0), 3) + b = min(max(lower - y_pos[i] + 1, 0), 3) + ratio = a * b / 9 # Proximity of LED to eyelid edges + packed = interp(ring_open_color, ring_blink_color, ratio) + glasses.left_ring[i] = glasses.right_ring[i] = packed + if 0 < i < 12: + i = 24 - i # Mirror half-ring to other side + glasses.left_ring[i] = glasses.right_ring[i] = packed + else: + glasses.left_ring.fill(ring_open_color_packed) + glasses.right_ring.fill(ring_open_color_packed) + + glasses.show() # Buffered mode MUST use show() to refresh matrix + + except OSError: # See "try" notes above regarding rare I2C errors. + print("Restarting") + reload() + + frames += 1 + elapsed = time.monotonic() - start_time + print(frames / elapsed) diff --git a/Rotary_Trinkey/Arduino_NeoPixel_Example/.rotarytrinkey_m0.test.only b/EyeLights_Bluetooth_Scroller/.ledglasses_nrf52840.generate similarity index 100% rename from Rotary_Trinkey/Arduino_NeoPixel_Example/.rotarytrinkey_m0.test.only rename to EyeLights_Bluetooth_Scroller/.ledglasses_nrf52840.generate diff --git a/Rotary_Trinkey/Arduino_SurfaceDial_Example/.rotarytrinkey_m0.test.only b/EyeLights_Bluetooth_Scroller/.ledglasses_nrf52840.test.only similarity index 100% rename from Rotary_Trinkey/Arduino_SurfaceDial_Example/.rotarytrinkey_m0.test.only rename to EyeLights_Bluetooth_Scroller/.ledglasses_nrf52840.test.only diff --git a/EyeLights_Bluetooth_Scroller/EyeLights_Bluetooth_Scroller.ino b/EyeLights_Bluetooth_Scroller/EyeLights_Bluetooth_Scroller.ino new file mode 100644 index 000000000..d810cd44d --- /dev/null +++ b/EyeLights_Bluetooth_Scroller/EyeLights_Bluetooth_Scroller.ino @@ -0,0 +1,202 @@ +// SPDX-FileCopyrightText: 2021 Phil Burgess for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +/* +BLUETOOTH SCROLLING MESSAGE for Adafruit EyeLights (LED Glasses + Driver). +Use BLUEFRUIT CONNECT app on iOS or Android to connect to LED glasses. +Use the app's UART input to enter a new message. +Use the app's Color Picker (under "Controller") to change text color. +This is based on the glassesdemo-3-smooth example from the +Adafruit_IS31FL3741 library, with Bluetooth additions on top. If this +code all seems a bit too much, you can start with that example (or the two +that precede it) to gain an understanding of the LED glasses basics, then +return here to see what the extra Bluetooth layers do. +*/ + +#include // For LED driver +#include // For Bluetooth communication +#include // Smooth scrolly font for glasses + +// These items are over in the packetParser.cpp tab: +extern uint8_t packetbuffer[]; +extern uint8_t readPacket(BLEUart *ble, uint16_t timeout); +extern int8_t packetType(uint8_t *buf, uint8_t len); +extern float parsefloat(uint8_t *buffer); +extern void printHex(const uint8_t * data, const uint32_t numBytes); + +// GLOBAL VARIABLES ------- + +// 'Buffered' glasses for buttery animation, +// 'true' to allocate a drawing canvas for smooth graphics: +Adafruit_EyeLights_buffered glasses(true); +GFXcanvas16 *canvas; // Pointer to glasses' canvas object +// Because 'canvas' is a pointer, always use -> when calling +// drawing functions there. 'glasses' is an object in itself, +// so . is used when calling its functions. + +char message[51] = "Run Bluefruit Connect app"; // Scrolling message +int16_t text_x; // Message position on canvas +int16_t text_min; // Leftmost position before restarting scroll + +BLEUart bleuart; // Bluetooth low energy UART + +int8_t last_packet_type = 99; // Last BLE packet type, init to nonsense value + +// ONE-TIME SETUP --------- + +void setup() { // Runs once at program start... + + Serial.begin(115200); + //while(!Serial); + + // Configure and start the BLE UART service + Bluefruit.begin(); + Bluefruit.setTxPower(4); + bleuart.begin(); + startAdv(); // Set up and start advertising + + if (!glasses.begin()) err("IS3741 not found", 2); + + canvas = glasses.getCanvas(); + if (!canvas) err("Can't allocate canvas", 5); + + // Configure glasses for full brightness and enable output + glasses.setLEDscaling(0xFF); + glasses.setGlobalCurrent(0xFF); + glasses.enable(true); + + // Set up for scrolling text, initialize color and position + canvas->setFont(&EyeLightsCanvasFont); + canvas->setTextWrap(false); // Allow text to extend off edges + canvas->setTextColor(glasses.color565(0x303030)); // Dim white to start + reposition_text(); // Sets up initial position & scroll limit +} + +// Crude error handler, prints message to Serial console, flashes LED +void err(char *str, uint8_t hz) { + Serial.println(str); + pinMode(LED_BUILTIN, OUTPUT); + for (;;) digitalWrite(LED_BUILTIN, (millis() * hz / 500) & 1); +} + +// Set up, start BLE advertising +void startAdv(void) { + // Advertising packet + Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE); + Bluefruit.Advertising.addTxPower(); + + // Include the BLE UART (AKA 'NUS') 128-bit UUID + Bluefruit.Advertising.addService(bleuart); + + // Secondary Scan Response packet (optional) + // Since there is no room for 'Name' in Advertising packet + Bluefruit.ScanResponse.addName(); + + // Start Advertising + // - Enable auto advertising if disconnected + // - Interval: fast mode = 20 ms, slow mode = 152.5 ms + // - Timeout for fast mode is 30 seconds + // - Start(timeout) with timeout = 0 will advertise forever (until connected) + // + // For recommended advertising interval + // https://developer.apple.com/library/content/qa/qa1931/_index.html + Bluefruit.Advertising.restartOnDisconnect(true); + Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms + Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode + Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds +} + +// MAIN LOOP -------------- + +void loop() { // Repeat forever... + // The packet read timeout (9 ms here) also determines the text + // scrolling speed -- if no data is received over BLE in that time, + // the function exits and returns here with len=0. + uint8_t len = readPacket(&bleuart, 9); + if (len) { + int8_t type = packetType(packetbuffer, len); + // The Bluefruit Connect app can return a variety of data from + // a phone's sensors. To keep this example relatively simple, + // we'll only look at color and text, but here's where others + // would go if we were to extend this. See Bluefruit library + // examples for the packet data formats. packetParser.cpp + // has a couple functions not used in this code but that may be + // helpful in interpreting these other packet types. + switch(type) { + case 0: // Accelerometer + Serial.println("Accel"); + break; + case 1: // Gyro: + Serial.println("Gyro"); + break; + case 2: // Magnetometer + Serial.println("Mag"); + break; + case 3: // Quaternion + Serial.println("Quat"); + break; + case 4: // Button + Serial.println("Button"); + break; + case 5: // Color + Serial.println("Color"); + // packetbuffer[2] through [4] contain R, G, B byte values. + // Because the drawing canvas uses lower-precision '565' color, + // and because glasses.scale() applies gamma correction and may + // quantize the dimmest colors to 0, set a brightness floor here + // so text isn't invisible. + for (uint8_t i=2; i<=4; i++) { + if (packetbuffer[i] < 0x20) packetbuffer[i] = 0x20; + } + canvas->setTextColor(glasses.color565(glasses.Color( + packetbuffer[2], packetbuffer[3], packetbuffer[4]))); + break; + case 6: // Location + Serial.println("Location"); + break; + default: // -1 + // Packet is not one of the Bluefruit Connect types. Most programs + // will ignore/reject it as not valud, but in this case we accept + // it as a freeform string for the scrolling message. + if (last_packet_type != -1) { + // If prior data was a packet, this is a new freeform string, + // initialize the message string with it... + strncpy(message, (char *)packetbuffer, 20); + } else { + // If prior data was also a freeform string, concatenate this onto + // the message (up to the max message length). BLE packets can only + // be so large, so long strings are broken into multiple packets. + uint8_t message_len = strlen(message); + uint8_t max_append = sizeof message - 1 - message_len; + strncpy(&message[message_len], (char *)packetbuffer, max_append); + len = message_len + max_append; + } + message[len] = 0; // End of string NUL char + Serial.println(message); + reposition_text(); // Reset text off right edge of canvas + } + last_packet_type = type; // Save packet type for next pass + } else { + last_packet_type = 99; // BLE read timeout, reset last type to nonsense + } + + canvas->fillScreen(0); // Clear the whole drawing canvas + // Update text to new position, and draw on canvas + if (--text_x < text_min) { // If text scrolls off left edge, + text_x = canvas->width(); // reset position off right edge + } + canvas->setCursor(text_x, canvas->height()); + canvas->print(message); + glasses.scale(); // 1:3 downsample canvas to LED matrix + glasses.show(); // MUST call show() to update matrix +} + +// When new message text is assigned, call this to reset its position +// off the right edge and calculate column where scrolling resets. +void reposition_text() { + uint16_t w, h, ignore; + canvas->getTextBounds(message, 0, 0, (int16_t *)&ignore, (int16_t *)&ignore, &w, &ignore); + text_x = canvas->width(); + text_min = -w; // Off left edge this many pixels +} diff --git a/EyeLights_Bluetooth_Scroller/packetParser.cpp b/EyeLights_Bluetooth_Scroller/packetParser.cpp new file mode 100644 index 000000000..82b6cd015 --- /dev/null +++ b/EyeLights_Bluetooth_Scroller/packetParser.cpp @@ -0,0 +1,119 @@ +#include + +// packetbuffer holds inbound data +#define READ_BUFSIZE 20 +uint8_t packetbuffer[READ_BUFSIZE + 1]; // +1 is for NUL string terminator + +/**************************************************************************/ +/*! + @brief Casts the four bytes at the specified address to a float. + @param ptr Pointer into packet buffer. + @returns Floating-point value. +*/ +/**************************************************************************/ +float parsefloat(uint8_t *ptr) { + float f; // Make a suitably-aligned float variable, + memcpy(&f, ptr, 4); // because in-buffer instance might be misaligned! + return f; // (You can't always safely parse in-place) +} + +/**************************************************************************/ +/*! + @brief Prints a series of bytes in 0xNN hexadecimal notation. + @param buf Pointer to array of byte data. + @param len Data length in bytes. +*/ +/**************************************************************************/ +void printHex(const uint8_t *buf, const uint32_t len) { + for (uint32_t i=0; i < len; i++) { + Serial.print(F("0x")); + if (buf[i] <= 0xF) Serial.write('0'); // Zero-pad small values + Serial.print(buf[i], HEX); + if (i < (len - 1)) Serial.write(' '); // Space between bytes + } + Serial.println(); +} + +static const struct { // Special payloads from Bluefruit Connect app... + char id; // Packet type identifier + uint8_t len; // Size of complete, well-formed packet of this type +} _app_packet[] = { + {'A', 15}, // Accelerometer + {'G', 15}, // Gyro + {'M', 15}, // Magnetometer + {'Q', 19}, // Quaterion + {'B', 5}, // Button + {'C', 6}, // Color + {'L', 15}, // Location +}; +#define NUM_PACKET_TYPES (sizeof _app_packet / sizeof _app_packet[0]) +#define SHORTEST_PACKET_LEN 5 // Button, for now + +/**************************************************************************/ +/*! + @brief Given packet data, identify if it's one of the known + Bluefruit Connect app packet types. + @param buf Pointer to packet data. + @param len Size of packet in bytes. + @returns Packet type index (0 to NUM_PACKET_TYPES-1) if recognized, + -1 if unrecognized. +*/ +/**************************************************************************/ +int8_t packetType(uint8_t *buf, uint8_t len) { + if ((len >= SHORTEST_PACKET_LEN) && (buf[0] == '!')) { + for (int8_t type=0; typeavailable()) { + char c = ble->read(); + if (c == '!') { // '!' resets buffer to start + len = 0; + xsum = 255; + } + packetbuffer[len++] = c; + // Stop when buffer's full or packet type recognized + if ((len >= READ_BUFSIZE) || + ((type = packetType(packetbuffer, len)) >= 0)) break; + start_time = now; // Reset timeout on char received + xsum -= c; // Not last char, do checksum math + type = -1; // Reset packet type finder + } + } while((now - start_time) < timeout); + + // If packet type recognized, verify checksum (else freeform string) + if ((type >= 0) && (xsum != packetbuffer[len-1])) { // Last byte = checksum + Serial.print("Packet checksum mismatch: "); + printHex(packetbuffer, len); + return 0; + } + + packetbuffer[len] = 0; // Terminate packet string + + return len; // Checksum is valid for packet, or it's a freeform string +} diff --git a/Rotary_Trinkey/Arduino_Volume_Mute_Example/.rotarytrinkey_m0.test.only b/EyeLights_Fire/EyeLights_Fire/.ledglasses_nrf52840.test.only similarity index 100% rename from Rotary_Trinkey/Arduino_Volume_Mute_Example/.rotarytrinkey_m0.test.only rename to EyeLights_Fire/EyeLights_Fire/.ledglasses_nrf52840.test.only diff --git a/EyeLights_Fire/EyeLights_Fire/EyeLights_Fire.ino b/EyeLights_Fire/EyeLights_Fire/EyeLights_Fire.ino new file mode 100644 index 000000000..1eb43c69a --- /dev/null +++ b/EyeLights_Fire/EyeLights_Fire/EyeLights_Fire.ino @@ -0,0 +1,135 @@ +// SPDX-FileCopyrightText: 2021 Phil Burgess for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +/* +FIRE EFFECT for Adafruit EyeLights (LED Glasses + Driver). +A demoscene classic that produces a cool analog-esque look with +modest means, iteratively scrolling and blurring raster data. +*/ + +#include // For LED driver + +Adafruit_EyeLights_buffered glasses; // Buffered for smooth animation + +// The raster data is intentionally one row taller than the LED matrix. +// Each frame, random noise is put in the bottom (off matrix) row. There's +// also an extra column on either side, to avoid needing edge clipping when +// neighboring pixels (left, center, right) are averaged later. +float data[6][20]; // 2D array where elements are accessed as data[y][x] + +// Each element in the raster is a single value representing brightness. +// A pre-computed lookup table maps these to RGB colors. This one happens +// to have 32 elements, but as we're not on an actual paletted hardware +// framebuffer it could be any size really (with suitable changes throughout). +uint32_t colormap[32]; +#define GAMMA 2.6 + +// Crude error handler, prints message to Serial console, flashes LED +void err(char *str, uint8_t hz) { + Serial.println(str); + pinMode(LED_BUILTIN, OUTPUT); + for (;;) digitalWrite(LED_BUILTIN, (millis() * hz / 500) & 1); +} + +void setup() { // Runs once at program start... + + // Initialize hardware + Serial.begin(115200); + if (! glasses.begin()) err("IS3741 not found", 2); + + // Configure glasses for reduced brightness, enable output + glasses.setLEDscaling(0xFF); + glasses.setGlobalCurrent(20); + glasses.enable(true); + + memset(data, 0, sizeof data); + + for(uint8_t i=0; i<32; i++) { + float n = i * 3.0 / 31.0; // 0.0 <= n <= 3.0 from start to end of map + float r, g, b; + if (n <= 1) { // 0.0 <= n <= 1.0 : black to red + r = n; // r,g,b are initially calculated 0 to 1 range + g = b = 0.0; + } else if (n <= 2) { // 1.0 <= n <= 2.0 : red to yellow + r = 1.0; + g = n - 1.0; + b = 0.0; + } else { // 2.0 <= n <= 3.0 : yellow to white + r = g = 1.0; + b = n - 2.0; + } + // Gamma correction linearizes perceived brightness, then scale to + // 0-255 for LEDs and store as a 'packed' RGB color. + colormap[i] = (uint32_t(pow(r, GAMMA) * 255.0) << 16) | + (uint32_t(pow(g, GAMMA) * 255.0) << 8) | + uint32_t(pow(b, GAMMA) * 255.0); + } +} + +// Linearly interpolate a range of brightnesses between two LEDs of +// one eyeglass ring, mapping through the global color table. LED range +// is non-inclusive; the first and last LEDs (which overlap matrix pixels) +// are not set. led2 MUST be > led1. LED indices may be >= 24 to 'wrap +// around' the seam at the top of the ring. +void interp(bool isRight, int led1, int led2, float level1, float level2) { + int span = led2 - led1 + 1; // Number of LEDs + float delta = level2 - level1; // Difference in brightness + for (int led = led1 + 1; led < led2; led++) { // For each LED in-between, + float ratio = (float)(led - led1) / span; // interpolate brightness level + uint32_t color = colormap[min(31, int(level1 + delta * ratio))]; + if (isRight) glasses.right_ring.setPixelColor(led % 24, color); + else glasses.left_ring.setPixelColor(led % 24, color); + } +} + +void loop() { // Repeat forever... + // At the start of each frame, fill the bottom (off matrix) row + // with random noise. To make things less strobey, old data from the + // prior frame still has about 1/3 'weight' here. There's no special + // real-world significance to the 85, it's just an empirically- + // derived fudge factor that happens to work well with the size of + // the color map. + for (uint8_t x=1; x<19; x++) { + data[5][x] = 0.33 * data[5][x] + 0.67 * ((float)random(1000) / 1000.0) * 85.0; + } + // If this were actual SRS BZNS 31337 D3M0SC3N3 code, great care + // would be taken to avoid floating-point math. But with few pixels, + // and so this code might be less obtuse, a casual approach is taken. + + // Each row (except last) is then processed, top-to-bottom. This + // order is important because it's an iterative algorithm...the + // output of each frame serves as input to the next, and the steps + // below (looking at the pixels below each row) are what makes the + // "flames" appear to move "up." + for (uint8_t y=0; y<5; y++) { // Current row of pixels + float *y1 = &data[y + 1][0]; // One row down + for (uint8_t x = 1; x < 19; x++) { // Skip left, right columns in data + // Each pixel is sort of the average of the three pixels + // under it (below left, below center, below right), but not + // exactly. The below center pixel has more 'weight' than the + // others, and the result is scaled to intentionally land + // short, making each row bit darker as they move up. + data[y][x] = (y1[x] + ((y1[x - 1] + y1[x + 1]) * 0.33)) * 0.35; + glasses.drawPixel(x - 1, y, glasses.color565(colormap[min(31, int(data[y][x]))])); + // Remember that the LED matrix uses GFX-style "565" colors, + // hence the round trip through color565() here, whereas the LED + // rings (referenced in interp()) use NeoPixel-style 24-bit colors + // (those can reference colormap[] directly). + } + } + + // That's all well and good for the matrix, but what about the extra + // LEDs in the rings? Since these don't align to the pixel grid, + // rather than trying to extend the raster data and filter it in + // somehow, we'll fill those arcs with colors interpolated from the + // endpoints where rings and matrix intersect. Maybe not perfect, + // but looks okay enough! + interp(false, 7, 17, data[4][8], data[4][1]); // Left ring bottom + interp(false, 21, 29, data[0][2], data[1][8]); // Left ring top + interp(true, 7, 17, data[4][18], data[4][11]); // Right ring bottom + interp(true, 19, 27, data[1][11], data[0][17]); // Right ring top + + glasses.show(); + delay(25); +} diff --git a/EyeLights_Fire/EyeLights_Fire_CircuitPython/code.py b/EyeLights_Fire/EyeLights_Fire_CircuitPython/code.py new file mode 100755 index 000000000..5c4bc670b --- /dev/null +++ b/EyeLights_Fire/EyeLights_Fire_CircuitPython/code.py @@ -0,0 +1,131 @@ +# SPDX-FileCopyrightText: 2021 Phil Burgess for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +""" +FIRE EFFECT for Adafruit EyeLights (LED Glasses + Driver). +A demoscene classic that produces a cool analog-esque look with +modest means, iteratively scrolling and blurring raster data. +""" + +import random +from supervisor import reload +import board +from busio import I2C +import adafruit_is31fl3741 +from adafruit_is31fl3741.adafruit_ledglasses import LED_Glasses + + +# HARDWARE SETUP --------- + +# Manually declare I2C (not board.I2C() directly) to access 1 MHz speed... +i2c = I2C(board.SCL, board.SDA, frequency=1000000) + +# Initialize the IS31 LED driver, buffered for smoother animation +glasses = LED_Glasses(i2c, allocate=adafruit_is31fl3741.MUST_BUFFER) +glasses.show() # Clear any residue on startup +glasses.global_current = 20 # Just middlin' bright, please + + +# INITIALIZE TABLES ------ + +# The raster data is intentionally one row taller than the LED matrix. +# Each frame, random noise is put in the bottom (off matrix) row. There's +# also an extra column on either side, to avoid needing edge clipping when +# neighboring pixels (left, center, right) are averaged later. +data = [[0] * (glasses.width + 2) for _ in range(glasses.height + 1)] +# (2D array where elements are accessed as data[y][x], initialized to 0) + +# Each element in the raster is a single value representing brightness. +# A pre-computed lookup table maps these to RGB colors. This one happens +# to have 32 elements, but as we're not on an actual paletted hardware +# framebuffer it could be any size really (with suitable changes throughout). +gamma = 2.6 +colormap = [] +for n in range(32): + n *= 3 / 31 # 0.0 <= n <= 3.0 from start to end of map + if n <= 1: # 0.0 <= n <= 1.0 : black to red + r = n # r,g,b are initially calculated 0 to 1 range + g = b = 0 + elif n <= 2: # 1.0 <= n <= 2.0 : red to yellow + r = 1 + g = n - 1 + b = 0 + else: # 2.0 <= n <= 3.0 : yellow to white + r = g = 1 + b = n - 2 + r = int((r ** gamma) * 255) # Gamma correction linearizes + g = int((g ** gamma) * 255) # perceived brightness, then + b = int((b ** gamma) * 255) # scale to 0-255 for LEDs and + colormap.append((r << 16) | (g << 8) | b) # store as 'packed' RGB color + + +# UTILITY FUNCTIONS ----- + + +def interp(ring, led1, led2, level1, level2): + """Linearly interpolate a range of brightnesses between two LEDs of + one eyeglass ring, mapping through the global color table. LED range + is non-inclusive; the first and last LEDs (which overlap matrix pixels) + are not set. led2 MUST be > led1. LED indices may be >= 24 to 'wrap + around' the seam at the top of the ring.""" + span = led2 - led1 + 1 # Number of LEDs + delta = level2 - level1 # Difference in brightness + for led in range(led1 + 1, led2): # For each LED in-between, + ratio = (led - led1) / span # interpolate brightness level + ring[led % 24] = colormap[min(31, int(level1 + delta * ratio))] + + +# MAIN LOOP ------------- + +while True: + # The try/except here is because VERY INFREQUENTLY the I2C bus will + # encounter an error when accessing the LED driver, whether from bumping + # around the wires or sometimes an I2C device just gets wedged. To more + # robustly handle the latter, the code will restart if that happens. + try: + + # At the start of each frame, fill the bottom (off matrix) row + # with random noise. To make things less strobey, old data from the + # prior frame still has about 1/3 'weight' here. There's no special + # real-world significance to the 85, it's just an empirically- + # derived fudge factor that happens to work well with the size of + # the color map. + for x in range(1, 19): + data[5][x] = 0.33 * data[5][x] + 0.67 * random.random() * 85 + # If this were actual SRS BZNS 31337 D3M0SC3N3 code, great care + # would be taken to avoid floating-point math. But with few pixels, + # and so this code might be less obtuse, a casual approach is taken. + + # Each row (except last) is then processed, top-to-bottom. This + # order is important because it's an iterative algorithm...the + # output of each frame serves as input to the next, and the steps + # below (looking at the pixels below each row) are what makes the + # "flames" appear to move "up." + for y in range(5): # Current row of pixels + y1 = data[y + 1] # One row down + for x in range(1, 19): # Skip left, right columns in data + # Each pixel is sort of the average of the three pixels + # under it (below left, below center, below right), but not + # exactly. The below center pixel has more 'weight' than the + # others, and the result is scaled to intentionally land + # short, making each row bit darker as they move up. + data[y][x] = (y1[x] + ((y1[x - 1] + y1[x + 1]) * 0.33)) * 0.35 + glasses.pixel(x - 1, y, colormap[min(31, int(data[y][x]))]) + + # That's all well and good for the matrix, but what about the extra + # LEDs in the rings? Since these don't align to the pixel grid, + # rather than trying to extend the raster data and filter it in + # somehow, we'll fill those arcs with colors interpolated from the + # endpoints where rings and matrix intersect. Maybe not perfect, + # but looks okay enough! + interp(glasses.left_ring, 7, 17, data[4][8], data[4][1]) + interp(glasses.left_ring, 21, 29, data[0][2], data[2][8]) + interp(glasses.right_ring, 7, 17, data[4][18], data[4][11]) + interp(glasses.right_ring, 19, 27, data[2][11], data[0][17]) + + glasses.show() # Buffered mode MUST use show() to refresh matrix + + except OSError: # See "try" notes above regarding rare I2C errors. + print("Restarting") + reload() diff --git a/Techno_Tiki_RGB_LED_Torch/Techno_Tiki_Circuit_Playground_Express/.ada_cpx.test.only b/EyeLights_Googly_Rings/EyeLights_Googly_Rings/.ledglasses_nrf52840.generate similarity index 100% rename from Techno_Tiki_RGB_LED_Torch/Techno_Tiki_Circuit_Playground_Express/.ada_cpx.test.only rename to EyeLights_Googly_Rings/EyeLights_Googly_Rings/.ledglasses_nrf52840.generate diff --git a/USB_SNES_Gamepad/teensySNES_Portal/.teensy2.test.only b/EyeLights_Googly_Rings/EyeLights_Googly_Rings/.ledglasses_nrf52840.test.only similarity index 100% rename from USB_SNES_Gamepad/teensySNES_Portal/.teensy2.test.only rename to EyeLights_Googly_Rings/EyeLights_Googly_Rings/.ledglasses_nrf52840.test.only diff --git a/EyeLights_Googly_Rings/EyeLights_Googly_Rings/EyeLights_Googly_Rings.ino b/EyeLights_Googly_Rings/EyeLights_Googly_Rings/EyeLights_Googly_Rings.ino new file mode 100644 index 000000000..c955083f1 --- /dev/null +++ b/EyeLights_Googly_Rings/EyeLights_Googly_Rings/EyeLights_Googly_Rings.ino @@ -0,0 +1,113 @@ +// SPDX-FileCopyrightText: 2021 Phil Burgess for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +/* +GOOGLY EYES for Adafruit EyeLight LED glasses + driver. Pendulum physics +simulation using accelerometer and math. This uses only the rings, not the +matrix portion. Adapted from Bill Earl's STEAM-Punk Goggles project: +https://learn.adafruit.com/steam-punk-goggles +*/ + +#include // For LED driver +#include // For accelerometer +#include // For m/s^2 accel units + +Adafruit_LIS3DH accel; +Adafruit_EyeLights_buffered glasses; // Buffered for smooth animation + +// A small class for our pendulum simulation. +class Pendulum { +public: + // Constructor. Pass pointer to EyeLights ring, and a 3-byte color array. + Pendulum(Adafruit_EyeLights_Ring_buffered *r, uint8_t *c) { + ring = r; + color = c; + // Initial pendulum position, plus axle friction, are randomized + // so rings don't spin in perfect lockstep. + angle = random(1000); + momentum = 0.0; + friction = 0.94 + random(300) * 0.0001; // Inverse friction, really + } + + // Given a pixel index (0-23) and a scaling factor (0.0-1.0), + // interpolate between LED "off" color (at 0.0) and this item's fully- + // lit color (at 1.0) and set pixel to the result. + void interp(uint8_t pixel, float scale) { + // Convert separate red, green, blue to "packed" 24-bit RGB value + ring->setPixelColor(pixel, + (int(color[0] * scale) << 16) | + (int(color[1] * scale) << 8) | + int(color[2] * scale)); + } + + // Given an accelerometer reading, run one cycle of the pendulum + // physics simulation and render the corresponding LED ring. + void iterate(sensors_event_t &event) { + // Minus here is because LED pixel indices run clockwise vs. trigwise. + // 0.006 is just an empirically-derived scaling fudge factor that looks + // good; smaller values for more sluggish rings, higher = more twitch. + momentum = momentum * friction - 0.006 * + (cos(angle) * event.acceleration.z + + sin(angle) * event.acceleration.x); + angle += momentum; + + // Scale pendulum angle into pixel space + float midpoint = fmodf(angle * 12.0 / M_PI, 24.0); + + // Go around the whole ring, setting each pixel based on proximity + // (this is also to erase the prior position)... + for (uint8_t i=0; i<24; i++) { + float dist = fabs(midpoint - (float)i); // Pixel to pendulum distance... + if (dist > 12.0) // If it crosses the "seam" at top, + dist = 24.0 - dist; // take the shorter path. + if (dist > 5.0) // Not close to pendulum, + ring->setPixelColor(i, 0); // erase pixel. + else if (dist < 2.0) // Close to pendulum, + interp(i, 1.0); // solid color + else // Anything in-between, + interp(i, (5.0 - dist) / 3.0); // interpolate + } + } +private: + Adafruit_EyeLights_Ring_buffered *ring; // -> glasses ring + uint8_t *color; // -> array of 3 uint8_t's [R,G,B] + float angle; // Current position around ring + float momentum; // Current 'oomph' + float friction; // A scaling constant to dampen motion +}; + +Pendulum pendulums[] = { + Pendulum(&glasses.left_ring, (uint8_t[3]){0, 20, 50}), // Cerulean blue, + Pendulum(&glasses.right_ring, (uint8_t[3]){0, 20, 50}), // 50 is plenty bright! +}; +#define N_PENDULUMS (sizeof pendulums / sizeof pendulums[0]) + +// Crude error handler, prints message to Serial console, flashes LED +void err(char *str, uint8_t hz) { + Serial.println(str); + pinMode(LED_BUILTIN, OUTPUT); + for (;;) digitalWrite(LED_BUILTIN, (millis() * hz / 500) & 1); +} + +void setup() { // Runs once at program start... + + // Initialize hardware + Serial.begin(115200); + if (! accel.begin()) err("LIS3DH not found", 5); + if (! glasses.begin()) err("IS3741 not found", 2); + + // Configure glasses for max brightness, enable output + glasses.setLEDscaling(0xFF); + glasses.setGlobalCurrent(0xFF); + glasses.enable(true); +} + +void loop() { // Repeat forever... + sensors_event_t event; + accel.getEvent(&event); // Read accelerometer once + for (uint8_t i=0; i dynamic_level: + # Got louder. Move level up quickly but allow initial "bump." + dynamic_level = upper * 0.7 + dynamic_level * 0.3 + else: + # Got quieter. Ease level down, else too many bumps. + dynamic_level = dynamic_level * 0.5 + lower * 0.5 + + # Apply vertical scale to spectrum data. Results may exceed + # matrix height...that's OK, adds impact! + #data = (spectrum - lower) * (7 / (dynamic_level - lower)) + data = (spectrum - lower) * ((glasses.height + 2) / (dynamic_level - lower)) + + for column, element in enumerate(column_table): + # Start BELOW matrix and accumulate bin weights UP, saves math + first_bin = element[0] + column_top = glasses.height + 1 + for bin_offset, weight in enumerate(element[1]): + column_top -= data[first_bin + bin_offset] * weight + + if column_top < element[3]: # Above current falling dot? + element[3] = column_top - 0.5 # Move dot up + element[4] = 0 # and clear out velocity + else: + element[3] += element[4] # Move dot down + element[4] += 0.2 # and accelerate + + column_top = int(column_top) # Quantize to pixel space + for row in range(column_top): # Erase area above column + glasses.pixel(column, row, 0) + for row in range(column_top, glasses.height): # Draw column + glasses.pixel(column, row, element[2]) + glasses.pixel(column, int(element[3]), 0xE08080) # Draw peak dot + + glasses.show() # Buffered mode MUST use show() to refresh matrix + + frames += 1 + # print(frames / (monotonic() - start_time), "FPS") + + except OSError: # See "try" notes above regarding rare I2C errors. + print("Restarting") + reload() diff --git a/Feather_Sense_Audio_Visualizer_13x9_RGB_LED_Matrix/code.py b/Feather_Sense_Audio_Visualizer_13x9_RGB_LED_Matrix/waterfall_visualizer/code.py similarity index 100% rename from Feather_Sense_Audio_Visualizer_13x9_RGB_LED_Matrix/code.py rename to Feather_Sense_Audio_Visualizer_13x9_RGB_LED_Matrix/waterfall_visualizer/code.py diff --git a/Flora_Citi_Bike_Helmet/Citi_Bike_Helmet/.teensy3.test.only b/Flora_Citi_Bike_Helmet/Citi_Bike_Helmet/.flora.test.only similarity index 100% rename from Flora_Citi_Bike_Helmet/Citi_Bike_Helmet/.teensy3.test.only rename to Flora_Citi_Bike_Helmet/Citi_Bike_Helmet/.flora.test.only diff --git a/Flora_Citi_Bike_Helmet/Citi_Bike_Helmet/Citi_Bike_Helmet.ino b/Flora_Citi_Bike_Helmet/Citi_Bike_Helmet/Citi_Bike_Helmet.ino index 015140329..f3a75ab57 100644 --- a/Flora_Citi_Bike_Helmet/Citi_Bike_Helmet/Citi_Bike_Helmet.ino +++ b/Flora_Citi_Bike_Helmet/Citi_Bike_Helmet/Citi_Bike_Helmet.ino @@ -22,7 +22,7 @@ LSM303 compass; #define LAT_LON_SIZE 311 -float lat_lon[LAT_LON_SIZE][2] PROGMEM = { +const float lat_lon[LAT_LON_SIZE][2] PROGMEM = { {40.767272, -73.993928}, {40.719115, -74.006666}, {40.711174, -74.000165}, @@ -475,7 +475,7 @@ void loop() // run over and over again //Serial.print("Altitude: "); Serial.println(GPS.altitude); //Serial.print("Satellites: "); Serial.println((int)GPS.satellites); compass.read(); - int heading = compass.heading((LSM303::vector){0,-1,0}); + int heading = compass.heading((LSM303::vector){0,-1,0}); Serial.print("Heading: "); Serial.println(heading); if ((calc_bearing(fLat, fLon, targetLat, targetLon) - heading) > 0) { @@ -639,8 +639,8 @@ unsigned long calc_dist(float flat1, float flon1, float flat2, float flon2) int find_closest_location(float current_lat, float current_lon) { int closest = 0; - unsigned long minDistance = -1; - unsigned long tempDistance; + signed long minDistance = -1; + signed long tempDistance; for (int i=0; i < LAT_LON_SIZE; i++) { float target_lat = pgm_read_float(&lat_lon[i][0]); float target_lon = pgm_read_float(&lat_lon[i][1]); @@ -729,7 +729,7 @@ void GoForward (uint32_t c, uint8_t wait) { // Slightly different, this makes the rainbow equally distributed throughout void rainbowCycle(uint8_t wait) { - uint16_t i, j; + uint16_t i; //for(j=0; j<256*5; j++) { // 5 cycles of all colors on wheel for(i=0; i< 10; i++) { diff --git a/USB_SNES_Gamepad/teensySNES_onebutton/.teensy2.test.only b/Guitar_Hero_MIDI/.qtpy_m0_tinyusb.test.only similarity index 100% rename from USB_SNES_Gamepad/teensySNES_onebutton/.teensy2.test.only rename to Guitar_Hero_MIDI/.qtpy_m0_tinyusb.test.only diff --git a/Guitar_Hero_MIDI/GuitarHeroMIDI.ino b/Guitar_Hero_MIDI/Guitar_Hero_MIDI.ino similarity index 100% rename from Guitar_Hero_MIDI/GuitarHeroMIDI.ino rename to Guitar_Hero_MIDI/Guitar_Hero_MIDI.ino diff --git a/USB_SNES_Gamepad/teensySNES_stellakey/.teensy2.test.only b/Introducing_CircuitPlaygroundExpress/digitalio_lib/.cpx_ada.test.only similarity index 100% rename from USB_SNES_Gamepad/teensySNES_stellakey/.teensy2.test.only rename to Introducing_CircuitPlaygroundExpress/digitalio_lib/.cpx_ada.test.only diff --git a/IrRobotControl/glove/code.py b/IrRobotControl/glove/code.py index f81b783f5..866a60dea 100644 --- a/IrRobotControl/glove/code.py +++ b/IrRobotControl/glove/code.py @@ -2,7 +2,6 @@ import time import busio import board import pulseio -import pwmio import adafruit_irremote import adafruit_lis3dh @@ -26,9 +25,8 @@ TRANSMIT_DELAY = 0.1 i2c = busio.I2C(board.ACCELEROMETER_SCL, board.ACCELEROMETER_SDA) sensor = adafruit_lis3dh.LIS3DH_I2C(i2c, address=0x19) -# Create a 'pwmio' output, to send infrared signals on the IR transmitter @ 38KHz -pwm = pwmio.PWMOut(board.IR_TX, frequency=38000, duty_cycle=2 ** 15) -pulseout = pulseio.PulseOut(pwm) +# Create a 'pulseio' output, to send infrared signals on the IR transmitter @ 38KHz +pulseout = pulseio.PulseOut(board.IR_TX, frequency=38000, duty_cycle=2 ** 15) # Create an encoder that will take numbers and turn them into IR pulses encoder = adafruit_irremote.GenericTransmit(header=[9500, 4500], diff --git a/USB_SNES_Gamepad/teensySNES_test1/.teensy2.test.only b/Joy_of_Arcada/.pygamer_tinyusb.test.only similarity index 100% rename from USB_SNES_Gamepad/teensySNES_test1/.teensy2.test.only rename to Joy_of_Arcada/.pygamer_tinyusb.test.only diff --git a/Joy_of_Arcada/Joy_of_Arcada.ino b/Joy_of_Arcada/Joy_of_Arcada.ino index de5280df1..ab6de3f9b 100644 --- a/Joy_of_Arcada/Joy_of_Arcada.ino +++ b/Joy_of_Arcada/Joy_of_Arcada.ino @@ -134,7 +134,7 @@ void setup() { // in which they are initialized. HID MUST be initialized before // Serial, which must be initialized before the display. - int status = arcada.begin(); // Save status for Serial print later + int status = arcada.arcadaBegin(); // Save status for Serial print later // HID (keyboard) initialization usb_hid.setPollInterval(2); @@ -157,7 +157,7 @@ void setup() { // Display initialization. This is all part of the persnickety sequence! arcada.displayBegin(); arcada.setBacklight(255); - arcada.fillScreen(ARCADA_BLACK); + arcada.display->fillScreen(ARCADA_BLACK); // Audio initialization AudioMemory(10); @@ -192,10 +192,10 @@ void setup() { } // At start, draw the entire blank/neutral face centered on screen - arcada.fillScreen(ARCADA_BLACK); // Erase any warnBoxes first - arcada.drawRGBBitmap( - (arcada.width() - FACE_WIDTH ) / 2, - (arcada.height() - FACE_HEIGHT) / 2, + arcada.display->fillScreen(ARCADA_BLACK); // Erase any warnBoxes first + arcada.display->drawRGBBitmap( + (arcada.display->width() - FACE_WIDTH ) / 2, + (arcada.display->height() - FACE_HEIGHT) / 2, (uint16_t *)face, FACE_WIDTH, FACE_HEIGHT); // Create an offscreen framebuffer that's just the bounding @@ -426,7 +426,7 @@ void loop() { // while a screen update is currently in progress. (This is assuming // SPI DMA is enabled in Adafruit_SPITFT.h. If it is not, that's OK, // this function call simply compiles to nothing in that case.) - arcada.dmaWait(); + arcada.display->dmaWait(); if(openRows) { // Draw the open section of the eyes, then draw the pupils on top @@ -484,7 +484,7 @@ void loop() { // is used...this is fastest as it can continue in the background // (while we process input on the next frame). arcada.blitFrameBuffer( - (arcada.width() - FACE_WIDTH ) / 2 + 13, - (arcada.height() - FACE_HEIGHT) / 2 + 25, + (arcada.display->width() - FACE_WIDTH ) / 2 + 13, + (arcada.display->height() - FACE_HEIGHT) / 2 + 25, false, true); // Non-blocking, big-endian } diff --git a/USB_SNES_Gamepad/teensySNES_test2/.teensy2.test.only b/Keypad_4x4_Clocked/.qtpy_m0_tinyusb.test.only similarity index 100% rename from USB_SNES_Gamepad/teensySNES_test2/.teensy2.test.only rename to Keypad_4x4_Clocked/.qtpy_m0_tinyusb.test.only diff --git a/Kinetic_POV/supernova_poi/.teensy3.test.only b/Kinetic_POV/supernova_poi/.none.test.only similarity index 100% rename from Kinetic_POV/supernova_poi/.teensy3.test.only rename to Kinetic_POV/supernova_poi/.none.test.only diff --git a/LED_Sand/.feather_32u4.test.only b/LED_Sand/.feather32u4.test.only similarity index 100% rename from LED_Sand/.feather_32u4.test.only rename to LED_Sand/.feather32u4.test.only diff --git a/MIDI_FeatherWing/.feather_m4_express_tinyusb.test.only b/MIDI_FeatherWing/.feather_m4_express_tinyusb.test.only new file mode 100644 index 000000000..e69de29bb diff --git a/MagTag_Progress_Displays/fonts/leaguespartan.license b/MagTag_Progress_Displays/weblate_translated_percent/fonts/leaguespartan.license similarity index 100% rename from MagTag_Progress_Displays/fonts/leaguespartan.license rename to MagTag_Progress_Displays/weblate_translated_percent/fonts/leaguespartan.license diff --git a/MagTag_Progress_Displays/fonts/leaguespartan11.bdf b/MagTag_Progress_Displays/weblate_translated_percent/fonts/leaguespartan11.bdf similarity index 100% rename from MagTag_Progress_Displays/fonts/leaguespartan11.bdf rename to MagTag_Progress_Displays/weblate_translated_percent/fonts/leaguespartan11.bdf diff --git a/MagTag_Progress_Displays/fonts/leaguespartan18.bdf b/MagTag_Progress_Displays/weblate_translated_percent/fonts/leaguespartan18.bdf similarity index 100% rename from MagTag_Progress_Displays/fonts/leaguespartan18.bdf rename to MagTag_Progress_Displays/weblate_translated_percent/fonts/leaguespartan18.bdf diff --git a/MagTag_Progress_Displays/fonts/epilogue.license b/MagTag_Progress_Displays/year_progress_percent/fonts/epilogue.license similarity index 100% rename from MagTag_Progress_Displays/fonts/epilogue.license rename to MagTag_Progress_Displays/year_progress_percent/fonts/epilogue.license diff --git a/MagTag_Progress_Displays/fonts/epilogue18.bdf b/MagTag_Progress_Displays/year_progress_percent/fonts/epilogue18.bdf similarity index 100% rename from MagTag_Progress_Displays/fonts/epilogue18.bdf rename to MagTag_Progress_Displays/year_progress_percent/fonts/epilogue18.bdf diff --git a/NeoKey_Trinkey/Arduino_HID_Cap_Touch_Example/hid_cap_touch.ino b/NeoKey_Trinkey/Arduino_HID_Cap_Touch_Example/Arduino_HID_Cap_Touch_Example.ino similarity index 100% rename from NeoKey_Trinkey/Arduino_HID_Cap_Touch_Example/hid_cap_touch.ino rename to NeoKey_Trinkey/Arduino_HID_Cap_Touch_Example/Arduino_HID_Cap_Touch_Example.ino diff --git a/Neopixel_Aquarium/.qtpy.test.only b/Neopixel_Aquarium/.qtpy_m0.test.only similarity index 100% rename from Neopixel_Aquarium/.qtpy.test.only rename to Neopixel_Aquarium/.qtpy_m0.test.only diff --git a/Nextmind_Unity_Control/.featherm4.test.only b/Nextmind_Unity_Control/.qtpy_m0.test.only similarity index 100% rename from Nextmind_Unity_Control/.featherm4.test.only rename to Nextmind_Unity_Control/.qtpy_m0.test.only diff --git a/Pico_Four_Keypad/code.py b/Pico_Four_Keypad/code.py new file mode 100644 index 000000000..73fe37473 --- /dev/null +++ b/Pico_Four_Keypad/code.py @@ -0,0 +1,47 @@ +# SPDX-FileCopyrightText: 2021 john park for Adafruit Industries +# SPDX-License-Identifier: MIT +# Pico Four Key USB HID Keypad + +import board +from digitalio import DigitalInOut, Pull +from adafruit_debouncer import Debouncer +import usb_hid +from adafruit_hid.keyboard import Keyboard +from adafruit_hid.keycode import Keycode + +kpd = Keyboard(usb_hid.devices) + +# define buttons +num_keys = 4 +pins = ( + board.GP0, + board.GP1, + board.GP2, + board.GP3 +) + +keys = [] +for pin in pins: + tmp_pin = DigitalInOut(pin) + tmp_pin.pull = Pull.UP + keys.append(Debouncer(tmp_pin)) + +keymap = { + (0): ("Select all", [Keycode.GUI, Keycode.A]), + (1): ("Cut", [Keycode.GUI, Keycode.X]), + (2): ("Copy", [Keycode.GUI, Keycode.C]), + (3): ("Paste", [Keycode.GUI, Keycode.V]) +} + +print("\nWelcome to keypad") +print("keymap:") +for k in range(num_keys): + print("\t", (keymap[k][0])) + + +while True: + for i in range(num_keys): + keys[i].update() + if keys[i].fell: + print(keymap[i][0]) + kpd.send(*keymap[i][1]) diff --git a/PyGamer_Bounce_Game/bounce/bounce.ino b/PyGamer_Bounce_Game/bounce/bounce.ino index 1f5961623..16d5e339a 100644 --- a/PyGamer_Bounce_Game/bounce/bounce.ino +++ b/PyGamer_Bounce_Game/bounce/bounce.ino @@ -90,25 +90,28 @@ void setup() { // initialize Serial.println("Hello! Arcada version of game"); - if (!arcada.begin()) { + if (!arcada.arcadaBegin()) { Serial.print("Failed to begin"); strip.fill(RED); strip.show(); while (1); } + + arcada.displayBegin(); // Initialize display code + arcada.setBacklight(0); // Initial display off + arcada.display->setRotation(0); // Rotate to portrait + arcada.display->fillScreen(background); // Clear screen if necessary + arcada.display->setTextColor(ARCADA_GREEN, ARCADA_BLACK); + arcada.display->setTextSize(2); + arcada.display->println(" "); + arcada.display->println(" Bounce!"); + if( !arcada.hasAccel() ) { strip.fill(YELLOW); strip.show(); arcada.haltBox("An accelerometer is required for this gamne"); } - arcada.displayBegin(); // Initialize display code - arcada.setBacklight(0); // Initial display off - arcada.setRotation(0); // Rotate to portrait - arcada.fillScreen(background); // Clear screen if necessary - arcada.setTextColor(ARCADA_GREEN, ARCADA_BLACK); - arcada.setTextSize(2); - arcada.println(" "); - arcada.println(" Bounce!"); + // Set up the logo bitmap int logo_origin_x = (128 - 2*LOGO_WIDTH ) / 2; int logo_origin_y = (160 - 2*LOGO_HEIGHT) / 2; @@ -118,34 +121,34 @@ void setup() { if(c & (0x80 >> (x & 7))) { int xx = logo_origin_x+2*x; int yy = logo_origin_y+2*y; - arcada.drawPixel(xx, yy, ARCADA_WHITE); - arcada.drawPixel(xx+1, yy, ARCADA_WHITE); - arcada.drawPixel(xx, yy+1, ARCADA_WHITE); - arcada.drawPixel(xx+1, yy+1, ARCADA_WHITE); + arcada.display->drawPixel(xx, yy, ARCADA_WHITE); + arcada.display->drawPixel(xx+1, yy, ARCADA_WHITE); + arcada.display->drawPixel(xx, yy+1, ARCADA_WHITE); + arcada.display->drawPixel(xx+1, yy+1, ARCADA_WHITE); } } } - arcada.println(" "); - arcada.println(" "); - arcada.println(" "); - arcada.println(" "); - arcada.println(" "); - arcada.setTextColor(ARCADA_ORANGE, ARCADA_BLACK); - arcada.setTextSize(1); - arcada.println(" "); - arcada.println(" Adafruit"); - arcada.println(" Industries"); + arcada.display->println(" "); + arcada.display->println(" "); + arcada.display->println(" "); + arcada.display->println(" "); + arcada.display->println(" "); + arcada.display->setTextColor(ARCADA_ORANGE, ARCADA_BLACK); + arcada.display->setTextSize(1); + arcada.display->println(" "); + arcada.display->println(" Adafruit"); + arcada.display->println(" Industries"); for (int i=0; i<220; i++) { // Display initial text arcada.setBacklight(i); delay(14); } arcada.setBacklight(250); - arcada.setTextColor(ST7735_WHITE, ST7735_BLACK); - arcada.println(" "); - arcada.println(" "); - arcada.println(" Press Start"); + arcada.display->setTextColor(ST7735_WHITE, ST7735_BLACK); + arcada.display->println(" "); + arcada.display->println(" "); + arcada.display->println(" Press Start"); while(!(arcada.readButtons() & ARCADA_BUTTONMASK_START)) ; // wait for start button - arcada.fillScreen(background); // Clear screen + arcada.display->fillScreen(background); // Clear screen arcada.enableSpeaker(1); // Enable the speaker and play opening tones pinMode(sound_pin, OUTPUT); @@ -187,7 +190,7 @@ void loop() { int acc_avg(int pin) { int avg = 0; - arcada.accel.getEvent(&event); + arcada.accel->getEvent(&event); switch (pin) { case acc_pinX: for(int i = 0; i < 50; i++) { @@ -214,7 +217,7 @@ int acc_avg(int pin) { int acc_readX() { int val; - arcada.accel.getEvent(&event); + arcada.accel->getEvent(&event); val = -1 * constrain((event.acceleration.y - acc_avgY)*7, -64, 64); // use Y for orientation // Serial.print("Acceleration: "); // joystick is at top // Serial.println(val); @@ -241,8 +244,8 @@ void BonusReset(){ nextBonus = random(30, 60); b_pendingPlatform = false; b_remaining = 0; - arcada.fillRect(0, s_height+2, 96, 10, background); - arcada.fillRect(0, s_height+1, 96, 1, w_color); + arcada.display->fillRect(0, s_height+2, 96, 10, background); + arcada.display->fillRect(0, s_height+1, 96, 1, w_color); EndUseBonus(); } @@ -250,8 +253,8 @@ void ClearBonus(){ EndUseBonus(); b_remaining = 0; p_color = p_color_default; - arcada.fillRect(0, s_height+2, 96, 10, background); - arcada.fillRect(0, s_height+1, s_width-1, 1, w_color); + arcada.display->fillRect(0, s_height+2, 96, 10, background); + arcada.display->fillRect(0, s_height+1, s_width-1, 1, w_color); b_used = false; } @@ -261,7 +264,7 @@ void GetBonus(){ b_pendingPlatform = false; beep(sound_pin, 3500, 50); // SOUND p_color = b_colors[b_onUseID]; - arcada.fillRect(0, s_height+2, 96, 10, background); + arcada.display->fillRect(0, s_height+2, 96, 10, background); switch (b_onUseID){ case 0: @@ -286,19 +289,19 @@ void GetBonus(){ break; } if(b_remaining > 1) { - arcada.fillRect(95, s_height+2, 1, 10, b_colors[b_onUseID]); - arcada.fillRect( 0, s_height+1, 95, 1, b_colors[b_onUseID]); + arcada.display->fillRect(95, s_height+2, 1, 10, b_colors[b_onUseID]); + arcada.display->fillRect( 0, s_height+1, 95, 1, b_colors[b_onUseID]); } } void UseBonus(){ if(b_remaining){ b_used = true; - arcada.fillRect(b_remaining*95/b_max, s_height+2, 1, 10, background); - arcada.drawPixel(b_remaining*95/b_max, s_height+1, w_color); + arcada.display->fillRect(b_remaining*95/b_max, s_height+2, 1, 10, background); + arcada.display->drawPixel(b_remaining*95/b_max, s_height+1, w_color); b_remaining --; - arcada.fillRect(b_remaining*95/b_max, s_height+2, 1, 10, b_colors[b_onUseID]); - arcada.drawPixel(b_remaining*95/b_max, s_height+1, b_colors[b_onUseID]); + arcada.display->fillRect(b_remaining*95/b_max, s_height+2, 1, 10, b_colors[b_onUseID]); + arcada.display->drawPixel(b_remaining*95/b_max, s_height+1, b_colors[b_onUseID]); switch (b_onUseID){ case 0: @@ -378,20 +381,20 @@ void CheckButtons(){ drawChar(s_width-6, textline2, speaker_icon, ARCADA_RED); // Put character in lower right corner to indicate speaker off } else { sound_on = 1; - arcada.fillRect( s_width-6, textline2, s_width-1, textline2+9, background); // Blank lower right character = sound on + arcada.display->fillRect( s_width-6, textline2, s_width-1, textline2+9, background); // Blank lower right character = sound on } } } void DrawPlayer(){ CheckButtons(); // check more frequently - arcada.fillRect(p_lastX, p_lastY, p_width, p_height, background); // erase previous pos + arcada.display->fillRect(p_lastX, p_lastY, p_width, p_height, background); // erase previous pos if(p_lastX > (s_width-1 - p_width)) // if across the edge of the screen - arcada.fillRect(0, p_lastY, p_lastX + p_width - s_width, p_height, background); + arcada.display->fillRect(0, p_lastY, p_lastX + p_width - s_width, p_height, background); - arcada.fillRect(p_X, p_Y, p_width, p_height, p_color); // draw new pos + arcada.display->fillRect(p_X, p_Y, p_width, p_height, p_color); // draw new pos if(p_X > (s_width-1 - p_width)) // if across the edge of the screen - arcada.fillRect(0, p_Y, p_X + p_width - s_width, p_height, p_color); + arcada.display->fillRect(0, p_Y, p_X + p_width - s_width, p_height, p_color); } void MovePlayer(){ @@ -429,7 +432,7 @@ void CollideBorders() { } } else { - arcada.fillRect(p_lastX, p_lastY, p_width, p_height, background); + arcada.display->fillRect(p_lastX, p_lastY, p_width, p_height, background); p_width--; p_height--; b_lives--; @@ -439,8 +442,8 @@ void CollideBorders() { } void ScoreSetup(){ - arcada.fillRect(0, s_height+2, 128, 10, background); - arcada.fillRect(0, s_height+1, 128, 1, w_color); + arcada.display->fillRect(0, s_height+2, 128, 10, background); + arcada.display->fillRect(0, s_height+1, 128, 1, w_color); // highscore = EEPROM.read(0); // highscore += (EEPROM.read(1)<<8); if(highscore > 64000){ @@ -478,11 +481,11 @@ void ScoreReset(){ void flashMessage() { uint8_t i; - arcada.fillRect( 0, textline2, s_width-10, textline2+9, background); + arcada.display->fillRect( 0, textline2, s_width-10, textline2+9, background); for(i=0; i<5; i++) { drawString(1, textline2, "HIGHSCORE!", p_color_default, 1); delay(400); - arcada.fillRect( 0, textline2, s_width-10, textline2+9, background); + arcada.display->fillRect( 0, textline2, s_width-10, textline2+9, background); delay(400); } drawString(1, textline2, "High score:", w_color, 1); @@ -507,7 +510,7 @@ void ScoreAdd(){ // add to the current score lower left // transform from int to string and display it void drawInt(unsigned int num, byte nx, byte ny, unsigned int color, unsigned int color2) { - arcada.fillRect(nx, ny, 29, 7, color2); + arcada.display->fillRect(nx, ny, 29, 7, color2); drawChar(nx+24, ny, 48+(num%10), color); if(num > 9) { @@ -593,26 +596,26 @@ void CollideWorld() { void DrawWorld() { for(byte i=0; ifillRect(world[i][2], world[i][3], world[i][5], 1, background); + arcada.display->fillRect(world[i][0], world[i][1], world[i][4], 1, w_color); } if(b_pendingPlatform){ - arcada.fillRect(world[b_platformID][0], world[b_platformID][1], world[b_platformID][4], 1, b_colors[b_pendingID]); + arcada.display->fillRect(world[b_platformID][0], world[b_platformID][1], world[b_platformID][4], 1, b_colors[b_pendingID]); } } void drawString(byte x, byte y, char *text, uint16_t color, bool wrap) { // replicate tft.drawString - arcada.setCursor(x,y); - arcada.setTextColor(color); - arcada.setTextWrap(wrap); - arcada.print(text); + arcada.display->setCursor(x,y); + arcada.display->setTextColor(color); + arcada.display->setTextWrap(wrap); + arcada.display->print(text); } void drawChar(byte x, byte y, char text, uint16_t color) { // replicate tft.drawChar - arcada.setCursor(x,y); - arcada.setTextColor(color); - arcada.print(text); + arcada.display->setCursor(x,y); + arcada.display->setTextColor(color); + arcada.display->print(text); Serial.println(text); } diff --git a/Rotary_Trinkey/neopixel_encoder_demo/.rotarytrinkey_m0.test.only b/Rotary_Trinkey/neopixel_encoder_demo/.rotarytrinkey_m0.test.only new file mode 100644 index 000000000..e69de29bb diff --git a/Rotary_Trinkey/Arduino_NeoPixel_Example/neopixel_encoder_demo.ino b/Rotary_Trinkey/neopixel_encoder_demo/neopixel_encoder_demo.ino similarity index 100% rename from Rotary_Trinkey/Arduino_NeoPixel_Example/neopixel_encoder_demo.ino rename to Rotary_Trinkey/neopixel_encoder_demo/neopixel_encoder_demo.ino diff --git a/Rotary_Trinkey/surfacedial_encoder_demo/.rotarytrinkey_m0.test.only b/Rotary_Trinkey/surfacedial_encoder_demo/.rotarytrinkey_m0.test.only new file mode 100644 index 000000000..e69de29bb diff --git a/Rotary_Trinkey/Arduino_SurfaceDial_Example/surfacedial_encoder_demo.ino b/Rotary_Trinkey/surfacedial_encoder_demo/surfacedial_encoder_demo.ino similarity index 100% rename from Rotary_Trinkey/Arduino_SurfaceDial_Example/surfacedial_encoder_demo.ino rename to Rotary_Trinkey/surfacedial_encoder_demo/surfacedial_encoder_demo.ino diff --git a/Rotary_Trinkey/volumemute_encoder_demo/.rotarytrinkey_m0.test.only b/Rotary_Trinkey/volumemute_encoder_demo/.rotarytrinkey_m0.test.only new file mode 100644 index 000000000..e69de29bb diff --git a/Rotary_Trinkey/Arduino_Volume_Mute_Example/volumemute_encoder_demo.ino b/Rotary_Trinkey/volumemute_encoder_demo/volumemute_encoder_demo.ino similarity index 100% rename from Rotary_Trinkey/Arduino_Volume_Mute_Example/volumemute_encoder_demo.ino rename to Rotary_Trinkey/volumemute_encoder_demo/volumemute_encoder_demo.ino diff --git a/Techno_Tiki_RGB_LED_Torch/Techno_Tiki_Circuit_Playground_Express/.cpx_ada.test.only b/Techno_Tiki_RGB_LED_Torch/Techno_Tiki_Circuit_Playground_Express/.cpx_ada.test.only new file mode 100644 index 000000000..e69de29bb diff --git a/TheThingsNetwork_Feather/ttn-featherm0-dht/.donttest.test.only b/TheThingsNetwork_Feather/ttn-featherm0-dht/.none.test.only similarity index 100% rename from TheThingsNetwork_Feather/ttn-featherm0-dht/.donttest.test.only rename to TheThingsNetwork_Feather/ttn-featherm0-dht/.none.test.only diff --git a/TheThingsNetwork_Feather/ttn-otaa-feather-us915-dht22-OLED/.donttest.test.only b/TheThingsNetwork_Feather/ttn-otaa-feather-us915-dht22-OLED/.none.test.only similarity index 100% rename from TheThingsNetwork_Feather/ttn-otaa-feather-us915-dht22-OLED/.donttest.test.only rename to TheThingsNetwork_Feather/ttn-otaa-feather-us915-dht22-OLED/.none.test.only diff --git a/USB_SNES_Gamepad/teensySNES_Portal/.none.test.only b/USB_SNES_Gamepad/teensySNES_Portal/.none.test.only new file mode 100644 index 000000000..e69de29bb diff --git a/USB_SNES_Gamepad/teensySNES_onebutton/.none.test.only b/USB_SNES_Gamepad/teensySNES_onebutton/.none.test.only new file mode 100644 index 000000000..e69de29bb diff --git a/USB_SNES_Gamepad/teensySNES_stellakey/.none.test.only b/USB_SNES_Gamepad/teensySNES_stellakey/.none.test.only new file mode 100644 index 000000000..e69de29bb diff --git a/USB_SNES_Gamepad/teensySNES_test1/.none.test.only b/USB_SNES_Gamepad/teensySNES_test1/.none.test.only new file mode 100644 index 000000000..e69de29bb diff --git a/USB_SNES_Gamepad/teensySNES_test2/.none.test.only b/USB_SNES_Gamepad/teensySNES_test2/.none.test.only new file mode 100644 index 000000000..e69de29bb diff --git a/Wearable_BLE_Temperature_Monitor/Wearable_BLE_Temperature_Monitor.ino b/Wearable_BLE_Temperature_Monitor/Wearable_BLE_Temperature_Monitor.ino index 85221025b..0e37a3cae 100644 --- a/Wearable_BLE_Temperature_Monitor/Wearable_BLE_Temperature_Monitor.ino +++ b/Wearable_BLE_Temperature_Monitor/Wearable_BLE_Temperature_Monitor.ino @@ -219,4 +219,4 @@ void disconnect_callback(uint16_t conn_handle, uint8_t reason) Serial.println(); Serial.print("Disconnected, reason = 0x"); Serial.println(reason, HEX); -} +} \ No newline at end of file diff --git a/library.deps b/library.deps index 693fd3551..20dde3b3d 100644 --- a/library.deps +++ b/library.deps @@ -1 +1 @@ -depends=Adafruit ILI9341, Adafruit BusIO, SD, Adafruit NeoPixel, Adafruit VS1053 Library, Adafruit BluefruitLE nRF51, Adafruit seesaw Library, Ethernet, Adafruit IO Arduino, FastLED, Adafruit LiquidCrystal, Adafruit SoftServo, TinyWireM, Adafruit AM radio library, WaveHC, Adafruit LED Backpack Library, MAX31850 OneWire, Adafruit VC0706 Serial Camera Library, RTClib, Adafruit SleepyDog Library, Adafruit Thermal Printer Library, Adafruit Zero I2S Library, Adafruit EPD, Adafruit SSD1351 library, Adafruit FONA Library, Adafruit Motor Shield V2 Library, Adafruit NeoMatrix, Adafruit Soundboard library, Adafruit Circuit Playground, ArduinoJson, Adafruit TCS34725, Adafruit Pixie, Adafruit GPS Library, TinyGPS, WiFi101, Adafruit DotStar, Adafruit Si7021 Library, Adafruit WS2801 Library, Mouse, Keyboard, Time, IRremote, Adafruit LSM9DS0 Library, Adafruit Arcada Library, MIDIUSB, PubSubClient, Adafruit LIS2MDL, Adafruit NeoPXL8, Adafruit MCP23017 Arduino Library, Adafruit MLX90640, LiquidCrystal, Adafruit NeoTrellis M4 Library, RGB matrix Panel, Adafruit MLX90614 Library, Adafruit RGB LCD Shield Library, MAX6675 library, Adafruit MP3, Adafruit Keypad, Adafruit Arcada GifDecoder, Keypad, Neosegment, Encoder, Adafruit TiCoServo, Adafruit Trellis Library, FauxmoESP, Adafruit LSM303 Accel, Adafruit LSM303DLH Mag, CapacitiveSensor, Adafruit Zero PDM Library, Adafruit DMA neopixel library, elapsedMillis, DST RTC, Adafruit SHARP Memory Display, Adafruit SPIFlash, BSEC Software Library, WiiChuck, Adafruit DPS310, Adafruit AHTX0, RotaryEncoder +depends=Adafruit ILI9341, Adafruit BusIO, SD, Adafruit NeoPixel, Adafruit VS1053 Library, Adafruit BluefruitLE nRF51, Adafruit seesaw Library, Ethernet, Adafruit IO Arduino, FastLED, Adafruit LiquidCrystal, Adafruit SoftServo, TinyWireM, Adafruit AM radio library, WaveHC, Adafruit LED Backpack Library, MAX31850 OneWire, Adafruit VC0706 Serial Camera Library, RTClib, Adafruit SleepyDog Library, Adafruit Thermal Printer Library, Adafruit Zero I2S Library, Adafruit EPD, Adafruit SSD1351 library, Adafruit FONA Library, Adafruit Motor Shield V2 Library, Adafruit NeoMatrix, Adafruit Soundboard library, Adafruit Circuit Playground, ArduinoJson, Adafruit TCS34725, Adafruit Pixie, Adafruit GPS Library, TinyGPS, WiFi101, Adafruit DotStar, Adafruit Si7021 Library, Adafruit WS2801 Library, Mouse, Keyboard, Time, IRremote, Adafruit LSM9DS0 Library, Adafruit Arcada Library, MIDIUSB, PubSubClient, Adafruit LIS2MDL, Adafruit NeoPXL8, Adafruit MCP23017 Arduino Library, Adafruit MLX90640, LiquidCrystal, Adafruit NeoTrellis M4 Library, RGB matrix Panel, Adafruit MLX90614 Library, Adafruit RGB LCD Shield Library, MAX6675 library, Adafruit MP3, Adafruit Keypad, Adafruit Arcada GifDecoder, Keypad, Neosegment, Encoder, Adafruit TiCoServo, Adafruit Trellis Library, FauxmoESP, Adafruit LSM303 Accel, Adafruit LSM303DLH Mag, Adafruit LSM303DLHC, CapacitiveSensor, Adafruit Zero PDM Library, Adafruit DMA neopixel library, elapsedMillis, DST RTC, Adafruit SHARP Memory Display, Adafruit SPIFlash, BSEC Software Library, WiiChuck, Adafruit DPS310, Adafruit AHTX0, RotaryEncoder, Adafruit MCP9808 Library, LSM303, Adafruit Protomatter, HID-Project, Adafruit IS31FL3741 Library diff --git a/oshwa_magtag_display/bmps/oshwa_full.bmp b/oshwa_magtag_display/bmps/oshwa_full.bmp new file mode 100644 index 000000000..b12d84f89 Binary files /dev/null and b/oshwa_magtag_display/bmps/oshwa_full.bmp differ diff --git a/oshwa_magtag_display/code.py b/oshwa_magtag_display/code.py new file mode 100644 index 000000000..48d8ba9ef --- /dev/null +++ b/oshwa_magtag_display/code.py @@ -0,0 +1,189 @@ +# SPDX-FileCopyrightText: 2021 Dylan Herrada for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +import random +import ssl +import gc +import wifi +import socketpool +import adafruit_requests as requests +from adafruit_magtag.magtag import MagTag + +# Get wifi details and more from a secrets.py file +try: + from secrets import secrets +except ImportError: + print("WiFi secrets are kept in secrets.py, please add them there!") + raise + +# Initialize magtag object +magtag = MagTag() + +magtag.set_background("bmps/oshwa_full.bmp") + +# Set up WiFi +wifi.radio.connect(secrets["ssid"], secrets["password"]) +print(f"Connected to {secrets['ssid']}!") +print("My IP address is", wifi.radio.ipv4_address) + +socket = socketpool.SocketPool(wifi.radio) +https = requests.Session(socket, ssl.create_default_context()) + +# Paste your API token below +TOKEN = "YOUR_API_TOKEN" + + +def font_width_to_dict(font): + # Reads the font file to determine how wide each character is + # Used to avoid bad wrapping breaking the QR code + chars = {} + with open(font, "r") as file: + for line in file: + if "FONTBOUNDINGBOX" in line: + size = int(line.split(" ")[1]) + if "ENCODING" in line and "_ENCODING" not in line: + character = chr(int(line.split(" ")[1][:-1])) + chars[character] = None + if "SWIDTH" in line: + swidth = (int(line.split(" ")[1]) / 1000) * size + if "DWIDTH" in line: + chars[character] = int(int(line.split(" ")[1]) + swidth) + return chars + + +def wrap(text, max_width, max_lines, font): + # Used to wrap the title and description to avoid breaking the QR code + lines = [] + ellipsis = 3 * font["."] + line = "" + line_width = 0 + for word in text.split(" "): + for character in word: + line_width += font[character] + if ( + len(lines) + 1 != max_lines + or sum(font[i] for i in word) + line_width <= max_width + ): + if line_width > max_width: + print(str(line_width) + line) + line_width = sum(font[i] for i in word) + lines.append(line.strip()) + line = word + " " + break + else: + for char_1 in word: + if line_width + ellipsis + font[char_1] > max_width: + line = line + "..." + print(str(line_width) + line) + lines.append(line) + return "\n".join(lines[:max_lines]) + line = line + char_1 + line_width += font[char_1] + + else: + line = line + word + " " + + lines.append(line.strip()) + return "\n".join(lines[:max_lines]) + + +# Get first 300 items, saving only the OSHWA UIDs. The first 300 are also used to find the +# number of requests that will need to be made. +# This was done this way since if the items themselves were all asked for and stored, the MagTag +# would run out of memory. If we just got the number of total projects and chose a random number, +# that also wouldn't work as you can only get individual projects with an OSHWA UID and these UIDs +# are prefixed by the country they were registered in, thus making getting it with a simple number +# in-between 1 and the total number of registered projects impossible. +URL = "https://certificationapi.oshwa.org/api/projects?limit=300" + +print(URL) + +payload = {} +headers = {"Content-Type": "application/json", "Authorization": f"Bearer {TOKEN}"} + +oshwaID = [] + +print("Getting number of projects and first set of 300 projects") +with https.get(URL, headers=headers, data=payload) as response: + R_JSON = response.json() + total = int(R_JSON["total"]) + print(f"{total} Projects") + for i in R_JSON["items"]: + oshwaID.append(i["oshwaUid"]) + R_JSON.clear() + R_JSON = None + gc.collect() + +# Gets the rest of the OSHWA UIDs +print(len(oshwaID)) +for i in range(int(total / 300)): + print(f"Getting request {i+2}") + url = ( + f"https://certificationapi.oshwa.org/api/projects?limit=300&offset={3*(i+1)}00" + ) + with https.get(url, headers=headers, data=payload) as response: + R_JSON = response.json() + for item in R_JSON["items"]: + oshwaID.append(item["oshwaUid"]) + R_JSON.clear() + R_JSON = None + gc.collect() + print(f"{len(oshwaID)} IDs gathered") + +# Select the UID that will be displayed +selected = random.choice(oshwaID) + +# Get the project that will be displayed +url = f"https://certificationapi.oshwa.org/api/projects/{selected}" +response = https.get(url, headers=headers, data=payload) + +selected = response.json()[0] + +# Filters out characters that the API or the MagTag itself isn't handling correctly +for char in range(1, 32): + selected["projectDescription"].replace(chr(char), "") + +selected["projectDescription"] = ( + selected["projectDescription"] + .replace("'", "'") + .replace("&#x27;", "'") + .replace("/", "/") + .replace(""", '"') + .replace("’", "'") +) + +# Add the two text fields +magtag.add_text( + text_font="fonts/Arial-Bold-12.bdf", + text_position=(5, 0), + text_scale=1, + line_spacing=0.7, + text_anchor_point=(0, 0), +) + +magtag.add_text( + text_font="fonts/ArialMT-9.bdf", + text_position=(5, 38), + text_scale=1, + line_spacing=0.6, + text_anchor_point=(0, 0), +) + +# Create the QR code +url = f"https://certification.oshwa.org/{selected['oshwaUid'].lower()}.html" +magtag.graphics.qrcode(url, qr_size=4, x=173, y=3) + +# Prepare to wrap the text correctly by getting the width of each character for every font +arial_12 = font_width_to_dict("fonts/Arial-Bold-12.bdf") +arial_9 = font_width_to_dict("fonts/ArialMT-9.bdf") + +# Set the text. On some characters, this fails. If so, run the whole file again in 5 seconds +try: + magtag.set_text(wrap(selected["projectName"], 545, 2, arial_12), 0, False) + magtag.set_text(wrap(selected["projectDescription"], 530, 19, arial_9), 1) + magtag.exit_and_deep_sleep(3600) +except Exception: # pylint: disable=broad-except + print("Could not set title or description: unsupported glyphs.") + print("Trying again in 10 seconds.") + magtag.exit_and_deep_sleep(10) diff --git a/oshwa_magtag_display/fonts/Arial-Bold-12.bdf b/oshwa_magtag_display/fonts/Arial-Bold-12.bdf new file mode 100644 index 000000000..672399a7c --- /dev/null +++ b/oshwa_magtag_display/fonts/Arial-Bold-12.bdf @@ -0,0 +1,6131 @@ +STARTFONT 2.1 +COMMENT +COMMENT Converted from OpenType font "arialbd.ttf" by "otf2bdf 3.0". +COMMENT +FONT -FreeType-Arial-Bold-R-Normal--17-120-100-100-P-89-ISO10646-1 +SIZE 12 100 100 +FONTBOUNDINGBOX 34 26 -9 -8 +STARTPROPERTIES 19 +FOUNDRY "FreeType" +FAMILY_NAME "Arial" +WEIGHT_NAME "Bold" +SLANT "R" +SETWIDTH_NAME "Normal" +ADD_STYLE_NAME "" +PIXEL_SIZE 17 +POINT_SIZE 120 +RESOLUTION_X 100 +RESOLUTION_Y 100 +SPACING "P" +AVERAGE_WIDTH 89 +CHARSET_REGISTRY "ISO10646" +CHARSET_ENCODING "1" +FONT_ASCENT 15 +FONT_DESCENT 3 +COPYRIGHT "© 2017 The Monotype Corporation. All Rights Reserved. Hebrew OpenType Layout logic copyright © 2003 & 2007, Ralph Hancock & John Hudson. This layout logic for Biblical Hebrew is open source software under the MIT License; see embedded license description for details." +_OTF_FONTFILE "arialbd.ttf" +_OTF_PSNAME "Arial-BoldMT" +ENDPROPERTIES +CHARS 318 +STARTCHAR 0020 +ENCODING 32 +SWIDTH 300 0 +DWIDTH 5 0 +BBX 0 0 0 0 +BITMAP +ENDCHAR +STARTCHAR 0021 +ENCODING 33 +SWIDTH 360 0 +DWIDTH 6 0 +BBX 2 12 2 0 +BITMAP +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +00 +C0 +C0 +ENDCHAR +STARTCHAR 0022 +ENCODING 34 +SWIDTH 480 0 +DWIDTH 8 0 +BBX 6 4 1 8 +BITMAP +CC +CC +CC +CC +ENDCHAR +STARTCHAR 0023 +ENCODING 35 +SWIDTH 540 0 +DWIDTH 9 0 +BBX 10 12 0 0 +BITMAP +0D80 +0D80 +1B00 +FFC0 +FFC0 +1B00 +3600 +FFC0 +FFC0 +3600 +6C00 +6C00 +ENDCHAR +STARTCHAR 0024 +ENCODING 36 +SWIDTH 540 0 +DWIDTH 9 0 +BBX 7 15 1 -2 +BITMAP +10 +38 +7C +D6 +D0 +F0 +78 +3C +1E +D6 +D6 +7C +38 +10 +10 +ENDCHAR +STARTCHAR 0025 +ENCODING 37 +SWIDTH 960 0 +DWIDTH 16 0 +BBX 15 12 0 0 +BITMAP +7830 +CC60 +CC60 +CCC0 +CD80 +7980 +033C +0366 +0666 +0666 +0C66 +183C +ENDCHAR +STARTCHAR 0026 +ENCODING 38 +SWIDTH 720 0 +DWIDTH 12 0 +BBX 11 12 1 0 +BITMAP +3E00 +7F00 +6300 +6300 +3E00 +3C00 +6C80 +CEC0 +C780 +C3C0 +7FE0 +3C40 +ENDCHAR +STARTCHAR 0027 +ENCODING 39 +SWIDTH 240 0 +DWIDTH 4 0 +BBX 2 4 1 8 +BITMAP +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 0028 +ENCODING 40 +SWIDTH 360 0 +DWIDTH 6 0 +BBX 4 15 1 -3 +BITMAP +30 +60 +60 +60 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +60 +60 +60 +30 +ENDCHAR +STARTCHAR 0029 +ENCODING 41 +SWIDTH 360 0 +DWIDTH 6 0 +BBX 4 15 1 -3 +BITMAP +C0 +60 +60 +60 +30 +30 +30 +30 +30 +30 +30 +60 +60 +60 +C0 +ENDCHAR +STARTCHAR 002A +ENCODING 42 +SWIDTH 420 0 +DWIDTH 7 0 +BBX 5 5 1 7 +BITMAP +20 +F8 +20 +50 +D8 +ENDCHAR +STARTCHAR 002B +ENCODING 43 +SWIDTH 600 0 +DWIDTH 10 0 +BBX 8 8 1 2 +BITMAP +18 +18 +18 +FF +FF +18 +18 +18 +ENDCHAR +STARTCHAR 002C +ENCODING 44 +SWIDTH 300 0 +DWIDTH 5 0 +BBX 2 5 1 -3 +BITMAP +C0 +C0 +40 +40 +80 +ENDCHAR +STARTCHAR 002D +ENCODING 45 +SWIDTH 360 0 +DWIDTH 6 0 +BBX 5 2 1 3 +BITMAP +F8 +F8 +ENDCHAR +STARTCHAR 002E +ENCODING 46 +SWIDTH 300 0 +DWIDTH 5 0 +BBX 2 2 1 0 +BITMAP +C0 +C0 +ENDCHAR +STARTCHAR 002F +ENCODING 47 +SWIDTH 300 0 +DWIDTH 5 0 +BBX 5 12 0 0 +BITMAP +18 +18 +30 +30 +30 +30 +60 +60 +60 +60 +C0 +C0 +ENDCHAR +STARTCHAR 0030 +ENCODING 48 +SWIDTH 540 0 +DWIDTH 9 0 +BBX 8 12 0 0 +BITMAP +3C +7E +E7 +C3 +C3 +C3 +C3 +C3 +C3 +E7 +7E +3C +ENDCHAR +STARTCHAR 0031 +ENCODING 49 +SWIDTH 540 0 +DWIDTH 9 0 +BBX 5 12 1 0 +BITMAP +18 +38 +78 +D8 +98 +18 +18 +18 +18 +18 +18 +18 +ENDCHAR +STARTCHAR 0032 +ENCODING 50 +SWIDTH 540 0 +DWIDTH 9 0 +BBX 8 12 0 0 +BITMAP +3C +7E +E3 +C3 +03 +06 +0E +1C +38 +60 +FF +FF +ENDCHAR +STARTCHAR 0033 +ENCODING 51 +SWIDTH 540 0 +DWIDTH 9 0 +BBX 8 12 0 0 +BITMAP +3E +7F +E3 +03 +1E +1E +07 +03 +C3 +E7 +7E +3C +ENDCHAR +STARTCHAR 0034 +ENCODING 52 +SWIDTH 540 0 +DWIDTH 9 0 +BBX 8 12 0 0 +BITMAP +06 +0E +0E +1E +36 +36 +66 +C6 +FF +FF +06 +06 +ENDCHAR +STARTCHAR 0035 +ENCODING 53 +SWIDTH 540 0 +DWIDTH 9 0 +BBX 8 12 0 0 +BITMAP +7E +7E +60 +C0 +FC +FE +C7 +03 +C3 +E7 +7E +3C +ENDCHAR +STARTCHAR 0036 +ENCODING 54 +SWIDTH 540 0 +DWIDTH 9 0 +BBX 8 12 0 0 +BITMAP +3E +7F +63 +C0 +DC +FE +E7 +C3 +C3 +63 +7E +3C +ENDCHAR +STARTCHAR 0037 +ENCODING 55 +SWIDTH 540 0 +DWIDTH 9 0 +BBX 8 12 0 0 +BITMAP +FF +FF +06 +0C +0C +18 +18 +18 +30 +30 +30 +30 +ENDCHAR +STARTCHAR 0038 +ENCODING 56 +SWIDTH 540 0 +DWIDTH 9 0 +BBX 8 12 0 0 +BITMAP +3C +7E +C3 +C3 +C3 +7E +7E +C3 +C3 +C3 +7E +3C +ENDCHAR +STARTCHAR 0039 +ENCODING 57 +SWIDTH 540 0 +DWIDTH 9 0 +BBX 8 12 0 0 +BITMAP +3C +7E +C6 +C3 +C3 +E7 +7F +3B +03 +C6 +FE +7C +ENDCHAR +STARTCHAR 003A +ENCODING 58 +SWIDTH 360 0 +DWIDTH 6 0 +BBX 2 9 2 0 +BITMAP +C0 +C0 +00 +00 +00 +00 +00 +C0 +C0 +ENDCHAR +STARTCHAR 003B +ENCODING 59 +SWIDTH 360 0 +DWIDTH 6 0 +BBX 2 12 2 -3 +BITMAP +C0 +C0 +00 +00 +00 +00 +00 +C0 +C0 +40 +40 +80 +ENDCHAR +STARTCHAR 003C +ENCODING 60 +SWIDTH 600 0 +DWIDTH 10 0 +BBX 8 9 0 1 +BITMAP +01 +07 +1E +78 +E0 +78 +1E +07 +01 +ENDCHAR +STARTCHAR 003D +ENCODING 61 +SWIDTH 600 0 +DWIDTH 10 0 +BBX 9 6 0 3 +BITMAP +FF80 +FF80 +0000 +0000 +FF80 +FF80 +ENDCHAR +STARTCHAR 003E +ENCODING 62 +SWIDTH 600 0 +DWIDTH 10 0 +BBX 8 9 0 1 +BITMAP +80 +E0 +78 +1E +07 +1E +78 +E0 +80 +ENDCHAR +STARTCHAR 003F +ENCODING 63 +SWIDTH 600 0 +DWIDTH 10 0 +BBX 8 12 1 0 +BITMAP +3C +7E +E3 +C3 +07 +0E +1C +18 +18 +00 +18 +18 +ENDCHAR +STARTCHAR 0040 +ENCODING 64 +SWIDTH 1020 0 +DWIDTH 17 0 +BBX 16 16 1 -4 +BITMAP +07E0 +1FF8 +381C +776C +6FE6 +ECE6 +D8E6 +D8C6 +D8CE +D9DC +DFF8 +6EF0 +7007 +381E +1FFC +07F0 +ENDCHAR +STARTCHAR 0041 +ENCODING 65 +SWIDTH 660 0 +DWIDTH 11 0 +BBX 11 12 0 0 +BITMAP +0E00 +0E00 +1B00 +1B00 +1B00 +3180 +3180 +3F80 +7FC0 +60C0 +60C0 +C060 +ENDCHAR +STARTCHAR 0042 +ENCODING 66 +SWIDTH 720 0 +DWIDTH 12 0 +BBX 10 12 1 0 +BITMAP +FF00 +FF80 +C180 +C180 +C180 +FF00 +FF80 +C0C0 +C0C0 +C0C0 +FF80 +FF00 +ENDCHAR +STARTCHAR 0043 +ENCODING 67 +SWIDTH 720 0 +DWIDTH 12 0 +BBX 10 12 1 0 +BITMAP +1F00 +7F80 +61C0 +E080 +C000 +C000 +C000 +C000 +E080 +61C0 +7F80 +1F00 +ENDCHAR +STARTCHAR 0044 +ENCODING 68 +SWIDTH 720 0 +DWIDTH 12 0 +BBX 10 12 1 0 +BITMAP +FE00 +FF80 +C180 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +C180 +FF80 +FE00 +ENDCHAR +STARTCHAR 0045 +ENCODING 69 +SWIDTH 660 0 +DWIDTH 11 0 +BBX 9 12 1 0 +BITMAP +FF80 +FF80 +C000 +C000 +C000 +FF80 +FF80 +C000 +C000 +C000 +FF80 +FF80 +ENDCHAR +STARTCHAR 0046 +ENCODING 70 +SWIDTH 600 0 +DWIDTH 10 0 +BBX 8 12 1 0 +BITMAP +FF +FF +C0 +C0 +C0 +FE +FE +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 0047 +ENCODING 71 +SWIDTH 780 0 +DWIDTH 13 0 +BBX 11 12 1 0 +BITMAP +1F80 +7FC0 +60E0 +E040 +C000 +C000 +C3E0 +C3E0 +E060 +60E0 +7FE0 +1F80 +ENDCHAR +STARTCHAR 0048 +ENCODING 72 +SWIDTH 720 0 +DWIDTH 12 0 +BBX 10 12 1 0 +BITMAP +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +FFC0 +FFC0 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +ENDCHAR +STARTCHAR 0049 +ENCODING 73 +SWIDTH 240 0 +DWIDTH 4 0 +BBX 2 12 1 0 +BITMAP +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 004A +ENCODING 74 +SWIDTH 540 0 +DWIDTH 9 0 +BBX 8 12 0 0 +BITMAP +03 +03 +03 +03 +03 +03 +03 +03 +C3 +E7 +7E +3C +ENDCHAR +STARTCHAR 004B +ENCODING 75 +SWIDTH 720 0 +DWIDTH 12 0 +BBX 10 12 1 0 +BITMAP +C0C0 +C180 +C300 +C600 +CC00 +DE00 +F700 +E300 +C380 +C180 +C0C0 +C0C0 +ENDCHAR +STARTCHAR 004C +ENCODING 76 +SWIDTH 600 0 +DWIDTH 10 0 +BBX 8 12 1 0 +BITMAP +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +FF +FF +ENDCHAR +STARTCHAR 004D +ENCODING 77 +SWIDTH 780 0 +DWIDTH 13 0 +BBX 11 12 1 0 +BITMAP +E0E0 +E0E0 +F1E0 +F1E0 +D160 +DB60 +DB60 +DB60 +CE60 +CE60 +CE60 +C460 +ENDCHAR +STARTCHAR 004E +ENCODING 78 +SWIDTH 720 0 +DWIDTH 12 0 +BBX 10 12 1 0 +BITMAP +C0C0 +E0C0 +F0C0 +F0C0 +D8C0 +CCC0 +CCC0 +C6C0 +C3C0 +C3C0 +C1C0 +C0C0 +ENDCHAR +STARTCHAR 004F +ENCODING 79 +SWIDTH 780 0 +DWIDTH 13 0 +BBX 11 12 1 0 +BITMAP +1F00 +7FC0 +60C0 +E060 +C060 +C060 +C060 +C060 +C060 +60C0 +7FC0 +1F00 +ENDCHAR +STARTCHAR 0050 +ENCODING 80 +SWIDTH 660 0 +DWIDTH 11 0 +BBX 9 12 1 0 +BITMAP +FE00 +FF00 +C380 +C180 +C380 +FF00 +FE00 +C000 +C000 +C000 +C000 +C000 +ENDCHAR +STARTCHAR 0051 +ENCODING 81 +SWIDTH 780 0 +DWIDTH 13 0 +BBX 11 13 1 -1 +BITMAP +1F00 +7FC0 +60C0 +E060 +C060 +C060 +C060 +C060 +C6E0 +63C0 +7FC0 +1EC0 +0060 +ENDCHAR +STARTCHAR 0052 +ENCODING 82 +SWIDTH 720 0 +DWIDTH 12 0 +BBX 11 12 1 0 +BITMAP +FF00 +FF80 +C1C0 +C0C0 +C1C0 +FF80 +FE00 +C700 +C380 +C180 +C1C0 +C0E0 +ENDCHAR +STARTCHAR 0053 +ENCODING 83 +SWIDTH 660 0 +DWIDTH 11 0 +BBX 9 12 1 0 +BITMAP +3E00 +7F00 +E380 +C180 +F000 +7E00 +1F00 +0380 +C180 +E380 +7F00 +3E00 +ENDCHAR +STARTCHAR 0054 +ENCODING 84 +SWIDTH 600 0 +DWIDTH 10 0 +BBX 10 12 0 0 +BITMAP +FFC0 +FFC0 +0C00 +0C00 +0C00 +0C00 +0C00 +0C00 +0C00 +0C00 +0C00 +0C00 +ENDCHAR +STARTCHAR 0055 +ENCODING 85 +SWIDTH 720 0 +DWIDTH 12 0 +BBX 10 12 1 0 +BITMAP +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +E1C0 +7F80 +3F00 +ENDCHAR +STARTCHAR 0056 +ENCODING 86 +SWIDTH 660 0 +DWIDTH 11 0 +BBX 11 12 0 0 +BITMAP +C060 +60C0 +60C0 +60C0 +3180 +3180 +3B80 +1B00 +1B00 +0E00 +0E00 +0E00 +ENDCHAR +STARTCHAR 0057 +ENCODING 87 +SWIDTH 1020 0 +DWIDTH 17 0 +BBX 17 12 0 0 +BITMAP +C1C180 +E1C180 +63E300 +636300 +636300 +377600 +363600 +363600 +1E3E00 +1C1C00 +1C1C00 +1C1C00 +ENDCHAR +STARTCHAR 0058 +ENCODING 88 +SWIDTH 660 0 +DWIDTH 11 0 +BBX 9 12 1 0 +BITMAP +C180 +E380 +6300 +3600 +3E00 +1C00 +1C00 +3E00 +3600 +6300 +E380 +C180 +ENDCHAR +STARTCHAR 0059 +ENCODING 89 +SWIDTH 600 0 +DWIDTH 10 0 +BBX 10 12 0 0 +BITMAP +C0C0 +E1C0 +6180 +3300 +3300 +1E00 +0C00 +0C00 +0C00 +0C00 +0C00 +0C00 +ENDCHAR +STARTCHAR 005A +ENCODING 90 +SWIDTH 540 0 +DWIDTH 9 0 +BBX 9 12 0 0 +BITMAP +7F80 +7F80 +0300 +0600 +0E00 +0C00 +1800 +3800 +3000 +6000 +FF80 +FF80 +ENDCHAR +STARTCHAR 005B +ENCODING 91 +SWIDTH 360 0 +DWIDTH 6 0 +BBX 4 15 1 -3 +BITMAP +F0 +F0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +F0 +F0 +ENDCHAR +STARTCHAR 005C +ENCODING 92 +SWIDTH 300 0 +DWIDTH 5 0 +BBX 5 12 0 0 +BITMAP +C0 +C0 +60 +60 +60 +60 +30 +30 +30 +30 +18 +18 +ENDCHAR +STARTCHAR 005D +ENCODING 93 +SWIDTH 360 0 +DWIDTH 6 0 +BBX 4 15 1 -3 +BITMAP +F0 +F0 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +F0 +F0 +ENDCHAR +STARTCHAR 005E +ENCODING 94 +SWIDTH 600 0 +DWIDTH 10 0 +BBX 8 7 1 5 +BITMAP +18 +3C +3C +66 +66 +66 +C3 +ENDCHAR +STARTCHAR 005F +ENCODING 95 +SWIDTH 540 0 +DWIDTH 9 0 +BBX 9 2 0 -3 +BITMAP +FF80 +FF80 +ENDCHAR +STARTCHAR 0060 +ENCODING 96 +SWIDTH 360 0 +DWIDTH 6 0 +BBX 3 2 1 10 +BITMAP +C0 +60 +ENDCHAR +STARTCHAR 0061 +ENCODING 97 +SWIDTH 540 0 +DWIDTH 9 0 +BBX 8 9 1 0 +BITMAP +7C +FE +C6 +1E +7E +E6 +C6 +FE +7B +ENDCHAR +STARTCHAR 0062 +ENCODING 98 +SWIDTH 600 0 +DWIDTH 10 0 +BBX 8 12 1 0 +BITMAP +C0 +C0 +C0 +DC +FE +E7 +C3 +C3 +C3 +E7 +FE +DC +ENDCHAR +STARTCHAR 0063 +ENCODING 99 +SWIDTH 540 0 +DWIDTH 9 0 +BBX 7 9 1 0 +BITMAP +3C +7E +E6 +C0 +C0 +C0 +E6 +7E +3C +ENDCHAR +STARTCHAR 0064 +ENCODING 100 +SWIDTH 600 0 +DWIDTH 10 0 +BBX 8 12 1 0 +BITMAP +03 +03 +03 +3B +7F +E7 +C3 +C3 +C3 +E7 +7F +3B +ENDCHAR +STARTCHAR 0065 +ENCODING 101 +SWIDTH 540 0 +DWIDTH 9 0 +BBX 7 9 1 0 +BITMAP +38 +7C +C6 +FE +FE +C0 +E6 +7C +38 +ENDCHAR +STARTCHAR 0066 +ENCODING 102 +SWIDTH 300 0 +DWIDTH 5 0 +BBX 6 12 0 0 +BITMAP +3C +7C +60 +F8 +F8 +60 +60 +60 +60 +60 +60 +60 +ENDCHAR +STARTCHAR 0067 +ENCODING 103 +SWIDTH 600 0 +DWIDTH 10 0 +BBX 8 12 1 -3 +BITMAP +3B +7F +E7 +C3 +C3 +C3 +E7 +7F +3B +C3 +FF +7E +ENDCHAR +STARTCHAR 0068 +ENCODING 104 +SWIDTH 600 0 +DWIDTH 10 0 +BBX 8 12 1 0 +BITMAP +C0 +C0 +C0 +DE +FF +E3 +C3 +C3 +C3 +C3 +C3 +C3 +ENDCHAR +STARTCHAR 0069 +ENCODING 105 +SWIDTH 240 0 +DWIDTH 4 0 +BBX 2 12 1 0 +BITMAP +C0 +C0 +00 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 006A +ENCODING 106 +SWIDTH 240 0 +DWIDTH 4 0 +BBX 4 15 -1 -3 +BITMAP +30 +30 +00 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +F0 +E0 +ENDCHAR +STARTCHAR 006B +ENCODING 107 +SWIDTH 540 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +C0 +C0 +C0 +C6 +CC +D8 +F8 +FC +EC +CC +C6 +C6 +ENDCHAR +STARTCHAR 006C +ENCODING 108 +SWIDTH 240 0 +DWIDTH 4 0 +BBX 2 12 1 0 +BITMAP +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 006D +ENCODING 109 +SWIDTH 840 0 +DWIDTH 14 0 +BBX 12 9 1 0 +BITMAP +DCE0 +FFF0 +E730 +C630 +C630 +C630 +C630 +C630 +C630 +ENDCHAR +STARTCHAR 006E +ENCODING 110 +SWIDTH 600 0 +DWIDTH 10 0 +BBX 8 9 1 0 +BITMAP +DE +FF +E3 +C3 +C3 +C3 +C3 +C3 +C3 +ENDCHAR +STARTCHAR 006F +ENCODING 111 +SWIDTH 600 0 +DWIDTH 10 0 +BBX 8 9 1 0 +BITMAP +3C +7E +E7 +C3 +C3 +C3 +E7 +7E +3C +ENDCHAR +STARTCHAR 0070 +ENCODING 112 +SWIDTH 600 0 +DWIDTH 10 0 +BBX 8 12 1 -3 +BITMAP +DC +FE +E7 +C3 +C3 +C3 +E7 +FE +DC +C0 +C0 +C0 +ENDCHAR +STARTCHAR 0071 +ENCODING 113 +SWIDTH 600 0 +DWIDTH 10 0 +BBX 8 12 1 -3 +BITMAP +3B +7F +E7 +C3 +C3 +C3 +E7 +7F +3B +03 +03 +03 +ENDCHAR +STARTCHAR 0072 +ENCODING 114 +SWIDTH 420 0 +DWIDTH 7 0 +BBX 6 9 1 0 +BITMAP +DC +FC +E0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 0073 +ENCODING 115 +SWIDTH 540 0 +DWIDTH 9 0 +BBX 7 9 1 0 +BITMAP +7C +FE +C6 +F0 +7C +0E +C6 +FE +7C +ENDCHAR +STARTCHAR 0074 +ENCODING 116 +SWIDTH 360 0 +DWIDTH 6 0 +BBX 5 12 0 0 +BITMAP +20 +60 +60 +F8 +F8 +60 +60 +60 +60 +60 +78 +38 +ENDCHAR +STARTCHAR 0075 +ENCODING 117 +SWIDTH 600 0 +DWIDTH 10 0 +BBX 8 9 1 0 +BITMAP +C3 +C3 +C3 +C3 +C3 +C3 +C7 +FF +7B +ENDCHAR +STARTCHAR 0076 +ENCODING 118 +SWIDTH 540 0 +DWIDTH 9 0 +BBX 7 9 1 0 +BITMAP +C6 +C6 +C6 +6C +6C +6C +38 +38 +38 +ENDCHAR +STARTCHAR 0077 +ENCODING 119 +SWIDTH 780 0 +DWIDTH 13 0 +BBX 13 9 0 0 +BITMAP +C718 +C718 +6730 +6DB0 +6DB0 +6DB0 +38E0 +38E0 +38E0 +ENDCHAR +STARTCHAR 0078 +ENCODING 120 +SWIDTH 540 0 +DWIDTH 9 0 +BBX 7 9 1 0 +BITMAP +C6 +EE +6C +38 +38 +38 +6C +EE +C6 +ENDCHAR +STARTCHAR 0079 +ENCODING 121 +SWIDTH 540 0 +DWIDTH 9 0 +BBX 9 12 0 -3 +BITMAP +C180 +C180 +6300 +6300 +3600 +3600 +3E00 +1C00 +1C00 +1800 +7800 +7000 +ENDCHAR +STARTCHAR 007A +ENCODING 122 +SWIDTH 540 0 +DWIDTH 9 0 +BBX 7 9 1 0 +BITMAP +FE +FE +0C +1C +38 +70 +60 +FE +FE +ENDCHAR +STARTCHAR 007B +ENCODING 123 +SWIDTH 420 0 +DWIDTH 7 0 +BBX 6 15 1 -3 +BITMAP +1C +3C +30 +30 +30 +30 +E0 +E0 +30 +30 +30 +30 +30 +3C +1C +ENDCHAR +STARTCHAR 007C +ENCODING 124 +SWIDTH 240 0 +DWIDTH 4 0 +BBX 2 16 1 -4 +BITMAP +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 007D +ENCODING 125 +SWIDTH 420 0 +DWIDTH 7 0 +BBX 6 15 0 -3 +BITMAP +E0 +F0 +30 +30 +30 +30 +1C +1C +30 +30 +30 +30 +30 +F0 +E0 +ENDCHAR +STARTCHAR 007E +ENCODING 126 +SWIDTH 600 0 +DWIDTH 10 0 +BBX 9 3 0 4 +BITMAP +7880 +FF80 +8F00 +ENDCHAR +STARTCHAR 00A0 +ENCODING 160 +SWIDTH 300 0 +DWIDTH 5 0 +BBX 0 0 0 0 +BITMAP +ENDCHAR +STARTCHAR 00A1 +ENCODING 161 +SWIDTH 360 0 +DWIDTH 6 0 +BBX 2 12 2 -3 +BITMAP +C0 +C0 +00 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 00A2 +ENCODING 162 +SWIDTH 540 0 +DWIDTH 9 0 +BBX 8 15 0 -3 +BITMAP +02 +02 +04 +3E +7E +EB +C8 +D0 +D3 +F7 +7E +3C +20 +40 +40 +ENDCHAR +STARTCHAR 00A3 +ENCODING 163 +SWIDTH 540 0 +DWIDTH 9 0 +BBX 9 12 0 0 +BITMAP +1E00 +3F00 +6380 +6180 +6000 +FC00 +FC00 +3000 +3000 +7900 +FF80 +4700 +ENDCHAR +STARTCHAR 00A4 +ENCODING 164 +SWIDTH 540 0 +DWIDTH 9 0 +BBX 9 9 0 1 +BITMAP +2200 +7F00 +FF80 +6300 +6300 +6300 +FF80 +7F00 +2200 +ENDCHAR +STARTCHAR 00A5 +ENCODING 165 +SWIDTH 540 0 +DWIDTH 9 0 +BBX 8 12 0 0 +BITMAP +C3 +66 +66 +24 +3C +3C +FF +18 +FF +18 +18 +18 +ENDCHAR +STARTCHAR 00A6 +ENCODING 166 +SWIDTH 240 0 +DWIDTH 4 0 +BBX 2 16 1 -4 +BITMAP +C0 +C0 +C0 +C0 +C0 +C0 +00 +00 +00 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 00A7 +ENCODING 167 +SWIDTH 540 0 +DWIDTH 9 0 +BBX 8 16 0 -4 +BITMAP +3C +7E +66 +70 +38 +7C +CE +C7 +E3 +73 +3E +1C +0E +66 +7E +3C +ENDCHAR +STARTCHAR 00A8 +ENCODING 168 +SWIDTH 360 0 +DWIDTH 6 0 +BBX 6 2 0 10 +BITMAP +CC +CC +ENDCHAR +STARTCHAR 00A9 +ENCODING 169 +SWIDTH 780 0 +DWIDTH 13 0 +BBX 12 12 0 0 +BITMAP +0F00 +30C0 +4020 +4F20 +9090 +9010 +9010 +9090 +4F20 +4020 +30C0 +0F00 +ENDCHAR +STARTCHAR 00AA +ENCODING 170 +SWIDTH 360 0 +DWIDTH 6 0 +BBX 5 6 0 6 +BITMAP +70 +D8 +38 +D8 +D8 +78 +ENDCHAR +STARTCHAR 00AB +ENCODING 171 +SWIDTH 540 0 +DWIDTH 9 0 +BBX 7 8 1 1 +BITMAP +36 +6C +6C +D8 +D8 +6C +6C +36 +ENDCHAR +STARTCHAR 00AC +ENCODING 172 +SWIDTH 600 0 +DWIDTH 10 0 +BBX 9 6 0 3 +BITMAP +FF80 +FF80 +0180 +0180 +0180 +0180 +ENDCHAR +STARTCHAR 00AD +ENCODING 173 +SWIDTH 360 0 +DWIDTH 6 0 +BBX 5 2 1 3 +BITMAP +F8 +F8 +ENDCHAR +STARTCHAR 00AE +ENCODING 174 +SWIDTH 780 0 +DWIDTH 13 0 +BBX 12 12 0 0 +BITMAP +0F00 +30C0 +4020 +4E20 +8910 +8910 +8E10 +8910 +4920 +4020 +30C0 +0F00 +ENDCHAR +STARTCHAR 00AF +ENCODING 175 +SWIDTH 540 0 +DWIDTH 9 0 +BBX 9 2 0 13 +BITMAP +FF80 +FF80 +ENDCHAR +STARTCHAR 00B0 +ENCODING 176 +SWIDTH 420 0 +DWIDTH 7 0 +BBX 5 5 1 7 +BITMAP +70 +88 +88 +88 +70 +ENDCHAR +STARTCHAR 00B1 +ENCODING 177 +SWIDTH 540 0 +DWIDTH 9 0 +BBX 8 11 0 0 +BITMAP +18 +18 +18 +FF +FF +18 +18 +18 +00 +FF +FF +ENDCHAR +STARTCHAR 00B2 +ENCODING 178 +SWIDTH 360 0 +DWIDTH 6 0 +BBX 5 6 0 6 +BITMAP +70 +D8 +18 +30 +60 +F8 +ENDCHAR +STARTCHAR 00B3 +ENCODING 179 +SWIDTH 360 0 +DWIDTH 6 0 +BBX 5 6 0 6 +BITMAP +70 +D8 +30 +18 +D8 +70 +ENDCHAR +STARTCHAR 00B4 +ENCODING 180 +SWIDTH 360 0 +DWIDTH 6 0 +BBX 3 2 1 10 +BITMAP +60 +C0 +ENDCHAR +STARTCHAR 00B5 +ENCODING 181 +SWIDTH 600 0 +DWIDTH 10 0 +BBX 8 12 1 -3 +BITMAP +C3 +C3 +C3 +C3 +C3 +C3 +E7 +FF +DB +C0 +C0 +C0 +ENDCHAR +STARTCHAR 00B6 +ENCODING 182 +SWIDTH 540 0 +DWIDTH 9 0 +BBX 9 16 0 -4 +BITMAP +3F80 +7F80 +FB00 +FB00 +FB00 +FB00 +7B00 +1B00 +1B00 +1B00 +1B00 +1B00 +1B00 +1B00 +1B00 +1B00 +ENDCHAR +STARTCHAR 00B7 +ENCODING 183 +SWIDTH 360 0 +DWIDTH 6 0 +BBX 2 2 2 5 +BITMAP +C0 +C0 +ENDCHAR +STARTCHAR 00B8 +ENCODING 184 +SWIDTH 300 0 +DWIDTH 5 0 +BBX 4 3 0 -3 +BITMAP +70 +30 +E0 +ENDCHAR +STARTCHAR 00B9 +ENCODING 185 +SWIDTH 360 0 +DWIDTH 6 0 +BBX 4 6 0 6 +BITMAP +30 +F0 +30 +30 +30 +30 +ENDCHAR +STARTCHAR 00BA +ENCODING 186 +SWIDTH 360 0 +DWIDTH 6 0 +BBX 5 6 1 6 +BITMAP +70 +D8 +D8 +D8 +D8 +70 +ENDCHAR +STARTCHAR 00BB +ENCODING 187 +SWIDTH 540 0 +DWIDTH 9 0 +BBX 7 8 1 1 +BITMAP +D8 +6C +6C +36 +36 +6C +6C +D8 +ENDCHAR +STARTCHAR 00BC +ENCODING 188 +SWIDTH 840 0 +DWIDTH 14 0 +BBX 14 12 0 0 +BITMAP +30C0 +F0C0 +3180 +3180 +3300 +3300 +0618 +0638 +0C58 +1898 +18FC +3018 +ENDCHAR +STARTCHAR 00BD +ENCODING 189 +SWIDTH 840 0 +DWIDTH 14 0 +BBX 13 12 0 0 +BITMAP +30C0 +F0C0 +3180 +3180 +3300 +3300 +0670 +0CD8 +0C18 +1830 +1860 +30F8 +ENDCHAR +STARTCHAR 00BE +ENCODING 190 +SWIDTH 840 0 +DWIDTH 14 0 +BBX 14 12 0 0 +BITMAP +7060 +D8C0 +30C0 +1980 +D980 +7300 +0618 +0638 +0C58 +0C98 +18FC +1818 +ENDCHAR +STARTCHAR 00BF +ENCODING 191 +SWIDTH 600 0 +DWIDTH 10 0 +BBX 8 12 1 -3 +BITMAP +18 +18 +00 +18 +18 +38 +70 +E0 +C3 +C7 +7E +3C +ENDCHAR +STARTCHAR 00C0 +ENCODING 192 +SWIDTH 660 0 +DWIDTH 11 0 +BBX 11 15 0 0 +BITMAP +0C00 +0600 +0000 +0E00 +0E00 +1B00 +1B00 +1B00 +3180 +3180 +3F80 +7FC0 +60C0 +60C0 +C060 +ENDCHAR +STARTCHAR 00C1 +ENCODING 193 +SWIDTH 660 0 +DWIDTH 11 0 +BBX 11 15 0 0 +BITMAP +0300 +0600 +0000 +0E00 +0E00 +1B00 +1B00 +1B00 +3180 +3180 +3F80 +7FC0 +60C0 +60C0 +C060 +ENDCHAR +STARTCHAR 00C2 +ENCODING 194 +SWIDTH 660 0 +DWIDTH 11 0 +BBX 11 15 0 0 +BITMAP +0E00 +1B00 +0000 +0E00 +0E00 +1B00 +1B00 +1B00 +3180 +3180 +3F80 +7FC0 +60C0 +60C0 +C060 +ENDCHAR +STARTCHAR 00C3 +ENCODING 195 +SWIDTH 660 0 +DWIDTH 11 0 +BBX 11 15 0 0 +BITMAP +1C80 +1380 +0000 +0E00 +0E00 +1B00 +1B00 +1B00 +3180 +3180 +3F80 +7FC0 +60C0 +60C0 +C060 +ENDCHAR +STARTCHAR 00C4 +ENCODING 196 +SWIDTH 660 0 +DWIDTH 11 0 +BBX 11 15 0 0 +BITMAP +1980 +1980 +0000 +0E00 +0E00 +1B00 +1B00 +1B00 +3180 +3180 +3F80 +7FC0 +60C0 +60C0 +C060 +ENDCHAR +STARTCHAR 00C5 +ENCODING 197 +SWIDTH 660 0 +DWIDTH 11 0 +BBX 11 15 0 0 +BITMAP +0600 +0900 +0900 +0E00 +0E00 +1B00 +1B00 +1B00 +3180 +3180 +3F80 +7FC0 +60C0 +60C0 +C060 +ENDCHAR +STARTCHAR 00C6 +ENCODING 198 +SWIDTH 1020 0 +DWIDTH 17 0 +BBX 17 12 -1 0 +BITMAP +03FF80 +07FF80 +06C000 +0CC000 +0CC000 +18FF80 +18FF80 +3FC000 +3FC000 +60C000 +60FF80 +C0FF80 +ENDCHAR +STARTCHAR 00C7 +ENCODING 199 +SWIDTH 720 0 +DWIDTH 12 0 +BBX 10 15 1 -3 +BITMAP +1F00 +7F80 +61C0 +E080 +C000 +C000 +C000 +C000 +E080 +61C0 +7F80 +1F00 +0E00 +0600 +1C00 +ENDCHAR +STARTCHAR 00C8 +ENCODING 200 +SWIDTH 660 0 +DWIDTH 11 0 +BBX 9 15 1 0 +BITMAP +1800 +0C00 +0000 +FF80 +FF80 +C000 +C000 +C000 +FF80 +FF80 +C000 +C000 +C000 +FF80 +FF80 +ENDCHAR +STARTCHAR 00C9 +ENCODING 201 +SWIDTH 660 0 +DWIDTH 11 0 +BBX 9 15 1 0 +BITMAP +0600 +0C00 +0000 +FF80 +FF80 +C000 +C000 +C000 +FF80 +FF80 +C000 +C000 +C000 +FF80 +FF80 +ENDCHAR +STARTCHAR 00CA +ENCODING 202 +SWIDTH 660 0 +DWIDTH 11 0 +BBX 9 15 1 0 +BITMAP +1C00 +3600 +0000 +FF80 +FF80 +C000 +C000 +C000 +FF80 +FF80 +C000 +C000 +C000 +FF80 +FF80 +ENDCHAR +STARTCHAR 00CB +ENCODING 203 +SWIDTH 660 0 +DWIDTH 11 0 +BBX 9 15 1 0 +BITMAP +3300 +3300 +0000 +FF80 +FF80 +C000 +C000 +C000 +FF80 +FF80 +C000 +C000 +C000 +FF80 +FF80 +ENDCHAR +STARTCHAR 00CC +ENCODING 204 +SWIDTH 240 0 +DWIDTH 4 0 +BBX 3 15 0 0 +BITMAP +C0 +60 +00 +60 +60 +60 +60 +60 +60 +60 +60 +60 +60 +60 +60 +ENDCHAR +STARTCHAR 00CD +ENCODING 205 +SWIDTH 240 0 +DWIDTH 4 0 +BBX 3 15 1 0 +BITMAP +60 +C0 +00 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 00CE +ENCODING 206 +SWIDTH 240 0 +DWIDTH 4 0 +BBX 5 15 0 0 +BITMAP +70 +D8 +00 +60 +60 +60 +60 +60 +60 +60 +60 +60 +60 +60 +60 +ENDCHAR +STARTCHAR 00CF +ENCODING 207 +SWIDTH 240 0 +DWIDTH 4 0 +BBX 6 15 -1 0 +BITMAP +CC +CC +00 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +ENDCHAR +STARTCHAR 00D0 +ENCODING 208 +SWIDTH 720 0 +DWIDTH 12 0 +BBX 11 12 0 0 +BITMAP +7F00 +7FC0 +60C0 +6060 +6060 +FC60 +6060 +6060 +6060 +60C0 +7FC0 +7F00 +ENDCHAR +STARTCHAR 00D1 +ENCODING 209 +SWIDTH 720 0 +DWIDTH 12 0 +BBX 10 15 1 0 +BITMAP +3900 +2700 +0000 +C0C0 +E0C0 +F0C0 +F0C0 +D8C0 +CCC0 +CCC0 +C6C0 +C3C0 +C3C0 +C1C0 +C0C0 +ENDCHAR +STARTCHAR 00D2 +ENCODING 210 +SWIDTH 780 0 +DWIDTH 13 0 +BBX 11 15 1 0 +BITMAP +0C00 +0600 +0000 +1F00 +7FC0 +60C0 +E060 +C060 +C060 +C060 +C060 +C060 +60C0 +7FC0 +1F00 +ENDCHAR +STARTCHAR 00D3 +ENCODING 211 +SWIDTH 780 0 +DWIDTH 13 0 +BBX 11 15 1 0 +BITMAP +0600 +0C00 +0000 +1F00 +7FC0 +60C0 +E060 +C060 +C060 +C060 +C060 +C060 +60C0 +7FC0 +1F00 +ENDCHAR +STARTCHAR 00D4 +ENCODING 212 +SWIDTH 780 0 +DWIDTH 13 0 +BBX 11 15 1 0 +BITMAP +0E00 +1B00 +0000 +1F00 +7FC0 +60C0 +E060 +C060 +C060 +C060 +C060 +C060 +60C0 +7FC0 +1F00 +ENDCHAR +STARTCHAR 00D5 +ENCODING 213 +SWIDTH 780 0 +DWIDTH 13 0 +BBX 11 15 1 0 +BITMAP +1C80 +1380 +0000 +1F00 +7FC0 +60C0 +E060 +C060 +C060 +C060 +C060 +C060 +60C0 +7FC0 +1F00 +ENDCHAR +STARTCHAR 00D6 +ENCODING 214 +SWIDTH 780 0 +DWIDTH 13 0 +BBX 11 15 1 0 +BITMAP +1980 +1980 +0000 +1F00 +7FC0 +60C0 +E060 +C060 +C060 +C060 +C060 +C060 +60C0 +7FC0 +1F00 +ENDCHAR +STARTCHAR 00D7 +ENCODING 215 +SWIDTH 600 0 +DWIDTH 10 0 +BBX 6 7 2 2 +BITMAP +84 +CC +78 +30 +78 +CC +84 +ENDCHAR +STARTCHAR 00D8 +ENCODING 216 +SWIDTH 780 0 +DWIDTH 13 0 +BBX 12 13 1 0 +BITMAP +0020 +1F30 +7FE0 +61C0 +C1E0 +C360 +C660 +CC60 +D860 +F060 +70C0 +FFC0 +9F00 +ENDCHAR +STARTCHAR 00D9 +ENCODING 217 +SWIDTH 720 0 +DWIDTH 12 0 +BBX 10 15 1 0 +BITMAP +1800 +0C00 +0000 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +E1C0 +7F80 +3F00 +ENDCHAR +STARTCHAR 00DA +ENCODING 218 +SWIDTH 720 0 +DWIDTH 12 0 +BBX 10 15 1 0 +BITMAP +0600 +0C00 +0000 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +E1C0 +7F80 +3F00 +ENDCHAR +STARTCHAR 00DB +ENCODING 219 +SWIDTH 720 0 +DWIDTH 12 0 +BBX 10 15 1 0 +BITMAP +0E00 +1B00 +0000 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +E1C0 +7F80 +3F00 +ENDCHAR +STARTCHAR 00DC +ENCODING 220 +SWIDTH 720 0 +DWIDTH 12 0 +BBX 10 15 1 0 +BITMAP +3300 +3300 +0000 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +E1C0 +7F80 +3F00 +ENDCHAR +STARTCHAR 00DD +ENCODING 221 +SWIDTH 600 0 +DWIDTH 10 0 +BBX 10 15 0 0 +BITMAP +0600 +0C00 +0000 +C0C0 +E1C0 +6180 +3300 +3300 +1E00 +0C00 +0C00 +0C00 +0C00 +0C00 +0C00 +ENDCHAR +STARTCHAR 00DE +ENCODING 222 +SWIDTH 660 0 +DWIDTH 11 0 +BBX 9 12 1 0 +BITMAP +C000 +C000 +FE00 +FF00 +C380 +C180 +C180 +C380 +FF00 +FE00 +C000 +C000 +ENDCHAR +STARTCHAR 00DF +ENCODING 223 +SWIDTH 600 0 +DWIDTH 10 0 +BBX 8 12 1 0 +BITMAP +7C +FE +C6 +C6 +CC +CC +CE +C6 +C3 +CB +DF +CE +ENDCHAR +STARTCHAR 00E0 +ENCODING 224 +SWIDTH 540 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +30 +18 +00 +7C +FE +C6 +1E +7E +E6 +C6 +FE +7B +ENDCHAR +STARTCHAR 00E1 +ENCODING 225 +SWIDTH 540 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +0C +18 +00 +7C +FE +C6 +1E +7E +E6 +C6 +FE +7B +ENDCHAR +STARTCHAR 00E2 +ENCODING 226 +SWIDTH 540 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +38 +6C +00 +7C +FE +C6 +1E +7E +E6 +C6 +FE +7B +ENDCHAR +STARTCHAR 00E3 +ENCODING 227 +SWIDTH 540 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +72 +4E +00 +7C +FE +C6 +1E +7E +E6 +C6 +FE +7B +ENDCHAR +STARTCHAR 00E4 +ENCODING 228 +SWIDTH 540 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +66 +66 +00 +7C +FE +C6 +1E +7E +E6 +C6 +FE +7B +ENDCHAR +STARTCHAR 00E5 +ENCODING 229 +SWIDTH 540 0 +DWIDTH 9 0 +BBX 8 14 1 0 +BITMAP +18 +24 +24 +18 +00 +7C +FE +C6 +1E +7E +E6 +C6 +FE +7B +ENDCHAR +STARTCHAR 00E6 +ENCODING 230 +SWIDTH 900 0 +DWIDTH 15 0 +BBX 13 9 1 0 +BITMAP +3DE0 +7FF0 +C618 +1FF8 +7FF8 +E600 +C718 +FFF0 +79E0 +ENDCHAR +STARTCHAR 00E7 +ENCODING 231 +SWIDTH 540 0 +DWIDTH 9 0 +BBX 7 12 1 -3 +BITMAP +3C +7E +E6 +C0 +C0 +C0 +E6 +7E +3C +38 +18 +70 +ENDCHAR +STARTCHAR 00E8 +ENCODING 232 +SWIDTH 540 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +30 +18 +00 +38 +7C +C6 +FE +FE +C0 +E6 +7C +38 +ENDCHAR +STARTCHAR 00E9 +ENCODING 233 +SWIDTH 540 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +18 +30 +00 +38 +7C +C6 +FE +FE +C0 +E6 +7C +38 +ENDCHAR +STARTCHAR 00EA +ENCODING 234 +SWIDTH 540 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +38 +6C +00 +38 +7C +C6 +FE +FE +C0 +E6 +7C +38 +ENDCHAR +STARTCHAR 00EB +ENCODING 235 +SWIDTH 540 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +66 +66 +00 +38 +7C +C6 +FE +FE +C0 +E6 +7C +38 +ENDCHAR +STARTCHAR 00EC +ENCODING 236 +SWIDTH 240 0 +DWIDTH 4 0 +BBX 3 12 0 0 +BITMAP +C0 +60 +00 +60 +60 +60 +60 +60 +60 +60 +60 +60 +ENDCHAR +STARTCHAR 00ED +ENCODING 237 +SWIDTH 240 0 +DWIDTH 4 0 +BBX 3 12 1 0 +BITMAP +60 +C0 +00 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 00EE +ENCODING 238 +SWIDTH 240 0 +DWIDTH 4 0 +BBX 5 12 0 0 +BITMAP +70 +D8 +00 +60 +60 +60 +60 +60 +60 +60 +60 +60 +ENDCHAR +STARTCHAR 00EF +ENCODING 239 +SWIDTH 240 0 +DWIDTH 4 0 +BBX 6 12 -1 0 +BITMAP +CC +CC +00 +30 +30 +30 +30 +30 +30 +30 +30 +30 +ENDCHAR +STARTCHAR 00F0 +ENCODING 240 +SWIDTH 600 0 +DWIDTH 10 0 +BBX 8 12 1 0 +BITMAP +1A +0C +16 +3A +7F +E7 +C3 +C3 +C3 +E7 +7E +3C +ENDCHAR +STARTCHAR 00F1 +ENCODING 241 +SWIDTH 600 0 +DWIDTH 10 0 +BBX 8 12 1 0 +BITMAP +72 +4E +00 +DE +FF +E3 +C3 +C3 +C3 +C3 +C3 +C3 +ENDCHAR +STARTCHAR 00F2 +ENCODING 242 +SWIDTH 600 0 +DWIDTH 10 0 +BBX 8 12 1 0 +BITMAP +18 +0C +00 +3C +7E +E7 +C3 +C3 +C3 +E7 +7E +3C +ENDCHAR +STARTCHAR 00F3 +ENCODING 243 +SWIDTH 600 0 +DWIDTH 10 0 +BBX 8 12 1 0 +BITMAP +0C +18 +00 +3C +7E +E7 +C3 +C3 +C3 +E7 +7E +3C +ENDCHAR +STARTCHAR 00F4 +ENCODING 244 +SWIDTH 600 0 +DWIDTH 10 0 +BBX 8 12 1 0 +BITMAP +1C +36 +00 +3C +7E +E7 +C3 +C3 +C3 +E7 +7E +3C +ENDCHAR +STARTCHAR 00F5 +ENCODING 245 +SWIDTH 600 0 +DWIDTH 10 0 +BBX 8 12 1 0 +BITMAP +72 +4E +00 +3C +7E +E7 +C3 +C3 +C3 +E7 +7E +3C +ENDCHAR +STARTCHAR 00F6 +ENCODING 246 +SWIDTH 600 0 +DWIDTH 10 0 +BBX 8 12 1 0 +BITMAP +66 +66 +00 +3C +7E +E7 +C3 +C3 +C3 +E7 +7E +3C +ENDCHAR +STARTCHAR 00F7 +ENCODING 247 +SWIDTH 540 0 +DWIDTH 9 0 +BBX 8 8 0 2 +BITMAP +18 +18 +00 +FF +FF +00 +18 +18 +ENDCHAR +STARTCHAR 00F8 +ENCODING 248 +SWIDTH 600 0 +DWIDTH 10 0 +BBX 8 10 1 0 +BITMAP +02 +3B +7E +EF +CB +DB +F3 +E7 +7E +DC +ENDCHAR +STARTCHAR 00F9 +ENCODING 249 +SWIDTH 600 0 +DWIDTH 10 0 +BBX 8 12 1 0 +BITMAP +30 +18 +00 +C3 +C3 +C3 +C3 +C3 +C3 +C7 +FF +7B +ENDCHAR +STARTCHAR 00FA +ENCODING 250 +SWIDTH 600 0 +DWIDTH 10 0 +BBX 8 12 1 0 +BITMAP +0C +18 +00 +C3 +C3 +C3 +C3 +C3 +C3 +C7 +FF +7B +ENDCHAR +STARTCHAR 00FB +ENCODING 251 +SWIDTH 600 0 +DWIDTH 10 0 +BBX 8 12 1 0 +BITMAP +1C +36 +00 +C3 +C3 +C3 +C3 +C3 +C3 +C7 +FF +7B +ENDCHAR +STARTCHAR 00FC +ENCODING 252 +SWIDTH 600 0 +DWIDTH 10 0 +BBX 8 12 1 0 +BITMAP +66 +66 +00 +C3 +C3 +C3 +C3 +C3 +C3 +C7 +FF +7B +ENDCHAR +STARTCHAR 00FD +ENCODING 253 +SWIDTH 540 0 +DWIDTH 9 0 +BBX 9 15 0 -3 +BITMAP +0600 +0C00 +0000 +C180 +C180 +6300 +6300 +3600 +3600 +3E00 +1C00 +1C00 +1800 +7800 +7000 +ENDCHAR +STARTCHAR 00FE +ENCODING 254 +SWIDTH 600 0 +DWIDTH 10 0 +BBX 8 15 1 -3 +BITMAP +C0 +C0 +C0 +DC +FE +E7 +C3 +C3 +C3 +E7 +FE +DC +C0 +C0 +C0 +ENDCHAR +STARTCHAR 00FF +ENCODING 255 +SWIDTH 540 0 +DWIDTH 9 0 +BBX 9 15 0 -3 +BITMAP +3300 +3300 +0000 +C180 +C180 +6300 +6300 +3600 +3600 +3E00 +1C00 +1C00 +1800 +7800 +7000 +ENDCHAR +STARTCHAR 0100 +ENCODING 256 +SWIDTH 660 0 +DWIDTH 11 0 +BBX 11 15 0 0 +BITMAP +1F80 +1F80 +0000 +0E00 +0E00 +1B00 +1B00 +1B00 +3180 +3180 +3F80 +7FC0 +60C0 +60C0 +C060 +ENDCHAR +STARTCHAR 0101 +ENCODING 257 +SWIDTH 540 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +7E +7E +00 +7C +FE +C6 +1E +7E +E6 +C6 +FE +7B +ENDCHAR +STARTCHAR 0102 +ENCODING 258 +SWIDTH 660 0 +DWIDTH 11 0 +BBX 11 15 0 0 +BITMAP +1100 +0E00 +0000 +0E00 +0E00 +1B00 +1B00 +1B00 +3180 +3180 +3F80 +7FC0 +60C0 +60C0 +C060 +ENDCHAR +STARTCHAR 0103 +ENCODING 259 +SWIDTH 540 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +44 +38 +00 +7C +FE +C6 +1E +7E +E6 +C6 +FE +7B +ENDCHAR +STARTCHAR 0104 +ENCODING 260 +SWIDTH 660 0 +DWIDTH 11 0 +BBX 11 15 0 -3 +BITMAP +0E00 +0E00 +1B00 +1B00 +1B00 +3180 +3180 +3F80 +7FC0 +60C0 +60C0 +C060 +0040 +00C0 +00E0 +ENDCHAR +STARTCHAR 0105 +ENCODING 261 +SWIDTH 540 0 +DWIDTH 9 0 +BBX 8 12 1 -3 +BITMAP +7C +FE +C6 +1E +7E +E6 +C6 +FE +7B +02 +06 +07 +ENDCHAR +STARTCHAR 0106 +ENCODING 262 +SWIDTH 720 0 +DWIDTH 12 0 +BBX 10 15 1 0 +BITMAP +0600 +0C00 +0000 +1F00 +7F80 +61C0 +E080 +C000 +C000 +C000 +C000 +E080 +61C0 +7F80 +1F00 +ENDCHAR +STARTCHAR 0107 +ENCODING 263 +SWIDTH 540 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +0C +18 +00 +3C +7E +E6 +C0 +C0 +C0 +E6 +7E +3C +ENDCHAR +STARTCHAR 0108 +ENCODING 264 +SWIDTH 720 0 +DWIDTH 12 0 +BBX 10 15 1 0 +BITMAP +0E00 +1B00 +0000 +1F00 +7F80 +61C0 +E080 +C000 +C000 +C000 +C000 +E080 +61C0 +7F80 +1F00 +ENDCHAR +STARTCHAR 0109 +ENCODING 265 +SWIDTH 540 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +38 +6C +00 +3C +7E +E6 +C0 +C0 +C0 +E6 +7E +3C +ENDCHAR +STARTCHAR 010A +ENCODING 266 +SWIDTH 720 0 +DWIDTH 12 0 +BBX 10 15 1 0 +BITMAP +0C00 +0C00 +0000 +1F00 +7F80 +61C0 +E080 +C000 +C000 +C000 +C000 +E080 +61C0 +7F80 +1F00 +ENDCHAR +STARTCHAR 010B +ENCODING 267 +SWIDTH 540 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +18 +18 +00 +3C +7E +E6 +C0 +C0 +C0 +E6 +7E +3C +ENDCHAR +STARTCHAR 010C +ENCODING 268 +SWIDTH 720 0 +DWIDTH 12 0 +BBX 10 15 1 0 +BITMAP +1B00 +0E00 +0000 +1F00 +7F80 +61C0 +E080 +C000 +C000 +C000 +C000 +E080 +61C0 +7F80 +1F00 +ENDCHAR +STARTCHAR 010D +ENCODING 269 +SWIDTH 540 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +6C +38 +00 +3C +7E +E6 +C0 +C0 +C0 +E6 +7E +3C +ENDCHAR +STARTCHAR 010E +ENCODING 270 +SWIDTH 720 0 +DWIDTH 12 0 +BBX 10 15 1 0 +BITMAP +3600 +1C00 +0000 +FE00 +FF80 +C180 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +C180 +FF80 +FE00 +ENDCHAR +STARTCHAR 010F +ENCODING 271 +SWIDTH 720 0 +DWIDTH 12 0 +BBX 11 12 1 0 +BITMAP +0360 +0360 +0320 +3B40 +7F00 +E700 +C300 +C300 +C300 +E700 +7F00 +3B00 +ENDCHAR +STARTCHAR 0110 +ENCODING 272 +SWIDTH 720 0 +DWIDTH 12 0 +BBX 11 12 0 0 +BITMAP +7F00 +7FC0 +60C0 +6060 +6060 +FC60 +6060 +6060 +6060 +60C0 +7FC0 +7F00 +ENDCHAR +STARTCHAR 0111 +ENCODING 273 +SWIDTH 600 0 +DWIDTH 10 0 +BBX 9 12 1 0 +BITMAP +0300 +1F80 +0300 +3B00 +7F00 +E700 +C300 +C300 +C300 +E700 +7F00 +3B00 +ENDCHAR +STARTCHAR 0112 +ENCODING 274 +SWIDTH 660 0 +DWIDTH 11 0 +BBX 9 15 1 0 +BITMAP +3F00 +3F00 +0000 +FF80 +FF80 +C000 +C000 +C000 +FF80 +FF80 +C000 +C000 +C000 +FF80 +FF80 +ENDCHAR +STARTCHAR 0113 +ENCODING 275 +SWIDTH 540 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +7E +7E +00 +38 +7C +C6 +FE +FE +C0 +E6 +7C +38 +ENDCHAR +STARTCHAR 0114 +ENCODING 276 +SWIDTH 660 0 +DWIDTH 11 0 +BBX 9 15 1 0 +BITMAP +2200 +1C00 +0000 +FF80 +FF80 +C000 +C000 +C000 +FF80 +FF80 +C000 +C000 +C000 +FF80 +FF80 +ENDCHAR +STARTCHAR 0115 +ENCODING 277 +SWIDTH 540 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +44 +38 +00 +38 +7C +C6 +FE +FE +C0 +E6 +7C +38 +ENDCHAR +STARTCHAR 0116 +ENCODING 278 +SWIDTH 660 0 +DWIDTH 11 0 +BBX 9 15 1 0 +BITMAP +0C00 +0C00 +0000 +FF80 +FF80 +C000 +C000 +C000 +FF80 +FF80 +C000 +C000 +C000 +FF80 +FF80 +ENDCHAR +STARTCHAR 0117 +ENCODING 279 +SWIDTH 540 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +18 +18 +00 +38 +7C +C6 +FE +FE +C0 +E6 +7C +38 +ENDCHAR +STARTCHAR 0118 +ENCODING 280 +SWIDTH 660 0 +DWIDTH 11 0 +BBX 9 15 1 -3 +BITMAP +FF80 +FF80 +C000 +C000 +C000 +FF80 +FF80 +C000 +C000 +C000 +FF80 +FF80 +0100 +0300 +0380 +ENDCHAR +STARTCHAR 0119 +ENCODING 281 +SWIDTH 540 0 +DWIDTH 9 0 +BBX 7 12 1 -3 +BITMAP +38 +7C +C6 +FE +FE +C0 +E6 +7C +38 +08 +18 +1C +ENDCHAR +STARTCHAR 011A +ENCODING 282 +SWIDTH 660 0 +DWIDTH 11 0 +BBX 9 15 1 0 +BITMAP +3600 +1C00 +0000 +FF80 +FF80 +C000 +C000 +C000 +FF80 +FF80 +C000 +C000 +C000 +FF80 +FF80 +ENDCHAR +STARTCHAR 011B +ENCODING 283 +SWIDTH 540 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +6C +38 +00 +38 +7C +C6 +FE +FE +C0 +E6 +7C +38 +ENDCHAR +STARTCHAR 011C +ENCODING 284 +SWIDTH 780 0 +DWIDTH 13 0 +BBX 11 15 1 0 +BITMAP +0E00 +1B00 +0000 +1F80 +7FC0 +60E0 +E040 +C000 +C000 +C3E0 +C3E0 +E060 +60E0 +7FE0 +1F80 +ENDCHAR +STARTCHAR 011D +ENCODING 285 +SWIDTH 600 0 +DWIDTH 10 0 +BBX 8 15 1 -3 +BITMAP +1C +36 +00 +3B +7F +E7 +C3 +C3 +C3 +E7 +7F +3B +C3 +FF +7E +ENDCHAR +STARTCHAR 011E +ENCODING 286 +SWIDTH 780 0 +DWIDTH 13 0 +BBX 11 15 1 0 +BITMAP +1100 +0E00 +0000 +1F80 +7FC0 +60E0 +E040 +C000 +C000 +C3E0 +C3E0 +E060 +60E0 +7FE0 +1F80 +ENDCHAR +STARTCHAR 011F +ENCODING 287 +SWIDTH 600 0 +DWIDTH 10 0 +BBX 8 15 1 -3 +BITMAP +22 +1C +00 +3B +7F +E7 +C3 +C3 +C3 +E7 +7F +3B +C3 +FF +7E +ENDCHAR +STARTCHAR 0120 +ENCODING 288 +SWIDTH 780 0 +DWIDTH 13 0 +BBX 11 15 1 0 +BITMAP +0600 +0600 +0000 +1F80 +7FC0 +60E0 +E040 +C000 +C000 +C3E0 +C3E0 +E060 +60E0 +7FE0 +1F80 +ENDCHAR +STARTCHAR 0121 +ENCODING 289 +SWIDTH 600 0 +DWIDTH 10 0 +BBX 8 15 1 -3 +BITMAP +18 +18 +00 +3B +7F +E7 +C3 +C3 +C3 +E7 +7F +3B +C3 +FF +7E +ENDCHAR +STARTCHAR 0122 +ENCODING 290 +SWIDTH 780 0 +DWIDTH 13 0 +BBX 11 17 1 -5 +BITMAP +1F80 +7FC0 +60E0 +E040 +C000 +C000 +C3E0 +C3E0 +E060 +60E0 +7FE0 +1F80 +0000 +0600 +0600 +0200 +0400 +ENDCHAR +STARTCHAR 0123 +ENCODING 291 +SWIDTH 600 0 +DWIDTH 10 0 +BBX 8 17 1 -3 +BITMAP +08 +10 +18 +18 +00 +3B +7F +E7 +C3 +C3 +C3 +E7 +7F +3B +C3 +FF +7C +ENDCHAR +STARTCHAR 0124 +ENCODING 292 +SWIDTH 720 0 +DWIDTH 12 0 +BBX 10 15 1 0 +BITMAP +0E00 +1B00 +0000 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +FFC0 +FFC0 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +ENDCHAR +STARTCHAR 0125 +ENCODING 293 +SWIDTH 600 0 +DWIDTH 10 0 +BBX 8 15 1 0 +BITMAP +1C +36 +00 +C0 +C0 +C0 +DE +FF +E3 +C3 +C3 +C3 +C3 +C3 +C3 +ENDCHAR +STARTCHAR 0126 +ENCODING 294 +SWIDTH 720 0 +DWIDTH 12 0 +BBX 12 12 0 0 +BITMAP +6060 +FFF0 +FFF0 +6060 +6060 +7FE0 +7FE0 +6060 +6060 +6060 +6060 +6060 +ENDCHAR +STARTCHAR 0127 +ENCODING 295 +SWIDTH 600 0 +DWIDTH 10 0 +BBX 9 12 0 0 +BITMAP +6000 +FC00 +6000 +6F00 +7F80 +7180 +6180 +6180 +6180 +6180 +6180 +6180 +ENDCHAR +STARTCHAR 0128 +ENCODING 296 +SWIDTH 240 0 +DWIDTH 4 0 +BBX 6 15 -1 0 +BITMAP +E4 +9C +00 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +ENDCHAR +STARTCHAR 0129 +ENCODING 297 +SWIDTH 240 0 +DWIDTH 4 0 +BBX 6 12 -1 0 +BITMAP +E4 +9C +00 +30 +30 +30 +30 +30 +30 +30 +30 +30 +ENDCHAR +STARTCHAR 012A +ENCODING 298 +SWIDTH 240 0 +DWIDTH 4 0 +BBX 6 15 -1 0 +BITMAP +FC +FC +00 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +ENDCHAR +STARTCHAR 012B +ENCODING 299 +SWIDTH 240 0 +DWIDTH 4 0 +BBX 6 12 -1 0 +BITMAP +FC +FC +00 +30 +30 +30 +30 +30 +30 +30 +30 +30 +ENDCHAR +STARTCHAR 012C +ENCODING 300 +SWIDTH 240 0 +DWIDTH 4 0 +BBX 5 15 0 0 +BITMAP +88 +70 +00 +60 +60 +60 +60 +60 +60 +60 +60 +60 +60 +60 +60 +ENDCHAR +STARTCHAR 012D +ENCODING 301 +SWIDTH 240 0 +DWIDTH 4 0 +BBX 5 12 0 0 +BITMAP +88 +70 +00 +60 +60 +60 +60 +60 +60 +60 +60 +60 +ENDCHAR +STARTCHAR 012E +ENCODING 302 +SWIDTH 240 0 +DWIDTH 4 0 +BBX 3 15 0 -3 +BITMAP +60 +60 +60 +60 +60 +60 +60 +60 +60 +60 +60 +60 +40 +C0 +E0 +ENDCHAR +STARTCHAR 012F +ENCODING 303 +SWIDTH 240 0 +DWIDTH 4 0 +BBX 3 15 0 -3 +BITMAP +60 +60 +00 +60 +60 +60 +60 +60 +60 +60 +60 +60 +40 +C0 +E0 +ENDCHAR +STARTCHAR 0130 +ENCODING 304 +SWIDTH 240 0 +DWIDTH 4 0 +BBX 2 15 1 0 +BITMAP +C0 +C0 +00 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 0131 +ENCODING 305 +SWIDTH 240 0 +DWIDTH 4 0 +BBX 2 9 1 0 +BITMAP +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 0132 +ENCODING 306 +SWIDTH 780 0 +DWIDTH 13 0 +BBX 11 12 1 0 +BITMAP +C060 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +D860 +DCE0 +CFC0 +C780 +ENDCHAR +STARTCHAR 0133 +ENCODING 307 +SWIDTH 540 0 +DWIDTH 9 0 +BBX 7 15 1 -3 +BITMAP +C6 +C6 +00 +C6 +C6 +C6 +C6 +C6 +C6 +C6 +C6 +C6 +06 +1E +1C +ENDCHAR +STARTCHAR 0134 +ENCODING 308 +SWIDTH 540 0 +DWIDTH 9 0 +BBX 9 15 0 0 +BITMAP +0700 +0D80 +0000 +0300 +0300 +0300 +0300 +0300 +0300 +0300 +0300 +C300 +E700 +7E00 +3C00 +ENDCHAR +STARTCHAR 0135 +ENCODING 309 +SWIDTH 240 0 +DWIDTH 4 0 +BBX 6 15 -1 -3 +BITMAP +38 +6C +00 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +F0 +E0 +ENDCHAR +STARTCHAR 0136 +ENCODING 310 +SWIDTH 720 0 +DWIDTH 12 0 +BBX 10 17 1 -5 +BITMAP +C0C0 +C180 +C300 +C600 +CC00 +DE00 +F700 +E300 +C380 +C180 +C0C0 +C0C0 +0000 +0C00 +0C00 +0400 +0800 +ENDCHAR +STARTCHAR 0137 +ENCODING 311 +SWIDTH 540 0 +DWIDTH 9 0 +BBX 7 17 1 -5 +BITMAP +C0 +C0 +C0 +C6 +CC +D8 +F8 +FC +EC +CC +C6 +C6 +00 +18 +18 +08 +10 +ENDCHAR +STARTCHAR 0138 +ENCODING 312 +SWIDTH 540 0 +DWIDTH 9 0 +BBX 8 9 1 0 +BITMAP +C7 +CE +DC +F8 +F8 +EC +CE +C6 +C3 +ENDCHAR +STARTCHAR 0139 +ENCODING 313 +SWIDTH 600 0 +DWIDTH 10 0 +BBX 8 15 1 0 +BITMAP +18 +30 +00 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +FF +FF +ENDCHAR +STARTCHAR 013A +ENCODING 314 +SWIDTH 240 0 +DWIDTH 4 0 +BBX 3 15 1 0 +BITMAP +60 +C0 +00 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 013B +ENCODING 315 +SWIDTH 600 0 +DWIDTH 10 0 +BBX 8 17 1 -5 +BITMAP +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +FF +FF +00 +18 +18 +08 +10 +ENDCHAR +STARTCHAR 013C +ENCODING 316 +SWIDTH 240 0 +DWIDTH 4 0 +BBX 2 17 1 -5 +BITMAP +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +00 +C0 +C0 +40 +80 +ENDCHAR +STARTCHAR 013D +ENCODING 317 +SWIDTH 600 0 +DWIDTH 10 0 +BBX 8 12 1 0 +BITMAP +C3 +C3 +C1 +C1 +C2 +C0 +C0 +C0 +C0 +C0 +FF +FF +ENDCHAR +STARTCHAR 013E +ENCODING 318 +SWIDTH 420 0 +DWIDTH 7 0 +BBX 6 12 1 0 +BITMAP +CC +CC +C4 +C8 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 013F +ENCODING 319 +SWIDTH 600 0 +DWIDTH 10 0 +BBX 8 12 1 0 +BITMAP +C0 +C0 +C0 +C0 +C6 +C6 +C0 +C0 +C0 +C0 +FF +FF +ENDCHAR +STARTCHAR 0140 +ENCODING 320 +SWIDTH 420 0 +DWIDTH 7 0 +BBX 5 12 1 0 +BITMAP +C0 +C0 +C0 +C0 +C0 +D8 +D8 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 0141 +ENCODING 321 +SWIDTH 600 0 +DWIDTH 10 0 +BBX 9 12 0 0 +BITMAP +6000 +6000 +6400 +6800 +7000 +6000 +6000 +E000 +6000 +6000 +7F80 +7F80 +ENDCHAR +STARTCHAR 0142 +ENCODING 322 +SWIDTH 240 0 +DWIDTH 4 0 +BBX 4 12 0 0 +BITMAP +60 +60 +60 +60 +70 +60 +60 +E0 +60 +60 +60 +60 +ENDCHAR +STARTCHAR 0143 +ENCODING 323 +SWIDTH 720 0 +DWIDTH 12 0 +BBX 10 15 1 0 +BITMAP +0600 +0C00 +0000 +C0C0 +E0C0 +F0C0 +F0C0 +D8C0 +CCC0 +CCC0 +C6C0 +C3C0 +C3C0 +C1C0 +C0C0 +ENDCHAR +STARTCHAR 0144 +ENCODING 324 +SWIDTH 600 0 +DWIDTH 10 0 +BBX 8 12 1 0 +BITMAP +0C +18 +00 +DE +FF +E3 +C3 +C3 +C3 +C3 +C3 +C3 +ENDCHAR +STARTCHAR 0145 +ENCODING 325 +SWIDTH 720 0 +DWIDTH 12 0 +BBX 10 17 1 -5 +BITMAP +C0C0 +E0C0 +F0C0 +F0C0 +D8C0 +CCC0 +CCC0 +C6C0 +C3C0 +C3C0 +C1C0 +C0C0 +0000 +0C00 +0C00 +0400 +0800 +ENDCHAR +STARTCHAR 0146 +ENCODING 326 +SWIDTH 600 0 +DWIDTH 10 0 +BBX 8 14 1 -5 +BITMAP +DE +FF +E3 +C3 +C3 +C3 +C3 +C3 +C3 +00 +18 +18 +08 +10 +ENDCHAR +STARTCHAR 0147 +ENCODING 327 +SWIDTH 720 0 +DWIDTH 12 0 +BBX 10 15 1 0 +BITMAP +1B00 +0E00 +0000 +C0C0 +E0C0 +F0C0 +F0C0 +D8C0 +CCC0 +CCC0 +C6C0 +C3C0 +C3C0 +C1C0 +C0C0 +ENDCHAR +STARTCHAR 0148 +ENCODING 328 +SWIDTH 600 0 +DWIDTH 10 0 +BBX 8 12 1 0 +BITMAP +36 +1C +00 +DE +FF +E3 +C3 +C3 +C3 +C3 +C3 +C3 +ENDCHAR +STARTCHAR 0149 +ENCODING 329 +SWIDTH 720 0 +DWIDTH 12 0 +BBX 11 12 0 0 +BITMAP +C000 +C000 +4000 +5BC0 +9FE0 +1C60 +1860 +1860 +1860 +1860 +1860 +1860 +ENDCHAR +STARTCHAR 014A +ENCODING 330 +SWIDTH 720 0 +DWIDTH 12 0 +BBX 10 12 1 0 +BITMAP +CF00 +FF80 +E1C0 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +C1C0 +CF80 +CF00 +ENDCHAR +STARTCHAR 014B +ENCODING 331 +SWIDTH 600 0 +DWIDTH 10 0 +BBX 8 13 1 -4 +BITMAP +DE +FF +E3 +C3 +C3 +C3 +C3 +C3 +C3 +03 +03 +0F +0E +ENDCHAR +STARTCHAR 014C +ENCODING 332 +SWIDTH 780 0 +DWIDTH 13 0 +BBX 11 15 1 0 +BITMAP +1F80 +1F80 +0000 +1F00 +7FC0 +60C0 +E060 +C060 +C060 +C060 +C060 +C060 +60C0 +7FC0 +1F00 +ENDCHAR +STARTCHAR 014D +ENCODING 333 +SWIDTH 600 0 +DWIDTH 10 0 +BBX 8 12 1 0 +BITMAP +7E +7E +00 +3C +7E +E7 +C3 +C3 +C3 +E7 +7E +3C +ENDCHAR +STARTCHAR 014E +ENCODING 334 +SWIDTH 780 0 +DWIDTH 13 0 +BBX 11 15 1 0 +BITMAP +1100 +0E00 +0000 +1F00 +7FC0 +60C0 +E060 +C060 +C060 +C060 +C060 +C060 +60C0 +7FC0 +1F00 +ENDCHAR +STARTCHAR 014F +ENCODING 335 +SWIDTH 600 0 +DWIDTH 10 0 +BBX 8 12 1 0 +BITMAP +22 +1C +00 +3C +7E +E7 +C3 +C3 +C3 +E7 +7E +3C +ENDCHAR +STARTCHAR 0150 +ENCODING 336 +SWIDTH 780 0 +DWIDTH 13 0 +BBX 11 15 1 0 +BITMAP +0D80 +1B00 +0000 +1F00 +7FC0 +60C0 +E060 +C060 +C060 +C060 +C060 +C060 +60C0 +7FC0 +1F00 +ENDCHAR +STARTCHAR 0151 +ENCODING 337 +SWIDTH 600 0 +DWIDTH 10 0 +BBX 8 12 1 0 +BITMAP +36 +6C +00 +3C +7E +E7 +C3 +C3 +C3 +E7 +7E +3C +ENDCHAR +STARTCHAR 0152 +ENCODING 338 +SWIDTH 1020 0 +DWIDTH 17 0 +BBX 16 12 0 0 +BITMAP +3DFF +7FFF +E380 +C180 +C180 +C1FF +C1FF +C180 +C180 +E380 +7FFF +3DFF +ENDCHAR +STARTCHAR 0153 +ENCODING 339 +SWIDTH 900 0 +DWIDTH 15 0 +BBX 13 9 1 0 +BITMAP +3CE0 +7FF0 +E718 +C3F8 +C3F8 +C300 +E798 +7FF0 +3CE0 +ENDCHAR +STARTCHAR 0154 +ENCODING 340 +SWIDTH 720 0 +DWIDTH 12 0 +BBX 11 15 1 0 +BITMAP +0600 +0C00 +0000 +FF00 +FF80 +C1C0 +C0C0 +C1C0 +FF80 +FE00 +C700 +C380 +C180 +C1C0 +C0E0 +ENDCHAR +STARTCHAR 0155 +ENCODING 341 +SWIDTH 420 0 +DWIDTH 7 0 +BBX 6 12 1 0 +BITMAP +18 +30 +00 +DC +FC +E0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 0156 +ENCODING 342 +SWIDTH 720 0 +DWIDTH 12 0 +BBX 11 17 1 -5 +BITMAP +FF00 +FF80 +C1C0 +C0C0 +C1C0 +FF80 +FE00 +C700 +C380 +C180 +C1C0 +C0E0 +0000 +0C00 +0C00 +0400 +0800 +ENDCHAR +STARTCHAR 0157 +ENCODING 343 +SWIDTH 420 0 +DWIDTH 7 0 +BBX 6 14 1 -5 +BITMAP +DC +FC +E0 +C0 +C0 +C0 +C0 +C0 +C0 +00 +C0 +C0 +40 +80 +ENDCHAR +STARTCHAR 0158 +ENCODING 344 +SWIDTH 720 0 +DWIDTH 12 0 +BBX 11 15 1 0 +BITMAP +3600 +1C00 +0000 +FF00 +FF80 +C1C0 +C0C0 +C1C0 +FF80 +FE00 +C700 +C380 +C180 +C1C0 +C0E0 +ENDCHAR +STARTCHAR 0159 +ENCODING 345 +SWIDTH 420 0 +DWIDTH 7 0 +BBX 6 12 1 0 +BITMAP +D8 +70 +00 +DC +FC +E0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 015A +ENCODING 346 +SWIDTH 660 0 +DWIDTH 11 0 +BBX 9 15 1 0 +BITMAP +0C00 +1800 +0000 +3E00 +7F00 +E380 +C180 +F000 +7E00 +1F00 +0380 +C180 +E380 +7F00 +3E00 +ENDCHAR +STARTCHAR 015B +ENCODING 347 +SWIDTH 540 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +18 +30 +00 +7C +FE +C6 +F0 +7C +0E +C6 +FE +7C +ENDCHAR +STARTCHAR 015C +ENCODING 348 +SWIDTH 660 0 +DWIDTH 11 0 +BBX 9 15 1 0 +BITMAP +1C00 +3600 +0000 +3E00 +7F00 +E380 +C180 +F000 +7E00 +1F00 +0380 +C180 +E380 +7F00 +3E00 +ENDCHAR +STARTCHAR 015D +ENCODING 349 +SWIDTH 540 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +38 +6C +00 +7C +FE +C6 +F0 +7C +0E +C6 +FE +7C +ENDCHAR +STARTCHAR 015E +ENCODING 350 +SWIDTH 660 0 +DWIDTH 11 0 +BBX 9 15 1 -3 +BITMAP +3E00 +7F00 +E380 +C180 +F000 +7E00 +1F00 +0380 +C180 +E380 +7F00 +3E00 +1C00 +0C00 +3800 +ENDCHAR +STARTCHAR 015F +ENCODING 351 +SWIDTH 540 0 +DWIDTH 9 0 +BBX 7 12 1 -3 +BITMAP +7C +FE +C6 +F0 +7C +0E +C6 +FE +7C +38 +18 +70 +ENDCHAR +STARTCHAR 0160 +ENCODING 352 +SWIDTH 660 0 +DWIDTH 11 0 +BBX 9 15 1 0 +BITMAP +3600 +1C00 +0000 +3E00 +7F00 +E380 +C180 +F000 +7E00 +1F00 +0380 +C180 +E380 +7F00 +3E00 +ENDCHAR +STARTCHAR 0161 +ENCODING 353 +SWIDTH 540 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +6C +38 +00 +7C +FE +C6 +F0 +7C +0E +C6 +FE +7C +ENDCHAR +STARTCHAR 0162 +ENCODING 354 +SWIDTH 600 0 +DWIDTH 10 0 +BBX 10 15 0 -3 +BITMAP +FFC0 +FFC0 +0C00 +0C00 +0C00 +0C00 +0C00 +0C00 +0C00 +0C00 +0C00 +0C00 +0E00 +0600 +1C00 +ENDCHAR +STARTCHAR 0163 +ENCODING 355 +SWIDTH 360 0 +DWIDTH 6 0 +BBX 5 15 0 -3 +BITMAP +20 +60 +60 +F8 +F8 +60 +60 +60 +60 +60 +78 +38 +38 +18 +70 +ENDCHAR +STARTCHAR 0164 +ENCODING 356 +SWIDTH 600 0 +DWIDTH 10 0 +BBX 10 15 0 0 +BITMAP +1B00 +0E00 +0000 +FFC0 +FFC0 +0C00 +0C00 +0C00 +0C00 +0C00 +0C00 +0C00 +0C00 +0C00 +0C00 +ENDCHAR +STARTCHAR 0165 +ENCODING 357 +SWIDTH 480 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +23 +63 +61 +FA +F8 +60 +60 +60 +60 +60 +78 +38 +ENDCHAR +STARTCHAR 0166 +ENCODING 358 +SWIDTH 600 0 +DWIDTH 10 0 +BBX 10 12 0 0 +BITMAP +FFC0 +FFC0 +0C00 +0C00 +0C00 +7F80 +7F80 +0C00 +0C00 +0C00 +0C00 +0C00 +ENDCHAR +STARTCHAR 0167 +ENCODING 359 +SWIDTH 360 0 +DWIDTH 6 0 +BBX 5 12 0 0 +BITMAP +20 +60 +60 +F8 +F8 +60 +F8 +F8 +60 +60 +78 +38 +ENDCHAR +STARTCHAR 0168 +ENCODING 360 +SWIDTH 720 0 +DWIDTH 12 0 +BBX 10 15 1 0 +BITMAP +3900 +2700 +0000 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +E1C0 +7F80 +3F00 +ENDCHAR +STARTCHAR 0169 +ENCODING 361 +SWIDTH 600 0 +DWIDTH 10 0 +BBX 8 12 1 0 +BITMAP +72 +4E +00 +C3 +C3 +C3 +C3 +C3 +C3 +C7 +FF +7B +ENDCHAR +STARTCHAR 016A +ENCODING 362 +SWIDTH 720 0 +DWIDTH 12 0 +BBX 10 15 1 0 +BITMAP +3F00 +3F00 +0000 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +E1C0 +7F80 +3F00 +ENDCHAR +STARTCHAR 016B +ENCODING 363 +SWIDTH 600 0 +DWIDTH 10 0 +BBX 8 12 1 0 +BITMAP +7E +7E +00 +C3 +C3 +C3 +C3 +C3 +C3 +C7 +FF +7B +ENDCHAR +STARTCHAR 016C +ENCODING 364 +SWIDTH 720 0 +DWIDTH 12 0 +BBX 10 15 1 0 +BITMAP +1100 +0E00 +0000 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +E1C0 +7F80 +3F00 +ENDCHAR +STARTCHAR 016D +ENCODING 365 +SWIDTH 600 0 +DWIDTH 10 0 +BBX 8 12 1 0 +BITMAP +22 +1C +00 +C3 +C3 +C3 +C3 +C3 +C3 +C7 +FF +7B +ENDCHAR +STARTCHAR 016E +ENCODING 366 +SWIDTH 720 0 +DWIDTH 12 0 +BBX 10 15 1 0 +BITMAP +0C00 +1200 +1200 +CCC0 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +E1C0 +7F80 +3F00 +ENDCHAR +STARTCHAR 016F +ENCODING 367 +SWIDTH 600 0 +DWIDTH 10 0 +BBX 8 14 1 0 +BITMAP +18 +24 +24 +18 +00 +C3 +C3 +C3 +C3 +C3 +C3 +C7 +FF +7B +ENDCHAR +STARTCHAR 0170 +ENCODING 368 +SWIDTH 720 0 +DWIDTH 12 0 +BBX 10 15 1 0 +BITMAP +1B00 +3600 +0000 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +E1C0 +7F80 +3F00 +ENDCHAR +STARTCHAR 0171 +ENCODING 369 +SWIDTH 600 0 +DWIDTH 10 0 +BBX 8 12 1 0 +BITMAP +36 +6C +00 +C3 +C3 +C3 +C3 +C3 +C3 +C7 +FF +7B +ENDCHAR +STARTCHAR 0172 +ENCODING 370 +SWIDTH 720 0 +DWIDTH 12 0 +BBX 10 15 1 -3 +BITMAP +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +E1C0 +7F80 +3F00 +0400 +0C00 +0E00 +ENDCHAR +STARTCHAR 0173 +ENCODING 371 +SWIDTH 600 0 +DWIDTH 10 0 +BBX 8 12 1 -3 +BITMAP +C3 +C3 +C3 +C3 +C3 +C3 +C7 +FF +7B +02 +06 +07 +ENDCHAR +STARTCHAR 0174 +ENCODING 372 +SWIDTH 1020 0 +DWIDTH 17 0 +BBX 17 15 0 0 +BITMAP +01C000 +036000 +000000 +C1C180 +E1C180 +63E300 +636300 +636300 +377600 +363600 +363600 +1E3E00 +1C1C00 +1C1C00 +1C1C00 +ENDCHAR +STARTCHAR 0175 +ENCODING 373 +SWIDTH 780 0 +DWIDTH 13 0 +BBX 13 12 0 0 +BITMAP +0700 +0D80 +0000 +C718 +C718 +6730 +6DB0 +6DB0 +6DB0 +38E0 +38E0 +38E0 +ENDCHAR +STARTCHAR 0176 +ENCODING 374 +SWIDTH 600 0 +DWIDTH 10 0 +BBX 10 15 0 0 +BITMAP +0E00 +1B00 +0000 +C0C0 +E1C0 +6180 +3300 +3300 +1E00 +0C00 +0C00 +0C00 +0C00 +0C00 +0C00 +ENDCHAR +STARTCHAR 0177 +ENCODING 375 +SWIDTH 540 0 +DWIDTH 9 0 +BBX 9 15 0 -3 +BITMAP +1C00 +3600 +0000 +C180 +C180 +6300 +6300 +3600 +3600 +3E00 +1C00 +1C00 +1800 +7800 +7000 +ENDCHAR +STARTCHAR 0178 +ENCODING 376 +SWIDTH 600 0 +DWIDTH 10 0 +BBX 10 15 0 0 +BITMAP +3300 +3300 +0000 +C0C0 +E1C0 +6180 +3300 +3300 +1E00 +0C00 +0C00 +0C00 +0C00 +0C00 +0C00 +ENDCHAR +STARTCHAR 0179 +ENCODING 377 +SWIDTH 540 0 +DWIDTH 9 0 +BBX 9 15 0 0 +BITMAP +0600 +0C00 +0000 +7F80 +7F80 +0300 +0600 +0E00 +0C00 +1800 +3800 +3000 +6000 +FF80 +FF80 +ENDCHAR +STARTCHAR 017A +ENCODING 378 +SWIDTH 540 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +0C +18 +00 +FE +FE +0C +1C +38 +70 +60 +FE +FE +ENDCHAR +STARTCHAR 017B +ENCODING 379 +SWIDTH 540 0 +DWIDTH 9 0 +BBX 9 15 0 0 +BITMAP +0C00 +0C00 +0000 +7F80 +7F80 +0300 +0600 +0E00 +0C00 +1800 +3800 +3000 +6000 +FF80 +FF80 +ENDCHAR +STARTCHAR 017C +ENCODING 380 +SWIDTH 540 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +18 +18 +00 +FE +FE +0C +1C +38 +70 +60 +FE +FE +ENDCHAR +STARTCHAR 017D +ENCODING 381 +SWIDTH 540 0 +DWIDTH 9 0 +BBX 9 15 0 0 +BITMAP +1B00 +0E00 +0000 +7F80 +7F80 +0300 +0600 +0E00 +0C00 +1800 +3800 +3000 +6000 +FF80 +FF80 +ENDCHAR +STARTCHAR 017E +ENCODING 382 +SWIDTH 540 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +6C +38 +00 +FE +FE +0C +1C +38 +70 +60 +FE +FE +ENDCHAR +ENDFONT diff --git a/oshwa_magtag_display/fonts/ArialMT-9.bdf b/oshwa_magtag_display/fonts/ArialMT-9.bdf new file mode 100644 index 000000000..99fb0676c --- /dev/null +++ b/oshwa_magtag_display/fonts/ArialMT-9.bdf @@ -0,0 +1,2668 @@ +STARTFONT 2.1 +FONT -FontForge-Arial-Book-R-Normal--9-90-75-75-P-46-ISO10646-1 +SIZE 9 75 75 +FONTBOUNDINGBOX 25 18 -7 -5 +COMMENT "Generated by fontforge, http://fontforge.sourceforge.net" +COMMENT "(c) 2017 The Monotype Corporation. All Rights Reserved. " +COMMENT "" +COMMENT "Hebrew OpenType Layout logic copyright (c) 2003 & 2007, Ralph Hancock & John Hudson. This layout logic for Biblical Hebrew is open source software under the MIT License; see embedded license description for details." +STARTPROPERTIES 40 +FOUNDRY "FontForge" +FAMILY_NAME "Arial" +WEIGHT_NAME "Book" +SLANT "R" +SETWIDTH_NAME "Normal" +ADD_STYLE_NAME "" +PIXEL_SIZE 9 +POINT_SIZE 90 +RESOLUTION_X 75 +RESOLUTION_Y 75 +SPACING "P" +AVERAGE_WIDTH 46 +CHARSET_REGISTRY "ISO10646" +CHARSET_ENCODING "1" +FONTNAME_REGISTRY "" +CHARSET_COLLECTIONS "ASCII ISOLatin1Encoding ISO8859-2 ISO8859-5 ISO8859-7 ISO8859-9 ISO8859-8 ISO8859-6 ISO8859-4 ISO10646-1" +FONT_NAME "ArialMT" +FACE_NAME "Arial" +COPYRIGHT "(c) 2017 The Monotype Corporation. All Rights Reserved. " +FONT_VERSION "7.00" +FONT_ASCENT 7 +FONT_DESCENT 2 +UNDERLINE_POSITION -1 +UNDERLINE_THICKNESS 1 +X_HEIGHT 4 +CAP_HEIGHT 6 +RAW_ASCENT 799 +RAW_DESCENT 200 +NORM_SPACE 3 +RELATIVE_WEIGHT 40 +RELATIVE_SETWIDTH 50 +SUPERSCRIPT_X 0 +SUPERSCRIPT_Y 4 +SUPERSCRIPT_SIZE 5 +SUBSCRIPT_X 0 +SUBSCRIPT_Y 1 +SUBSCRIPT_SIZE 5 +FIGURE_WIDTH 5 +AVG_LOWERCASE_WIDTH 49 +AVG_UPPERCASE_WIDTH 65 +ENDPROPERTIES +CHARS 4604 +STARTCHAR space +ENCODING 32 +SWIDTH 277 0 +DWIDTH 3 0 +BBX 1 1 0 0 +BITMAP +00 +ENDCHAR +STARTCHAR exclam +ENCODING 33 +SWIDTH 277 0 +DWIDTH 3 0 +BBX 1 7 1 0 +BITMAP +80 +80 +80 +80 +80 +00 +80 +ENDCHAR +STARTCHAR quotedbl +ENCODING 34 +SWIDTH 354 0 +DWIDTH 3 0 +BBX 3 2 0 5 +BITMAP +A0 +A0 +ENDCHAR +STARTCHAR numbersign +ENCODING 35 +SWIDTH 556 0 +DWIDTH 5 0 +BBX 4 7 0 0 +BITMAP +50 +50 +F0 +50 +F0 +A0 +A0 +ENDCHAR +STARTCHAR dollar +ENCODING 36 +SWIDTH 556 0 +DWIDTH 5 0 +BBX 5 8 0 -1 +BITMAP +70 +A8 +A0 +70 +28 +A8 +70 +20 +ENDCHAR +STARTCHAR percent +ENCODING 37 +SWIDTH 889 0 +DWIDTH 8 0 +BBX 6 7 1 0 +BITMAP +48 +B0 +50 +10 +28 +34 +28 +ENDCHAR +STARTCHAR ampersand +ENCODING 38 +SWIDTH 666 0 +DWIDTH 6 0 +BBX 6 7 0 0 +BITMAP +30 +48 +48 +70 +94 +88 +74 +ENDCHAR +STARTCHAR quotesingle +ENCODING 39 +SWIDTH 190 0 +DWIDTH 2 0 +BBX 1 2 0 5 +BITMAP +80 +80 +ENDCHAR +STARTCHAR parenleft +ENCODING 40 +SWIDTH 333 0 +DWIDTH 3 0 +BBX 3 9 0 -2 +BITMAP +20 +40 +80 +80 +80 +80 +80 +40 +20 +ENDCHAR +STARTCHAR parenright +ENCODING 41 +SWIDTH 333 0 +DWIDTH 3 0 +BBX 3 9 0 -2 +BITMAP +80 +40 +20 +20 +20 +20 +20 +40 +80 +ENDCHAR +STARTCHAR asterisk +ENCODING 42 +SWIDTH 389 0 +DWIDTH 4 0 +BBX 3 3 0 4 +BITMAP +E0 +40 +A0 +ENDCHAR +STARTCHAR plus +ENCODING 43 +SWIDTH 583 0 +DWIDTH 5 0 +BBX 5 5 0 0 +BITMAP +20 +20 +F8 +20 +20 +ENDCHAR +STARTCHAR comma +ENCODING 44 +SWIDTH 277 0 +DWIDTH 3 0 +BBX 1 2 1 -1 +BITMAP +80 +80 +ENDCHAR +STARTCHAR hyphen +ENCODING 45 +SWIDTH 333 0 +DWIDTH 3 0 +BBX 2 1 0 2 +BITMAP +C0 +ENDCHAR +STARTCHAR period +ENCODING 46 +SWIDTH 277 0 +DWIDTH 3 0 +BBX 1 1 1 0 +BITMAP +80 +ENDCHAR +STARTCHAR slash +ENCODING 47 +SWIDTH 277 0 +DWIDTH 3 0 +BBX 3 7 0 0 +BITMAP +20 +20 +40 +40 +40 +80 +80 +ENDCHAR +STARTCHAR zero +ENCODING 48 +SWIDTH 556 0 +DWIDTH 5 0 +BBX 4 7 0 0 +BITMAP +60 +90 +90 +90 +90 +90 +E0 +ENDCHAR +STARTCHAR one +ENCODING 49 +SWIDTH 556 0 +DWIDTH 5 0 +BBX 2 7 1 0 +BITMAP +40 +C0 +40 +40 +40 +40 +40 +ENDCHAR +STARTCHAR two +ENCODING 50 +SWIDTH 556 0 +DWIDTH 5 0 +BBX 4 7 0 0 +BITMAP +60 +90 +10 +20 +20 +40 +F0 +ENDCHAR +STARTCHAR three +ENCODING 51 +SWIDTH 556 0 +DWIDTH 5 0 +BBX 4 7 0 0 +BITMAP +60 +90 +10 +20 +10 +90 +60 +ENDCHAR +STARTCHAR four +ENCODING 52 +SWIDTH 556 0 +DWIDTH 5 0 +BBX 5 7 0 0 +BITMAP +10 +30 +50 +90 +F8 +10 +10 +ENDCHAR +STARTCHAR five +ENCODING 53 +SWIDTH 556 0 +DWIDTH 5 0 +BBX 4 7 0 0 +BITMAP +70 +40 +E0 +90 +10 +90 +60 +ENDCHAR +STARTCHAR six +ENCODING 54 +SWIDTH 556 0 +DWIDTH 5 0 +BBX 4 7 0 0 +BITMAP +60 +90 +E0 +90 +90 +90 +60 +ENDCHAR +STARTCHAR seven +ENCODING 55 +SWIDTH 556 0 +DWIDTH 5 0 +BBX 4 7 0 0 +BITMAP +F0 +10 +20 +20 +40 +40 +40 +ENDCHAR +STARTCHAR eight +ENCODING 56 +SWIDTH 556 0 +DWIDTH 5 0 +BBX 4 7 0 0 +BITMAP +60 +90 +90 +60 +90 +90 +60 +ENDCHAR +STARTCHAR nine +ENCODING 57 +SWIDTH 556 0 +DWIDTH 5 0 +BBX 4 7 0 0 +BITMAP +60 +90 +90 +90 +70 +90 +60 +ENDCHAR +STARTCHAR colon +ENCODING 58 +SWIDTH 277 0 +DWIDTH 3 0 +BBX 1 5 1 0 +BITMAP +80 +00 +00 +00 +80 +ENDCHAR +STARTCHAR semicolon +ENCODING 59 +SWIDTH 277 0 +DWIDTH 3 0 +BBX 1 6 1 -1 +BITMAP +80 +00 +00 +00 +80 +80 +ENDCHAR +STARTCHAR less +ENCODING 60 +SWIDTH 583 0 +DWIDTH 5 0 +BBX 3 5 1 1 +BITMAP +20 +40 +80 +40 +20 +ENDCHAR +STARTCHAR equal +ENCODING 61 +SWIDTH 583 0 +DWIDTH 5 0 +BBX 4 3 0 2 +BITMAP +F0 +00 +F0 +ENDCHAR +STARTCHAR greater +ENCODING 62 +SWIDTH 583 0 +DWIDTH 5 0 +BBX 3 5 1 1 +BITMAP +80 +40 +20 +40 +80 +ENDCHAR +STARTCHAR question +ENCODING 63 +SWIDTH 556 0 +DWIDTH 5 0 +BBX 5 7 0 0 +BITMAP +70 +88 +08 +30 +20 +00 +20 +ENDCHAR +STARTCHAR at +ENCODING 64 +SWIDTH 1015 0 +DWIDTH 9 0 +BBX 8 9 1 -2 +BITMAP +3C +42 +95 +AD +A9 +AA +BC +43 +3C +ENDCHAR +STARTCHAR A +ENCODING 65 +SWIDTH 666 0 +DWIDTH 6 0 +BBX 7 7 0 0 +BITMAP +10 +28 +28 +44 +7C +44 +82 +ENDCHAR +STARTCHAR B +ENCODING 66 +SWIDTH 666 0 +DWIDTH 6 0 +BBX 4 7 1 0 +BITMAP +E0 +90 +90 +F0 +90 +90 +E0 +ENDCHAR +STARTCHAR C +ENCODING 67 +SWIDTH 722 0 +DWIDTH 7 0 +BBX 5 7 1 0 +BITMAP +70 +88 +80 +80 +80 +88 +70 +ENDCHAR +STARTCHAR D +ENCODING 68 +SWIDTH 722 0 +DWIDTH 7 0 +BBX 5 7 1 0 +BITMAP +F0 +88 +88 +88 +88 +88 +F0 +ENDCHAR +STARTCHAR E +ENCODING 69 +SWIDTH 666 0 +DWIDTH 6 0 +BBX 5 7 1 0 +BITMAP +F8 +80 +80 +F8 +80 +80 +F8 +ENDCHAR +STARTCHAR F +ENCODING 70 +SWIDTH 610 0 +DWIDTH 6 0 +BBX 4 7 1 0 +BITMAP +F0 +80 +80 +E0 +80 +80 +80 +ENDCHAR +STARTCHAR G +ENCODING 71 +SWIDTH 777 0 +DWIDTH 7 0 +BBX 5 7 1 0 +BITMAP +70 +88 +80 +98 +88 +88 +70 +ENDCHAR +STARTCHAR H +ENCODING 72 +SWIDTH 722 0 +DWIDTH 7 0 +BBX 5 7 1 0 +BITMAP +88 +88 +88 +F8 +88 +88 +88 +ENDCHAR +STARTCHAR I +ENCODING 73 +SWIDTH 277 0 +DWIDTH 3 0 +BBX 1 7 1 0 +BITMAP +80 +80 +80 +80 +80 +80 +80 +ENDCHAR +STARTCHAR J +ENCODING 74 +SWIDTH 500 0 +DWIDTH 5 0 +BBX 4 7 0 0 +BITMAP +10 +10 +10 +10 +10 +90 +E0 +ENDCHAR +STARTCHAR K +ENCODING 75 +SWIDTH 666 0 +DWIDTH 6 0 +BBX 5 7 1 0 +BITMAP +88 +90 +A0 +C0 +A0 +90 +88 +ENDCHAR +STARTCHAR L +ENCODING 76 +SWIDTH 556 0 +DWIDTH 5 0 +BBX 4 7 1 0 +BITMAP +80 +80 +80 +80 +80 +80 +F0 +ENDCHAR +STARTCHAR M +ENCODING 77 +SWIDTH 833 0 +DWIDTH 7 0 +BBX 7 7 0 0 +BITMAP +82 +C6 +C6 +AA +AA +AA +92 +ENDCHAR +STARTCHAR N +ENCODING 78 +SWIDTH 722 0 +DWIDTH 7 0 +BBX 5 7 1 0 +BITMAP +88 +C8 +C8 +A8 +98 +98 +88 +ENDCHAR +STARTCHAR O +ENCODING 79 +SWIDTH 777 0 +DWIDTH 7 0 +BBX 5 7 1 0 +BITMAP +70 +88 +88 +88 +88 +88 +70 +ENDCHAR +STARTCHAR P +ENCODING 80 +SWIDTH 666 0 +DWIDTH 6 0 +BBX 4 7 1 0 +BITMAP +F0 +90 +90 +F0 +80 +80 +80 +ENDCHAR +STARTCHAR Q +ENCODING 81 +SWIDTH 777 0 +DWIDTH 7 0 +BBX 5 7 1 0 +BITMAP +70 +88 +88 +88 +88 +90 +78 +ENDCHAR +STARTCHAR R +ENCODING 82 +SWIDTH 722 0 +DWIDTH 7 0 +BBX 5 7 1 0 +BITMAP +F0 +88 +88 +F0 +90 +88 +88 +ENDCHAR +STARTCHAR S +ENCODING 83 +SWIDTH 666 0 +DWIDTH 6 0 +BBX 4 7 1 0 +BITMAP +60 +90 +80 +60 +10 +90 +60 +ENDCHAR +STARTCHAR T +ENCODING 84 +SWIDTH 610 0 +DWIDTH 5 0 +BBX 5 7 0 0 +BITMAP +F8 +20 +20 +20 +20 +20 +20 +ENDCHAR +STARTCHAR U +ENCODING 85 +SWIDTH 722 0 +DWIDTH 7 0 +BBX 5 7 1 0 +BITMAP +88 +88 +88 +88 +88 +88 +70 +ENDCHAR +STARTCHAR V +ENCODING 86 +SWIDTH 666 0 +DWIDTH 6 0 +BBX 7 7 0 0 +BITMAP +82 +82 +44 +44 +28 +28 +10 +ENDCHAR +STARTCHAR W +ENCODING 87 +SWIDTH 943 0 +DWIDTH 9 0 +BBX 9 7 0 0 +BITMAP +8880 +9480 +5500 +5500 +5500 +5500 +2200 +ENDCHAR +STARTCHAR X +ENCODING 88 +SWIDTH 666 0 +DWIDTH 5 0 +BBX 5 7 0 0 +BITMAP +88 +50 +50 +20 +50 +50 +88 +ENDCHAR +STARTCHAR Y +ENCODING 89 +SWIDTH 666 0 +DWIDTH 7 0 +BBX 5 7 1 0 +BITMAP +88 +50 +50 +20 +20 +20 +20 +ENDCHAR +STARTCHAR Z +ENCODING 90 +SWIDTH 610 0 +DWIDTH 6 0 +BBX 6 7 0 0 +BITMAP +FC +08 +10 +20 +40 +80 +FC +ENDCHAR +STARTCHAR bracketleft +ENCODING 91 +SWIDTH 277 0 +DWIDTH 3 0 +BBX 2 9 1 -2 +BITMAP +C0 +80 +80 +80 +80 +80 +80 +80 +C0 +ENDCHAR +STARTCHAR backslash +ENCODING 92 +SWIDTH 277 0 +DWIDTH 3 0 +BBX 3 7 0 0 +BITMAP +80 +80 +40 +40 +40 +20 +20 +ENDCHAR +STARTCHAR bracketright +ENCODING 93 +SWIDTH 277 0 +DWIDTH 3 0 +BBX 2 9 0 -2 +BITMAP +C0 +40 +40 +40 +40 +40 +40 +40 +C0 +ENDCHAR +STARTCHAR asciicircum +ENCODING 94 +SWIDTH 469 0 +DWIDTH 3 0 +BBX 3 3 0 4 +BITMAP +40 +A0 +A0 +ENDCHAR +STARTCHAR underscore +ENCODING 95 +SWIDTH 556 0 +DWIDTH 5 0 +BBX 5 1 0 -2 +BITMAP +F8 +ENDCHAR +STARTCHAR grave +ENCODING 96 +SWIDTH 333 0 +DWIDTH 3 0 +BBX 2 2 0 5 +BITMAP +80 +40 +ENDCHAR +STARTCHAR a +ENCODING 97 +SWIDTH 556 0 +DWIDTH 5 0 +BBX 4 5 0 0 +BITMAP +F0 +10 +70 +90 +F0 +ENDCHAR +STARTCHAR b +ENCODING 98 +SWIDTH 556 0 +DWIDTH 5 0 +BBX 4 7 0 0 +BITMAP +80 +80 +E0 +90 +90 +90 +E0 +ENDCHAR +STARTCHAR c +ENCODING 99 +SWIDTH 500 0 +DWIDTH 5 0 +BBX 4 5 0 0 +BITMAP +60 +90 +80 +90 +60 +ENDCHAR +STARTCHAR d +ENCODING 100 +SWIDTH 556 0 +DWIDTH 5 0 +BBX 4 7 0 0 +BITMAP +10 +10 +70 +90 +90 +90 +70 +ENDCHAR +STARTCHAR e +ENCODING 101 +SWIDTH 556 0 +DWIDTH 5 0 +BBX 4 5 0 0 +BITMAP +60 +90 +F0 +80 +70 +ENDCHAR +STARTCHAR f +ENCODING 102 +SWIDTH 277 0 +DWIDTH 4 0 +BBX 3 7 0 0 +BITMAP +20 +40 +E0 +40 +40 +40 +40 +ENDCHAR +STARTCHAR g +ENCODING 103 +SWIDTH 556 0 +DWIDTH 5 0 +BBX 4 7 0 -2 +BITMAP +70 +90 +90 +90 +70 +90 +60 +ENDCHAR +STARTCHAR h +ENCODING 104 +SWIDTH 556 0 +DWIDTH 5 0 +BBX 4 7 0 0 +BITMAP +80 +80 +E0 +90 +90 +90 +90 +ENDCHAR +STARTCHAR i +ENCODING 105 +SWIDTH 222 0 +DWIDTH 2 0 +BBX 1 7 0 0 +BITMAP +80 +00 +80 +80 +80 +80 +80 +ENDCHAR +STARTCHAR j +ENCODING 106 +SWIDTH 222 0 +DWIDTH 2 0 +BBX 2 9 -1 -2 +BITMAP +40 +00 +40 +40 +40 +40 +40 +40 +80 +ENDCHAR +STARTCHAR k +ENCODING 107 +SWIDTH 500 0 +DWIDTH 5 0 +BBX 4 7 0 0 +BITMAP +80 +80 +90 +A0 +E0 +A0 +90 +ENDCHAR +STARTCHAR l +ENCODING 108 +SWIDTH 222 0 +DWIDTH 2 0 +BBX 1 7 0 0 +BITMAP +80 +80 +80 +80 +80 +80 +80 +ENDCHAR +STARTCHAR m +ENCODING 109 +SWIDTH 833 0 +DWIDTH 8 0 +BBX 7 5 0 0 +BITMAP +FC +92 +92 +92 +92 +ENDCHAR +STARTCHAR n +ENCODING 110 +SWIDTH 556 0 +DWIDTH 5 0 +BBX 4 5 0 0 +BITMAP +E0 +90 +90 +90 +90 +ENDCHAR +STARTCHAR o +ENCODING 111 +SWIDTH 556 0 +DWIDTH 5 0 +BBX 4 5 0 0 +BITMAP +60 +90 +90 +90 +60 +ENDCHAR +STARTCHAR p +ENCODING 112 +SWIDTH 556 0 +DWIDTH 5 0 +BBX 4 7 0 -2 +BITMAP +E0 +90 +90 +90 +E0 +80 +80 +ENDCHAR +STARTCHAR q +ENCODING 113 +SWIDTH 556 0 +DWIDTH 5 0 +BBX 4 7 0 -2 +BITMAP +70 +90 +90 +90 +70 +10 +10 +ENDCHAR +STARTCHAR r +ENCODING 114 +SWIDTH 333 0 +DWIDTH 3 0 +BBX 3 5 0 0 +BITMAP +E0 +80 +80 +80 +80 +ENDCHAR +STARTCHAR s +ENCODING 115 +SWIDTH 500 0 +DWIDTH 5 0 +BBX 4 5 0 0 +BITMAP +70 +80 +60 +10 +E0 +ENDCHAR +STARTCHAR t +ENCODING 116 +SWIDTH 277 0 +DWIDTH 3 0 +BBX 3 6 -1 0 +BITMAP +40 +E0 +40 +40 +40 +60 +ENDCHAR +STARTCHAR u +ENCODING 117 +SWIDTH 556 0 +DWIDTH 5 0 +BBX 4 5 0 0 +BITMAP +90 +90 +90 +90 +70 +ENDCHAR +STARTCHAR v +ENCODING 118 +SWIDTH 500 0 +DWIDTH 6 0 +BBX 5 5 0 0 +BITMAP +88 +50 +50 +50 +20 +ENDCHAR +STARTCHAR w +ENCODING 119 +SWIDTH 722 0 +DWIDTH 6 0 +BBX 5 5 0 0 +BITMAP +A8 +A8 +A8 +A8 +50 +ENDCHAR +STARTCHAR x +ENCODING 120 +SWIDTH 500 0 +DWIDTH 5 0 +BBX 4 5 0 0 +BITMAP +90 +60 +40 +60 +90 +ENDCHAR +STARTCHAR y +ENCODING 121 +SWIDTH 500 0 +DWIDTH 6 0 +BBX 5 7 0 -2 +BITMAP +88 +50 +50 +50 +20 +20 +40 +ENDCHAR +STARTCHAR z +ENCODING 122 +SWIDTH 500 0 +DWIDTH 4 0 +BBX 3 5 0 0 +BITMAP +E0 +20 +40 +80 +E0 +ENDCHAR +STARTCHAR braceleft +ENCODING 123 +SWIDTH 333 0 +DWIDTH 3 0 +BBX 3 9 0 -2 +BITMAP +60 +40 +40 +40 +80 +40 +40 +40 +60 +ENDCHAR +STARTCHAR bar +ENCODING 124 +SWIDTH 259 0 +DWIDTH 3 0 +BBX 1 8 1 -1 +BITMAP +80 +80 +80 +80 +80 +80 +80 +80 +ENDCHAR +STARTCHAR braceright +ENCODING 125 +SWIDTH 333 0 +DWIDTH 3 0 +BBX 3 9 0 -2 +BITMAP +C0 +40 +40 +40 +20 +40 +40 +40 +C0 +ENDCHAR +STARTCHAR asciitilde +ENCODING 126 +SWIDTH 583 0 +DWIDTH 5 0 +BBX 4 2 0 2 +BITMAP +D0 +B0 +ENDCHAR +STARTCHAR space.dup1 +ENCODING 160 +SWIDTH 277 0 +DWIDTH 3 0 +BBX 1 1 0 0 +BITMAP +00 +ENDCHAR +STARTCHAR exclamdown +ENCODING 161 +SWIDTH 333 0 +DWIDTH 3 0 +BBX 1 7 1 -2 +BITMAP +80 +00 +80 +80 +80 +80 +80 +ENDCHAR +STARTCHAR cent +ENCODING 162 +SWIDTH 556 0 +DWIDTH 5 0 +BBX 4 9 0 -2 +BITMAP +20 +20 +60 +B0 +A0 +D0 +60 +40 +40 +ENDCHAR +STARTCHAR sterling +ENCODING 163 +SWIDTH 556 0 +DWIDTH 5 0 +BBX 5 7 0 0 +BITMAP +30 +48 +40 +E0 +40 +40 +F8 +ENDCHAR +STARTCHAR currency +ENCODING 164 +SWIDTH 556 0 +DWIDTH 5 0 +BBX 4 4 1 1 +BITMAP +F0 +90 +90 +F0 +ENDCHAR +STARTCHAR yen +ENCODING 165 +SWIDTH 556 0 +DWIDTH 5 0 +BBX 5 7 0 0 +BITMAP +88 +50 +50 +F8 +20 +F8 +20 +ENDCHAR +STARTCHAR brokenbar +ENCODING 166 +SWIDTH 259 0 +DWIDTH 3 0 +BBX 1 8 1 -1 +BITMAP +80 +80 +80 +00 +00 +80 +80 +80 +ENDCHAR +STARTCHAR section +ENCODING 167 +SWIDTH 556 0 +DWIDTH 5 0 +BBX 4 9 0 -2 +BITMAP +E0 +90 +40 +A0 +90 +50 +20 +90 +70 +ENDCHAR +STARTCHAR dieresis +ENCODING 168 +SWIDTH 333 0 +DWIDTH 3 0 +BBX 3 1 0 6 +BITMAP +A0 +ENDCHAR +STARTCHAR copyright +ENCODING 169 +SWIDTH 736 0 +DWIDTH 7 0 +BBX 7 7 0 0 +BITMAP +7C +82 +9A +A2 +9A +82 +7C +ENDCHAR +STARTCHAR ordfeminine +ENCODING 170 +SWIDTH 370 0 +DWIDTH 3 0 +BBX 3 3 0 4 +BITMAP +E0 +60 +E0 +ENDCHAR +STARTCHAR guillemotleft +ENCODING 171 +SWIDTH 556 0 +DWIDTH 5 0 +BBX 4 4 1 0 +BITMAP +50 +A0 +A0 +50 +ENDCHAR +STARTCHAR logicalnot +ENCODING 172 +SWIDTH 583 0 +DWIDTH 5 0 +BBX 4 3 0 2 +BITMAP +F0 +10 +10 +ENDCHAR +STARTCHAR hyphen.dup2 +ENCODING 173 +SWIDTH 333 0 +DWIDTH 3 0 +BBX 2 1 0 2 +BITMAP +C0 +ENDCHAR +STARTCHAR registered +ENCODING 174 +SWIDTH 736 0 +DWIDTH 7 0 +BBX 7 7 0 0 +BITMAP +7C +82 +B2 +BA +AA +82 +7C +ENDCHAR +STARTCHAR macron +ENCODING 175 +SWIDTH 552 0 +DWIDTH 5 0 +BBX 5 1 0 7 +BITMAP +F8 +ENDCHAR +STARTCHAR degree +ENCODING 176 +SWIDTH 399 0 +DWIDTH 4 0 +BBX 3 3 1 4 +BITMAP +E0 +A0 +E0 +ENDCHAR +STARTCHAR plusminus +ENCODING 177 +SWIDTH 548 0 +DWIDTH 5 0 +BBX 5 6 0 0 +BITMAP +20 +20 +F8 +20 +20 +F8 +ENDCHAR +STARTCHAR uni00B2 +ENCODING 178 +SWIDTH 333 0 +DWIDTH 3 0 +BBX 3 3 0 4 +BITMAP +E0 +40 +E0 +ENDCHAR +STARTCHAR uni00B3 +ENCODING 179 +SWIDTH 333 0 +DWIDTH 3 0 +BBX 3 3 0 4 +BITMAP +E0 +40 +E0 +ENDCHAR +STARTCHAR acute +ENCODING 180 +SWIDTH 333 0 +DWIDTH 3 0 +BBX 2 2 1 5 +BITMAP +40 +80 +ENDCHAR +STARTCHAR mu +ENCODING 181 +SWIDTH 576 0 +DWIDTH 5 0 +BBX 4 7 0 -2 +BITMAP +90 +90 +90 +90 +F0 +80 +80 +ENDCHAR +STARTCHAR paragraph +ENCODING 182 +SWIDTH 537 0 +DWIDTH 5 0 +BBX 5 8 0 -1 +BITMAP +78 +D0 +D0 +D0 +50 +50 +50 +50 +ENDCHAR +STARTCHAR periodcentered +ENCODING 183 +SWIDTH 333 0 +DWIDTH 3 0 +BBX 1 1 1 3 +BITMAP +80 +ENDCHAR +STARTCHAR cedilla +ENCODING 184 +SWIDTH 333 0 +DWIDTH 3 0 +BBX 2 3 0 -3 +BITMAP +40 +40 +C0 +ENDCHAR +STARTCHAR uni00B9 +ENCODING 185 +SWIDTH 333 0 +DWIDTH 3 0 +BBX 2 3 1 4 +BITMAP +40 +C0 +40 +ENDCHAR +STARTCHAR ordmasculine +ENCODING 186 +SWIDTH 365 0 +DWIDTH 3 0 +BBX 3 3 0 4 +BITMAP +E0 +A0 +E0 +ENDCHAR +STARTCHAR guillemotright +ENCODING 187 +SWIDTH 556 0 +DWIDTH 5 0 +BBX 4 4 0 0 +BITMAP +A0 +50 +50 +A0 +ENDCHAR +STARTCHAR onequarter +ENCODING 188 +SWIDTH 833 0 +DWIDTH 8 0 +BBX 6 7 1 0 +BITMAP +44 +C8 +50 +10 +24 +4C +84 +ENDCHAR +STARTCHAR onehalf +ENCODING 189 +SWIDTH 833 0 +DWIDTH 8 0 +BBX 7 7 1 0 +BITMAP +44 +C8 +50 +10 +2E +44 +8E +ENDCHAR +STARTCHAR threequarters +ENCODING 190 +SWIDTH 833 0 +DWIDTH 8 0 +BBX 7 7 0 0 +BITMAP +E2 +44 +E8 +08 +12 +26 +22 +ENDCHAR +STARTCHAR questiondown +ENCODING 191 +SWIDTH 610 0 +DWIDTH 6 0 +BBX 4 7 1 -2 +BITMAP +20 +00 +20 +60 +80 +90 +60 +ENDCHAR +STARTCHAR Agrave +ENCODING 192 +SWIDTH 666 0 +DWIDTH 6 0 +BBX 7 10 0 0 +BITMAP +10 +08 +00 +10 +28 +28 +44 +7C +44 +82 +ENDCHAR +STARTCHAR Aacute +ENCODING 193 +SWIDTH 666 0 +DWIDTH 6 0 +BBX 7 10 0 0 +BITMAP +08 +10 +00 +10 +28 +28 +44 +7C +44 +82 +ENDCHAR +STARTCHAR Acircumflex +ENCODING 194 +SWIDTH 666 0 +DWIDTH 6 0 +BBX 7 10 0 0 +BITMAP +18 +34 +00 +10 +28 +28 +44 +7C +44 +82 +ENDCHAR +STARTCHAR Atilde +ENCODING 195 +SWIDTH 666 0 +DWIDTH 6 0 +BBX 7 10 0 0 +BITMAP +28 +50 +00 +10 +28 +28 +44 +7C +44 +82 +ENDCHAR +STARTCHAR Adieresis +ENCODING 196 +SWIDTH 666 0 +DWIDTH 6 0 +BBX 7 9 0 0 +BITMAP +28 +00 +10 +28 +28 +44 +7C +44 +82 +ENDCHAR +STARTCHAR Aring +ENCODING 197 +SWIDTH 666 0 +DWIDTH 6 0 +BBX 7 9 0 0 +BITMAP +38 +28 +38 +28 +28 +44 +7C +44 +82 +ENDCHAR +STARTCHAR AE +ENCODING 198 +SWIDTH 1000 0 +DWIDTH 9 0 +BBX 9 7 0 0 +BITMAP +1F80 +2800 +2800 +4F80 +7800 +8800 +8F80 +ENDCHAR +STARTCHAR Ccedilla +ENCODING 199 +SWIDTH 722 0 +DWIDTH 7 0 +BBX 5 10 1 -3 +BITMAP +70 +88 +80 +80 +80 +88 +70 +10 +10 +30 +ENDCHAR +STARTCHAR Egrave +ENCODING 200 +SWIDTH 666 0 +DWIDTH 6 0 +BBX 5 10 1 0 +BITMAP +20 +10 +00 +F8 +80 +80 +F8 +80 +80 +F8 +ENDCHAR +STARTCHAR Eacute +ENCODING 201 +SWIDTH 666 0 +DWIDTH 6 0 +BBX 5 10 1 0 +BITMAP +10 +20 +00 +F8 +80 +80 +F8 +80 +80 +F8 +ENDCHAR +STARTCHAR Ecircumflex +ENCODING 202 +SWIDTH 666 0 +DWIDTH 6 0 +BBX 5 10 1 0 +BITMAP +20 +50 +00 +F8 +80 +80 +F8 +80 +80 +F8 +ENDCHAR +STARTCHAR Edieresis +ENCODING 203 +SWIDTH 666 0 +DWIDTH 6 0 +BBX 5 9 1 0 +BITMAP +50 +00 +F8 +80 +80 +F8 +80 +80 +F8 +ENDCHAR +STARTCHAR Igrave +ENCODING 204 +SWIDTH 277 0 +DWIDTH 3 0 +BBX 2 10 1 0 +BITMAP +80 +40 +00 +80 +80 +80 +80 +80 +80 +80 +ENDCHAR +STARTCHAR Iacute +ENCODING 205 +SWIDTH 277 0 +DWIDTH 3 0 +BBX 2 10 0 0 +BITMAP +40 +80 +00 +40 +40 +40 +40 +40 +40 +40 +ENDCHAR +STARTCHAR Icircumflex +ENCODING 206 +SWIDTH 277 0 +DWIDTH 3 0 +BBX 3 10 -1 0 +BITMAP +40 +A0 +00 +20 +20 +20 +20 +20 +20 +20 +ENDCHAR +STARTCHAR Idieresis +ENCODING 207 +SWIDTH 277 0 +DWIDTH 3 0 +BBX 3 9 0 0 +BITMAP +A0 +00 +40 +40 +40 +40 +40 +40 +40 +ENDCHAR +STARTCHAR Eth +ENCODING 208 +SWIDTH 722 0 +DWIDTH 7 0 +BBX 6 7 0 0 +BITMAP +78 +44 +44 +F4 +44 +44 +78 +ENDCHAR +STARTCHAR Ntilde +ENCODING 209 +SWIDTH 722 0 +DWIDTH 7 0 +BBX 5 10 1 0 +BITMAP +50 +A0 +00 +88 +C8 +C8 +A8 +98 +98 +88 +ENDCHAR +STARTCHAR Ograve +ENCODING 210 +SWIDTH 777 0 +DWIDTH 7 0 +BBX 5 10 1 0 +BITMAP +20 +10 +00 +70 +88 +88 +88 +88 +88 +70 +ENDCHAR +STARTCHAR Oacute +ENCODING 211 +SWIDTH 777 0 +DWIDTH 7 0 +BBX 5 10 1 0 +BITMAP +10 +20 +00 +70 +88 +88 +88 +88 +88 +70 +ENDCHAR +STARTCHAR Ocircumflex +ENCODING 212 +SWIDTH 777 0 +DWIDTH 7 0 +BBX 5 10 1 0 +BITMAP +20 +50 +00 +70 +88 +88 +88 +88 +88 +70 +ENDCHAR +STARTCHAR Otilde +ENCODING 213 +SWIDTH 777 0 +DWIDTH 7 0 +BBX 5 10 1 0 +BITMAP +50 +A0 +00 +70 +88 +88 +88 +88 +88 +70 +ENDCHAR +STARTCHAR Odieresis +ENCODING 214 +SWIDTH 777 0 +DWIDTH 7 0 +BBX 5 9 1 0 +BITMAP +50 +00 +70 +88 +88 +88 +88 +88 +70 +ENDCHAR +STARTCHAR multiply +ENCODING 215 +SWIDTH 583 0 +DWIDTH 5 0 +BBX 5 5 0 1 +BITMAP +88 +70 +20 +70 +88 +ENDCHAR +STARTCHAR Oslash +ENCODING 216 +SWIDTH 777 0 +DWIDTH 7 0 +BBX 5 7 1 0 +BITMAP +78 +90 +98 +A8 +C8 +48 +F0 +ENDCHAR +STARTCHAR Ugrave +ENCODING 217 +SWIDTH 722 0 +DWIDTH 7 0 +BBX 5 10 1 0 +BITMAP +40 +20 +00 +88 +88 +88 +88 +88 +88 +70 +ENDCHAR +STARTCHAR Uacute +ENCODING 218 +SWIDTH 722 0 +DWIDTH 7 0 +BBX 5 10 1 0 +BITMAP +20 +40 +00 +88 +88 +88 +88 +88 +88 +70 +ENDCHAR +STARTCHAR Ucircumflex +ENCODING 219 +SWIDTH 722 0 +DWIDTH 7 0 +BBX 5 10 1 0 +BITMAP +20 +50 +00 +88 +88 +88 +88 +88 +88 +70 +ENDCHAR +STARTCHAR Udieresis +ENCODING 220 +SWIDTH 722 0 +DWIDTH 7 0 +BBX 5 9 1 0 +BITMAP +28 +00 +88 +88 +88 +88 +88 +88 +70 +ENDCHAR +STARTCHAR Yacute +ENCODING 221 +SWIDTH 666 0 +DWIDTH 7 0 +BBX 5 10 1 0 +BITMAP +10 +20 +00 +88 +50 +50 +20 +20 +20 +20 +ENDCHAR +STARTCHAR Thorn +ENCODING 222 +SWIDTH 666 0 +DWIDTH 6 0 +BBX 5 7 1 0 +BITMAP +80 +F0 +88 +88 +88 +F0 +80 +ENDCHAR +STARTCHAR germandbls +ENCODING 223 +SWIDTH 610 0 +DWIDTH 6 0 +BBX 4 7 1 0 +BITMAP +40 +A0 +A0 +C0 +B0 +D0 +A0 +ENDCHAR +STARTCHAR agrave +ENCODING 224 +SWIDTH 556 0 +DWIDTH 5 0 +BBX 4 8 0 0 +BITMAP +40 +20 +00 +F0 +10 +70 +90 +F0 +ENDCHAR +STARTCHAR aacute +ENCODING 225 +SWIDTH 556 0 +DWIDTH 5 0 +BBX 4 8 0 0 +BITMAP +20 +40 +00 +F0 +10 +70 +90 +F0 +ENDCHAR +STARTCHAR acircumflex +ENCODING 226 +SWIDTH 556 0 +DWIDTH 5 0 +BBX 4 8 0 0 +BITMAP +20 +50 +00 +F0 +10 +70 +90 +F0 +ENDCHAR +STARTCHAR atilde +ENCODING 227 +SWIDTH 556 0 +DWIDTH 5 0 +BBX 4 8 0 0 +BITMAP +50 +A0 +00 +F0 +10 +70 +90 +F0 +ENDCHAR +STARTCHAR adieresis +ENCODING 228 +SWIDTH 556 0 +DWIDTH 5 0 +BBX 4 7 0 0 +BITMAP +50 +00 +F0 +10 +70 +90 +F0 +ENDCHAR +STARTCHAR aring +ENCODING 229 +SWIDTH 556 0 +DWIDTH 5 0 +BBX 4 9 0 0 +BITMAP +70 +50 +70 +00 +F0 +10 +70 +90 +F0 +ENDCHAR +STARTCHAR ae +ENCODING 230 +SWIDTH 889 0 +DWIDTH 8 0 +BBX 7 5 0 0 +BITMAP +EC +12 +7E +90 +EE +ENDCHAR +STARTCHAR ccedilla +ENCODING 231 +SWIDTH 500 0 +DWIDTH 5 0 +BBX 4 8 0 -3 +BITMAP +60 +90 +80 +90 +60 +20 +20 +60 +ENDCHAR +STARTCHAR egrave +ENCODING 232 +SWIDTH 556 0 +DWIDTH 5 0 +BBX 4 8 0 0 +BITMAP +40 +20 +00 +60 +90 +F0 +80 +70 +ENDCHAR +STARTCHAR eacute +ENCODING 233 +SWIDTH 556 0 +DWIDTH 5 0 +BBX 4 8 0 0 +BITMAP +20 +40 +00 +60 +90 +F0 +80 +70 +ENDCHAR +STARTCHAR ecircumflex +ENCODING 234 +SWIDTH 556 0 +DWIDTH 5 0 +BBX 4 8 0 0 +BITMAP +20 +50 +00 +60 +90 +F0 +80 +70 +ENDCHAR +STARTCHAR edieresis +ENCODING 235 +SWIDTH 556 0 +DWIDTH 5 0 +BBX 4 7 0 0 +BITMAP +A0 +00 +60 +90 +F0 +80 +70 +ENDCHAR +STARTCHAR igrave +ENCODING 236 +SWIDTH 277 0 +DWIDTH 2 0 +BBX 2 8 0 0 +BITMAP +80 +40 +00 +80 +80 +80 +80 +80 +ENDCHAR +STARTCHAR iacute +ENCODING 237 +SWIDTH 277 0 +DWIDTH 2 0 +BBX 2 8 -1 0 +BITMAP +40 +80 +00 +40 +40 +40 +40 +40 +ENDCHAR +STARTCHAR icircumflex +ENCODING 238 +SWIDTH 277 0 +DWIDTH 2 0 +BBX 3 8 0 0 +BITMAP +C0 +A0 +00 +80 +80 +80 +80 +80 +ENDCHAR +STARTCHAR idieresis +ENCODING 239 +SWIDTH 277 0 +DWIDTH 2 0 +BBX 3 7 -1 0 +BITMAP +A0 +00 +40 +40 +40 +40 +40 +ENDCHAR +STARTCHAR eth +ENCODING 240 +SWIDTH 556 0 +DWIDTH 5 0 +BBX 4 7 0 0 +BITMAP +60 +20 +70 +90 +90 +90 +60 +ENDCHAR +STARTCHAR ntilde +ENCODING 241 +SWIDTH 556 0 +DWIDTH 5 0 +BBX 4 8 0 0 +BITMAP +50 +A0 +00 +E0 +90 +90 +90 +90 +ENDCHAR +STARTCHAR ograve +ENCODING 242 +SWIDTH 556 0 +DWIDTH 5 0 +BBX 4 8 0 0 +BITMAP +40 +20 +00 +60 +90 +90 +90 +60 +ENDCHAR +STARTCHAR oacute +ENCODING 243 +SWIDTH 556 0 +DWIDTH 5 0 +BBX 4 8 0 0 +BITMAP +20 +40 +00 +60 +90 +90 +90 +60 +ENDCHAR +STARTCHAR ocircumflex +ENCODING 244 +SWIDTH 556 0 +DWIDTH 5 0 +BBX 4 8 0 0 +BITMAP +20 +50 +00 +60 +90 +90 +90 +60 +ENDCHAR +STARTCHAR otilde +ENCODING 245 +SWIDTH 556 0 +DWIDTH 5 0 +BBX 4 8 0 0 +BITMAP +50 +A0 +00 +60 +90 +90 +90 +60 +ENDCHAR +STARTCHAR odieresis +ENCODING 246 +SWIDTH 556 0 +DWIDTH 5 0 +BBX 4 7 0 0 +BITMAP +A0 +00 +60 +90 +90 +90 +60 +ENDCHAR +STARTCHAR divide +ENCODING 247 +SWIDTH 548 0 +DWIDTH 5 0 +BBX 5 5 0 0 +BITMAP +20 +00 +F8 +00 +20 +ENDCHAR +STARTCHAR oslash +ENCODING 248 +SWIDTH 610 0 +DWIDTH 5 0 +BBX 4 5 0 0 +BITMAP +70 +B0 +D0 +D0 +E0 +ENDCHAR +STARTCHAR ugrave +ENCODING 249 +SWIDTH 556 0 +DWIDTH 5 0 +BBX 4 8 0 0 +BITMAP +40 +20 +00 +90 +90 +90 +90 +70 +ENDCHAR +STARTCHAR uacute +ENCODING 250 +SWIDTH 556 0 +DWIDTH 5 0 +BBX 4 8 0 0 +BITMAP +20 +40 +00 +90 +90 +90 +90 +70 +ENDCHAR +STARTCHAR ucircumflex +ENCODING 251 +SWIDTH 556 0 +DWIDTH 5 0 +BBX 4 8 0 0 +BITMAP +40 +A0 +00 +90 +90 +90 +90 +70 +ENDCHAR +STARTCHAR udieresis +ENCODING 252 +SWIDTH 556 0 +DWIDTH 5 0 +BBX 4 7 0 0 +BITMAP +50 +00 +90 +90 +90 +90 +70 +ENDCHAR +STARTCHAR yacute +ENCODING 253 +SWIDTH 500 0 +DWIDTH 6 0 +BBX 5 10 0 -2 +BITMAP +10 +20 +00 +88 +50 +50 +50 +20 +20 +40 +ENDCHAR +STARTCHAR thorn +ENCODING 254 +SWIDTH 556 0 +DWIDTH 5 0 +BBX 4 9 0 -2 +BITMAP +80 +80 +E0 +90 +90 +90 +E0 +80 +80 +ENDCHAR +STARTCHAR ydieresis +ENCODING 255 +SWIDTH 500 0 +DWIDTH 6 0 +BBX 5 9 0 -2 +BITMAP +50 +00 +88 +50 +50 +50 +20 +20 +40 +ENDCHAR +ENDFONT