Compare commits

...

209 Commits

Author SHA1 Message Date
morgan 753ca34560 increment version 2021-04-19 13:23:23 -04:00
morgan 888697bb79 bugfixes for nRF examples 2021-04-19 13:20:54 -04:00
Morgan Redfield 1500d07213 adding nRF52840 (feather) example 2021-04-19 10:49:34 -04:00
Morgan Redfield 70bd364473 update reset comments for HSMini 2019-12-23 11:14:37 -05:00
Morgan Redfield ef2268ca22 fix serial rx flush in examples 2019-09-07 19:43:11 -07:00
Morgan Redfield aa14035c94 stabilize comms timing 2019-09-07 19:40:22 -07:00
Morgan Redfield 777a56d131 fix I2C comments 2019-08-20 14:34:20 -07:00
spaceneedle 0e520d74f9
Update README.md 2019-08-07 09:53:55 -04:00
Morgan Redfield f630fc8d88 loop speech 2019-07-18 18:08:02 -07:00
Morgan Redfield 4006afff64 make speechTX more polite and more verbose 2019-07-18 18:06:38 -07:00
Morgan Redfield 3d3f6a36b6 update dtmf, morse, and examples 2019-07-14 13:37:14 -07:00
Morgan Redfield 71acbbb975 update DTMF tx and rx 2019-06-01 18:09:15 -07:00
Morgan Redfield 6472b103b4 update Morse 2019-06-01 15:25:56 -07:00
Morgan Redfield 7e509ca0fc minor morse updates 2019-05-11 15:32:13 -07:00
Morgan Redfield 12fd074aed let HSTone be generated by HamShield itself 2019-04-28 11:41:29 -07:00
Morgan Redfield 1d0eb281e2 serial messenger bug fixes 2019-04-12 11:50:17 -07:00
Morgan Redfield 7941388980 adding in HandyTalkie_nrf52840 2019-04-06 14:00:45 -07:00
Morgan Redfield f83b547de4 merge RPi branch in, add Feather nRF52840 Express example BLE sketch 2019-04-06 14:00:03 -07:00
Morgan Redfield b147edfcfa minor bug fix 2019-03-24 15:17:45 -07:00
Morgan Redfield 3c3d83c057 unify pin naming scheme 2019-03-15 10:43:15 -07:00
Morgan Redfield 9d708e4046 update afsk_messenger example 2019-02-10 12:01:09 -08:00
Morgan Redfield 250dd330b7 noTone bugfixes 2019-02-04 17:41:35 -08:00
Morgan Redfield 289d1f73a8 removing duration from tone calls 2019-02-04 15:25:29 -08:00
morgan 00fd294bde working with RPi 2019-02-04 21:28:59 +00:00
morgan 1b1c9b3f80 fix noTone calls 2019-02-02 21:22:37 +00:00
morgan 467765d892 update tone calls 2019-02-02 21:16:33 +00:00
morgan 844bb6b8c6 finish abstraction for RPi 2019-02-02 21:13:21 +00:00
Morgan Redfield f7c76eb1ad begin abstracting hardware functions 2019-01-29 21:10:18 -08:00
morgan 76a92a882f remove library control of button 2019-01-29 20:13:45 -08:00
morgan 7427b426b1 allow non-standard digital control pins 2019-01-29 20:09:42 -08:00
Morgan Redfield 6b05b7754d update vox and mic signal strength reading 2019-01-19 11:42:39 -08:00
morgan 6c891c9f32 update example comments 2018-12-09 09:43:41 -08:00
morgan d65877ad29 update library properties 2018-11-17 11:43:59 -08:00
morgan dc93752730 temporary fixes for KISS example 2018-11-07 16:45:46 -08:00
morgan 220bd8aa28 remove overloading of frequency function, now using frequency_float for subkhz frequency settings 2018-10-29 18:31:37 -07:00
morgan 373c584ae9 Merge branch 'master' of https://github.com/EnhancedRadioDevices/HamShield 2018-10-21 19:27:45 -07:00
morgan a38ac4bf27 update examples, rev arduino version 2018-10-21 19:27:24 -07:00
morgan 5e895f7799 update examples, rev arduino version 2018-10-21 18:45:58 -07:00
Morgan Redfield 88264e1998 fix mute in ctcss example 2018-08-17 19:25:38 -07:00
Morgan Redfield 0b6d1a3cac update comments 2018-08-17 08:01:11 -07:00
Morgan Redfield afbecf6e5e update ctcss getfreq and example 2018-08-15 19:30:20 -07:00
Morgan Redfield 96d02c3bd9 adding CTCSS and example 2018-08-11 20:30:09 -07:00
Morgan Redfield 73f8cb3d93 adding Morse rx example 2018-08-11 19:39:31 -07:00
Morgan Redfield c2a58487d3 update ctcss/cdcss and morse 2018-08-09 20:32:29 -07:00
Morgan Redfield 38f5a467ef whitespace fix 2018-08-08 18:50:30 -07:00
Morgan Redfield 88efafa0e2 Updating examples 2018-08-08 18:49:56 -07:00
Morgan Redfield 3457f11211 updating examples 2018-08-07 21:56:33 -07:00
Morgan Redfield 450d05fdea add delay after power on to examples, minor bugfixing 2018-08-04 19:47:58 -07:00
Morgan Redfield 45527b826f dtmf timing, sub-khz frequency resolution 2018-08-04 19:31:53 -07:00
Morgan Redfield 176814bc98 update examples 2018-07-03 16:02:21 -07:00
Morgan Redfield a9f3380f85 update DTMF example 2018-07-03 15:32:05 -07:00
Morgan Redfield c813bac7b8 rever KISS example 2018-06-24 17:16:39 -07:00
Morgan Redfield 24082d5a11 working DTMF 2018-06-24 17:12:04 -07:00
Morgan Redfield c340fef0b4 dtmf update 2018-06-16 19:14:13 -07:00
Morgan Redfield ac31e5e79e dtmf changes 2018-06-16 19:13:36 -07:00
Nigel Vander Houwen 5e36ab2898 Fixed origin/destination swap. Saved a little RAM to improve stability. 2018-04-06 17:20:38 -07:00
Nigel Vander Houwen d4027f1e7b Removed JustTransmit example. It doesn't add anything not covered in other basic examples like FMBeacon or HandyTalkie 2018-02-13 16:54:37 -08:00
Nigel Vander Houwen e73f67429d Added some additional comments to FMBeacon example sketch. 2018-02-13 16:51:32 -08:00
Nigel Vander Houwen daa4befe2c General FoxHunt example sketch fixups. Added code comments to aid understanding. Added a number of serial prints so you can see what it's doing. Moved the long wait inside the if->transmit block so we don't wait a long time if the channel was busy. 2018-02-13 16:49:52 -08:00
Nigel Vander Houwen ae0dacac77 General FMBeacon example sketch fixups. Raised morse audio freq to match conventional 600Hz. Increased morse speed a little. Shortened test message. Lengthened interval between transmissions. 2018-02-13 16:29:12 -08:00
Morgan Redfield e64095c6d5 Merge pull request #36 from radiohound/master
Added SpeechTX example
2017-09-05 20:40:20 -07:00
Morgan Redfield 23c8c85b98 Merge pull request #34 from dmbryson/setgpios
Add support for directly setting the GPIO values
2017-09-05 20:38:30 -07:00
Morgan Redfield 6c7997f756 Merge pull request #35 from dmbryson/dtmfdecode
Correct DTMF decoding functions for the Auctus AT1846S
2017-09-05 20:37:42 -07:00
nick6x 74a2d1cb90 Update DDS.ino example for DDS library changes 2017-07-30 12:08:24 -07:00
nick6x 2edaac6fca Update dds example for dds library changes 2017-07-28 16:22:11 -07:00
Walter Dunckel ad40307b3c wav file of speech example
Radio call sign, followed by a few word examples
2017-06-18 11:00:50 -07:00
Walter Dunckel 6f7affe635 Create SpeechTX.ino
Example of using the Talkie library to enable the HamShield to transmit encoded audio speech.
2017-06-18 10:51:56 -07:00
spaceneedle 3e3b0daeab minor tweak to fix receive on start 2017-06-10 12:50:31 -05:00
spaceneedle 74230282b8 incrementing library version 2017-06-10 12:43:57 -05:00
spaceneedle 1416a5c1bf Adding App Serial Controller 2017-06-10 12:40:19 -05:00
Casey Halverson 4f7db1d561 revised lib properties 2017-05-09 13:43:19 -04:00
Casey Halverson d8d97789d7 Fixed critical define
Fixed a critical define
2017-05-09 13:40:54 -04:00
spaceneedle d232424bb4 Library properties so Arduino knows to update
Incremented version
2017-05-08 19:23:14 -05:00
spaceneedle 6538ae7db3 Long awaited fix to CTCSS detection and encoding
Two extremely powerful functions:

setCtcssEncoder(float freq)
setCtcssDecoder(float freq)

Yes, that does mean *any* frequency, including non-standard CTCSS tones.

Enjoy.

-Casey
2017-05-08 19:21:18 -05:00
David M. Bryson b1180ab135 Correct DTMF decoding functions for the Auctus AT1846S 2017-05-03 20:14:00 -07:00
David M. Bryson aca7de3328 Add support for directly setting the GPIO values 2017-05-03 19:42:02 -07:00
Morgan Redfield 307d33add0 update version to 1.0.3 2017-01-15 12:12:20 -08:00
nick6x 219d89ff60 Merge branch 'master' of https://github.com/EnhancedRadioDevices/HamShield 2017-01-15 12:06:12 -08:00
nick6x 6954402ac6 Clarify example descriptions 2017-01-15 12:05:43 -08:00
morgan ec0400c1c6 adding narrow/wide band control 2017-01-15 11:31:22 -08:00
morgan 1d02387649 add yaac instructions to example 2016-12-27 12:46:27 -08:00
morgan 4593f1d44c fix KISS example 2016-12-27 12:08:28 -08:00
morgan 292a774a79 make morse dot duration user settable 2016-12-19 11:53:36 -08:00
morgan 5874e6b8e5 make morse tone freq user settable 2016-12-19 11:40:44 -08:00
morgan 4ff3f7d9d0 working afsk packets 2016-09-24 17:33:00 -07:00
morgan b9f75e0c11 update AFSK messenger example 2016-09-24 15:32:24 -07:00
Morgan Redfield f462bc0342 Merge pull request #24 from Temtel/master
Fixed Frequency Display at startup in AX25Receive.ino
2016-09-20 10:10:40 -07:00
Temtel 33962a585d Fixed Frequency Display at startup
Added   Serial.println(radio.getFrequency()); to setup.  May have been
removed accidentaly
2016-09-18 15:12:42 -07:00
Morgan Redfield d54c5404a8 clarify new library setup 2016-08-27 09:36:01 -07:00
nick6x 6b775130d1 Remove unfinished examples 2016-08-26 15:02:40 -07:00
nick6x e65893402a Fix typos 2016-08-26 14:40:47 -07:00
nick6x 9096d2ffa2 Update to separated libraries 2016-08-26 11:22:41 -07:00
nick6x 3e76e6e72f Merge branch 'master' of https://github.com/EnhancedRadioDevices/HamShield 2016-08-26 11:15:27 -07:00
nick6x 8b8fd7a9a1 Fix Functional Test example 2016-08-26 11:14:39 -07:00
Nigel Vander Houwen 164888fd49 Fixed DDS.cpp to reference ADC channel 2 instead of old channel 0. 2016-08-23 20:39:21 -07:00
nick6x e8ad7e9c93 Clarify Signal Test example explanation 2016-08-22 18:37:32 -07:00
nick6x 4f30789e88 Resolve problems with examples not compiling or otherwise not functioning. 2016-08-22 01:40:27 -07:00
nick6x f369c2ff9a Fix examples to reflect combined KISS and AFSK libraries. 2016-08-19 18:52:36 -07:00
nick6x 25813b7968 Clairify Parrot example description. 2016-08-18 20:47:35 -07:00
nick6x e10e351e49 Clarify Parros example description 2016-08-18 20:46:00 -07:00
nick6x 62e137f8f2 Standardize serial monitor baud rate in AFSK Packet Tester example 2016-08-18 19:14:08 -07:00
nick6x 9e0db9d537 Update HamShield examples to work with seperated libraries. 2016-08-17 14:17:56 -07:00
nick6x bce0b1e0d8 Merge branch 'master' into dev 2016-08-17 12:45:23 -07:00
nick6x 39b543877b Resolve SSTV example issues 2016-08-17 12:43:51 -07:00
nick6x f5e004fbb3 -Seperate AFSK, DDS, and KISS into their own libraries to conserve memory. 2016-08-17 12:24:36 -07:00
nick6x 09c9911ba1 Merge branch 'master' into dev 2016-08-14 15:41:59 -07:00
nick6x 2b5fbeff4a Change dashes to underscores 2016-08-14 15:33:33 -07:00
nick6x 8e35c83185 Merge branch 'master' into dev 2016-08-13 19:26:52 -07:00
nick6x 7a07bd3056 Add comments, some standardizing 2016-08-13 19:25:46 -07:00
nick6x ad7d729010 Fix examples to match Master branch. 2016-08-13 15:39:53 -07:00
nick6x c9a9320719 Update to arduino library 1.5 standard 2016-08-13 14:39:20 -07:00
nick6x 0ed024cd7d Add comments, update to new HamShield library standard. 2016-08-13 14:05:19 -07:00
nick6x 07221e2426 Merge branch 'master' into dev 2016-08-11 21:47:59 -07:00
nick6x 06cb3f24ed Resolve compiling issues in Examples. 2016-08-11 20:01:02 -07:00
nick6x 2907eaf02e add comments, update library to Arduino 1.5 standard 2016-08-10 17:30:43 -07:00
morgan 0fe34bbbb9 updated readme for dev branch 2016-07-09 20:31:51 -07:00
morgan 6a889580f2 using standard Arduino fcns for bit banging 2016-07-09 20:29:01 -07:00
Morgan Redfield d98eafb11a fix devAddr bug 2016-07-03 14:18:02 -07:00
morgan 705884497a merging 2016-07-03 14:03:15 -07:00
Morgan Redfield b818b73054 Merge pull request #18 from nvahalik/patch-1
Update HamShield.h to remove hyphen from define
2016-07-03 14:00:58 -07:00
morgan 506d3dfb0c remove i2c comments 2016-07-03 13:02:11 -07:00
morgan a92b011492 updating squelch and cs options 2016-06-30 19:33:40 -07:00
Nigel Vander Houwen 12c9cdf3d9 Fixed FoxHunt example. Verified working with current library and hardware v09 2016-06-05 13:01:39 -07:00
Nigel Vander Houwen 8c90a134ad Fixed FMBeacon example, required slight modification to library. TO-DO notes in example header. 2016-06-05 12:41:35 -07:00
Nigel Vander Houwen 3c9965fd62 Removed AFSKSend example. Redundant with AFSK-PacketTester. Cleanup on DDS example. Verified working with current library and hardware v09 2016-06-05 12:02:21 -07:00
Nigel Vander Houwen 868882f81e Cleanup on AFSK-PacketTester example, verified working with current library and hardware v09 2016-06-05 11:53:49 -07:00
Nick Vahalik 558414d084 Update HamShield.h
Remove the hyphen in the define which causes the Arduino compiler to error. This define doesn't seem to be used anywhere.
2016-05-23 06:44:13 -05:00
morgan 75e964289c use master for HS09 and above 2016-05-04 11:40:26 -07:00
morgan fbd1003c44 updated kiss 2016-05-04 11:35:06 -07:00
morgan 0011026567 fix dangermode 2016-04-17 17:19:33 -07:00
morgan 5f363f1537 updating all examples for new library 2016-04-13 19:12:06 -07:00
morgan 3a209d8db4 updating files for HS09 2016-03-24 20:31:17 -07:00
morgan 9111ba5301 changing default power levels of all examples 2016-01-04 19:36:37 -08:00
morgan c107df93dd made certain library functions private to ensure they aren't improperly called from an arduino sketch 2015-12-15 14:43:57 -08:00
morgan 28f1ff016c switched to standard I2Cdev lib, changed reg 0x44 volume control to remove agc delay 2015-12-10 17:32:18 -08:00
morgan c97b0801d5 updated HandieTalkie example, change setTxBand I2C writes 2015-12-02 21:07:36 -08:00
morgan edc78a3858 adding HandyTalkie example 2015-11-23 19:16:56 -08:00
morgan 807617de83 updated for HS05 2015-11-23 08:54:10 -08:00
morgan a196501f15 updated setting for GPIO voltage, added code to handle special frequencies 2015-09-18 18:04:03 -07:00
Casey Halverson c679bec886 some additional fixes for serial transceiver
removed old setrx/settx stuff
2015-07-14 20:10:39 -07:00
Casey Halverson e55cb9f221 added morse out to serial transceiver, fixed some library version issues 2015-07-14 20:05:22 -07:00
Nigel VH 8ab7f97cbd Merge pull request #14 from slepp/rel-jul13
Minor fixups to KISS, now append FCS. Remove 19200 refclk for now.
2015-07-13 21:34:14 -07:00
Stephen Olesen 638369d659 Minor fixups to KISS, now append FCS. Remove 19200 refclk for now. 2015-07-13 21:16:22 -06:00
Nigel VH e444b4ef4e Merge pull request #13 from slepp/rel-jul13
Early release branch including AFSK/AX25/KISS, PSK and SSTV.
2015-07-13 18:55:20 -07:00
Stephen Olesen ab7613c8d3 Updated AFSK/AX25 examples for modifications to AFSK library. 2015-07-13 19:01:32 -06:00
Stephen Olesen a22b814d63 KISS TNC mode for the AX25 stack and example. 2015-07-13 18:55:07 -06:00
Stephen Olesen 45ec01bd31 Rewrite of framing to always be pure frames, no escapes.
Added parser for packets to pretty print them to serial.
Added parser for easier packet handling on receipt.
Moved bitclock timer to outside ISR loop.
2015-07-13 18:53:18 -06:00
Stephen Olesen 4f1c863487 Default refclk now 9600, remove old table and serial debugging. 2015-07-13 18:50:48 -06:00
Stephen Olesen ed136d6fe9 Merge remote-tracking branch 'upstream/au_updates' into rel-jul13 2015-07-12 16:59:35 -06:00
Stephen Olesen 6cb8ed68d3 Rename for library compatability. 2015-07-11 14:23:03 -06:00
Stephen Olesen cf93050e52 Updated AFSK with print routine, use new delay line. AX25 receive tune to APRS. 2015-07-10 11:58:37 -06:00
Stephen Olesen 888cf9d9fd Merge remote-tracking branch 'upstream/au_updates' into afsk-au-update 2015-07-09 14:58:58 -06:00
Stephen Olesen 52ac3def7d Finalize merger. 2015-07-09 14:57:22 -06:00
Casey Halverson f685e88a42 Reference to wiki added 2015-07-06 17:35:43 -07:00
Casey Halverson 5d4efb9a0f Applying license
AGPLv3
2015-07-06 16:55:28 -07:00
Stephen Olesen 6d8813f200 Merge remote-tracking branch 'upstream/master' into afsk 2015-07-06 11:41:05 -06:00
Stephen Olesen 4fb55520ea First round of AX25 receiver. 2015-07-06 11:40:50 -06:00
Nigel VH 26e5aa75a8 Merge pull request #11 from slepp/hs-progmem
Need const on some compilers.
2015-07-05 20:33:53 -07:00
Stephen Olesen a2778779d0 Need const on some compilers. 2015-07-05 21:19:16 -06:00
Stephen Olesen 1f81215577 Merge remote-tracking branch 'upstream/master' into afsk 2015-07-05 21:08:09 -06:00
Nigel VH aaee8915b5 Merge pull request #10 from slepp/hs-progmem
Move frequency lookup tables into progmem.
2015-07-05 16:53:16 -07:00
Nigel VH efca76806c Merge pull request #9 from slepp/id-test
Check for 0x3AC or 0x32C in testConnection().
2015-07-05 16:52:26 -07:00
Stephen Olesen 1afc2c18f9 Remove extraneous pgmspace.h include. 2015-07-05 17:05:55 -06:00
Stephen Olesen 0721456c28 Move frequency lookup tables into progmem. 2015-07-05 17:03:05 -06:00
Stephen Olesen 2eea6db437 Check for 0x3AC or 0x32C in testConnection(). 2015-07-05 16:32:55 -06:00
Stephen Olesen 9bcf52ec64 Update large DDS sine table to use signed integers. 2015-07-05 16:29:27 -06:00
Stephen Olesen 7131e46ff0 Allow refclkOffset to be set on the fly in DDS and the calibration tool. 2015-07-04 18:31:18 -06:00
Stephen Olesen 1c29498e44 Received frequency calculation added. 2015-07-04 16:39:17 -06:00
Stephen Olesen 4af33167a0 Added Crystal Calibration sketch with simple Serial UI. Fixed ddsAccumulator_t type. 2015-07-04 14:13:45 -06:00
Stephen Olesen 7c67a704c3 Use HamShield now, fix refclk rate, increase toggle speed. 2015-07-04 02:17:03 -06:00
Stephen Olesen ed594d3128 Back to Wire library usage, mistaken commit on changing it. 2015-07-04 00:03:12 -06:00
Stephen Olesen f30f9003c1 Merge remote-tracking branch 'upstream/master' into afsk 2015-07-03 23:56:00 -06:00
Nigel VH 167c792116 Merge pull request #6 from slepp/master
Move singleton to the initializer to be used by more things later
2015-07-03 22:55:20 -07:00
Stephen Olesen c708b3703a Merge remote-tracking branch 'upstream/master' into afsk 2015-07-03 23:54:34 -06:00
Nigel VH 1257cb0b4b Merge pull request #3 from slepp/morse-clean
Clean (no whitespace changes) of the Morse table changes.
2015-07-03 22:51:54 -07:00
Stephen Olesen 8ebeabe496 Now using actual radio hardware in AFSK and SSTV. Tuned Tx settling timers. 2015-07-03 21:21:51 -06:00
Stephen Olesen 208087693d Pretty basic SSTV transmitter in Martin-1. Sends a static image. 2015-07-03 15:24:17 -06:00
Stephen Olesen acc4aebe03 Add calculators for frequency steps. Accumulator has a typedef now. Optimize tick. 2015-07-03 15:23:39 -06:00
Stephen Olesen 5fd0fdf154 Merge branch 'master' into afsk 2015-07-02 21:32:54 -06:00
Stephen Olesen 1aa7f7d224 Merge remote-tracking branch 'upstream/master' 2015-07-02 21:32:24 -06:00
Stephen Olesen 28248365c8 Added QPSK63. Set both sketches to run on either pin 3 or 11. 2015-07-02 21:27:12 -06:00
Stephen Olesen 26ffcd332b Faster reference clock rate (using pin 3), skip outer loop to slow PSK. 2015-07-02 19:58:54 -06:00
Stephen Olesen 77a8c62b78 Correct Pin 3 output to scale to the reduced comparator size. 2015-07-02 19:57:32 -06:00
Stephen Olesen 6ff2791963 Change to the waveform shaping trying to reduce IMD. 2015-07-02 19:31:16 -06:00
Stephen Olesen 7db28bff0e Change DDS to using signed integers to try to keep our DC bias averaged out. 2015-07-02 19:30:53 -06:00
Stephen Olesen 437e750e76 Rough PSK31 example, constant transmit of a string. 2015-07-02 18:06:57 -06:00
Stephen Olesen 2152100873 Change amplitude scaling. Go back to refclk for ICR1. Added phase changes. 2015-07-02 18:04:12 -06:00
Stephen Olesen 0e9a549f56 Fix a compile error. Add a quick callsign appending string method. 2015-07-02 02:38:28 -06:00
Stephen Olesen 4a8e9c69e6 Workaround for lockup on AFSK/DDS startup when using the Wire library. 2015-07-02 01:32:00 -06:00
Stephen Olesen 8e8c88f67c Stop transmitting (in a hackish way) when the TX is done. 2015-07-02 01:31:36 -06:00
Stephen Olesen 13be6810f1 Modified to initialize and try to use the radio. 2015-07-02 01:26:47 -06:00
Stephen Olesen 80a1741575 Preliminary addition of static memory allocations for packet buffers.
Fixed(?) DDS frequency calculation on-chip.
2015-07-02 01:24:55 -06:00
Stephen Olesen d2dc9adbc0 Remove ISR from HamShield, add DDS header. 2015-07-01 20:47:56 -06:00
Stephen Olesen 429e645ad2 Example for AFSK sending (AX25 format) added. DDS updated to a slower clock rate again. 2015-07-01 20:30:49 -06:00
Stephen Olesen 5689393c11 Replace local DDS with the DDS class. 2015-07-01 18:25:59 -06:00
Stephen Olesen 660fe0c602 Corrected the duration calculation on fixed DDS length. 2015-07-01 18:05:17 -06:00
Stephen Olesen 120442533d Added DDS sample. Fixed pin 11 PWM output, now default (3 works better). 2015-07-01 17:56:40 -06:00
Stephen Olesen 016ad2398a Added a define to use pin 3 for PWM, instead of the new default pin 11. 2015-07-01 15:01:55 -06:00
Stephen Olesen 8f2115adbc Add some comments. 2015-07-01 14:54:22 -06:00
Stephen Olesen 2f4d17e4ed Fixed up the duration timers, clockTick needs a cleanup. 2015-07-01 14:42:20 -06:00
Stephen Olesen 31eb465ebf Allow for high idle duty cycle when output is 'off', amplitude adjustments. 2015-07-01 14:27:10 -06:00
Stephen Olesen 1117542411 Created generic DDS class for tone generation, update AFSK to start the right timers. 2015-07-01 14:04:20 -06:00
Stephen Olesen 55c10c503b Some spacing, added header length minimum. 2015-06-30 20:32:28 -06:00
Stephen Olesen 9b2987de08 Initial import of the main code from https://github.com/slepp/AX25
Partially functional, but no accuracy tests complete yet.
2015-06-30 19:22:46 -06:00
Stephen Olesen 6a5815d9b5 Move singleton to the initializer to be used by more things later. Made public. 2015-06-30 16:37:55 -06:00
Stephen Olesen 0fd2d484e1 Added back in the tone waits in morseOut. 2015-06-30 16:03:21 -06:00
Stephen Olesen fc09429133 Alter morseOut to use a for loop and clearer dit/dah timing in the tone.
Back up to 1000Hz tones.
2015-06-30 15:30:06 -06:00
Stephen Olesen 1c7dbfc4b6 Correct the return time on morseLookup to be more obvious it's binary. 2015-06-30 15:17:07 -06:00
Stephen Olesen 7dff74d780 Clean version of the Morse binary format/table and lookup functions. 2015-06-30 15:13:55 -06:00
41 changed files with 7139 additions and 4659 deletions

File diff suppressed because it is too large Load Diff

View File

@ -1,558 +0,0 @@
// HamShield library collection
// Based on Programming Manual rev. 2.0, 5/19/2011 (RM-MPU-6000A-00)
// 11/22/2013 by Morgan Redfield <redfieldm@gmail.com>
// 04/26/2015 various changes Casey Halverson <spaceneedle@gmail.com>
#ifndef _HAMSHIELD_H_
#define _HAMSHIELD_H_
#include "I2Cdev_rda.h"
#include <avr/pgmspace.h>
// HamShield constants
#define HAMSHIELD_MORSE_DOT 100 // Morse code dot length (smaller is faster WPM)
#define HAMSHIELD_MORSE_BUFFER_SIZE 80 // Char buffer size for morse code text
#define HAMSHIELD_AUX_BUTTON 5 // Pin assignment for AUX button
#define HAMSHIELD_PWM_PIN 11 // Pin assignment for PWM output
#define HAMSHIELD_EMPTY_CHANNEL_RSSI -110 // Default threshold where channel is considered "clear"
// button modes
#define PTT_MODE 1
#define RESET_MODE 2
// Device Constants
#define A1846S_DEV_ADDR_SENHIGH 0b0101110
#define A1846S_DEV_ADDR_SENLOW 0b1110001
// Device Registers
#define A1846S_CTL_REG 0x30 // control register
#define A1846S_CLK_MODE_REG 0x04 // clk_mode
#define A1846S_PABIAS_REG 0x0A // control register for bias voltage
//#define A1846S_BAND_SEL_REG 0x0F // band_sel register <1:0>
#define A1846S_GPIO_MODE_REG 0x1F // GPIO mode select register
#define A1846S_FREQ_HI_REG 0x29 // freq<29:16>
#define A1846S_FREQ_LO_REG 0x2A // freq<15:0>
//#define A1846S_XTAL_FREQ_REG 0x2B // xtal_freq<15:0>
//#define A1846S_ADCLK_FREQ_REG 0x2C // adclk_freq<15:0>
#define A1846S_INT_MODE_REG 0x2D // interrupt enables
#define A1846S_TX_VOICE_REG 0x3A // tx voice control reg
#define A1846S_TH_H_VOX_REG 0x41 // register holds vox high (open) threshold bits
#define A1846S_TH_L_VOX_REG 0x42 // register holds vox low (shut) threshold bits
#define A1846S_FM_DEV_REG 0x43 // register holds fm deviation settings
#define A1846S_RX_VOLUME_REG 0x44 // register holds RX volume settings
#define A1846S_SUBAUDIO_REG 0x45 // sub audio register
#define A1846S_SQ_OPEN_THRESH_REG 0x48 // see sq
#define A1846S_SQ_SHUT_THRESH_REG 0x49 // see sq
#define A1846S_CTCSS_FREQ_REG 0x4A // ctcss_freq<15:0>
#define A1846S_CDCSS_CODE_HI_REG 0x4B // cdcss_code<23:16>
#define A1846S_CDCSS_CODE_LO_REG 0x4C // cdccs_code<15:0>
#define A1846S_SQ_OUT_SEL_REG 0x54 // see sq
#define A1846S_EMPH_FILTER_REG 0x58
#define A1846S_FLAG_REG 0x5C // holds flags for different statuses
#define A1846S_RSSI_REG 0x1B // holds RSSI (unit 1dB)
#define A1846S_VSSI_REG 0x1A // holds VSSI (unit mV)
#define A1846S_DTMF_CTL_REG 0x63 // see dtmf
#define A1846S_DTMF_C01_REG 0x66 // holds frequency value for c0 and c1
#define A1846S_DTMF_C23_REG 0x67 // holds frequency value for c2 and c3
#define A1846S_DTMF_C45_REG 0x68 // holds frequency value for c4 and c5
#define A1846S_DTMF_C67_REG 0x69 // holds frequency value for c6 and c7
#define A1846S_DTMF_RX_REG 0x6C // received dtmf signal
// NOTE: could add registers and bitfields for dtmf tones, is this necessary?
// Device Bit Fields
// Bitfields for A1846S_CTL_REG
#define A1846S_CHAN_MODE_BIT 13 //channel_mode<1:0>
#define A1846S_CHAN_MODE_LENGTH 2
#define A1846S_TAIL_ELIM_EN_BIT 11 // enables tail elim when set to 1
#define A1846S_ST_MODE_BIT 9 // set mode for txon and rxon
#define A1846S_ST_MODE_LENGTH 2
#define A1846S_MUTE_BIT 7 // 0 no mute, 1 mute when rxno
#define A1846S_TX_MODE_BIT 6 //tx-on
#define A1846S_RX_MODE_BIT 5 //rx-on
#define A1846S_VOX_ON_BIT 4 // 0 off, 1 on and chip auto-vox
#define A1846S_SQ_ON_BIT 3 // auto sq enable bit
#define A1846S_PWR_DWN_BIT 2 // power control bit
#define A1846S_CHIP_CAL_EN_BIT 1 // 0 cal disable, 1 cal enable
#define A1846S_SOFT_RESET_BIT 0 // 0 normal value, 1 reset all registers to normal value
// Bitfields for A1846S_CLK_MODE_REG
#define A1846S_CLK_MODE_BIT 0 // 0 24-28MHz, 1 12-14MHz
// Bitfields for A1846S_PABIAS_REG
#define A1846S_PABIAS_BIT 5 // pabias_voltage<5:0>
#define A1846S_PABIAS_LENGTH 6
#define A1846S_PADRV_BIT 14 // pabias_voltage<14:11>
#define A1846S_PADRV_LENGTH 4
// Bitfields for A1846S_BAND_SEL_REG
//#define A1846S_BAND_SEL_BIT 7 // band_sel<1:0>
//#define A1846S_BAND_SEL_LENGTH 2
// Bitfields for RDA1864_GPIO_MODE_REG
#define RDA1864_GPIO7_MODE_BIT 15 // <1:0> 00=hi-z,01=vox,10=low,11=hi
#define RDA1864_GPIO7_MODE_LENGTH 2
#define RDA1864_GPIO6_MODE_BIT 13 // <1:0> 00=hi-z,01=sq or =sq&ctcss/cdcss when sq_out_sel=1,10=low,11=hi
#define RDA1864_GPIO6_MODE_LENGTH 2
#define RDA1864_GPIO5_MODE_BIT 11 // <1:0> 00=hi-z,01=txon_rf,10=low,11=hi
#define RDA1864_GPIO5_MODE_LENGTH 2
#define RDA1864_GPIO4_MODE_BIT 9 // <1:0> 00=hi-z,01=rxon_rf,10=low,11=hi
#define RDA1864_GPIO4_MODE_LENGTH 2
#define RDA1864_GPIO3_MODE_BIT 7 // <1:0> 00=hi-z,01=sdo,10=low,11=hi
#define RDA1864_GPIO3_MODE_LENGTH 2
#define RDA1864_GPIO2_MODE_BIT 5 // <1:0> 00=hi-z,01=int,10=low,11=hi
#define RDA1864_GPIO2_MODE_LENGTH 2
#define RDA1864_GPIO1_MODE_BIT 3 // <1:0> 00=hi-z,01=code_out/code_in,10=low,11=hi
#define RDA1864_GPIO1_MODE_LENGTH 2
#define RDA1864_GPIO0_MODE_BIT 1 // <1:0> 00=hi-z,01=css_out/css_in/css_cmp,10=low,11=hi
#define RDA1864_GPIO0_MODE_LENGTH 2
// Bitfields for A1846S_INT_MODE_REG
#define A1846S_CSS_CMP_INT_BIT 9 // css_cmp_uint16_t enable
#define A1846S_RXON_RF_INT_BIT 8 // rxon_rf_uint16_t enable
#define A1846S_TXON_RF_INT_BIT 7 // txon_rf_uint16_t enable
#define A1846S_DTMF_IDLE_INT_BIT 6 // dtmf_idle_uint16_t enable
#define A1846S_CTCSS_PHASE_INT_BIT 5 // ctcss phase shift detect uint16_t enable
#define A1846S_IDLE_TIMEOUT_INT_BIT 4 // idle state time out uint16_t enable
#define A1846S_RXON_RF_TIMeOUT_INT_BIT 3 // rxon_rf timerout uint16_t enable
#define A1846S_SQ_INT_BIT 2 // sq uint16_t enable
#define A1846S_TXON_RF_TIMEOUT_INT_BIT 1 // txon_rf time out uint16_t enable
#define A1846S_VOX_INT_BIT 0 // vox uint16_t enable
// Bitfields for A1846S_TX_VOICE_REG
#define A1846S_VOICE_SEL_BIT 14 //voice_sel<1:0>
#define A1846S_VOICE_SEL_LENGTH 3
// Bitfields for A1846S_TH_H_VOX_REG
#define A1846S_TH_H_VOX_BIT 14 // th_h_vox<14:0>
#define A1846S_TH_H_VOX_LENGTH 15
// Bitfields for A1846S_FM_DEV_REG
#define A1846S_FM_DEV_VOICE_BIT 12 // CTCSS/CDCSS and voice deviation <6:0>
#define A1846S_FM_DEV_VOICE_LENGTH 7
#define A1846S_FM_DEV_CSS_BIT 5 // CTCSS/CDCSS deviation only <5:0>
#define A1846S_FM_DEV_CSS_LENGTH 6
// Bitfields for A1846S_RX_VOLUME_REG
#define A1846S_RX_VOL_1_BIT 7 // volume 1 <3:0>, (0000)-15dB~(1111)0dB, step 1dB
#define A1846S_RX_VOL_1_LENGTH 4
#define A1846S_RX_VOL_2_BIT 3 // volume 2 <3:0>, (0000)-15dB~(1111)0dB, step 1dB
#define A1846S_RX_VOL_2_LENGTH 4
// Bitfields for A1846S_SUBAUDIO_REG Sub Audio Register
#define A1846S_SHIFT_SEL_BIT 15 // shift_sel<1:0> see eliminating tail noise
#define A1846S_SHIFT_SEL_LENGTH 2
#define A1846S_POS_DET_EN_BIT 11 // if 1, cdcss code will be detected
#define A1846S_CSS_DET_EN_BIT 10 // 1 - sq detect will add ctcss/cdcss detect result and control voice output on or off
#define A1846S_NEG_DET_EN_BIT 7 // if 1, cdcss inverse code will be detected at same time
#define A1846S_CDCSS_SEL_BIT 4 // cdcss_sel
#define A1846S_CTCSS_SEL_BIT 3 // ctcss_sel
#define A1846S_C_MODE_BIT 2 // c_mode<2:0>
#define A1846S_C_MODE_LENGTH 3
// Bitfields for A1846S_SQ_THRESH_REG
#define A1846S_SQ_OPEN_THRESH_BIT 9 // sq open threshold <9:0>
#define A1846S_SQ_OPEN_THRESH_LENGTH 10
// Bitfields for A1846S_SQ_SHUT_THRESH_REG
#define A1846S_SQ_SHUT_THRESH_BIT 9 // sq shut threshold <9:0>
#define A1846S_SQ_SHUT_THRESH_LENGTH 10
// Bitfields for A1846S_SQ_OUT_SEL_REG
#define A1846S_SQ_OUT_SEL_BIT 7 // sq_out_sel
// Bitfields for A1846S_EMPH_FILTER_REG
#define A1846S_EMPH_FILTER_EN 3
// Bitfields for A1846S_FLAG_REG
#define A1846S_DTMF_IDLE_FLAG_BIT 12 // dtmf idle flag
#define A1846S_RXON_RF_FLAG_BIT 10 // 1 when rxon is enabled
#define A1846S_TXON_RF_FLAG_BIT 9 // 1 when txon is enabled
#define A1846S_INVERT_DET_FLAG_BIT 7 // ctcss phase shift detect
#define A1846S_CSS_CMP_FLAG_BIT 2 // ctcss/cdcss compared
#define A1846S_SQ_FLAG_BIT 1 // sq final signal out from dsp
#define A1846S_VOX_FLAG_BIT 0 // vox out from dsp
// Bitfields for A1846S_RSSI_REG
#define A1846S_RSSI_BIT 15 // RSSI readings <9:0>
#define A1846S_RSSI_LENGTH 8
// Bitfields for A1846S_VSSI_REG
#define A1846S_VSSI_BIT 14 // voice signal strength indicator <14:0> (unit mV)
#define A1846S_VSSI_LENGTH 15
// Bitfields for A1846S_DTMF_CTL_REG
#define A1846S_DTMF_MODE_BIT 9 //
#define A1846S_DTMF_MODE_LENGTH 2
#define A1846S_DTMF_EN_BIT 8 // enable dtmf
#define A1846S_DTMF_TIME1_BIT 7 // dtmf time 1 <3:0>
#define A1846S_DTMF_TIME1_LENGTH 4
#define A1846S_DTMF_TIME2_BIT 3 // dtmf time 2 <3:0>
#define A1846S_DTMF_TIME2_LENGTH 4
// Bitfields for A1846S_DTMF_RX_REG
#define A1846S_DTMF_INDEX_BIT 10 // dtmf index <5:3> - tone 1 detect index, <2:0> - tone 2 detect index
#define A1846S_DTMF_INDEX_LENGTH 6
#define A1846S_DTMF_TONE1_IND_BIT 10
#define A1846S_DTMF_TONE1_IND_LENGTH 3
#define A1846S_DTMF_TONE2_IND_BIT 7
#define A1846S_DTMF_TONE2_IND_LENGTH 3
#define A1846S_DTMF_FLAG_BIT 4
#define A1846S_DTMF_CODE_BIT 3 // dtmf code out <3:0>
#define A1846S_DTMF_CODE_LENGTH 4
// dtmf code out
// 1:f0+f4, 2:f0+f5, 3:f0+f6, A:f0+f7,
// 4:f1+f4, 5:f1+f5, 6:f1+f6, B:f1+f7,
// 7:f2+f4, 8:f2+f5, 9:f2+f6, C:f2+f7,
// E(*):f3+f4, 0:f3+f5, F(#):f3+f6, D:f3+f7
// Bitfields for DTMF registers
#define A1846S_DTMF_C0_BIT 15
#define A1846S_DTMF_C0_LENGTH 8
#define A1846S_DTMF_C1_BIT 7
#define A1846S_DTMF_C1_LENGTH 8
#define A1846S_DTMF_C2_BIT 15
#define A1846S_DTMF_C2_LENGTH 8
#define A1846S_DTMF_C3_BIT 7
#define A1846S_DTMF_C3_LENGTH 8
#define A1846S_DTMF_C4_BIT 15
#define A1846S_DTMF_C4_LENGTH 8
#define A1846S_DTMF_C5_BIT 7
#define A1846S_DTMF_C5_LENGTH 8
#define A1846S_DTMF_C6_BIT 15
#define A1846S_DTMF_C6_LENGTH 8
#define A1846S_DTMF_C7_BIT 7
#define A1846S_DTMF_C7_LENGTH 8
// SSTV VIS Codes
#define ROBOT8BW 2
#define SC2-180 55
#define MARTIN1 44
// RTTY Frequencies
#define HAMSHIELD_RTTY_FREQ 2200
#define HAMSHIELD_RTTY_SHIFT 850
#define HAMSHIELD_RTTY_BAUD 75
// PSK31 Frequencies
#define HAMSHIELD_PSK31_FREQ 1000
class HamShield {
public:
HamShield();
HamShield(uint8_t address);
void initialize();
bool testConnection();
// read control reg
uint16_t readCtlReg();
void softReset();
// center frequency
void setFrequency(uint32_t freq_khz);
uint32_t getFrequency();
// band
// 00 - 400-520MHz
// 10 - 200-260MHz
// 11 - 134-174MHz
void setBand(uint16_t band);
uint16_t getBand();
void setUHF();
void setVHF();
void setNoFilters();
bool frequency(uint32_t freq_khz);
// xtal frequency (kHz)
// 12-14MHz crystal: this reg is set to crystal freq_khz
// 24-28MHz crystal: this reg is set to crystal freq_khz / 2
void setXtalFreq(uint16_t freq_kHz);
uint16_t getXtalFreq();
// adclk frequency (kHz)
// 12-14MHz crystal: this reg is set to crystal freq_khz / 2
// 24-28MHz crystal: this reg is set to crystal freq_khz / 4
void setAdcClkFreq(uint16_t freq_kHz);
uint16_t getAdcClkFreq();
// clk mode
// 12-14MHz: set to 1
// 24-28MHz: set to 0
void setClkMode(bool LFClk);
bool getClkMode();
// clk example
// 12.8MHz clock
// A1846S_XTAL_FREQ_REG[15:0]= xtal_freq<15:0>=12.8*1000=12800
// A1846S_ADCLK_FREQ_REG[12:0] =adclk_freq<15:0>=(12.8/2)*1000=6400
// A1846S_CLK_MODE_REG[0]= clk_mode =1
// TX/RX control
// channel mode
// 11 - 25kHz channel
// 00 - 12.5kHz channel
// 10,01 - reserved
void setChanMode(uint16_t mode);
uint16_t getChanMode();
// choose tx or rx
void setTX(bool on_noff);
bool getTX();
void setRX(bool on_noff);
bool getRX();
void setModeTransmit(); // turn off rx, turn on tx
void setModeReceive(); // turn on rx, turn off tx
void setModeOff(); // turn off rx, turn off tx, set pwr_dwn bit
// set tx source
// 00 - Mic source
// 01 - sine source from tone2
// 10 - tx code from GPIO1 code_in (gpio1<1:0> must be set to 01)
// 11 - no tx source
void setTxSource(uint16_t tx_source);
void setTxSourceMic();
void setTxSourceTone1();
void setTxSourceTone2();
void setTxSourceTones();
void setTxSourceNone();
uint16_t getTxSource();
// set PA_bias voltage
// 000000: 1.01V
// 000001:1.05V
// 000010:1.09V
// 000100: 1.18V
// 001000: 1.34V
// 010000: 1.68V
// 100000: 2.45V
// 1111111:3.13V
void setPABiasVoltage(uint16_t voltage);
uint16_t getPABiasVoltage();
// Subaudio settings
// Ctcss/cdcss mode sel
// x00=disable,
// 001=inner ctcss en,
// 010= inner cdcss en
// 101= outer ctcss en,
// 110=outer cdcss en
// others =disable
void setCtcssCdcssMode(uint16_t mode);
uint16_t getCtcssCdcssMode();
void setInnerCtcssMode();
void setInnerCdcssMode();
void setOuterCtcssMode();
void setOuterCdcssMode();
void disableCtcssCdcss();
// Ctcss_sel
// 1 = ctcss_cmp/cdcss_cmp out via gpio
// 0 = ctcss/cdcss sdo out vio gpio
void setCtcssSel(bool cmp_nsdo);
bool getCtcssSel();
// Cdcss_sel
// 1 = long (24 bit) code
// 0 = short(23 bit) code
void setCdcssSel(bool long_nshort);
bool getCdcssSel();
// Cdcss neg_det_en
void enableCdcssNegDet();
void disableCdcssNegDet();
bool getCdcssNegDetEnabled();
// Cdcss pos_det_en
void enableCdcssPosDet();
void disableCdcssPosDet();
bool getCdcssPosDetEnabled();
// css_det_en
void enableCssDet();
void disableCssDet();
bool getCssDetEnabled();
// ctcss freq
void setCtcss(float freq);
void setCtcssFreq(uint16_t freq);
uint16_t getCtcssFreq();
void setCtcssFreqToStandard(); // freq must be 134.4Hz for standard cdcss mode
// cdcss codes
void setCdcssCode(uint16_t code);
uint16_t getCdcssCode();
// SQ
void setSQOn();
void setSQOff();
bool getSQState();
// SQ threshold
void setSQHiThresh(uint16_t sq_hi_threshold); // Sq detect high th, rssi_cmp will be 1 when rssi>th_h_sq, unit 1/8dB
uint16_t getSQHiThresh();
void setSQLoThresh(uint16_t sq_lo_threshold); // Sq detect low th, rssi_cmp will be 0 when rssi<th_l_sq && time delay meet, unit 1/8 dB
uint16_t getSQLoThresh();
// SQ out select
void setSQOutSel();
void clearSQOutSel();
bool getSQOutSel();
// VOX
void setVoxOn();
void setVoxOff();
bool getVoxOn();
// Vox Threshold
void setVoxOpenThresh(uint16_t vox_open_thresh); // When vssi > th_h_vox, then vox will be 1(unit mV )
uint16_t getVoxOpenThresh();
void setVoxShutThresh(uint16_t vox_shut_thresh); // When vssi < th_l_vox && time delay meet, then vox will be 0 (unit mV )
uint16_t getVoxShutThresh();
// Tail Noise
void enableTailNoiseElim();
void disableTailNoiseElim();
bool getTailNoiseElimEnabled();
// tail noise shift select
// Select ctcss phase shift when use tail eliminating function when TX
// 00 = 120 degree shift
// 01 = 180 degree shift
// 10 = 240 degree shift
// 11 = reserved
void setShiftSelect(uint16_t shift_sel);
uint16_t getShiftSelect();
// DTMF
void setDTMFC0(uint16_t freq);
uint16_t getDTMFC0();
void setDTMFC1(uint16_t freq);
uint16_t getDTMFC1();
void setDTMFC2(uint16_t freq);
uint16_t getDTMFC2();
void setDTMFC3(uint16_t freq);
uint16_t getDTMFC3();
void setDTMFC4(uint16_t freq);
uint16_t getDTMFC4();
void setDTMFC5(uint16_t freq);
uint16_t getDTMFC5();
void setDTMFC6(uint16_t freq);
uint16_t getDTMFC6();
void setDTMFC7(uint16_t freq);
uint16_t getDTMFC7();
// TX FM deviation
void setFMVoiceCssDeviation(uint16_t deviation);
uint16_t getFMVoiceCssDeviation();
void setFMCssDeviation(uint16_t deviation);
uint16_t getFMCssDeviation();
// RX voice range
void setVolume1(uint16_t volume);
uint16_t getVolume1();
void setVolume2(uint16_t volume);
uint16_t getVolume2();
// GPIO
void setGpioMode(uint16_t gpio, uint16_t mode);
void setGpioHiZ(uint16_t gpio);
void setGpioFcn(uint16_t gpio);
void setGpioLow(uint16_t gpio);
void setGpioHi(uint16_t gpio);
uint16_t getGpioMode(uint16_t gpio);
// Int
void enableInterrupt(uint16_t interrupt);
void disableInterrupt(uint16_t interrupt);
bool getInterruptEnabled(uint16_t interrupt);
// ST mode
void setStMode(uint16_t mode);
uint16_t getStMode();
void setStFullAuto();
void setStRxAutoTxManu();
void setStFullManu();
// Pre-emphasis, De-emphasis filter
void bypassPreDeEmph();
void usePreDeEmph();
bool getPreDeEmphEnabled();
// Read Only Status Registers
int16_t readRSSI();
uint16_t readVSSI();
uint16_t readDTMFIndex(); // may want to split this into two (index1 and index2)
uint16_t readDTMFCode();
// set output power of radio
void setRfPower(uint8_t pwr);
// channel helper functions
bool setGMRSChannel(uint8_t channel);
bool setFRSChannel(uint8_t channel);
bool setMURSChannel(uint8_t channel);
bool setWXChannel(uint8_t channel);
uint8_t scanWXChannel();
// restrictions control
void dangerMode();
void safeMode();
// utilities
uint32_t scanMode(uint32_t start,uint32_t stop, uint8_t speed, uint16_t step, uint16_t threshold);
uint32_t findWhitespace(uint32_t start,uint32_t stop, uint8_t dwell, uint16_t step, uint16_t threshold);
uint32_t scanChannels(uint32_t buffer[],uint8_t buffsize, uint8_t speed, uint16_t threshold);
uint32_t findWhitespaceChannels(uint32_t buffer[],uint8_t buffsize, uint8_t dwell, uint16_t threshold);
void buttonMode(uint8_t mode);
static void isr_ptt();
static void isr_reset();
void morseOut(char buffer[HAMSHIELD_MORSE_BUFFER_SIZE]);
char morseLookup(char letter);
bool waitForChannel(long timeout, long breakwindow, int setRSSI);
void SSTVVISCode(int code);
void SSTVTestPattern(int code);
void toneWait(uint16_t freq, long timer);
void toneWaitU(uint16_t freq, long timer);
bool parityCalc(int code);
// void AFSKOut(char buffer[80]);
private:
uint8_t devAddr;
uint16_t radio_i2c_buf[4];
int pwr_control_pin;
uint32_t radio_frequency;
uint32_t FRS[];
uint32_t GMRS[];
uint32_t MURS[];
uint32_t WX[];
static HamShield *sHamShield; // HamShield singleton, used for ISRs mostly
// int8_t A1846S::readWord(uint8_t devAddr, uint8_t regAddr, uint16_t *data, uint16_t timeout);
// int8_t A1846S::readBits(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint16_t *data, uint16_t timeout);
// int8_t A1846S::readBit(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint16_t *data, uint16_t timeout);
// int8_t A1846S::writeWord(uint8_t devAddr, uint8_t regAddr, uint16_t *data, uint16_t timeout);
// bool A1846S::writeBits(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint16_t data);
// bool A1846S::writeBit(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint16_t data);
};
#endif /* _HAMSHIELD_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -1,269 +0,0 @@
// I2Cdev library collection - Main I2C device class header file
// Abstracts bit and byte I2C R/W functions into a convenient class
// 6/9/2012 by Jeff Rowberg <jeff@rowberg.net>
//
// Changelog:
// 2013-05-06 - add Francesco Ferrara's Fastwire v0.24 implementation with small modifications
// 2013-05-05 - fix issue with writing bit values to words (Sasquatch/Farzanegan)
// 2012-06-09 - fix major issue with reading > 32 bytes at a time with Arduino Wire
// - add compiler warnings when using outdated or IDE or limited I2Cdev implementation
// 2011-11-01 - fix write*Bits mask calculation (thanks sasquatch @ Arduino forums)
// 2011-10-03 - added automatic Arduino version detection for ease of use
// 2011-10-02 - added Gene Knight's NBWire TwoWire class implementation with small modifications
// 2011-08-31 - added support for Arduino 1.0 Wire library (methods are different from 0.x)
// 2011-08-03 - added optional timeout parameter to read* methods to easily change from default
// 2011-08-02 - added support for 16-bit registers
// - fixed incorrect Doxygen comments on some methods
// - added timeout value for read operations (thanks mem @ Arduino forums)
// 2011-07-30 - changed read/write function structures to return success or byte counts
// - made all methods static for multi-device memory savings
// 2011-07-28 - initial release
/* ============================================
I2Cdev device library code is placed under the MIT license
Copyright (c) 2013 Jeff Rowberg
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
===============================================
*/
#ifndef _I2CDEV_RDA_H_
#define _I2CDEV_RDA_H_
// -----------------------------------------------------------------------------
// I2C interface implementation setting
// -----------------------------------------------------------------------------
#define I2CDEV_IMPLEMENTATION I2CDEV_ARDUINO_WIRE
//#define I2CDEV_IMPLEMENTATION I2CDEV_BUILTIN_FASTWIRE
// comment this out if you are using a non-optimal IDE/implementation setting
// but want the compiler to shut up about it
#define I2CDEV_IMPLEMENTATION_WARNINGS
// -----------------------------------------------------------------------------
// I2C interface implementation options
// -----------------------------------------------------------------------------
#define I2CDEV_ARDUINO_WIRE 1 // Wire object from Arduino
#define I2CDEV_BUILTIN_NBWIRE 2 // Tweaked Wire object from Gene Knight's NBWire project
// ^^^ NBWire implementation is still buggy w/some interrupts!
#define I2CDEV_BUILTIN_FASTWIRE 3 // FastWire object from Francesco Ferrara's project
#define I2CDEV_I2CMASTER_LIBRARY 4 // I2C object from DSSCircuits I2C-Master Library at https://github.com/DSSCircuits/I2C-Master-Library
// -----------------------------------------------------------------------------
// Arduino-style "Serial.print" debug constant (uncomment to enable)
// -----------------------------------------------------------------------------
//#define I2CDEV_SERIAL_DEBUG
#ifdef ARDUINO
#if ARDUINO < 100
#include "WProgram.h"
#else
#include "Arduino.h"
#endif
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
#include <Wire.h>
#endif
#if I2CDEV_IMPLEMENTATION == I2CDEV_I2CMASTER_LIBRARY
#include <I2C.h>
#endif
#endif
// 1000ms default read timeout (modify with "I2Cdev::readTimeout = [ms];")
#define I2CDEV_DEFAULT_READ_TIMEOUT 1000
class I2Cdev {
public:
I2Cdev();
static int8_t readBit(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint8_t *data, uint16_t timeout=I2Cdev::readTimeout);
static int8_t readBitW(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint16_t *data, uint16_t timeout=I2Cdev::readTimeout);
static int8_t readBits(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint8_t *data, uint16_t timeout=I2Cdev::readTimeout);
static int8_t readBitsW(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint16_t *data, uint16_t timeout=I2Cdev::readTimeout);
static int8_t readByte(uint8_t devAddr, uint8_t regAddr, uint8_t *data, uint16_t timeout=I2Cdev::readTimeout);
static int8_t readWord(uint8_t devAddr, uint8_t regAddr, uint16_t *data, uint16_t timeout=I2Cdev::readTimeout);
static int8_t readBytes(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint8_t *data, uint16_t timeout=I2Cdev::readTimeout);
static int8_t readWords(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint16_t *data, uint16_t timeout=I2Cdev::readTimeout);
static bool writeBit(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint8_t data);
static bool writeBitW(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint16_t data);
static bool writeBits(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint8_t data);
static bool writeBitsW(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint16_t data);
static bool writeByte(uint8_t devAddr, uint8_t regAddr, uint8_t data);
static bool writeWord(uint8_t devAddr, uint8_t regAddr, uint16_t data);
static bool writeBytes(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint8_t *data);
static bool writeWords(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint16_t *data);
static uint16_t readTimeout;
};
#if I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
//////////////////////
// FastWire 0.24
// This is a library to help faster programs to read I2C devices.
// Copyright(C) 2012
// Francesco Ferrara
//////////////////////
/* Master */
#define TW_START 0x08
#define TW_REP_START 0x10
/* Master Transmitter */
#define TW_MT_SLA_ACK 0x18
#define TW_MT_SLA_NACK 0x20
#define TW_MT_DATA_ACK 0x28
#define TW_MT_DATA_NACK 0x30
#define TW_MT_ARB_LOST 0x38
/* Master Receiver */
#define TW_MR_ARB_LOST 0x38
#define TW_MR_SLA_ACK 0x40
#define TW_MR_SLA_NACK 0x48
#define TW_MR_DATA_ACK 0x50
#define TW_MR_DATA_NACK 0x58
#define TW_OK 0
#define TW_ERROR 1
class Fastwire {
private:
static boolean waitInt();
public:
static void setup(int khz, boolean pullup);
static byte beginTransmission(byte device);
static byte write(byte value);
static byte writeBuf(byte device, byte address, byte *data, byte num);
static byte readBuf(byte device, byte address, byte *data, byte num);
static void reset();
static byte stop();
};
#endif
#if I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_NBWIRE
// NBWire implementation based heavily on code by Gene Knight <Gene@Telobot.com>
// Originally posted on the Arduino forum at http://arduino.cc/forum/index.php/topic,70705.0.html
// Originally offered to the i2cdevlib project at http://arduino.cc/forum/index.php/topic,68210.30.html
#define NBWIRE_BUFFER_LENGTH 32
class TwoWire {
private:
static uint8_t rxBuffer[];
static uint8_t rxBufferIndex;
static uint8_t rxBufferLength;
static uint8_t txAddress;
static uint8_t txBuffer[];
static uint8_t txBufferIndex;
static uint8_t txBufferLength;
// static uint8_t transmitting;
static void (*user_onRequest)(void);
static void (*user_onReceive)(int);
static void onRequestService(void);
static void onReceiveService(uint8_t*, int);
public:
TwoWire();
void begin();
void begin(uint8_t);
void begin(int);
void beginTransmission(uint8_t);
//void beginTransmission(int);
uint8_t endTransmission(uint16_t timeout=0);
void nbendTransmission(void (*function)(int)) ;
uint8_t requestFrom(uint8_t, int, uint16_t timeout=0);
//uint8_t requestFrom(int, int);
void nbrequestFrom(uint8_t, int, void (*function)(int));
void send(uint8_t);
void send(uint8_t*, uint8_t);
//void send(int);
void send(char*);
uint8_t available(void);
uint8_t receive(void);
void onReceive(void (*)(int));
void onRequest(void (*)(void));
};
#define TWI_READY 0
#define TWI_MRX 1
#define TWI_MTX 2
#define TWI_SRX 3
#define TWI_STX 4
#define TW_WRITE 0
#define TW_READ 1
#define TW_MT_SLA_NACK 0x20
#define TW_MT_DATA_NACK 0x30
#define CPU_FREQ 16000000L
#define TWI_FREQ 100000L
#define TWI_BUFFER_LENGTH 32
/* TWI Status is in TWSR, in the top 5 bits: TWS7 - TWS3 */
#define TW_STATUS_MASK (_BV(TWS7)|_BV(TWS6)|_BV(TWS5)|_BV(TWS4)|_BV(TWS3))
#define TW_STATUS (TWSR & TW_STATUS_MASK)
#define TW_START 0x08
#define TW_REP_START 0x10
#define TW_MT_SLA_ACK 0x18
#define TW_MT_SLA_NACK 0x20
#define TW_MT_DATA_ACK 0x28
#define TW_MT_DATA_NACK 0x30
#define TW_MT_ARB_LOST 0x38
#define TW_MR_ARB_LOST 0x38
#define TW_MR_SLA_ACK 0x40
#define TW_MR_SLA_NACK 0x48
#define TW_MR_DATA_ACK 0x50
#define TW_MR_DATA_NACK 0x58
#define TW_ST_SLA_ACK 0xA8
#define TW_ST_ARB_LOST_SLA_ACK 0xB0
#define TW_ST_DATA_ACK 0xB8
#define TW_ST_DATA_NACK 0xC0
#define TW_ST_LAST_DATA 0xC8
#define TW_SR_SLA_ACK 0x60
#define TW_SR_ARB_LOST_SLA_ACK 0x68
#define TW_SR_GCALL_ACK 0x70
#define TW_SR_ARB_LOST_GCALL_ACK 0x78
#define TW_SR_DATA_ACK 0x80
#define TW_SR_DATA_NACK 0x88
#define TW_SR_GCALL_DATA_ACK 0x90
#define TW_SR_GCALL_DATA_NACK 0x98
#define TW_SR_STOP 0xA0
#define TW_NO_INFO 0xF8
#define TW_BUS_ERROR 0x00
//#define _MMIO_BYTE(mem_addr) (*(volatile uint8_t *)(mem_addr))
//#define _SFR_BYTE(sfr) _MMIO_BYTE(_SFR_ADDR(sfr))
#ifndef sbi // set bit
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif // sbi
#ifndef cbi // clear bit
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif // cbi
extern TwoWire Wire;
#endif // I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_NBWIRE
#endif /* _I2CDEV_RDA_H_ */

View File

@ -1,4 +1,23 @@
# HamShield
HamShield Arduino Library and Example Sketches
You can purchase HamShield (as well as smaller variants or LoRa version) at http://www.enhancedradio.com/
The master branch is intended for use with HamShield hardware -09 and above.
WARNING: The dev branch is not guaranteed to work. Please use caution if you choose to use that branch.
# HamShield Arduino Library and Example Sketches
This repository is meant to be checked out into your Arduino application's libraries folder. After reloading the application, the library and example sketches should be available for use.
For overview, help, tricks, tips, and more, check out the wiki:
https://github.com/EnhancedRadioDevices/HamShield/wiki
# KISS and AFSK
We've moved the KISS and AFSK code to a separate library to help keep memory usage in simple sketches down. To use the AFSK examples, please also install these libraries:
- https://github.com/EnhancedRadioDevices/DDS
- https://github.com/EnhancedRadioDevices/HamShield_KISS

View File

@ -0,0 +1,165 @@
/* Hamshield
* Example: AFSK Serial Messenger
* Serial glue to send messages over APRS. You will need a
* seperate AFSK receiver to test the output of this example.
* Connect the HamShield to your Arduino. Screw the antenna
* into the HamShield RF jack. After uploading this program
* to your Arduino, open the Serial Monitor to monitor. Type
* a message under 254 characters into the bar at the top of
* the monitor. Click the "Send" button. Check for output on
* AFSK receiver.
*
* To send a message: connect to the Arduino over a Serial link.
* Send the following over the serial link:
* `from,to,:message
* example: * KG7OGM,KG7OGM,:Hi there`
*/
#include <HamShield.h>
#include <DDS.h>
#include <packet.h>
#include <avr/wdt.h>
#define MIC_PIN 3
#define RESET_PIN A3
#define SWITCH_PIN 2
HamShield radio;
DDS dds;
AFSK afsk;
String messagebuff = "";
String origin_call = "";
String destination_call = "";
String textmessage = "";
int msgptr = 0;
void setup() {
// NOTE: if not using PWM out, it should be held low to avoid tx noise
pinMode(MIC_PIN, OUTPUT);
digitalWrite(MIC_PIN, LOW);
// prep the switch
// NOTE: HamShieldMini doesn't have a reset pin, so this has no effect
pinMode(SWITCH_PIN, INPUT_PULLUP);
// set up the reset control pin
pinMode(RESET_PIN, OUTPUT);
// turn on the radio
digitalWrite(RESET_PIN, HIGH);
delay(5); // wait for device to come up
Serial.begin(9600);
radio.initialize();
radio.frequency(144390); // default aprs frequency in North America
radio.setRfPower(0);
radio.setVolume1(0xFF);
radio.setVolume2(0xFF);
radio.setSQHiThresh(-100);
radio.setSQLoThresh(-100);
//radio.setSQOn();
radio.bypassPreDeEmph();
dds.start();
afsk.start(&dds);
delay(100);
radio.setModeReceive();
Serial.println("HELLO");
}
void loop() {
if(Serial.available()) {
char temp = (char)Serial.read();
if(temp == '`') {
//Serial.println(messagebuff);
prepMessage();
msgptr = 0;
messagebuff = "";
Serial.print("!!");
}
else {
messagebuff += temp;
msgptr++;
}
}
if(msgptr > 254) { messagebuff = ""; Serial.print("X!"); }
if(afsk.decoder.read() || afsk.rxPacketCount()) {
// A true return means something was put onto the packet FIFO
// If we actually have data packets in the buffer, process them all now
while(afsk.rxPacketCount()) {
AFSK::Packet *packet = afsk.getRXPacket();
Serial.print(F("Packet: "));
if(packet) {
packet->printPacket(&Serial);
AFSK::PacketBuffer::freePacket(packet);
}
}
}
}
void prepMessage() {
radio.setModeTransmit();
delay(1000);
origin_call = messagebuff.substring(0,messagebuff.indexOf(',')); // get originating callsign
destination_call = messagebuff.substring(messagebuff.indexOf(',')+1,messagebuff.indexOf(',',messagebuff.indexOf(',')+1)); // get the destination call
textmessage = messagebuff.substring(messagebuff.indexOf(":")+1);
// Serial.print("From: "); Serial.print(origin_call); Serial.print(" To: "); Serial.println(destination_call); Serial.println("Text: "); Serial.println(textmessage);
AFSK::Packet *packet = AFSK::PacketBuffer::makePacket(22 + 32);
packet->start();
packet->appendCallsign(origin_call.c_str(),0);
packet->appendCallsign(destination_call.c_str(),15,true);
packet->appendFCS(0x03);
packet->appendFCS(0xf0);
packet->print(textmessage);
packet->finish();
bool ret = afsk.putTXPacket(packet);
if(afsk.txReady()) {
Serial.println(F("txReady"));
radio.setModeTransmit();
//delay(100);
if(afsk.txStart()) {
Serial.println(F("txStart"));
} else {
radio.setModeReceive();
}
}
// Wait 2 seconds before we send our beacon again.
Serial.println("tick");
// Wait up to 2.5 seconds to finish sending, and stop transmitter.
// TODO: This is hackery.
for(int i = 0; i < 500; i++) {
if(afsk.encoder.isDone())
break;
delay(50);
}
Serial.println("Done sending");
radio.setModeReceive();
}
ISR(TIMER2_OVF_vect) {
TIFR2 = _BV(TOV2);
static uint8_t tcnt = 0;
if(++tcnt == 8) {
dds.clockTick();
tcnt = 0;
}
}
ISR(ADC_vect) {
static uint8_t tcnt = 0;
TIFR1 = _BV(ICF1); // Clear the timer flag
dds.clockTick();
if(++tcnt == 1) {
afsk.timer();
tcnt = 0;
}
}

View File

View File

View File

@ -0,0 +1,182 @@
/* Hamshield
* Example: SerialController
* This application is used in conjunction with a computer to provide full serial control of HamShield.
*/
#include <HamShield.h>
#define MIC_PIN 3
#define RESET_PIN A3
#define SWITCH_PIN 2
HamShield radio;
uint8_t freq_buffer[32];
uint8_t pl_tx_buffer[32];
uint8_t pl_rx_buffer[32];
void setup() {
// NOTE: if not using PWM out, it should be held low to avoid tx noise
pinMode(MIC_PIN, OUTPUT);
digitalWrite(MIC_PIN, LOW);
// prep the switch
pinMode(SWITCH_PIN, INPUT_PULLUP);
// set up the reset control pin
// NOTE: HamShieldMini doesn't have a reset pin, so this has no effect
pinMode(RESET_PIN, OUTPUT);
digitalWrite(RESET_PIN, HIGH);
delay(5); // wait for device to come up
Serial.begin(9600);
Serial.println("If the sketch freezes at radio status, there is something wrong with power or the shield");
Serial.print("Radio status: ");
int result = radio.testConnection();
Serial.println(result,DEC);
Serial.println("Setting radio to its defaults..");
radio.initialize();
radio.setRfPower(0);
radio.frequency(432100); // 70cm calling frequency
radio.setModeReceive();
}
void loop() {
if(Serial.available()) {
uint8_t buf = Serial.read();
Serial.write(buf);
switch (buf) {
case 'X': // absorb reset command because we are already reset
break;
case 'F': // frequency configuration command
tune_freq(); break;
case 'P': // TX PL Tone configuration command
pl_tone_tx(); break;
case 'R': // RX PL Tone configuration command
pl_tone_rx(); break;
case 'T': // turn on transmitter command
tx_on(); break;
case 'O': // turn off transmitter command
tx_off(); break;
case 'A': // configure amplifier
amplifier(); break;
case 'D': // configure predeemph
predeemph(); break;
default:
break;
}
}
}
void tx_on() {
radio.setModeTransmit();
Serial.println("Transmitting");
}
void tx_off() {
radio.setModeReceive();
Serial.println("Transmit off");
}
void pl_tone_tx() {
Serial.println("TX PL tone");
memset(pl_tx_buffer,0,32);
uint8_t ptr = 0;
while(1) {
if(Serial.available()) {
uint8_t buf = Serial.read();
Serial.write(buf);
if(buf == 'X') { return; }
if(buf == '!') { pl_tx_buffer[ptr] = 0; program_pl_tx(); return; }
if(ptr == 31) { return; }
pl_tx_buffer[ptr] = buf; ptr++;
}
}
}
void program_pl_tx() {
Serial.print("programming TX PL to ");
for(int x = 0; x < 32; x++) {
Serial.write(pl_tx_buffer[x]);
}
long pl_tx = atof(pl_tx_buffer);
Serial.print(" Which is FLOAT of ");
Serial.println(pl_tx,DEC);
radio.setCtcss(pl_tx);
}
void pl_tone_rx() {
Serial.println("RX PL tone");
memset(pl_rx_buffer,0,32);
uint8_t ptr = 0;
while(1) {
if(Serial.available()) {
uint8_t buf = Serial.read();
Serial.write(buf);
if(buf == 'X') { return; }
if(buf == '!') { pl_rx_buffer[ptr] = 0; program_pl_rx(); return; }
if(ptr == 31) { return; }
pl_rx_buffer[ptr] = buf; ptr++;
}
}
}
void program_pl_rx() {
Serial.print("programming RX PL to ");
for(int x = 0; x < 32; x++) {
Serial.write(pl_rx_buffer[x]);
}
long pl_rx = atof(pl_rx_buffer);
Serial.print(" Which is FLOAT of ");
Serial.println(pl_rx,DEC);
radio.setCtcss(pl_rx);
}
void tune_freq() {
Serial.println("program frequency mode");
memset(freq_buffer,0,32);
uint8_t ptr = 0;
while(1) {
if(Serial.available()) {
uint8_t buf = Serial.read();
Serial.write(buf);
if(buf == 'X') { return; }
if(buf == '!') { freq_buffer[ptr] = 0; program_frequency(); return; }
if(buf != '.') { freq_buffer[ptr] = buf; ptr++; }
if(ptr == 31) { return; }
}
}
}
void program_frequency() {
Serial.print("programming frequency to ");
for(int x = 0; x < 32; x++) {
Serial.write(freq_buffer[x]);
}
long freq = atol(freq_buffer);
Serial.print(" Which is LONG of ");
Serial.println(freq,DEC);
radio.frequency(freq);
}
void amplifier() {
while(1) {
if(Serial.available()) {
uint8_t buf = Serial.read();
Serial.write(buf);
if(buf == 'X') { return; }
if(buf != '!') { radio.setRfPower(buf); return; }
if(buf == '!') { return; }
}
}
}
void predeemph() { }

183
examples/CTCSS/CTCSS.ino Normal file
View File

@ -0,0 +1,183 @@
/* Hamshield
* Example: CTCSS
* This is a simple example to demonstrate HamShield receive
* and transmit functionality using CTCSS. The HamShield will
* have audio output muted until it receives the correct
* sub-audible tone. It does this by polling a tone detection
* flag on the HamShield, but it's also possible to do this
* using interrupts if you connect GPIO0 from the HamShield
* to your Arduino (code for that not provided).
*
* Setup:
* Connect the HamShield to your Arduino. Screw the antenna
* into the HamShield RF jack. Plug a pair of headphones into
* the HamShield. Connect the Arduino to wall power and then
* to your computer via USB. Set the CTCSS tone that you
* want to use in the setup() function below.
* After uploading this program to your Arduino, open the
* Serial Monitor. Press the button on the HamShield to begin
* setup. The sketch then works exactly like the HandyTalkie
* example, with the exception that only valid CTCSS coded
* receptions are put out to the headset.
*/
#include <HamShield.h>
// create object for radio
HamShield radio;
#define LED_PIN 13
#define RSSI_REPORT_RATE_MS 5000
#define MIC_PIN 3
#define RESET_PIN A3
#define SWITCH_PIN 2
bool currently_tx;
uint32_t freq;
float ctcss_tone;
bool muted;
unsigned long rssi_timeout;
void setup() {
// NOTE: if not using PWM out, it should be held low to avoid tx noise
pinMode(MIC_PIN, OUTPUT);
digitalWrite(MIC_PIN, LOW);
// prep the switch
pinMode(SWITCH_PIN, INPUT_PULLUP);
// set up the reset control pin
// NOTE: HamShieldMini doesn't have a reset pin, so this has no effect
pinMode(RESET_PIN, OUTPUT);
digitalWrite(RESET_PIN, LOW);
// initialize serial communication
Serial.begin(9600);
Serial.println("press the switch to begin...");
while (digitalRead(SWITCH_PIN));
// let the AU ot of reset
digitalWrite(RESET_PIN, HIGH);
delay(5); // wait for device to come up
Serial.println("beginning radio setup");
// verify connection
Serial.println("Testing device connections...");
Serial.println(radio.testConnection() ? "radio connection successful" : "radio connection failed");
// initialize device
Serial.println("Initializing radio device...");
radio.initialize(); // initializes automatically for UHF 12.5kHz channel
Serial.println("setting default Radio configuration");
// set frequency
Serial.println("changing frequency");
freq = 432100; // 70cm calling frequency
radio.frequency(freq);
// set to receive
radio.setModeReceive();
currently_tx = false;
Serial.print("config register is: ");
Serial.println(radio.readCtlReg());
Serial.println(radio.readRSSI());
// set up squelch
radio.setSQLoThresh(-80);
radio.setSQHiThresh(-70);
radio.setSQOn();
radio.setRfPower(0);
// CTCSS Setup code
ctcss_tone = 131.8;
radio.setCtcss(ctcss_tone);
radio.enableCtcss();
Serial.print("ctcss tone: ");
Serial.println(radio.getCtcssFreqHz());
// mute audio until we get a CTCSS tone
radio.setMute();
muted = true;
// configure Arduino LED for
pinMode(LED_PIN, OUTPUT);
rssi_timeout = 0;
}
void loop() {
// handle CTCSS tone detection
if (!currently_tx) {
// check for CTCSS tone
if (radio.getCtcssToneDetected()) {
if (muted) {
muted = false;
radio.setUnmute();
Serial.println("tone");
}
} else {
if (!muted) {
muted = true;
radio.setMute();
Serial.println("no tone");
}
}
}
// handle manual transmit
if (!digitalRead(SWITCH_PIN))
{
if (!currently_tx)
{
currently_tx = true;
// set to transmit
radio.setModeTransmit();
Serial.println("Tx");
radio.setUnmute(); // can't mute during transmit
muted = false;
}
} else if (currently_tx) {
radio.setModeReceive();
currently_tx = false;
Serial.println("Rx");
radio.setMute(); // default to mute during rx
muted = true;
}
// handle serial commands
if (Serial.available()) {
if (Serial.peek() == 'r') {
Serial.read();
digitalWrite(RESET_PIN, LOW);
delay(1000);
digitalWrite(RESET_PIN, HIGH);
radio.initialize(); // initializes automatically for UHF 12.5kHz channel
} else {
Serial.setTimeout(40);
freq = Serial.parseInt();
while (Serial.available()) Serial.read();
radio.frequency(freq);
Serial.print("set frequency: ");
Serial.println(freq);
}
}
// periodically read RSSI and print to screen
if (!currently_tx && (millis() - rssi_timeout) > RSSI_REPORT_RATE_MS)
{
Serial.println(radio.readRSSI());
rssi_timeout = millis();
}
}

View File

@ -1,8 +0,0 @@
chrome.app.runtime.onLaunched.addListener(function() {
chrome.app.window.create("window.html", {
"bounds": {
"width": 685,
"height": 263
}
});
});

View File

@ -1,10 +0,0 @@
{
"name": "HamShield",
"description": "HamShield",
"version": "1.0.0",
"app": {
"background": {
"scripts": ["background.js"]
}
}
}

View File

@ -1 +0,0 @@
chromeApp

View File

@ -1,48 +0,0 @@
body{
display: inline-block;
}
.btn {
background: #adadad;
background-image: -webkit-linear-gradient(top, #adadad, #3d3d3d);
background-image: -moz-linear-gradient(top, #adadad, #3d3d3d);
background-image: -ms-linear-gradient(top, #adadad, #3d3d3d);
background-image: -o-linear-gradient(top, #adadad, #3d3d3d);
background-image: linear-gradient(to bottom, #adadad, #3d3d3d);
-webkit-border-radius: 0;
-moz-border-radius: 0;
border-radius: 0px;
font-family: Arial;
color: #ffffff;
font-size: 20px;
padding: 10px 20px 10px 20px;
text-decoration: none;
float: left;
text-align:center;
}
.btn:hover {
background: #3d3d3d;
text-decoration: none;
}
.lcd {
-webkit-border-radius: 0;
-moz-border-radius: 0;
border-radius: 0px;
font-family: Courier New;
color: #00ff00;
font-size: 50px;
background: #000000;
padding: 10px 20px 10px 20px;
text-decoration: none;
width: 500px;
}
.lcd:hover {
text-decoration: none;
}
.bs1 { width: 50px; }
.bs2 { width: 100px; }
.bs3 { width: 200px; }

View File

@ -1,67 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" type="text/css" href="styles.css">
</head>
<body>
<div class="lcd" style="width: 623px">
220.000 MHz
</div>
<div class="lcd" style="width: 623px; font-size: 15px;">
1.25M | BW 12.5KHz | TX CTCSS: 103.5 | RX CTCSS: 109.4 | Filter OFF
</div>
<div class="btn" style="width: 75px">
BW
</div>
<div class="btn">
Band
</div>
<div class="btn">
+
</div>
<div class="btn">
-
</div>
<div class="btn">
&lt;&lt;
</div>
<div class="btn">
&gt;&gt;
</div>
<div class="btn">
SQ-
</div>
<div class="btn">
SQ+
</div>
<div class="btn">
VOL
</div>
<br/>
<div class="btn">
CTCSS
</div>
<div class="btn">
CDCSS
</div>
<div class="btn">
Vox
</div>
<div class="btn">
Filter
</div>
<div class="btn">
Offset
</div>
<div class="btn">
Directory
</div>
<div class="btn">
WX
</div>
<br/>
<div class="btn" style="width: 622px">
Transmit
</div>
</body>
</html>

78
examples/DDS/DDS.ino Normal file
View File

@ -0,0 +1,78 @@
/* Hamshield
* Example: DDS
* This is a simple example to show how to transmit arbitrary
* tones. In this case, the sketh alternates between 1200Hz
* and 2200Hz at 1s intervals.
* Connect the HamShield to your Arduino. Screw the antenna
* into the HamShield RF jack. Connect the Arduino to wall
* power and then to your computer via USB. Upload this program
* to your Arduino. To test, set a HandyTalkie to 438MHz. You
* should hear two alternating tones.
*/
#define DDS_REFCLK_DEFAULT 9600
#include <HamShield.h>
#include <DDS.h>
#define MIC_PIN 3
#define RESET_PIN A3
#define SWITCH_PIN 2
#define DDS_USE_ONLY_TIMER2 true
#define TIMER2_PHASE_ADVANCE 24
HamShield radio;
DDS dds;
void setup() {
// NOTE: if not using PWM out, it should be held low to avoid tx noise
pinMode(MIC_PIN, OUTPUT);
digitalWrite(MIC_PIN, LOW);
// prep the switch
pinMode(SWITCH_PIN, INPUT_PULLUP);
// set up the reset control pin
// NOTE: HamShieldMini doesn't have a reset pin, so this has no effect
pinMode(RESET_PIN, OUTPUT);
// turn on radio
digitalWrite(RESET_PIN, HIGH);
delay(5); // wait for device to come up
radio.initialize();
radio.setRfPower(0);
radio.frequency(438000);
radio.setModeTransmit();
dds.start();
dds.startPhaseAccumulator(DDS_USE_ONLY_TIMER2);
dds.playWait(600, 3000);
dds.on();
//dds.setAmplitude(31);
}
void loop() {
dds.setFrequency(2200);
delay(1000);
dds.setFrequency(1200);
delay(1000);
}
#if DDS_USE_ONLY_TIMER2
ISR(TIMER2_OVF_vect) {
static unsigned char tcnt = 0;
if(++tcnt == TIMER2_PHASE_ADVANCE) {
tcnt = 0;
dds.clockTick();
}
}
#else // Use the ADC timer instead
ISR(ADC_vect) {
static unsigned char tcnt = 0;
TIFR1 = _BV(ICF1); // Clear the timer flag
if(++tcnt == 4) {
tcnt = 0;
}
dds.clockTick();
}
#endif

153
examples/DTMF/DTMF.ino Normal file
View File

@ -0,0 +1,153 @@
/* Hamshield
* Example: DTMF
* This is a simple example to demonstrate how to use DTMF.
*
* Connect the HamShield to your Arduino. Screw the antenna
* into the HamShield RF jack.
* Connect the Arduino to wall power and then to your computer
* via USB. After uploading this program to your Arduino, open
* the Serial Monitor. Press the switch on the HamShield to
* begin setup. After setup is complete, type in a DTMF value
* (0-9, A, B, C, D, *, #) and hit enter. The corresponding
* DTMF tones will be transmitted. The sketch will also print
* any received DTMF tones to the screen.
**/
#include <HamShield.h>
// create object for radio
HamShield radio;
#define LED_PIN 13
#define MIC_PIN 3
#define RESET_PIN A3
#define SWITCH_PIN 2
uint32_t freq;
void setup() {
// NOTE: if not using PWM out, it should be held low to avoid tx noise
pinMode(MIC_PIN, OUTPUT);
digitalWrite(MIC_PIN, LOW);
// prep the switch
pinMode(SWITCH_PIN, INPUT_PULLUP);
// set up the reset control pin
// NOTE: HamShieldMini doesn't have a reset pin, so this has no effect
pinMode(RESET_PIN, OUTPUT);
digitalWrite(RESET_PIN, LOW);
// initialize serial communication
Serial.begin(9600);
Serial.println("press the switch to begin...");
while (digitalRead(SWITCH_PIN));
// now we let the AU ot of reset
digitalWrite(RESET_PIN, HIGH);
delay(5); // wait for device to come up
Serial.println("beginning radio setup");
// verify connection
Serial.println("Testing device connections...");
Serial.println(radio.testConnection() ? "HamShield connection successful" : "HamShield connection failed");
// initialize device
radio.initialize();
Serial.println("setting default Radio configuration");
Serial.println("setting squelch");
radio.setSQHiThresh(-10);
radio.setSQLoThresh(-30);
Serial.print("sq hi: ");
Serial.println(radio.getSQHiThresh());
Serial.print("sq lo: ");
Serial.println(radio.getSQLoThresh());
radio.setSQOn();
//radio.setSQOff();
Serial.println("setting frequency to: ");
freq = 432100; // 70cm calling frequency
radio.frequency(freq);
Serial.print(radio.getFrequency());
Serial.println("kHz");
// set RX volume to minimum to reduce false positives on DTMF rx
radio.setVolume1(6);
radio.setVolume2(0);
// set to receive
radio.setModeReceive();
radio.setRfPower(0);
// configure Arduino LED for
pinMode(LED_PIN, OUTPUT);
// set up DTMF
radio.enableDTMFReceive();
/* DTMF timing settings are optional.
* These times are set to default values when the device is started.
* You may want to change them if you're DTMF receiver isn't detecting
* codes from the HamShield (or vice versa).
*/
radio.setDTMFDetectTime(24); // time to detect a DTMF code, units are 2.5ms
radio.setDTMFIdleTime(50); // time between transmitted DTMF codes, units are 2.5ms
radio.setDTMFTxTime(60); // duration of transmitted DTMF codes, units are 2.5ms
Serial.println("ready");
}
void loop() {
// look for tone
char m = radio.DTMFRxLoop();
if (m != 0) {
Serial.print(m);
}
// Is it time to send tone?
if (Serial.available()) {
// get first code
uint8_t code = radio.DTMFchar2code(Serial.read());
// start transmitting
radio.setDTMFCode(code); // set first
radio.setTxSourceTones();
radio.setModeTransmit();
delay(300); // wait for TX to come to full power
bool dtmf_to_tx = true;
while (dtmf_to_tx) {
// wait until ready
while (radio.getDTMFTxActive() != 1) {
// wait until we're ready for a new code
delay(10);
}
if (Serial.available()) {
code = radio.DTMFchar2code(Serial.read());
if (code == 255) code = 0xE; // throw a * in there so we don't break things with an invalid code
radio.setDTMFCode(code); // set first
} else {
dtmf_to_tx = false;
break;
}
while (radio.getDTMFTxActive() != 0) {
// wait until this code is done
delay(10);
}
}
// done with tone
radio.setModeReceive();
radio.setTxSourceMic();
}
}

View File

@ -1,28 +1,48 @@
/*
Morse Code Beacon
Test beacon will transmit and wait 30 seconds.
Beacon will check to see if the channel is clear before it will transmit.
/* Hamshield
* Example: Morse Code Beacon
*
* Test beacon will transmit and wait 30 seconds.
* Beacon will check to see if the channel is clear before it
* will transmit.
* Connect the HamShield to your Arduino. Screw the antenna
* into the HamShield RF jack. Connect the Arduino to wall
* power and then to your computer via USB. After uploading
* this program to your Arduino, open the Serial Monitor to
* monitor the status of the beacon. To test, set a HandyTalkie
* to 438MHz. You should hear the message " CALLSIGN HAMSHIELD"
* in morse code.
*/
// Include the HamSheild and Wire (I2C) libraries
#define DDS_REFCLK_DEFAULT 9600
#include <HamShield.h>
#include <Wire.h>
// Create a new instance of our HamSheild class, called 'radio'
#define MIC_PIN 3
#define RESET_PIN A3
#define SWITCH_PIN 2
HamShield radio;
// Run our start up things here
void setup() {
// NOTE: if not using PWM out, it should be held low to avoid tx noise
pinMode(MIC_PIN, OUTPUT);
digitalWrite(MIC_PIN, LOW);
// prep the switch
pinMode(SWITCH_PIN, INPUT_PULLUP);
// set up the reset control pin
// NOTE: HamShieldMini doesn't have a reset pin, so this has no effect
pinMode(RESET_PIN, OUTPUT);
digitalWrite(RESET_PIN, HIGH);
delay(5); // wait for device to come up
// Set up the serial port at 9600 Baud
Serial.begin(9600);
// Send a quick serial string
Serial.println("HamShield FM Beacon Example Sketch");
// Start the Wire (I2C) library
Wire.begin();
// Query the HamShield for status information
Serial.print("Radio status: ");
int result = radio.testConnection();
@ -31,15 +51,22 @@ void setup() {
// Tell the HamShield to start up
radio.initialize();
// Configure the HamShield to transmit and recieve on 446.000MHz
radio.frequency(446000);
// Set the transmit power level (0-8)
radio.setRfPower(0);
// Set the morse code characteristics
radio.setMorseFreq(600);
radio.setMorseDotMillis(100);
// Configure the HamShield
radio.frequency(432300); // 70cm beacon frequency
Serial.println("Radio Configured.");
}
void loop() {
// We'll wait up to 30 seconds for a clear channel, requiring that the channel is clear for 2 seconds before we transmit
if (radio.waitForChannel(30000,2000,-50)) {
if (radio.waitForChannel(30000,2000,-5)) {
// If we get here, the channel is clear. Let's print the RSSI to the serial port as well.
Serial.print("Signal is clear, RSSI: ");
Serial.println(radio.readRSSI());
@ -49,20 +76,17 @@ void loop() {
radio.setModeTransmit();
// Send a message out in morse code
radio.morseOut("CALLSIGN LOCATOR ARDUINO HAMSHIELD");
radio.morseOut(" CALLSIGN HAMSHIELD");
// We're done sending the message, set the radio back into recieve mode.
radio.setModeReceive();
Serial.println("Done.");
// Wait 30 seconds before we send our beacon again.
delay(30000);
} else {
// If we get here, the channel is busy. Let's also print out the RSSI.
Serial.print("The channel was busy. Waiting 10 seconds. RSSI: ");
Serial.println(radio.readRSSI());
}
// Wait 10 seconds and check the channel again.
delay(10000);
}
// Wait 30 seconds before we send our beacon again.
delay(30000);
}

View File

@ -1,283 +0,0 @@
// BlueHAM Proto01 Connection Guide
/**********************
**
** BlueHAM Proto01 <--> Arduino
** ADC_SCL A5
** ADC_DIO A4
** GND GND
** PWM_RF_CTL D9
**
** Setting Connections
** MODE -> GND
** SENB -> GND
** PDN -> 3.3V
** AVDD -> 5V (note this should be a beefy supply, could draw up to 4As)
**
**
**
** Pinout information for RadioPeripheral01 Prototype board
** GPIO0 -
** GPIO1 -
** GPIO2 - VHF_SEL
** GPIO3 - UHF_SEL
** GPIO4 - RX_EN
** GPIO5 - TX_EN
** GPIO6 -
** GPIO7 -
**************************/
// Arduino Wire library is required if I2Cdev I2CDEV_ARDUINO_WIRE implementation
// is used in I2Cdev.h
#include "Wire.h"
#include "HAMShield.h"
#include <Goertzel.h>
//typedef enum {
#define MAIN_S 0
#define RX_S 1
#define TX_S 2
#define FREQ_S 3
#define UHF_S 4
#define VHF_S 5
#define PWR_S 6
#define GPIO_S 7
//} menu_view;
int state;
/* goertzel routines */
int sensorPin = A0;
int led = 13;
const float TARGET_FREQUENCY = 2200;
const int N = 100;
const float THRESHOLD = 4000;
const float SAMPLING_FREQUENCY = 8900;
Goertzel goertzel = Goertzel(TARGET_FREQUENCY, N, SAMPLING_FREQUENCY);
// create object for RDA
HAMShield radio;
#define LED_PIN 13
bool blinkState = false;
void setup() {
// initialize serial communication
Serial.begin(115200);
Serial.println("beginning radio setup");
// join I2C bus (I2Cdev library doesn't do this automatically)
Wire.begin();
// verify connection
Serial.println("Testing device connections...");
Serial.println(radio.testConnection() ? "RDA radio connection successful" : "RDA radio connection failed");
// initialize device
Serial.println("Initializing I2C devices...");
radio.initialize(); // initializes automatically for UHF 12.5kHz channel
Serial.println("setting default Radio configuration");
// set frequency
Serial.println("changing frequency");
radio.setFrequency(446000); // in kHz
radio.setModeReceive();
// configure Arduino LED for
pinMode(LED_PIN, OUTPUT);
state = MAIN_S;
print_menu();
}
void loop() {
goertzel.sample(sensorPin);
float magnitude = goertzel.detect();
if(magnitude>THRESHOLD) digitalWrite(led, HIGH); //if found, enable led
else digitalWrite(led, LOW);
while (Serial.available()) {
if (state == FREQ_S) {
char freq_khz[6];
int i = 0;
while(i < 6) {
if (Serial.available()) {
freq_khz[i] = Serial.read();
i++;
}
}
// interpret frequency
uint32_t freq = 0;
i = 0;
while (i < 6) {
uint32_t temp = freq_khz[i] - '0';
for (int k = 5-i; k > 0; k--) {
temp = temp * 10;
}
freq += temp;
i++;
}
Serial.print("setting frequency to: ");
Serial.println(freq);
radio.setFrequency(freq);
state = MAIN_S;
} else if (state == PWR_S) {
uint8_t pwr_raw[3];
int i = 0;
while(i < 3) {
if (Serial.available()) {
pwr_raw[i] = Serial.read();
i++;
}
}
// interpret power
uint8_t pwr = 0;
i = 0;
while (i < 3) {
uint8_t temp = pwr_raw[i] - '0';
for (int k = 2-i; k > 0; k--) {
temp = temp * 10;
}
pwr += temp;
i++;
}
Serial.print("Setting power to: ");
Serial.println(pwr);
radio.setRfPower(pwr);
state = MAIN_S;
} else if (state == GPIO_S) {
uint8_t gpio_raw[2];
int i = 0;
while(i < 2) {
if (Serial.available()) {
gpio_raw[i] = Serial.read();
i++;
}
}
uint16_t gpio_pin = gpio_raw[0] - 48; // '0';
uint16_t gpio_mode = gpio_raw[1] - 48;
radio.setGpioMode(gpio_pin, gpio_mode);
state = MAIN_S;
} else {
char action = Serial.read();
if (action == 'r') { // get current state
state = RX_S;
} else if (action == 't') {
state = TX_S;
} else if (action == 'f') {
state = FREQ_S;
} else if (action == 'u') {
state = UHF_S;
} else if (action == 'v') {
state = VHF_S;
} else if (action == '1') {
turn_on(state);
state = MAIN_S;
} else if (action == '0') {
turn_off(state);
state = MAIN_S;
} else if (action == 'p') {
state = PWR_S;
} else if (action == 'g') {
state = GPIO_S;
} else if (action == 's') {
int16_t rssi = radio.readRSSI();
Serial.print("rssi: ");
Serial.println(rssi);
} else if (action == 'i') {
int16_t vssi = radio.readVSSI();
Serial.print("vssi: ");
Serial.println(vssi);
}
Serial.println(action);
}
Serial.flush();
print_menu();
}
}
void turn_off(int dev) {
switch (dev) {
case RX_S:
radio.setRX(0);
break;
case TX_S:
radio.setTX(0);
break;
case UHF_S:
radio.setGpioMode(3, 3); // set GPIO3 high (uhf is active low)
break;
case VHF_S:
radio.setGpioMode(2, 3); // set GPIO2 high (vhf is active low)
break;
default:
break;
}
}
void turn_on(int dev) {
switch (dev) {
case RX_S:
radio.setRX(1);
break;
case TX_S:
radio.setTX(1);
break;
case UHF_S:
radio.setGpioMode(3, 2); // set GPIO3 low (uhf is active low)
break;
case VHF_S:
radio.setGpioMode(2, 2); // set GPIO2 low (uhf is active low)
break;
default:
break;
}
}
void print_menu() {
Serial.println("MENU");
switch (state) {
case MAIN_S:
Serial.println("select step: [r]x, [t]x, [f]req, [u]hf, [v]hf, [p]wr, [g]pio control, r[s]si, vss[i] ...");
break;
case RX_S:
Serial.println("enter 1 to turn on rx, 0 to turn off rx");
break;
case TX_S:
Serial.println("enter 1 to turn on tx, 0 to turn off tx");
break;
case FREQ_S:
Serial.println("enter frequency in kHz (ffffff)");
break;
case UHF_S:
Serial.println("enter 1 to turn on uhf, 0 to turn off uhf");
break;
case VHF_S:
Serial.println("enter 1 to turn on vhf, 0 to turn off vhf");
break;
case PWR_S:
Serial.println("enter power (raw) (ppp)");
break;
case GPIO_S:
Serial.println("enter GPIO pin and control (no spaces, eg pin 1 mode 3 is 13");
Serial.println("modes 0 - HiZ, 1 - FCN, 2 - Low, 3 - Hi");
break;
default:
state = MAIN_S;
break;
}
}

View File

@ -1,37 +1,104 @@
/* Fox Hunt */
/* Hamshield
* Example: Fox Hunt
*
* Plays a one minute tone, then IDs at 10-13 minute intervals. Script
* will check to see if the channel is clear before it will transmit.
*
* Connect the HamShield to your Arduino. Screw the antenna
* into the HamShield RF jack. Connect the Arduino to wall
* power and then to your computer via USB. After uploading
* this program to your Arduino, open the Serial Monitor to
* monitor the status of the beacon. To test, set a HandyTalkie
* to 438MHz. You should hear a one-minute tone followed by
* a callsign every 10-13 minutes.
*/
#include <HAMShield.h>
#include <Wire.h>
#include <HamShield.h>
// transmit for 1 minute, every 10 minutes
#define MIC_PIN 3
#define RESET_PIN A3
#define SWITCH_PIN 2
#define TRANSMITLENGTH 1
// In milliseconds
#define TRANSMITLENGTH 60000
// In minutes
#define INTERVAL 10
#define RANDOMCHANCE 3
HAMShield radio;
HamShield radio;
void setup() {
Wire.begin();
// NOTE: if not using PWM out, it should be held low to avoid tx noise
pinMode(MIC_PIN, OUTPUT);
digitalWrite(MIC_PIN, LOW);
// prep the switch
pinMode(SWITCH_PIN, INPUT_PULLUP);
// set up the reset control pin
// NOTE: HamShieldMini doesn't have a reset pin, so this has no effect
pinMode(RESET_PIN, OUTPUT);
digitalWrite(RESET_PIN, HIGH);
delay(5); // wait for device to come up
// Set up the serial port at 9600 Baud
Serial.begin(9600);
// Send a quick serial string
Serial.println("HamShield FoxHunt Example Sketch");
// Query the HamShield for status information
Serial.print("Radio status: ");
int result = radio.testConnection();
Serial.println(result, DEC);
// Tell the HamShield to start up
radio.initialize();
radio.setFrequency(145510);
radio.setModeReceive();
// Set the transmit power level (0-8)
radio.setRfPower(0);
// Set the morse code characteristics
radio.setMorseFreq(600);
radio.setMorseDotMillis(100);
// Configure the HamShield frequency
radio.frequency(432400);
Serial.println("Radio configured.");
}
void loop() {
waitMinute(INTERVAL + random(0,RANDOMCHANCE)); // wait before transmitting, randomly up to 3 minutes later
if(radio.waitForChannel(30000,2000)) { // wait for a clear channel, abort after 30 seconds, wait 2 seconds of dead air for breakers
radio.setModeTransmit(); // turn on transmit mode
tone(1000,11,TRANSMITLENGTH * 60 * 1000); // play a long solid tone
radio.morseOut("1ZZ9ZZ/B FOXHUNT"); // identify the fox hunt transmitter
radio.setModeReceive(); // turn off the transmit mode
// We'll wait up to 30 seconds for a clear channel, requiring that the channel is clear for 2 seconds before we transmit
if (radio.waitForChannel(30000,2000, -90)) {
// If we get here, the channel is clear. Let's print the RSSI to the serial port as well.
Serial.print("Signal is clear, RSSI: ");
Serial.println(radio.readRSSI());
// Set the HamShield to TX
Serial.print("Transmitting...");
radio.setModeTransmit();
// Generate a 600Hz tone for TRANSMITLENGTH time
tone(MIC_PIN, 600, TRANSMITLENGTH);
delay(TRANSMITLENGTH);
// Identify the transmitter
radio.morseOut(" CALLSIGN FOXHUNT");
// Set the HamShield back to RX
radio.setModeReceive();
Serial.println("Done.");
// Wait for INTERLVAL + some random minutes before transmitting again
waitMinute(INTERVAL + random(0,RANDOMCHANCE));
}
}
// a function so we can wait by minutes
void waitMinute(int period) {
void waitMinute(unsigned long period) {
Serial.print("Waiting for ");
Serial.print(period, DEC);
Serial.println(" minutes.");
delay(period * 60 * 1000);
}

View File

@ -1,100 +0,0 @@
/*
Gauges
Simple gauges for the radio receiver.
*/
#include <HAMShield.h>
#include <Wire.h>
HAMShield radio;
void clr() {
/* Serial.write(27);
Serial.print("[2J"); // cursor to home command */
Serial.write(27);
Serial.print("[H"); // cursor to home command
}
void setup() {
analogReference(DEFAULT);
Serial.begin(115200);
Wire.begin();
Serial.print("Radio status: ");
int result = radio.testConnection();
Serial.println(result,DEC);
radio.initialize();
radio.setFrequency(446000);
radio.setModeReceive();
Serial.println("Entering gauges...");
tone(9,1000);
delay(2000);
}
int gauge;
int x = 0;
int y = 0;
int peak = 0;
int a = 0;
int mini = 0;
int vpeak = 0;
int txc = 0;
int mode = 0;
void loop() {
clr();
int16_t rssi = radio.readRSSI();
gauge = map(rssi,-123,-50,0,8);
Serial.print("[");
for(x = 0; x < gauge; x++) {
Serial.print(".");
}
Serial.print("|");
for(y = x; y < 8; y++) {
Serial.print(".");
}
Serial.print("] ");
Serial.print(rssi);
Serial.println(" ");
Serial.println("Signal \n");
// radio.setModeTransmit();
int16_t vssi = radio.readVSSI();
// radio.setModeReceive();
if(vssi > vpeak) { vpeak = vssi; }
gauge = map(vssi,-50,-150,0,8);
Serial.print("[");
for(x = 0; x < gauge; x++) {
Serial.print(".");
}
Serial.print("|");
for(y = x; y < 8; y++) {
Serial.print(".");
}
Serial.print("] ");
Serial.print(vpeak);
Serial.println(" ");
Serial.println("Audio In\n");
a = analogRead(0);
if(a > peak) { peak = a; }
if(a < mini) { mini = a; }
gauge = map(a,400,1023,0,8);
Serial.print("[");
for(x = 0; x < gauge; x++) {
Serial.print(".");
}
Serial.print("|");
for(y = x; y < 8; y++) {
Serial.print(".");
}
Serial.print("] ");
Serial.print(a,DEC);
Serial.print(" ("); Serial.print(peak,DEC); Serial.println(") ");
Serial.println("Audio RX ADC Peak\n");
}

View File

@ -1,32 +0,0 @@
/* Simple DTMF controlled HAM Radio Robot */
#include <ArduinoRobot.h> // include the robot library
#include <HAMShield.h>
#include <Wire.h>
#include <SPI.h>
HAMShield radio;
void setup() {
Robot.begin();
Wire.begin();
radio.initialize();
radio.setFrequency(145510);
}
void loop() {
if(radio.waitForDTMF()) { // wait for a received DTMF tone
uint8_t command = radio.getLastDTMFDigit(); // get the last DTMF tone sent
if(command == '4') { Robot.turn(-90); } // turn robot left
if(command == '6') { Robot.turn(90); } // turn robot right
if(command == '2') { Robot.motorsWrite(-255,-255); delay(500); Robot.motorsWrite(255, 255); } // move robot forward
if(command == '5') { // tell robot to send morse code identity
if(radio.waitForChannel()) { // wait for the user to release the transmit button
radio.setModeTransmit(); // turn on transmit mode
radio.morseOut("1ZZ9ZZ I AM HAMRADIO ROBOT"); // send morse code
radio.setModeReceive(); // go back to receive mode on radio
}
}
}
}

View File

@ -0,0 +1,152 @@
/* Hamshield
* Example: HandyTalkie
* This is a simple example to demonstrate HamShield receive
* and transmit functionality.
* Connect the HamShield to your Arduino. Screw the antenna
* into the HamShield RF jack. Plug a pair of headphones into
* the HamShield. Connect the Arduino to wall power and then
* to your computer via USB. After uploading this program to
* your Arduino, open the Serial Monitor. Press the button on
* the HamShield to begin setup. After setup is complete, type
* your desired Tx/Rx frequency, in hertz, into the bar at the
* top of the Serial Monitor and click the "Send" button.
* To test with another HandyTalkie (HT), key up on your HT
* and make sure you can hear it through the headphones
* attached to the HamShield. Key up on the HamShield by
* holding the button.
*/
#include <HamShield.h>
// create object for radio
HamShield radio;
// To use non-standard pins, use the following initialization
//HamShield radio(ncs_pin, clk_pin, dat_pin);
#define LED_PIN 13
#define RSSI_REPORT_RATE_MS 5000
#define MIC_PIN 3
#define RESET_PIN A3
#define SWITCH_PIN 2
bool blinkState = false;
bool currently_tx;
uint32_t freq;
unsigned long rssi_timeout;
void setup() {
// NOTE: if not using PWM out, it should be held low to avoid tx noise
pinMode(MIC_PIN, OUTPUT);
digitalWrite(MIC_PIN, LOW);
// prep the switch
pinMode(SWITCH_PIN, INPUT_PULLUP);
// set up the reset control pin
// NOTE: HamShieldMini doesn't have a reset pin, so this has no effect
pinMode(RESET_PIN, OUTPUT);
digitalWrite(RESET_PIN, LOW);
// initialize serial communication
Serial.begin(9600);
Serial.println("press the switch or send any character to begin...");
while (digitalRead(SWITCH_PIN) && !Serial.available());
Serial.read(); // flush
// let the radio out of reset
// NOTE: HamShieldMini doesn't have a reset pin, so this has no effect
digitalWrite(RESET_PIN, HIGH);
delay(5); // wait for device to come up
Serial.println("beginning radio setup");
// verify connection
Serial.println("Testing device connections...");
Serial.println(radio.testConnection() ? "radio connection successful" : "radio connection failed");
// initialize device
Serial.println("Initializing radio device...");
radio.initialize(); // initializes automatically for UHF 12.5kHz channel
Serial.println("setting default Radio configuration");
// set frequency
Serial.println("changing frequency");
radio.setSQOff();
freq = 432100; // 70cm calling frequency
radio.frequency(freq);
// set to receive
radio.setModeReceive();
currently_tx = false;
Serial.print("config register is: ");
Serial.println(radio.readCtlReg());
Serial.println(radio.readRSSI());
/*
// set to transmit
radio.setModeTransmit();
// maybe set PA bias voltage
Serial.println("configured for transmit");
radio.setTxSourceMic();
*/
radio.setRfPower(0);
// configure Arduino LED for
pinMode(LED_PIN, OUTPUT);
rssi_timeout = 0;
}
void loop() {
if (!digitalRead(SWITCH_PIN))
{
if (!currently_tx)
{
currently_tx = true;
// set to transmit
radio.setModeTransmit();
Serial.println("Tx");
//radio.setTxSourceMic();
//radio.setRfPower(1);
}
} else if (currently_tx) {
radio.setModeReceive();
currently_tx = false;
Serial.println("Rx");
}
if (Serial.available()) {
if (Serial.peek() == 'r') {
Serial.read();
digitalWrite(RESET_PIN, LOW);
delay(1000);
digitalWrite(RESET_PIN, HIGH);
radio.initialize(); // initializes automatically for UHF 12.5kHz channel
} else {
Serial.setTimeout(40);
freq = Serial.parseInt();
while (Serial.available()) Serial.read();
radio.frequency(freq);
Serial.print("set frequency: ");
Serial.println(freq);
}
}
if (!currently_tx && (millis() - rssi_timeout) > RSSI_REPORT_RATE_MS)
{
Serial.println(radio.readRSSI());
rssi_timeout = millis();
}
}

View File

@ -0,0 +1,283 @@
/* Hamshield
* Example: HandyTalkie_nRF52840
* This is a simple example to demonstrate the HamShield working
* with an Adafruit Feather nRF52840 Express
*
* HamShield to Feather Connections:
* SPKR - Feather A0
* MIC - Feather D11
* CLK - Feather D5
* nCS - Feather D6
* DAT - Feather D9
* GND - Feather GND
* VCC - Feather 3.3V
*
* Connect the HamShield to your Feather as above.
* Screw the antenna into the HamShield RF jack. Plug a pair
* of headphones into the HamShield.
*
* Connect the Feather nRF52840 Express to your computer via
* a USB Micro B cable. After uploading this program to
* your Feather, open the Serial Monitor. You should see some
* text displayed that documents the setup process.
*
* Once the Feather is set up and talking to the HamShield,
* you can control it over USB-Serial or BLE-Serial(UART).
*
* Try using Adafruit's Bluefruit app to connect to the Feather.
* Once you're connected, you can control the HamShield using
* the same commands you'd use over USB-Serial. The response to
* all commands will be echoed to both USB-Serial and BLE-Serial(UART).
*
* Serial UART commands:
* t - change from Tx to Rx (or vice versa)
* F123400 - set frequency to 123400 kHz
*/
#include <bluefruit.h>
// BLE Service
BLEDis bledis; // device information
BLEUart bleuart; // uart over ble
BLEBas blebas; // battery
#include <HamShield.h>
// create object for radio
HamShield radio(6,5,9);
// To use non-standard pins, use the following initialization
//HamShield radio(ncs_pin, clk_pin, dat_pin);
#define LED_PIN 3
#define RSSI_REPORT_RATE_MS 5000
#define MIC_PIN A1
bool blinkState = false;
bool currently_tx;
uint32_t freq;
unsigned long rssi_timeout;
void setup() {
// NOTE: if not using PWM out, it should be held low to avoid tx noise
pinMode(MIC_PIN, OUTPUT);
digitalWrite(MIC_PIN, LOW);
// initialize serial communication
Serial.begin(115200);
while (!Serial) delay(10);
Serial.println("Setting up BLE");
// Setup the BLE LED to be enabled on CONNECT
// Note: This is actually the default behaviour, but provided
// here in case you want to control this LED manually via PIN 19
Bluefruit.autoConnLed(true);
// Config the peripheral connection with maximum bandwidth
// more SRAM required by SoftDevice
// Note: All config***() function must be called before begin()
Bluefruit.configPrphBandwidth(BANDWIDTH_MAX);
Bluefruit.begin();
// Set max power. Accepted values are: -40, -30, -20, -16, -12, -8, -4, 0, 4
Bluefruit.setTxPower(4);
Bluefruit.setName("MyBlueHam");
//Bluefruit.setName(getMcuUniqueID()); // useful testing with multiple central connections
Bluefruit.setConnectCallback(connect_callback);
Bluefruit.setDisconnectCallback(disconnect_callback);
// Configure and Start Device Information Service
bledis.setManufacturer("Enhanced Radio Devices");
bledis.setModel("BlueHam");
bledis.begin();
// Configure and Start BLE Uart Service
bleuart.begin();
// Start BLE Battery Service
blebas.begin();
blebas.write(100);
// Set up and start advertising
startAdv();
delay(100);
Serial.println("beginning Ham radio setup");
// verify connection
Serial.println("Testing device connections...");
if (radio.testConnection()) {
Serial.println("HamShield connection successful");
} else {
Serial.print("HamShield connection failed");
while(1) delay(100);
}
// initialize device
Serial.println("Initializing radio device...");
radio.initialize(); // initializes automatically for UHF 12.5kHz channel
Serial.println("setting default Radio configuration");
// set frequency
Serial.println("changing frequency");
radio.setSQOff();
freq = 432100; // 70cm calling frequency
radio.frequency(freq);
// set to receive
radio.setModeReceive();
currently_tx = false;
Serial.print("config register is: ");
Serial.println(radio.readCtlReg());
Serial.println(radio.readRSSI());
/*
// set to transmit
radio.setModeTransmit();
// maybe set PA bias voltage
Serial.println("configured for transmit");
radio.setTxSourceMic();
*/
radio.setRfPower(0);
// configure Arduino LED for
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, HIGH);
rssi_timeout = 0;
}
void startAdv(void)
{
// Advertising packet
Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
Bluefruit.Advertising.addTxPower();
// Include bleuart 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
}
// for serial output buffer on both interfaces
#define TEXT_BUF_LEN 64
char text_buf[TEXT_BUF_LEN];
void loop() {
char c = 0;
bool ble_serial = false;
if (Serial.available()) {
Serial.readBytes(&c, 1);
} else if (bleuart.available()) {
c = (char) bleuart.read();
ble_serial = true;
}
if (c != 0) {
if (c == 't')
{
if (!currently_tx)
{
currently_tx = true;
// set to transmit
radio.setModeTransmit();
Serial.println("Tx");
int str_len = snprintf(text_buf, TEXT_BUF_LEN, "Tx\n");
bleuart.write(text_buf, str_len);
//radio.setTxSourceMic();
//radio.setRfPower(1);
} else {
radio.setModeReceive();
currently_tx = false;
Serial.println("Rx");
int str_len = snprintf(text_buf, TEXT_BUF_LEN, "Rx\n");
bleuart.write(text_buf, str_len);
}
} else if (c == 'F') {
if (ble_serial == false) {
Serial.setTimeout(40);
freq = Serial.parseInt();
Serial.flush();
} else {
int idx = 0;
while (bleuart.available() &&
bleuart.peek() >= '0' &&
bleuart.peek() <= '9' &&
idx < TEXT_BUF_LEN) {
text_buf[idx] = bleuart.read();
idx++;
}
text_buf[idx] = 0; // null terminate
freq = atoi(text_buf);
}
radio.frequency(freq);
Serial.print("set frequency: ");
Serial.println(freq);
int str_len = snprintf(text_buf, TEXT_BUF_LEN, "set frequency: %d\n", freq);
bleuart.write(text_buf, str_len);
}
}
if (!currently_tx && (millis() - rssi_timeout) > RSSI_REPORT_RATE_MS)
{
int rssi = radio.readRSSI();
Serial.println(rssi);
int str_len = snprintf(text_buf, TEXT_BUF_LEN, "rssi: %d\n", rssi);
bleuart.write(text_buf, str_len);
rssi_timeout = millis();
}
}
// callback invoked when central connects
void connect_callback(uint16_t conn_handle)
{
char central_name[32] = { 0 };
Bluefruit.Gap.getPeerName(conn_handle, central_name, sizeof(central_name));
Serial.print("Connected to ");
Serial.println(central_name);
}
/**
* Callback invoked when a connection is dropped
* @param conn_handle connection where this event happens
* @param reason is a BLE_HCI_STATUS_CODE which can be found in ble_hci.h
* https://github.com/adafruit/Adafruit_nRF52_Arduino/blob/master/cores/nRF5/nordic/softdevice/s140_nrf52_6.1.1_API/include/ble_hci.h
*/
void disconnect_callback(uint16_t conn_handle, uint8_t reason)
{
(void) conn_handle;
(void) reason;
Serial.println();
Serial.println("Disconnected");
}

View File

@ -1,80 +0,0 @@
/*
Indentifier
Arduino audio overlay example
*/
#include <HAMShield.h>
#include <Wire.h>
#define DOT 100
HAMShield radio;
const char *bascii = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.,?'!/()&:;=+-_\"$@",
*bitu[] = { ".-","-...","-.-.","-..",".","..-.","--.","....","..",".---","-.-",".-..","--","-.","---",".--.","--.-",".-.","...","-","..-","...-",".--","-..-","-.--","--..","-----",".----","..---","...--","....-",".....","-....","--...","---..","----.",".-.-.-","--..--","..--..",".----.","-.-.--","-..-.","-.--.","-.--.-",".-...","---...","-.-.-.","-...-",".-.-.","-....-","..--.-",".-..-.","...-..-",".--.-."
};
const char *callsign = {"1ZZ9ZZ/B"} ;
char morsebuffer[8];
void setup() {
Serial.begin(9600);
Serial.println("starting up..");
Wire.begin();
Serial.print("Radio status: ");
int result = radio.testConnection();
Serial.println(result,DEC);
radio.initialize();
radio.setFrequency(446000);
radio.setVolume1(0xF);
radio.setVolume2(0xF);
radio.setModeReceive();
radio.setTxSourceMic();
radio.setSQLoThresh(80);
radio.setSQOn();
Serial.println("Done with radio beacon setup. Press and hold a key to transmit.");
}
int state = 0;
long timer = 0;
int morseletter = 0;
int morsesymbol = 0;
long keyer = 0;
char symbol;
void loop() {
if(Serial.available() > 0) {
if(state == 0) {
state = 10;
radio.setModeTransmit();
timer = millis();
keyer = millis();
}
if(state == 10) {
timer = millis();
}
}
if(millis() > (timer + 500)) { radio.setModeReceive(); morseletter = 0; morsesymbol = 0; state = 0; }
if(state == 10) {
if(millis() > (keyer + (DOT * 3))) {
keyer = millis();
symbol = lookup(callsign[morseletter],morsesymbol);
if(symbol == '-') { tone(9,1000,DOT*3); }
if(symbol == '.') { tone(9,1000,DOT); }
if(symbol == 0) { morsesymbol = 0; morseletter++; }
if(callsign[morseletter] == 0) { morsesymbol = 0; morseletter = 0; }
}
}
}
char lookup(char letter, int morsesymbol) {
for(int x = 0; x < 54; x++) {
if(letter == bascii[x]) {
return bitu[x][morsesymbol];
}
}
}

95
examples/KISS/KISS.ino Normal file
View File

@ -0,0 +1,95 @@
/* Hamshield
* Example: KISS
* This is a example configures the HamShield to be used as
* a TNC/KISS device. You will need a KISS device to input
* commands to the HamShield
* Connect the HamShield to your Arduino. Screw the antenna
* into the HamShield RF jack. Connect the Arduino to wall
* power and then to your computer via USB. Issue commands
* via the KISS equipment.
*
* You can also just use the serial terminal to send and receive
* APRS packets, but keep in mind that several fields in the packet
* are bit-shifted from standard ASCII (so if you're receiving,
* you won't get human readable callsigns or paths).
*
* To use the KISS example with YAAC:
* 1. open the configure YAAC wizard
* 2. follow the prompts and enter in your details until you get to the "Add and Configure Interfaces" window
* 3. Choose "Add Serial KISS TNC Port"
* 4. Choose the COM port for your Arduino
* 5. set baud rate to 9600 (default)
* 6. set it to KISS-only: with no command to enter KISS mode (just leave the box empty)
* 7. Use APRS protocol (default)
* 8. hit the next button and follow directions to finish configuration
*/
#include <HamShield.h>
#include <KISS.h>
#include <DDS.h>
#include <packet.h>
#include <avr/wdt.h>
HamShield radio;
DDS dds;
AFSK afsk;
KISS kiss(&Serial, &radio, &dds, &afsk);
#define MIC_PIN 3
#define RESET_PIN A3
#define SWITCH_PIN 2
void setup() {
// NOTE: if not using PWM out, it should be held low to avoid tx noise
pinMode(MIC_PIN, OUTPUT);
digitalWrite(MIC_PIN, LOW);
// prep the switch
pinMode(SWITCH_PIN, INPUT_PULLUP);
// set up the reset control pin
// NOTE: HamShieldMini doesn't have a reset pin, so this has no effect
pinMode(RESET_PIN, OUTPUT);
digitalWrite(RESET_PIN, HIGH);
delay(5); // wait for device to come up
Serial.begin(9600);
radio.initialize();
//radio.setSQOff();
radio.setVolume1(0xFF);
radio.setVolume2(0xFF);
radio.setSQHiThresh(-100);
radio.setSQLoThresh(-100);
//radio.setSQOn();
radio.frequency(144390);
radio.bypassPreDeEmph();
dds.start();
afsk.start(&dds);
delay(100);
radio.setModeReceive();
}
void loop() {
kiss.loop();
}
ISR(TIMER2_OVF_vect) {
TIFR2 = _BV(TOV2);
static uint8_t tcnt = 0;
if(++tcnt == 8) {
dds.clockTick();
tcnt = 0;
}
}
ISR(ADC_vect) {
static uint8_t tcnt = 0;
TIFR1 = _BV(ICF1); // Clear the timer flag
dds.clockTick();
if(++tcnt == 1) {
afsk.timer();
tcnt = 0;
}
}

128
examples/Morse/Morse.ino Normal file
View File

@ -0,0 +1,128 @@
/* Hamshield
* Example: Morse Code Transceiver
*
* Serial to Morse transceiver. Sends characters from the Serial
* port over the air, and vice versa.
* Connect the HamShield to your Arduino. Screw the antenna
* into the HamShield RF jack. Connect the Arduino to wall
* power and then to your computer via USB. After uploading
* this program to your Arduino, open the Serial Monitor to
* monitor the status of the beacon. To test, set a HandyTalkie
* to 438MHz. You should hear the message " CALLSIGN HAMSHIELD"
* in morse code.
*
*
* Note: only upper case letters, numbers, and a few symbols
* are supported.
* Supported symbols: &/+(=:?";@`-._),!$
*
* If you're having trouble accurately decoding, you may want to
* tweak the min/max . and - times. You can also uncomment
* the Serial.print debug statements that can tell you when tones
* are being detected, how long they're detected for, and whether
* the tones are decoded as a . or -.
*
*/
#define DDS_REFCLK_DEFAULT 9600
#include <HamShield.h>
#define MIC_PIN 3
#define RESET_PIN A3
#define SWITCH_PIN 2
#define MORSE_FREQ 600
#define MORSE_DOT 150 // ms
// Note that all timing is defined in terms of MORSE_DOT relative durations
// You may want to tweak those timings below
HamShield radio;
// Run our start up things here
void setup() {
// NOTE: if not using PWM out, it should be held low to avoid tx noise
pinMode(MIC_PIN, OUTPUT);
digitalWrite(MIC_PIN, LOW);
// prep the switch
pinMode(SWITCH_PIN, INPUT_PULLUP);
// set up the reset control pin
// NOTE: HamShieldMini doesn't have a reset pin, so this has no effect
pinMode(RESET_PIN, OUTPUT);
digitalWrite(RESET_PIN, HIGH);
delay(5); // wait for device to come up
// Set up the serial port at 9600 Baud
Serial.begin(9600);
// Send a quick serial string
Serial.println("HamShield Morse Example Sketch");
Serial.print("Radio status: ");
int result = radio.testConnection();
Serial.println(result,DEC);
// Tell the HamShield to start up
radio.initialize();
// Set the transmit power level (0-8)
radio.setRfPower(0);
// Set the morse code characteristics
radio.setMorseFreq(MORSE_FREQ);
radio.setMorseDotMillis(MORSE_DOT);
radio.lookForTone(MORSE_FREQ);
radio.setupMorseRx();
// Configure the HamShield frequency
radio.frequency(432100); // 70cm calling frequency
radio.setModeReceive();
Serial.println("Radio Configured.");
}
void loop() {
char rx_char = radio.morseRxLoop();
if (rx_char != 0) {
Serial.print(rx_char);
}
// should we send anything
if (Serial.available()) {
Serial.println("checking channel");
// We'll wait up to 30 seconds for a clear channel, requiring that the channel is clear for 2 seconds before we transmit
if (radio.waitForChannel(30000,2000,-5)) {
// If we get here, the channel is clear.
Serial.println("sending");
// Start transmitting by putting the radio into transmit mode.
radio.setModeTransmit();
Serial.println("tx");
unsigned int MORSE_BUF_SIZE = 128;
char morse_buf[MORSE_BUF_SIZE];
unsigned int morse_idx;
morse_buf[morse_idx++] = ' '; // start with space to let PA come up
while (Serial.available() && morse_idx < MORSE_BUF_SIZE) {
morse_buf[morse_idx++] = Serial.read();
}
morse_buf[morse_idx] = '\0'; // null terminate
// Send a message out in morse code
radio.morseOut(morse_buf);
// We're done sending the message, set the radio back into recieve mode.
Serial.println("sent");
radio.setModeReceive();
radio.lookForTone(MORSE_FREQ);
} else {
// If we get here, the channel is busy. Let's also print out the RSSI.
Serial.print("The channel was busy. RSSI: ");
Serial.println(radio.readRSSI());
}
}
}

View File

@ -1,111 +0,0 @@
/*
Record sound and then plays it back a few times.
Very low sound quality @ 2KHz 0.75 seconds
A bit robotic and weird
*/
#include <HAMShield.h>
#include <Wire.h>
#define RATE 500
#define SIZE 1500
HAMShield radio;
char sound[SIZE];
unsigned int sample1;
int x = -1;
int16_t rssi;
byte mode = 8;
void setup() {
Wire.begin();
// int result = radio.testConnection();
radio.initialize();
radio.setFrequency(446000);
setPwmFrequency(9, 1);
}
void loop() {
rssi = radio.readRSSI();
if(rssi > -100) {
if(x == -1) {
for(x = 0; x < SIZE; x++) {
if(mode == 4) {
sample1 = analogRead(0);
sound[x] = sample1 >> 4;
delayMicroseconds(RATE); x++;
sample1 = analogRead(0);
sound[x] = (sample1 & 0xF0) | sound[x];
delayMicroseconds(RATE);
} else {
sound[x] = analogRead(0);
delayMicroseconds(RATE); x++;
sound[x] = analogRead(0);
delayMicroseconds(RATE);
}
}
}
}
if(rssi < -100) {
if(x == 1500) {
radio.setModeTransmit();
delay(500);
tone(9,1000,500); delay(750);
for(int r = 0; r < 10; r++) {
for(x = 0; x < SIZE; x++) {
if(mode == 4) {
analogWrite(9,sound[x] << 4);
delayMicroseconds(RATE); x++;
analogWrite(9,sound[x] & 0xF);
delayMicroseconds(RATE); } else {
analogWrite(9,sound[x]);
delayMicroseconds(RATE); x++;
analogWrite(9,sound[x]);
delayMicroseconds(RATE);
}
} }
tone(9,1000,500); delay(750);
radio.setModeReceive();
x = -1;
}
}
}
void setPwmFrequency(int pin, int divisor) {
byte mode;
if(pin == 5 || pin == 6 || pin == 9 || pin == 10) {
switch(divisor) {
case 1: mode = 0x01; break;
case 8: mode = 0x02; break;
case 64: mode = 0x03; break;
case 256: mode = 0x04; break;
case 1024: mode = 0x05; break;
default: return;
}
if(pin == 5 || pin == 6) {
TCCR0B = TCCR0B & 0b11111000 | mode;
} else {
TCCR1B = TCCR1B & 0b11111000 | mode;
}
} else if(pin == 3 || pin == 11) {
switch(divisor) {
case 1: mode = 0x01; break;
case 8: mode = 0x02; break;
case 32: mode = 0x03; break;
case 64: mode = 0x04; break;
case 128: mode = 0x05; break;
case 256: mode = 0x06; break;
case 1024: mode = 0x7; break;
default: return;
}
TCCR2B = TCCR2B & 0b11111000 | mode;
}
}

View File

@ -1,30 +1,51 @@
/*
Sends an SSTV test pattern
/* Hamshield
* Example: SSTV
* This program will transmit a test pattern. You will need
* SSTV equipment to test the output.
* Connect the HamShield to your Arduino. Screw the antenna
* into the HamShield RF jack. Connect the Arduino to wall
* power and then to your computer via USB. After uploading
* this program to your Arduino, open the Serial Monitor to
* view the status of the program. Tune your SSTV to
* 446MHz to receive the image output.
*/
#define MIC_PIN 3
#define RESET_PIN A3
#define SWITCH_PIN 2
#define DOT 100
#define CALLSIGN "1ZZ9ZZ/B"
/* Standard libraries and variable init */
#include <HAMShield.h>
#include <Wire.h>
#include <HamShield.h>
HAMShield radio;
HamShield radio;
int16_t rssi;
/* get our radio ready */
void setup() {
Wire.begin();
// NOTE: if not using PWM out, it should be held low to avoid tx noise
pinMode(MIC_PIN, OUTPUT);
digitalWrite(MIC_PIN, LOW);
// prep the switch
pinMode(SWITCH_PIN, INPUT_PULLUP);
// set up the reset control pin
// NOTE: HamShieldMini doesn't have a reset pin, so this has no effect
pinMode(RESET_PIN, OUTPUT);
digitalWrite(RESET_PIN, HIGH);
delay(5); // wait for device to come up
Serial.begin(9600);
Serial.print("Radio status: ");
int result = radio.testConnection();
Serial.println(result);
radio.initialize();
radio.setFrequency(446000);
radio.frequency(446000);
radio.setModeReceive();
}
@ -32,7 +53,7 @@ void setup() {
void loop() {
if(radio.waitForChannel(1000,2000)) { // Wait forever for calling frequency to open, then wait 2 seconds for breakers
if(radio.waitForChannel(1000,2000, -90)) { // Wait forever for calling frequency to open, then wait 2 seconds for breakers
radio.setModeTransmit(); // Turn on the transmitter
delay(250); // Wait a moment
radio.SSTVTestPattern(MARTIN1); // send a MARTIN1 test pattern

View File

@ -0,0 +1,455 @@
/* Hamshield
* Example: SSTV M1 Static
* This program will transmit a static image. You will need
* SSTV equipment to test the output.
* Connect the HamShield to your Arduino. Screw the antenna
* into the HamShield RF jack. Connect the Arduino to wall
* power and then to your computer via USB. After uploading
* this program to your Arduino, open the Serial Monitor to
* view the status of the program. Tune your SSTV to
* 145.5MHz to receive the image output.
*/
// So the precalculated values will get stored
#define DDS_REFCLK_DEFAULT (34965/2)
#include <HamShield.h>
#include <DDS.h>
#define MIC_PIN 3
#define RESET_PIN A3
#define SWITCH_PIN 2
HamShield radio;
DDS dds;
// Defined at the end of the sketch
extern const uint16_t image[256*20] PROGMEM;
#define F_1200 0
#define F_1500 1
#define F_2400 2
ddsAccumulator_t freqTable[3];
void setup() {
// NOTE: if not using PWM out, it should be held low to avoid tx noise
pinMode(MIC_PIN, OUTPUT);
digitalWrite(MIC_PIN, LOW);
// prep the switch
pinMode(SWITCH_PIN, INPUT_PULLUP);
// set up the reset control pin
// NOTE: HamShieldMini doesn't have a reset pin, so this has no effect
pinMode(RESET_PIN, OUTPUT);
digitalWrite(RESET_PIN, HIGH);
delay(5); // wait for device to come up
Serial.begin(9600);
// Query the HamShield for status information
Serial.print("Radio status: ");
int result = 0;
result = radio.testConnection();
Serial.println(result,DEC);
// Tell the HamShield to start up
radio.initialize();
radio.setRfPower(0);
radio.frequency(446000);
// put your setup code here, to run once:
//dds.setReferenceClock(34965/4);
dds.start();
freqTable[F_1200] = dds.calcFrequency(1200);
freqTable[F_1500] = dds.calcFrequency(1500);
freqTable[F_2400] = dds.calcFrequency(2400);
dds.setFrequency(1000);
dds.on();
Serial.println("DDS on");
delay(1000);
dds.off();
delay(2000);
Serial.println("Next");
}
uint8_t code = MARTIN1;
bool parityCalc(int code) {
unsigned int v; // word value to compute the parity of
bool parity = false; // parity will be the parity of v
while (code)
{
parity = !parity;
code = code & (code - 1);
}
return parity;
}
volatile bool registered = false;
volatile bool scanning = false;
volatile bool done = false;
volatile uint16_t nextBlock = 0;
volatile uint8_t currentScanline = 0;
volatile uint16_t scanline[2][20];
// Format is 3 'images', one each for green, blue and red
// But we don't have room, so it's monochrome
// 256 rows each
// 10 sets of 32 bits encoding on/off for the colour
//const unsigned long image[256][10] PROGMEM = {
//};
void loadScanline(uint8_t s, int y) {
for(int i = 0; i < 20; i++) {
scanline[s][i] = pgm_read_word_near(image + y*20 + i);
}
}
#define DON() PORTD |= _BV(2);
#define DOFF() PORTD &= ~_BV(2);
void loop() {
// Load the first scanline
loadScanline(0, 0);
radio.setModeTransmit();
delay(500);
// VIS
dds.playWait(1900,300);
dds.playWait(1200,10);
dds.playWait(1900,300);
dds.playWait(1200,30);
for(int x = 0; x < 7; x++) {
if(bitRead(code,x)) { dds.playWait(1100,30); } else { dds.playWait(1300,30); }
}
if(parityCalc(code)) { dds.playWait(1300,30); } else { dds.playWait(1100,30); }
dds.playWait(1200,30);
dds.on();
for(int y = 1; y < 256; y++){
DON();
dds.setPrecalcFrequency(freqTable[F_1200]);
// Subtract for the timer ticks
delayMicroseconds(3562); // sync pulse (4862 uS)
DOFF();
DON();
dds.setPrecalcFrequency(freqTable[F_1500]);
// Subtract for the timer ticks
delayMicroseconds(442); // sync porch (572 uS)
DOFF();
scanning = true;
for(uint8_t c = 0; c<3; c++) {
scanning = true;
while(!registered);
registered = false;
loadScanline((++currentScanline) & 1, y);
while(!done);
dds.setPrecalcFrequency(freqTable[F_1500]);
done = false;
scanning = false;
DON();
delayMicroseconds(442); // color separator pulse (572 uS)
DOFF();
}
}
dds.off();
radio.setModeReceive();
delay(10000);
return;
}
// The DDS is running faster than the pixel clock, so we
// only update the pixel frequency every few ticks.
ISR(ADC_vect) {
static uint8_t tcnt = 0;
static uint8_t shifts = 0;
static uint8_t shiftingLine = 0;
static uint8_t linePos = 0;
static uint16_t pixelBlock;
TIFR1 |= _BV(ICF1);
dds.clockTick();
if(scanning) {
if(++tcnt == 8) {
tcnt = 0;
if(linePos == 21) {
done = true;
linePos = 0;
}
if(linePos == 0) {
shifts = 0;
shiftingLine = currentScanline&1;
registered = true;
}
if(shifts == 0) {
pixelBlock = scanline[shiftingLine][linePos++];
}
if(pixelBlock & 0x8000) {
dds.setPrecalcFrequency(freqTable[F_2400]);
} else {
dds.setPrecalcFrequency(freqTable[F_1500]);
}
if(++shifts == 16) {
shifts = 0;
}
pixelBlock <<= 1;
}
}
}
// Image is 256 lines * 320 pixels per line, packed to 16 bits at a time
const uint16_t image[256*20] PROGMEM = {
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 1
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 2
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 3
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 4
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 5
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 6
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 7
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 8
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 9
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 10
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 11
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 12
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 13
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 14
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 15
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 16
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 17
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 18
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 19
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 20
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 21
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 22
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 23
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 24
0xFFFF, 0xE0FF, 0x07FF, 0xBFCF, 0xFFFF, 0xFFC1, 0xF3FE, 0x7FF9, 0xFF3F, 0xFC1F, 0xE0FF, 0xF7F9, 0xFFFF, 0xFFF8, 0x3E7F, 0xCFFF, 0x3FE7, 0xFFFF, 0xFFFF, 0xFFFF, // Line 25
0xFFFF, 0x807C, 0x03FF, 0x3FCF, 0xFFFF, 0xFF80, 0x73FE, 0x7FF9, 0xFF3F, 0xF00F, 0x807F, 0xE7F9, 0xFFFF, 0xFFF0, 0x0E7F, 0xCFFF, 0x3FE7, 0xFFFF, 0xFFFF, 0xFFFF, // Line 26
0xFFFF, 0x1F38, 0xF9FF, 0x3FCF, 0xFFFF, 0xFF1E, 0x33FF, 0xFFF9, 0xFF3F, 0xE3E7, 0x1F3F, 0xE7F9, 0xFFFF, 0xFFE3, 0xC67F, 0xFFFF, 0x3FE7, 0xFFFF, 0xFFFF, 0xFFFF, // Line 27
0xFFFF, 0x3F19, 0xFCFF, 0x3FCF, 0xFFFF, 0xFF3F, 0x33FF, 0xFFF9, 0xFF3F, 0xE7E3, 0x3F9F, 0xE7F9, 0xFFFF, 0xFFE7, 0xE67F, 0xFFFF, 0x3FE7, 0xFFFF, 0xFFFF, 0xFFFF, // Line 28
0xFFFE, 0x7FF3, 0xFCFF, 0x3FCF, 0x0723, 0x8F3F, 0xF21E, 0x7879, 0xE13F, 0xCFFE, 0x7F9F, 0xE7F9, 0xE0E4, 0x71E7, 0xFE43, 0xCF0F, 0x3C27, 0xFFFF, 0xFFFF, 0xFFFF, // Line 29
0xFFFE, 0x7FF3, 0xFCFF, 0x3FCE, 0x0300, 0x071F, 0xF00E, 0x7019, 0xC03F, 0xCFFE, 0x7F9F, 0xE7F9, 0xC060, 0x00E3, 0xFE01, 0xCE03, 0x3807, 0xFFFF, 0xFFFF, 0xFFFF, // Line 30
0xFFFE, 0x7FF3, 0xFE7F, 0x000C, 0xF31C, 0x7381, 0xF1E6, 0x6799, 0x9E3F, 0xCFFE, 0x7FCF, 0xE001, 0x9E63, 0x8E70, 0x3E3C, 0xCCF3, 0x33C7, 0xFFFF, 0xFFFF, 0xFFFF, // Line 31
0xFFFE, 0x7FF3, 0xFC7F, 0x000F, 0x833C, 0xF3F0, 0x73E6, 0x67C9, 0x9F3F, 0xCFFE, 0x7F8F, 0xE001, 0xF067, 0x9E7E, 0x0E7C, 0xCCF9, 0x33E7, 0xFFFF, 0xFFFF, 0xFFFF, // Line 32
0xFFFE, 0x7FF3, 0xFCFF, 0x3FCE, 0x033C, 0xF3FF, 0x33E6, 0x6009, 0x9F3F, 0xCFFE, 0x7F9F, 0xE7F9, 0xC067, 0x9E7F, 0xE67C, 0xCC01, 0x33E7, 0xFFFF, 0xFFFF, 0xFFFF, // Line 33
0xFFFE, 0x7FB3, 0xFCFF, 0x3FCC, 0xF33C, 0xF3FF, 0x33E6, 0x67F9, 0x9F3F, 0xCFF6, 0x7F9F, 0xE7F9, 0x9E67, 0x9E7F, 0xE67C, 0xCCFF, 0x33E7, 0xFFFF, 0xFFFF, 0xFFFF, // Line 34
0xFFFF, 0x3F19, 0xE0FF, 0x3FCC, 0xF33C, 0xF33F, 0x33E6, 0x67F9, 0x9F3F, 0xE7E3, 0x3C1F, 0xE7F9, 0x9E67, 0x9E67, 0xE67C, 0xCCFF, 0x33E7, 0xFFFF, 0xFFFF, 0xFFFF, // Line 35
0xFFFF, 0x1F38, 0xF1FF, 0x3FCC, 0xE33C, 0xF31F, 0x33E6, 0x6789, 0x9E3F, 0xE3E7, 0x1E3F, 0xE7F9, 0x9C67, 0x9E63, 0xE67C, 0xCCF1, 0x33C7, 0xFFFF, 0xFFFF, 0xFFFF, // Line 36
0xFFFF, 0x807C, 0x01FF, 0x3FCC, 0x033C, 0xF380, 0x73E6, 0x7019, 0xC03F, 0xF00F, 0x803F, 0xE7F9, 0x8067, 0x9E70, 0x0E7C, 0xCE03, 0x3807, 0xFFFF, 0xFFFF, 0xFFFF, // Line 37
0xFFFF, 0xE0FF, 0x04FF, 0xBFCE, 0x1B3C, 0xF3C0, 0xF3E6, 0x7839, 0xE13F, 0xFC1F, 0xE09F, 0xF7F9, 0xC367, 0x9E78, 0x1E7C, 0xCF07, 0x3C27, 0xFFFF, 0xFFFF, 0xFFFF, // Line 38
0xFFFF, 0xFFFF, 0xFEFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFDF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 39
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 40
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 41
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 42
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 43
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 44
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 45
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 46
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 47
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 48
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 49
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 50
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 51
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 52
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 53
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 54
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 55
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x1FFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 56
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFE0, 0x007F, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 57
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFF80, 0x001F, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 58
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFE00, 0x0007, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 59
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFC3, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFC00, 0x0003, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 60
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xF800, 0x3FFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xF800, 0x0001, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 61
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xC000, 0x0FFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xF800, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 62
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x8000, 0x03FF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xF000, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 63
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, 0x01FF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xE000, 0x0000, 0x7FFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 64
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFE, 0x0000, 0x00FF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xE000, 0x0000, 0x7FFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 65
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFC, 0x0000, 0x007F, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xC000, 0x0000, 0x7FFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 66
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFC, 0x0000, 0x003F, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xC000, 0x0000, 0x7FFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 67
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFF8, 0x0000, 0x001F, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xC000, 0x0000, 0x7FFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 68
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFF8, 0x0000, 0x000F, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xC000, 0x0000, 0x7FFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 69
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFF8, 0x0000, 0x000F, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x8000, 0x0000, 0x7FFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 70
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFF0, 0x0000, 0x000F, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x8000, 0x0000, 0x7FFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 71
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFF0, 0x0000, 0x0007, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x8000, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 72
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFE0, 0x0000, 0x0007, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x8000, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 73
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFE0, 0x0000, 0x0007, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x8000, 0x0001, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 74
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFE0, 0x0000, 0x0007, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x8000, 0x0001, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 75
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFE0, 0x0000, 0x0007, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x8000, 0x0003, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 76
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFE0, 0x0000, 0x0007, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x8000, 0x0003, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 77
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFE0, 0x0000, 0x0007, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x8000, 0x0007, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 78
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFE0, 0x0000, 0x0007, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xC000, 0x000F, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 79
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFE0, 0x0000, 0x000F, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xC000, 0x001F, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 80
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFE0, 0x0000, 0x000F, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xE000, 0x007F, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 81
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFF0, 0x0000, 0x001F, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xF000, 0x01FF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 82
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFF0, 0x0000, 0x001F, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFC00, 0x07FF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 83
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFF8, 0x0000, 0x003F, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 84
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFC, 0x0000, 0x007F, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 85
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFE, 0x0000, 0x01FF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 86
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x8000, 0x07FF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 87
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xF000, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 88
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 89
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 90
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 91
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 92
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 93
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 94
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 95
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 96
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 97
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 98
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 99
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 100
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 101
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 102
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 103
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 104
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 105
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 106
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 107
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 108
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 109
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x87FF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 110
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x03FF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 111
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFE, 0x01FF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 112
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFE, 0x01FF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 113
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFE, 0x01FF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 114
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFE, 0x01FF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 115
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x03FF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 116
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x87FF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 117
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 118
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 119
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 120
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 121
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 122
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 123
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 124
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 125
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 126
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 127
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 128
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 129
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xF9FF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 130
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xE07F, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 131
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xC03F, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 132
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x801F, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 133
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x000F, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 134
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x000F, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 135
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x000F, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 136
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x000F, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 137
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x0007, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 138
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x0007, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFF83, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 139
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x0007, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFE01, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 140
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x0007, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFC00, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 141
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x0003, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xF800, 0x7FFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 142
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x0001, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xF000, 0x7FFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 143
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x0001, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xE000, 0x7FFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 144
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x8000, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xE000, 0x7FFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 145
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x8000, 0x7FFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xC000, 0x7FFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 146
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xC000, 0x3FFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x8000, 0x7FFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 147
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xC000, 0x1FFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x8000, 0x7FFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 148
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xE000, 0x07FF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 149
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xF000, 0x03FF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFE, 0x0001, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 150
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xF000, 0x00FF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFC, 0x0001, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 151
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xF800, 0x003F, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFF0, 0x0003, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 152
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFC00, 0x001F, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFE0, 0x0007, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 153
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFE00, 0x000F, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFC0, 0x0007, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 154
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFF00, 0x0003, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFF00, 0x000F, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 155
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFF80, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFE00, 0x001F, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 156
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFC0, 0x0000, 0x3FFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFC00, 0x003F, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 157
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFE0, 0x0000, 0x0FFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xF800, 0x003F, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 158
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFF0, 0x0000, 0x03FF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xF000, 0x007F, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 159
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFC, 0x0000, 0x00FF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xE000, 0x00FF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 160
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFE, 0x0000, 0x003F, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xC000, 0x03FF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 161
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x8000, 0x000F, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, 0x07FF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 162
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xE000, 0x0003, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFC, 0x0000, 0x1FFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 163
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xF000, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFF0, 0x0000, 0x3FFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 164
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFC00, 0x0000, 0x3FFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFC0, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 165
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFE00, 0x0000, 0x0FFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFF00, 0x0001, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 166
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFF80, 0x0000, 0x03FF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFC00, 0x0003, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 167
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFE0, 0x0000, 0x00FF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xE000, 0x0007, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 168
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFF8, 0x0000, 0x003F, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFE, 0x0000, 0x000F, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 169
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFE, 0x0000, 0x000F, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFE0, 0x0000, 0x001F, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 170
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x8000, 0x0003, 0xFFFF, 0xFFFF, 0xFFFF, 0xFF80, 0x0000, 0x003F, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 171
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xE000, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0xFC00, 0x0000, 0x007F, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 172
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFC00, 0x0000, 0x3FFF, 0xFFFF, 0xFFFF, 0xF000, 0x0000, 0x01FF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 173
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFF00, 0x0000, 0x07FF, 0xFFFF, 0xFFFF, 0xC000, 0x0000, 0x03FF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 174
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFF80, 0x0000, 0x001F, 0xFFFF, 0xFFF8, 0x0000, 0x0000, 0x0FFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 175
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFE0, 0x0000, 0x0000, 0x1FFF, 0xA000, 0x0000, 0x0000, 0x7FFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 176
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFF8, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 177
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFE, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x000F, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 178
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x8000, 0x0000, 0x0000, 0x0000, 0x0000, 0x003F, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 179
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xE000, 0x0000, 0x0000, 0x0000, 0x0000, 0x00FF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 180
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xF800, 0x0000, 0x0000, 0x0000, 0x0000, 0x0FFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 181
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFE00, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 182
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFF80, 0x0000, 0x0000, 0x0000, 0x0007, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 183
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFE0, 0x0000, 0x0000, 0x0000, 0x001F, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 184
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFC, 0x0000, 0x0000, 0x0000, 0x007F, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 185
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x03FF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 186
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xF000, 0x0000, 0x0000, 0x1FFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 187
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFC0, 0x0000, 0x0007, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 188
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 189
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 190
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 191
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 192
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 193
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 194
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 195
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 196
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 197
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 198
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 199
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 200
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 201
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 202
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 203
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 204
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 205
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 206
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 207
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 208
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 209
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 210
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 211
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 212
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 213
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 214
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 215
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 216
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 217
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 218
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 219
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 220
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 221
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 222
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 223
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 224
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 225
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 226
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 227
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 228
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 229
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xF9FF, 0xFFBF, 0xEE00, 0xF87F, 0x07EF, 0xFC03, 0xFFFF, 0xFFFF, // Line 230
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xF9FF, 0xFF9F, 0xCC00, 0xF01E, 0x01CF, 0xF801, 0xFFFF, 0xFFFF, // Line 231
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xF9FF, 0xFF9F, 0xCCFF, 0xE79C, 0x78CF, 0xF9F8, 0xFFFF, 0xFFFF, // Line 232
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xF9FF, 0xFF8F, 0x8CFF, 0xEFDC, 0xFCCF, 0xF9FC, 0xFFFF, 0xFFFF, // Line 233
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x09E1, 0xFFCF, 0x9CFF, 0xCFFC, 0xFFCF, 0xF9FC, 0xFFFF, 0xFFFF, // Line 234
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFE, 0x01C0, 0x7FCF, 0x9CFF, 0xC83C, 0x7FCF, 0xF9F8, 0xFFFF, 0xFFFF, // Line 235
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFC, 0xF19E, 0x7FE7, 0x3C01, 0xC01E, 0x07CF, 0xF801, 0xFFFF, 0xFFFF, // Line 236
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFC, 0xF99F, 0x3FE7, 0x3C01, 0xC78F, 0xC1CF, 0xF803, 0xFFFF, 0xFFFF, // Line 237
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFC, 0xF980, 0x3FE7, 0x3CFF, 0xCFCF, 0xFCCF, 0xF9FF, 0xFFFF, 0xFFFF, // Line 238
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFC, 0xF99F, 0xFFF2, 0x7CFF, 0xCFCF, 0xFCCF, 0xF9FF, 0xFFFF, 0xFFFF, // Line 239
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFC, 0xF99F, 0xFFF2, 0x7CFF, 0xCFCC, 0xFCCF, 0xF9FF, 0xFFFF, 0xFFFF, // Line 240
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFC, 0xF19E, 0x3FF8, 0xFCFF, 0xE79C, 0x7CCF, 0xF9FF, 0xFFFF, 0xFFFF, // Line 241
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFE, 0x01C0, 0x7FF8, 0xFC00, 0xF01E, 0x01E0, 0x09FF, 0xFFFF, 0xFFFF, // Line 242
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x09E0, 0xFFF8, 0xFE00, 0xF87F, 0x03E0, 0x0DFF, 0xFFFF, 0xFFFF, // Line 243
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 244
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 245
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 246
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 247
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 248
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 249
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 250
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 251
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 252
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 253
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 254
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 255
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // Line 256
};

551
examples/SerialTransceiver/SerialTransceiver.ino Executable file → Normal file
View File

@ -1,36 +1,46 @@
/*
/* Hamshield
* Example: Serial Tranceiver
* SerialTransceiver is TTL Serial port "glue" to allow
* desktop or laptop control of the HamShield.
* Connect the HamShield to your Arduino. Screw the antenna
* into the HamShield RF jack. Plug a pair of headphones into
* the HamShield. Connect the Arduino to wall power and then
* to your computer via USB. After uploading this program to
* your Arduino, open the Serial Monitor. Use the bar at the
* top of the serial monitor to enter commands as seen below.
*
* EXAMPLE: To change the repeater offset to 144.425MHz,
* enable offset, then key in, use the following commands:
* T144425;
* R1;
* [Just a space]
SerialTransceiver is TTL Serial port "glue" to allow desktop or laptop control of the HAMShield
// see also: https://github.com/EnhancedRadioDevices/HamShield/wiki/HamShield-Serial-Mode
Commands:
Mode ASCII Description Implemented
-------------- ----------- -------------------------------------------------------------------------------------------------------------------------------------------- -----------------
Transmit space Space must be received at least every 500 mS Yes
Receive not space If space is not received and/or 500 mS timeout of space occurs, unit will go into receive mode Yes
CTCSS In A<tone>; <tone> must be a numerical ascii value with decimal point indicating CTCSS receive tone required to unsquelch No
CTCSS Out B<tone>; <tone> must be a numerical ascii value with decimal point indicating CTCSS transmit tone No
CTCSS Enable C<state>; Turns on CTCSS mode (analog tone) with 1, off with 0. No
CDCSS Enable D<state>; Turns on CDCSS mode (digital tone) with 1, off with 0. No
Bandwidth E<mode>; for 12.5KHz mode is 0, for 25KHz, mode is 1 No
Frequency F<freq>; Set the receive frequency in KHz, if offset is disabled, this is the transmit frequency No
CDCSS In G<code>; <code> must be a valid CDCSS code No
CDCSS Out H<code>; <code> must be a valid CDCSS code No
Print tones I Prints out all configured tones and codes, coma delimited in format: CTCSS In, CTCSS Out, CDCSS In, CDCSS Out No
Power level P<level>; Set the power amp level, 0 = lowest, 15 = highest No
Enable Offset R<state>; 1 turns on repeater offset mode, 0 turns off repeater offset mode No
Squelch S<level>; Set the squelch level No
TX Offset T<freq>; The absolute frequency of the repeater offset to transmit on in KHz No
Volume V<level>; Set the volume level of the receiver No
Reset X Reset all settings to default No
Sleep Z Sleep radio No
Filters @<state>; Set bit to enable, clear bit to disable: 0 = pre/de-emphasis, 1 = high pass filter, 2 = low pass filter (default: ascii 7, all enabled) No
Vox mode $<state>; 0 = vox off, >= 1 audio sensitivity. lower value more sensitive No
Mic Channel *<state>; Set the voice channel. 0 = signal from mic or arduino, 1 = internal tone generator No
RSSI ? Respond with the current receive level in - dBm (no sign provided on numerical response) No
Tone Gen % (notes) To send a tone, use the following format: Single tone: %1,<freq>,<length>; Dual tone: %2,<freq>,<freq>,<length>; DTMF: %3,<key>,<length>; No
Voice Level ^ Respond with the current voice level (VSSI)
Mode ASCII Description
-------------- ----------- --------------------------------------------------------------------------------------------------------------------------------------------
Transmit space Space must be received at least every 500 mS
Receive not space If space is not received and/or 500 mS timeout of space occurs, unit will go into receive mode
Frequency F<freq>; Set the receive frequency in KHz, if offset is disabled, this is the transmit frequency
Morse Out M<text>; A small buffer for morse code (32 chars)
Morse In N; Sets mode to Morse In, listening for Morse
Power level P<level>; Set the power amp level, 0 = lowest, 15 = highest
Enable Offset R<state>; 1 turns on repeater offset mode, 0 turns off repeater offset mode
Squelch S<level>; Set the squelch level
TX Offset T<freq>; The absolute frequency of the repeater offset to transmit on in KHz
RSSI ? Respond with the current receive level in - dBm (no sign provided on numerical response)
Voice Level ^ Respond with the current voice level (VSSI), only valid when transmitting
DTMF Out D<vals>; A small buffer for DTMF out (only 0-9,A,B,C,D,*,# accepted)
DTMF In B; Sets mode to DTMF In, listening for DTMF
PL Tone Tx A<val>; Sets PL tone for TX, value is tone frequency in Hz (float), set to 0 to disable
PL Tone Rx C<val>; Sets PL tone for RX, value is tone frequency in Hz (float), set to 0 to disable
Volume 1 V1<val>; Set volume 1 (value between 0 and 15)
Volume 2 V2<val>; Set volume 2 (value between 0 and 15)
KISS TNC K; Move to KISS TNC mode (send ^; to move back to normal mode). NOT IMPELEMENTED YET
Normal Mode _ Move to Normal mode from any other mode (except TX)
Responses:
@ -42,137 +52,349 @@ Error X<code>; Indicates an error code. The numerical value is the type
Value :<value>; In response to a query
Status #<value>; Unsolicited status message
Debug Msg @<text>; 32 character debug message
Rx Msg R<text>; up to 32 characters of received message, only if device is in DTMF or Morse Rx modes
*/
#include "Wire.h"
#include "HAMShield.h"
int state;
// Note that the following are not yet implemented
// TODO: change get_value so it's intuitive
// TODO: Squelch open and squelch shut independently controllable
// TODO: pre/de emph filter
// TODO: walkie-talkie
// TODO: KISS TNC
#include "HamShield.h"
#define MIC_PIN 3
#define RESET_PIN A3
#define SWITCH_PIN 2
enum {TX, NORMAL, DTMF, MORSE, KISS};
int state = NORMAL;
bool rx_ctcss = false;
bool muted = false;
int txcount = 0;
long timer = 0;
long freq = 144390;
long tx = 0;
long timer = 0; // Transmit timer to track timeout (send space to reset)
long freq = 432100; // 70cm calling frequency, receive frequency and default transmit frequency
long tx_freq = 0; // transmit frequency if repeater is on
int pwr = 0; // tx power
char cmdbuff[32] = "";
int temp = 0;
int repeater = 0;
bool repeater = false; // true if transmit and receive operate on different frequencies
char pl_rx_buffer[32]; // pl tone rx buffer
char pl_tx_buffer[32]; // pl tone tx buffer
float ctcssin = 0;
float ctcssout = 0;
int cdcssin = 0;
int cdcssout = 0;
HAMShield radio;
HamShield radio;
void setup() {
Serial.begin(115200);
Serial.print(";;;;;;;;;;;;;;;;;;;;;;;;;;");
Wire.begin();
// NOTE: if not using PWM out (MIC pin), it should be held low to avoid tx noise
pinMode(MIC_PIN, OUTPUT);
digitalWrite(MIC_PIN, LOW);
// prep the switch
pinMode(SWITCH_PIN, INPUT_PULLUP);
// set up the reset control pin
// NOTE: HamShieldMini doesn't have a reset pin, so this has no effect
pinMode(RESET_PIN, OUTPUT);
digitalWrite(RESET_PIN, HIGH);
Serial.begin(9600);
Serial.println(";;;;;;;;;;;;;;;;;;;;;;;;;;");
int result = radio.testConnection();
Serial.print("*");
Serial.print(result,DEC);
Serial.print(";");
Serial.println(";");
radio.initialize(); // initializes automatically for UHF 12.5kHz channel
Serial.print("*START;");
radio.frequency(freq);
radio.setVolume1(0xF);
radio.setVolume2(0xF);
radio.setModeReceive();
radio.setTxSourceMic();
radio.setRfPower(9);
radio.setSQLoThresh(80);
radio.setRfPower(pwr);
radio.setSQLoThresh(-80);
radio.setSQHiThresh(-70);
radio.setSQOn();
Serial.println("*START;");
}
void loop() {
if(Serial.available()) {
int text = Serial.read();
int text = Serial.read(); // get the first char to see what the upcoming command is
switch (state) {
// we handle commands differently based on what state we're in
case 10:
if(text == 32) { timer = millis();}
case TX:
// we're currently transmitting
// if we got a space, reset our transmit timeout
if(text == ' ') { timer = millis();}
break;
case 0:
case NORMAL:
switch(text) {
case 32: // space - transmit
if(repeater == 1) { radio.frequency(tx); }
radio.setRX(0);
radio.setTX(1);
state = 10;
Serial.print("#TX,ON;");
case ' ': // space - transmit
if(repeater == true && tx_freq != 0) { radio.frequency(tx_freq); }
muted = false; // can't mute (for PL tones) during tx
radio.setUnmute();
radio.setModeTransmit();
state = TX;
Serial.println("#TX,ON;");
timer = millis();
break;
case 63: // ? - RSSI
case '?': // ? - RSSI
Serial.print(":");
Serial.print(radio.readRSSI(),DEC);
Serial.print(";");
Serial.println(";");
break;
case 65: // A - CTCSS In
getValue();
ctcssin = atof(cmdbuff);
radio.setCtcss(ctcssin);
case '^': // ^ - VSSI (voice) level
Serial.print(":");
Serial.print(radio.readVSSI(),DEC);
Serial.println(";");
break;
case 66: // B - CTCSS Out
break;
case 67: // C - CTCSS Enable
break;
case 68: // D - CDCSS Enable
break;
case 70: // F - frequency
case 'F': // F - frequency
getValue();
freq = atol(cmdbuff);
if(radio.frequency(freq) == true) { Serial.print("@"); Serial.print(freq,DEC); Serial.print(";!;"); } else { Serial.print("X1;"); }
if(radio.frequency(freq) == true) {
Serial.print("@");
Serial.print(freq,DEC);
Serial.println(";!;");
} else {
Serial.println("X1;");
}
break;
case 80: // P - power level
case 'P': // P - power level
getValue();
temp = atol(cmdbuff);
radio.setRfPower(temp);
Serial.println("!;");
break;
case 82: // R - repeater offset mode
case 'S': // S - squelch
getValue();
temp = atol(cmdbuff);
if (temp < -2 && temp > -130) {
radio.setSQLoThresh(temp);
radio.setSQHiThresh(temp+2);
radio.setSQOn();
Serial.print(temp);
Serial.println("!;");
} else {
Serial.println("X!;");
}
break;
case 'R': // R - repeater offset mode
getValue();
temp = atol(cmdbuff);
if(temp == 0) { repeater = 0; }
if(temp == 1) { repeater = 1; }
Serial.println("!;");
break;
case 83: // S - squelch
case 'T': // T - transmit offset
getValue();
temp = atol(cmdbuff);
radio.setSQLoThresh(temp);
tx_freq = atol(cmdbuff);
Serial.println("!;");
break;
case 84: // T - transmit offset
case 'M': // M - Morse
getValue();
tx = atol(cmdbuff);
if(repeater == true && tx_freq != 0) { radio.frequency(tx_freq); }
muted = false; // can't mute (for PL tones) during tx
radio.setUnmute();
radio.setModeTransmit();
delay(300);
radio.morseOut(cmdbuff);
if(repeater == true) { radio.frequency(freq); }
radio.setModeReceive();
Serial.println("!;");
break;
case 'N': // N - set to Morse in Mode
morse_rx_setup();
state = MORSE;
Serial.println("!;");
break;
case 94: // ^ - VSSI (voice) level
Serial.print(":");
Serial.print(radio.readVSSI(),DEC);
Serial.print(";");
case 'D': // D - DTMF Out
dtmfSetup();
getValue();
dtmf_out(cmdbuff);
Serial.println("!;");
break;
case 'B': // B - set to DTMF in Mode
dtmfSetup();
radio.enableDTMFReceive();
state = DTMF;
Serial.println("!;");
break;
case 'A': // A - TX PL Tone configuration command
pl_tone_tx();
Serial.println("!;");
break;
case 'C': // C - RX PL Tone configuration command
pl_tone_rx();
Serial.println("!;");
break;
case 'V': // V - set volume
getValue();
temp = cmdbuff[0];
if (temp == 0x31) {
temp = atol(cmdbuff + 1);
radio.setVolume1(temp);
Serial.println("!;");
} else if (temp == 0x32) {
temp = atol(cmdbuff + 1);
radio.setVolume2(temp);
Serial.println("!;");
} else {
// not a valid volume command
while (Serial.available()) { Serial.read(); }
Serial.println("X!;");
}
break;
case 'K': // K - switch to KISS TNC mode
//state = KISS;
//TODO: set up KISS
Serial.println("X1;");
break;
default:
// unknown command, flush the input buffer and wait for next one
Serial.println("X1;");
while (Serial.available()) { Serial.read(); }
break;
}
break;
case KISS:
if (Serial.peek() == '_') {
state = NORMAL;
if (rx_ctcss) {
radio.enableCtcss();
muted = true; // can't mute (for PL tones) during tx
radio.setMute();
}
}
// TODO: handle KISS TNC
break;
case MORSE:
if (text == '_') { state = NORMAL; }
if (text == 'M') { // tx message
getValue();
if(repeater == true && tx_freq != 0) { radio.frequency(tx_freq); }
muted = false; // can't mute (for PL tones) during tx
radio.setUnmute();
radio.setModeTransmit();
delay(300);
radio.morseOut(cmdbuff);
if(repeater == true) { radio.frequency(freq); }
radio.setModeReceive();
} else {
// not a valid cmd
while (Serial.available()) { Serial.read(); }
}
break;
case DTMF:
if (text == '_') { state = NORMAL; }
if (text == 'D') { // tx message
getValue();
dtmf_out(cmdbuff);
} else {
// not a valid cmd
while (Serial.available()) { Serial.read(); }
}
break;
default:
// we're in an invalid state, reset to safe settings
while (Serial.available()) { Serial.read(); }
radio.frequency(freq);
radio.setModeReceive();
state = NORMAL;
break;
}
}
if(state == 10) {
if(millis() > (timer + 500)) { Serial.print("#TX,OFF;");radio.setRX(1); radio.setTX(0); if(repeater == 1) { radio.frequency(freq); } state = 0; txcount = 0; }
// now handle any state related functions
switch (state) {
case TX:
if(millis() > (timer + 500)) {
Serial.println("#TX,OFF;");
radio.setModeReceive();
if(repeater == true) { radio.frequency(freq); }
if (rx_ctcss) {
radio.setMute();
muted = true;
}
txcount = 0;
state = NORMAL;
}
break;
case NORMAL:
// deal with rx ctccs if necessary
if (rx_ctcss) {
if (radio.getCtcssToneDetected()) {
if (muted) {
muted = false;
radio.setUnmute();
}
} else {
if (!muted) {
muted = true;
radio.setMute();
}
}
}
break;
case DTMF:
dtmf_rx(); // wait for DTMF reception
break;
case MORSE:
morse_rx(); // wait for Morse reception
break;
}
// get rid of any trailing whitespace in the serial buffer
if (Serial.available()) {
char cpeek = Serial.peek();
while (cpeek == ' ' || cpeek == '\r' || cpeek == '\n')
{
Serial.read();
cpeek = Serial.peek();
}
}
}
@ -182,22 +404,159 @@ void getValue() {
for(;;) {
if(Serial.available()) {
temp = Serial.read();
if(temp == 59) { cmdbuff[p] = 0; Serial.print("@");
for(int x = 0; x < 32; x++) { Serial.print(cmdbuff[x]); }
if(temp == 59) {
cmdbuff[p] = 0;
return;
}
cmdbuff[p] = temp;
p++;
if(p == 32) {
Serial.print("@");
for(int x = 0; x < 32; x++) {
Serial.print(cmdbuff[x]);
}
cmdbuff[0] = 0;
Serial.print("X0;"); return; } // some sort of alignment issue? lets not feed junk into whatever takes this string in
return;
}
}
}
}
void dtmfSetup() {
radio.setVolume1(6);
radio.setVolume2(0);
radio.setDTMFDetectTime(24); // time to detect a DTMF code, units are 2.5ms
radio.setDTMFIdleTime(50); // time between transmitted DTMF codes, units are 2.5ms
radio.setDTMFTxTime(60); // duration of transmitted DTMF codes, units are 2.5ms
}
void dtmf_out(char * out_buf) {
if (out_buf[0] == ';' || out_buf[0] == 0) return; // empty message
uint8_t i = 0;
uint8_t code = radio.DTMFchar2code(out_buf[i]);
// start transmitting
radio.setDTMFCode(code); // set first
radio.setTxSourceTones();
if(repeater == true && tx_freq != 0) { radio.frequency(tx_freq); }
muted = false; // can't mute during transmit
radio.setUnmute();
radio.setModeTransmit();
delay(300); // wait for TX to come to full power
bool dtmf_to_tx = true;
while (dtmf_to_tx) {
// wait until ready
while (radio.getDTMFTxActive() != 1) {
// wait until we're ready for a new code
delay(10);
}
if (i < 32 && out_buf[i] != ';' && out_buf[i] != 0) {
code = radio.DTMFchar2code(out_buf[i]);
if (code == 255) code = 0xE; // throw a * in there so we don't break things with an invalid code
radio.setDTMFCode(code); // set first
} else {
dtmf_to_tx = false;
break;
}
i++;
while (radio.getDTMFTxActive() != 0) {
// wait until this code is done
delay(10);
}
}
// done with tone
radio.setModeReceive();
if (repeater == true) {radio.frequency(freq);}
radio.setTxSourceMic();
}
void dtmf_rx() {
char m = radio.DTMFRxLoop();
if (m != 0) {
// Note: not doing buffering of messages,
// we just send a single morse character
// whenever we get it
Serial.print('R');
Serial.print(m);
Serial.println(';');
}
}
// TODO: morse config info
void morse_rx_setup() {
// Set the morse code characteristics
radio.setMorseFreq(MORSE_FREQ);
radio.setMorseDotMillis(MORSE_DOT);
radio.lookForTone(MORSE_FREQ);
radio.setupMorseRx();
}
void morse_rx() {
char m = radio.morseRxLoop();
if (m != 0) {
// Note: not doing buffering of messages,
// we just send a single morse character
// whenever we get it
Serial.print('R');
Serial.print(m);
Serial.println(';');
}
}
void pl_tone_tx() {
memset(pl_tx_buffer,0,32);
uint8_t ptr = 0;
while(1) {
if(Serial.available()) {
uint8_t buf = Serial.read();
if(buf == 'X') { return; }
if(buf == ';') { pl_tx_buffer[ptr] = 0; program_pl_tx(); return; }
if(ptr == 31) { return; }
pl_tx_buffer[ptr] = buf; ptr++;
}
}
}
void program_pl_tx() {
float pl_tx = atof(pl_tx_buffer);
radio.setCtcss(pl_tx);
if (pl_tx == 0) {
radio.disableCtcssTx();
} else {
radio.enableCtcssTx();
}
}
void pl_tone_rx() {
memset(pl_rx_buffer,0,32);
uint8_t ptr = 0;
while(1) {
if(Serial.available()) {
uint8_t buf = Serial.read();
if(buf == 'X') { return; }
if(buf == ';') { pl_rx_buffer[ptr] = 0; program_pl_rx(); return; }
if(ptr == 31) { return; }
pl_rx_buffer[ptr] = buf; ptr++;
}
}
}
void program_pl_rx() {
float pl_rx = atof(pl_rx_buffer);
radio.setCtcss(pl_rx);
if (pl_rx == 0) {
rx_ctcss = false;
radio.setUnmute();
muted = false;
radio.disableCtcssRx();
} else {
rx_ctcss = true;
radio.setMute();
muted = true;
radio.enableCtcssRx();
}
}

View File

@ -0,0 +1,704 @@
/* Hamshield
* Example: AppSerialController_nRF52840
* This is a simple example to demonstrate the HamShield working
* with an Adafruit Feather nRF52840 Express
*
* HamShield to Feather Connections:
* SPKR - Feather A0
* MIC - Feather D11
* CLK - Feather D5
* nCS - Feather D6
* DAT - Feather D9
* GND - Feather GND
* VCC - Feather 3.3V
*
* Connect the HamShield to your Feather as above.
* Screw the antenna into the HamShield RF jack. Plug a pair
* of headphones into the HamShield.
*
* Connect the Feather nRF52840 Express to your computer via
* a USB Micro B cable. After uploading this program to
* your Feather, open the Serial Monitor. You should see some
* text displayed that documents the setup process.
*
* Once the Feather is set up and talking to the HamShield,
* you can control it over USB-Serial or BLE-Serial(UART).
*
* Try using Adafruit's Bluefruit app to connect to the Feather.
* Once you're connected, you can control the HamShield using
* the same commands you'd use over USB-Serial. The response to
* all commands will be echoed to both USB-Serial and BLE-Serial(UART).
*
Commands:
Mode ASCII Description
-------------- ----------- --------------------------------------------------------------------------------------------------------------------------------------------
Transmit space Space must be received at least every 500 mS
Receive not space If space is not received and/or 500 mS timeout of space occurs, unit will go into receive mode
Frequency F<freq>; Set the receive frequency in KHz, if offset is disabled, this is the transmit frequency
Morse Out M<text>; A small buffer for morse code (32 chars)
Morse In N; Sets mode to Morse In, listening for Morse
Power level P<level>; Set the power amp level, 0 = lowest, 15 = highest
Enable Offset R<state>; 1 turns on repeater offset mode, 0 turns off repeater offset mode
Squelch S<level>; Set the squelch level
TX Offset T<freq>; The absolute frequency of the repeater offset to transmit on in KHz
RSSI ? Respond with the current receive level in - dBm (no sign provided on numerical response)
Voice Level ^ Respond with the current voice level (VSSI), only valid when transmitting
DTMF Out D<vals>; A small buffer for DTMF out (only 0-9,A,B,C,D,*,# accepted)
DTMF In B; Sets mode to DTMF In, listening for DTMF
PL Tone Tx A<val>; Sets PL tone for TX, value is tone frequency in Hz (float), set to 0 to disable
PL Tone Rx C<val>; Sets PL tone for RX, value is tone frequency in Hz (float), set to 0 to disable
Volume 1 V1<val>; Set volume 1 (value between 0 and 15)
Volume 2 V2<val>; Set volume 2 (value between 0 and 15)
KISS TNC K; Move to KISS TNC mode (send ^; to move back to normal mode). NOT IMPELEMENTED YET
Normal Mode _ Move to Normal mode from any other mode (except TX)
Responses:
Condition ASCII Description
------------ ---------- -----------------------------------------------------------------
Startup *<code>; Startup and shield connection status
Success !; Generic success message for command that returns no value
Error X<code>; Indicates an error code. The numerical value is the type of error
Value :<value>; In response to a query
Status #<value>; Unsolicited status message
Debug Msg @<text>; 32 character debug message
Rx Msg R<text>; up to 32 characters of received message, only if device is in DTMF or Morse Rx modes
*/
// Note that the following are not yet implemented
// TODO: change get_value so it's intuitive
// TODO: Squelch open and squelch shut independently controllable
// TODO: pre/de emph filter
// TODO: walkie-talkie
// TODO: KISS TNC
#include <bluefruit.h>
#include <stdarg.h>
#include <stdio.h>
#include <HamShield.h>
// BLE Service
BLEDis bledis; // device information
BLEUart bleuart; // uart over ble
BLEBas blebas; // battery
// create object for radio
HamShield radio(6,5,9);
// To use non-standard pins, use the following initialization
//HamShield radio(ncs_pin, clk_pin, dat_pin);
#define LED_PIN 3
#define MIC_PIN A1
enum {TX, NORMAL, DTMF, MORSE, KISS};
int state = NORMAL;
bool rx_ctcss = false;
bool muted = false;
int txcount = 0;
long timer = 0; // Transmit timer to track timeout (send space to reset)
long freq = 432100; // 70cm calling frequency, receive frequency and default transmit frequency
long tx_freq = 0; // transmit frequency if repeater is on
int pwr = 0; // tx power
char cmdbuff[32] = "";
int temp = 0;
bool repeater = false; // true if transmit and receive operate on different frequencies
char pl_rx_buffer[32]; // pl tone rx buffer
char pl_tx_buffer[32]; // pl tone tx buffer
float ctcssin = 0;
float ctcssout = 0;
int cdcssin = 0;
int cdcssout = 0;
void setup() {
// NOTE: if not using PWM out (MIC pin), it should be held low to avoid tx noise
pinMode(MIC_PIN, OUTPUT);
digitalWrite(MIC_PIN, LOW);
// initialize serial communication
Serial.begin(115200);
while (!Serial) delay(10);
// Setup the BLE LED to be enabled on CONNECT
// Note: This is actually the default behaviour, but provided
// here in case you want to control this LED manually via PIN 19
Bluefruit.autoConnLed(true);
// Config the peripheral connection with maximum bandwidth
// more SRAM required by SoftDevice
// Note: All config***() function must be called before begin()
Bluefruit.configPrphBandwidth(BANDWIDTH_MAX);
Bluefruit.begin();
// Set max power. Accepted values are: -40, -30, -20, -16, -12, -8, -4, 0, 4
Bluefruit.setTxPower(4);
Bluefruit.setName("MyBlueHam");
//Bluefruit.setName(getMcuUniqueID()); // useful testing with multiple central connections
Bluefruit.setConnectCallback(connect_callback);
Bluefruit.setDisconnectCallback(disconnect_callback);
// Configure and Start Device Information Service
bledis.setManufacturer("Enhanced Radio Devices");
bledis.setModel("BlueHam");
bledis.begin();
// Configure and Start BLE Uart Service
bleuart.begin();
// Start BLE Battery Service
blebas.begin();
blebas.write(100);
// Set up and start advertising
startAdv();
delay(100);
SerialWrite(";;;;;;;;;;;;;;;;;;;;;;;;;;\n");
int result = radio.testConnection();
SerialWrite("*%d;\n", result);
radio.initialize(); // initializes automatically for UHF 12.5kHz channel
radio.frequency(freq);
radio.setVolume1(0xF);
radio.setVolume2(0xF);
radio.setModeReceive();
radio.setTxSourceMic();
radio.setRfPower(pwr);
radio.setSQLoThresh(-80);
radio.setSQHiThresh(-70);
radio.setSQOn();
SerialWrite("*START;\n");
}
void startAdv(void)
{
// Advertising packet
Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
Bluefruit.Advertising.addTxPower();
// Include bleuart 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
}
void loop() {
// TODO: loop fixing based on serialtransciever!
char c = 0;
bool ble_serial = false;
if (Serial.available()) {
Serial.readBytes(&c, 1);
} else if (bleuart.available()) {
c = (char) bleuart.read();
ble_serial = true;
}
// TODO: BLE
if(c != 0) {
int text = c; // get the first char to see what the upcoming command is
switch (state) {
// we handle commands differently based on what state we're in
case TX:
// we're currently transmitting
// if we got a space, reset our transmit timeout
if(text == ' ') { timer = millis();}
break;
case NORMAL:
switch(text) {
case ' ': // space - transmit
if(repeater == true && tx_freq != 0) { radio.frequency(tx_freq); }
muted = false; // can't mute (for PL tones) during tx
radio.setUnmute();
radio.setModeTransmit();
state = TX;
SerialWrite("#TX,ON;\n");
timer = millis();
break;
case '?': // ? - RSSI
SerialWrite(":%d;\n", radio.readRSSI());
break;
case '^': // ^ - VSSI (voice) level
SerialWrite(":%d;\n", radio.readVSSI());
break;
case 'F': // F - frequency
getValue(ble_serial);
freq = atol(cmdbuff);
if(radio.frequency(freq) == true) {
SerialWrite("@%d;!;\n", freq);
} else {
SerialWrite("X1;\n");
}
break;
case 'P': // P - power level
getValue(ble_serial);
temp = atol(cmdbuff);
radio.setRfPower(temp);
SerialWrite("!;\n");
break;
case 'S': // S - squelch
getValue(ble_serial);
temp = atol(cmdbuff);
if (temp < -2 && temp > -130) {
radio.setSQLoThresh(temp);
radio.setSQHiThresh(temp+2);
radio.setSQOn();
SerialWrite("%d!;\n", temp);
} else {
SerialWrite("X!;\n");
}
break;
case 'R': // R - repeater offset mode
getValue(ble_serial);
temp = atol(cmdbuff);
if(temp == 0) { repeater = 0; }
if(temp == 1) { repeater = 1; }
SerialWrite("!;\n");
break;
case 'T': // T - transmit offset
getValue(ble_serial);
tx_freq = atol(cmdbuff);
SerialWrite("!;\n");
break;
case 'M': // M - Morse
getValue(ble_serial);
if(repeater == true && tx_freq != 0) { radio.frequency(tx_freq); }
muted = false; // can't mute (for PL tones) during tx
radio.setUnmute();
radio.setModeTransmit();
delay(300);
radio.morseOut(cmdbuff);
if(repeater == true) { radio.frequency(freq); }
radio.setModeReceive();
SerialWrite("!;\n");
break;
case 'N': // N - set to Morse in Mode
morse_rx_setup();
state = MORSE;
SerialWrite("!;\n");
break;
case 'D': // D - DTMF Out
dtmfSetup();
getValue(ble_serial);
dtmf_out(cmdbuff);
SerialWrite("!;\n");
break;
case 'B': // B - set to DTMF in Mode
dtmfSetup();
radio.enableDTMFReceive();
state = DTMF;
SerialWrite("!;\n");
break;
case 'A': // A - TX PL Tone configuration command
pl_tone_tx();
SerialWrite("!;\n");
break;
case 'C': // C - RX PL Tone configuration command
pl_tone_rx();
SerialWrite("!;\n");
break;
case 'V': // V - set volume
getValue(ble_serial);
temp = cmdbuff[0];
if (temp == 0x31) {
temp = atol(cmdbuff + 1);
radio.setVolume1(temp);
SerialWrite("!;\n");
} else if (temp == 0x32) {
temp = atol(cmdbuff + 1);
radio.setVolume2(temp);
SerialWrite("!;\n");
} else {
// not a valid volume command, flush buffers
SerialFlush(ble_serial);
SerialWrite("X!;\n");
}
break;
case 'K': // K - switch to KISS TNC mode
//state = KISS;
//TODO: set up KISS
SerialWrite("X1;\n");
break;
default:
// unknown command, flush the input buffer and wait for next one
SerialWrite("X1;\n");
SerialFlush(ble_serial);
break;
}
break;
case KISS:
if ((ble_serial && bleuart.peek() == '_') || (!ble_serial && Serial.peek() == '_')) {
state = NORMAL;
if (rx_ctcss) {
radio.enableCtcss();
muted = true; // can't mute (for PL tones) during tx
radio.setMute();
}
}
// TODO: handle KISS TNC
break;
case MORSE:
if (text == '_') { state = NORMAL; }
if (text == 'M') { // tx message
getValue(ble_serial);
if(repeater == true && tx_freq != 0) { radio.frequency(tx_freq); }
muted = false; // can't mute (for PL tones) during tx
radio.setUnmute();
radio.setModeTransmit();
delay(300);
radio.morseOut(cmdbuff);
if(repeater == true) { radio.frequency(freq); }
radio.setModeReceive();
} else {
// not a valid cmd
SerialFlush(ble_serial);
}
break;
case DTMF:
if (text == '_') { state = NORMAL; }
if (text == 'D') { // tx message
getValue(ble_serial);
dtmf_out(cmdbuff);
} else {
// not a valid cmd
SerialFlush(ble_serial);
}
break;
default:
// we're in an invalid state, reset to safe settings
SerialFlush(ble_serial);
radio.frequency(freq);
radio.setModeReceive();
state = NORMAL;
break;
}
}
// now handle any state related functions
switch (state) {
case TX:
if(millis() > (timer + 500)) {
SerialWrite("#TX,OFF;\n");
radio.setModeReceive();
if(repeater == true) { radio.frequency(freq); }
if (rx_ctcss) {
radio.setMute();
muted = true;
}
txcount = 0;
state = NORMAL;
}
break;
case NORMAL:
// deal with rx ctccs if necessary
if (rx_ctcss) {
if (radio.getCtcssToneDetected()) {
if (muted) {
muted = false;
radio.setUnmute();
}
} else {
if (!muted) {
muted = true;
radio.setMute();
}
}
}
break;
case DTMF:
dtmf_rx(); // wait for DTMF reception
break;
case MORSE:
morse_rx(); // wait for Morse reception
break;
}
// get rid of any trailing whitespace in the serial buffer
SerialFlushWhitespace(ble_serial);
}
// callback invoked when central connects
void connect_callback(uint16_t conn_handle)
{
char central_name[32] = { 0 };
Bluefruit.Gap.getPeerName(conn_handle, central_name, sizeof(central_name));
Serial.print("Connected to ");
Serial.println(central_name);
}
/**
* Callback invoked when a connection is dropped
* @param conn_handle connection where this event happens
* @param reason is a BLE_HCI_STATUS_CODE which can be found in ble_hci.h
* https://github.com/adafruit/Adafruit_nRF52_Arduino/blob/master/cores/nRF5/nordic/softdevice/s140_nrf52_6.1.1_API/include/ble_hci.h
*/
void disconnect_callback(uint16_t conn_handle, uint8_t reason)
{
(void) conn_handle;
(void) reason;
Serial.println();
Serial.println("Disconnected");
}
void getValue(bool ble_serial) {
int p = 0;
char temp;
for(;;) {
if((!ble_serial && Serial.available()) || (ble_serial && bleuart.available())) {
if (ble_serial) {
temp = bleuart.read();
} else {
temp = Serial.read();
}
if(temp == 59) {
cmdbuff[p] = 0;
return;
}
cmdbuff[p] = temp;
p++;
if(p == 32) {
cmdbuff[0] = 0;
return;
}
}
}
}
void dtmfSetup() {
radio.setVolume1(6);
radio.setVolume2(0);
radio.setDTMFDetectTime(24); // time to detect a DTMF code, units are 2.5ms
radio.setDTMFIdleTime(50); // time between transmitted DTMF codes, units are 2.5ms
radio.setDTMFTxTime(60); // duration of transmitted DTMF codes, units are 2.5ms
}
void dtmf_out(char * out_buf) {
if (out_buf[0] == ';' || out_buf[0] == 0) return; // empty message
uint8_t i = 0;
uint8_t code = radio.DTMFchar2code(out_buf[i]);
// start transmitting
radio.setDTMFCode(code); // set first
radio.setTxSourceTones();
if(repeater == true && tx_freq != 0) { radio.frequency(tx_freq); }
muted = false; // can't mute during transmit
radio.setUnmute();
radio.setModeTransmit();
delay(300); // wait for TX to come to full power
bool dtmf_to_tx = true;
while (dtmf_to_tx) {
// wait until ready
while (radio.getDTMFTxActive() != 1) {
// wait until we're ready for a new code
delay(10);
}
if (i < 32 && out_buf[i] != ';' && out_buf[i] != 0) {
code = radio.DTMFchar2code(out_buf[i]);
if (code == 255) code = 0xE; // throw a * in there so we don't break things with an invalid code
radio.setDTMFCode(code); // set first
} else {
dtmf_to_tx = false;
break;
}
i++;
while (radio.getDTMFTxActive() != 0) {
// wait until this code is done
delay(10);
}
}
// done with tone
radio.setModeReceive();
if (repeater == true) {radio.frequency(freq);}
radio.setTxSourceMic();
}
void dtmf_rx() {
char m = radio.DTMFRxLoop();
if (m != 0) {
// Note: not doing buffering of messages,
// we just send a single morse character
// whenever we get it
SerialWrite("R%d;\n", m);
}
}
// TODO: morse config info
void morse_rx_setup() {
// Set the morse code characteristics
radio.setMorseFreq(MORSE_FREQ);
radio.setMorseDotMillis(MORSE_DOT);
radio.lookForTone(MORSE_FREQ);
radio.setupMorseRx();
}
void morse_rx() {
char m = radio.morseRxLoop();
if (m != 0) {
// Note: not doing buffering of messages,
// we just send a single morse character
// whenever we get it
SerialWrite("R%c;\n",m);
}
}
void pl_tone_tx() {
memset(pl_tx_buffer,0,32);
uint8_t ptr = 0;
while(1) {
if(Serial.available()) {
uint8_t buf = Serial.read();
if(buf == 'X') { return; }
if(buf == ';') { pl_tx_buffer[ptr] = 0; program_pl_tx(); return; }
if(ptr == 31) { return; }
pl_tx_buffer[ptr] = buf; ptr++;
}
}
}
void program_pl_tx() {
float pl_tx = atof(pl_tx_buffer);
radio.setCtcss(pl_tx);
if (pl_tx == 0) {
radio.disableCtcssTx();
} else {
radio.enableCtcssTx();
}
}
void pl_tone_rx() {
memset(pl_rx_buffer,0,32);
uint8_t ptr = 0;
while(1) {
if(Serial.available()) {
uint8_t buf = Serial.read();
if(buf == 'X') { return; }
if(buf == ';') { pl_rx_buffer[ptr] = 0; program_pl_rx(); return; }
if(ptr == 31) { return; }
pl_rx_buffer[ptr] = buf; ptr++;
}
}
}
void program_pl_rx() {
float pl_rx = atof(pl_rx_buffer);
radio.setCtcss(pl_rx);
if (pl_rx == 0) {
rx_ctcss = false;
radio.setUnmute();
muted = false;
radio.disableCtcssRx();
} else {
rx_ctcss = true;
radio.setMute();
muted = true;
radio.enableCtcssRx();
}
}
#define TEXT_BUF_LEN 64
char text_buf[TEXT_BUF_LEN];
void SerialWrite(const char *fmt, ...) {
va_list args;
va_start(args, fmt);
int str_len = vsnprintf(text_buf, TEXT_BUF_LEN, fmt, args);
va_end(args);
bleuart.write(text_buf, str_len);
Serial.write(text_buf, str_len);
}
void SerialFlush(bool ble_serial) {
if (ble_serial) {
while (bleuart.available()) { bleuart.read(); }
} else {
while (Serial.available()) { Serial.read(); }
}
}
void SerialFlushWhitespace(bool ble_serial) {
if (!ble_serial && Serial.available()) {
char cpeek = Serial.peek();
while (cpeek == ' ' || cpeek == '\r' || cpeek == '\n')
{
Serial.read();
cpeek = Serial.peek();
}
} else if (ble_serial && bleuart.available()) {
char cpeek = bleuart.peek();
while (cpeek == ' ' || cpeek == '\r' || cpeek == '\n')
{
bleuart.read();
cpeek = bleuart.peek();
}
}
}

View File

@ -1,20 +1,35 @@
/*
Plays back the current signal strength level and morses out it's call sign at the end.
/* Hamshield
* Example: Signal Test
* Transmits current signal strength level and Morses out
* it's call sign at the end. You will need a HandyTalkie (HT)
* to test the output of this example. You will also need to
* download the PCM library from
* https://github.com/damellis/PCM
* Connect the HamShield to your Arduino. Screw the antenna
* into the HamShield RF jack. Plug a pair of headphones into
* the HamShield. Connect the Arduino to wall power and then
* to your computer via USB. After uploading this program to
* your Arduino, open the Serial Monitor. HamShield will print
* the results of its signal test to the Serial Monitor. To
* test with another HandyTalkie (HT), tune in to 446MHz and
* listen for the call sign. Then key up on your HT and make
* sure you can hear it through the headphones attached to the
* HamShield.
*/
#define DOT 100
#define CALLSIGN "1ZZ9ZZ/B"
char CALLSIGN[] = "1ZZ9ZZ/B";
/* Standard libraries and variable init */
#include <HAMShield.h>
#include <Wire.h>
#include <HamShield.h>
#include <PCM.h>
HAMShield radio;
#define MIC_PIN 3
#define RESET_PIN A3
#define SWITCH_PIN 2
HamShield radio;
int16_t rssi;
int peak = -150;
char sig[8];
@ -74,13 +89,25 @@ const unsigned char dbm[] PROGMEM = {
/* get our radio ready */
void setup() {
Wire.begin();
// NOTE: if not using PWM out, it should be held low to avoid tx noise
pinMode(MIC_PIN, OUTPUT);
digitalWrite(MIC_PIN, LOW);
// prep the switch
pinMode(SWITCH_PIN, INPUT_PULLUP);
// set up the reset control pin
// NOTE: HamShieldMini doesn't have a reset pin, so this has no effect
pinMode(RESET_PIN, OUTPUT);
digitalWrite(RESET_PIN, HIGH);
delay(5); // wait for device to come up
Serial.begin(9600);
Serial.print("Radio status: ");
int result = radio.testConnection();
Serial.println(result);
radio.initialize();
radio.setFrequency(446000);
radio.frequency(432400);
radio.setVolume1(0xF);
radio.setVolume2(0xF);
radio.setModeReceive();
@ -104,7 +131,7 @@ void loop() {
if(rssi < -120) {
Serial.println("Transmit On");
radio.setTX(1);
radio.setModeTransmit();
delay(250);
tone(11,1000,500);
delay(1000);
@ -131,9 +158,8 @@ void loop() {
delay(1000);
Serial.println("done!");
radio.morseOut(CALLSIGN);
radio.setTX(0);
Serial.println("Transmit off");
radio.setModeReceive();
Serial.println("Transmit off");
delay(1000);
}
}

Binary file not shown.

View File

@ -0,0 +1,284 @@
/* Hamshield (See https://github.com/EnhancedRadioDevices/HamShield)
* Example: SpeechTX - This example used the basic JustTransmit example from the above site
* This example uses the Talkie Arduino speech library. It transmits pre-encoded speech over the air.
* More info at: https://github.com/going-digital/Talkie
*
* Make sure you're using an Arduino Uno or equivalent. The Talkie library doesn't work
* with hardware that doesn't use the ATMega328 or ATMega168.
*
* Connect the HamShield to your Arduino. Screw the antenna
* into the HamShield RF jack. Connect the Arduino to
* wall power and then to your computer via USB. After
* uploading this program to your Arduino
* tune a HandyTalkie (HT) to 144.025MHz. Listen on
* the HT for the HamShield broadcasting with its own speech.
*/
#include <HamShield.h>
#define MIC_PIN 3
#define RESET_PIN A3
#define SWITCH_PIN 2
HamShield radio;
#include "talkie.h"
Talkie voice;
const uint8_t spZERO[] PROGMEM = {0x69,0xFB,0x59,0xDD,0x51,0xD5,0xD7,0xB5,0x6F,0x0A,0x78,0xC0,0x52,0x01,0x0F,0x50,0xAC,0xF6,0xA8,0x16,0x15,0xF2,0x7B,0xEA,0x19,0x47,0xD0,0x64,0xEB,0xAD,0x76,0xB5,0xEB,0xD1,0x96,0x24,0x6E,0x62,0x6D,0x5B,0x1F,0x0A,0xA7,0xB9,0xC5,0xAB,0xFD,0x1A,0x62,0xF0,0xF0,0xE2,0x6C,0x73,0x1C,0x73,0x52,0x1D,0x19,0x94,0x6F,0xCE,0x7D,0xED,0x6B,0xD9,0x82,0xDC,0x48,0xC7,0x2E,0x71,0x8B,0xBB,0xDF,0xFF,0x1F};
const uint8_t spFOUR[] PROGMEM = {0x08,0x68,0x21,0x0D,0x03,0x04,0x28,0xCE,0x92,0x03,0x23,0x4A,0xCA,0xA6,0x1C,0xDA,0xAD,0xB4,0x70,0xED,0x19,0x64,0xB7,0xD3,0x91,0x45,0x51,0x35,0x89,0xEA,0x66,0xDE,0xEA,0xE0,0xAB,0xD3,0x29,0x4F,0x1F,0xFA,0x52,0xF6,0x90,0x52,0x3B,0x25,0x7F,0xDD,0xCB,0x9D,0x72,0x72,0x8C,0x79,0xCB,0x6F,0xFA,0xD2,0x10,0x9E,0xB4,0x2C,0xE1,0x4F,0x25,0x70,0x3A,0xDC,0xBA,0x2F,0x6F,0xC1,0x75,0xCB,0xF2,0xFF};
const uint8_t spEIGHT[] PROGMEM = {0x65,0x69,0x89,0xC5,0x73,0x66,0xDF,0xE9,0x8C,0x33,0x0E,0x41,0xC6,0xEA,0x5B,0xEF,0x7A,0xF5,0x33,0x25,0x50,0xE5,0xEA,0x39,0xD7,0xC5,0x6E,0x08,0x14,0xC1,0xDD,0x45,0x64,0x03,0x00,0x80,0x00,0xAE,0x70,0x33,0xC0,0x73,0x33,0x1A,0x10,0x40,0x8F,0x2B,0x14,0xF8,0x7F};
const uint8_t spTWELVE[] PROGMEM = {0x09,0x98,0xDA,0x22,0x01,0x37,0x78,0x1A,0x20,0x85,0xD1,0x50,0x3A,0x33,0x11,0x81,0x5D,0x5B,0x95,0xD4,0x44,0x04,0x76,0x9D,0xD5,0xA9,0x3A,0xAB,0xF0,0xA1,0x3E,0xB7,0xBA,0xD5,0xA9,0x2B,0xEB,0xCC,0xA0,0x3E,0xB7,0xBD,0xC3,0x5A,0x3B,0xC8,0x69,0x67,0xBD,0xFB,0xE8,0x67,0xBF,0xCA,0x9D,0xE9,0x74,0x08,0xE7,0xCE,0x77,0x78,0x06,0x89,0x32,0x57,0xD6,0xF1,0xF1,0x8F,0x7D,0xFE,0x1F};
const uint8_t spTWENTY[] PROGMEM = {0x0A,0xE8,0x4A,0xCD,0x01,0xDB,0xB9,0x33,0xC0,0xA6,0x54,0x0C,0xA4,0x34,0xD9,0xF2,0x0A,0x6C,0xBB,0xB3,0x53,0x0E,0x5D,0xA6,0x25,0x9B,0x6F,0x75,0xCA,0x61,0x52,0xDC,0x74,0x49,0xA9,0x8A,0xC4,0x76,0x4D,0xD7,0xB1,0x76,0xC0,0x55,0xA6,0x65,0xD8,0x26,0x99,0x5C,0x56,0xAD,0xB9,0x25,0x23,0xD5,0x7C,0x32,0x96,0xE9,0x9B,0x20,0x7D,0xCB,0x3C,0xFA,0x55,0xAE,0x99,0x1A,0x30,0xFC,0x4B,0x3C,0xFF,0x1F};
const uint8_t spONE[] PROGMEM = {0x66,0x4E,0xA8,0x7A,0x8D,0xED,0xC4,0xB5,0xCD,0x89,0xD4,0xBC,0xA2,0xDB,0xD1,0x27,0xBE,0x33,0x4C,0xD9,0x4F,0x9B,0x4D,0x57,0x8A,0x76,0xBE,0xF5,0xA9,0xAA,0x2E,0x4F,0xD5,0xCD,0xB7,0xD9,0x43,0x5B,0x87,0x13,0x4C,0x0D,0xA7,0x75,0xAB,0x7B,0x3E,0xE3,0x19,0x6F,0x7F,0xA7,0xA7,0xF9,0xD0,0x30,0x5B,0x1D,0x9E,0x9A,0x34,0x44,0xBC,0xB6,0x7D,0xFE,0x1F};
const uint8_t spFIVE[] PROGMEM = {0x08,0x68,0x4E,0x9D,0x02,0x1C,0x60,0xC0,0x8C,0x69,0x12,0xB0,0xC0,0x28,0xAB,0x8C,0x9C,0xC0,0x2D,0xBB,0x38,0x79,0x31,0x15,0xA3,0xB6,0xE4,0x16,0xB7,0xDC,0xF5,0x6E,0x57,0xDF,0x54,0x5B,0x85,0xBE,0xD9,0xE3,0x5C,0xC6,0xD6,0x6D,0xB1,0xA5,0xBF,0x99,0x5B,0x3B,0x5A,0x30,0x09,0xAF,0x2F,0xED,0xEC,0x31,0xC4,0x5C,0xBE,0xD6,0x33,0xDD,0xAD,0x88,0x87,0xE2,0xD2,0xF2,0xF4,0xE0,0x16,0x2A,0xB2,0xE3,0x63,0x1F,0xF9,0xF0,0xE7,0xFF,0x01};
const uint8_t spNINE[] PROGMEM = {0xE6,0xA8,0x1A,0x35,0x5D,0xD6,0x9A,0x35,0x4B,0x8C,0x4E,0x6B,0x1A,0xD6,0xA6,0x51,0xB2,0xB5,0xEE,0x58,0x9A,0x13,0x4F,0xB5,0x35,0x67,0x68,0x26,0x3D,0x4D,0x97,0x9C,0xBE,0xC9,0x75,0x2F,0x6D,0x7B,0xBB,0x5B,0xDF,0xFA,0x36,0xA7,0xEF,0xBA,0x25,0xDA,0x16,0xDF,0x69,0xAC,0x23,0x05,0x45,0xF9,0xAC,0xB9,0x8F,0xA3,0x97,0x20,0x73,0x9F,0x54,0xCE,0x1E,0x45,0xC2,0xA2,0x4E,0x3E,0xD3,0xD5,0x3D,0xB1,0x79,0x24,0x0D,0xD7,0x48,0x4C,0x6E,0xE1,0x2C,0xDE,0xFF,0x0F};
const uint8_t spTHIR_[] PROGMEM = {0x04,0xA8,0xBE,0x5C,0x00,0xDD,0xA5,0x11,0xA0,0xFA,0x72,0x02,0x74,0x97,0xC6,0x01,0x09,0x9C,0xA6,0xAB,0x30,0x0D,0xCE,0x7A,0xEA,0x6A,0x4A,0x39,0x35,0xFB,0xAA,0x8B,0x1B,0xC6,0x76,0xF7,0xAB,0x2E,0x79,0x19,0xCA,0xD5,0xEF,0xCA,0x57,0x08,0x14,0xA1,0xDC,0x45,0x64,0x03,0x00,0xC0,0xFF,0x03};
const uint8_t spHUNDRED[] PROGMEM = {0x04,0xC8,0x7E,0x5C,0x02,0x0A,0xA8,0x62,0x43,0x03,0xA7,0xA8,0x62,0x43,0x4B,0x97,0xDC,0xF2,0x14,0xC5,0xA7,0x9B,0x7A,0xD3,0x95,0x37,0xC3,0x1E,0x16,0x4A,0x66,0x36,0xF3,0x5A,0x89,0x6E,0xD4,0x30,0x55,0xB5,0x32,0xB7,0x31,0xB5,0xC1,0x69,0x2C,0xE9,0xF7,0xBC,0x96,0x12,0x39,0xD4,0xB5,0xFD,0xDA,0x9B,0x0F,0xD1,0x90,0xEE,0xF5,0xE4,0x17,0x02,0x45,0x28,0x77,0x11,0xD9,0x40,0x9E,0x45,0xDD,0x2B,0x33,0x71,0x7A,0xBA,0x0B,0x13,0x95,0x2D,0xF9,0xF9,0x7F};
const uint8_t spTWO[] PROGMEM = {0x06,0xB8,0x59,0x34,0x00,0x27,0xD6,0x38,0x60,0x58,0xD3,0x91,0x55,0x2D,0xAA,0x65,0x9D,0x4F,0xD1,0xB8,0x39,0x17,0x67,0xBF,0xC5,0xAE,0x5A,0x1D,0xB5,0x7A,0x06,0xF6,0xA9,0x7D,0x9D,0xD2,0x6C,0x55,0xA5,0x26,0x75,0xC9,0x9B,0xDF,0xFC,0x6E,0x0E,0x63,0x3A,0x34,0x70,0xAF,0x3E,0xFF,0x1F};
const uint8_t spSIX[] PROGMEM = {0x04,0xF8,0xAD,0x4C,0x02,0x16,0xB0,0x80,0x06,0x56,0x35,0x5D,0xA8,0x2A,0x6D,0xB9,0xCD,0x69,0xBB,0x2B,0x55,0xB5,0x2D,0xB7,0xDB,0xFD,0x9C,0x0D,0xD8,0x32,0x8A,0x7B,0xBC,0x02,0x00,0x03,0x0C,0xB1,0x2E,0x80,0xDF,0xD2,0x35,0x20,0x01,0x0E,0x60,0xE0,0xFF,0x01};
const uint8_t spTEN[] PROGMEM = {0x0E,0x38,0x3C,0x2D,0x00,0x5F,0xB6,0x19,0x60,0xA8,0x90,0x93,0x36,0x2B,0xE2,0x99,0xB3,0x4E,0xD9,0x7D,0x89,0x85,0x2F,0xBE,0xD5,0xAD,0x4F,0x3F,0x64,0xAB,0xA4,0x3E,0xBA,0xD3,0x59,0x9A,0x2E,0x75,0xD5,0x39,0x6D,0x6B,0x0A,0x2D,0x3C,0xEC,0xE5,0xDD,0x1F,0xFE,0xB0,0xE7,0xFF,0x03};
const uint8_t spFIF_[] PROGMEM = {0x08,0x98,0x31,0x93,0x02,0x1C,0xE0,0x80,0x07,0x5A,0xD6,0x1C,0x6B,0x78,0x2E,0xBD,0xE5,0x2D,0x4F,0xDD,0xAD,0xAB,0xAA,0x6D,0xC9,0x23,0x02,0x56,0x4C,0x93,0x00,0x05,0x10,0x90,0x89,0x31,0xFC,0x3F};
const uint8_t spTHOUSAND[] PROGMEM = {0x0C,0xE8,0x2E,0xD4,0x02,0x06,0x98,0xD2,0x55,0x03,0x16,0x68,0x7D,0x17,0xE9,0x6E,0xBC,0x65,0x8C,0x45,0x6D,0xA6,0xE9,0x96,0xDD,0xDE,0xF6,0xB6,0xB7,0x5E,0x75,0xD4,0x93,0xA5,0x9C,0x7B,0x57,0xB3,0x6E,0x7D,0x12,0x19,0xAD,0xDC,0x29,0x8D,0x4F,0x93,0xB4,0x87,0xD2,0xB6,0xFC,0xDD,0xAC,0x22,0x56,0x02,0x70,0x18,0xCA,0x18,0x26,0xB5,0x90,0xD4,0xDE,0x6B,0x29,0xDA,0x2D,0x25,0x17,0x8D,0x79,0x88,0xD4,0x48,0x79,0x5D,0xF7,0x74,0x75,0xA1,0x94,0xA9,0xD1,0xF2,0xED,0x9E,0xAA,0x51,0xA6,0xD4,0x9E,0x7F,0xED,0x6F,0xFE,0x2B,0xD1,0xC7,0x3D,0x89,0xFA,0xB7,0x0D,0x57,0xD3,0xB4,0xF5,0x37,0x55,0x37,0x2E,0xE6,0xB2,0xD7,0x57,0xFF,0x0F};
const uint8_t spTHREE[] PROGMEM = {0x0C,0xE8,0x2E,0x94,0x01,0x4D,0xBA,0x4A,0x40,0x03,0x16,0x68,0x69,0x36,0x1C,0xE9,0xBA,0xB8,0xE5,0x39,0x70,0x72,0x84,0xDB,0x51,0xA4,0xA8,0x4E,0xA3,0xC9,0x77,0xB1,0xCA,0xD6,0x52,0xA8,0x71,0xED,0x2A,0x7B,0x4B,0xA6,0xE0,0x37,0xB7,0x5A,0xDD,0x48,0x8E,0x94,0xF1,0x64,0xCE,0x6D,0x19,0x55,0x91,0xBC,0x6E,0xD7,0xAD,0x1E,0xF5,0xAA,0x77,0x7A,0xC6,0x70,0x22,0xCD,0xC7,0xF9,0x89,0xCF,0xFF,0x03};
const uint8_t spSEVEN[] PROGMEM = {0x0C,0xF8,0x5E,0x4C,0x01,0xBF,0x95,0x7B,0xC0,0x02,0x16,0xB0,0xC0,0xC8,0xBA,0x36,0x4D,0xB7,0x27,0x37,0xBB,0xC5,0x29,0xBA,0x71,0x6D,0xB7,0xB5,0xAB,0xA8,0xCE,0xBD,0xD4,0xDE,0xA6,0xB2,0x5A,0xB1,0x34,0x6A,0x1D,0xA7,0x35,0x37,0xE5,0x5A,0xAE,0x6B,0xEE,0xD2,0xB6,0x26,0x4C,0x37,0xF5,0x4D,0xB9,0x9A,0x34,0x39,0xB7,0xC6,0xE1,0x1E,0x81,0xD8,0xA2,0xEC,0xE6,0xC7,0x7F,0xFE,0xFB,0x7F};
const uint8_t spELEVEN[] PROGMEM = {0xA5,0xEF,0xD6,0x50,0x3B,0x67,0x8F,0xB9,0x3B,0x23,0x49,0x7F,0x33,0x87,0x31,0x0C,0xE9,0x22,0x49,0x7D,0x56,0xDF,0x69,0xAA,0x39,0x6D,0x59,0xDD,0x82,0x56,0x92,0xDA,0xE5,0x74,0x9D,0xA7,0xA6,0xD3,0x9A,0x53,0x37,0x99,0x56,0xA6,0x6F,0x4F,0x59,0x9D,0x7B,0x89,0x2F,0xDD,0xC5,0x28,0xAA,0x15,0x4B,0xA3,0xD6,0xAE,0x8C,0x8A,0xAD,0x54,0x3B,0xA7,0xA9,0x3B,0xB3,0x54,0x5D,0x33,0xE6,0xA6,0x5C,0xCB,0x75,0xCD,0x5E,0xC6,0xDA,0xA4,0xCA,0xB9,0x35,0xAE,0x67,0xB8,0x46,0x40,0xB6,0x28,0xBB,0xF1,0xF6,0xB7,0xB9,0x47,0x20,0xB6,0x28,0xBB,0xFF,0x0F};
const uint8_t sp_TEEN[] PROGMEM = {0x09,0x58,0x2A,0x25,0x00,0xCB,0x9F,0x95,0x6C,0x14,0x21,0x89,0xA9,0x78,0xB3,0x5B,0xEC,0xBA,0xB5,0x23,0x13,0x46,0x97,0x99,0x3E,0xD6,0xB9,0x2E,0x79,0xC9,0x5B,0xD8,0x47,0x41,0x53,0x1F,0xC7,0xE1,0x9C,0x85,0x54,0x22,0xEC,0xFA,0xDB,0xDD,0x23,0x93,0x49,0xB8,0xE6,0x78,0xFF,0x3F};
const uint8_t spA[] PROGMEM = {0x65,0x2C,0x96,0xAD,0x7B,0x6A,0x9F,0x66,0xE4,0x20,0x8D,0x9C,0x73,0xAB,0x5B,0xDC,0xE2,0x96,0xB7,0xBA,0xF5,0x6A,0x66,0x28,0xA0,0xCE,0xD5,0xBB,0xDB,0xFD,0x1E,0xE6,0x38,0xA7,0x36,0xCF,0x9C,0x80,0x51,0x8B,0xEB,0x52,0xD7,0xBC,0xFF,0x3F};
const uint8_t spB[] PROGMEM = {0xA6,0x2F,0xAA,0x05,0x5C,0xD6,0x8C,0xBC,0xC7,0x16,0x70,0x59,0x33,0xB2,0x95,0x0B,0xC1,0xFD,0xCD,0xCC,0x66,0x3A,0xF3,0x51,0xAD,0x98,0x00,0x55,0x8B,0x67,0xDB,0xC7,0x3E,0xD5,0xAD,0xEE,0x75,0x2F,0xE7,0x2C,0x4D,0x60,0xBE,0x26,0xDF,0xF1,0x89,0xEF,0xFF,0x03};
const uint8_t spC[] PROGMEM = {0x04,0xF8,0xA5,0x83,0x03,0x12,0xB0,0x80,0x07,0x22,0xB0,0xC2,0xEE,0x8D,0x45,0x7D,0xC9,0xCA,0x67,0x29,0x42,0xF5,0x35,0x3B,0xDF,0xF9,0x28,0x66,0x0D,0x40,0xCF,0xD7,0xB3,0x1C,0xCD,0xAC,0x06,0x14,0xB5,0x68,0x0E,0x7D,0xEE,0x4B,0xDF,0xD2,0x39,0x5B,0x02,0x44,0xBD,0xCE,0x57,0xBE,0xF2,0x9D,0xEE,0x55,0x0A,0xC1,0x73,0x4D,0x7E,0xF2,0xF3,0xFF};
const uint8_t spD[] PROGMEM = {0x06,0x98,0x30,0x68,0xE4,0x6B,0x84,0xA0,0xE8,0xD3,0x93,0x8D,0xEC,0x84,0x9E,0x4B,0x6E,0x36,0x8A,0x19,0x0D,0xA8,0xEA,0x71,0xAF,0x7A,0xDF,0xE7,0xB2,0xAD,0xE0,0x00,0xD3,0x8B,0xEB,0x9E,0x8F,0x7C,0xA6,0x73,0xE5,0x40,0xA8,0x5A,0x1C,0xAF,0x78,0xC5,0xDB,0xDF,0xFF,0x0F};
const uint8_t spE[] PROGMEM = {0xA2,0x59,0x95,0x51,0xBA,0x17,0xF7,0x6A,0x95,0xAB,0x38,0x42,0xE4,0x92,0x5D,0xEE,0x62,0x15,0x33,0x3B,0x50,0xD6,0x92,0x5D,0xAE,0x6A,0xC5,0x04,0xA8,0x5A,0xBC,0xEB,0xDD,0xEC,0x76,0x77,0xBB,0xDF,0xD3,0x9E,0xF6,0x32,0x97,0xBE,0xF5,0xAD,0xED,0xB3,0x34,0x81,0xF9,0x9A,0xFF,0x07};
const uint8_t spF[] PROGMEM = {0xAB,0x1B,0x61,0x94,0xDD,0xD6,0xDC,0xF1,0x74,0xDD,0x37,0xB9,0xE7,0xEA,0xD3,0x35,0xB3,0x1C,0xE1,0xAF,0x6F,0x77,0xC7,0xB5,0xD4,0xE0,0x56,0x9C,0x77,0xDB,0x5A,0x9D,0xEB,0x98,0x8C,0x61,0xC0,0x30,0xE9,0x1A,0xB0,0x80,0x05,0x14,0x30,0x6D,0xBB,0x06,0x24,0x20,0x01,0x0E,0x10,0xA0,0x06,0xB5,0xFF,0x07};
const uint8_t spG[] PROGMEM = {0x6E,0x3F,0x29,0x8D,0x98,0x95,0xCD,0x3D,0x00,0xAB,0x38,0x95,0xE2,0xD4,0xEB,0x34,0x81,0x7A,0xF2,0x51,0x53,0x50,0x75,0xEB,0xCE,0x76,0xB6,0xD3,0x95,0x8D,0x92,0x48,0x99,0xAB,0x77,0xBE,0xCB,0xDD,0x8E,0x71,0x96,0x04,0x8C,0x5A,0x3C,0xE7,0x39,0xF7,0xAD,0x6E,0xF5,0x2A,0xD7,0x2A,0x85,0xE0,0xB9,0x26,0x3E,0xF1,0xF9,0x7F};
const uint8_t spH[] PROGMEM = {0x65,0x18,0x6D,0x90,0x2D,0xD6,0xEC,0xF6,0x56,0xB7,0xBC,0xC5,0xAE,0xC7,0x30,0xA3,0x01,0x6D,0x2D,0xCE,0x8B,0x3D,0xDC,0xD6,0x3C,0x61,0x76,0xC5,0x25,0x9B,0x08,0xE5,0x2E,0x22,0x1B,0x00,0x80,0x01,0x2B,0x87,0x38,0x60,0xE5,0xED,0x08,0x58,0xC0,0x02,0x16,0xB0,0x80,0x06,0x34,0x40,0x80,0x76,0xD3,0xFE,0x1F};
const uint8_t spI[] PROGMEM = {0xAA,0x8D,0x63,0xA8,0xAA,0x66,0xAD,0xB9,0xA8,0xCB,0x08,0xDD,0x7C,0xFB,0x5B,0xDF,0xFA,0x36,0xB7,0x39,0x6D,0xB5,0xA3,0x15,0xBA,0xF8,0x76,0xBB,0xDF,0xD3,0x9E,0xD7,0xDA,0x5C,0x49,0xA5,0x2D,0xDE,0x7B,0xDB,0x6B,0x76,0x29,0xAF,0xC7,0x6D,0xEF,0x31,0xD8,0x5C,0x1E,0xF7,0xBD,0x1E,0xF5,0x48,0xE7,0x28,0x89,0xE2,0xF2,0x38,0x5F,0xF9,0xFE,0x7F};
const uint8_t spL[] PROGMEM = {0x6B,0x68,0x2E,0xD8,0x2A,0x37,0xDF,0xFE,0xF6,0xA7,0xAF,0x21,0xBC,0xC4,0x17,0xDF,0xFE,0xF6,0x67,0xC8,0x6A,0xC3,0x4D,0x3A,0xDF,0x61,0x4D,0x95,0x6C,0xA6,0x71,0x9E,0xB1,0x36,0x98,0x53,0x49,0x5E,0xFB,0x5A,0x8E,0x0A,0x7A,0x43,0xD9,0x4F,0x3C,0xC2,0x59,0xE0,0xF4,0x08,0xF9,0x09,0x67,0x03,0x31,0x19,0xA2,0x25,0x9E,0xFF,0x0F};
const uint8_t spJ[] PROGMEM = {0x6E,0x5A,0xC1,0x99,0x54,0xB2,0x09,0x60,0x49,0x22,0x07,0xEC,0xA8,0x16,0x80,0x5D,0x26,0xC7,0xD0,0xA3,0x92,0x78,0x74,0x3E,0x55,0x2F,0x21,0x6A,0xB1,0xFA,0x56,0xB7,0xBA,0xD5,0xAD,0x6F,0x7D,0xBB,0x3D,0x8E,0x75,0xB4,0x22,0x36,0x7F,0x53,0xCF,0x7E,0xB5,0x67,0x96,0x61,0x34,0xDB,0x52,0x9F,0xF4,0x8E,0xDC,0x88,0xE1,0x5F,0xF2,0x9D,0xEF,0xFF,0x07};
const uint8_t spK[] PROGMEM = {0x01,0x18,0x91,0xB9,0x00,0x4D,0x91,0x46,0x60,0x65,0x2D,0xB3,0xB8,0x67,0xED,0x53,0xF4,0x14,0x64,0x11,0x4B,0x6E,0x79,0x8B,0x5B,0xDE,0xF2,0x74,0xC3,0x05,0x6A,0xE7,0xEA,0x3D,0xEC,0x71,0x2F,0x6D,0x1F,0xB1,0x00,0x2B,0xDF,0xF4,0xA3,0x1D,0xB3,0x24,0x60,0xD4,0xE2,0x7A,0xE5,0x2B,0xDF,0xE9,0x1E,0x43,0x48,0xA3,0xEB,0xE4,0xFB,0xFF,0x01};
const uint8_t spM[] PROGMEM = {0xA9,0xE8,0xC5,0xD8,0x73,0x16,0xCF,0xE2,0x0E,0xB7,0xBB,0xCD,0xA9,0xBB,0x6F,0xF1,0xF0,0xD5,0xB7,0xBE,0xCD,0xEE,0xC6,0x50,0x63,0x72,0x98,0x58,0xEE,0x73,0x5F,0xDB,0xD6,0x62,0x72,0x98,0x58,0xAE,0x7B,0xDD,0xD3,0x5E,0x45,0x72,0x93,0xD8,0x8D,0x87,0x3D,0xEC,0x61,0xCF,0x70,0x96,0x58,0xE1,0xA2,0x4D,0xE2,0x15,0xEF,0xFF,0x07};
const uint8_t spN[] PROGMEM = {0x41,0xEE,0xD1,0xC8,0xB3,0x16,0xEF,0xEE,0xD4,0xC3,0x35,0x59,0xC4,0xE3,0x5B,0xDD,0xEA,0x56,0xBB,0x59,0xED,0x92,0xCD,0x91,0xB4,0x78,0x4F,0x63,0x19,0x9E,0x38,0x2C,0x9C,0xCE,0xA5,0xAF,0xF5,0x08,0xC7,0xB0,0xC2,0x61,0x1E,0x35,0x1E,0xF1,0x8C,0x57,0xBC,0xD3,0xDD,0x4D,0x49,0xB8,0xCE,0x0E,0xF7,0x34,0xAD,0x16,0xBC,0xF9,0xFF,0x01};
const uint8_t spO[] PROGMEM = {0xA3,0x6D,0xB4,0xBA,0x8D,0xBC,0xAD,0xA6,0x92,0xEC,0x0E,0xF2,0xB6,0xAB,0x5D,0x8C,0xA2,0xE0,0xEE,0x16,0xF6,0x3F,0xCB,0x39,0xCC,0xB1,0xAC,0x91,0xE5,0x0C,0x8B,0xBF,0xB0,0x3B,0xD3,0x1D,0x28,0x59,0xE2,0xE9,0x4F,0x7B,0xF9,0xE7,0xFF,0x01};
const uint8_t spP[] PROGMEM = {0x02,0x88,0x26,0xD4,0x00,0x6D,0x96,0xB5,0xB8,0x25,0x05,0x89,0x6C,0x3D,0xD2,0xE6,0x51,0xB3,0xA6,0xF4,0x48,0x67,0x09,0xA0,0x8C,0xC7,0x33,0x9B,0x79,0xCB,0x67,0x0E,0x80,0xCA,0xD7,0xBD,0x6A,0xD5,0x72,0x06,0xB4,0xB5,0xBA,0xB7,0xBD,0xAF,0x73,0x5D,0xF3,0x91,0x8F,0x78,0xFE,0x3F};
const uint8_t spQ[] PROGMEM = {0x0E,0x98,0xD5,0x28,0x02,0x11,0x18,0xE9,0xCC,0x46,0x98,0xF1,0x66,0xA7,0x27,0x1D,0x21,0x99,0x92,0xB6,0xDC,0x7C,0x17,0xAB,0x2C,0xD2,0x2D,0x13,0x3B,0xEF,0xAA,0x75,0xCE,0x94,0x47,0xD0,0xEE,0x3A,0xC4,0x29,0x2F,0x61,0x35,0x31,0xA2,0x50,0xB6,0xF8,0xCD,0x1F,0xFF,0x0F};
const uint8_t spR[] PROGMEM = {0xAB,0xC8,0x72,0x33,0x93,0xBB,0xDC,0xEE,0xB6,0xB7,0xB9,0xF5,0x68,0x53,0x5C,0xA9,0xA6,0x4D,0xB3,0x6B,0x73,0x0A,0xCB,0x71,0xD8,0xBB,0xAF,0x7D,0x2F,0x47,0xB6,0xC7,0xF4,0x94,0x37,0x9D,0xA9,0x34,0xF8,0x53,0x97,0x78,0xFD,0x3F};
const uint8_t spS[] PROGMEM = {0x6B,0x6E,0xD9,0x34,0x6C,0xE6,0xDC,0xF6,0x36,0xB7,0xBE,0xF5,0x19,0xAA,0x0F,0x2D,0xDA,0x25,0x7B,0x19,0x5B,0x4D,0x9A,0xA2,0xE7,0xB8,0x1D,0x23,0xA5,0x26,0x71,0x2A,0x03,0xFC,0x94,0xE6,0x01,0x0F,0x68,0x40,0x03,0x12,0xE0,0x00,0x07,0x30,0xF0,0xFF};
const uint8_t spT[] PROGMEM = {0x01,0xD8,0xB6,0xDD,0x01,0x2F,0xF4,0x38,0x60,0xD5,0xD1,0x91,0x4D,0x97,0x84,0xE6,0x4B,0x4E,0x36,0xB2,0x10,0x67,0xCD,0x19,0xD9,0x2C,0x01,0x94,0xF1,0x78,0x66,0x33,0xEB,0x79,0xAF,0x7B,0x57,0x87,0x36,0xAF,0x52,0x08,0x9E,0x6B,0xEA,0x5A,0xB7,0x7A,0x94,0x73,0x45,0x47,0xAC,0x5A,0x9C,0xAF,0xFF,0x07};
const uint8_t spU[] PROGMEM = {0xA1,0x9F,0x9C,0x94,0x72,0x26,0x8D,0x76,0x07,0x55,0x90,0x78,0x3C,0xEB,0x59,0x9D,0xA2,0x87,0x60,0x76,0xDA,0x72,0x8B,0x53,0x36,0xA5,0x64,0x2D,0x7B,0x6E,0xB5,0xFA,0x24,0xDC,0x32,0xB1,0x73,0x1F,0xFA,0x1C,0x16,0xAB,0xC6,0xCA,0xE0,0xB5,0xDF,0xCD,0xA1,0xD4,0x78,0x1B,0xB6,0x53,0x97,0x74,0xA7,0x21,0xBC,0xE4,0xFF,0x01};
const uint8_t spV[] PROGMEM = {0x66,0xF3,0xD2,0x38,0x43,0xB3,0xD8,0x2D,0xAC,0x4D,0xBB,0x70,0xB0,0xDB,0xB0,0x0E,0x17,0x2C,0x26,0xAE,0xD3,0x32,0x6C,0xBB,0x32,0xAB,0x19,0x63,0xF7,0x21,0x6C,0x9C,0xE5,0xD4,0x33,0xB6,0x80,0xCB,0x9A,0x9B,0xAF,0x6C,0xE5,0x42,0x70,0x7F,0xB3,0xB3,0x9D,0xEE,0x7C,0x55,0x2B,0x26,0x40,0xD5,0xE2,0xD9,0xF6,0xB1,0x4F,0x75,0xAB,0x7B,0x3D,0xCA,0x35,0x4B,0x13,0x98,0xAF,0xA9,0x57,0x7E,0xF3,0x97,0xBE,0x19,0x0B,0x31,0xF3,0xCD,0xFF,0x03};
const uint8_t spW[] PROGMEM = {0xA1,0xDE,0xC2,0x44,0xC2,0xFC,0x9C,0x6A,0x88,0x70,0x09,0x59,0x7B,0x8A,0xCA,0x3B,0x3D,0xA4,0xCF,0xCD,0x56,0x96,0xC4,0xA6,0xBB,0xF4,0x6E,0x59,0xE2,0x9D,0xEA,0xE2,0x4A,0xD5,0x12,0x65,0xBB,0xB3,0xEB,0x51,0x57,0x12,0x99,0xC1,0xD9,0x6E,0xB7,0xC7,0x31,0x35,0x92,0x6A,0xC9,0x9B,0xC7,0x34,0x4C,0x12,0x46,0x6C,0x99,0x73,0x5F,0xDA,0xD2,0x92,0x92,0x64,0x6C,0xEE,0x6B,0xD9,0x6A,0x22,0x71,0x8F,0xCF,0xE5,0x2C,0x41,0xD4,0xDD,0x36,0xA5,0x3B,0x19,0xF5,0x0C,0xEE,0x13,0xEF,0xFC,0x9A,0xD7,0x85,0xC8,0x62,0xEE,0x6D,0xBF,0xFF,0x07};
const uint8_t spX[] PROGMEM = {0xAD,0x68,0xC9,0xC5,0x32,0x56,0xDF,0xFA,0x54,0x2D,0x35,0x7B,0xF8,0xEA,0x5B,0xDD,0xE6,0x4C,0x6D,0x04,0xA6,0xC5,0xEA,0xB9,0x84,0xB5,0x75,0x23,0x37,0x4F,0x83,0x40,0x11,0xCA,0x5D,0x44,0x36,0x00,0x28,0xA0,0xE6,0x31,0x0F,0x68,0xC0,0x00,0xBF,0x8D,0x79,0xC0,0x03,0x16,0xD0,0x00,0x07,0xFE,0x1F};
const uint8_t spY[] PROGMEM = {0x6A,0xB1,0xA2,0xA7,0x95,0xD2,0xD8,0x25,0x0F,0xA3,0x2D,0xB2,0x7A,0x1C,0xB3,0xDE,0xE6,0xD4,0x45,0x6D,0x56,0xCA,0x9A,0x5B,0xDF,0xFA,0xB6,0xBB,0xDB,0xFD,0x1A,0x8A,0x6F,0x2B,0xF3,0x37,0x7B,0x19,0x4B,0xD3,0x25,0x39,0xFA,0xB9,0x6F,0x6D,0xEB,0x31,0xC4,0x5C,0x1E,0xF7,0xAD,0x1F,0xE5,0x1C,0xA5,0x48,0x5C,0x1E,0xD7,0x2B,0x5F,0xF9,0xFA,0x7F};
const uint8_t spZ[] PROGMEM = {0x6D,0xFD,0xC6,0x5C,0x95,0xD5,0xF5,0xD5,0x02,0x7B,0x5D,0xFD,0x51,0x2D,0x2A,0xE4,0x77,0x75,0xA3,0x3A,0xB1,0xFA,0x9B,0x5D,0xEF,0x6A,0x55,0x33,0x27,0x60,0xD4,0xE2,0xD9,0xCC,0x76,0x4E,0x73,0x9D,0x7B,0x3F,0xFB,0x59,0xAE,0x55,0x0A,0xC1,0x73,0x4D,0xBD,0xEA,0x9D,0x9E,0x15,0x12,0xA0,0x6B,0x75,0x7E,0xFE,0x1F};
const uint8_t spALPHA[] PROGMEM = {0xAD,0xED,0x6A,0xDC,0x4B,0x57,0xEF,0xF6,0xB4,0x53,0x6C,0x6A,0x4B,0x97,0x53,0x77,0x7E,0x19,0xC9,0x9B,0x57,0x99,0xCC,0x7B,0x9A,0x6E,0x9E,0x45,0x2B,0xA2,0xA9,0x0A,0x91,0xCC,0xB5,0x00,0x02,0x14,0x67,0xA1,0x80,0x16,0x2C,0x3C,0x60,0x80,0xE6,0x2C,0x4A,0x51,0x54,0x47,0x38,0x6F,0xDE,0xC3,0x5D,0xF6,0x36,0xF7,0x7A,0xE5,0xFB,0xFF,0x01};
const uint8_t spBRAVO[] PROGMEM = {0x61,0x5A,0xBA,0xC2,0xDD,0x62,0x85,0xD6,0xE8,0x15,0x59,0xB1,0x97,0x9A,0x30,0xD5,0xBC,0x85,0xDF,0xA8,0x63,0x0F,0xE9,0x50,0xE5,0xA7,0xCA,0x6E,0x22,0x5D,0x57,0xEF,0x72,0x97,0xB3,0x2A,0x6D,0x74,0x15,0xE9,0xBA,0x3A,0xF6,0x66,0xE8,0x3E,0xD4,0x5C,0x65,0xD7,0x31,0x2D,0x95,0x54,0xBB,0x8B,0xDF,0xD9,0xAE,0xB1,0xA1,0xAC,0x0E,0x51,0x3F,0xE7,0xB6,0x14,0xD2,0x35,0x4E,0xEE,0xFB,0x5E,0x77,0xB3,0x7B,0xDF,0x19,0x2C,0x7D,0xEC,0xE9,0x2F,0x73,0x05,0xDF,0x19,0x2C,0x7D,0xF8,0xF3,0xFF};
const uint8_t spCHARLIE[] PROGMEM = {0x06,0xD8,0x2D,0x2C,0x01,0x33,0xB7,0x67,0x60,0xC4,0x35,0x94,0xAA,0x5A,0xEA,0x93,0x15,0xD7,0xAA,0x23,0xEE,0x56,0x9E,0xD3,0xAA,0x2E,0xE5,0xDB,0xF9,0xC8,0x4B,0x6A,0x8E,0xE3,0x3E,0x33,0x2F,0x45,0x6E,0x62,0x39,0x9A,0x76,0x74,0x4D,0xA5,0xA5,0x73,0xD2,0x3B,0xAC,0xA9,0xD9,0x61,0x0D,0xDF,0x32,0xE6,0xEE,0x0A,0x39,0xE3,0xF3,0x58,0x97,0x2D,0xC2,0x8C,0x2D,0x7D,0x4D,0xE7,0xCC,0x09,0x18,0xB5,0x38,0x5E,0xFE,0xFE,0x7F};
const uint8_t spDELTA[] PROGMEM = {0x02,0xE8,0x54,0x6D,0xB5,0x35,0x84,0xB9,0xDA,0x9A,0x5B,0x9F,0xAA,0x98,0x71,0x77,0xDB,0x7C,0x8A,0x64,0x2F,0x5C,0xBD,0xF7,0xCA,0x33,0x9F,0x4A,0x95,0x2C,0x2D,0xCB,0xD2,0xAA,0x95,0xDD,0x9A,0x7C,0x7B,0x15,0xD2,0x48,0x8C,0x40,0x11,0xCA,0x5D,0x44,0x36,0x28,0xE0,0x47,0x73,0x01,0x24,0xEA,0xB2,0xBA,0x6A,0xC2,0xC3,0x7C,0xCB,0x1D,0xCF,0xD6,0x54,0xA5,0x87,0x74,0xDD,0xE7,0xBA,0xAB,0x1A,0xF3,0x94,0xCE,0xFD,0xC9,0xEF,0xFF,0x03};
const uint8_t spECHO[] PROGMEM = {0x2B,0x6F,0xB1,0xD9,0xD3,0x36,0xDF,0xF6,0x36,0xB7,0x26,0x85,0x08,0xE5,0x2E,0x22,0x1B,0x20,0x00,0x25,0xAC,0x2A,0x20,0xCF,0xD3,0x52,0x45,0x53,0x6A,0xA9,0x9E,0x4F,0x9B,0x54,0x47,0xB9,0xE4,0xDF,0xC3,0x1C,0xC6,0x98,0x45,0x65,0xBB,0x78,0x9F,0xCB,0x5C,0xD2,0xEA,0x43,0x67,0xB0,0xE5,0xCD,0x7B,0x38,0x9D,0xAD,0x2C,0x15,0x37,0xF1,0xFC,0x7F};
const uint8_t spFOXTROT[] PROGMEM = {0x08,0x98,0xB1,0x53,0x02,0x1E,0x88,0xC0,0xCA,0x8B,0xDA,0x4A,0x97,0x2E,0xB7,0xBA,0xD5,0x2A,0x73,0xE8,0x48,0xD3,0xCD,0xAD,0xA8,0x35,0xA2,0xC5,0xAA,0x90,0x42,0x84,0x72,0x17,0x91,0x0D,0x0A,0xA8,0xA1,0xC5,0x01,0xAF,0xF8,0x78,0x40,0x01,0x6F,0xB5,0x23,0xA0,0x47,0x53,0x0C,0x44,0xC0,0x03,0xAD,0x49,0x85,0x53,0x53,0xDD,0x8D,0x26,0x56,0xCB,0x70,0xCD,0xB7,0xA6,0x64,0xC7,0x2B,0x39,0xEF,0x5A,0xAA,0xB8,0xF4,0xE2,0x3E,0xF3,0x1C,0x57,0x0E,0x1D,0x69,0xBA,0xD9,0x5F,0x08,0x14,0xA1,0xDC,0x45,0x64,0x03,0x80,0x00,0x8E,0xE0,0x30,0xC0,0xB2,0x53,0x04,0xA8,0xCA,0xE5,0xFF,0x01};
const uint8_t spGOLF[] PROGMEM = {0x0A,0x88,0xA1,0x71,0x15,0x85,0x76,0x45,0x8A,0xFF,0x9B,0xDF,0x6C,0x65,0x99,0x5C,0xB7,0x72,0xDE,0x9D,0xED,0x72,0x77,0x73,0x6C,0x4B,0x54,0x35,0x63,0xE4,0xA6,0xEE,0xF9,0x34,0x57,0x94,0x39,0x63,0xE4,0x86,0x5F,0x04,0x98,0x34,0xDD,0x02,0x0E,0x98,0x32,0x5D,0x03,0x12,0xE0,0xC0,0xFF,0x03};
const uint8_t spHENRY[] PROGMEM = {0x08,0xC8,0x4A,0x8C,0x03,0x1A,0x68,0x49,0x0B,0xAC,0xE5,0x11,0xFA,0x14,0xCD,0x35,0x59,0xC4,0xE3,0x5B,0xEC,0xBC,0xA5,0xD5,0x88,0x96,0x99,0xBD,0x9E,0x95,0x3C,0x1B,0xB3,0x64,0x69,0x1A,0xEB,0xD2,0xA7,0xA9,0x1C,0xE6,0xD1,0xDB,0x98,0x07,0xA7,0x5A,0xAA,0x5F,0x53,0x4D,0xAA,0x61,0x9E,0x7D,0xAC,0xDD,0x8E,0x48,0xC8,0x9E,0xB1,0x77,0x5B,0x44,0x95,0xAB,0xEB,0x15,0xAE,0x1E,0x0D,0x2D,0xF3,0x4D,0x7C,0xFC,0xF3,0xFF};
const uint8_t spINDIA[] PROGMEM = {0xA3,0x9D,0xD6,0x99,0x32,0x17,0xAF,0x66,0x86,0x16,0x74,0x5F,0x73,0x9A,0xE1,0x4A,0xC4,0xF4,0xCE,0xAD,0x46,0xD1,0x1D,0x5A,0x46,0x3A,0x99,0x45,0x2B,0xAA,0x82,0xAC,0x08,0x27,0xBE,0x5A,0xDD,0x0C,0x25,0x42,0xBC,0xFB,0xF4,0xD3,0x17,0x61,0xF8,0x96,0x3B,0xDC,0xF1,0x4C,0xDD,0x26,0x4B,0xD9,0x9E,0xBB,0xAC,0xB5,0xBB,0x36,0x0D,0xDA,0x7B,0xF6,0xA6,0xD3,0x3A,0xA5,0xF7,0x7E,0xE7,0x3B,0xBF,0xF2,0x55,0x17,0xD6,0xCE,0xAB,0xFD,0xFF,0xFF};
const uint8_t spJULIET[] PROGMEM = {0x61,0x5D,0x96,0x49,0x34,0xD2,0x06,0x60,0xC7,0x90,0x0C,0x8C,0x66,0xF6,0x15,0x22,0x4D,0x37,0xAA,0x6A,0xC8,0x2C,0x6D,0xCD,0x28,0xB2,0x15,0x8B,0xE4,0x35,0xB3,0x68,0x79,0x51,0xE6,0xDA,0x9C,0xBE,0x15,0x43,0x89,0xF0,0xA2,0xDB,0x95,0x77,0xA7,0xA6,0x66,0x49,0x77,0xB1,0x9A,0x9E,0x0A,0xD5,0x75,0xEB,0xEE,0xF6,0xB0,0xC6,0xE6,0x83,0xD2,0xE3,0xEB,0x5E,0xD7,0xDA,0x5C,0x48,0x87,0x6D,0x9E,0x7B,0xDF,0xF3,0x89,0x40,0x11,0xCA,0x5D,0x44,0x36,0x00,0x38,0x60,0xEA,0x8C,0x00,0x2C,0xB3,0x6D,0x01,0x01,0x14,0x5F,0x8E,0x81,0xFF,0x07};
const uint8_t spLIMA[] PROGMEM = {0x61,0x5A,0x90,0xBA,0xC0,0xD7,0xA6,0x69,0x00,0x19,0x85,0x6A,0xDA,0x9A,0xCD,0x24,0xD9,0xCC,0xCB,0x29,0x46,0x76,0x66,0xF5,0x37,0x3B,0x9B,0xC9,0x48,0x7B,0x50,0xD4,0x8E,0xD9,0xBD,0xA8,0x75,0x6B,0xB3,0x62,0xEE,0xF4,0xB8,0xB5,0xAD,0xFD,0x98,0x8A,0x51,0x0E,0x91,0xB4,0xA3,0x6F,0xBC,0x32,0x8B,0x3A,0xDF,0xE1,0xEE,0xE3,0xCC,0x6A,0x23,0x43,0x57,0xF5,0xA7,0xBE,0xF5,0xFD,0x7F};
const uint8_t spMIKE[] PROGMEM = {0x66,0x31,0x3C,0x7C,0x52,0xE3,0xC4,0x69,0xF5,0x85,0x57,0x86,0x51,0xAA,0xD3,0x56,0x75,0xA1,0x69,0x9D,0x6F,0x7D,0xCA,0x6A,0x57,0x23,0x6D,0xF5,0xCD,0x57,0xD1,0x4B,0x50,0x78,0x2C,0xDA,0x75,0x69,0x46,0x77,0xB4,0xCE,0xDB,0xB1,0x45,0xAD,0x08,0xE5,0x2E,0x22,0x1B,0x00,0x18,0xD0,0x3C,0x91,0x03,0x5A,0x09,0xB1,0x80,0x00,0xB2,0x13,0xFE,0x7F};
const uint8_t spNOVEMBER[] PROGMEM = {0x6A,0x2B,0x02,0x62,0x4B,0xE3,0xDA,0x75,0x2C,0x5D,0x87,0xB8,0x73,0x9B,0xD5,0x66,0x1D,0x16,0x66,0x7D,0x57,0x9B,0x45,0x59,0x07,0xB7,0x6B,0x55,0xB0,0x99,0xCD,0x9C,0xAD,0x56,0xA1,0x88,0xCE,0x3A,0x99,0x33,0xFB,0xC5,0xCC,0xD5,0xA8,0xA5,0xA9,0x1B,0xDF,0x8E,0xBA,0x05,0xB3,0x34,0xED,0x7C,0xCB,0x9B,0x8F,0xAC,0x38,0xCB,0x0C,0x6D,0x5C,0xB2,0xA2,0x94,0xDA,0xCD,0x4D,0x2C,0x55,0x2B,0x75,0x4A,0xA7,0xBB,0xD5,0x3D,0xA4,0x2D,0x77,0xE5,0x2A,0xEE,0x9C,0xD7,0xB4,0x65,0x77,0xA0,0x9B,0xFA,0xE2,0x9E,0xAE,0x5C,0x0B,0xAA,0xD4,0xB7,0xBF,0xFD,0x6D,0x9E,0xE2,0x1A,0x7C,0x43,0xAF,0x7A,0xCB,0x30,0xCA,0xE6,0x2D,0xFF,0x0F};
const uint8_t spOSCAR[] PROGMEM = {0x6B,0xC8,0xE2,0xB2,0x42,0x3A,0xDF,0xFA,0x16,0x27,0x4F,0xAE,0x7D,0xC4,0x17,0xB7,0x2C,0x45,0xAF,0xA4,0xB6,0x6D,0x80,0x03,0xD8,0x0C,0xF0,0xA7,0x9B,0x07,0x3C,0xE0,0x80,0xEB,0xB5,0xC1,0x6C,0x4D,0x5D,0x45,0x69,0xDC,0xD4,0x17,0x37,0x49,0x26,0x4A,0x5B,0x9B,0x53,0x91,0x0D,0xE7,0x9D,0xFD,0x1C,0xDB,0x92,0x9B,0x61,0xB5,0xF4,0x9E,0x5B,0xDD,0xEB,0x99,0xEE,0x12,0x07,0x75,0x52,0x6F,0xFE,0xC2,0x5F,0x5A,0x91,0x0E,0x67,0xF9,0x7F};
const uint8_t spPAPA[] PROGMEM = {0x0A,0x70,0x4A,0xB5,0xA5,0x45,0x55,0x84,0x49,0xCC,0x93,0x66,0xD7,0x19,0x26,0x4B,0x4E,0x96,0xDD,0x44,0xBA,0xAE,0xBE,0xD9,0xCC,0x10,0x28,0x42,0xB9,0x8B,0xC8,0x06,0x60,0x80,0xF1,0xE9,0xAB,0xCA,0xA6,0x23,0xD4,0x36,0xDF,0xE1,0x8C,0x55,0x74,0x86,0x6B,0x9F,0xB1,0x67,0xBD,0xE1,0xE6,0xBB,0xDB,0x97,0x53,0x45,0x88,0xCF,0xAE,0xDF,0xFF,0x03};
const uint8_t spQUEBEC[] PROGMEM = {0x0C,0x88,0x7E,0x8C,0x02,0xA5,0x0A,0x31,0xDD,0x5C,0xB2,0xAC,0x26,0x5B,0xCF,0x4C,0xEE,0xBB,0xBB,0xDE,0xA7,0xCD,0xA8,0xB4,0x75,0x4D,0x1C,0xB7,0xD1,0xD5,0x28,0xEE,0xE6,0x5B,0x76,0x7B,0x9A,0x1A,0xC4,0x33,0xF3,0xF1,0x6D,0x76,0x3F,0xE7,0xB6,0xB6,0xEC,0x12,0x91,0x9B,0xF2,0x8E,0x40,0x11,0xCA,0x5D,0x44,0x36,0x80,0x00,0x7A,0x2F,0x53,0x40,0x2D,0x24,0x14,0xF8,0x7F};
const uint8_t spROMEO[] PROGMEM = {0xA2,0xD5,0x39,0x38,0xCA,0xEC,0xDB,0xA5,0x4C,0xA1,0x98,0x5A,0xB9,0xF2,0xD3,0x47,0x6F,0xE9,0x69,0xCA,0x4E,0xDD,0x89,0x57,0x0E,0x69,0x3F,0x45,0x61,0xD9,0x95,0x98,0x65,0x67,0x25,0x6B,0x86,0x64,0x4C,0xAC,0xF5,0xE2,0x54,0xCD,0x86,0x7A,0xD0,0xE6,0x35,0x4C,0xD7,0x02,0xA5,0x7B,0xF6,0xB0,0xA7,0xBD,0xAC,0xB5,0xAA,0x54,0x1D,0xDB,0xB2,0xF6,0xEC,0xC3,0xD3,0x64,0x73,0xD9,0x63,0xC8,0x2C,0xD5,0xDF,0xE9,0x0C,0xA1,0x33,0xD8,0xF2,0xE6,0x33,0x5E,0xEE,0x09,0xB6,0xB2,0x54,0xDC,0xF8,0xE7,0xFF,0x01};
const uint8_t spSIERRA[] PROGMEM = {0x0C,0xF8,0xAD,0xDC,0x02,0x1E,0xB0,0x80,0x06,0x4A,0xDE,0x7D,0x90,0xB8,0xBD,0x1E,0xD5,0xC8,0x45,0xE8,0xF6,0x76,0x56,0xB3,0xDE,0xF5,0xAD,0x4F,0x35,0x72,0xB1,0xB8,0xAE,0x39,0x65,0x0F,0x45,0x56,0xFA,0xE5,0xE4,0x25,0x24,0xE5,0xC8,0xE6,0x91,0xC6,0xC9,0x99,0x6E,0x69,0x7B,0xDA,0xF3,0xD5,0xA4,0xA4,0x95,0x6E,0x5D,0xF6,0xB0,0xB7,0xB5,0x17,0x5B,0xD6,0x2A,0x9B,0xC7,0x9D,0x5D,0x5B,0x9B,0xEF,0xEA,0x77,0x7D,0xCA,0x5F,0x55,0xD9,0x94,0xF4,0xFE,0x7F};
const uint8_t spTANGO[] PROGMEM = {0x0E,0x58,0x5A,0xC3,0x02,0x27,0xEB,0xA1,0xC4,0x2B,0x97,0xDC,0xF2,0x16,0x27,0xEF,0x51,0xB9,0x2A,0x2B,0xEF,0xAC,0x64,0x3D,0x60,0x79,0x99,0xE2,0x52,0x74,0x8F,0x9E,0x56,0xAA,0x43,0x99,0x24,0x75,0x5A,0x3A,0x0E,0x4D,0x31,0xC1,0xAC,0x96,0x24,0xCD,0x35,0x96,0x38,0xC9,0xAA,0xD6,0x25,0x17,0x96,0xA6,0xBB,0xE7,0xB0,0xA6,0x2C,0x2A,0xDB,0xC5,0xFB,0x9E,0xE6,0x92,0x76,0x1F,0x3A,0x83,0x2D,0x6F,0x3C,0xC3,0xE5,0x6C,0x65,0xA9,0xB8,0xF1,0xB7,0xBD,0xFF,0x1F};
const uint8_t spUNIFORM[] PROGMEM = {0x61,0x3D,0x56,0x98,0xD4,0xB6,0xE6,0xA5,0x8D,0xC7,0xA8,0x01,0xC5,0xDA,0x33,0x2C,0x97,0x06,0x12,0xD9,0x4F,0xD9,0x6D,0x30,0xA6,0x65,0xDF,0x79,0x4B,0x8B,0x11,0xCF,0xE0,0xAE,0x29,0xCD,0x4E,0x5D,0x38,0xEA,0xF5,0xF4,0x64,0x45,0x47,0x84,0xCA,0xE6,0x5D,0xF5,0x96,0x01,0xCD,0x97,0x6A,0x40,0x03,0x1A,0x28,0x5D,0xD0,0xDB,0x61,0xEC,0x7D,0xF7,0x7B,0x3C,0x53,0x16,0xDB,0x9A,0xEA,0xF5,0x2E,0x6B,0x2D,0x6A,0x43,0x46,0xBC,0xCD,0xB3,0x3D,0xD9,0xB5,0xDA,0x70,0xDF,0x72,0xE7,0x94,0xEA,0xCD,0x9D,0xDD,0x9D,0xBC,0x73,0xA9,0x28,0x35,0x4F,0x12,0x41,0xE1,0x96,0xD4,0x3D,0x4D,0x24,0xA7,0x8A,0x94,0xF8,0xFA,0x37,0x7C,0xCD,0x76,0x78,0x50,0xEA,0xF8,0xFD,0x3F};
const uint8_t spVICTOR[] PROGMEM = {0x6E,0x2D,0xCA,0xD8,0x43,0xD5,0x99,0xBD,0x58,0xE6,0x70,0xF1,0x9A,0x97,0xD5,0xB6,0x54,0xAA,0x26,0x7D,0x6E,0xB5,0xB2,0xD6,0x8D,0x4D,0x74,0xCB,0x4E,0x4D,0x3C,0xB2,0xAA,0x8B,0x38,0x16,0x40,0xE5,0x8C,0x18,0x40,0xA0,0x08,0xE5,0x2E,0x22,0x1B,0x0C,0xB0,0xED,0xA4,0x02,0xAA,0x15,0x5A,0x43,0xF5,0x21,0x54,0x96,0x6D,0x2C,0xA5,0x26,0x7A,0xB9,0xB7,0xBE,0xA5,0x27,0x57,0x87,0x2E,0xF7,0x1F,0xFE,0xDC,0x49,0xBB,0xBC,0x6F,0xFC,0xFD,0xEF,0xFF,0xFF,0x07};
const uint8_t spWHISKY[] PROGMEM = {0x04,0x88,0xAE,0x8C,0x03,0x12,0x08,0x51,0x74,0x65,0xE9,0xEC,0x68,0x24,0x59,0x46,0x78,0x41,0xD7,0x13,0x37,0x6D,0x62,0xC3,0x5B,0x6F,0xDC,0xD2,0xEA,0x54,0xD2,0xE3,0x89,0x01,0x7E,0x2B,0xF7,0x80,0x07,0x14,0xD0,0xE5,0x15,0x38,0x60,0x8C,0x70,0x03,0x04,0x29,0x36,0xBA,0x5E,0x14,0x34,0x72,0xF6,0xE8,0xA7,0x6F,0x82,0xF4,0x2D,0x73,0xEA,0x47,0x3A,0x67,0x6A,0xC0,0xF0,0x2F,0xF1,0x4E,0xCF,0xA8,0x8A,0x1C,0xB9,0xD8,0xFF,0xEE,0x1F,0xBB,0x59,0xD0,0xD6,0xFE,0x3F};
const uint8_t spXRAY[] PROGMEM = {0x69,0xAE,0xDE,0x34,0x3A,0x6B,0x9F,0xAC,0xA5,0x66,0x0F,0x5F,0x7D,0x8B,0x5B,0xAD,0xAA,0x8D,0xC0,0xB4,0x58,0xDD,0xDB,0xD0,0xB6,0x6E,0xE4,0xE6,0x69,0x10,0x28,0x42,0xB9,0x8B,0xC8,0x06,0x10,0x40,0xCD,0x63,0x1A,0x60,0xC0,0x6F,0x63,0x1C,0xA0,0x00,0x5B,0xFD,0x54,0xEA,0x54,0xE7,0x66,0x4E,0x8D,0xC3,0xD3,0xF4,0xE6,0xA9,0x4F,0x6B,0xAE,0x2E,0x39,0x42,0xFB,0xEE,0x6D,0x1C,0xCD,0x24,0x45,0xF9,0xE7,0x7E,0xF6,0x33,0x5F,0xF9,0x0A,0xCF,0xB4,0x4B,0x94,0xBE,0x27,0x3E,0xF1,0x75,0xEF,0xCC,0x09,0x18,0xB5,0xF8,0xFF,0x01};
const uint8_t spYANKEE[] PROGMEM = {0x6E,0xEF,0x42,0x58,0xB6,0x6B,0xA7,0x7D,0x68,0x25,0xCC,0x59,0xB4,0xF6,0x11,0x82,0xC8,0x6A,0xF1,0x1A,0x46,0x2E,0x12,0x8D,0x37,0xA7,0xEF,0xC9,0xC9,0xA3,0x6E,0x9F,0x76,0xD4,0x22,0x73,0x7F,0xB4,0xEA,0x51,0x0B,0x2D,0x62,0xE2,0xA8,0x47,0x43,0xD7,0x2E,0x29,0xAE,0x4D,0x92,0xAA,0x28,0x5C,0x8B,0xB9,0x6A,0xEB,0x24,0x95,0xE3,0x80,0x1D,0x93,0x35,0x90,0xBA,0x59,0x03,0x45,0xB3,0x75,0x19,0x46,0x27,0x96,0x98,0xC5,0x65,0x1F,0xCD,0x88,0xBC,0x16,0xD7,0x3D,0x3D,0x63,0x10,0x49,0x6E,0xED,0xF8,0xFA,0xEF,0xFF,0x01};
const uint8_t spZULU[] PROGMEM = {0x6D,0xFE,0xDE,0xC4,0xC4,0xE8,0x29,0x60,0x00,0x2E,0x0F,0x9C,0x6C,0x29,0x71,0x2A,0x4E,0x77,0x93,0x15,0x77,0x2A,0xAE,0xC3,0xCE,0x76,0x3C,0x92,0xA5,0x44,0x78,0xD1,0x6D,0xCF,0x47,0x3B,0xB8,0xBB,0x07,0xF6,0x5B,0x43,0x91,0x6E,0xA9,0xF2,0x65,0x4C,0xC9,0x98,0x97,0x69,0x9F,0xBA,0xE5,0x33,0x9C,0xC1,0x9A,0x8F,0xCA,0xDE,0x70,0x07,0x9D,0xEE,0xC9,0x79,0xE2,0xED,0xFF,0xFF,0x07};
const uint8_t spTHE[] PROGMEM = {0x6E,0xAD,0xCC,0x34,0x9C,0x97,0xE8,0x23,0xED,0x5D,0xA4,0xBB,0xF1,0x96,0xD9,0xEE,0xFA,0xD4,0x45,0x75,0xA6,0xC9,0xE6,0x5B,0xDF,0xE6,0x0E,0x67,0xAE,0x7C,0xD3,0x43,0xFB,0xEC,0x7D,0x9E,0xFD,0xFE,0x7F};
const uint8_t spWATTS[] PROGMEM = {0xAA,0x15,0x7A,0x23,0x5C,0x12,0xE9,0xD1,0x0D,0x5A,0x76,0x75,0xB2,0xAA,0xD0,0x3B,0xD9,0xED,0x81,0x99,0x4A,0x1B,0xD5,0x8C,0x25,0xFA,0xDD,0xF5,0xA9,0xA3,0x9F,0x2C,0xE3,0x2E,0xB7,0xBE,0xCD,0xEE,0xD6,0x9C,0xDC,0x44,0xAB,0xAD,0x6E,0x67,0x0E,0xE9,0xCD,0x7D,0xBB,0x1E,0x0C,0x1C,0x24,0xCA,0x5C,0x59,0x03,0x00,0x01,0xB6,0x2A,0x15,0xC0,0x2F,0x19,0x1A,0xB0,0x80,0x05,0x2C,0x60,0x80,0xAF,0xA2,0x24,0xF0,0xFF};
const uint8_t spMETER[] PROGMEM = {0xA1,0x8F,0x5C,0xB5,0x56,0x92,0xE4,0xE1,0xF4,0xDD,0x0B,0x59,0x6B,0xE3,0x53,0x8C,0x14,0x44,0x15,0x8B,0x46,0x3A,0xB3,0x03,0x7B,0xBE,0x99,0x89,0x49,0xB7,0x72,0xC4,0xEA,0x4C,0x01,0xD8,0x2E,0xC8,0x03,0xA3,0xAB,0x91,0x39,0x2C,0x17,0x8D,0xAE,0x36,0xE6,0x34,0x7F,0x3D,0xE6,0xEA,0x13,0x6C,0x79,0x73,0x3B,0xAA,0x1B,0xB0,0xD3,0x3C,0xFD,0x6A,0x4F,0xF1,0x09,0x35,0x9E,0xA5,0xBE,0xFF,0x0F};
const uint8_t spDANGER[] PROGMEM = {0x2D,0xBF,0x21,0x92,0x59,0xB4,0x9F,0xA2,0x87,0x10,0x8E,0xDC,0x72,0xAB,0x5B,0x9D,0x62,0xA6,0x42,0x9E,0x9C,0xB8,0xB3,0x95,0x0D,0xAF,0x14,0x15,0xA5,0x47,0xDE,0x1D,0x7A,0x78,0x3A,0x49,0x65,0x55,0xD0,0x5E,0xAE,0x3A,0xB5,0x53,0x93,0x88,0x65,0xE2,0x00,0xEC,0x9A,0xEA,0x80,0x65,0x82,0xC7,0xD8,0x63,0x0A,0x9A,0x65,0x5D,0x53,0xC9,0x49,0x5C,0xE1,0x7D,0x2F,0x73,0x2F,0x47,0x59,0xC2,0xDE,0x9A,0x27,0x5F,0xF1,0x8B,0xDF,0xFF,0x03};
const uint8_t spPRESSURE[] PROGMEM = {0x06,0x28,0xC1,0x4C,0x03,0x2D,0x49,0x59,0x4A,0x9A,0x3D,0x9F,0xAC,0x04,0x2D,0x2D,0x69,0x73,0xB2,0x56,0x4C,0x43,0x6D,0xF5,0xCD,0x5A,0x3E,0x6A,0x89,0x09,0x65,0x71,0xC0,0xAA,0xDB,0x1E,0x88,0x40,0x04,0x46,0xDF,0x63,0x0A,0x9A,0x65,0x1D,0x43,0xC9,0x49,0x5C,0xE1,0x7D,0xCF,0x7B,0x9F,0x47,0xB9,0xCA,0x12,0xF6,0xD6,0x3C,0xF9,0x8B,0x9F,0xFD,0xFF,0x1F};
const uint8_t spCHANGE[] PROGMEM = {0x06,0x58,0xD5,0xC3,0x01,0x73,0x6E,0x64,0xC0,0x03,0x2B,0x1B,0xB9,0x95,0xDC,0xFB,0xDE,0xE2,0x14,0xA3,0x06,0x4B,0xE5,0xA2,0x9B,0xEF,0x7C,0x95,0xC3,0x1B,0xCA,0x64,0xA5,0x5D,0xED,0x76,0xCE,0x7D,0x2D,0x6B,0xB3,0x24,0x19,0x11,0x3A,0x1D,0xDD,0x93,0x94,0x7A,0x54,0x7F,0xBA,0xBB,0x4B,0xC5,0x08,0xAD,0x1A,0x9E,0xEE,0x85,0x43,0x2D,0x9E,0x79,0xAA,0x10,0xCA,0xD2,0x2A,0xEA,0xC9,0x82,0xAC,0xC3,0x6B,0xCB,0x87,0x3D,0x51,0xB2,0x75,0x74,0x2D,0xF4,0xCE,0x30,0x2C,0x62,0x76,0x14,0x30,0x94,0x92,0x02,0xC6,0x5C,0xB7,0x00,0x02,0x5A,0x17,0xF9,0x7F};
const uint8_t spMINUS[] PROGMEM = {0xE6,0x28,0xC4,0xF8,0x44,0x9A,0xFB,0xCD,0xAD,0x8D,0x2A,0x4E,0x4A,0xBC,0xB8,0x8C,0xB9,0x8A,0xA9,0x48,0xED,0x72,0x87,0xD3,0x74,0x3B,0x1A,0xA9,0x9D,0x6F,0xB3,0xCA,0x5E,0x8C,0xC3,0x7B,0xF2,0xCE,0x5A,0x5E,0x35,0x66,0x5A,0x3A,0xAE,0x55,0xEB,0x9A,0x57,0x75,0xA9,0x29,0x6B,0xEE,0xB6,0xD5,0x4D,0x37,0xEF,0xB5,0x5D,0xC5,0x95,0x84,0xE5,0xA6,0xFC,0x30,0xE0,0x97,0x0C,0x0D,0x58,0x40,0x03,0x1C,0xA0,0xC0,0xFF,0x03};
const uint8_t spNOT[] PROGMEM = {0x66,0x6B,0x1A,0x25,0x5B,0xEB,0xFA,0x35,0x2D,0xCD,0x89,0xA7,0xDA,0x9A,0x31,0x34,0x93,0x9E,0xA6,0x4B,0x4E,0x57,0xE5,0x86,0x85,0x6C,0xBE,0xED,0x6D,0x57,0x93,0xFC,0xB9,0x96,0x2D,0x1E,0x4D,0xCE,0xAD,0xE9,0x3E,0x7B,0xF7,0x7D,0x66,0xB3,0x08,0xE5,0x2E,0x22,0x1B,0x00,0x40,0x01,0x4B,0xB8,0x2B,0xE0,0x87,0x68,0x05,0x74,0x9D,0x82,0x80,0x62,0x55,0xFE,0x1F};
const uint8_t spSTART[] PROGMEM = {0x04,0xF8,0xC5,0x9C,0x03,0x1A,0xD0,0x80,0x04,0x38,0x00,0x06,0x58,0x22,0x7D,0x65,0x9D,0x87,0x8B,0x5B,0xD7,0x53,0x67,0x37,0x96,0x21,0x79,0x6F,0x7D,0xEB,0xD5,0x64,0xB7,0x92,0x43,0x9B,0xC7,0x50,0xDD,0x92,0x1D,0xF7,0x9E,0x53,0xDF,0xDD,0x59,0xCB,0x21,0xAD,0xF6,0x46,0xA0,0x08,0xE5,0x2E,0x22,0x1B,0x40,0x01,0xDD,0xB2,0x2A,0xE0,0xB7,0x0C,0x03,0x4C,0x9D,0x4A,0x80,0xEA,0x54,0xFE,0x1F};
const uint8_t spLINE[] PROGMEM = {0x61,0xED,0x40,0xC7,0xCD,0xD2,0x96,0x65,0x01,0x9E,0x50,0x73,0x5B,0x96,0x83,0x70,0x87,0x2D,0xD9,0x9A,0x3B,0xA9,0x49,0x97,0x2E,0xB7,0xBF,0xDD,0x6D,0x4F,0x5B,0xD5,0xBA,0x95,0x75,0xD9,0xFD,0x1A,0x86,0x6B,0xD6,0x8A,0xC5,0x7B,0x9A,0xF3,0x3C,0xFA,0x51,0xAE,0x9E,0x59,0x55,0x2A,0x72,0xBE,0xC2,0x35,0x12,0xB9,0x88,0xBB,0x89,0x57,0xB8,0x7A,0x72,0x77,0xB0,0x3A,0xE9,0xEF,0x2E,0xC5,0xDD,0x1F,0x87,0xBF,0x8A,0xD0,0xEA,0x68,0xF8,0xFF};
const uint8_t spOFF[] PROGMEM = {0x6B,0x4A,0xE2,0xBA,0x8D,0xBC,0xED,0x66,0xD7,0xBB,0x9E,0xC3,0x98,0x93,0xB9,0x18,0xB2,0xDE,0x7D,0x73,0x67,0x88,0xDD,0xC5,0xF6,0x59,0x15,0x55,0x44,0x56,0x71,0x6B,0x06,0x74,0x53,0xA6,0x01,0x0D,0x68,0x80,0x03,0x1C,0xF8,0x7F};
const uint8_t spTIME[] PROGMEM = {0x0E,0xD8,0x5A,0x2D,0x00,0x37,0xA6,0x39,0xA0,0x9B,0xB0,0x95,0x17,0x9B,0x1E,0x21,0x2D,0x4F,0x51,0xF4,0x86,0x25,0x6F,0xB9,0xD5,0xA9,0xBB,0x9E,0xE0,0xD6,0x36,0xB7,0xBE,0xED,0x1E,0xD6,0xDC,0x5D,0x29,0xB7,0xAF,0xDE,0x6B,0xDD,0xCB,0xDE,0xB4,0xB1,0xAB,0xD6,0xC9,0x67,0x3C,0xDD,0x35,0x85,0x73,0x98,0xD8,0xFD,0x7F};
const uint8_t spAUTOMATIC[] PROGMEM = {0x6B,0xAC,0xA4,0xA7,0x82,0xFD,0xDD,0xF1,0x0E,0x67,0x68,0xB2,0xA2,0x83,0x72,0x1B,0xA0,0x52,0x65,0x03,0xFC,0x24,0x3A,0xEA,0xAD,0xCD,0xD5,0x4C,0xDB,0xA9,0xAB,0x76,0x4B,0x93,0x2D,0x67,0x28,0xA2,0xCC,0xC2,0xF3,0x8C,0x21,0x2B,0xD7,0x70,0xC9,0xD8,0x86,0x4A,0x8D,0xC6,0x35,0x49,0xE9,0x8B,0x54,0x29,0x76,0x37,0x63,0xC8,0xCE,0xDD,0x54,0x6A,0x9D,0xBA,0xC6,0xD2,0xD2,0x58,0x72,0xAB,0x5B,0xDE,0x72,0x35,0x35,0x5B,0x84,0x54,0x6D,0xD3,0xEE,0x90,0x11,0xEA,0x4E,0x5A,0x5B,0x53,0xAA,0xB3,0x2F,0xB9,0xD3,0x59,0xBB,0x6B,0xE5,0x94,0x35,0x7B,0x6F,0xE7,0x34,0xAD,0xD8,0xBA,0x17,0x81,0x22,0x94,0xBB,0x88,0x6C,0x00,0x03,0xB4,0x12,0x22,0x01,0x0E,0xFC,0x3F};
const uint8_t spWEIGHT[] PROGMEM = {0x62,0x13,0x7E,0x23,0x4C,0x22,0xEB,0x4D,0xAD,0x46,0x7F,0x5A,0xB0,0x95,0xB4,0x38,0xF3,0xA1,0x4E,0x6D,0xD6,0x94,0xCC,0x9A,0x3B,0x6D,0x39,0x7D,0xF3,0xC1,0x99,0xF2,0xE6,0xB4,0x23,0x0E,0x51,0xF8,0x9A,0xDB,0x8E,0x6E,0xE4,0x04,0xC9,0x7C,0xDC,0x17,0x75,0x8C,0x26,0xA8,0x56,0x8B,0x11,0x28,0x42,0xB9,0x8B,0xC8,0x06,0x00,0x00,0x01,0xBC,0xC0,0x66,0x80,0x1F,0x73,0x04,0xB0,0xDD,0x34,0x02,0x46,0xE9,0xF8,0x7F};
const uint8_t spSMOKE[] PROGMEM = {0x08,0xF8,0xBB,0x4D,0x02,0x0A,0x78,0x33,0xCC,0x03,0x1E,0x40,0x40,0x53,0x1A,0x22,0xC8,0x92,0x35,0x87,0x92,0xD4,0x74,0x95,0x99,0x55,0x7B,0x52,0xB7,0x5D,0xEE,0x72,0x57,0xAD,0xF7,0x6E,0xA2,0x84,0xFB,0xD6,0xD1,0x6D,0x4E,0x6E,0x84,0xA3,0x37,0x84,0x8B,0x50,0xEE,0x22,0xB2,0x01,0x80,0x01,0x75,0x14,0x7B,0x80,0x01,0x39,0x98,0xFC,0x3F};
const uint8_t spABORT[] PROGMEM = {0x63,0xC9,0xA6,0x2A,0x54,0xD7,0x9C,0xA5,0xF0,0xEC,0x0A,0xCA,0xBB,0x67,0xB6,0x1B,0xD9,0xA6,0xAA,0x59,0xE9,0x46,0x8E,0x20,0xC2,0x83,0x25,0x0B,0x39,0x1D,0x4D,0x4D,0x77,0x37,0x76,0x1A,0x55,0x54,0x53,0xA9,0x94,0x65,0x17,0xAB,0xC8,0xAC,0xDA,0x53,0xB9,0xEF,0x72,0x35,0x51,0x5E,0x58,0xAB,0xFE,0xD5,0x66,0xB5,0x12,0x23,0xFA,0xD7,0x94,0x63,0x53,0x95,0xF8,0x69,0x6B,0xEE,0x4E,0x51,0xE2,0x2F,0x6C,0xB9,0x13,0x57,0x59,0x7F,0x04,0x8A,0x50,0xEE,0x22,0xB2,0x01,0x1C,0xB0,0x9D,0xBA,0x03,0x7E,0x0F,0x53,0xC0,0x48,0x53,0x08,0x88,0xD2,0xEC,0xFF,0x01};
const uint8_t spCALL[] PROGMEM = {0x02,0x48,0xA5,0xD8,0x02,0x1A,0x18,0x71,0x16,0x15,0x95,0xA4,0x7A,0x65,0x95,0xD5,0x44,0x88,0xFB,0x5B,0xDC,0x62,0x95,0x49,0x4E,0xA7,0x49,0xB6,0x5D,0xED,0x76,0x76,0x73,0x9A,0x4B,0xD9,0x83,0xBD,0x2A,0xB4,0xCE,0xF5,0x0A,0x77,0x50,0xB9,0x25,0x92,0x25,0xDE,0xE1,0x49,0xC2,0x77,0x44,0x5D,0xFB,0xEF,0xFF,0x01};
const uint8_t spCYCLE[] PROGMEM = {0x08,0xF8,0xB3,0x5C,0x03,0x16,0xB0,0x80,0x06,0x56,0x55,0x64,0xB9,0xBB,0xB7,0x39,0x4D,0x71,0xA5,0x15,0xBA,0xF8,0x36,0xBB,0x19,0x75,0xCB,0x8A,0xED,0x35,0xB1,0xB7,0xAC,0x15,0xA1,0xDC,0x45,0x64,0x03,0x03,0xE2,0x10,0x2A,0x53,0x54,0xE3,0x69,0xDC,0x79,0xAD,0x1D,0x67,0x57,0xB0,0xB7,0x76,0x6C,0xAC,0xDD,0xC9,0xEC,0xDB,0xD5,0x70,0x4C,0x07,0x69,0xCD,0x8F,0x7B,0x13,0x9B,0x49,0xA1,0xBC,0xFE,0xFB,0x7F};
const uint8_t spDISPLAY[] PROGMEM = {0x04,0x88,0xD0,0x63,0x2C,0x53,0xB5,0xB1,0x52,0x9F,0x3B,0xDF,0x79,0x4F,0x65,0xF8,0xCE,0x5D,0x4D,0xB9,0x29,0xE0,0xCF,0x52,0x0B,0x78,0x40,0x03,0x08,0xC8,0xDC,0x15,0x40,0x02,0xA9,0x2D,0x4A,0x6A,0x45,0xEC,0xB5,0xB6,0xA0,0xCA,0x71,0x4C,0x73,0xEA,0xCA,0x3B,0xC2,0xA5,0xCB,0xAD,0x6E,0x75,0x9A,0xA6,0x93,0xAD,0x62,0xF3,0xED,0xEE,0xB4,0x96,0x1E,0x13,0x25,0x7D,0xF3,0xDE,0xFB,0xDE,0xCE,0xE6,0x15,0xA3,0x6A,0x55,0x7D,0xCA,0x3B,0x62,0x22,0x67,0x6C,0xCE,0xDF,0xFF,0x03};
const uint8_t spEQUAL[] PROGMEM = {0x6D,0x18,0x49,0x91,0xBC,0x17,0xEF,0x6E,0x15,0xA3,0x15,0xA2,0xE5,0x93,0x9D,0xB5,0x7C,0x6C,0x07,0xB6,0x7C,0x1C,0xF2,0x11,0x19,0xAC,0xB2,0x0E,0x02,0x45,0x28,0x77,0x11,0xD9,0x00,0x04,0xF0,0xA3,0x88,0x01,0xBE,0x65,0xB4,0x36,0xC8,0x8D,0x08,0xF4,0x33,0xBB,0x39,0xB4,0xB5,0xE2,0xAE,0x0E,0xF2,0xDB,0xD7,0x7A,0xA4,0x33,0xD3,0xEA,0x0E,0xF0,0x9B,0xCE,0xC8,0xAE,0x92,0x24,0x77,0xB8,0x33,0xF8,0x68,0xE6,0xD6,0xF1,0xFE,0x7F};
const uint8_t spFAST[] PROGMEM = {0x08,0x68,0xD6,0x55,0x02,0x0A,0x18,0x22,0x5D,0x02,0x1A,0x58,0x45,0x75,0xA3,0x5E,0xFA,0xE6,0x96,0xB7,0x39,0x6D,0xD3,0xA3,0xD6,0xBA,0xFA,0xF6,0x6B,0xAE,0xAE,0xA4,0xCA,0xEE,0xAC,0xAD,0x99,0xD1,0x28,0x5B,0x5C,0x8E,0xE2,0x4A,0x2B,0xFD,0x4E,0xBE,0xE2,0x85,0x80,0x25,0x5B,0x39,0xC0,0x80,0xDF,0x32,0x24,0xA0,0x01,0x0B,0x58,0x80,0x02,0xC0,0x80,0x3B,0x4C,0x14,0xF0,0xBC,0x38,0x03,0x96,0xDD,0xF9,0x7F};
const uint8_t spABOUT[] PROGMEM = {0x63,0xCF,0xA6,0x2A,0x54,0xD7,0xDC,0x6D,0xAD,0x85,0x67,0x57,0x50,0x5E,0x76,0x1A,0xD9,0xA6,0xAA,0x59,0xF9,0x26,0xB6,0x20,0xC2,0x83,0x25,0x0B,0x5B,0x1C,0x4D,0x4D,0x77,0x37,0xA1,0x6F,0xD4,0x45,0xCD,0xB2,0xAC,0xBE,0x98,0xCD,0x34,0xDD,0x72,0xDA,0xAA,0xDA,0x2B,0x79,0xCD,0x6D,0x6F,0x77,0xC7,0xBD,0x94,0x23,0xA4,0xCE,0x22,0xDB,0x15,0x8F,0xF0,0x45,0xEB,0x55,0xC2,0x79,0xC4,0x2F,0x42,0xB9,0x8B,0xC8,0x06,0x00,0x03,0x4C,0xA7,0xEE,0x80,0xD7,0x53,0x09,0x50,0x83,0xCB,0xFF,0x03};
const uint8_t spGO[] PROGMEM = {0x06,0x08,0xDA,0x75,0xB5,0x8D,0x87,0x4B,0x4B,0xBA,0x5B,0xDD,0xE2,0xE4,0x49,0x4E,0xA6,0x73,0xBE,0x9B,0xEF,0x62,0x37,0xBB,0x9B,0x4B,0xDB,0x82,0x1A,0x5F,0xC1,0x7C,0x79,0xF7,0xA7,0xBF,0xFE,0x1F};
const uint8_t spINCH[] PROGMEM = {0x23,0x1B,0xD6,0x48,0x2A,0x67,0x9F,0x76,0xC4,0x20,0x89,0xBC,0x7D,0xEB,0x53,0x8F,0x90,0xEC,0x12,0xB7,0x77,0xBB,0xC6,0xEE,0x55,0x92,0x6B,0x72,0x59,0xAA,0x82,0x28,0x4F,0x35,0xE9,0x68,0x0A,0xB9,0xD3,0x6D,0x93,0xA6,0x28,0xC8,0xB1,0xB0,0x85,0x40,0x11,0xCA,0x5D,0x44,0x36,0x00,0x02,0xD6,0xDC,0xD2,0x80,0x05,0x32,0xE0,0x01,0x0F,0x10,0xA0,0x26,0xA1,0xFF,0x07};
const uint8_t spLOW[] PROGMEM = {0x65,0xDF,0x98,0xA3,0x4A,0xB4,0xE5,0x65,0x4E,0xAB,0x9F,0xD4,0xA2,0x92,0xBC,0x9E,0xB6,0xF2,0xC8,0x71,0xEA,0x7B,0x9B,0xD5,0x24,0x5E,0x3D,0xCC,0x79,0x77,0x3B,0xFB,0xB9,0xF4,0xBD,0xEE,0xF5,0x0C,0x97,0x37,0x5D,0x0B,0x92,0xC7,0xDF,0xFE,0xFD,0x7F};
const uint8_t spMOTOR[] PROGMEM = {0x66,0xAA,0x8C,0x69,0x53,0x92,0xC4,0x2D,0x2F,0x6B,0x2A,0x74,0xDA,0x9D,0xB2,0xDD,0xF6,0x36,0xAB,0xCE,0x78,0xDA,0x9D,0xB2,0xD5,0x9A,0x01,0xDB,0x77,0x45,0xA0,0x75,0xC5,0xB8,0x71,0x59,0xDA,0x31,0xE5,0x6A,0x22,0x63,0xDE,0xDA,0x9A,0xBB,0xA3,0x75,0x68,0xAF,0x7B,0x3E,0xC3,0x9D,0x97,0x60,0x87,0xE6,0x8B,0x4F,0x78,0x4B,0x76,0xB2,0x09,0xAF,0xFE,0xFD,0x7F};
const uint8_t spOPEN[] PROGMEM = {0x61,0xCC,0xB8,0x7B,0x8C,0xB2,0xF5,0x61,0x8F,0xAB,0xA9,0x30,0xA7,0x83,0xBC,0xCD,0xBA,0x95,0x19,0x57,0x97,0xB1,0x6B,0xD2,0x58,0x12,0x31,0x11,0x89,0x01,0x01,0x2E,0x9A,0x48,0x60,0x94,0xC5,0x86,0xBB,0xC9,0xA6,0x35,0x36,0x95,0x1A,0xA6,0x7B,0xF6,0x3E,0x8E,0x26,0x42,0x3D,0x78,0xF1,0x3C,0xCB,0xD5,0x0D,0x71,0x78,0x24,0xAB,0x77,0xBA,0x47,0x12,0x73,0xB1,0xB8,0xF9,0xFE,0x7F};
const uint8_t spPERCENT[] PROGMEM = {0x02,0xC8,0xD9,0x5C,0x03,0x2D,0x8A,0xB1,0x30,0x46,0x52,0xAF,0xBA,0x86,0x26,0x1A,0xF6,0x77,0x9B,0xD3,0xD5,0x18,0x68,0x69,0x59,0x63,0xEF,0x80,0x5F,0x5A,0x2D,0x60,0x01,0x0B,0x68,0xC0,0x03,0xAB,0x6E,0xDE,0x25,0x2D,0x17,0xDF,0xFA,0x36,0xBB,0x1D,0x53,0xB1,0x6E,0x23,0x5D,0xA7,0x5D,0x23,0x92,0xB9,0xA7,0x62,0x7F,0x20,0x50,0x84,0x72,0x17,0x91,0x0D,0x00,0xA0,0x80,0xA5,0x33,0x0C,0xF0,0xB3,0x27,0x02,0x5A,0x4A,0xFD,0x7F};
const uint8_t spPROBE[] PROGMEM = {0x02,0xC8,0x29,0x5D,0x03,0x2E,0x0A,0x83,0xCB,0x5D,0x33,0xF7,0xFC,0x94,0xD1,0x96,0x57,0x71,0xF2,0x53,0x66,0xDE,0xE9,0x8D,0xDE,0x76,0x3D,0xDB,0x3E,0x95,0xDD,0xBB,0x8E,0x54,0xEA,0x13,0x0F,0x73,0x19,0x95,0x91,0x46,0x9E,0xD8,0x23,0x68,0x47,0x47,0x24,0xE1,0x1F,0xFF,0xC3,0xEF,0x4D,0x6A,0x99,0x25,0x49,0x67,0xF4,0x96,0x69,0xBA,0x24,0x5E,0xEE,0xAA,0x91,0x2B,0x59,0xD7,0xFE,0x3F};
const uint8_t spREADY[] PROGMEM = {0x6A,0xB4,0xD9,0x25,0x4A,0xE5,0xDB,0xD9,0x8D,0xB1,0xB2,0x45,0x9A,0xF6,0xD8,0x9F,0xAE,0x26,0xD7,0x30,0xED,0x72,0xDA,0x9E,0xCD,0x9C,0x6D,0xC9,0x6D,0x76,0xED,0xFA,0xE1,0x93,0x8D,0xAD,0x51,0x1F,0xC7,0xD8,0x13,0x8B,0x5A,0x3F,0x99,0x4B,0x39,0x7A,0x13,0xE2,0xE8,0x3B,0xF5,0xCA,0x77,0x7E,0xC2,0xDB,0x2B,0x8A,0xC7,0xD6,0xFA,0x7F};
const uint8_t spSET[] PROGMEM = {0x08,0xF8,0x35,0x95,0x03,0x02,0xF8,0xC5,0x58,0x03,0x16,0xB0,0xC0,0x2A,0xA6,0x08,0x13,0xD7,0xCE,0xA7,0xEC,0xAE,0xD5,0xCC,0xD6,0xDC,0xEA,0x54,0x35,0xA6,0xA4,0xE5,0x9A,0x3D,0xCC,0x25,0x2E,0x08,0x14,0xA1,0xDC,0x45,0x64,0x03,0x00,0x30,0x60,0x88,0x30,0x05,0xFC,0x1C,0x25,0x80,0x65,0xB6,0x10,0x50,0xA2,0xD0,0xFF,0x03};
const uint8_t spSPEED[] PROGMEM = {0x04,0xF8,0xBD,0x5C,0x02,0x1A,0xD0,0x80,0x04,0x30,0x40,0x00,0x6E,0x55,0x59,0xCB,0x75,0x7A,0x7A,0xA5,0x59,0xC5,0xC8,0x41,0x64,0xBA,0x66,0xE5,0x33,0x95,0x82,0xEB,0xD6,0x9B,0xEE,0x6C,0xE5,0x33,0x8D,0x82,0xEB,0xD6,0x5D,0xAD,0x7E,0xC5,0x22,0x48,0xDF,0xB2,0xC7,0xBD,0xCC,0x6D,0x1E,0xF5,0x60,0xA7,0x65,0x1E,0x95,0x91,0x88,0x9F,0xF4,0x2A,0xD7,0xD0,0x4D,0x64,0xBE,0xE5,0xFF,0x01};
const uint8_t spUNDER[] PROGMEM = {0xA7,0x6B,0xA4,0x3B,0x4A,0xB3,0x9C,0xAE,0xF1,0xF6,0x48,0xE9,0x7C,0xDB,0x55,0x56,0x13,0x56,0x62,0x8D,0x5B,0x56,0x15,0xFA,0x68,0x68,0xA9,0x79,0x28,0xA2,0xE0,0x31,0x4D,0x8D,0xA6,0x36,0x52,0x27,0x39,0x13,0x85,0x7E,0x7A,0x35,0x56,0x4D,0xB2,0xD6,0xE6,0x4D,0x55,0xAD,0xD5,0x58,0x6B,0x0E,0xB2,0x92,0x3C,0x73,0x2F,0x47,0xE9,0x4A,0x99,0xBC,0x25,0x9F,0xE1,0xCA,0x43,0xB0,0x53,0x7A,0x85,0xBB,0x1C,0xE1,0x56,0xCB,0xEC,0xEF,0xFF,0x07};
const uint8_t spOPERATOR[] PROGMEM = {0xB0,0x9A,0xAC,0xB6,0xC2,0xAD,0xCD,0xA9,0x3B,0x9D,0xCE,0x94,0x2C,0xB7,0x5A,0x65,0xB6,0x9B,0x61,0xBA,0x66,0x15,0xC5,0x65,0x8C,0xF3,0x62,0x94,0x89,0x50,0xEE,0x22,0xB2,0x01,0x5A,0x95,0x7C,0xB9,0xAB,0x25,0x29,0x55,0x5C,0xC2,0xD3,0x94,0xB5,0x37,0xA9,0x0B,0x9B,0x2C,0x4B,0xB9,0xE6,0xA1,0x8E,0x63,0xCE,0x83,0x53,0xD2,0xFC,0xAE,0xA5,0x16,0x97,0x70,0xCD,0x3B,0xD6,0x11,0x4F,0x30,0xB4,0x4F,0xDB,0x46,0x3C,0x62,0xE3,0x3D,0xF9,0x00,0x07,0xCC,0xD4,0x29,0x81,0xB6,0xD5,0x3A,0x28,0x2D,0x7E,0xDB,0x51,0xFD,0x09,0x2C,0xFB,0xCF,0x77,0x7A,0x4A,0x2C,0x94,0x93,0xBC,0xE1,0xA9,0xE1,0x04,0x46,0xFD,0xC5,0x37,0xFC,0x65,0x19,0x56,0x72,0x96,0xFF,0x07};
const uint8_t spAMPS[] PROGMEM = {0x69,0xEA,0xA5,0x45,0xD2,0x57,0xEF,0xF1,0x0E,0x77,0xB8,0xDD,0x6D,0x4F,0x53,0x43,0x49,0x79,0xCC,0xDE,0x5D,0x19,0x9B,0x08,0x2C,0x31,0xA7,0x6E,0x49,0x3C,0x39,0xC5,0xBC,0xEA,0x07,0x81,0x22,0x94,0xBB,0x88,0x6C,0x00,0x06,0x44,0x16,0xC6,0x80,0x5F,0xD3,0x39,0xC0,0x01,0x0E,0x50,0x00,0x03,0x18,0xF8,0x7F};
const uint8_t spMEGA[] PROGMEM = {0x66,0x31,0x3C,0x7C,0x52,0xE3,0xF8,0xC5,0xCF,0x6B,0x2A,0x5E,0x3C,0x34,0x96,0x9C,0xBE,0xC7,0x10,0x77,0x7F,0x7D,0x9B,0x51,0xF5,0xA1,0x6C,0xE2,0x8F,0x53,0xDD,0x1A,0x52,0x68,0x4D,0x0E,0x43,0xF5,0x48,0xE3,0x55,0xBA,0xCD,0x7D,0xA4,0x28,0x6B,0x93,0x35,0xB7,0xC2,0x12,0x9A,0x4F,0xCE,0x5A,0x5D,0x68,0xBA,0x6E,0xDE,0xDB,0x3C,0xC7,0x59,0xA2,0x66,0x6A,0xCC,0xE9,0x6F,0x7D,0xFF,0x1F};
const uint8_t spPICO[] PROGMEM = {0x08,0xC8,0x8E,0x48,0x03,0x2B,0xEA,0xC1,0x48,0xD2,0x57,0x9F,0x6C,0xE6,0x25,0x08,0x5B,0x73,0xB3,0x54,0x8C,0xC1,0xE0,0x56,0xB3,0x75,0x15,0x80,0xE6,0x47,0x3D,0x30,0x86,0xE2,0x82,0x35,0xB4,0xF7,0x1A,0xB2,0x71,0xF3,0xD6,0xBC,0x6B,0xA9,0xA2,0x2C,0x8A,0xBD,0x8F,0x23,0x89,0xF5,0x34,0xC9,0xDF,0xCF,0x76,0x45,0x57,0x51,0x22,0x79,0xD3,0xED,0xFD,0x6A,0xA8,0x75,0x8D,0x8F,0x79,0x6C,0xCD,0x74,0xB6,0xDD,0xEA,0xB5,0x65,0xD4,0xCD,0xFA,0xFC,0x3F};
const uint8_t spFIRE[] PROGMEM = {0x04,0x18,0xCE,0x4D,0x02,0x1A,0xD0,0x80,0x04,0x46,0x91,0x55,0x57,0x07,0x6D,0xD9,0xCD,0xAE,0x4F,0x55,0x5D,0x59,0x87,0xAE,0xB9,0xD5,0x6D,0x5B,0xDB,0x7D,0x93,0xB6,0xED,0xEE,0xE3,0x5A,0x6B,0x6A,0xF4,0x91,0xD5,0x73,0x6B,0x67,0xF5,0x47,0xBC,0xD4,0xA7,0x9C,0xA5,0x34,0xE4,0xD0,0xA6,0xF0,0xE4,0xAA,0xB8,0x2D,0xAB,0xC3,0x9B,0x62,0xC2,0xAC,0x74,0xF6,0x9F,0xFB,0x72,0x0B,0xEC,0x92,0xCD,0xEE,0xCF,0x43,0x69,0x4C,0x5B,0xFF,0x3F};
const uint8_t spPOWER[] PROGMEM = {0x0C,0xF0,0xDC,0x4C,0x03,0x2B,0xCD,0x36,0xAB,0x85,0x1B,0x9F,0xBC,0xB1,0xAE,0x6A,0xEA,0x7A,0xB3,0x95,0x15,0xD5,0x39,0x85,0x5D,0x46,0x96,0x7C,0x57,0x3B,0xB6,0x19,0x79,0x30,0x93,0x55,0xA4,0xBB,0xD4,0x2E,0xAD,0x79,0xB1,0xDE,0x3E,0x8D,0x29,0x85,0x61,0x1F,0xF6,0x3B,0xB7,0x7E,0x94,0x33,0x97,0x46,0x5B,0xCE,0x9D,0x9F,0xF0,0x16,0x3F,0x48,0xE7,0x7E,0xC3,0x5B,0xE3,0xA2,0xAC,0xEB,0xF6,0xDF,0xFF,0x03};
const uint8_t spCOMPLETE[] PROGMEM = {0x0E,0x68,0xA1,0x43,0x03,0xA7,0x2E,0xB2,0x22,0x0B,0xBB,0xDC,0x76,0x75,0x55,0x99,0xB7,0x53,0xB4,0xD1,0x77,0xA6,0x1C,0xA5,0xD6,0x7A,0x9F,0xFA,0x44,0x39,0x5A,0xDC,0x1E,0x9D,0x0C,0x50,0x94,0xB8,0x01,0x46,0x14,0x2F,0x69,0x97,0x9C,0x69,0xA6,0xE4,0x14,0x8D,0x85,0xBB,0x73,0xB3,0x93,0x75,0x6D,0xA2,0x29,0x6F,0x56,0xD6,0xB3,0xB2,0xA8,0x3F,0x59,0xF9,0x18,0x4E,0xA4,0xBE,0x66,0xB6,0x69,0x9F,0xB9,0x08,0xD2,0xDE,0xC4,0x1D,0x81,0x22,0x94,0xBB,0x88,0x6C,0x00,0x00,0x05,0x1C,0xD9,0x6E,0x80,0x65,0x7E,0x18,0xD0,0xEB,0x3A,0x02,0x6A,0x09,0xFC,0x7F};
const uint8_t spREPAIR[] PROGMEM = {0x69,0x8E,0x8D,0xCD,0x22,0x95,0xB7,0xA9,0x74,0x09,0xB2,0x54,0x7F,0xC6,0x16,0x83,0xCD,0xB5,0xEF,0x1A,0x7A,0x18,0x22,0x97,0xBE,0x75,0x62,0x93,0x08,0xE5,0x2E,0x22,0x1B,0x00,0x04,0xE0,0x93,0x59,0xCB,0x92,0x53,0xCB,0x8C,0x9A,0xAB,0x68,0xD1,0xC5,0xC2,0x5E,0x9F,0xB2,0xA5,0x22,0x0F,0xD9,0x72,0xAB,0x5B,0xDF,0xE6,0x4E,0x63,0xA9,0x25,0xB0,0x4A,0x3B,0xCF,0xAD,0x1F,0xE9,0xAE,0x7A,0x85,0x4E,0xF2,0xE5,0x27,0xBF,0xF9,0xCD,0x5F,0xFA,0x4A,0x1C,0x92,0xE3,0xDC,0xE9,0x2B,0x35,0xA9,0x5A,0x72,0xFF,0x3F};
const uint8_t spTEMPERATURE[] PROGMEM = {0x0E,0xF8,0x2E,0x2C,0x00,0xCB,0x8F,0x8F,0xA8,0x59,0x15,0xF7,0x58,0x79,0xD2,0x9A,0x5D,0x22,0xB5,0xF5,0x4D,0x47,0x96,0xAB,0x5A,0x87,0x69,0x0E,0x85,0xF7,0x46,0x1D,0xA1,0x0C,0x10,0xE0,0x32,0xBB,0x04,0x56,0x5E,0x62,0x91,0xA6,0x79,0xEF,0x7D,0xEC,0xC1,0x00,0x63,0x6C,0x46,0xC0,0x03,0x16,0x18,0x7D,0x8F,0x29,0x68,0x96,0xB5,0x4D,0x25,0x27,0x71,0x85,0xF7,0xBE,0xF6,0xBD,0x9F,0xF5,0x09,0x77,0x59,0xC2,0xDE,0x9A,0x27,0xBE,0xFE,0xFD,0x7F};
const uint8_t spSTOP[] PROGMEM = {0x0C,0xF8,0xA5,0x4C,0x02,0x1A,0xD0,0x80,0x04,0x38,0x00,0x1A,0x58,0x59,0x95,0x13,0x51,0xDC,0xE7,0x16,0xB7,0x3A,0x75,0x95,0xE3,0x1D,0xB4,0xF9,0x8E,0x77,0xDD,0x7B,0x7F,0xD8,0x2E,0x42,0xB9,0x8B,0xC8,0x06,0x60,0x80,0x0B,0x16,0x18,0xF8,0x7F};
const uint8_t spMACHINE[] PROGMEM = {0xC2,0x56,0x3C,0x7D,0xDC,0x12,0xDB,0x3E,0x8C,0x89,0xBA,0x4C,0x4A,0x96,0xD3,0x75,0x95,0x12,0x6E,0xBD,0x6F,0xB7,0xBA,0x16,0x5A,0x58,0x3D,0xB3,0x03,0xA6,0x14,0x76,0xC0,0xCC,0x37,0x11,0xC8,0x40,0x04,0x22,0xB0,0x92,0xD9,0x9A,0xC1,0x7D,0xF5,0xCD,0x6F,0x3E,0x8A,0x39,0x14,0xA5,0x72,0xD4,0x28,0x67,0x56,0xD4,0x89,0xD2,0xB3,0xE9,0x63,0x5D,0xD2,0xDA,0x03,0x49,0xA9,0xDB,0xCD,0x47,0x3C,0xE3,0xEB,0xBF,0xF4,0x75,0x57,0xEC,0xEE,0x9B,0xF2,0x9B,0xBE,0x56,0x34,0xCC,0xA2,0xF2,0xFF,0x03};
const uint8_t spON[] PROGMEM = {0x65,0x4A,0xEA,0x3A,0x5C,0xB2,0xCE,0x6E,0x57,0xA7,0x48,0xE6,0xD2,0x5D,0xBB,0xEC,0x62,0x17,0xBB,0xDE,0x7D,0x9F,0xDA,0x5C,0x5C,0x7A,0xAA,0xB5,0x6E,0xCB,0xD0,0x0E,0xAD,0x6E,0xAF,0xEE,0xF9,0x88,0x67,0xBC,0xDC,0x3D,0xAC,0x60,0xB8,0x45,0xF3,0xB7,0xBF,0xC3,0xDD,0xA2,0xBB,0xAB,0xCD,0x89,0x8F,0x7F,0xFE,0x1F};
const uint8_t spCONTROL[] PROGMEM = {0x06,0x68,0xA5,0xCD,0x02,0x2B,0xA9,0x36,0xD5,0x43,0x5A,0x9F,0xA6,0xA9,0x36,0x4F,0xEE,0x73,0xDA,0xC1,0xDA,0x35,0x79,0x73,0x6B,0x9B,0x62,0xEA,0xB0,0x78,0xB3,0x4B,0x7D,0x91,0x18,0xED,0xE6,0x16,0x81,0x22,0x94,0xBB,0x88,0x6C,0x10,0x40,0x0B,0xE1,0x1E,0x88,0xC0,0x48,0x53,0xE2,0x0A,0x17,0x67,0x3B,0x3B,0x59,0xB2,0x11,0x95,0xA2,0x7C,0x64,0x91,0x4F,0x47,0x92,0xF7,0x99,0xAF,0xA2,0xE0,0xEE,0x76,0x56,0xBF,0x9B,0x39,0xB4,0x29,0xB1,0x9C,0x76,0xF4,0x56,0xD7,0xBA,0xE5,0x3B,0x3F,0xF1,0x29,0x77,0xE6,0x9D,0x63,0x9C,0xE7,0xFF,0x01};
const uint8_t spELECTRICIAN[] PROGMEM = {0x6B,0x9D,0xA6,0x88,0xD3,0x36,0xDF,0xF1,0x8C,0x5B,0x84,0x93,0x79,0xBB,0x35,0x5C,0x26,0xA9,0xEC,0x6B,0xCF,0x70,0xB8,0x87,0xBA,0x68,0x3F,0x5D,0x4B,0xA1,0x29,0xB6,0xF9,0xB6,0xAD,0x69,0xB1,0x48,0x5B,0x1B,0x23,0x50,0x84,0x72,0x17,0x91,0x0D,0x00,0x06,0x38,0xAE,0xD2,0x03,0xA3,0xAC,0x59,0x4D,0xDD,0x9D,0xAE,0xA2,0x16,0x63,0x37,0xEB,0xBA,0x8B,0x51,0x36,0x63,0x1A,0x9E,0x6B,0x7A,0x65,0x80,0x55,0xB7,0x3D,0x10,0x81,0x0C,0x58,0x60,0x75,0xCD,0x98,0x84,0xF9,0xA6,0xBD,0xF4,0xAD,0x5C,0x43,0x19,0x46,0x58,0xB4,0x7C,0xE7,0x27,0x7D,0x3D,0x0A,0xBB,0x87,0xDD,0xF8,0xC7,0xFF,0xFF,0x01};
const uint8_t spAT[] PROGMEM = {0xAD,0xA8,0xC9,0xB5,0xBC,0xA6,0xDC,0xFE,0x36,0xB7,0xB9,0xF5,0x6D,0xC7,0x58,0x9B,0x69,0xF9,0x4C,0x99,0x73,0xDD,0xC8,0x24,0x42,0xB9,0x8B,0xC8,0x06,0x00,0x50,0xC0,0x52,0x2E,0x0E,0xB8,0x66,0x8A,0x01,0xAD,0x95,0x20,0x20,0x3A,0xF2,0xFF,0x07};
const uint8_t spRED[] PROGMEM = {0x6A,0xB5,0xD9,0x25,0x4A,0xE5,0xDB,0xC5,0x4F,0x6D,0x88,0x95,0x2D,0xD2,0xB4,0x8F,0x2E,0x37,0x0E,0x33,0xCF,0x7E,0xAA,0x9A,0x5C,0xC3,0xB4,0xCB,0xA9,0x86,0x69,0x76,0xD3,0x37,0xB7,0xBE,0xCD,0xED,0xEF,0xB4,0xB7,0xB0,0x35,0x69,0x94,0x22,0x6D,0x10,0x28,0x42,0xB9,0x8B,0xC8,0x06,0x00,0x50,0xCF,0x0E,0xEE,0x62,0xEA,0xA6,0xBC,0xC3,0x14,0xBB,0x4A,0x9F,0xFA,0xA5,0xAF,0x25,0x13,0x17,0xDF,0x9C,0xBF,0xFF,0x07};
const uint8_t spALL[] PROGMEM = {0x65,0x0D,0xFA,0x3B,0x84,0xFB,0x8D,0x2E,0xB1,0x9D,0x34,0xCA,0xBA,0xAB,0x5D,0xEC,0x62,0x15,0x89,0x5F,0xA7,0x49,0xB6,0x5D,0xEF,0x6E,0x0E,0x73,0x99,0xEB,0x3C,0xCA,0x11,0x65,0xCE,0x18,0xB9,0x89,0x67,0xBC,0xDC,0x15,0xF8,0xE5,0xA0,0xE6,0x71,0x77,0x94,0x51,0x8F,0x96,0xE6,0xFF,0x01};
const uint8_t spCANCEL[] PROGMEM = {0x01,0x98,0x29,0xC4,0x00,0xDD,0x29,0x9C,0xAC,0x25,0xD7,0xD2,0x9C,0x7C,0x8B,0x5B,0xAE,0xBC,0x26,0xB3,0x94,0x89,0x52,0xF2,0xE6,0x29,0x42,0x52,0x53,0x28,0xAA,0xC1,0xB6,0xB0,0xC4,0x0C,0xF8,0xDE,0xC2,0x02,0x1E,0xF0,0x80,0x05,0x46,0x5C,0x78,0x45,0x25,0xE5,0x19,0x53,0x45,0x93,0xE3,0xA2,0x77,0xAE,0x75,0x4B,0x67,0x92,0xD5,0x6D,0x98,0x25,0x3F,0xF9,0xFD,0x7F};
const uint8_t spPHASE[] PROGMEM = {0x22,0x5E,0x2E,0xD5,0xC4,0x64,0xA5,0xF6,0x9A,0x52,0x26,0xF1,0xB6,0xDA,0xEA,0x54,0x2C,0x6B,0xCE,0x69,0x7A,0x0A,0x51,0x89,0xB7,0xA7,0x19,0xA9,0x98,0xCD,0xDE,0xDC,0xE6,0x36,0xAB,0x9B,0xA1,0x11,0x23,0x3E,0xCF,0xB1,0xAF,0x7D,0xAB,0x7B,0x3C,0xFC,0x19,0x9E,0xA6,0x55,0x9C,0x6D,0xB7,0x7F,0xEC,0xCB,0x80,0xEF,0xCB,0x39,0x40,0x81,0xFF,0x07};
const uint8_t spNOR[] PROGMEM = {0xE9,0x38,0x5C,0x84,0x33,0xBD,0x8E,0xB6,0x9A,0x70,0x09,0x6B,0xBB,0x8B,0x93,0x66,0xDE,0x91,0xC9,0xFE,0x6E,0xBA,0xB2,0x24,0xAA,0x26,0x51,0xDD,0xCC,0x47,0x1D,0x7C,0x75,0x3A,0xE5,0x99,0xC3,0x5C,0xCA,0x1E,0x52,0x6A,0xA7,0xE4,0xCF,0x7B,0xB9,0x53,0x4E,0x8E,0x31,0x6F,0xFD,0x4C,0x77,0x1A,0xC2,0x93,0x96,0x25,0xDD,0xA9,0x04,0x4E,0x87,0xDB,0xF0,0xE4,0x2D,0xB4,0x6E,0x59,0xE2,0xE3,0xDF,0xFF,0x07};
const uint8_t spEXIT[] PROGMEM = {0x6B,0x68,0xC1,0x24,0xAD,0xEE,0xAC,0xA6,0xE7,0x66,0x57,0x7F,0x73,0x9B,0x5B,0xB6,0xA2,0x1F,0x56,0xC5,0x69,0x6A,0xDA,0x96,0x94,0x02,0xB2,0x89,0x02,0x9A,0x1C,0x35,0xC0,0xCF,0x99,0x16,0xB0,0x80,0x04,0xDA,0x5C,0x83,0x4A,0xF0,0xDC,0x5E,0x5B,0x33,0x49,0xA1,0xFE,0xB9,0x9F,0xE1,0x6B,0x41,0x39,0xD8,0x1E,0x23,0x50,0x84,0x72,0x17,0x91,0x0D,0x00,0x02,0x38,0xCC,0xDC,0x02,0x04,0x18,0xF6,0xF3,0xFF,0x01};
const uint8_t spFLOW[] PROGMEM = {0x04,0xE8,0x3E,0x83,0x02,0x1C,0xE0,0x80,0x04,0x3C,0x10,0xB2,0x24,0x75,0xD9,0xAC,0x4D,0xCD,0x5A,0x9D,0x85,0xAC,0x93,0x79,0x39,0x75,0xA3,0xDE,0x15,0x98,0xED,0x56,0xB7,0x5A,0x55,0xE2,0xD3,0xE9,0xE4,0x6F,0xD6,0xB3,0x9B,0x43,0x5F,0xEB,0x91,0x4F,0x77,0x5B,0xBB,0x15,0xC2,0x7E,0xFC,0x63,0x5E,0x1B,0xD7,0x0B,0xA5,0xB7,0x7E,0xFF,0x1F};
const uint8_t spGAUGE[] PROGMEM = {0x0E,0x18,0xD5,0xB0,0xB5,0x2B,0x24,0x09,0x7B,0x92,0x55,0xF7,0x4C,0xA2,0xD1,0x8D,0x6F,0x7D,0x9A,0x91,0x83,0x34,0x72,0xCE,0x6D,0x6E,0x73,0xDB,0xD5,0xCD,0x50,0x40,0x9D,0xAB,0xF7,0xB8,0xE7,0xBD,0xB5,0x7D,0xA5,0x46,0x8C,0x58,0x5D,0x0F,0x76,0x15,0x05,0xBE,0x96,0x8D,0xD8,0x59,0x0D,0xE8,0x58,0xD5,0xA2,0x97,0x7A,0xC6,0x72,0x17,0x31,0x5B,0xB2,0x65,0xC0,0x9A,0xCE,0x12,0xB0,0x80,0x02,0xE6,0x50,0xF9,0x7F};
const uint8_t spGREEN[] PROGMEM = {0xE1,0x6A,0xEA,0x2A,0x4A,0xE3,0xA6,0xA1,0xB8,0x49,0x32,0x51,0x9A,0xFA,0xE8,0xCC,0xAC,0x2C,0x59,0xED,0x5A,0x5B,0x3A,0x05,0x27,0x77,0x9D,0xF5,0x29,0xDA,0x70,0x91,0x90,0xB6,0xA7,0x18,0x35,0x90,0xD3,0x17,0xED,0x7C,0xE5,0x33,0x06,0xE2,0x54,0xA5,0x5D,0xCC,0xAA,0xF5,0xB3,0x07,0x50,0xD6,0xA8,0x36,0x8E,0xA0,0x68,0x6B,0x61,0xFA,0x52,0xB7,0xB2,0x8F,0x44,0x54,0x15,0x41,0xD2,0x31,0x12,0x86,0xB8,0xBB,0xCE,0x67,0xBA,0xAA,0x66,0x4B,0xF1,0xB8,0xE9,0xEA,0x91,0x43,0xCC,0x5C,0xC7,0x33,0x5E,0xE5,0x6A,0xD6,0x25,0xDC,0x67,0xA5,0xA7,0x55,0x0D,0xD5,0x98,0x9C,0xDF,0xFF,0x07};
const uint8_t spINSPECTOR[] PROGMEM = {0x29,0xEB,0x5E,0xD9,0x32,0x27,0x9D,0x6E,0xFA,0x66,0x17,0x59,0x7D,0xDB,0xDB,0xB4,0xB6,0x7B,0xD0,0xCC,0x70,0xD2,0xDB,0xD6,0x0D,0xC7,0x38,0xAC,0x4D,0xD2,0xF0,0x0D,0xB3,0xA9,0xBB,0x73,0xC0,0x4F,0xE9,0x11,0xF0,0x80,0x02,0x86,0x52,0x01,0x03,0x44,0xEA,0x7A,0xA2,0x1A,0x43,0xD3,0x6C,0xF3,0x4D,0x6F,0xDA,0xB2,0x56,0x0C,0x82,0xAD,0x31,0x29,0x44,0x28,0x77,0x11,0xD9,0x00,0xE0,0x80,0xED,0x3C,0x46,0x5F,0xEB,0xA0,0xB4,0xF8,0x2D,0x53,0xF5,0x27,0xB0,0xEC,0x3F,0x6F,0x69,0x2F,0xB1,0x50,0x4E,0xF2,0x86,0xB3,0x86,0x13,0x18,0xF5,0x17,0xDF,0xF0,0x96,0x65,0x58,0xC9,0x59,0xFC,0xF7,0xFF};
const uint8_t spMANUAL[] PROGMEM = {0x6E,0x8A,0x42,0x6C,0xD5,0x9A,0xA4,0xB1,0x72,0xA5,0x2A,0x49,0x5B,0x87,0xD3,0x75,0x5B,0x1A,0x2E,0xAB,0x6F,0x7D,0xAB,0x53,0x76,0xDF,0x12,0xE6,0xAF,0x6F,0x71,0x8A,0x1E,0x43,0x52,0x72,0xF1,0x2A,0x7A,0x24,0x4D,0x4E,0xD7,0xA5,0x6A,0x06,0x32,0x2D,0x34,0x8F,0x7A,0x24,0x12,0x97,0x4E,0xB8,0xFA,0xE1,0x1D,0xD5,0xB3,0xE1,0x1A,0x7A,0x0D,0x12,0xB5,0xD5,0x6B,0xAC,0x51,0x24,0xD4,0x56,0x97,0x25,0x5A,0xB3,0x32,0x59,0x93,0xB6,0xA8,0x27,0x3C,0x31,0x4F,0xDE,0xEB,0x5E,0xCF,0x72,0x26,0x3E,0xD5,0xC6,0xF9,0xCA,0x55,0x71,0x77,0x39,0x7B,0x2B,0xD7,0x40,0xD1,0x1D,0xAC,0xBD,0xDC,0x05,0x57,0x77,0x90,0xB7,0xFC,0xFC,0x3F};
const uint8_t spMOVE[] PROGMEM = {0x6A,0xD7,0xC2,0xF2,0xD2,0xEC,0xB8,0x39,0x08,0xF6,0x4D,0x4D,0x1A,0xC6,0x24,0x31,0xB2,0xCC,0x69,0x1E,0x56,0x9D,0x85,0x7B,0x15,0xA4,0x3B,0x55,0x23,0x9E,0x3E,0xE0,0x6D,0xE7,0x23,0xAF,0x20,0xC6,0x0A,0xBC,0xCE,0xA2,0x34,0x91,0x6C,0x89,0x43,0xDF,0x3A,0x94,0x31,0x83,0x6E,0x4D,0xE8,0x9A,0x96,0x0C,0x3A,0x63,0x20,0x5B,0xD8,0xAC,0xEC,0xC8,0x20,0x37,0x7E,0xB7,0xA7,0x3D,0xCD,0xD9,0x8A,0x78,0x28,0x2E,0xB5,0x97,0xBD,0xED,0xCD,0x80,0x52,0x32,0x28,0x80,0x81,0xFF,0x07};
const uint8_t spOVER[] PROGMEM = {0x63,0x6F,0xC4,0x7A,0x1D,0xB5,0xED,0x61,0x37,0xBB,0x6E,0x75,0x62,0xD9,0x2D,0xEC,0xBF,0x56,0xAD,0x09,0xBA,0x32,0x8C,0x13,0xC7,0xD6,0xED,0x4D,0x85,0x86,0x99,0xE3,0x3E,0xB7,0x29,0x86,0x90,0x2C,0x76,0xDB,0xE6,0x98,0x95,0xBB,0x38,0x4F,0x5B,0x72,0x29,0xB4,0x51,0x6F,0x7D,0xAF,0x47,0xB9,0x73,0x71,0x8C,0x31,0x3F,0xE1,0xC9,0xA9,0x50,0xD6,0xFD,0xBA,0x27,0x57,0xC5,0x6E,0xCD,0xFD,0xFF};
const uint8_t spPLUS[] PROGMEM = {0x0A,0x18,0x4D,0x44,0x01,0x23,0x70,0x12,0x40,0x8B,0xD8,0x92,0x7A,0xD3,0x63,0x10,0xAD,0x57,0x91,0xC4,0xB5,0x8A,0xAE,0x39,0x45,0xE1,0x93,0xE9,0xBC,0xE5,0x96,0xB7,0x59,0x43,0x15,0x63,0xE9,0xBA,0x6B,0x6E,0xF5,0x64,0x40,0xF0,0xEE,0x0A,0xF8,0x25,0x43,0x03,0x1E,0xD0,0x80,0x04,0x38,0x40,0x01,0x0C,0xFC,0x3F};
const uint8_t spPULL[] PROGMEM = {0x06,0xF0,0xB6,0x9C,0x01,0x2C,0xB7,0x8F,0x28,0xCA,0x1E,0x53,0x5A,0xBA,0x93,0x95,0x0C,0x2C,0xD3,0x81,0xDA,0x76,0xBA,0xB3,0x51,0x57,0x14,0xB3,0x8E,0xEE,0x67,0xDF,0x87,0x34,0x17,0xE2,0x3B,0x86,0x5E,0xEB,0x11,0xCE,0x24,0x62,0xD3,0xB0,0x69,0xBE,0xFD,0xE3,0xDE,0x20,0x67,0x54,0xA5,0xCD,0xFF,0x03};
const uint8_t spREPEAT[] PROGMEM = {0x6E,0xF1,0x49,0x42,0x33,0xD8,0xC5,0xB9,0x8C,0xB9,0x62,0x8A,0x87,0xF6,0xD3,0xB7,0xCC,0xC6,0x1A,0xE9,0x4E,0x33,0x9C,0x23,0x79,0x7C,0xDE,0x4D,0x6B,0x5B,0x62,0xB0,0xF4,0x95,0x64,0x16,0xA1,0xDC,0x45,0x64,0x03,0x04,0xA0,0xB5,0x94,0x96,0xF6,0x14,0x4C,0x62,0xAF,0x4E,0xD6,0x13,0x93,0x66,0xCD,0x3E,0xD9,0x6C,0x89,0x64,0xB1,0xFA,0x66,0xBB,0x18,0xFD,0xAC,0x0A,0x92,0xB5,0xA8,0xAD,0xA3,0x10,0x8B,0x4D,0x6D,0x7B,0x21,0x50,0x84,0x72,0x17,0x91,0x0D,0x00,0x06,0xB8,0xDC,0xCD,0x01,0x33,0x6C,0x62,0x00,0x03,0xFF,0x0F};
const uint8_t spSHUT[] PROGMEM = {0x04,0x58,0xE3,0x5A,0x03,0x16,0xF0,0x80,0x07,0x22,0x60,0x81,0x55,0xB4,0xE4,0xA2,0x61,0x5D,0x6E,0x71,0xCA,0x12,0x3C,0xCA,0x7C,0xCE,0xAD,0x76,0x31,0xD7,0xBC,0x23,0x50,0x84,0x72,0x17,0x91,0x0D,0x00,0x06,0xE8,0x44,0x5D,0x01,0x3F,0x66,0x11,0xE0,0x98,0x59,0x04,0xF4,0x38,0xFE,0xFF};
const uint8_t spTEST[] PROGMEM = {0x0E,0x98,0x6A,0xC9,0x00,0x2B,0x37,0xAF,0xA4,0x45,0x91,0xB0,0x5A,0x72,0xEA,0x9A,0x9D,0x23,0xE3,0xCD,0x6D,0x56,0x57,0x93,0x5A,0x78,0x2D,0xD9,0xE3,0x9E,0xEB,0x4E,0x77,0x02,0x6C,0x95,0x4A,0x80,0xDF,0xD2,0x39,0xA0,0x01,0x0D,0x48,0x80,0x01,0x4F,0x2B,0x53,0x00,0x14,0x70,0x45,0x9A,0x06,0x10,0x50,0x73,0xC3,0xFF,0x03};
const uint8_t spVOLTS[] PROGMEM = {0xA0,0xDA,0xA2,0xB2,0x3A,0x44,0x55,0x9C,0xFA,0xB0,0xBA,0x46,0x72,0xDA,0xD1,0xDB,0xAE,0x47,0x59,0x61,0xED,0x28,0x79,0xED,0x45,0xAF,0x5A,0xDF,0x60,0xF4,0x39,0x69,0xAB,0x63,0xD9,0x3B,0xD2,0xBC,0x24,0xA5,0xF5,0xB6,0x0F,0x80,0x01,0x3E,0x63,0x65,0xC0,0x5F,0x63,0x12,0x90,0x80,0x06,0x24,0x20,0x01,0x0E,0xFC,0x3F};
const uint8_t spGALLONS[] PROGMEM = {0x0E,0x28,0x8A,0xE5,0xB4,0xAD,0x04,0x9B,0xF9,0x9A,0x5B,0x9F,0xBA,0xE9,0x91,0x4A,0x5D,0x7D,0xAB,0x53,0x15,0x35,0xBE,0xA2,0x8B,0x77,0x35,0xEA,0xCC,0xC6,0x4F,0xA9,0x6E,0x6B,0x07,0xC8,0xEC,0x45,0xCF,0x6B,0x2C,0xA2,0x7C,0x4D,0x36,0xCF,0x65,0xAC,0x8D,0x97,0xB6,0xE9,0xE2,0x7A,0x86,0x7B,0x44,0xD4,0xB0,0x54,0x1A,0xEE,0xA6,0x51,0x32,0xC2,0xA9,0x7F,0xCC,0xD3,0x2D,0xA3,0xA7,0xC4,0xB7,0xAF,0x7E,0xE4,0xE7,0xBE,0xAF,0x4D,0x54,0x53,0x19,0x03,0xBE,0x60,0x62,0xC0,0xAF,0xAE,0x12,0x90,0x00,0x02,0x6A,0x70,0xFE,0x7F};
const uint8_t spHERTZ[] PROGMEM = {0x04,0xC8,0xA1,0xD8,0x02,0x1E,0x58,0x71,0x2E,0x81,0x31,0xDC,0x65,0x25,0xD5,0x9E,0xC2,0x9A,0xFE,0x9D,0xED,0x7A,0x8E,0x61,0xAD,0x25,0xC1,0x4A,0xF3,0x01,0x00,0x02,0xB6,0x09,0x65,0xC0,0x6F,0x65,0x1C,0xB0,0x80,0x05,0x34,0xE0,0x01,0x0D,0x10,0xA0,0x09,0x97,0xFF,0x07};
const uint8_t spMICRO[] PROGMEM = {0x22,0x8B,0x44,0xF5,0x92,0x9B,0xDA,0xC5,0xCF,0x6B,0xA8,0xBC,0x2B,0x8B,0xB3,0xDC,0xEE,0xB6,0xA7,0x6E,0x3E,0xB9,0xC2,0x56,0x9F,0xA2,0x57,0x93,0xD0,0x9C,0x5D,0x8A,0x3E,0x88,0x52,0xA6,0x32,0x2B,0xAA,0x15,0x34,0xCB,0xD4,0xC0,0x80,0x12,0x23,0x22,0x60,0x81,0x30,0xC5,0xAA,0x61,0x25,0xF9,0x7A,0xDF,0x87,0x31,0x17,0xDE,0x1E,0xC5,0xFE,0xDB,0x96,0xD5,0xD8,0x38,0xF4,0xAB,0x47,0x78,0xBC,0xAB,0x18,0xE1,0x3C,0xFE,0xF5,0xDF,0xFF,0x03};
const uint8_t spOHMS[] PROGMEM = {0xAD,0xC9,0x74,0x37,0x59,0xD2,0xED,0xE6,0xD4,0x95,0xF8,0x56,0xB0,0xD2,0x5D,0x9D,0xAA,0x12,0xAF,0x2D,0xB7,0xBA,0xDB,0xDE,0xB7,0x79,0x68,0x93,0x32,0x96,0xD2,0x97,0xBA,0xE6,0x3D,0x9F,0xEE,0x6A,0x92,0xB9,0x22,0x9C,0x98,0x2B,0x33,0x8E,0x16,0x8F,0xEB,0xEE,0x6E,0xD1,0x5A,0x3C,0x4D,0xB8,0x06,0x09,0x35,0xA5,0xDE,0xE1,0xFA,0xC5,0xD8,0x4D,0xE4,0x2A,0xE0,0x5B,0x15,0x05,0x7C,0x27,0xA4,0x01,0x0E,0x70,0x00,0x01,0xDE,0x6C,0xFE,0x3F};
const uint8_t spAREA[] PROGMEM = {0x2D,0xEF,0xA1,0xC8,0x32,0x36,0xDF,0xE5,0x0C,0xDD,0x0D,0xCB,0x68,0xDF,0xDB,0xAC,0xBA,0x0C,0xB1,0x32,0xED,0x3A,0xAA,0xD4,0x39,0x2C,0x4D,0xEF,0xAC,0x67,0xB3,0xFA,0xD2,0x58,0xD3,0x3D,0xEF,0x1A,0xBA,0x2B,0xD0,0xF2,0xDD,0x73,0x1E,0x4B,0xF7,0x89,0xE6,0xF1,0x79,0xAF,0x63,0xED,0x3E,0xD8,0xDD,0x3E,0x8F,0xAD,0x3A,0xF7,0x76,0x5D,0xD3,0xB7,0xBE,0xB7,0xBB,0xE9,0xB4,0x4E,0xE9,0x5D,0x3F,0xF7,0xA7,0x1C,0x9E,0xEA,0x4B,0xFE,0x1F};
const uint8_t spCIRCUIT[] PROGMEM = {0x02,0x78,0x2D,0x55,0x02,0x12,0xB0,0x80,0x01,0x5E,0x49,0x5D,0x49,0x35,0xAE,0x1A,0xD6,0xF6,0x94,0x25,0x05,0x5B,0x4A,0xD7,0x55,0x94,0x3C,0x28,0x2D,0xFE,0x76,0x11,0xCA,0xEA,0x06,0x25,0x35,0x29,0x02,0x45,0x28,0x77,0x11,0xD9,0x08,0x28,0x4E,0x15,0x1C,0x50,0x1C,0xD3,0xEA,0x6A,0x14,0x49,0xF7,0x4D,0x7B,0x19,0x67,0x53,0x45,0x65,0xB1,0xA7,0x3E,0x08,0x14,0xA1,0xDC,0x45,0x64,0x03,0x80,0x00,0x96,0x56,0x53,0xC0,0x1F,0xAD,0x02,0x78,0xAE,0x06,0x01,0xCB,0xB7,0xFF,0x3F};
const uint8_t spCONNECT[] PROGMEM = {0x06,0xA8,0xD5,0x29,0x24,0x3D,0xAC,0xB3,0x52,0xE6,0x55,0x97,0xA0,0x56,0x12,0x8D,0x4F,0xDB,0x9C,0x6A,0x4B,0x2C,0x2D,0xDD,0xC8,0xA8,0xEE,0xE9,0xB4,0xF6,0xAB,0x6B,0x4E,0xB5,0x28,0x93,0xAC,0xB6,0xC5,0x66,0x4F,0xDB,0x7C,0xBB,0xDB,0xEF,0x69,0x9E,0xE5,0x69,0xA1,0x39,0x3C,0x96,0x20,0x50,0x84,0x72,0x17,0x91,0x0D,0x00,0x20,0x80,0xA5,0xC3,0x1C,0xB0,0xEC,0x97,0x05,0x18,0xD0,0xCB,0xDA,0xFF,0x03};
const uint8_t spSECONDS[] PROGMEM = {0x04,0xF8,0xC5,0x51,0x01,0xBF,0xA6,0x6A,0x40,0x03,0x16,0xD0,0xC0,0xCA,0xAB,0x75,0x2D,0xCD,0x25,0x37,0xBB,0xD9,0xCA,0xDA,0x54,0x0F,0xEE,0xD9,0x29,0x6B,0x47,0x30,0xD8,0xE3,0x80,0x00,0x6A,0x26,0x6D,0x55,0xEB,0xCA,0x21,0xB9,0xE4,0xD4,0xDD,0x26,0xA5,0xF9,0xE3,0x3D,0xB6,0x75,0x38,0xA3,0x31,0x5B,0x9A,0xB6,0x11,0x51,0x32,0xD2,0xAA,0x3F,0xFC,0x21,0xCE,0x22,0xD1,0xD7,0x2D,0x9E,0x39,0x0B,0x37,0x4E,0xD7,0x26,0xE1,0xFA,0xC4,0x55,0x42,0xFD,0x85,0xFB,0x7B,0x77,0x13,0xA3,0x27,0x80,0x03,0xD0,0x25,0x20,0x01,0x0A,0x20,0x20,0x69,0xD6,0xFF,0x07};
const uint8_t spUNIT[] PROGMEM = {0x61,0xB9,0x96,0x84,0xB9,0x56,0xE5,0xB9,0xCE,0x63,0xDE,0xCE,0x0D,0x30,0x36,0x9F,0x6E,0x86,0x36,0x60,0xE9,0x7B,0xCA,0x5E,0x93,0x45,0xA4,0xEB,0xC9,0xBB,0x77,0x72,0xE7,0x2D,0x2B,0xAB,0xD6,0x24,0x94,0x17,0x8F,0xA2,0x79,0x4C,0xD5,0x48,0x5D,0xAA,0xEE,0x21,0x23,0x42,0xF1,0x1A,0x66,0x54,0x15,0x97,0xD6,0x6B,0x19,0xD1,0xC5,0xC5,0x77,0xEF,0xB3,0x9F,0x7E,0x47,0xA0,0x08,0xE5,0x2E,0x22,0x1B,0x00,0x01,0xCB,0xBB,0x3B,0xE0,0xD7,0x0A,0x05,0x9C,0xD0,0x4D,0x80,0xE6,0x92,0xFE,0x1F};
const uint8_t spTIMER[] PROGMEM = {0x0E,0xB8,0x36,0xC3,0x01,0xCD,0x98,0xB4,0x38,0x87,0x8C,0x0A,0x59,0x72,0x8B,0x5B,0x9D,0xAA,0x15,0x35,0x0B,0x9F,0x7D,0x8B,0x5D,0xB4,0xAA,0x78,0x96,0xB4,0xB0,0x5B,0xFB,0x32,0xE7,0xE8,0x9C,0x85,0x6D,0xDA,0x96,0xC3,0x10,0x9F,0x78,0x49,0x67,0x35,0xA7,0xF0,0xA6,0x2F,0xDD,0x39,0x2D,0xF2,0x89,0x9F,0xFC,0xC4,0xD7,0xFD,0xC5,0x1F,0xC3,0xBA,0x3F,0xF3,0x97,0x6D,0x54,0xC9,0xFD,0xFE,0x1F};
const uint8_t spUP[] PROGMEM = {0x2D,0xCD,0x72,0xA2,0x55,0x77,0xDD,0xF6,0x36,0xB7,0xB9,0xD5,0xEA,0xB3,0xC9,0x6C,0xF1,0xD5,0xE9,0x4A,0xB6,0xBD,0x39,0x7F,0x21,0x50,0x84,0x72,0x17,0x91,0x0D,0x00,0x20,0x80,0x48,0xD3,0x08,0x90,0x54,0x28,0x06,0xFE,0x1F};
const uint8_t spIS[] PROGMEM = {0xAD,0xED,0xD5,0x58,0xA4,0x9E,0xCE,0x76,0xF5,0xDD,0xAB,0x29,0xF5,0xD2,0xDD,0xEF,0x7E,0x0C,0xC3,0xA9,0x06,0xFA,0xD3,0x32,0x0F,0x6E,0x94,0x22,0x8F,0xF3,0x92,0xF6,0x05,0x43,0xCC,0x74,0x77,0x3E,0xC3,0xF5,0x95,0x98,0xA9,0xBA,0x8B,0x8F,0x00,0x7E,0x73,0xE5,0x00,0x05,0x28,0xF0,0xFF};
const uint8_t spALERT[] PROGMEM = {0xA5,0xCF,0xC6,0xAB,0x55,0x5B,0xAF,0x39,0xDA,0xC9,0x54,0xDD,0xBC,0xC6,0xC2,0x3C,0x27,0x20,0xCF,0x1C,0xD7,0x30,0xB0,0x45,0x16,0x69,0x1D,0xC3,0x11,0xE4,0x59,0x8A,0x7C,0xB5,0x9B,0x8B,0xD9,0x30,0xB7,0xD3,0x76,0x19,0x9A,0x25,0x59,0x57,0x59,0xEC,0x11,0xAF,0xE8,0xD9,0xF9,0x2A,0x8A,0x1D,0xF0,0x75,0x3F,0x73,0xAC,0x87,0x3B,0xA2,0x0B,0xAA,0x2B,0xCF,0xE4,0x10,0xA1,0xDC,0x45,0x64,0x03,0x00,0x80,0x01,0x66,0x36,0x33,0xC0,0xAB,0xD5,0x0A,0x68,0x25,0x85,0x02,0xFF,0x0F};
const uint8_t spADJUST[] PROGMEM = {0xAD,0xAD,0xA1,0xD5,0xC4,0x5A,0x9F,0xB1,0xFA,0x14,0xB3,0x78,0xBC,0x87,0x31,0x55,0x9B,0xEC,0xC2,0x6B,0xC4,0xE6,0xB9,0xDB,0xB8,0x97,0x24,0x87,0xA6,0x99,0x59,0x61,0x4B,0x1C,0x05,0x63,0x56,0x79,0x6C,0x05,0x4C,0xC5,0x14,0x81,0x35,0xB4,0x98,0xAC,0xAE,0x7D,0x6E,0x77,0xAA,0xE2,0xD2,0x5A,0x63,0xD5,0xAD,0x6E,0xBD,0xBA,0xE2,0xD3,0x8A,0xAB,0xF2,0x1C,0x15,0x50,0x41,0x8A,0x03,0x7E,0x29,0xF1,0x80,0x05,0x2C,0xA0,0x01,0x01,0xFC,0xD6,0x2A,0x01,0x60,0xC0,0x0B,0xEC,0x16,0x60,0x40,0xB7,0x63,0xFF,0x0F};
const uint8_t spBETWEEN[] PROGMEM = {0xA2,0xED,0xD9,0x59,0x4C,0xFB,0xEC,0xE2,0x0C,0x33,0x34,0x83,0xD9,0x96,0x3B,0x8E,0x69,0xC6,0x15,0x14,0xDA,0x03,0xE0,0x80,0x6E,0xCD,0x03,0xD0,0xE3,0xB8,0x02,0x72,0x48,0x2B,0x45,0xB0,0xE9,0x69,0x12,0x77,0x55,0x99,0xA7,0x57,0x42,0x93,0x53,0x74,0x19,0xE6,0x89,0x6B,0x4E,0x39,0x82,0xB3,0xA6,0x3E,0x3A,0xE5,0x2C,0x81,0x5C,0x59,0xE9,0xD6,0xAB,0xEB,0x81,0x31,0x27,0xCA,0xCC,0xA5,0x6F,0x65,0x1B,0x09,0x5D,0x3D,0xDC,0xD4,0x23,0x9F,0xE9,0xA9,0x8A,0xB4,0xDD,0x92,0xFC,0x3F};
const uint8_t spMINUTES[] PROGMEM = {0x61,0xCA,0xCC,0x38,0x5B,0x9A,0xE6,0xA9,0xB6,0xA7,0xEC,0x2A,0xC5,0xDD,0x17,0xDF,0xE2,0xE6,0x23,0x6B,0x16,0xC3,0x2D,0x92,0xCC,0x72,0xB5,0xD5,0xBA,0x86,0xD5,0xEC,0xB9,0x94,0xAD,0x98,0x90,0xF4,0x79,0x14,0xDE,0x8E,0x53,0x3C,0x63,0x23,0x02,0x45,0x28,0x77,0x11,0xD9,0x00,0x80,0x80,0xCF,0x58,0x05,0xF0,0x7B,0x99,0x04,0x38,0xC0,0x01,0x0A,0x50,0xE0,0xFF,0x01};
const uint8_t spBUTTON[] PROGMEM = {0x10,0xA6,0x28,0xDD,0xCD,0x2D,0xD5,0x6A,0x8B,0xEE,0x6C,0xB1,0x4D,0xA7,0xAC,0x2E,0xA3,0x44,0x97,0xDC,0xA6,0xF5,0xCD,0x6B,0x34,0x46,0x13,0x32,0x89,0x50,0xEE,0x22,0xB2,0x01,0x20,0xA5,0xDD,0xA1,0x94,0xBB,0xB3,0xB6,0x0C,0x2F,0xA4,0xE6,0xF1,0xFA,0x96,0x8F,0x70,0x8F,0xC2,0x2A,0xE6,0x4A,0xDD,0xD3,0x2D,0x51,0x7A,0xDA,0xF3,0xAF,0x7B,0x47,0x63,0x51,0x73,0x67,0xE1,0x6B,0x46,0xDD,0x49,0xEB,0xFE,0x3F};
const uint8_t spCLOCK[] PROGMEM = {0x06,0x48,0x65,0x34,0x00,0x93,0xA7,0x5B,0xA0,0xA4,0x95,0xBA,0x5F,0x82,0x9B,0x95,0x07,0x37,0x55,0x24,0x4D,0x4E,0x51,0xE9,0x54,0x25,0x76,0xB9,0xE5,0x2D,0x4F,0x93,0x7D,0xE5,0x98,0xAE,0xDE,0x63,0x3B,0x72,0xC9,0x2C,0x8E,0xD9,0xF1,0x41,0xA0,0x08,0xE5,0x2E,0x22,0x1B,0x00,0x40,0x00,0x35,0x0D,0x69,0x80,0x02,0xFF,0x0F};
const uint8_t spDEVICE[] PROGMEM = {0x64,0x8E,0x38,0x3C,0x4B,0x62,0x8F,0x7D,0x89,0x14,0xD4,0xCC,0xB5,0x86,0x11,0x9A,0xD1,0xB5,0xCF,0x1C,0xDC,0xDC,0xA5,0x23,0xB5,0x3B,0xCB,0x73,0x9D,0x46,0x99,0x6D,0x59,0x35,0xE5,0xD9,0xF5,0x69,0xAA,0x1E,0xCB,0xE2,0xCD,0xB7,0xB9,0xDD,0x19,0xAA,0x2F,0xE9,0xD0,0xD5,0x7B,0x69,0x57,0xF3,0x49,0x1E,0xF1,0x28,0xDE,0x0C,0xB8,0x36,0x54,0x00,0xBF,0x55,0x6A,0x40,0x03,0x1A,0xE0,0x00,0x07,0x28,0xF0,0xFF};
const uint8_t spEAST[] PROGMEM = {0xAD,0x1D,0x59,0x50,0xBC,0x17,0x8F,0x7A,0x96,0x02,0x8C,0x7C,0xB2,0xEB,0x5D,0xCD,0x7A,0x0C,0x63,0x10,0x71,0xCC,0xEC,0x3E,0xA5,0x75,0x0C,0x41,0xF2,0x7A,0x4C,0x80,0x6F,0x67,0x24,0xA0,0x01,0x05,0xFC,0x3C,0xA5,0x01,0x0D,0x58,0x40,0x02,0x04,0xF8,0xDA,0x1C,0x03,0x1A,0x30,0xC0,0x31,0x37,0x02,0xE8,0xF5,0x8D,0x00,0xD5,0x39,0xFC,0x3F};
const uint8_t spFAIL[] PROGMEM = {0x04,0x98,0x3E,0x8D,0x03,0x1C,0xD0,0x80,0x07,0x4A,0xBF,0x54,0x9B,0x3A,0x79,0x9C,0xCD,0xAA,0x9B,0x0F,0x31,0x8F,0x37,0xB7,0xBE,0xCD,0x6A,0x47,0x2A,0x66,0xB3,0xB7,0xB3,0xDB,0x6B,0x5F,0xC7,0x56,0x44,0x58,0x8E,0x76,0xAA,0x7B,0xD8,0x33,0xB9,0x32,0xD7,0x3C,0xF9,0x0C,0x67,0xD4,0x13,0x9E,0x98,0xC7,0x5F,0xEE,0x49,0x7C,0xAA,0x8D,0xF3,0xF9,0xF7,0xFF,0x01};
const uint8_t spFREQUENCY[] PROGMEM = {0x04,0xA8,0x4A,0x9D,0x01,0x33,0x8C,0x71,0x40,0x02,0x1A,0x08,0x71,0x4E,0x5C,0x52,0xEA,0x7E,0x67,0x2B,0xEB,0xB5,0x98,0x82,0xB7,0xEE,0x64,0xA4,0x7D,0x18,0xB2,0xDB,0x1B,0x9B,0x22,0x50,0x84,0x72,0x17,0x91,0x0D,0x04,0xF0,0x35,0x2D,0x25,0x59,0xB9,0x57,0xCA,0xE2,0x39,0xB4,0xB1,0x69,0xB4,0xF2,0xB4,0x5B,0x97,0xB0,0x14,0x05,0x15,0x91,0x6A,0xF4,0x2A,0x80,0x5F,0x4A,0x2D,0xE0,0x01,0x0B,0x68,0x40,0x03,0x63,0x69,0x56,0xC5,0x25,0x57,0x8D,0xAD,0x27,0x63,0xB1,0x78,0xDC,0x8F,0x7E,0x95,0x6B,0xE6,0x24,0x32,0x5B,0x93,0xEE,0xD1,0x83,0x58,0xEC,0x4D,0x7E,0xE3,0xF7,0xFF};
const uint8_t spGATE[] PROGMEM = {0x0C,0x08,0xDA,0x75,0x2C,0xB3,0x27,0x19,0xBB,0xDD,0xD1,0xB7,0x44,0xE4,0x51,0x73,0x4E,0x3D,0x7A,0x90,0x49,0x2C,0xB9,0xE5,0xAD,0x6E,0xB5,0xBA,0x99,0x0A,0x24,0xE3,0xF1,0x1E,0xFA,0x1E,0xEE,0x31,0x13,0x59,0xE3,0x8D,0xFA,0x47,0x21,0x32,0xAF,0xC7,0x08,0x14,0xA1,0xDC,0x45,0x64,0x03,0x00,0x38,0x60,0x89,0x52,0x03,0x6C,0xF3,0xC3,0x80,0xDE,0xD7,0x08,0x50,0x8D,0xE1,0xFF,0x03};
const uint8_t spHIGH[] PROGMEM = {0x04,0xC8,0x7E,0x9C,0x02,0x12,0xD0,0x80,0x06,0x56,0x96,0x7D,0x67,0x4B,0x2C,0xB9,0xC5,0x6D,0x6E,0x7D,0xEB,0xDB,0xDC,0xEE,0x8C,0x4D,0x8F,0x65,0xF1,0xE6,0xBD,0xEE,0x6D,0xEC,0xCD,0x97,0x74,0xE8,0xEA,0x79,0xCE,0xAB,0x5C,0x23,0x06,0x69,0xC4,0xA3,0x7C,0xC7,0xC7,0xBF,0xFF,0x0F};
const uint8_t spINTRUDER[] PROGMEM = {0xAB,0x1D,0xA9,0x88,0xCC,0x37,0x9F,0x66,0xBA,0x16,0x31,0xFE,0xBC,0xEB,0x55,0x0F,0xCF,0x98,0x69,0x55,0x47,0xD3,0x0C,0xF2,0xA4,0x45,0xAB,0x6D,0x6D,0x43,0x57,0x34,0xF8,0x78,0x34,0x45,0xA0,0x08,0xE5,0x2E,0x22,0x1B,0x14,0xD0,0x4A,0x46,0x06,0x34,0xD0,0xD2,0xEC,0x39,0xCC,0xCC,0xDD,0xCC,0x56,0x9E,0x95,0x58,0x14,0xB5,0xDB,0x45,0xAB,0xAB,0x27,0x4B,0xF6,0x74,0xA2,0x62,0xCE,0xB2,0x3C,0x66,0xB7,0x7A,0x2C,0x0B,0x61,0x95,0xBB,0x96,0x96,0x4C,0xD9,0x35,0xDB,0x98,0xAB,0x29,0xA2,0xB3,0x7C,0x73,0xED,0x47,0xBB,0x4A,0x2E,0xD0,0x71,0x3F,0xF9,0x8B,0x5F,0xF8,0x4A,0x0F,0xF4,0xD1,0x3C,0xFF,0x0F};
const uint8_t spMEASURE[] PROGMEM = {0x66,0x71,0x52,0xED,0xD2,0x92,0x86,0x39,0x2B,0xE6,0x4E,0x8F,0x9B,0xC7,0xD1,0x17,0xA3,0x1C,0x22,0x69,0x4F,0xD7,0x73,0xA8,0x9B,0xAE,0xBE,0xF5,0xAD,0x6E,0x39,0xF2,0xEE,0x45,0xD4,0x7C,0xA5,0x01,0x1A,0x63,0x0E,0xC0,0xA8,0x81,0x11,0x18,0x7D,0x8F,0x29,0x68,0x96,0x75,0x0C,0x25,0x27,0x71,0x85,0xF7,0x39,0xCF,0x7D,0x1E,0xE5,0x2A,0x4B,0xD8,0x5B,0xF3,0xE4,0x27,0x3E,0xFE,0x75,0x7F,0x19,0x46,0xD9,0xBC,0xE5,0xFF,0x01};
const uint8_t spNORTH[] PROGMEM = {0x66,0x8E,0x54,0xAC,0x9A,0xE7,0x84,0xA9,0x0A,0xE2,0x1C,0xAE,0x5B,0xC6,0xE6,0x51,0xCD,0x23,0xE9,0xE9,0x8B,0x71,0x77,0xD3,0xAE,0xA7,0x2A,0x22,0x3D,0x8B,0xB2,0x9E,0x32,0x8B,0xCE,0x6C,0xD6,0x76,0x8B,0x55,0x26,0xB7,0xE2,0xCB,0x7A,0x77,0x35,0x87,0xB6,0xE5,0x92,0x54,0xA9,0xF9,0xC6,0x91,0x63,0x88,0xA7,0x77,0xEE,0x67,0xBA,0x4B,0x60,0x2F,0xAB,0xD6,0x04,0x18,0xB2,0x44,0x03,0x06,0xC8,0xB2,0x44,0x03,0x14,0xA0,0xC0,0xFF,0x03};
const uint8_t spPASS[] PROGMEM = {0x0A,0xC8,0x33,0x83,0x03,0xA3,0xEC,0x55,0x2D,0xD4,0x12,0xAF,0xAA,0x04,0xC9,0xD4,0x0E,0x7D,0xAA,0x16,0x4A,0x33,0x65,0xCE,0xAD,0x6F,0x7D,0x9A,0x9A,0xDC,0xDB,0x62,0xEE,0x6D,0x6E,0x73,0xC6,0x12,0xDD,0x5B,0x6B,0xEE,0x5D,0xF6,0x3A,0xCE,0xAA,0xD2,0x26,0xED,0x75,0xBB,0x9B,0x4D,0x6D,0xF1,0x25,0xFD,0x77,0x7F,0xEF,0xD2,0xCE,0x9D,0x46,0x00,0x4B,0x17,0x2B,0xE0,0x8F,0x52,0x0B,0x68,0x40,0x02,0x1C,0x90,0xC0,0xFF,0x03};
const uint8_t spPOSITION[] PROGMEM = {0x02,0xC8,0x3C,0x78,0x24,0x5D,0xB8,0xBB,0x53,0xB7,0x5B,0xDC,0x62,0xD5,0x4B,0x38,0x87,0xA1,0x1F,0x05,0x5C,0x40,0x66,0x81,0x95,0x1D,0x19,0xA6,0x4E,0x7E,0x4E,0x3C,0x75,0xA8,0x39,0xF5,0x3D,0x51,0xB7,0xA9,0xA6,0xBA,0xE7,0x44,0x2D,0x99,0x2A,0xC7,0xA6,0x04,0x8C,0x3E,0x95,0x81,0x0C,0x78,0xA0,0xF5,0x2D,0xA8,0x98,0xD9,0x96,0x3D,0x8D,0x69,0xE8,0x64,0x4B,0xE9,0x3B,0x8E,0xA1,0x9D,0xBD,0xA4,0x4B,0x3B,0xBA,0x16,0x2C,0x77,0x7B,0xF9,0xCA,0x4F,0x78,0x7B,0x20,0x35,0x0B,0xA7,0xF1,0xFF,0x7F};const uint8_t spPUSH[] PROGMEM = {0x06,0x28,0x22,0x5D,0x03,0xCB,0x4B,0x2A,0x23,0x03,0xDB,0x9E,0xB8,0x88,0x8C,0x18,0xCC,0x7A,0xD3,0x9B,0xAF,0xBA,0x78,0xE7,0x70,0xEB,0xDA,0xC6,0x9E,0x27,0x44,0x44,0xAB,0x01,0x56,0xBE,0x8A,0x40,0x04,0x22,0xE0,0x01,0x0F,0x78,0x40,0x02,0xFF,0x0F};
const uint8_t spRIGHT[] PROGMEM = {0x66,0xD7,0xB1,0x24,0xDC,0xE3,0x98,0xCD,0x95,0xA4,0x28,0xB5,0x97,0xD6,0xD0,0x8C,0x3A,0x55,0xFE,0x18,0x43,0xB1,0x4C,0x37,0x6F,0xA7,0x2D,0x72,0x22,0x8A,0xF3,0x9E,0xA6,0xFA,0x94,0x0A,0xDD,0x7C,0x9B,0xDB,0xAD,0xB1,0xD7,0x40,0xF3,0x78,0x3D,0xE7,0x7E,0xE6,0x07,0x81,0x22,0x94,0xBB,0x88,0x6C,0x00,0x50,0xC0,0xB6,0xD7,0x1E,0x10,0x40,0x9B,0xEB,0x0C,0x28,0x56,0xE9,0xFF,0x01};
const uint8_t spSLOW[] PROGMEM = {0x04,0xF8,0xCB,0x44,0x01,0xBF,0x86,0x5B,0xC0,0x02,0x1C,0x28,0xD3,0xC6,0x1C,0x55,0xA2,0xAD,0x0F,0xB3,0x3D,0xC5,0xA4,0x16,0x95,0xE4,0xF5,0x64,0x95,0x7B,0x8E,0x53,0xDF,0x9B,0xAD,0x22,0xF1,0xEA,0x61,0xCE,0xBB,0x9B,0xD9,0xCF,0xB9,0x2F,0x7D,0x0D,0x9B,0xD7,0x5D,0x0B,0x92,0x27,0x1E,0xEE,0xD4,0xA5,0x32,0x50,0xDB,0xD8,0xD3,0x5E,0xEE,0xF6,0xB1,0xDD,0x55,0xBB,0xFC,0x3F};
const uint8_t spTOOL[] PROGMEM = {0x09,0x38,0xD6,0xCC,0x01,0xCB,0x76,0xB5,0x38,0x73,0x0B,0x4F,0xCA,0x3A,0x92,0x42,0xAD,0x25,0x29,0xFD,0x4E,0x47,0x9A,0x78,0x64,0x34,0xA4,0xEB,0xC5,0xA8,0x0A,0xB1,0xCA,0x02,0x77,0xB5,0xAF,0x73,0x5A,0x83,0x88,0x69,0xA3,0x6C,0x69,0xCD,0xCC,0x67,0x94,0xDC,0xE7,0x3D,0x5E,0xF1,0x09,0x7F,0x11,0xDA,0xC3,0xE2,0xF5,0xFF,0x01};
const uint8_t spWEST[] PROGMEM = {0x66,0xB7,0x7C,0x53,0x53,0x6B,0xFA,0xC5,0xCF,0x65,0x4C,0x64,0x56,0x5C,0x1C,0xAF,0xA6,0xE0,0xEA,0x68,0x52,0x77,0x8A,0x2A,0xD2,0xB3,0x29,0xDF,0xC9,0x9B,0x4A,0xCD,0xE2,0xCD,0x37,0x5F,0x45,0x8B,0x21,0xAD,0xF1,0x78,0xB7,0xBB,0x1F,0x4B,0x89,0x92,0xC6,0x17,0x5B,0x01,0x8F,0x9B,0x1A,0xE0,0x97,0x48,0x0F,0x78,0xC0,0x03,0x1A,0x10,0xC0,0x9F,0xED,0x1C,0xC0,0x00,0x28,0xE0,0x15,0x56,0x05,0x1C,0x9F,0x43,0x80,0x61,0x26,0xFF,0x1F};
const uint8_t spKILO[] PROGMEM = {0x06,0xD8,0x29,0x25,0x01,0x5D,0x22,0x7B,0xA0,0x85,0x33,0x1A,0x52,0xD7,0xDB,0x19,0xCF,0x68,0x44,0xD3,0x29,0x51,0x79,0xBC,0x99,0xAC,0x6C,0x71,0x0B,0x4D,0xCA,0xB6,0xC7,0x35,0x55,0xEE,0x39,0x4E,0x7D,0xEF,0xBA,0xD6,0xC2,0x32,0xAB,0xB8,0xEF,0xDE,0xDB,0x99,0x4C,0x65,0x2B,0xF5,0xED,0x67,0xB9,0x7D,0xAC,0x6C,0xD4,0x35,0xF1,0x8E,0x4F,0x78,0x83,0x9A,0xCA,0x20,0xBF,0xEE,0x4F,0x62,0xBC,0x82,0xF4,0xFD,0x3F};
const uint8_t spAND[] PROGMEM = {0xA9,0x6B,0x21,0xB9,0x22,0x66,0x9F,0xAE,0xC7,0xE1,0x70,0x7B,0x72,0xBB,0x5B,0xDF,0xEA,0x56,0xBB,0x5C,0x65,0xCB,0x66,0xC5,0x3D,0x67,0xD7,0xAB,0x6D,0x2E,0x64,0x30,0x93,0xEE,0xB1,0xCD,0x3D,0x92,0xB9,0x9A,0xDA,0xB2,0x8E,0x40,0x12,0x9A,0x6A,0xEB,0x96,0x8F,0x78,0x98,0xB3,0x2A,0xB4,0xD3,0x48,0xAA,0x2F,0x7D,0xA7,0x7B,0xFB,0x0C,0x73,0x71,0x5C,0xCE,0x6E,0x5C,0x52,0x6C,0x73,0x79,0x9A,0x13,0x4B,0x89,0x45,0xE9,0x6E,0x49,0x42,0xA9,0x57,0xFF,0x3F};
const uint8_t spFARAD[] PROGMEM = {0x04,0x58,0x3E,0x8D,0x03,0x1C,0xD0,0x80,0x05,0x4A,0xB9,0x54,0x9B,0x3A,0x79,0x9C,0xD5,0xA9,0x7B,0x0C,0x71,0xF7,0xD7,0xB7,0xBE,0xCD,0x68,0x4B,0x56,0xF1,0x12,0x3F,0xB5,0x4B,0x6B,0x2C,0x6C,0x91,0x26,0xBF,0x4E,0x63,0x2E,0x91,0x43,0x5D,0xDB,0xAF,0xA5,0xF9,0x10,0x0D,0xE9,0x3E,0xF7,0x7A,0xF2,0x0B,0x81,0x22,0x94,0xBB,0x88,0x6C,0x20,0xCF,0xA2,0xEE,0x95,0x99,0x38,0x3D,0xDD,0x85,0x89,0xCA,0x96,0xFC,0xFC,0x3F};
const uint8_t spMILLI[] PROGMEM = {0x6E,0xF0,0x8A,0xB3,0x4B,0xEB,0xC6,0xAE,0x36,0xA7,0x1A,0x3A,0x54,0x53,0xD6,0xDC,0xEC,0x66,0x23,0xDF,0x58,0x26,0x43,0xB4,0xCD,0xEA,0x74,0x5D,0x94,0x46,0xF0,0x96,0x3B,0x9D,0x79,0x98,0x26,0x75,0xDB,0xB3,0xD7,0xB6,0xF5,0x90,0xA8,0x91,0x9F,0xEA,0x9E,0xEE,0xE9,0x9B,0x20,0x7D,0xCB,0xFF,0x03};
const uint8_t spCAUTION[] PROGMEM = {0x02,0x48,0x69,0x4D,0x03,0x06,0xE8,0x34,0xA2,0x85,0x95,0x4C,0x78,0xA8,0xD2,0x93,0x66,0xB1,0xE9,0x4D,0x79,0x6F,0x7A,0xD3,0x9D,0xF5,0xCC,0x01,0x2B,0x86,0x06,0x60,0xC5,0xAB,0x08,0x44,0x20,0x00,0xCD,0x10,0x8D,0xB6,0x26,0x11,0x8B,0xE8,0x3C,0xE6,0x62,0x5D,0x3D,0x63,0xF7,0x58,0xBB,0x4E,0xF1,0xB0,0x2E,0xED,0x28,0xCA,0x74,0xCC,0x9B,0xB8,0xB7,0x69,0xA6,0x0E,0x8F,0x66,0xBE,0xAC,0x48,0xC6,0xAD,0xAE,0xFB,0x9A,0x16,0x0E,0xF3,0x78,0xFE,0xF3,0xBF,0xFF,0xED,0xFF,0xFF};
const uint8_t spLIGHT[] PROGMEM = {0x61,0x69,0xC0,0x2B,0x82,0xB3,0xA5,0x79,0x01,0x9A,0x52,0x71,0x57,0xC7,0x31,0x0C,0x5C,0x5D,0xC1,0x59,0x6F,0x7B,0x9A,0xC6,0x3B,0xCB,0xA5,0xCB,0xA9,0xAA,0x6D,0x6B,0xB3,0xCD,0xA7,0x6C,0x29,0xB4,0x34,0x56,0xAF,0xBA,0x0F,0x23,0x93,0x5C,0x32,0xC7,0xB6,0xF6,0x46,0xA4,0x39,0xB3,0xF3,0x86,0x40,0x11,0xCA,0x5D,0x44,0x36,0x00,0x80,0x02,0x96,0x2A,0x35,0xC0,0xB6,0x97,0x0C,0xE8,0xF9,0x04,0x01,0xC5,0x19,0xFC,0x3F};
const uint8_t spCHECK[] PROGMEM = {0x0E,0x58,0x25,0x25,0x00,0xB3,0x8E,0x7B,0x60,0xC5,0x35,0xB3,0x68,0xE4,0xEA,0x53,0xB4,0x1C,0x12,0xEE,0x9B,0x6F,0x79,0xAB,0x5B,0xEF,0x71,0xEF,0xE6,0xAE,0x49,0xA9,0x2A,0x17,0x21,0x50,0x84,0x72,0x17,0x91,0x0D,0x00,0x0A,0x68,0xC5,0x49,0x02,0x12,0xE0,0xC0,0xFF,0x03};
const uint8_t spDEGREES[] PROGMEM = {0x65,0x9F,0x5A,0x48,0x42,0x1D,0x8F,0x61,0xB8,0x62,0x56,0xFE,0xB2,0xFA,0x51,0x9C,0x85,0xED,0xCD,0xEA,0x47,0x4B,0x64,0xD5,0x35,0x69,0xE8,0xC7,0x41,0xD4,0x5E,0x8B,0x25,0x6B,0xB4,0x75,0xB7,0x84,0x40,0x11,0xCA,0x5D,0x44,0x36,0x98,0xAD,0xA9,0xAB,0x28,0x8D,0x1B,0xFA,0xE2,0x26,0xC9,0x44,0x69,0x6A,0xA3,0x13,0x8F,0x70,0xAD,0xA5,0xC9,0x99,0x42,0xDC,0x9C,0x8D,0xA6,0x36,0x4E,0x72,0xB3,0xBF,0xEA,0xD6,0x54,0xD9,0x25,0xFD,0xAA,0x46,0x19,0x86,0x90,0xAF,0xB3,0xEE,0x4D,0x19,0x47,0x12,0x90,0xCE,0x5B,0x75,0xC9,0x5B,0xDA,0x47,0x31,0x14,0xF3,0xD7,0xF9,0xCC,0x77,0xFC,0xFC,0xEF,0xFE,0xE6,0x99,0xC2,0x7C,0x93,0xFE,0xC5,0xDF,0x44,0x08,0x5B,0x75,0x36,0xFF,0xD2,0xC6,0xE2,0x91,0xCE,0xFD,0xDF,0x89,0x9A,0x68,0x3A,0x01,0x4C,0x48,0x2A,0x80,0x5F,0x33,0x34,0x40,0x81,0xFF,0x07};
const uint8_t spSERVICE[] PROGMEM = {0x04,0xF8,0xAD,0x94,0x03,0x1A,0xB0,0x80,0x07,0x2C,0xB0,0xA2,0xE6,0xCD,0xD4,0xB4,0xEB,0xC9,0xAA,0x4D,0xE1,0xD6,0xEC,0x23,0x2B,0xBE,0x85,0x96,0xFD,0xCD,0xBC,0x15,0xB9,0x16,0xE9,0xB0,0xBF,0x51,0x66,0x5F,0x24,0xA3,0x7A,0x53,0x97,0xBD,0x89,0xBB,0xC4,0x52,0x4B,0xB1,0xAE,0xE6,0x9A,0xB9,0xEE,0x63,0xAD,0xCE,0x35,0xD4,0x7A,0xCF,0xA3,0x9F,0xE9,0x2E,0xD2,0x25,0xDD,0x77,0x13,0xE0,0xB7,0x52,0x09,0x48,0xC0,0x02,0x16,0x90,0x00,0x05,0xFE,0x1F};
const uint8_t spSWITCH[] PROGMEM = {0x08,0xF8,0x3B,0x93,0x03,0x1A,0xB0,0x80,0x01,0xAE,0xCF,0x54,0x40,0x33,0x99,0x2E,0xF6,0xB2,0x4B,0x9D,0x52,0xA7,0x36,0xF0,0x2E,0x2F,0x70,0xDB,0xCB,0x93,0x75,0xEE,0xA6,0x4B,0x79,0x4F,0x36,0x4C,0x89,0x34,0x77,0xB9,0xF9,0xAA,0x5B,0x08,0x76,0xF5,0xCD,0x73,0xE4,0x13,0x99,0x45,0x28,0x77,0x11,0xD9,0x40,0x80,0x55,0xCB,0x25,0xE0,0x80,0x59,0x2F,0x23,0xE0,0x01,0x0B,0x08,0xA0,0x46,0xB1,0xFF,0x07};
const uint8_t spVALVE[] PROGMEM = {0x61,0x1F,0x5A,0x58,0x4D,0x9C,0x08,0x60,0x58,0x95,0x32,0x0D,0x2D,0xAC,0x26,0x4E,0x46,0xD7,0x5C,0x58,0x18,0xAF,0x3E,0x6D,0x73,0x6A,0x65,0xF6,0xE4,0x34,0xCD,0xA6,0x97,0xD9,0x93,0x5B,0xDF,0xFA,0x36,0xAB,0xCF,0x6A,0xA3,0x55,0x36,0xEF,0x7E,0xCF,0x63,0x2E,0xF4,0xAA,0x9C,0xFA,0x8C,0xAD,0xC1,0x9E,0x76,0xF2,0xD6,0xF7,0xBA,0xD7,0xA3,0x1C,0x85,0x78,0x76,0xA1,0xFA,0x78,0xC4,0x3B,0xDC,0x91,0x55,0x94,0x70,0x6A,0x7F,0xEB,0x87,0x00,0x55,0xA8,0x70,0x80,0x02,0x14,0xC0,0xC0,0xFF,0x03};
const uint8_t spVAL[] PROGMEM = {0x24,0x4B,0x38,0x2C,0x43,0x13,0xBB,0xEC,0xB8,0xB6,0xD0,0x76,0xBD,0xDA,0x6D,0x4B,0xC5,0xD8,0xF7,0x69,0x9B,0x55,0x2B,0xB3,0x27,0xA7,0x69,0x36,0xAD,0xCC,0x9E,0xDC,0xFA,0xD6,0xB7,0x59,0x7D,0x56,0x1B,0xAD,0xB2,0x79,0xF7,0x73,0x68,0x73,0x0C,0x5D,0xE1,0xD2,0xA6,0xEE,0xF9,0x0C,0x57,0xB0,0x13,0xC1,0x9E,0x36,0x5E,0xEE,0xCE,0x22,0xAC,0xD5,0xE2,0xF8,0xDB,0xDC,0x4D,0x09,0xA5,0x47,0xDC,0x78,0x9B,0xBB,0x7B,0x62,0xB7,0x70,0xF6,0xFF};
const uint8_t spNUMBER[] PROGMEM = {0x66,0xA9,0x12,0x72,0x42,0x9B,0x86,0xA5,0x1B,0x90,0x0E,0x6D,0x76,0xA6,0x26,0x2B,0xDC,0xA5,0xCF,0x6D,0x4F,0x95,0x4D,0xA5,0xBB,0x6E,0x5E,0x45,0x31,0x5E,0x65,0x92,0x66,0x14,0x45,0xAA,0xB4,0x98,0x9D,0x5A,0x84,0x2A,0x18,0xF6,0x92,0x74,0x43,0x3A,0xAD,0x5C,0x27,0xDD,0x6D,0x98,0xA3,0x09,0xF5,0x92,0xA4,0x65,0x4C,0x4D,0xA4,0x82,0x56,0x97,0x39,0x77,0xC7,0x68,0xF1,0x5D,0xD6,0xDC,0x1D,0x63,0xD4,0x4F,0xBE,0xC3,0x9D,0x53,0x81,0x4E,0xF3,0x89,0x9F,0xFF,0xDC,0x5F,0x66,0x92,0xB5,0x7A,0xFE,0x7F};
const uint8_t spOUT[] PROGMEM = {0xAD,0xCF,0xE6,0xDD,0xD3,0x17,0xED,0xFE,0xF4,0x9D,0x4F,0x56,0x71,0x97,0xDB,0xDD,0xEE,0x76,0xA7,0xCF,0xAE,0x6A,0x54,0x5A,0xEF,0x7E,0x0F,0x7B,0x4C,0x6B,0x88,0x95,0x21,0xBC,0xD9,0x6F,0x08,0x14,0xA1,0xDC,0x45,0x64,0x03,0x00,0x08,0xE0,0xE8,0x2E,0x0F,0x50,0xE0,0xFF,0x01};
const uint8_t spPOINT[] PROGMEM = {0x06,0xA8,0xCC,0x4B,0x03,0x2D,0xF3,0x69,0x2B,0x8C,0x1A,0xAF,0x2C,0x98,0xE9,0x28,0x4A,0xB3,0xF3,0x53,0xC6,0x90,0x9E,0xC1,0x6D,0x76,0x77,0xE6,0x9C,0x5D,0xD3,0x75,0xF1,0x58,0x5B,0x75,0x76,0xB7,0x4F,0xE3,0xE8,0xCE,0x31,0x3A,0x17,0xB6,0xB3,0x45,0x96,0xF4,0xAA,0x6D,0x4F,0x75,0x76,0xA3,0x94,0x66,0x6E,0x10,0x28,0x42,0xB9,0x8B,0xC8,0x06,0x50,0xC0,0x32,0x11,0x0A,0x58,0x76,0x87,0x01,0x3D,0xB5,0xFE,0x3F};
const uint8_t spBREAK[] PROGMEM = {0x90,0xC6,0x62,0x2D,0xDC,0xCC,0x76,0xE9,0x63,0x55,0xD3,0x32,0xF5,0xAD,0x4F,0x5D,0x42,0x53,0xF5,0x9D,0xB6,0x14,0x49,0x0D,0xCD,0x73,0xEA,0x5A,0x4C,0xC3,0x6D,0xF3,0x69,0x7A,0x0B,0x52,0x8D,0x25,0xBB,0x9D,0x8B,0xDB,0xC7,0x13,0x90,0x8A,0xC7,0x08,0x14,0xA1,0xDC,0x45,0x64,0x03,0x00,0x03,0xC6,0xA8,0x14,0x40,0xCD,0x4A,0x16,0xE0,0x00,0x06,0xFE,0x1F};
const uint8_t spHOURS[] PROGMEM = {0x63,0xC9,0x66,0xA2,0xCC,0x57,0x9F,0xB1,0xF1,0xCE,0x6E,0xEE,0x72,0xBB,0xD3,0x24,0x3B,0x99,0x49,0x79,0x6E,0x35,0x2A,0x1F,0x27,0xBD,0xC8,0x4B,0x69,0x4D,0xDA,0xB0,0x54,0x2E,0x65,0xB0,0x65,0x34,0x43,0xF8,0x96,0x31,0x75,0xA5,0x6E,0xEA,0x53,0xD7,0x7C,0xA4,0x27,0xD7,0x00,0x6F,0xD7,0x1B,0x1F,0xFF,0xB8,0xB7,0x26,0x16,0x49,0xEB,0xE6,0x5F,0xF7,0x56,0x2B,0x62,0xEA,0xEB,0xDC,0xDB,0x83,0xB2,0x9A,0x74,0x73,0xEF,0x76,0x9E,0xC4,0xAA,0xDE,0x7D,0xBF,0x87,0xA6,0xA0,0x52,0x06,0x7C,0x4B,0x24,0x01,0x09,0x70,0xE0,0xFF,0x01};
const uint8_t spCALIBRATE[] PROGMEM = {0x0E,0x18,0xC9,0xD9,0x01,0x55,0x29,0x9E,0xA0,0x16,0x97,0x70,0x5F,0x7C,0xB2,0xAA,0xDB,0x2B,0x79,0xCD,0xCD,0x56,0x51,0xC9,0x54,0x0D,0x26,0x1E,0x45,0xC3,0x55,0xDE,0xE2,0xF8,0x54,0xC5,0x94,0xA7,0x73,0x97,0xDB,0x94,0x3E,0xE9,0x52,0x2F,0xF6,0xC2,0x16,0xA9,0x4B,0xB3,0xCC,0x5E,0xD8,0xAA,0x34,0x31,0x73,0x27,0xE5,0x4C,0x8D,0xC3,0xD3,0xF4,0xF6,0xA9,0x2F,0xEB,0xA8,0x2E,0x39,0x42,0xFB,0x8E,0xAB,0x99,0xA4,0x28,0xFF,0x5C,0xEE,0x69,0x97,0x28,0x7D,0x4F,0x7D,0xD2,0xDF,0xAB,0x92,0x98,0x6F,0x41,0x8F,0x08,0xE5,0x2E,0x22,0x1B,0x00,0x18,0xB0,0x42,0xA4,0x02,0x5E,0xA8,0x26,0xC0,0xF0,0xE7,0xFF,0x0F};
const uint8_t spCRANE[] PROGMEM = {0x0A,0xC8,0xBD,0xD5,0x03,0x16,0x50,0x40,0x5E,0x15,0x23,0x4F,0x5D,0xCC,0x87,0xB3,0xAE,0xA2,0xE4,0x64,0x1D,0x73,0x7F,0x8A,0x9A,0x9B,0xB5,0xA5,0xEB,0x29,0x7A,0x4D,0x36,0xB7,0x45,0xB7,0x58,0xF5,0x28,0x8E,0xDA,0x31,0x69,0x77,0x7B,0x98,0x73,0x5F,0xEA,0x1A,0xF6,0x1E,0x99,0xB3,0x62,0x74,0xB8,0xBA,0x47,0x73,0x4F,0xA7,0xF1,0x0A,0x77,0x4F,0xE4,0x2A,0xEE,0xD5,0x3D,0xCD,0x91,0x86,0x86,0xBB,0xF0,0x8C,0xC8,0x6C,0x9A,0xCE,0xFE,0x1F};
const uint8_t spDIRECTION[] PROGMEM = {0xA5,0x7E,0xBE,0x3C,0x49,0x14,0xAF,0x6E,0xAA,0x52,0x72,0xCD,0x77,0xBA,0x66,0x4A,0x38,0xAC,0xDB,0xE9,0x8A,0x0F,0xB6,0xB0,0xF4,0xAD,0x4B,0x5D,0xDC,0x35,0xED,0xCF,0xF6,0xD4,0xA5,0x68,0xB8,0x85,0xFB,0x53,0xD6,0x90,0x34,0x1E,0x9D,0x6E,0x31,0xF2,0x36,0x9D,0x4A,0x6C,0x91,0xC9,0x47,0x18,0x63,0xD1,0xD8,0x02,0xE8,0xC1,0xCC,0x01,0x63,0x6C,0x45,0x20,0x02,0x1E,0x68,0x45,0x8D,0xAA,0x6E,0xD1,0x69,0x36,0x63,0x69,0x81,0x2D,0x25,0x9A,0xD4,0x23,0x1D,0x5D,0x0B,0xA5,0x7B,0xB4,0x78,0xF9,0xDB,0x7D,0x23,0x18,0xB9,0x58,0x7C,0xFF,0xBB,0xAF,0x19,0xC1,0x54,0x4B,0xF6,0xFF};
const uint8_t spENTER[] PROGMEM = {0xAB,0x18,0xB6,0x39,0xDC,0x5E,0xDD,0xFA,0x96,0xAB,0xE8,0x41,0x24,0xC9,0x17,0xE5,0x0A,0x0C,0x70,0x4C,0x65,0xE9,0x4A,0x37,0xCC,0xE4,0xDE,0xB3,0x6F,0x73,0xA9,0x0D,0x36,0x9C,0x37,0xEF,0xE9,0xCA,0x35,0xA0,0x5A,0xFA,0x94,0xB7,0xD4,0xC4,0x48,0xC9,0x93,0xBF,0xFF,0x07};
const uint8_t spFEET[] PROGMEM = {0x08,0x98,0x31,0x93,0x02,0x1C,0xE0,0x80,0x07,0x5A,0x3E,0x4A,0x28,0x99,0x3F,0x59,0xE9,0xE8,0x4E,0x64,0xFE,0x64,0x67,0xA3,0x98,0x45,0x41,0xB2,0x67,0xF7,0x36,0x4F,0x6A,0x9F,0x9D,0x91,0xB3,0x6E,0xA3,0x7B,0xCA,0x30,0x53,0x95,0x03,0x00,0x00,0x08,0x18,0xD2,0x4D,0x00,0xC7,0x6C,0x6A,0x40,0x00,0x3D,0xAC,0x62,0xE0,0xFF,0x01};
const uint8_t spFROM[] PROGMEM = {0x04,0x18,0x26,0x8D,0x03,0x12,0xF0,0x80,0xAB,0x42,0x57,0x8B,0x61,0x6F,0xAB,0x4C,0xCE,0x2B,0xD2,0xD4,0xDD,0xE2,0x96,0xA7,0xCC,0x72,0xCA,0x93,0xDB,0xEC,0x6A,0xB7,0x73,0x68,0x4B,0xA7,0x61,0xA1,0x6C,0xB6,0xAF,0xF9,0x88,0x47,0x3C,0xFD,0xF3,0xFF};
const uint8_t spGAP[] PROGMEM = {0x0C,0x08,0xDA,0x75,0x2C,0xB3,0x27,0x19,0xBB,0xDD,0xD1,0xB7,0x44,0xE4,0x51,0x73,0x4E,0x3B,0x7A,0x90,0x49,0x2C,0x39,0x75,0x77,0xAD,0x66,0xB6,0xE6,0x56,0xA7,0xAA,0x31,0x25,0x2D,0xD7,0xEC,0x61,0x2E,0x71,0x41,0xA0,0x08,0xE5,0x2E,0x22,0x1B,0x00,0x00,0x01,0x5D,0x85,0x29,0xE0,0x88,0x76,0x05,0x4C,0xF7,0xCE,0x80,0xEE,0x9B,0x29,0xF0,0xFF};
const uint8_t spHOLD[] PROGMEM = {0x08,0x68,0x34,0x5A,0x03,0x06,0x98,0x42,0xCC,0x02,0x23,0x4F,0x7C,0xD6,0x85,0xDA,0xAC,0xAC,0xE2,0xD8,0x32,0x4C,0xD3,0xF2,0x8C,0xF3,0x9C,0xA9,0x4B,0xCF,0x5A,0x51,0x91,0xEE,0x04,0xBA,0xEB,0x55,0xED,0xCB,0x12,0x85,0x6F,0x0A,0xBB,0xCB,0x6B,0xDC,0xE3,0x61,0x0F,0x73,0x65,0x41,0xAB,0x6A,0x69,0xCC,0x95,0x04,0x75,0x93,0xA7,0x35,0x67,0xD3,0x28,0xE3,0x9A,0x56,0x5D,0x85,0x93,0x65,0x68,0xB6,0x74,0x55,0x63,0xE6,0x62,0x6B,0xDC,0x59,0x2D,0x87,0xBB,0x3F,0xF9,0x7F};
const uint8_t spLEFT[] PROGMEM = {0x69,0x1D,0xC0,0xDA,0xCC,0xD3,0xA6,0xB5,0x81,0x68,0xD1,0xF4,0xDA,0xC7,0xD3,0x57,0x6F,0x11,0xDC,0x4B,0x6E,0x73,0x9A,0xE6,0x5D,0x5B,0x72,0xF5,0xED,0xF7,0xD2,0xCE,0x92,0x2C,0x5C,0xEA,0x0D,0x03,0x8A,0x0E,0x25,0xC0,0x74,0xE3,0x12,0xD0,0x80,0x04,0x10,0x90,0x89,0x2B,0x08,0x60,0x8B,0x71,0x0B,0x10,0xA0,0xB5,0xF3,0xFF,0x07};
const uint8_t spMILL[] PROGMEM = {0x66,0x8E,0x8A,0xA2,0xC2,0x93,0xFA,0x29,0x8E,0xB9,0x1B,0x6D,0x4B,0xA6,0x26,0xF9,0xE4,0xD6,0xB7,0xBA,0xD5,0x6A,0xAB,0x4C,0x6B,0xD5,0xC7,0x6B,0x28,0xA4,0xB3,0x8D,0xFB,0xCC,0xB9,0xEC,0x05,0x75,0x97,0x61,0xDE,0xBA,0xE7,0x33,0x5D,0x0D,0x47,0x4D,0x80,0x97,0x78,0x9B,0xC7,0xEA,0xA9,0x62,0xED,0xFC,0xFF};
const uint8_t spUH[] PROGMEM = {0x63,0x2A,0xAC,0x2B,0x8D,0xF7,0xEC,0xF1,0xB6,0xB7,0xDD,0xDD,0xEC,0xC7,0x5A,0x58,0x55,0x39,0xF5,0x9E,0x6B,0x3D,0xD3,0x59,0xB8,0x67,0x39,0xEE,0x8A,0x77,0x7A,0xAB,0x54,0x6F,0xC7,0x4C,0xF6,0x91,0xCF,0xFF,0x03};
const uint8_t spPAST[] PROGMEM = {0x0A,0x88,0x29,0x4C,0x02,0x25,0xAB,0x4E,0xB4,0xCC,0x6B,0x9E,0x22,0x47,0x89,0xF2,0xAA,0x7C,0xEA,0x1A,0xDC,0x3A,0xED,0xCE,0xAD,0x6F,0x77,0x87,0x3B,0xCF,0x7D,0x9C,0xD5,0xBA,0x75,0xEA,0xE2,0x7E,0xB5,0xAB,0x05,0x8D,0x96,0x5C,0xE2,0xCE,0x3E,0x39,0x93,0xCA,0x0D,0x03,0xBE,0x37,0xD5,0x80,0x05,0x3C,0x60,0x01,0x0D,0x00,0x02,0x9E,0xE7,0xB0,0x80,0x00,0xA6,0x5E,0x47,0x40,0x1D,0x4B,0xFF,0x0F};
const uint8_t spPRESS[] PROGMEM = {0x02,0x28,0x31,0x43,0x03,0x25,0xCB,0xBE,0xDC,0x5D,0xED,0x94,0x22,0x0E,0xCE,0x70,0xC9,0xBD,0xF2,0x9C,0xD5,0xBD,0x24,0xEF,0xC9,0xAB,0x77,0xF5,0x92,0x3E,0x27,0x6B,0xA1,0x25,0xD5,0x56,0xDF,0xEC,0x34,0x5D,0xA7,0x94,0xF9,0xEB,0x3B,0xEC,0x69,0xEE,0x75,0x15,0xC0,0x57,0xC1,0x02,0xF8,0x3D,0x5D,0x02,0x1A,0xD0,0x80,0x04,0x28,0x80,0x81,0xFF,0x07};
const uint8_t spRANGE[] PROGMEM = {0x6C,0xE7,0xA5,0xD9,0x33,0xAD,0xAA,0x4D,0xF7,0xC0,0x6C,0x93,0xEA,0x66,0x3F,0x95,0x3A,0xD5,0x79,0xEB,0x62,0x17,0x69,0x0B,0xE7,0xAB,0x29,0x45,0x8A,0x4B,0xBD,0x9E,0xBA,0x17,0x63,0xB7,0x58,0x7D,0xAB,0x5B,0xAD,0x7A,0x94,0x00,0xAB,0x9C,0xB5,0xBB,0x39,0xCC,0xB9,0xAF,0x75,0x4F,0x7B,0x8F,0x10,0xEE,0x69,0x27,0x9C,0x3D,0x93,0xA4,0x79,0x5C,0x7F,0x87,0xB7,0x7B,0xE6,0x30,0x8B,0xE7,0x5F,0xF3,0x54,0xCD,0x92,0xA1,0x75,0xFC,0xC3,0x80,0x51,0x9C,0x24,0x60,0x01,0x01,0x8C,0xEC,0xF4,0xFF};
const uint8_t spSAFE[] PROGMEM = {0x08,0xF8,0x39,0x4C,0x02,0x1A,0xD0,0x80,0x05,0x3C,0x60,0x81,0x95,0x0F,0x15,0xE2,0x6A,0xAB,0x4F,0xD1,0x43,0x8A,0x8A,0xBF,0xB9,0xD5,0xAD,0x57,0x3F,0xAA,0x23,0xBB,0x3F,0x9E,0xCB,0xDC,0xF3,0x99,0x9E,0x5E,0x19,0xCD,0xEB,0x8E,0x79,0x7A,0x43,0x13,0xED,0x39,0x0C,0x18,0x7E,0x5C,0x02,0x12,0x90,0x00,0x07,0x28,0x40,0x81,0xFF,0x07};
const uint8_t spSOUTH[] PROGMEM = {0x08,0xF8,0x2E,0x8C,0x03,0x0C,0xF8,0xB5,0xCD,0x02,0x16,0x50,0xC0,0x6F,0xA5,0x1E,0x50,0xC0,0x37,0xEE,0x23,0x69,0xCA,0x35,0x55,0x57,0xAF,0xA2,0xD8,0x8E,0x16,0x5D,0x7D,0xEB,0xDB,0xDC,0x76,0xF5,0xC9,0x4C,0x95,0x71,0xEF,0x3D,0xCD,0xBD,0x9C,0xC1,0x75,0x95,0x72,0x97,0xFC,0x84,0x3F,0xAA,0xAE,0x31,0xF1,0x2D,0x5E,0x5B,0x72,0x9C,0x62,0xB5,0xF9,0x92,0x8E,0x18,0x93,0xC4,0x04,0x18,0xB2,0x45,0x02,0x1C,0xA0,0x00,0x05,0x28,0x40,0x81,0xFF,0x07};
const uint8_t spTURN[] PROGMEM = {0x01,0x18,0xA9,0xCC,0x02,0x06,0x28,0x4E,0xA9,0x14,0x39,0x25,0x69,0x4B,0xBA,0x5D,0xAE,0xAA,0x84,0x15,0x5A,0xF5,0xBE,0xAB,0x59,0xCF,0x61,0xCE,0x7D,0x6B,0x5B,0x09,0x49,0x76,0xEE,0xB5,0x1E,0xE5,0x69,0x2E,0x44,0xD3,0x9A,0xE6,0x27,0x7C,0x4D,0x09,0xA5,0x47,0xDC,0xF8,0xB9,0xAF,0x7B,0x62,0xB7,0x70,0xE6,0xBE,0x1A,0x54,0x4C,0xB8,0xDD,0xFF,0x03};
const uint8_t spYELLOW[] PROGMEM = {0x69,0xBD,0x56,0x15,0xAC,0x67,0xE5,0xA5,0xCC,0x2B,0x8E,0x82,0xD8,0xD6,0x39,0x9E,0xAE,0x85,0x50,0x37,0x5F,0x7D,0xEB,0x53,0x55,0x1B,0xDE,0xA6,0x6B,0x56,0x5D,0x74,0x47,0x2B,0x77,0x6E,0x75,0x87,0x59,0x95,0xA4,0x76,0x76,0x6B,0xCE,0xA2,0xB3,0x4C,0xF2,0xCF,0xBD,0xED,0xC9,0x54,0xB6,0x52,0x9F,0x7E,0xA5,0xDB,0xC7,0xCA,0x46,0x5D,0x13,0xEF,0xF8,0x84,0x37,0xA8,0xA9,0x0C,0xF2,0xE3,0xBE,0x24,0xC6,0x2B,0x48,0xDF,0xFF,0x03};
void setup() {
// NOTE: if not using PWM out, it should be held low to avoid tx noise
pinMode(MIC_PIN, OUTPUT);
digitalWrite(MIC_PIN, HIGH);
// prep the switch
pinMode(SWITCH_PIN, INPUT_PULLUP);
// set up the reset control pin
// NOTE: HamShieldMini doesn't have a reset pin, so this has no effect
pinMode(RESET_PIN, OUTPUT);
digitalWrite(RESET_PIN, HIGH);
delay(5); // wait for device to come up
Serial.begin(9600);
Serial.println("If the sketch freezes at radio status, there is something wrong with power or the shield");
Serial.print("Radio status: ");
int result = radio.testConnection();
Serial.println(result,DEC);
Serial.println("Setting radio to its defaults..");
radio.initialize();
radio.setRfPower(0);
radio.frequency(145010);
}
void loop() {
radio.waitForChannel(); // wait for the channel to be empty
radio.setModeTransmit();
delay(100); // wait for PA to come up
voice.say(spKILO); // to change these to the words you would like to say, or a ham radio call sign - uncomment above encoded words
voice.say(spSIX); // more word choices can be found at the talkie github site
voice.say(spALPHA);
voice.say(spTANGO);
voice.say(spVICTOR);
delay(2000);
voice.say(spDANGER);
voice.say(spDANGER);
voice.say(spMOTOR);
voice.say(spIS);
voice.say(spON);
voice.say(spFIRE);
radio.setModeReceive();
delay(10000);
}

661
extras/LICENSE Normal file
View File

@ -0,0 +1,661 @@
GNU AFFERO GENERAL PUBLIC LICENSE
Version 3, 19 November 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU Affero General Public License is a free, copyleft license for
software and other kinds of works, specifically designed to ensure
cooperation with the community in the case of network server software.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
our General Public Licenses are intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
Developers that use our General Public Licenses protect your rights
with two steps: (1) assert copyright on the software, and (2) offer
you this License which gives you legal permission to copy, distribute
and/or modify the software.
A secondary benefit of defending all users' freedom is that
improvements made in alternate versions of the program, if they
receive widespread use, become available for other developers to
incorporate. Many developers of free software are heartened and
encouraged by the resulting cooperation. However, in the case of
software used on network servers, this result may fail to come about.
The GNU General Public License permits making a modified version and
letting the public access it on a server without ever releasing its
source code to the public.
The GNU Affero General Public License is designed specifically to
ensure that, in such cases, the modified source code becomes available
to the community. It requires the operator of a network server to
provide the source code of the modified version running there to the
users of that server. Therefore, public use of a modified version, on
a publicly accessible server, gives the public access to the source
code of the modified version.
An older license, called the Affero General Public License and
published by Affero, was designed to accomplish similar goals. This is
a different license, not a version of the Affero GPL, but Affero has
released a new version of the Affero GPL which permits relicensing under
this license.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU Affero General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Remote Network Interaction; Use with the GNU General Public License.
Notwithstanding any other provision of this License, if you modify the
Program, your modified version must prominently offer all users
interacting with it remotely through a computer network (if your version
supports such interaction) an opportunity to receive the Corresponding
Source of your version by providing access to the Corresponding Source
from a network server at no charge, through some standard or customary
means of facilitating copying of software. This Corresponding Source
shall include the Corresponding Source for any work covered by version 3
of the GNU General Public License that is incorporated pursuant to the
following paragraph.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the work with which it is combined will remain governed by version
3 of the GNU General Public License.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU Affero General Public License from time to time. Such new versions
will be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU Affero General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU Affero General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU Affero General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If your software can interact with users remotely through a computer
network, you should also make sure that it provides a way for users to
get its source. For example, if your program is a web application, its
interface could display a "Source" link that leads users to an archive
of the code. There are many ways you could offer source, and different
solutions will be better for different programs; see section 13 for the
specific requirements.
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU AGPL, see
<http://www.gnu.org/licenses/>.

10
library.properties Normal file
View File

@ -0,0 +1,10 @@
name=HamShield
version=1.1.4
author=Morgan Redfield <morgan@enhancedradio.com>, Casey Halverson <casey@enhancedradio.com>
maintainer=Morgan Redfield <morgan@enhancedradio.com>
sentence=A library for use with HamShield by Enhanced Radio Devices.
paragraph=
category=Device Control
url=http://www.hamshield.com
architectures=*
includes=HamShield.h

2035
src/HamShield.cpp Normal file

File diff suppressed because it is too large Load Diff

574
src/HamShield.h Normal file
View File

@ -0,0 +1,574 @@
// HamShield library collection
// Based on Programming Manual rev. 2.0, 5/19/2011 (RM-MPU-6000A-00)
// 11/22/2013 by Morgan Redfield <redfieldm@gmail.com>
// 04/26/2015 various changes Casey Halverson <spaceneedle@gmail.com>
// 05/08/2017 CTCSS code added
#ifndef _HAMSHIELD_H_
#define _HAMSHIELD_H_
#include "HamShield_comms.h"
// HamShield constants
#define HAMSHIELD_MORSE_BUFFER_SIZE 80 // Char buffer size for morse code text
#define HAMSHIELD_EMPTY_CHANNEL_RSSI -110 // Default threshold where channel is considered "clear"
// Device Registers
#define A1846S_CTL_REG 0x30 // control register
#define A1846S_CLK_MODE_REG 0x04 // clk_mode
#define A1846S_PABIAS_REG 0x0A // control register for bias voltage
//#define A1846S_BAND_SEL_REG 0x0F // band_sel register <1:0>
#define A1846S_FLAG_REG 0x1C
#define A1846S_GPIO_MODE_REG 0x1F // GPIO mode select register
#define A1846S_FREQ_HI_REG 0x29 // freq<29:16>
#define A1846S_FREQ_LO_REG 0x2A // freq<15:0>
//#define A1846S_XTAL_FREQ_REG 0x2B // xtal_freq<15:0>
//#define A1846S_ADCLK_FREQ_REG 0x2C // adclk_freq<15:0>
#define A1846S_INT_MODE_REG 0x2D // interrupt enables
#define A1846S_TX_VOICE_REG 0x3A // tx voice control reg
#define A1846S_TH_H_VOX_REG 0x64 // register holds vox high (open) threshold bits
#define A1846S_TH_L_VOX_REG 0x64 // register holds vox low (shut) threshold bits
#define A1846S_FM_DEV_REG 0x43 // register holds fm deviation settings
#define A1846S_RX_VOLUME_REG 0x44 // register holds RX volume settings
#define A1846S_SQ_OPEN_THRESH_REG 0x49 // see sq
#define A1846S_SQ_SHUT_THRESH_REG 0x49 // see sq
#define A1846S_CTCSS_FREQ_REG 0x4A // ctcss_freq<15:0>
#define A1846S_CDCSS_CODE_HI_REG 0x4B // cdcss_code<23:16>
#define A1846S_CDCSS_CODE_LO_REG 0x4C // cdccs_code<15:0>
#define A1846S_CTCSS_MODE_REG 0x4e // see ctcss
#define A1846S_SQ_OUT_SEL_REG 0x54 // see sq
#define A1846S_FILTER_REG 0x58
#define A1846S_CTCSS_THRESH_REG 0x5B
#define A1846S_RSSI_REG 0x1B // holds RSSI (unit 1dB)
#define A1846S_VSSI_REG 0x1A // holds VSSI (unit mV)
#define A1846S_DTMF_ENABLE_REG 0x7A // holds dtmf_enable
#define A1846S_DTMF_CODE_REG 0x7E // holds dtmf_sample and dtmf_code
#define A1846S_TONE1_FREQ 0x35 // holds frequency of tone 1 (in 0.1Hz increments)
#define A1846S_TONE2_FREQ 0x36 // holds frequency of tone 2 (in 0.1Hz increments)
#define A1846S_DTMF_TIME_REG 0x7B // holds time intervals for DTMF
// Device Bit Fields
// Bitfields for A1846S_CTL_REG
#define A1846S_CHAN_MODE_BIT 13 //channel_mode<1:0>
#define A1846S_CHAN_MODE_LENGTH 2
#define A1846S_TAIL_ELIM_EN_BIT 11 // enables tail elim when set to 1
#define A1846S_ST_MODE_BIT 9 // set mode for txon and rxon
#define A1846S_ST_MODE_LENGTH 2
#define A1846S_MUTE_BIT 7 // 0 no mute, 1 mute when rxno
#define A1846S_TX_MODE_BIT 6 //tx-on
#define A1846S_RX_MODE_BIT 5 //rx-on
#define A1846S_VOX_ON_BIT 4 // 0 off, 1 on and chip auto-vox
#define A1846S_SQ_ON_BIT 3 // auto sq enable bit
#define A1846S_PWR_DWN_BIT 2 // power control bit
#define A1846S_CHIP_CAL_EN_BIT 1 // 0 cal disable, 1 cal enable
#define A1846S_SOFT_RESET_BIT 0 // 0 normal value, 1 reset all registers to normal value
// Bitfields for A1846S_CLK_MODE_REG
#define A1846S_CLK_MODE_BIT 0 // 0 24-28MHz, 1 12-14MHz
// Bitfields for A1846S_PABIAS_REG
#define A1846S_PABIAS_BIT 5 // pabias_voltage<5:0>
#define A1846S_PABIAS_LENGTH 6
#define A1846S_PADRV_BIT 14 // pabias_voltage<14:11>
#define A1846S_PADRV_LENGTH 4
// Bitfields for A1846S_BAND_SEL_REG
//#define A1846S_BAND_SEL_BIT 7 // band_sel<1:0>
//#define A1846S_BAND_SEL_LENGTH 2
// Bitfields for A1846_GPIO_MODE_REG
#define A1846S_GPIO7_MODE_BIT 15 // <1:0> 00=hi-z,01=vox,10=low,11=hi
#define A1846S_GPIO7_MODE_LENGTH 2
#define A1846S_GPIO6_MODE_BIT 13 // <1:0> 00=hi-z,01=sq or =sq&ctcss/cdcss when sq_out_sel=1,10=low,11=hi
#define A1846S_GPIO6_MODE_LENGTH 2
#define A1846S_GPIO5_MODE_BIT 11 // <1:0> 00=hi-z,01=txon_rf,10=low,11=hi
#define A1846S_GPIO5_MODE_LENGTH 2
#define A1846S_GPIO4_MODE_BIT 9 // <1:0> 00=hi-z,01=rxon_rf,10=low,11=hi
#define A1846S_GPIO4_MODE_LENGTH 2
#define A1846S_GPIO3_MODE_BIT 7 // <1:0> 00=hi-z,01=sdo,10=low,11=hi
#define A1846S_GPIO3_MODE_LENGTH 2
#define A1846S_GPIO2_MODE_BIT 5 // <1:0> 00=hi-z,01=int,10=low,11=hi
#define A1846S_GPIO2_MODE_LENGTH 2
#define A1846S_GPIO1_MODE_BIT 3 // <1:0> 00=hi-z,01=code_out/code_in,10=low,11=hi
#define A1846S_GPIO1_MODE_LENGTH 2
#define A1846S_GPIO0_MODE_BIT 1 // <1:0> 00=hi-z,01=css_out/css_in/css_cmp,10=low,11=hi
#define A1846S_GPIO0_MODE_LENGTH 2
// Bitfields for A1846S_INT_MODE_REG
#define A1846S_CSS_CMP_INT_BIT 9 // css_cmp_uint16_t enable
#define A1846S_RXON_RF_INT_BIT 8 // rxon_rf_uint16_t enable
#define A1846S_TXON_RF_INT_BIT 7 // txon_rf_uint16_t enable
#define A1846S_CTCSS_PHASE_INT_BIT 5 // ctcss phase shift detect uint16_t enable
#define A1846S_IDLE_TIMEOUT_INT_BIT 4 // idle state time out uint16_t enable
#define A1846S_RXON_RF_TIMEOUT_INT_BIT 3 // rxon_rf timerout uint16_t enable
#define A1846S_SQ_INT_BIT 2 // sq uint16_t enable
#define A1846S_TXON_RF_TIMEOUT_INT_BIT 1 // txon_rf time out uint16_t enable
#define A1846S_VOX_INT_BIT 0 // vox uint16_t enable
// Bitfields for A1846S_TX_VOICE_REG
#define A1846S_VOICE_SEL_BIT 14 //voice_sel<1:0>
#define A1846S_VOICE_SEL_LENGTH 3
#define A1846S_CTCSS_DET_BIT 5
// Bitfields for A1846S_TH_H_VOX_REG
#define A1846S_TH_H_VOX_BIT 13 // th_h_vox<13:7>
#define A1846S_TH_H_VOX_LEN 7
// Bitfields for A1846S_TH_L_VOX_REG
#define A1846S_TH_L_VOX_BIT 6 // th_l_vox<6:0>
#define A1846S_TH_L_VOX_LEN 7
// Bitfields for A1846S_FM_DEV_REG
#define A1846S_FM_DEV_VOICE_BIT 12 // CTCSS/CDCSS and voice deviation <6:0>
#define A1846S_FM_DEV_VOICE_LENGTH 7
#define A1846S_FM_DEV_CSS_BIT 5 // CTCSS/CDCSS deviation only <5:0>
#define A1846S_FM_DEV_CSS_LENGTH 6
// Bitfields for A1846S_RX_VOLUME_REG
#define A1846S_RX_VOL_1_BIT 7 // volume 1 <3:0>, (0000)-15dB~(1111)0dB, step 1dB
#define A1846S_RX_VOL_1_LENGTH 4
#define A1846S_RX_VOL_2_BIT 3 // volume 2 <3:0>, (0000)-15dB~(1111)0dB, step 1dB
#define A1846S_RX_VOL_2_LENGTH 4
// Bitfields for Sub Audio Bits
#define A1846S_CTDCSS_OUT_SEL_BIT 5
#define A1846S_CTDCSS_DTEN_BIT 4
#define A1846S_CTDCSS_DTEN_LEN 5
#define A1846S_CDCSS_SEL_BIT 6 // cdcss_sel
#define A1846S_CDCSS_INVERT_BIT 6 // cdcss_sel
#define A1846S_SHIFT_SEL_BIT 15
#define A1846S_SHIFT_SEL_LEN 2
// Bitfields for A1846S_SQ_THRESH_REG
#define A1846S_SQ_OPEN_THRESH_BIT 13 // sq open threshold <6:0>
#define A1846S_SQ_OPEN_THRESH_LENGTH 7
// Bitfields for A1846S_SQ_SHUT_THRESH_REG
#define A1846S_SQ_SHUT_THRESH_BIT 6 // sq shut threshold <6:0>
#define A1846S_SQ_SHUT_THRESH_LENGTH 7
// Bitfields for A1846S_SQ_OUT_SEL_REG
#define A1846S_SQ_OUT_SEL_BIT 7 // sq_out_sel
// Bitfields for A1846S_FILTER_REG
#define A1846S_VXHPF_FILTER_EN 11
#define A1846S_VXLPF_FILTER_EN 12
#define A1846S_EMPH_FILTER_EN 7
#define A1846S_VHPF_FILTER_EN 6
#define A1846S_VLPF_FILTER_EN 5
#define A1846S_CTCSS_FILTER_BYPASS 3
// Bitfields for A1846S_FLAG_REG
#define A1846S_CTCSS1_FLAG_BIT 9 // 1 when rxon is enabled
#define A1846S_CTCSS2_FLAG_BIT 8 // 1 when txon is enabled
#define A1846S_INVERT_DET_FLAG_BIT 7 // ctcss phase shift detect
#define A1846S_CSS_CMP_FLAG_BIT 2 // ctcss/cdcss compared
#define A1846S_SQ_FLAG_BIT 0 // sq final signal out from dsp
#define A1846S_VOX_FLAG_BIT 1 // vox out from dsp
// Bitfields for A1846S_RSSI_REG
#define A1846S_RSSI_BIT 15 // RSSI readings <7:0>
#define A1846S_RSSI_LENGTH 8
// Bitfields for A1846S_VSSI_REG
#define A1846S_VSSI_BIT 15 // voice signal strength indicator <7:0> (unit 0.5dB)
#define A1846S_VSSI_LENGTH 8
#define A1846S_MSSI_BIT 7 // mic signal strength <7:0> (unit 0.5 dB)
#define A1846S_MSSI_LENGTH 8
// Bitfields for A1846S_DTMF_ENABLE_REG
#define A1846S_DTMF_ENABLE_BIT 15
#define A1846S_TONE_DETECT 14
#define A18462_DTMF_DET_TIME_BIT 7
#define A18462_DTMF_DET_TIME_LEN 8
// Bitfields for A1846S_DTMF_SAMPLE_REG
#define A1846S_DTMF_SAMPLE_BIT 4
#define A1846S_DTMF_CODE_BIT 3
#define A1846S_DTMF_CODE_LEN 4
#define A1846S_DTMF_TX_IDLE_BIT 5
// Bitfields for A1846S_DTMF_TIME_REG
#define A1846S_DUALTONE_TX_TIME_BIT 5 // duration of dual tone TX (via DTMF) in 2.5ms increments
#define A1846S_DUALTONE_TX_TIME_LEN 6
#define A1846S_DTMF_IDLE_TIME_BIT 11
#define A1846S_DTMF_IDLE_TIME_LEN 6
// SSTV VIS Codes
#define ROBOT8BW 2
#define SC2_180 55
#define MARTIN1 44
// RTTY Frequencies
#define HAMSHIELD_RTTY_FREQ 2200
#define HAMSHIELD_RTTY_SHIFT 850
#define HAMSHIELD_RTTY_BAUD 75
// PSK31 Frequencies
#define HAMSHIELD_PSK31_FREQ 1000
// Morse Configuration
#define MORSE_FREQ 600
#define MORSE_DOT 150 // ms
#define SYMBOL_END_TIME 5 //millis
#define CHAR_END_TIME (MORSE_DOT*2.7)
#define MESSAGE_END_TIME (MORSE_DOT*8)
#define MIN_DOT_TIME (MORSE_DOT-30)
#define MAX_DOT_TIME (MORSE_DOT+55)
#define MIN_DASH_TIME (MORSE_DOT*3-30)
#define MAX_DASH_TIME (MORSE_DOT*3+55)
class HamShield {
public:
HamShield(uint8_t ncs_pin = nCS, uint8_t clk_pin = CLK, uint8_t dat_pin = DAT, uint8_t mic_pin = MIC);
void initialize(); // defaults to 12.5kHz
void initialize(bool narrowBand); // select 12.5kHz if true or 25kHz if false
void setupWideBand();
void setupNarrowBand();
bool testConnection();
// read control reg
uint16_t readCtlReg();
void softReset();
// restrictions control
void dangerMode();
void safeMode();
bool frequency(uint32_t freq_khz);
bool frequency_float(float freq_khz);
uint32_t getFrequency();
float getFrequency_float();
/* ToDo
// channel mode
// 11 - 25kHz channel
// 00 - 12.5kHz channel
// 10,01 - reserved
void setChanMode(uint16_t mode);
uint16_t getChanMode();
*/
void setModeTransmit(); // turn off rx, turn on tx
void setModeReceive(); // turn on rx, turn off tx
void setModeOff(); // turn off rx, turn off tx, set pwr_dwn bit
// set tx source
// 00 - Mic source
// 01 - sine source from tone2
// 10 - tx code from GPIO1 code_in (gpio1<1:0> must be set to 01)
// 11 - no tx source
void setTxSource(uint16_t tx_source);
void setTxSourceMic();
void setTxSourceTone1();
void setTxSourceTone2();
void setTxSourceTones();
void setTxSourceNone();
uint16_t getTxSource();
/*
// PA bias voltage is unused (maybe remove this)
// set PA_bias voltage
// 000000: 1.01V
// 000001:1.05V
// 000010:1.09V
// 000100: 1.18V
// 001000: 1.34V
// 010000: 1.68V
// 100000: 2.45V
// 1111111:3.13V
void setPABiasVoltage(uint16_t voltage);
uint16_t getPABiasVoltage();
*/
// Subaudio settings
// Ctcss/cdcss mode sel
void setCtcssCdcssMode(uint16_t mode);
uint16_t getCtcssCdcssMode();
void setDetPhaseShift();
void setDetInvertCdcss();
void setDetCdcss();
void setDetCtcss();
void disableCtcssCdcss();
// ctcss settings
void setCtcss(float freq_Hz);
void setCtcssFreq(uint16_t freq_milliHz);
uint16_t getCtcssFreqMilliHz();
float getCtcssFreqHz();
void setCtcssFreqToStandard(); // freq must be 134.4Hz for standard cdcss mode
void enableCtcssTx();
void enableCtcssRx();
void enableCtcss();
void disableCtcssTx();
void disableCtcssRx();
void disableCtcss();
void setCtcssDetThreshIn(uint8_t thresh);
uint8_t getCtcssDetThreshIn();
void setCtcssDetThreshOut(uint8_t thresh);
uint8_t getCtcssDetThreshOut();
bool getCtcssToneDetected();
// Ctcss_sel
// 1 = ctcss_cmp/cdcss_cmp out via gpio
// 0 = ctcss/cdcss sdo out vio gpio
void setCtcssGpioSel(bool cmp_nsdo);
bool getCtcssGpioSel();
void setCdcssInvert(bool invert);
bool getCdcssInvert();
// Cdcss_sel
// 1 = long (24 bit) code
// 0 = short(23 bit) code
void setCdcssSel(bool long_nshort);
bool getCdcssSel();
// Cdcss neg_det_en
bool getCdcssNegDetEnabled();
// Cdcss pos_det_en
bool getCdcssPosDetEnabled();
// ctss_det_en
bool getCtssDetEnabled();
// cdcss codes
void setCdcssCode(uint16_t code);
uint16_t getCdcssCode();
// SQ
void setSQOn();
void setSQOff();
bool getSQState();
// SQ threshold
void setSQHiThresh(int16_t sq_hi_threshold); // Sq detect high th, rssi_cmp will be 1 when rssi>th_h_sq, unit 1dB
int16_t getSQHiThresh();
void setSQLoThresh(int16_t sq_lo_threshold); // Sq detect low th, rssi_cmp will be 0 when rssi<th_l_sq && time delay meet, unit 1dB
int16_t getSQLoThresh();
bool getSquelching();
// SQ out select
void setSQOutSel();
void clearSQOutSel();
bool getSQOutSel();
// VOX
void setVoxOn();
void setVoxOff();
bool getVoxOn();
// Vox Threshold
void setVoxOpenThresh(uint16_t vox_open_thresh); // When vssi > th_h_vox, then vox will be 1(unit mV )
uint16_t getVoxOpenThresh();
void setVoxShutThresh(uint16_t vox_shut_thresh); // When vssi < th_l_vox && time delay meet, then vox will be 0 (unit mV )
uint16_t getVoxShutThresh();
// Tail Noise
void enableTailNoiseElim();
void disableTailNoiseElim();
bool getTailNoiseElimEnabled();
// tail noise shift select
// Select ctcss phase shift when use tail eliminating function when TX
// 00 = 120 degree shift
// 01 = 180 degree shift
// 10 = 240 degree shift
// 11 = reserved
void setShiftSelect(uint16_t shift_sel);
uint16_t getShiftSelect();
// DTMF
// Reading a single DTMF code:
// enableDTMFReceive()
// while (getDTMFSample() == 0) { delay(10); }
// uint16_t code = getDTMFCode();
// while (getDTMFSample() == 1) { delay(10); }
// disableDTMF();
// Writing a single DTMF code:
// setDTMFCode(code); // code is a uint16_t from 0x0 to 0xF
void enableDTMFReceive();
void setDTMFDetectTime(uint16_t detect_time);
uint16_t getDTMFDetectTime();
void setDTMFIdleTime(uint16_t idle_time); // idle time is time between DTMF Tone
uint16_t getDTMFIdleTime();
char DTMFRxLoop();
char DTMFcode2char(uint16_t code);
uint8_t DTMFchar2code(char c);
void setDTMFTxTime(uint16_t tx_time); // tx time is duration of DTMF Tone
uint16_t getDTMFTxTime();
uint16_t disableDTMF();
uint16_t getDTMFSample();
uint16_t getDTMFCode();
uint16_t getDTMFTxActive();
void setDTMFCode(uint16_t code);
// Tone
void HStone(uint8_t pin, unsigned int frequency);
void HSnoTone(uint8_t pin);
void lookForTone(uint16_t tone_hz);
uint8_t toneDetected();
// TX FM deviation
void setFMVoiceCssDeviation(uint16_t deviation);
uint16_t getFMVoiceCssDeviation();
void setFMCssDeviation(uint16_t deviation);
uint16_t getFMCssDeviation();
// RX voice range
void setMute();
void setUnmute();
void setVolume1(uint16_t volume);
uint16_t getVolume1();
void setVolume2(uint16_t volume);
uint16_t getVolume2();
// GPIO
void setGpioMode(uint16_t gpio, uint16_t mode);
void setGpioHiZ(uint16_t gpio);
void setGpioFcn(uint16_t gpio);
void setGpioLow(uint16_t gpio);
void setGpioHi(uint16_t gpio);
uint16_t getGpioMode(uint16_t gpio);
void setGpios(uint16_t mode);
uint16_t getGpios();
// Int
void enableInterrupt(uint16_t interrupt);
void disableInterrupt(uint16_t interrupt);
bool getInterruptEnabled(uint16_t interrupt);
// ST mode
void setStMode(uint16_t mode);
uint16_t getStMode();
void setStFullAuto();
void setStRxAutoTxManu();
void setStFullManu();
// Pre-emphasis, De-emphasis filter
void bypassPreDeEmph();
void usePreDeEmph();
bool getPreDeEmphEnabled();
// Voice filters
void bypassVoiceHpf();
void useVoiceHpf();
bool getVoiceHpfEnabled();
void bypassVoiceLpf();
void useVoiceLpf();
bool getVoiceLpfEnabled();
// Vox filters
void bypassVoxHpf();
void useVoxHpf();
bool getVoxHpfEnabled();
void bypassVoxLpf();
void useVoxLpf();
bool getVoxLpfEnabled();
// Read Only Status Registers
int16_t readRSSI();
uint16_t readVSSI();
uint16_t readMSSI();
// set output power of radio
void setRfPower(uint8_t pwr);
// channel helper functions
bool setGMRSChannel(uint8_t channel);
bool setFRSChannel(uint8_t channel);
bool setMURSChannel(uint8_t channel);
bool setWXChannel(uint8_t channel);
uint8_t scanWXChannel();
// utilities
uint32_t scanMode(uint32_t start,uint32_t stop, uint8_t speed, uint16_t step, uint16_t threshold);
uint32_t findWhitespace(uint32_t start,uint32_t stop, uint8_t dwell, uint16_t step, uint16_t threshold);
uint32_t scanChannels(uint32_t buffer[],uint8_t buffsize, uint8_t speed, uint16_t threshold);
uint32_t findWhitespaceChannels(uint32_t buffer[],uint8_t buffsize, uint8_t dwell, uint16_t threshold);
void setupMorseRx();
unsigned int getMorseFreq();
void setMorseFreq(unsigned int morse_freq_hz);
unsigned int getMorseDotMillis();
void setMorseDotMillis(unsigned int morse_dot_dur_millis);
void morseOut(char buffer[HAMSHIELD_MORSE_BUFFER_SIZE]);
char morseRxLoop();
bool handleMorseTone(uint16_t tone_time, bool bits_to_process, uint8_t * rx_morse_char, uint8_t * rx_morse_bit);
char parseMorse(uint8_t rx_morse_char, uint8_t rx_morse_bit);
uint8_t morseLookup(char letter);
uint8_t morseReverseLookup(uint8_t itu);
bool waitForChannel(long timeout = 0, long breakwindow = 0, int setRSSI = HAMSHIELD_EMPTY_CHANNEL_RSSI);
void SSTVVISCode(int code);
void SSTVTestPattern(int code);
void toneWait(uint16_t freq, long timer);
void toneWaitU(uint16_t freq, long timer);
bool parityCalc(int code);
private:
uint8_t devAddr;
uint8_t hs_mic_pin;
uint16_t radio_dat_buf[4];
bool tx_active;
bool rx_active;
float radio_frequency;
/* uint32_t FRS[];
uint32_t GMRS[];
uint32_t MURS[];
uint32_t WX[];
*/
// private utility functions
// these functions should not be called in the Arduino sketch
// just use the above public functions to do everything
void setFrequency(uint32_t freq_khz);
void setTxBand2m();
void setTxBand1_2m();
void setTxBand70cm();
// xtal frequency (kHz)
// 12-14MHz crystal: this reg is set to crystal freq_khz
// 24-28MHz crystal: this reg is set to crystal freq_khz / 2
void setXtalFreq(uint16_t freq_kHz);
uint16_t getXtalFreq();
// adclk frequency (kHz)
// 12-14MHz crystal: this reg is set to crystal freq_khz / 2
// 24-28MHz crystal: this reg is set to crystal freq_khz / 4
void setAdcClkFreq(uint16_t freq_kHz);
uint16_t getAdcClkFreq();
// clk mode
// 12-14MHz: set to 1
// 24-28MHz: set to 0
void setClkMode(bool LFClk);
bool getClkMode();
// choose tx or rx
void setTX(bool on_noff);
bool getTX();
void setRX(bool on_noff);
bool getRX();
};
#endif /* _HAMSHIELD_H_ */

161
src/HamShield_comms.cpp Normal file
View File

@ -0,0 +1,161 @@
/*
* Based loosely on I2Cdev by Jeff Rowberg, except for all kludgy bit-banging
*
* Note that while the Radio IC (AU1846) does have an I2C interface, we've found
* it to be a bit buggy. Instead, we are using a secondary interface to communicate
* with it. The secondary interface is a bit of a hybrid between I2C and SPI.
* uses a Chip-Select pin like SPI, but has bi-directional data like I2C. In order
* to deal with this, we bit-bang the interface.
*/
#include "HamShield_comms.h"
uint8_t ncs_pin = nCS;
uint8_t clk_pin = CLK;
uint8_t dat_pin = DAT;
void HSsetPins(uint8_t ncs, uint8_t clk, uint8_t dat) {
ncs_pin = ncs;
clk_pin = clk;
dat_pin = dat;
#if !defined(ARDUINO)
wiringPiSetup();
#endif
pinMode(ncs_pin, OUTPUT);
digitalWrite(ncs_pin, HIGH);
pinMode(clk_pin, OUTPUT);
digitalWrite(clk_pin, HIGH);
pinMode(dat_pin, OUTPUT);
digitalWrite(dat_pin, HIGH);
}
int8_t HSreadBitW(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint16_t *data)
{
uint16_t b;
uint8_t count = HSreadWord(devAddr, regAddr, &b);
*data = b & (1 << bitNum);
return count;
}
int8_t HSreadBitsW(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint16_t *data)
{
uint8_t count;
uint16_t w;
if ((count = HSreadWord(devAddr, regAddr, &w)) != 0) {
uint16_t mask = ((1 << length) - 1) << (bitStart - length + 1);
w &= mask;
w >>= (bitStart - length + 1);
*data = w;
}
return count;
}
int8_t HSreadWord(uint8_t devAddr, uint8_t regAddr, uint16_t *data)
{
//return I2Cdev::readWord(devAddr, regAddr, data);
uint8_t temp;
uint16_t temp_dat;
// bitbang for great justice!
*data = 0;
pinMode(dat_pin, OUTPUT);
regAddr = regAddr | (1 << 7);
digitalWrite(devAddr, 0); //PORTC &= ~(1<<1); //devAddr used as chip select
for (int i = 0; i < 8; i++) {
temp = ((regAddr & (0x80 >> i)) != 0);
digitalWrite(clk_pin, 0); //PORTC &= ~(1<<5); //
digitalWrite(dat_pin, temp);
HSdelayMicroseconds(1);
digitalWrite(clk_pin, 1); //PORTC |= (1<<5); //
HSdelayMicroseconds(1);
}
// change direction of dat_pin
pinMode(dat_pin, INPUT); // DDRC &= ~(1<<4); //
for (int i = 15; i >= 0; i--) {
digitalWrite(clk_pin, 0); //PORTC &= ~(1<<5); //
HSdelayMicroseconds(1);
digitalWrite(clk_pin, 1); //PORTC |= (1<<5); //
temp_dat = digitalRead(dat_pin); //((PINC & (1<<4)) != 0);
temp_dat = temp_dat << i;
*data |= temp_dat;
HSdelayMicroseconds(1);
}
digitalWrite(devAddr, 1); //PORTC |= (1<<1);// CS
return 1;
}
bool HSwriteBitW(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint16_t data)
{
uint16_t w;
HSreadWord(devAddr, regAddr, &w);
w = (data != 0) ? (w | (1 << bitNum)) : (w & ~(1 << bitNum));
return HSwriteWord(devAddr, regAddr, w);
}
bool HSwriteBitsW(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint16_t data)
{
uint16_t w;
if (HSreadWord(devAddr, regAddr, &w) != 0) {
uint16_t mask = ((1 << length) - 1) << (bitStart - length + 1);
data <<= (bitStart - length + 1); // shift data into correct position
data &= mask; // zero all non-important bits in data
w &= ~(mask); // zero all important bits in existing word
w |= data; // combine data with existing word
return HSwriteWord(devAddr, regAddr, w);
} else {
return false;
}
}
bool HSwriteWord(uint8_t devAddr, uint8_t regAddr, uint16_t data)
{
//return I2Cdev::writeWord(devAddr, regAddr, data);
uint8_t temp_reg;
uint16_t temp_dat;
//digitalWrite(13, HIGH);
// bitbang for great justice!
pinMode(dat_pin, OUTPUT);
regAddr = regAddr & ~(1 << 7);
digitalWrite(devAddr, 0); // PORTC &= ~(1<<1); //CS
for (int i = 0; i < 8; i++) {
temp_reg = ((regAddr & (0x80 >> i)) != 0);
digitalWrite(clk_pin, 0); //PORTC &= ~(1<<5); //
digitalWrite(dat_pin, regAddr & (0x80 >> i));
HSdelayMicroseconds(1);
digitalWrite(clk_pin, 1); // PORTC |= (1<<5); //
HSdelayMicroseconds(1);
}
for (int i = 0; i < 16; i++) {
temp_dat = ((data & (0x8000 >> i)) != 0);
digitalWrite(clk_pin, 0); //PORTC &= ~(1<<5); //
digitalWrite(dat_pin, temp_dat);
HSdelayMicroseconds(1);
digitalWrite(clk_pin, 1); // PORTC |= (1<<5); //
HSdelayMicroseconds(1);
}
digitalWrite(devAddr, 1); //PORTC |= (1<<1); //CS
return true;
}
// Hardware abstraction
unsigned long HSmillis(){
return millis();
}
void HSdelay(unsigned long ms) {
delay(ms);
}
void HSdelayMicroseconds(unsigned int us) {
delayMicroseconds(us);
}

45
src/HamShield_comms.h Normal file
View File

@ -0,0 +1,45 @@
#ifndef _HAMSHIELD_COMMS_H_
#define _HAMSHIELD_COMMS_H_
#if defined(ARDUINO)
#include "Arduino.h"
#define nCS A1 //15 //
#define CLK A5 //19 //
#define DAT A4 //18 //
#define MIC 3
#else // assume Raspberry Pi
#include "stdint.h"
#include <wiringPi.h>
#include <softTone.h>
#define nCS 0 //BCM17, HW pin 11
#define CLK 3 //BCM22, HW pin 15
#define DAT 2 //BCM27, HW pin 13
#define MIC 1 //BCM18, HW pin 12
#endif
void HSsetPins(uint8_t ncs, uint8_t clk, uint8_t dat);
int8_t HSreadBitW(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint16_t *data);
int8_t HSreadBitsW(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint16_t *data);
int8_t HSreadWord(uint8_t devAddr, uint8_t regAddr, uint16_t *data);
bool HSwriteBitW(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint16_t data);
bool HSwriteBitsW(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint16_t data);
bool HSwriteWord(uint8_t devAddr, uint8_t regAddr, uint16_t data);
// hardware abstraction layer
unsigned long HSmillis();
void HSdelay(unsigned long ms);
void HSdelayMicroseconds(unsigned int us);
#endif /* _HAMSHIELD_COMMS_H_ */