kopia lustrzana https://github.com/Max-Plastix/tbeam-helium-mapper
Porównaj commity
36 Commity
v1.7.1-bet
...
main
Autor | SHA1 | Data |
---|---|---|
Max-Plastix | 415a77331e | |
Max-Plastix | 947a7f630c | |
Stephan Martin | 88e52f18b5 | |
Mike Causer | 149f5b034d | |
Max-Plastix | 00cec9c130 | |
Mike Causer | bd95ec5e3b | |
Mike Causer | 27372a617e | |
Mike Causer | a3c662a52a | |
Max-Plastix | bc87deb3f8 | |
Max-Plastix | 2b6ad6dab0 | |
Max-Plastix | ef64432f3b | |
Max-Plastix | b1ca01581e | |
Max-Plastix | 60a9462ebf | |
Max-Plastix | 8dcd9d4f5e | |
Max-Plastix | bc3226fd23 | |
Max-Plastix | 57dc008214 | |
Max-Plastix | 5a5d23f45b | |
Max-Plastix | 3b6692b011 | |
Max-Plastix | 32a1c84855 | |
Max-Plastix | 32f51fd068 | |
Max-Plastix | b64e90e9fb | |
Max-Plastix | 3ac1d7f5dc | |
Max-Plastix | a89c71d526 | |
Max-Plastix | 4d64271b07 | |
Max-Plastix | 549a51951a | |
Max-Plastix | a68c2305a0 | |
Max-Plastix | 88e5ced7cf | |
Max-Plastix | 981e6497ef | |
Max-Plastix | 6c18350127 | |
Max-Plastix | c1155c13e4 | |
Max-Plastix | 2749d67de6 | |
Max-Plastix | b90680746b | |
Max-Plastix | fa284c02a8 | |
Max-Plastix | c972309bf6 | |
Max-Plastix | aebc32ccc9 | |
Max-Plastix | 21925d0f70 |
|
@ -3,3 +3,4 @@
|
|||
.vscode/c_cpp_properties.json
|
||||
.vscode/launch.json
|
||||
.vscode/ipch
|
||||
.vscode/extensions.json
|
||||
|
|
|
@ -3,5 +3,8 @@
|
|||
// for the documentation about the extensions.json format
|
||||
"recommendations": [
|
||||
"platformio.platformio-ide"
|
||||
],
|
||||
"unwantedRecommendations": [
|
||||
"ms-vscode.cpptools-extension-pack"
|
||||
]
|
||||
}
|
||||
|
|
218
README.md
218
README.md
|
@ -3,55 +3,144 @@
|
|||
by [Max-Plastix](https://github.com/Max-Plastix/tbeam-helium-mapper/)
|
||||
|
||||
### TL;DR
|
||||
Read through the comments in the three source files listed below. Edit to taste, compile, and Upload to your TTGO T-Beam device. Drive around and map the Helium network!
|
||||
This code loads onto LilyGo TTGO T-Beam v1.1 board to make a Helium Network Mapper. To build one: download this build, configure some files, and upload it to your device. Go travel the world to contribute to the Helium Network Coverage Maps!
|
||||
|
||||
## Purpose
|
||||
The goal of this version is to have a **TTGO T-Beam** Mapper that's ideally suited to walking or driving, taking cues from the USB Power source and movement for activity level.
|
||||
The goal of this software is to have a **TTGO T-Beam** Mapper that's ideally suited to walking or driving, taking cues from the USB Power source and movement for activity level.
|
||||
|
||||
This device uploads GPS coordinates from the TTGO T-Beam to the Helium network, be used for tracking and determining signal coverage of LoRaWAN gateways and hotspots.
|
||||
With this software and a T-Beam device, one can contribute to the [Helium Network](https://www.helium.com) Mapper or Cargo projects.
|
||||
Details for the Mapper project can be found [here](https://mappers.helium.com/) and details for Cargo can be found [here](https://cargo.helium.com/)
|
||||
Details for the Mapper project can be found [here](https://mappers.helium.com/) and details for Cargo can be found [here](https://cargo.helium.com/). It also works with [Coverage Map](https://coveragemap.net/heatmap/), a new Heatmap view of Helium hotspots and coverage.
|
||||
|
||||
The Mapper is intended to be highly active while the vehicle is in motion, and quieter when the vehicle is stationary. By default, it is not miserly with Data Credits. If you want to conserve Data Credits or battery power, tune the default configuration to send packets less frequently.
|
||||
The Mapper is intended to be highly active while the vehicle is in motion, and quieter when the vehicle is stationary. By default, it is not miserly with Data Credits. If you want to conserve Data Credits or battery power, tune the configuration to send packets less frequently.
|
||||
|
||||
### But do I get PAID for Mapping?!
|
||||
|
||||
No, you do not. I put this here because it seems to be the #1 FAQ. You do not earn HNT or Data Credits by mapping. Mapping costs you very little -- One Penny (USD $0.01) for every thousand mapping packets. It helps the Helium network by providing a coverage map, and it helps you by providing clarity on your own local Helium environment.
|
||||
No, you do not. I put this here because it seems to be the #1 FAQ. You do not earn HNT or Data Credits by mapping. Mapping costs you very little -- One Penny (USD $0.01) for every thousand mapping packets. It helps the Helium network by providing a coverage map, and it helps you by providing clarity on your own local Helium environment. It's all volunteer.
|
||||
|
||||
### But do I get to flag and delist spoofing gamer Hotspots?!
|
||||
|
||||
No, you do not. It's the #2 FAQ. The Mapper data and coverage maps are not involved in any POC challenges or used for gaming denylists.
|
||||
|
||||
## Supported Hardware
|
||||
I tested this software on (several) LilyGo TTGO T-Beam v1.1 devices, all on **US915**. These are commonly avaialable as "Meshtastic" devices from AliExpress, Amazon, Banggood, eBay, etc, usually as a kit with an unsoldered OLED screen and SMA antenna.
|
||||
I tested this software on (many) LilyGo [TTGO T-Beam v1.1](http://www.lilygo.cn/prod_view.aspx?TypeId=50060&Id=1317&FId=t3:50060:3) devices, all on **US915**. Others have enjoyed success on **EU688** and other worldwide bands, with the matching device. These are commonly available as "Meshtastic" devices from AliExpress, Amazon, Banggood, eBay, etc, usually as a kit with an unsoldered OLED screen and SMA antenna for around USD $30.00.
|
||||
|
||||
If you have an older v0.7 board or different region, adjust the configuration to match. If you have a unique variant (Neo 8M?) and find something not working, open an Issue and provide what information you can.
|
||||
If you have an older v0.7 board or different region, adjust the configuration to match. If you have a unique variant and find something not working, open an Issue and provide what information you can.
|
||||
|
||||
### Semtech LoRa Radio
|
||||
This build uses the [MCCI Catena LMIC Library](https://github.com/mcci-catena/arduino-lmic) for LoRaWAN on the Semtech SX1276 or SX1272 radio modules.
|
||||
|
||||
Note that the T-Beam device with a [U.FL / I-PEX](https://www.hirose.com/product/series/U.FL#) LoRa antenna connector and uBlox NEO-8M GPS module comes with a Semtech SX1262 radio, which is NOT supported by the LMIC library.
|
||||
**Do Not Buy** [this incorrect device](https://www.amazon.com/T-Beam-NEO-M8N-Wireless-Bluetooth-Display/dp/B07X2SNNGQ) for use on Helium! It will not work.
|
||||
|
||||
### OLED Display
|
||||
Most T-Beam units arrive with no OLED Display attached. You **can** operate the mapper without an OLED display, if you would like. Of course, the status and menu will be invisible, but there may be applications where a display is not required.
|
||||
|
||||
The most common OLED Display used is a 0.96" screen with SSD1306 controller. You may also use 1.3" displays, or displays with an SH1106 controller. The software should auto-detect the correct controller protocol and display i2c address, but if you have an unusual display, file an issue to see if it can be supported. When an OLED display is installed, you should see the detected type and address in the startup messages on UART.
|
||||
|
||||
#### Soldering the 4-pin OLED connection
|
||||
|
||||
Since the display is not pre-installed, the buyer must solder the 4-pin connection between the T-Beam and OLED. Be very careful to match the pinout and position of the display! Some OLED displays have VCC and GND reversed from the expected pinout, and require some creative wiring to adapt. If your OLED came with the T-Beam, it's probably correct and ready-to-solder.
|
||||
|
||||
If you incorrectly power the OLED, short connections, or damage the Pin 21/22 connections (i2c), it is very likely that both the OLED and the AXP Power management unit are unreachable, and the board may fail in unexpected ways. It's a good idea to program the device and check the UART Monitor output before installing the OLED, for some confidence that the board works before soldering. (Nobody actually does this, but it's a good idea.)
|
||||
|
||||
# Mandatory Configuration
|
||||
Before Buliding and Uploading, you will probably want to inspect or change some items in these three files:
|
||||
- `platformio.ini`
|
||||
- `main/configuration.h`
|
||||
- `main/credentials.cpp`
|
||||
The comments and text below will guide you on what values to look out for.
|
||||
|
||||
The comments and text below will guide you on what values to look out for. By default, this build is for the **US915** region. Change `platformio.ini` for a different locale.
|
||||
You might have to adjust the COM Port in `platformio.ini` for Uploading and Monitoring if PlatformIO doesn't auto-detect your port correctly.
|
||||
### Geographic Region, and Frequency
|
||||
By default, this build is for the **US915** region. Change the declaration in `platformio.ini` for a different locale, to select the correct operating rules and frequency for your country.
|
||||
|
||||
You should choose your own AppKey value in `credentials.cpp`. Either take the random one suggested by the Console Device entry, or make up one of your own. Read the notes in `credentials.cpp` for details. By default, the DevEUI is generated automatically to be unique to each unit, but you may want to hardcode it in `credentials.cpp` instead.
|
||||
### PlatformIO Communication port
|
||||
You might have to adjust the COM Port in `platformio.ini` for Uploading and Monitoring if PlatformIO doesn't auto-detect your port correctly. If you have a single T-Beam on a Windows computer, PlatformIO will usually auto-detect it correctly. If you have a bunch of Serial USB devices, unusual USB topography, or weird device drivers, you might have to set this to a fixed port. Note that Upload and Monitor are set separately, and have different auto-detection logic.
|
||||
|
||||
On MacOS, it can be significantly more complicated to connect PlatformIO to your device. Ask in the Discord for help.
|
||||
|
||||
### Helium Device IDs
|
||||
Each LoRaWAN device on Helium is identified by the three OTAA values used in Joining the network: `DevEUI`, `AppEUI`, and `AppKey`.
|
||||
|
||||
You should choose your own private `AppKey` value in `credentials.cpp`. Either take the random value generated by the new Console Device entry, or make up one of your own. Read the notes in `credentials.cpp` for details. The value in the build must match the value in Console, regardless of how you achieve that.
|
||||
|
||||
By default, the `DevEUI` is generated automatically to be unique to each unit, but you may want to hardcode it in `credentials.cpp` instead. There is an explanation there of why you might want to go either way.
|
||||
|
||||
### Mapper uplink period and behavior
|
||||
Read through the comments in `configuration.h` to see if the default Mapper behavior suits your needs, especially in the area of default time/distance between Uplink packets.
|
||||
|
||||
## How it Works
|
||||
# Building and Programming
|
||||
This code started off as an Arduino IDE project, with `.ino` filenames, but the complexity of managing installed libraries in Arduino IDE made it difficult to sustain. Now, the code must be built with PlatformIO and Visual Studio Code. These is an excellent free/open-source IDE for ESP32 platforms, and allows each project to pull in the required libraries to complete the build, as well as program it into the device.
|
||||
|
||||
There are excellent guides to installing and using PlatformIO, but for this project, your goal is to open the project, edit the configuration files, and then select `Build` and `Upload` to program the T-Beam device.
|
||||
|
||||
## MacOS Guide
|
||||
Building and programming with PlatformIO on MacOS is mostly the same, but has some unique challenges. `@Rob Cryft` wrote this excellent guide on ["Getting Started with Helium Mapping"](https://levelup.gitconnected.com/getting-started-with-helium-mapping-2833914c4d3) that walks through the whole process on Mac.
|
||||
|
||||
# Battery life and power consumption
|
||||
The T-Beam is not the lowest-power Mapper device, because it has a powerful dual-core ESP32 CPU, Power Management IC (PMIC or PMU), and other design decisions that lead to a pretty high operating current of 110mA or so.
|
||||
|
||||
There is an excellent Lithium-Ion 18650 battery management and charger built-in, so you can install a battery cell, and operate it from USB power while it charges and maintains the battery. The USB port can draw up to 1 Amp, with 750mA or so going to battery charging.
|
||||
|
||||
## Battery Selection
|
||||
If you plan to run the Mapper primarily on battery with infrequent charging, you will want a battery with the highest mAh (milliamp-hour) rating, typically 3000 mAh or more. Some battery cells like Sony's excellent VTC6, are optimized for very high current discharge (heaters, drones, scooters). These are expensive, and may make other compromises in capacity. You don't need high current at all, so look for a good balance of cost and capacity.
|
||||
|
||||
If you expect to have USB power available most of the time, then the cheapest 18650 cells will do just fine -- don't feel bad about using an old or low-capacity one.
|
||||
|
||||
### Battery Fitment
|
||||
The included battery holder in the TTGO T-Beam is **small** and **tight**. Your battery cell must have **NO Protruding bump** or nipple on the Positive end. Look for a flat or low-profile positive end. (If you must, you may be able to crush the spring-terminals at the ends of the battery holder, but this should be done carefully to avoid damaging the attached PCB or cracking the holder.)
|
||||
|
||||
Always insert the cell carefully and deliberately, noting the `+` and `-` orientation but also supporting the PCB to avoid bending the whole assembly with force.
|
||||
|
||||
Some battery cells have a built-in Protection Circuit, advertised as "protected" or safe cells. These batteries are longer in size, and won't easily fit in the battery holder.
|
||||
|
||||
## Runtime and Battery Life
|
||||
While the T-Beam Mapper is typically USB powered from a vehicle, it can run for weeks from the built-in 18650 cell responding to occasional movement.
|
||||
|
||||
The GPS receiver is the single largest power consumer on the Mapper, so settings that allow for more GPS-off time will save battery.
|
||||
|
||||
## Runtime
|
||||
It depends on configuration, of course, but here's a ballpark figure: Without any sleep, the fully-operating Mapper should track for about **24 hours of nonstop movement**. (3000mAh cell, 105mA operating current, reasonable battery margins and uplink rate)
|
||||
|
||||
When mostly stationary, the mapper can wait for movement or events for about a **month**! (3000mA cell, mostly 2.23mA sleep, some wake and activity.)
|
||||
|
||||
## Operating power
|
||||
In the full-operating state, with the GPS tracking, Mapper uplinks, and OLED display on, the T-Beam draws about 100 to **120mA** from the 18650 cell.
|
||||
(Searching for GPS fix is the highest power, 120mA, and when it has a solid fix, closer to 110mA.)
|
||||
There is a little extra power consumed for a short while as it charges the GPS coin cell automatically.
|
||||
|
||||
### OLED Screen OFF
|
||||
Turning off the OLED Display is done more to save the screen from pixel burn-in than to save power. It draws just under 10mA when lit with text display, so the Mapper drops to about **101.6mA** when the screen is off.
|
||||
|
||||
### LoRa power?
|
||||
Uplink transmissions use more power (200mA), but they are usually short and infrequent. Back-to-back SF10 transmissions could start to weigh on battery life, of course.
|
||||
|
||||
### Rest or Sleep
|
||||
With the GPS and OLED off, and the ESP32 waiting for USB power, button press, or movement checks, it is in the lowest-power operating state.
|
||||
This draws **2.23mA** from the battery.
|
||||
|
||||
### Power Off
|
||||
Powered off, the circuit still draws **3.22 μA (micro-amps)**. Not significant, but not zero. Remove the battery cell at about half to 80% charge for long-term storage longer than a month or two.
|
||||
|
||||
# Operation: How it Works
|
||||
When your car is started, and USB Power appears, the Mapper will power on, acquire GPS, and continue mapping.
|
||||
It re-uses the last network Join state for faster connection and fewer packets.
|
||||
|
||||
The Mapper is always looking to see if it's been a long time, or you moved some distance from the last report. Whichever one happens first causes a transmission to be sent, plotting a point on the Helium map.
|
||||
The Mapper is always looking to see if it's been a long time, or you moved some distance from the last report. Whichever one happens first causes a transmission to be sent, plotting a point on the Helium map. **Time or Distance** are the two main factors in determining when to send Uplinks.
|
||||
|
||||
When moving, the Mapper will send out a packet every time GPS indicates it has moved `MIN_DIST` meters. This is the primary knob to turn for more/fewer packets. A Helium hex cell is about 340meters across, so the default 68-meter packet distance will send quite a few redundant packets for each mapped cell. DC is incredibly cheap, but adjust the distance if you want to send fewer packets.
|
||||
|
||||
This is the normal operation of the Mapper in motion.. every `MIN_DIST` meters, one ping reporting position, while the battery charges from USB. If the speed of motion is fast, it may even result in back-to-back packet sends (at greater distance) limited by the bandwidth of your chosen Spreading Factor (Data Rate) and country restrictions. (In the United States US915, at SF10, this is about two seconds maximum speed. In Thailand, it can be 37 seconds or more.)
|
||||
This is the normal operation of the Mapper in motion: every `MIN_DIST` meters, one Uplink is sent reporting position while the battery charges from USB. If the speed of motion is fast, it may even result in back-to-back packet sends (at greater distance) limited by the bandwidth of your chosen Spreading Factor (Data Rate) and country restrictions. (In the United States US915, at SF10, this is about two seconds maximum speed. In Thailand, it can be 37 seconds or more.)
|
||||
|
||||
When the Mapper comes to a stop, staying within `MIN_DIST` meters, it sends a hearbeat ping every `STATIONARY_TX_INTERVAL` seconds (default: 60). This serves to keep it visible on the map and report battery voltage. Too often? Dial up the `STATIONARY_TX_INTERVAL` to a longer interval.
|
||||
When the Mapper comes to a stop, staying within `MIN_DIST` meters, it sends a heartbeat ping every `STATIONARY_TX_INTERVAL` seconds (default: 60). This serves to keep it visible on the map and report battery voltage. (Too often for you? Dial up the `STATIONARY_TX_INTERVAL` to a longer interval.)
|
||||
|
||||
After being stationary a long time (parked) with a decreasing battery voltage, we change to a slower pace of updates. This happens after `REST_WAIT` seconds (default: 30 minutes). In the Rest state, the Mapper transmits every `REST_TX_INTERVAL` seconds (default: 5 minutes).
|
||||
After being stationary a long time (parked) with a decreasing battery voltage, we change to a slower pace of "not moving" updates. This happens after `REST_WAIT` seconds (default: 30 minutes). In the Rest state, the Mapper transmits every `REST_TX_INTERVAL` seconds (default: 5 minutes).
|
||||
|
||||
After an even longer time (parked, not moving, no USB), the Mapper will power off the GPS to save significant power. It will go into the lowest power state, waiting for USB power to come back. Periodically, it will power up the GPS, get a location fix and see if it moved while sleeping. It may have missed significant movement during sleep time, and wake to full Mapping. Or it hasn't moved at all and goes back to sleep.
|
||||
|
||||
Eventually, the ~100mA power drain of the mapper (with OLED screen & GPS) runs the battery down below `BATTERY_LOW_VOLTAGE` volts, and the Mapper will save state and completely power off.
|
||||
It will power on and resume only when USB power appears.
|
||||
|
||||
Regardless of battery or sleep state, the Mapper will power on and resume when USB power appears.
|
||||
|
||||
# Detailed Operation
|
||||
|
||||
|
@ -98,9 +187,9 @@ indicating that the system experienced a normal boot (instead of a timer wakeup
|
|||
Next are some important debugging messages printed at startup, indicating whether the OLED screen, AXP Power Management IC, and GPS were found and initialized. If these are not found or connected quickly, then there could be a hardware failure, soldering error, or other board-level issue preventing the software from working correctly.
|
||||
|
||||
You should see `AXP192 PMU` on the T-Beam, and `SSD1306 OLED display` if a display is installed. If you see neither of these, the i2c port likely has problems.
|
||||
If you expected an OLED display, and none was found, then it may be misconnected.
|
||||
If you expected an OLED display, and none was found, then it may be disconnected.
|
||||
|
||||
After this are serveral data messages about voltages and settings, largely uninteresting, until you get to..
|
||||
After this are several data messages about voltages and settings, largely uninteresting, until you get to..
|
||||
|
||||
### Settings and Credentials
|
||||
On startup, the USB Serial port will print the DevEUI, AppID, and AppKey values, suitable for cut & paste entry into the Helium Console for your Device.
|
||||
|
@ -121,12 +210,12 @@ The Mapper will flash the Blue LED at 4Hz and attempt to Join the Helium network
|
|||
1. Out of Range: The nearest Helium hotspot can't hear the device, or the device can't hear the response.
|
||||
2. Wrong RF configuration or Localization: The frequency band and protocol must match the local Helium Network, as configured in `platformio.ini`.
|
||||
3. The Device keys are not correctly registered in the Helium Console. Check all three.
|
||||
4. The Device was recently added to Console and is still "Pending" or waiting for XOR Filter update to propegate through the blockchain or network. This can take 20 minutes or more.
|
||||
4. The Device was recently added to Console and is still "Pending" or waiting for XOR Filter update to propagate through the blockchain or network. This can take 20 minutes or more.
|
||||
5. Helium network outage. Any failure in the helium network that prevents Join will hang here, as was seen often in November 2021.
|
||||
6. RF or hardware issues. Disconnected antenna, mismatched antenna frequency, etc.
|
||||
|
||||
### Or, Re-Join
|
||||
Once the Mapper joins the Helium network, it stores these Network Key credentials for future use. Ideally, the Mapper does not have to send a Join request at the next startup, but fetches them from the nonvolatile "Preferences" memory. To successfully continue with these same credentials, the Mapper needs to continue the Frame Count from prior transmissions, or the Helium network will reject Uplink packets as "Late" (for re-using old Frame Count values).
|
||||
Once the Mapper joins the Helium network, it stores these Network Key credentials for future use. Ideally, the Mapper does not have to send a Join request at the next startup, but fetches them from the non-volatile "Preferences" memory. To successfully continue with these same credentials, the Mapper needs to continue the Frame Count from prior transmissions, or the Helium network will reject Uplink packets as "Late" (for re-using old Frame Count values).
|
||||
|
||||
When you see `(re-used join)` on the screen and serial log, this means no Join Request/Accept packets were sent, and the unit will attempt to use the same credentials.
|
||||
|
||||
|
@ -136,12 +225,40 @@ There are some instances where this is problematic or not correct:
|
|||
* Very long time since last Uplink
|
||||
* Helium Network resets that invalidate Join keys.
|
||||
|
||||
At any time, you can select `Flush Prefs` in the system menu to discard these keys, reset the device, and Join fresh.
|
||||
At any time, you can select `Full Reset` in the system menu to discard these keys, reset the device, and Join fresh.
|
||||
|
||||
### GPS Connected
|
||||
You should also see a message reporting `GPS connected`. The first time you run this software on hardware that came with Mestastic or other builds, it will automatically try all common baud rates to find the Neo GPS module. Eventually it will connect, then configure the GPS for the needed NMEA Messages at 115,200 bps, then save the configuration to flash so that subsequent boot is faster. In any case, you should always see `GPS connected` at startup.
|
||||
## GPS Connection and Issues
|
||||
The typical GPS operation is to power on, search the sky for satellites, and get a 3D fix in 10 seconds or less. 3 to 5 seconds is common.
|
||||
|
||||
This means the Mapper is receving NMEA messages at the expected bitrate, but it may not yet have a 3D position fix from the GPS.
|
||||
You should see a **Red LED** blinking once per second on the far right side of the T-Beam (away from the OLED). If this Red LED is not blinking, the GPS does not have a fix and no Mapper packets will be sent.
|
||||
|
||||
The T-Beam must have an Active GPS antenna connected to operate. The included rectangular antenna is stuck with tape to the battery holder, but any Active GPS Antenna with 3v power and a U.FL connector could be used as well. Many mappers use a larger 25x25mm GPS patch antenna for improved reception, but the included antenna is just fine.
|
||||
|
||||
### First Power-On
|
||||
If your device is new, unused for a long time, or shipped from elsewhere in the world, it may take significantly longer for that first GPS fix. I recommend installing a charged battery, powering on, and leaving the unit with a clear view of the sky (outdoors) for 15 min before attempting any diagnostics. In most cases, this will allow it to get a 3D Fix, download the current GPS Almanac data, charge the battery cell, and prepare for optimum startups.
|
||||
|
||||
#### GPS battery cell
|
||||
The Neo-6M has a dedicated GPS backup battery cell that recharges any time the Mapper is powered on. This helps retain the GPS state for faster time to first fix. If your device is new or unused for a long time, this battery is likely dead and will charge with some use. There's nothing to do but use the Mapper, and you should see fast GPS connections in the future.
|
||||
|
||||
#### GPS Bitrate and configuration
|
||||
On the Debug/Monitoring UART console, you should also see a message reporting `GPS connected`. The first time you run this software on hardware that came with Meshtastic or other builds, it will automatically try all common baud rates to find the Neo GPS module. Eventually it will connect, then configure the GPS for the needed NMEA Messages at 115,200 bps, then save the configuration to flash so that subsequent boot is faster. In any case, you should always see `GPS connected` at startup if you are watching the UART/Monitor serial data.
|
||||
|
||||
This means the Mapper is receiving NMEA messages at the expected bitrate, but it may not yet have a 3D position fix from the GPS.
|
||||
|
||||
Note that you never need to load or run special "GPS Reset" scripts to change the GPS settings. This build will find and configure the GPS from any known state, including Meshtastic builds.
|
||||
|
||||
### GPS Debug
|
||||
First, it is uncommon for GPS modules to be defective on the T-Beam. Try these steps to debug it, and reach out in the `#mappers` channel for help.
|
||||
|
||||
If 15 minutes of clear sky view did not result in a GPS Fix (blinking Red LED), then something is not correct. Ensure you have a good view of the sky, outdoors, with at least some horizon in view. The **most common** cause of failure is trying to get a first fix indoors, or with a limited view of the sky. "Near a window" doesn't count. That first fix takes time and needs many good and constant signals to download the full data set. Get it out in the open, and be patient.
|
||||
|
||||
Check the antenna cable connection to the board. The U.FL connector is fragile, and the routing of the wire through the hole in the PCB can cause tension, or disconnect in shipping. Some boards have been found with a broken U.FL connector, so inspect the solder joints as well.
|
||||
|
||||
Ensure the unit has good power, using a charged LiIon cell for power. It needs to stay on for 15 minutes or more without interruption.
|
||||
|
||||
If you see a blinking Red LED from the GPS, but the Mapper software does not have a fix, reporting `*** NO GPS ***`, then there is a software issue between the ESP32 and GPS. You can debug this further by selecting `USB GPS` from the menu and inspecting the NMEA sentences from the GPS to the UART console. You may also run Ublox tools this way, such as U-Center to study the GPS module behavior.
|
||||
|
||||
If `USB GPS` does not relay any NMEA sentences from the unit, then something is wrong in unusual ways. Reset the board and ensure that "GPS Connected" is shown during boot. It is not common for GPS modules to be defective, so keep trying different things and ask `#mappers` for ideas.
|
||||
|
||||
## LED Indicators
|
||||
|
||||
|
@ -166,7 +283,7 @@ The top status line alternates between two displays every few seconds:
|
|||
- `#ABC` is the last three hex digits of your DevEUI, so you can match it to the correct device in Console. Handy if you have several Mappers that look the same.
|
||||
- `4.10v` is the battery voltage
|
||||
- `48mA` is the charge (or discharge) current to the battery. The TTGO charges the battery cell at around 300mA from USB, when possible.
|
||||
- Satellite Count is displayed on the right at all times.
|
||||
- Satellite HDOP & Count is displayed on the right at all times. (Lower HDOP hints at better GSP accuracy.)
|
||||
- The GPS Time of Day (UTC) alternates on the display line every 2 seconds.
|
||||
- A `*** NO GPS ***` message will show when no GPS Fix is available.
|
||||
|
||||
|
@ -192,43 +309,16 @@ for Frame Count 1850, a time-triggered packet after 2 minutes and only 1 meter a
|
|||
How often Acks are requested is configurable, defaulting to one-every-ten.
|
||||
|
||||
# Uplink Payload
|
||||
The Payload Port and byte content have been selected to match the format used by CubeCell mappers as well:
|
||||
Lat, Long, Altitude, Speed, Battery, and Sats. This common decoder function can now be used for both TTGO and CubeCell mappers:
|
||||
The Payload Port and byte content have been selected to match the format used by CubeCell mappers as well.
|
||||
|
||||
```
|
||||
// From https://github.com/hkicko/CubeCell-GPS-Helium-Mapper
|
||||
function Decoder(bytes, port) {
|
||||
var decoded = {};
|
||||
|
||||
var latitude = ((bytes[0]<<16)>>>0) + ((bytes[1]<<8)>>>0) + bytes[2];
|
||||
latitude = (latitude / 16777215.0 * 180) - 90;
|
||||
|
||||
var longitude = ((bytes[3]<<16)>>>0) + ((bytes[4]<<8)>>>0) + bytes[5];
|
||||
longitude = (longitude / 16777215.0 * 360) - 180;
|
||||
|
||||
switch (port)
|
||||
{
|
||||
case 2:
|
||||
decoded.latitude = latitude;
|
||||
decoded.longitude = longitude;
|
||||
|
||||
var altValue = ((bytes[6]<<8)>>>0) + bytes[7];
|
||||
var sign = bytes[6] & (1 << 7);
|
||||
if(sign) decoded.altitude = 0xFFFF0000 | altValue;
|
||||
else decoded.altitude = altValue;
|
||||
|
||||
decoded.speed = parseFloat((((bytes[8]))/1.609).toFixed(2));
|
||||
decoded.battery = parseFloat((bytes[9]/100 + 2).toFixed(2));
|
||||
decoded.sats = bytes[10];
|
||||
decoded.accuracy = 2.5; // Bogus Accuracy required by Cargo/Mapper integration
|
||||
break;
|
||||
}
|
||||
|
||||
return decoded;
|
||||
}
|
||||
```
|
||||
A custom Decoder Function translates the payload bytes into a set of JSON values required by the Integrations for both Mapper and Cargo.
|
||||
This turns the Base64 Payload into values for Lat, Long, Altitude, Speed, Battery, and Sats.
|
||||
|
||||
Note that HDOP is not sent in this data.
|
||||
This [Decoder Function](https://github.com/Max-Plastix/tbeam-helium-mapper/blob/main/console-decoders/unified_decoder.js) can be pasted directly into the Console custom function. Do not use Decoder functions from other builds or instructions! The Uplink decoding is specific to the software that made the packet, so it has to match. (Note that HDOP is not sent in this data.)
|
||||
|
||||
## Grafana integration for custom maps
|
||||
|
||||
If you want to maintain your own device map, there is an excellent [Grafana guide](https://friendsoflittleyus.nl/grafana-helium-gps-tracker-on-raspberry-pi/) here and additional information and [template scripts](https://github.com/takeabyte/helium_mapper_grafana) by @takeabyte (`@friends just call me bob`) available.
|
||||
|
||||
# Downlink
|
||||
This builds adds the option to reconfigure the Mapper remotely via Helium Downlink (network to device). You can change the maximum Time Interval, Distance, and Battery Cut-off voltage remotely.
|
||||
|
@ -284,7 +374,7 @@ This build is a modification of work by many experts, with input from the [Heliu
|
|||
|
||||
The Fork history here in Github shows the lineage and prior work, including https://github.com/helium/longfi-arduino/tree/master/TTGO-TBeam-Tracker
|
||||
|
||||
This code was originally developed for use on The Things Network (TTN) it has been editied/repurposed for use with the Helium Network.
|
||||
This code was originally developed for use on The Things Network (TTN) it has been edited/repurposed for use with the Helium Network.
|
||||
|
||||
This version is based on a forked repo from github user [kizniche] https://github.com/kizniche/ttgo-tbeam-ttn-tracker. Which in turn is based on the code from [xoseperez/ttgo-beam-tracker](https://github.com/xoseperez/ttgo-beam-tracker), with excerpts from [dermatthias/Lora-TTNMapper-T-Beam](https://github.com/dermatthias/Lora-TTNMapper-T-Beam) to fix an issue with incorrect GPS data being transmitted to the network. Support was also added for the 915 MHz frequency (North and South America). [lewisxhe/TTGO-T-Beam](https://github.com/lewisxhe/TTGO-T-Beam) was referenced for enabling use on the newer T-Beam board (Rev1).
|
||||
|
||||
|
@ -299,7 +389,7 @@ NOTE: There are now 2 versions of the TTGO T-BEAM, the first version (Rev0) and
|
|||
|
||||
2. Add the PlattformIO extension within VS Code (https://platformio.org/install/ide?install=vscode)
|
||||
|
||||
3. Check Device Manager if a serialdevice appear on conntecting the T-Beam. If nothing appears a driver for the USB to serial Adpater need to be installed.(https://www.silabs.com/developers/usb-to-uart-bridge-vcp-drivers)
|
||||
3. Check Device Manager if a serial device appear on connecting the T-Beam. If nothing appears a driver for the USB to serial Adapter need to be installed.(https://www.silabs.com/developers/usb-to-uart-bridge-vcp-drivers)
|
||||
|
||||
3. Check and edit platformio.ini to use the right bandplan for your region.
|
||||
|
||||
|
@ -307,9 +397,9 @@ NOTE: There are now 2 versions of the TTGO T-BEAM, the first version (Rev0) and
|
|||
- step by step details for setting up a Mapper integration can be found [here](https://docs.helium.com/use-the-network/coverage-mapping/mappers-quickstart/#mappers-quickstart).
|
||||
- detail for setting up a Cargo integration can be found [here](https://docs.helium.com/use-the-network/console/integrations/cargo).
|
||||
|
||||
The specific details for adding a Mapper or Cargo integration use a different edge node device than the one detailed here. When prompted to add a function decoder, be sure to use the following decoder. Note: This decoder can also be found within this project in the console-decoders directory.
|
||||
The specific details for adding a Mapper or Cargo integration use a different edge node device than the one detailed here. When prompted to add a function decoder, be sure to use the Decoder Function above.
|
||||
|
||||
5. Open this project file ```main/main.ino``` with the Arduino IDE Verify/Compile the project. If the compile is successful upload the application to your TTGO T-Beam.
|
||||
Filenames with `.ino` are a holdover from Arduino IDE. **Do not use Arduino IDE to compile this build; use PlatformIO instead.**
|
||||
|
||||
6. Disconnect and turn on the device and once a GPS lock is acquired, the device should start sending data to the Helium network and Helium Mapper or Helium Cargo depending upon which you configured in step 6.
|
||||
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
function doPost(e) {
|
||||
var GS = SpreadsheetApp.openById('<your sheet ID goes here>')
|
||||
// Create a sheet for today if it doesn't exist and add column headers
|
||||
var SheetDate = new Date().toLocaleDateString();
|
||||
if (!GS.getSheetByName(SheetDate))
|
||||
GS.insertSheet(SheetDate).getRange('A1:N1').setValues([[
|
||||
'Time', 'DateTime', 'Device EUI', 'Device Name', 'Battery',
|
||||
'Latitude', 'Longitude', 'Sats', 'Speed',
|
||||
'Hotspot', 'RSSI', 'SNR', 'Hotspot Dist', 'Hotspot Count'
|
||||
]]);
|
||||
|
||||
// Get all contents
|
||||
var json = JSON.parse(e.postData.contents);
|
||||
|
||||
if (json.port == 2)
|
||||
var ThisSheet = GS.getSheetByName(SheetDate);
|
||||
else if (json.port == 5)
|
||||
var ThisSheet = GS.getSheetByName('Status');
|
||||
else if (json.port == 6)
|
||||
var ThisSheet = GS.getSheetByName('Lost GPS');
|
||||
else
|
||||
var ThisSheet = GS.getSheetByName('Unknown');
|
||||
|
||||
// Row place holder
|
||||
var ThisRecord = [];
|
||||
var i = 0;
|
||||
|
||||
ThisRecord[i++] = new Date().toLocaleTimeString(); // Timestamp
|
||||
ThisRecord[i++] = new Date().toLocaleString(); // DateTime
|
||||
ThisRecord[i++] = json.dev_eui; // EUI
|
||||
ThisRecord[i++] = json.name; // Device Name
|
||||
ThisRecord[i++] = json.decoded.payload.battery; // Battery
|
||||
|
||||
if (json.port == 2) {
|
||||
ThisRecord[i++] = json.decoded.payload.latitude; // Latitude
|
||||
ThisRecord[i++] = json.decoded.payload.longitude; // Longitude
|
||||
ThisRecord[i++] = json.decoded.payload.sats; // Sats
|
||||
ThisRecord[i++] = json.decoded.payload.speed; // Speed
|
||||
//ThisRecord[i++] = json.decoded.payload.accuracy; // Accuracy stuck at 2.5
|
||||
} else if (json.port == 5) {
|
||||
ThisRecord[i++] = json.decoded.payload.last_latitude; // Latitude
|
||||
ThisRecord[i++] = json.decoded.payload.last_longitude; // Longitude
|
||||
ThisRecord[i++] = json.decoded.payload.status;
|
||||
ThisRecord[i++] = json.decoded.payload.value;
|
||||
} else if (json.port == 6) {
|
||||
ThisRecord[i++] = json.decoded.payload.last_latitude; // Latitude
|
||||
ThisRecord[i++] = json.decoded.payload.last_longitude; // Longitude
|
||||
ThisRecord[i++] = json.decoded.payload.sats;
|
||||
ThisRecord[i++] = json.decoded.payload.minutes;
|
||||
} else {
|
||||
ThisRecord[i++] = json.port;
|
||||
ThisRecord[i++] = json.payload;
|
||||
ThisRecord[i++] = json.payload_size;
|
||||
}
|
||||
|
||||
ThisRecord[i++] = json.hotspots[0].name; //Hotspot Name
|
||||
// ThisRecord[i++] = json.hotspots[0].lat; //Hotspot Latitude
|
||||
// ThisRecord[i++] = json.hotspots[0].long; //Hotspot Longitude
|
||||
ThisRecord[i++] = json.hotspots[0].rssi; //Hotspot RSSI
|
||||
ThisRecord[i++] = json.hotspots[0].snr; //Hotspot SNR
|
||||
|
||||
// Distance to Hotspot
|
||||
var lat1 = Number(json.decoded.payload.latitude);
|
||||
var lon1 = Number(json.decoded.payload.longitude);
|
||||
var lat2 = Number(json.hotspots[0].lat);
|
||||
var lon2 = Number(json.hotspots[0].long);
|
||||
var R = 6378.137; // Radius of earth in KM
|
||||
var dLat = lat2 * Math.PI / 180 - lat1 * Math.PI / 180;
|
||||
var dLon = lon2 * Math.PI / 180 - lon1 * Math.PI / 180;
|
||||
var a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
|
||||
Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) *
|
||||
Math.sin(dLon / 2) * Math.sin(dLon / 2);
|
||||
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
|
||||
var d = R * c;
|
||||
ThisRecord[i++] = (d * 1000);
|
||||
|
||||
ThisRecord[i++] = json.hotspots.length; // How many hotspots heard this?
|
||||
|
||||
|
||||
// Save in spreadsheet
|
||||
ThisSheet.getRange(ThisSheet.getLastRow() + 1, 1, 1, ThisRecord.length).setValues([ThisRecord]);
|
||||
}
|
|
@ -1,15 +1,15 @@
|
|||
// Decoder for MaxPlastix mappers, compatible with:
|
||||
// https://github.com/hkicko/CubeCell-GPS-Helium-Mapper
|
||||
// but without the Tracker payload.
|
||||
// Decoder for MaxPlastix mappers
|
||||
//
|
||||
// 11 Byte payload:
|
||||
// 3 Lat, 3 Long, 2 Altitude (m), 1 Speed (km/hr), 1 Battery, 1 Sats.
|
||||
// Accuracy is a dummy value required by some Integrations.
|
||||
// Battery is 1/100 of a volt, offset by 2v for a range of 2.00 to 4.56 volts.
|
||||
//
|
||||
|
||||
function Decoder(bytes, port) {
|
||||
var decoded = {};
|
||||
|
||||
// All formats carry a lat & lon reading:
|
||||
var latitude = ((bytes[0] << 16) >>> 0) + ((bytes[1] << 8) >>> 0) + bytes[2];
|
||||
latitude = (latitude / 16777215.0 * 180) - 90;
|
||||
|
||||
|
@ -23,8 +23,10 @@ function Decoder(bytes, port) {
|
|||
|
||||
var altValue = ((bytes[6] << 8) >>> 0) + bytes[7];
|
||||
var sign = bytes[6] & (1 << 7);
|
||||
if (sign) decoded.altitude = 0xFFFF0000 | altValue;
|
||||
else decoded.altitude = altValue;
|
||||
if (sign)
|
||||
decoded.altitude = 0xFFFF0000 | altValue;
|
||||
else
|
||||
decoded.altitude = altValue;
|
||||
|
||||
decoded.speed = parseFloat((((bytes[8])) / 1.609).toFixed(2));
|
||||
decoded.battery = parseFloat((bytes[9] / 100 + 2).toFixed(2));
|
||||
|
@ -32,9 +34,22 @@ function Decoder(bytes, port) {
|
|||
decoded.accuracy = 2.5; // Bogus Accuracy required by Cargo/Mapper integration
|
||||
break;
|
||||
case 5: // System status
|
||||
decoded.last_latitude = latitude;
|
||||
decoded.last_longitude = longitude;
|
||||
decoded.battery = parseFloat((bytes[6] / 100 + 2).toFixed(2));
|
||||
decoded.status = bytes[7];
|
||||
decoded.value = bytes[8];
|
||||
decoded.status = bytes[7];
|
||||
switch (bytes[7]) {
|
||||
case 1:
|
||||
decoded.status = "BOOT";
|
||||
break;
|
||||
case 2:
|
||||
decoded.status = "USB ON";
|
||||
break
|
||||
case 3:
|
||||
decoded.status = "USB OFF";
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 6: // Lost GPS
|
||||
decoded.last_latitude = latitude;
|
||||
|
@ -46,4 +61,11 @@ function Decoder(bytes, port) {
|
|||
}
|
||||
|
||||
return decoded;
|
||||
}
|
||||
}
|
||||
|
||||
// Wrapper for ChirpStack V4:
|
||||
function decodeUplink(input) {
|
||||
return {
|
||||
data: Decoder(input.bytes, input.fPort)
|
||||
};
|
||||
}
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Empty file. Ignore. This directory needs to exist to hush a platformio warning about ./include missing.
|
|
@ -27,8 +27,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
// -----------------------------------------------------------------------------
|
||||
// Version
|
||||
// -----------------------------------------------------------------------------
|
||||
#define APP_NAME "MaxP Mapper"
|
||||
#define APP_VERSION "1.7.1"
|
||||
#define APP_NAME "MaxP Mapper"
|
||||
#define APP_VERSION "1.7.8" // 2022-Nov-18
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// CONFIGURATION
|
||||
|
@ -39,52 +39,58 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
|
||||
// Minimum Distance between Mapper reports. This is your MAIN knob to turn for more/fewer uplink packets.
|
||||
// SMALLER distance: More packets, more dots on the map, more DC spent, more power consumed
|
||||
// (If you set this to a very small value, it will still be rate-limited by how often your Region allows back-to-back Uplink packets.)
|
||||
// LARGER distance: Fewer packets, might miss some hexes, conserves DC, battery might last longer
|
||||
// Note that a hex is about 340m across. Ideally, you want at least two uplinks in each hex to map it.
|
||||
#define MIN_DIST 70.0 // Minimum distance in meters from the last sent location before we send again.
|
||||
// (If you set this to a very small value, it will still be rate-limited by how often your Region allows back-to-back
|
||||
// Uplink packets.) LARGER distance: Fewer packets, might miss some hexes, conserves DC, battery might last longer Note
|
||||
// that a hex is about 340m across. Ideally, you want at least two uplinks in each hex to map it.
|
||||
#define MIN_DIST 70.0 // Minimum distance in meters from the last sent location before we send again.
|
||||
|
||||
// If we are not moving at least MIN_DIST meters away from the last uplink, when should we send a redundant
|
||||
// Mapper Uplink from the same location? This Heartbeat or ping isn't all that important for mapping, but might be
|
||||
// useful for time-at-location tracking or other monitoring. You can safely set this value very high.
|
||||
#define STATIONARY_TX_INTERVAL ( 5 * 60) // Send one uplink at least once every N seconds
|
||||
#define NEVER_REST 0 // Change to 1 if you want to always send at THIS rate, with no slowing or sleeping.
|
||||
#define STATIONARY_TX_INTERVAL (5 * 60) // Send one uplink at least once every N seconds
|
||||
#define NEVER_REST 0 // Change to 1 if you want to always send at THIS rate, with no slowing or sleeping.
|
||||
|
||||
// After being stationary for a long while, we move to a slower heartbeat interval:
|
||||
#define REST_WAIT (20 * 60) // If we still haven't moved in this many seconds, start sending even slower..
|
||||
#define REST_TX_INTERVAL (30 * 60) // Slow resting ping frequency in seconds
|
||||
#define REST_WAIT (20 * 60) // If we still haven't moved in this many seconds, start sending even slower..
|
||||
#define REST_TX_INTERVAL (30 * 60) // Slow resting ping frequency in seconds
|
||||
|
||||
// This last stage is a low-power sleep to conserve battery when the Mapper has not moved for a long time.
|
||||
// This one is a difficult compromise: Waking up to boot & power on the GPS is not a fast operation,
|
||||
// so we want to avoid it as much as possible. There is no other motion sensor, so if we make it too long,
|
||||
// This one is a difficult compromise: Waking up to boot & power on the GPS is not a fast operation,
|
||||
// so we want to avoid it as much as possible. There is no other motion sensor, so if we make it too long,
|
||||
// we miss the first minutes of each motion while sleeping.
|
||||
// Note that USB Power will prevent this low-power sleep, and also wake us up from it.
|
||||
// A button press will also wake from sleep, but takes some time to initialise and re-aquire
|
||||
#define SLEEP_WAIT ( 2 * 60 * 60) // If we STILL haven't moved in this long, turn off the GPS to save power
|
||||
// A button press will also wake from sleep, but takes some time to initialise and re-acquire
|
||||
#define SLEEP_WAIT (2 * 60 * 60) // If we STILL haven't moved in this long, turn off the GPS to save power
|
||||
// For a vehicle application where USB Power appears BEFORE motion, this can be set very high without missing anything:
|
||||
#define SLEEP_TX_INTERVAL ( 1 * 60 * 60) // Wake up and check position every now and then to see if movement happened
|
||||
#define SLEEP_TX_INTERVAL (1 * 60 * 60) // Wake up and check position every now and then to see if movement happened
|
||||
|
||||
// When searching for a GPS Fix, we may never find one due to obstruction, noise, or reduced availability.
|
||||
// Note that GPS Lost also counts as no-movement, so the Sleep tier above still applies
|
||||
#define GPS_LOST_WAIT ( 5 * 60) // How long to wait for a GPS fix before declaring failure
|
||||
#define GPS_LOST_PING (15 * 60) // Without GPS reception, how often to send a non-mapper status packet
|
||||
#define GPS_LOST_WAIT (5 * 60) // How long to wait for a GPS fix before declaring failure
|
||||
#define GPS_LOST_PING (15 * 60) // Without GPS reception, how often to send a non-mapper status packet
|
||||
|
||||
#define SCREEN_IDLE_OFF_S ( 2 * 60) // If there are no Uplinks or button presses sent for this long, turn the screen off.
|
||||
#define MENU_TIMEOUT_S 5 // Seconds to wait before exiting the menu.
|
||||
#define SCREEN_IDLE_OFF_S (2 * 60) // If there are no Uplinks or button presses sent for this long, turn the screen off.
|
||||
#define MENU_TIMEOUT_S 5 // Seconds to wait before exiting the menu.
|
||||
|
||||
// Below this voltage, power off until USB power allows charging. The PMIC also has a (safety) turn-off much lower than this.
|
||||
// We use a conservative 3.3v here since the battery will last longer.
|
||||
#define BATTERY_LOW_VOLTAGE 3.3
|
||||
// Below BATTERY_LOW_VOLTAGE, power off until USB power allows charging.
|
||||
// The PMIC also has a (safety) turn-off at 2.6v, much lower than this setting.
|
||||
// We use a conservative cutoff here since the battery will last longer if it's not repeatedly run to minimum.
|
||||
// A new-condition 18650 cell gives around 9Wh (Molicell) when discharged to the absolute lowest 2.5v
|
||||
// 8110mWh to 3.3v
|
||||
// 8875mWh to 3.1v
|
||||
// 9210mWh to 2.5v
|
||||
#define BATTERY_LOW_VOLTAGE 3.1
|
||||
|
||||
// Confirmed packets (ACK request) conflict with the function of a Mapper and should not normally be enabled.
|
||||
// In areas of reduced coverage, the Mapper will try to send each packet six or more times with different SF/DR.
|
||||
// This causes irregular results and the location updates are infrequent, unpredictable, and out of date.
|
||||
#define LORAWAN_CONFIRMED_EVERY 0 // Request Confirmation message every N Uplinks (0 means never, 1 means always, 2 every-other-one..)
|
||||
// (0 means never, 1 means always, 2 every-other-one..)
|
||||
#define LORAWAN_CONFIRMED_EVERY 0 // Request Confirmation message every N Uplinks
|
||||
|
||||
// Spreading Factor (Data Rate) determines how long each 11-byte Mapper Uplink is on-air, and how observable it is.
|
||||
// SF10 is about two seconds of transmission per packet, and the highest range, while SF7 is a good compromise
|
||||
// SF10 is about two seconds per packet, and the highest range, while SF7 is a good compromise
|
||||
// for moving vehicles and reasonable mapping observations.
|
||||
#define LORAWAN_SF DR_SF7 // Spreading factor (recommended DR_SF7 for network map purposes)
|
||||
#define LORAWAN_SF DR_SF7 // Spreading factor (recommended DR_SF7 for network map purposes)
|
||||
|
||||
// Deadzone defines a circular area where no map packets will originate.
|
||||
// This is useful to avoid sending many redundant packets in your own driveway or office, or just for local privacy.
|
||||
|
@ -101,14 +107,24 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
#define DEADZONE_RADIUS_M 500 // meters
|
||||
#endif
|
||||
|
||||
// There are some extra non-Mapper Uplink messages we can send, but there's no good way to avoid sending these
|
||||
// to all Integrations from the Decoder. This causes (normal) Error messages on the Console because Mapper will throw
|
||||
// them out for having no coordinates. It doesn't hurt anything, as they are correctly filtered by the Decoder, but if
|
||||
// you don't like seeing Integration Errors, then set these to 0. Set these to 1 for extra non-mapper messages.
|
||||
#ifndef SEND_GPSLOST_UPLINKS
|
||||
#define SEND_GPSLOST_UPLINKS 0 // GPS Lost messages
|
||||
#endif
|
||||
#ifndef SEND_STATUS_UPLINKS
|
||||
#define SEND_STATUS_UPLINKS 0 // USB Connect/disconnect messages
|
||||
#endif
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Less common Configuration iteams
|
||||
// Less common Configuration items
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Select which T-Beam board is being used. Only uncomment one.
|
||||
//#define T_BEAM_V07 // AKA Rev0 (first board released) UNTESTED! Expect bugs.
|
||||
#define T_BEAM_V10 // AKA Rev1 (second board released), this is the common "v1.1"
|
||||
#define T_BEAM_V10 // AKA Rev1 (second board released), this is the common "v1.1"
|
||||
|
||||
#define LOGO_DELAY 2000 // Time to show logo on first boot (ms)
|
||||
|
||||
|
@ -117,8 +133,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
|
||||
// Never enable ADR on Mappers because they are moving, so we don't want to adjust
|
||||
// anything based on packet reception.
|
||||
#define LORAWAN_ADR 0 // Do not enable ADR
|
||||
|
||||
#define LORAWAN_ADR 0 // Do not enable ADR
|
||||
|
||||
// If you are having difficulty sending messages to TTN after the first successful send,
|
||||
// uncomment the next option and experiment with values (~ 1 - 5)
|
||||
|
@ -169,11 +184,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
#endif
|
||||
|
||||
#define RED_LED 4 // GPIO4 on T-Beam v1.1
|
||||
// -----------------------------------------------------------------------------
|
||||
// OLED
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#define SSD1306_ADDRESS 0x3C
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// GPS
|
||||
|
@ -189,7 +199,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
#elif defined(T_BEAM_V10) // Or T-Beam v1.1
|
||||
#define GPS_RX_PIN 34
|
||||
#define GPS_TX_PIN 12
|
||||
#define GPS_INT 37 // 30ns accurate timepulse from Neo-6M pin 3
|
||||
#define GPS_INT 37 // 30ns accurate timepulse from Neo-6M pin 3
|
||||
#endif
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
|
|
@ -0,0 +1,460 @@
|
|||
#include <Arduino.h>
|
||||
#include "font.h"
|
||||
// Created by http://oleddisplay.squix.ch/
|
||||
// DejaVu Sans, Plain, Size 9Roboto Medium, Plain, 11
|
||||
const uint8_t Custom_Font[] PROGMEM = {
|
||||
0x0A, // Width: 10
|
||||
0x0A, // Height: 12 (hacked to 10)
|
||||
0x20, // First Char: 32
|
||||
0xE0, // Numbers of Chars: 224
|
||||
|
||||
// Jump Table:
|
||||
0xFF, 0xFF, 0x00, 0x03, // 32:65535
|
||||
0x00, 0x00, 0x04, 0x03, // 33:0
|
||||
0x00, 0x04, 0x07, 0x04, // 34:4
|
||||
0x00, 0x0B, 0x0D, 0x08, // 35:11
|
||||
0x00, 0x18, 0x09, 0x06, // 36:24
|
||||
0x00, 0x21, 0x10, 0x09, // 37:33
|
||||
0x00, 0x31, 0x0E, 0x08, // 38:49
|
||||
0x00, 0x3F, 0x03, 0x02, // 39:63
|
||||
0x00, 0x42, 0x06, 0x04, // 40:66
|
||||
0x00, 0x48, 0x05, 0x04, // 41:72
|
||||
0x00, 0x4D, 0x09, 0x05, // 42:77
|
||||
0x00, 0x56, 0x0B, 0x08, // 43:86
|
||||
0x00, 0x61, 0x04, 0x03, // 44:97
|
||||
0x00, 0x65, 0x05, 0x03, // 45:101
|
||||
0x00, 0x6A, 0x04, 0x03, // 46:106
|
||||
0x00, 0x6E, 0x05, 0x03, // 47:110
|
||||
0x00, 0x73, 0x09, 0x06, // 48:115
|
||||
0x00, 0x7C, 0x0A, 0x06, // 49:124
|
||||
0x00, 0x86, 0x0A, 0x06, // 50:134
|
||||
0x00, 0x90, 0x09, 0x06, // 51:144
|
||||
0x00, 0x99, 0x0B, 0x06, // 52:153
|
||||
0x00, 0xA4, 0x09, 0x06, // 53:164
|
||||
0x00, 0xAD, 0x09, 0x06, // 54:173
|
||||
0x00, 0xB6, 0x09, 0x06, // 55:182
|
||||
0x00, 0xBF, 0x09, 0x06, // 56:191
|
||||
0x00, 0xC8, 0x09, 0x06, // 57:200
|
||||
0x00, 0xD1, 0x04, 0x03, // 58:209
|
||||
0x00, 0xD5, 0x04, 0x03, // 59:213
|
||||
0x00, 0xD9, 0x0E, 0x08, // 60:217
|
||||
0x00, 0xE7, 0x0D, 0x08, // 61:231
|
||||
0x00, 0xF4, 0x0D, 0x08, // 62:244
|
||||
0x01, 0x01, 0x09, 0x05, // 63:257
|
||||
0x01, 0x0A, 0x11, 0x0A, // 64:266
|
||||
0x01, 0x1B, 0x0C, 0x06, // 65:283
|
||||
0x01, 0x27, 0x0B, 0x07, // 66:295
|
||||
0x01, 0x32, 0x0C, 0x07, // 67:306
|
||||
0x01, 0x3E, 0x0B, 0x07, // 68:318
|
||||
0x01, 0x49, 0x0A, 0x06, // 69:329
|
||||
0x01, 0x53, 0x09, 0x06, // 70:339
|
||||
0x01, 0x5C, 0x0B, 0x07, // 71:348
|
||||
0x01, 0x67, 0x0C, 0x07, // 72:359
|
||||
0x01, 0x73, 0x04, 0x03, // 73:371
|
||||
0x01, 0x77, 0x04, 0x03, // 74:375
|
||||
0x01, 0x7B, 0x0C, 0x06, // 75:379
|
||||
0x01, 0x87, 0x0A, 0x05, // 76:391
|
||||
0x01, 0x91, 0x0E, 0x08, // 77:401
|
||||
0x01, 0x9F, 0x0C, 0x07, // 78:415
|
||||
0x01, 0xAB, 0x0B, 0x07, // 79:427
|
||||
0x01, 0xB6, 0x09, 0x06, // 80:438
|
||||
0x01, 0xBF, 0x0B, 0x07, // 81:447
|
||||
0x01, 0xCA, 0x0C, 0x06, // 82:458
|
||||
0x01, 0xD6, 0x0B, 0x07, // 83:470
|
||||
0x01, 0xE1, 0x09, 0x05, // 84:481
|
||||
0x01, 0xEA, 0x0B, 0x07, // 85:490
|
||||
0x01, 0xF5, 0x0B, 0x06, // 86:501
|
||||
0x02, 0x00, 0x0D, 0x07, // 87:512
|
||||
0x02, 0x0D, 0x0C, 0x06, // 88:525
|
||||
0x02, 0x19, 0x09, 0x05, // 89:537
|
||||
0x02, 0x22, 0x0A, 0x05, // 90:546
|
||||
0x02, 0x2C, 0x06, 0x04, // 91:556
|
||||
0x02, 0x32, 0x06, 0x03, // 92:562
|
||||
0x02, 0x38, 0x06, 0x04, // 93:568
|
||||
0x02, 0x3E, 0x0B, 0x08, // 94:574
|
||||
0x02, 0x49, 0x0A, 0x05, // 95:585
|
||||
0x02, 0x53, 0x05, 0x05, // 96:595
|
||||
0x02, 0x58, 0x0A, 0x06, // 97:600
|
||||
0x02, 0x62, 0x09, 0x06, // 98:610
|
||||
0x02, 0x6B, 0x0A, 0x06, // 99:619
|
||||
0x02, 0x75, 0x0A, 0x06, // 100:629
|
||||
0x02, 0x7F, 0x0A, 0x06, // 101:639
|
||||
0x02, 0x89, 0x05, 0x03, // 102:649
|
||||
0x02, 0x8E, 0x0A, 0x06, // 103:654
|
||||
0x02, 0x98, 0x0A, 0x06, // 104:664
|
||||
0x02, 0xA2, 0x04, 0x03, // 105:674
|
||||
0x02, 0xA6, 0x04, 0x03, // 106:678
|
||||
0x02, 0xAA, 0x0A, 0x05, // 107:682
|
||||
0x02, 0xB4, 0x04, 0x03, // 108:692
|
||||
0x02, 0xB8, 0x10, 0x09, // 109:696
|
||||
0x02, 0xC8, 0x0A, 0x06, // 110:712
|
||||
0x02, 0xD2, 0x09, 0x06, // 111:722
|
||||
0x02, 0xDB, 0x09, 0x06, // 112:731
|
||||
0x02, 0xE4, 0x0A, 0x06, // 113:740
|
||||
0x02, 0xEE, 0x07, 0x04, // 114:750
|
||||
0x02, 0xF5, 0x08, 0x05, // 115:757
|
||||
0x02, 0xFD, 0x08, 0x04, // 116:765
|
||||
0x03, 0x05, 0x0A, 0x06, // 117:773
|
||||
0x03, 0x0F, 0x09, 0x05, // 118:783
|
||||
0x03, 0x18, 0x0D, 0x07, // 119:792
|
||||
0x03, 0x25, 0x0A, 0x05, // 120:805
|
||||
0x03, 0x2F, 0x09, 0x05, // 121:815
|
||||
0x03, 0x38, 0x0A, 0x06, // 122:824
|
||||
0x03, 0x42, 0x08, 0x05, // 123:834
|
||||
0x03, 0x4A, 0x04, 0x03, // 124:842
|
||||
0x03, 0x4E, 0x07, 0x05, // 125:846
|
||||
0x03, 0x55, 0x0D, 0x08, // 126:853
|
||||
0x03, 0x62, 0x0A, 0x05, // 127:866
|
||||
0x03, 0x6C, 0x0A, 0x05, // 128:876
|
||||
0x03, 0x76, 0x0A, 0x05, // 129:886
|
||||
0x03, 0x80, 0x0A, 0x05, // 130:896
|
||||
0x03, 0x8A, 0x0A, 0x05, // 131:906
|
||||
0x03, 0x94, 0x0A, 0x05, // 132:916
|
||||
0x03, 0x9E, 0x0A, 0x05, // 133:926
|
||||
0x03, 0xA8, 0x0A, 0x05, // 134:936
|
||||
0x03, 0xB2, 0x0A, 0x05, // 135:946
|
||||
0x03, 0xBC, 0x0A, 0x05, // 136:956
|
||||
0x03, 0xC6, 0x0A, 0x05, // 137:966
|
||||
0x03, 0xD0, 0x0A, 0x05, // 138:976
|
||||
0x03, 0xDA, 0x0A, 0x05, // 139:986
|
||||
0x03, 0xE4, 0x0A, 0x05, // 140:996
|
||||
0x03, 0xEE, 0x0A, 0x05, // 141:1006
|
||||
0x03, 0xF8, 0x0A, 0x05, // 142:1016
|
||||
0x04, 0x02, 0x0A, 0x05, // 143:1026
|
||||
0x04, 0x0C, 0x0A, 0x05, // 144:1036
|
||||
0x04, 0x16, 0x0A, 0x05, // 145:1046
|
||||
0x04, 0x20, 0x0A, 0x05, // 146:1056
|
||||
0x04, 0x2A, 0x0A, 0x05, // 147:1066
|
||||
0x04, 0x34, 0x0A, 0x05, // 148:1076
|
||||
0x04, 0x3E, 0x0A, 0x05, // 149:1086
|
||||
0x04, 0x48, 0x0A, 0x05, // 150:1096
|
||||
0x04, 0x52, 0x0A, 0x05, // 151:1106
|
||||
0x04, 0x5C, 0x0A, 0x05, // 152:1116
|
||||
0x04, 0x66, 0x0A, 0x05, // 153:1126
|
||||
0x04, 0x70, 0x0A, 0x05, // 154:1136
|
||||
0x04, 0x7A, 0x0A, 0x05, // 155:1146
|
||||
0x04, 0x84, 0x0A, 0x05, // 156:1156
|
||||
0x04, 0x8E, 0x0A, 0x05, // 157:1166
|
||||
0x04, 0x98, 0x0A, 0x05, // 158:1176
|
||||
0x04, 0xA2, 0x0A, 0x05, // 159:1186
|
||||
0xFF, 0xFF, 0x00, 0x03, // 160:65535
|
||||
0x04, 0xAC, 0x04, 0x03, // 161:1196
|
||||
0x04, 0xB0, 0x0A, 0x06, // 162:1200
|
||||
0x04, 0xBA, 0x0A, 0x06, // 163:1210
|
||||
0x04, 0xC4, 0x0C, 0x06, // 164:1220
|
||||
0x04, 0xD0, 0x09, 0x06, // 165:1232
|
||||
0x04, 0xD9, 0x04, 0x03, // 166:1241
|
||||
0x04, 0xDD, 0x0A, 0x05, // 167:1245
|
||||
0x04, 0xE7, 0x07, 0x05, // 168:1255
|
||||
0x04, 0xEE, 0x0F, 0x09, // 169:1262
|
||||
0x04, 0xFD, 0x07, 0x04, // 170:1277
|
||||
0x05, 0x04, 0x09, 0x06, // 171:1284
|
||||
0x05, 0x0D, 0x0D, 0x08, // 172:1293
|
||||
0x05, 0x1A, 0x05, 0x03, // 173:1306
|
||||
0x05, 0x1F, 0x0F, 0x09, // 174:1311
|
||||
0x05, 0x2E, 0x07, 0x05, // 175:1326
|
||||
0x05, 0x35, 0x07, 0x05, // 176:1333
|
||||
0x05, 0x3C, 0x0C, 0x08, // 177:1340
|
||||
0x05, 0x48, 0x07, 0x04, // 178:1352
|
||||
0x05, 0x4F, 0x07, 0x04, // 179:1359
|
||||
0x05, 0x56, 0x07, 0x05, // 180:1366
|
||||
0x05, 0x5D, 0x0C, 0x06, // 181:1373
|
||||
0x05, 0x69, 0x0A, 0x06, // 182:1385
|
||||
0x05, 0x73, 0x03, 0x03, // 183:1395
|
||||
0x05, 0x76, 0x06, 0x05, // 184:1398
|
||||
0x05, 0x7C, 0x07, 0x04, // 185:1404
|
||||
0x05, 0x83, 0x07, 0x04, // 186:1411
|
||||
0x05, 0x8A, 0x09, 0x06, // 187:1418
|
||||
0x05, 0x93, 0x11, 0x09, // 188:1427
|
||||
0x05, 0xA4, 0x12, 0x09, // 189:1444
|
||||
0x05, 0xB6, 0x11, 0x09, // 190:1462
|
||||
0x05, 0xC7, 0x0A, 0x05, // 191:1479
|
||||
0x05, 0xD1, 0x0C, 0x06, // 192:1489
|
||||
0x05, 0xDD, 0x0C, 0x06, // 193:1501
|
||||
0x05, 0xE9, 0x0C, 0x06, // 194:1513
|
||||
0x05, 0xF5, 0x0C, 0x06, // 195:1525
|
||||
0x06, 0x01, 0x0C, 0x06, // 196:1537
|
||||
0x06, 0x0D, 0x0C, 0x06, // 197:1549
|
||||
0x06, 0x19, 0x10, 0x09, // 198:1561
|
||||
0x06, 0x29, 0x0C, 0x07, // 199:1577
|
||||
0x06, 0x35, 0x0A, 0x06, // 200:1589
|
||||
0x06, 0x3F, 0x0A, 0x06, // 201:1599
|
||||
0x06, 0x49, 0x0A, 0x06, // 202:1609
|
||||
0x06, 0x53, 0x0A, 0x06, // 203:1619
|
||||
0x06, 0x5D, 0x05, 0x03, // 204:1629
|
||||
0x06, 0x62, 0x04, 0x03, // 205:1634
|
||||
0x06, 0x66, 0x05, 0x03, // 206:1638
|
||||
0x06, 0x6B, 0x05, 0x03, // 207:1643
|
||||
0x06, 0x70, 0x0B, 0x07, // 208:1648
|
||||
0x06, 0x7B, 0x0C, 0x07, // 209:1659
|
||||
0x06, 0x87, 0x0B, 0x07, // 210:1671
|
||||
0x06, 0x92, 0x0B, 0x07, // 211:1682
|
||||
0x06, 0x9D, 0x0B, 0x07, // 212:1693
|
||||
0x06, 0xA8, 0x0B, 0x07, // 213:1704
|
||||
0x06, 0xB3, 0x0B, 0x07, // 214:1715
|
||||
0x06, 0xBE, 0x0C, 0x08, // 215:1726
|
||||
0x06, 0xCA, 0x0B, 0x07, // 216:1738
|
||||
0x06, 0xD5, 0x0B, 0x07, // 217:1749
|
||||
0x06, 0xE0, 0x0B, 0x07, // 218:1760
|
||||
0x06, 0xEB, 0x0B, 0x07, // 219:1771
|
||||
0x06, 0xF6, 0x0B, 0x07, // 220:1782
|
||||
0x07, 0x01, 0x09, 0x05, // 221:1793
|
||||
0x07, 0x0A, 0x09, 0x06, // 222:1802
|
||||
0x07, 0x13, 0x0A, 0x06, // 223:1811
|
||||
0x07, 0x1D, 0x0A, 0x06, // 224:1821
|
||||
0x07, 0x27, 0x0A, 0x06, // 225:1831
|
||||
0x07, 0x31, 0x0A, 0x06, // 226:1841
|
||||
0x07, 0x3B, 0x0A, 0x06, // 227:1851
|
||||
0x07, 0x45, 0x0A, 0x06, // 228:1861
|
||||
0x07, 0x4F, 0x0A, 0x06, // 229:1871
|
||||
0x07, 0x59, 0x10, 0x09, // 230:1881
|
||||
0x07, 0x69, 0x0A, 0x06, // 231:1897
|
||||
0x07, 0x73, 0x0A, 0x06, // 232:1907
|
||||
0x07, 0x7D, 0x0A, 0x06, // 233:1917
|
||||
0x07, 0x87, 0x0A, 0x06, // 234:1927
|
||||
0x07, 0x91, 0x0A, 0x06, // 235:1937
|
||||
0x07, 0x9B, 0x04, 0x03, // 236:1947
|
||||
0x07, 0x9F, 0x05, 0x03, // 237:1951
|
||||
0x07, 0xA4, 0x05, 0x03, // 238:1956
|
||||
0x07, 0xA9, 0x05, 0x03, // 239:1961
|
||||
0x07, 0xAE, 0x09, 0x06, // 240:1966
|
||||
0x07, 0xB7, 0x0A, 0x06, // 241:1975
|
||||
0x07, 0xC1, 0x09, 0x06, // 242:1985
|
||||
0x07, 0xCA, 0x09, 0x06, // 243:1994
|
||||
0x07, 0xD3, 0x09, 0x06, // 244:2003
|
||||
0x07, 0xDC, 0x09, 0x06, // 245:2012
|
||||
0x07, 0xE5, 0x09, 0x06, // 246:2021
|
||||
0x07, 0xEE, 0x0B, 0x08, // 247:2030
|
||||
0x07, 0xF9, 0x09, 0x06, // 248:2041
|
||||
0x08, 0x02, 0x0A, 0x06, // 249:2050
|
||||
0x08, 0x0C, 0x0A, 0x06, // 250:2060
|
||||
0x08, 0x16, 0x0A, 0x06, // 251:2070
|
||||
0x08, 0x20, 0x0A, 0x06, // 252:2080
|
||||
0x08, 0x2A, 0x09, 0x05, // 253:2090
|
||||
0x08, 0x33, 0x09, 0x06, // 254:2099
|
||||
0x08, 0x3C, 0x09, 0x05, // 255:2108
|
||||
|
||||
// Font Data:
|
||||
0x00,0x00,0x7C,0x01, // 33
|
||||
0x00,0x00,0x0C,0x00,0x00,0x00,0x0C, // 34
|
||||
0x00,0x00,0x50,0x00,0xD0,0x01,0x7C,0x00,0xD0,0x01,0x7C,0x00,0x50, // 35
|
||||
0x30,0x01,0x28,0x01,0xFC,0x03,0x48,0x01,0xC8, // 36
|
||||
0x3C,0x00,0x24,0x00,0xBC,0x01,0x60,0x00,0x30,0x00,0xEC,0x01,0x20,0x01,0xE0,0x01, // 37
|
||||
0x00,0x00,0xC0,0x00,0x38,0x01,0x24,0x01,0xC4,0x00,0x88,0x01,0x60,0x01, // 38
|
||||
0x00,0x00,0x0C, // 39
|
||||
0x00,0x00,0xFC,0x00,0x02,0x01, // 40
|
||||
0x00,0x00,0x86,0x01,0x78, // 41
|
||||
0x24,0x00,0x18,0x00,0x3C,0x00,0x18,0x00,0x24, // 42
|
||||
0x00,0x00,0x40,0x00,0x40,0x00,0xF0,0x01,0x40,0x00,0x40, // 43
|
||||
0x00,0x00,0x00,0x03, // 44
|
||||
0x00,0x00,0x40,0x00,0x40, // 45
|
||||
0x00,0x00,0x00,0x01, // 46
|
||||
0x80,0x01,0x70,0x00,0x0C, // 47
|
||||
0x00,0x00,0xF8,0x00,0x04,0x01,0x04,0x01,0xF8, // 48
|
||||
0x00,0x00,0x00,0x00,0x04,0x01,0xFC,0x01,0x00,0x01, // 49
|
||||
0x00,0x00,0x88,0x01,0x44,0x01,0x24,0x01,0x18,0x01, // 50
|
||||
0x00,0x00,0x08,0x01,0x24,0x01,0x24,0x01,0xD8, // 51
|
||||
0x00,0x00,0xC0,0x00,0xB0,0x00,0x88,0x00,0xFC,0x01,0x80, // 52
|
||||
0x00,0x00,0x3C,0x01,0x24,0x01,0x24,0x01,0xC4, // 53
|
||||
0x00,0x00,0xF8,0x00,0x2C,0x01,0x24,0x01,0xC4, // 54
|
||||
0x00,0x00,0x04,0x00,0x84,0x01,0x74,0x00,0x0C, // 55
|
||||
0x00,0x00,0xD8,0x00,0x24,0x01,0x24,0x01,0xD8, // 56
|
||||
0x00,0x00,0x38,0x01,0x24,0x01,0xA4,0x01,0xF8, // 57
|
||||
0x00,0x00,0x10,0x01, // 58
|
||||
0x00,0x00,0x10,0x03, // 59
|
||||
0x00,0x00,0x40,0x00,0x40,0x00,0xA0,0x00,0xA0,0x00,0xA0,0x00,0x10,0x01, // 60
|
||||
0x00,0x00,0xA0,0x00,0xA0,0x00,0xA0,0x00,0xA0,0x00,0xA0,0x00,0xA0, // 61
|
||||
0x00,0x00,0x10,0x01,0xA0,0x00,0xA0,0x00,0xA0,0x00,0x40,0x00,0x40, // 62
|
||||
0x00,0x00,0x04,0x00,0x64,0x01,0x14,0x00,0x0C, // 63
|
||||
0x00,0x00,0xF0,0x00,0x08,0x01,0x64,0x02,0x94,0x02,0x94,0x02,0xF4,0x01,0x88,0x00,0x70, // 64
|
||||
0x80,0x01,0x70,0x00,0x4C,0x00,0x4C,0x00,0x70,0x00,0x80,0x01, // 65
|
||||
0x00,0x00,0xFC,0x01,0x24,0x01,0x24,0x01,0x24,0x01,0xD8, // 66
|
||||
0x00,0x00,0xF8,0x00,0x8C,0x01,0x04,0x01,0x04,0x01,0x08,0x01, // 67
|
||||
0x00,0x00,0xFC,0x01,0x04,0x01,0x04,0x01,0x8C,0x01,0xF8, // 68
|
||||
0x00,0x00,0xFC,0x01,0x24,0x01,0x24,0x01,0x24,0x01, // 69
|
||||
0x00,0x00,0xFC,0x01,0x24,0x00,0x24,0x00,0x24, // 70
|
||||
0x00,0x00,0xF8,0x00,0x8C,0x01,0x04,0x01,0x24,0x01,0xE8, // 71
|
||||
0x00,0x00,0xFC,0x01,0x20,0x00,0x20,0x00,0x20,0x00,0xFC,0x01, // 72
|
||||
0x00,0x00,0xFC,0x01, // 73
|
||||
0x00,0x04,0xFC,0x03, // 74
|
||||
0x00,0x00,0xFC,0x01,0x20,0x00,0x50,0x00,0x88,0x00,0x04,0x01, // 75
|
||||
0x00,0x00,0xFC,0x01,0x00,0x01,0x00,0x01,0x00,0x01, // 76
|
||||
0x00,0x00,0xFC,0x01,0x18,0x00,0x60,0x00,0x60,0x00,0x18,0x00,0xFC,0x01, // 77
|
||||
0x00,0x00,0xFC,0x01,0x18,0x00,0x20,0x00,0xC0,0x00,0xFC,0x01, // 78
|
||||
0x00,0x00,0xF8,0x00,0x8C,0x01,0x04,0x01,0x8C,0x01,0xF8, // 79
|
||||
0x00,0x00,0xFC,0x01,0x24,0x00,0x24,0x00,0x18, // 80
|
||||
0x00,0x00,0xF8,0x00,0x8C,0x01,0x04,0x01,0x8C,0x03,0xF8, // 81
|
||||
0x00,0x00,0xFC,0x01,0x24,0x00,0x64,0x00,0x9C,0x00,0x00,0x01, // 82
|
||||
0x00,0x00,0x98,0x00,0x24,0x01,0x24,0x01,0x24,0x01,0xC8, // 83
|
||||
0x04,0x00,0x04,0x00,0xFC,0x01,0x04,0x00,0x04, // 84
|
||||
0x00,0x00,0xFC,0x00,0x00,0x01,0x00,0x01,0x00,0x01,0xFC, // 85
|
||||
0x0C,0x00,0x70,0x00,0x80,0x01,0x80,0x01,0x70,0x00,0x0C, // 86
|
||||
0x0C,0x00,0x70,0x00,0xC0,0x01,0x3C,0x00,0xC0,0x01,0x70,0x00,0x0C, // 87
|
||||
0x04,0x01,0x8C,0x00,0x70,0x00,0x70,0x00,0x8C,0x01,0x04,0x01, // 88
|
||||
0x04,0x00,0x18,0x00,0xE0,0x01,0x18,0x00,0x04, // 89
|
||||
0x84,0x01,0x44,0x01,0x24,0x01,0x14,0x01,0x0C,0x01, // 90
|
||||
0x00,0x00,0xFC,0x03,0x04,0x02, // 91
|
||||
0x0C,0x00,0x70,0x00,0x80,0x01, // 92
|
||||
0x00,0x00,0x04,0x02,0xFC,0x03, // 93
|
||||
0x00,0x00,0x00,0x00,0x08,0x00,0x04,0x00,0x04,0x00,0x08, // 94
|
||||
0x00,0x04,0x00,0x04,0x00,0x04,0x00,0x04,0x00,0x04, // 95
|
||||
0x00,0x00,0x02,0x00,0x04, // 96
|
||||
0x00,0x00,0xC0,0x01,0x50,0x01,0x50,0x01,0xF0,0x01, // 97
|
||||
0x00,0x00,0xFE,0x01,0x10,0x01,0x10,0x01,0xE0, // 98
|
||||
0x00,0x00,0xE0,0x00,0x10,0x01,0x10,0x01,0x10,0x01, // 99
|
||||
0x00,0x00,0xE0,0x00,0x10,0x01,0x10,0x01,0xFE,0x01, // 100
|
||||
0x00,0x00,0xE0,0x00,0x50,0x01,0x50,0x01,0x60,0x01, // 101
|
||||
0x10,0x00,0xFE,0x01,0x12, // 102
|
||||
0x00,0x00,0xE0,0x00,0x10,0x05,0x10,0x05,0xF0,0x03, // 103
|
||||
0x00,0x00,0xFE,0x01,0x10,0x00,0x10,0x00,0xF0,0x01, // 104
|
||||
0x00,0x00,0xF4,0x01, // 105
|
||||
0x00,0x04,0xF4,0x07, // 106
|
||||
0x00,0x00,0xFE,0x01,0x40,0x00,0xA0,0x00,0x10,0x01, // 107
|
||||
0x00,0x00,0xFE,0x01, // 108
|
||||
0x00,0x00,0xF0,0x01,0x10,0x00,0x10,0x00,0xF0,0x01,0x10,0x00,0x10,0x00,0xF0,0x01, // 109
|
||||
0x00,0x00,0xF0,0x01,0x10,0x00,0x10,0x00,0xF0,0x01, // 110
|
||||
0x00,0x00,0xE0,0x00,0x10,0x01,0x10,0x01,0xE0, // 111
|
||||
0x00,0x00,0xF0,0x07,0x10,0x01,0x10,0x01,0xE0, // 112
|
||||
0x00,0x00,0xE0,0x00,0x10,0x01,0x10,0x01,0xF0,0x07, // 113
|
||||
0x00,0x00,0xF0,0x01,0x10,0x00,0x10, // 114
|
||||
0x00,0x00,0x30,0x01,0x50,0x01,0xD0,0x01, // 115
|
||||
0x10,0x00,0xF8,0x01,0x10,0x01,0x10,0x01, // 116
|
||||
0x00,0x00,0xF0,0x01,0x00,0x01,0x00,0x01,0xF0,0x01, // 117
|
||||
0x30,0x00,0xC0,0x00,0x00,0x01,0xC0,0x00,0x30, // 118
|
||||
0x70,0x00,0x80,0x01,0x60,0x00,0x10,0x00,0x60,0x00,0x80,0x01,0x70, // 119
|
||||
0x10,0x01,0xA0,0x00,0x40,0x00,0xA0,0x00,0x10,0x01, // 120
|
||||
0x30,0x04,0xC0,0x04,0x00,0x03,0xC0,0x00,0x30, // 121
|
||||
0x00,0x00,0x10,0x01,0x90,0x01,0x50,0x01,0x30,0x01, // 122
|
||||
0x00,0x00,0x20,0x00,0xDC,0x03,0x04,0x02, // 123
|
||||
0x00,0x00,0xFC,0x07, // 124
|
||||
0x00,0x00,0x04,0x02,0xDC,0x03,0x20, // 125
|
||||
0x00,0x00,0x40,0x00,0x20,0x00,0x20,0x00,0x40,0x00,0x40,0x00,0x20, // 126
|
||||
0xF8,0x07,0x08,0x04,0x08,0x04,0x08,0x04,0xF8,0x07, // 127
|
||||
0xF8,0x07,0x08,0x04,0x08,0x04,0x08,0x04,0xF8,0x07, // 128
|
||||
0xF8,0x07,0x08,0x04,0x08,0x04,0x08,0x04,0xF8,0x07, // 129
|
||||
0xF8,0x07,0x08,0x04,0x08,0x04,0x08,0x04,0xF8,0x07, // 130
|
||||
0xF8,0x07,0x08,0x04,0x08,0x04,0x08,0x04,0xF8,0x07, // 131
|
||||
0xF8,0x07,0x08,0x04,0x08,0x04,0x08,0x04,0xF8,0x07, // 132
|
||||
0xF8,0x07,0x08,0x04,0x08,0x04,0x08,0x04,0xF8,0x07, // 133
|
||||
0xF8,0x07,0x08,0x04,0x08,0x04,0x08,0x04,0xF8,0x07, // 134
|
||||
0xF8,0x07,0x08,0x04,0x08,0x04,0x08,0x04,0xF8,0x07, // 135
|
||||
0xF8,0x07,0x08,0x04,0x08,0x04,0x08,0x04,0xF8,0x07, // 136
|
||||
0xF8,0x07,0x08,0x04,0x08,0x04,0x08,0x04,0xF8,0x07, // 137
|
||||
0xF8,0x07,0x08,0x04,0x08,0x04,0x08,0x04,0xF8,0x07, // 138
|
||||
0xF8,0x07,0x08,0x04,0x08,0x04,0x08,0x04,0xF8,0x07, // 139
|
||||
0xF8,0x07,0x08,0x04,0x08,0x04,0x08,0x04,0xF8,0x07, // 140
|
||||
0xF8,0x07,0x08,0x04,0x08,0x04,0x08,0x04,0xF8,0x07, // 141
|
||||
0xF8,0x07,0x08,0x04,0x08,0x04,0x08,0x04,0xF8,0x07, // 142
|
||||
0xF8,0x07,0x08,0x04,0x08,0x04,0x08,0x04,0xF8,0x07, // 143
|
||||
0xF8,0x07,0x08,0x04,0x08,0x04,0x08,0x04,0xF8,0x07, // 144
|
||||
0xF8,0x07,0x08,0x04,0x08,0x04,0x08,0x04,0xF8,0x07, // 145
|
||||
0xF8,0x07,0x08,0x04,0x08,0x04,0x08,0x04,0xF8,0x07, // 146
|
||||
0xF8,0x07,0x08,0x04,0x08,0x04,0x08,0x04,0xF8,0x07, // 147
|
||||
0xF8,0x07,0x08,0x04,0x08,0x04,0x08,0x04,0xF8,0x07, // 148
|
||||
0xF8,0x07,0x08,0x04,0x08,0x04,0x08,0x04,0xF8,0x07, // 149
|
||||
0xF8,0x07,0x08,0x04,0x08,0x04,0x08,0x04,0xF8,0x07, // 150
|
||||
0xF8,0x07,0x08,0x04,0x08,0x04,0x08,0x04,0xF8,0x07, // 151
|
||||
0xF8,0x07,0x08,0x04,0x08,0x04,0x08,0x04,0xF8,0x07, // 152
|
||||
0xF8,0x07,0x08,0x04,0x08,0x04,0x08,0x04,0xF8,0x07, // 153
|
||||
0xF8,0x07,0x08,0x04,0x08,0x04,0x08,0x04,0xF8,0x07, // 154
|
||||
0xF8,0x07,0x08,0x04,0x08,0x04,0x08,0x04,0xF8,0x07, // 155
|
||||
0xF8,0x07,0x08,0x04,0x08,0x04,0x08,0x04,0xF8,0x07, // 156
|
||||
0xF8,0x07,0x08,0x04,0x08,0x04,0x08,0x04,0xF8,0x07, // 157
|
||||
0xF8,0x07,0x08,0x04,0x08,0x04,0x08,0x04,0xF8,0x07, // 158
|
||||
0xF8,0x07,0x08,0x04,0x08,0x04,0x08,0x04,0xF8,0x07, // 159
|
||||
0x00,0x00,0xD0,0x07, // 161
|
||||
0x00,0x00,0xE0,0x00,0x10,0x01,0xF8,0x03,0x10,0x01, // 162
|
||||
0x00,0x00,0x20,0x01,0xF8,0x01,0x24,0x01,0x24,0x01, // 163
|
||||
0x08,0x01,0xF0,0x00,0x90,0x00,0x90,0x00,0xF0,0x00,0x08,0x01, // 164
|
||||
0xA4,0x00,0xB8,0x00,0xE0,0x01,0xB8,0x00,0xA4, // 165
|
||||
0x00,0x00,0xB8,0x03, // 166
|
||||
0x00,0x00,0x6C,0x02,0x54,0x02,0xB4,0x02,0x64,0x03, // 167
|
||||
0x00,0x00,0x04,0x00,0x00,0x00,0x04, // 168
|
||||
0x00,0x00,0x70,0x00,0x88,0x00,0x74,0x01,0x54,0x01,0x54,0x01,0x88,0x00,0x70, // 169
|
||||
0x00,0x00,0xB0,0x00,0xB4,0x00,0xBC, // 170
|
||||
0x00,0x00,0x60,0x00,0xF0,0x00,0x60,0x00,0xF0, // 171
|
||||
0x00,0x00,0x20,0x00,0x20,0x00,0x20,0x00,0x20,0x00,0x20,0x00,0xE0, // 172
|
||||
0x00,0x00,0x40,0x00,0x40, // 173
|
||||
0x00,0x00,0x70,0x00,0x88,0x00,0x74,0x01,0x34,0x01,0x74,0x01,0x88,0x00,0x70, // 174
|
||||
0x00,0x00,0x02,0x00,0x02,0x00,0x02, // 175
|
||||
0x00,0x00,0x1C,0x00,0x14,0x00,0x1C, // 176
|
||||
0x00,0x00,0x20,0x01,0x20,0x01,0xF8,0x01,0x20,0x01,0x20,0x01, // 177
|
||||
0x00,0x00,0x24,0x00,0x34,0x00,0x2C, // 178
|
||||
0x00,0x00,0x24,0x00,0x34,0x00,0x2C, // 179
|
||||
0x00,0x00,0x00,0x00,0x04,0x00,0x02, // 180
|
||||
0x00,0x00,0xF0,0x07,0x00,0x01,0x00,0x01,0xF0,0x01,0x00,0x01, // 181
|
||||
0x00,0x00,0x3C,0x00,0xFC,0x03,0x04,0x00,0xFC,0x03, // 182
|
||||
0x00,0x00,0x20, // 183
|
||||
0x00,0x00,0x00,0x04,0x00,0x06, // 184
|
||||
0x00,0x00,0x24,0x00,0x3C,0x00,0x20, // 185
|
||||
0x00,0x00,0xBC,0x00,0xA4,0x00,0xBC, // 186
|
||||
0x00,0x00,0xF0,0x00,0x60,0x00,0xF0,0x00,0x60, // 187
|
||||
0x00,0x00,0x24,0x00,0x3C,0x01,0xE0,0x00,0x70,0x00,0x18,0x00,0xC4,0x00,0xE0,0x01,0x80, // 188
|
||||
0x00,0x00,0x24,0x00,0x3C,0x01,0xE0,0x00,0x70,0x00,0x18,0x00,0x24,0x01,0xA0,0x01,0x60,0x01, // 189
|
||||
0x00,0x00,0x24,0x00,0x34,0x01,0xEC,0x00,0x70,0x00,0x18,0x00,0xC4,0x00,0xE0,0x01,0x80, // 190
|
||||
0x00,0x00,0x00,0x06,0x00,0x05,0xD0,0x04,0x00,0x04, // 191
|
||||
0x80,0x01,0x70,0x00,0x4C,0x00,0x4D,0x00,0x70,0x00,0x80,0x01, // 192
|
||||
0x80,0x01,0x70,0x00,0x4D,0x00,0x4C,0x00,0x70,0x00,0x80,0x01, // 193
|
||||
0x80,0x01,0x71,0x00,0x4C,0x00,0x4C,0x00,0x71,0x00,0x80,0x01, // 194
|
||||
0x80,0x01,0x70,0x00,0x4D,0x00,0x4D,0x00,0x70,0x00,0x80,0x01, // 195
|
||||
0x80,0x01,0x71,0x00,0x4C,0x00,0x4C,0x00,0x71,0x00,0x80,0x01, // 196
|
||||
0x00,0x01,0xC0,0x00,0xBF,0x00,0xBB,0x00,0xC0,0x00,0x00,0x01, // 197
|
||||
0x00,0x01,0xE0,0x00,0x98,0x00,0x84,0x00,0xFC,0x01,0x24,0x01,0x24,0x01,0x24,0x01, // 198
|
||||
0x00,0x00,0xF8,0x00,0x8C,0x05,0x04,0x07,0x04,0x01,0x08,0x01, // 199
|
||||
0x00,0x00,0xFC,0x01,0x24,0x01,0x25,0x01,0x24,0x01, // 200
|
||||
0x00,0x00,0xFC,0x01,0x25,0x01,0x24,0x01,0x24,0x01, // 201
|
||||
0x00,0x00,0xFD,0x01,0x24,0x01,0x25,0x01,0x24,0x01, // 202
|
||||
0x00,0x00,0xFD,0x01,0x24,0x01,0x25,0x01,0x24,0x01, // 203
|
||||
0x00,0x00,0xFC,0x01,0x01, // 204
|
||||
0x00,0x00,0xFD,0x01, // 205
|
||||
0x01,0x00,0xFC,0x01,0x01, // 206
|
||||
0x01,0x00,0xFC,0x01,0x01, // 207
|
||||
0x20,0x00,0xFC,0x01,0x24,0x01,0x04,0x01,0x8C,0x01,0xF8, // 208
|
||||
0x00,0x00,0xFC,0x01,0x19,0x00,0x21,0x00,0xC1,0x00,0xFC,0x01, // 209
|
||||
0x00,0x00,0xF8,0x00,0x8C,0x01,0x04,0x01,0x8D,0x01,0xF8, // 210
|
||||
0x00,0x00,0xF8,0x00,0x8C,0x01,0x05,0x01,0x8C,0x01,0xF8, // 211
|
||||
0x00,0x00,0xF8,0x00,0x8D,0x01,0x04,0x01,0x8D,0x01,0xF8, // 212
|
||||
0x00,0x00,0xF8,0x00,0x8D,0x01,0x05,0x01,0x8D,0x01,0xF8, // 213
|
||||
0x00,0x00,0xF8,0x00,0x8D,0x01,0x04,0x01,0x8D,0x01,0xF8, // 214
|
||||
0x00,0x00,0x10,0x01,0xA0,0x00,0x40,0x00,0xA0,0x00,0x10,0x01, // 215
|
||||
0x00,0x00,0x78,0x01,0xCC,0x01,0x34,0x01,0x8C,0x01,0xF4, // 216
|
||||
0x00,0x00,0xFC,0x00,0x00,0x01,0x00,0x01,0x01,0x01,0xFC, // 217
|
||||
0x00,0x00,0xFC,0x00,0x00,0x01,0x01,0x01,0x00,0x01,0xFC, // 218
|
||||
0x00,0x00,0xFC,0x00,0x01,0x01,0x00,0x01,0x01,0x01,0xFC, // 219
|
||||
0x00,0x00,0xFC,0x00,0x01,0x01,0x00,0x01,0x01,0x01,0xFC, // 220
|
||||
0x04,0x00,0x18,0x00,0xE1,0x01,0x18,0x00,0x04, // 221
|
||||
0x00,0x00,0xFC,0x01,0x48,0x00,0x48,0x00,0x30, // 222
|
||||
0x00,0x00,0xFE,0x01,0x12,0x00,0x2A,0x01,0xC4,0x01, // 223
|
||||
0x00,0x00,0xC2,0x01,0x54,0x01,0x50,0x01,0xF0,0x01, // 224
|
||||
0x00,0x00,0xC0,0x01,0x54,0x01,0x52,0x01,0xF0,0x01, // 225
|
||||
0x00,0x00,0xC0,0x01,0x56,0x01,0x54,0x01,0xF0,0x01, // 226
|
||||
0x00,0x00,0xC6,0x01,0x52,0x01,0x54,0x01,0xF6,0x01, // 227
|
||||
0x00,0x00,0xC4,0x01,0x50,0x01,0x50,0x01,0xF4,0x01, // 228
|
||||
0x00,0x00,0xC0,0x01,0x57,0x01,0x55,0x01,0xF7,0x01, // 229
|
||||
0x00,0x00,0xC0,0x01,0x50,0x01,0x50,0x01,0xE0,0x00,0x50,0x01,0x50,0x01,0x60,0x01, // 230
|
||||
0x00,0x00,0xE0,0x00,0x10,0x05,0x10,0x07,0x10,0x01, // 231
|
||||
0x00,0x00,0xE0,0x00,0x52,0x01,0x54,0x01,0x60,0x01, // 232
|
||||
0x00,0x00,0xE0,0x00,0x50,0x01,0x54,0x01,0x62,0x01, // 233
|
||||
0x00,0x00,0xE4,0x00,0x52,0x01,0x52,0x01,0x64,0x01, // 234
|
||||
0x00,0x00,0xE0,0x00,0x54,0x01,0x50,0x01,0x64,0x01, // 235
|
||||
0x02,0x00,0xF4,0x01, // 236
|
||||
0x00,0x00,0xF4,0x01,0x02, // 237
|
||||
0x04,0x00,0xF2,0x01,0x04, // 238
|
||||
0x04,0x00,0xF0,0x01,0x04, // 239
|
||||
0x00,0x00,0xE0,0x00,0x14,0x01,0x1C,0x01,0xE0, // 240
|
||||
0x00,0x00,0xF6,0x01,0x12,0x00,0x14,0x00,0xF6,0x01, // 241
|
||||
0x00,0x00,0xE0,0x00,0x12,0x01,0x14,0x01,0xE0, // 242
|
||||
0x00,0x00,0xE0,0x00,0x10,0x01,0x14,0x01,0xE2, // 243
|
||||
0x00,0x00,0xE0,0x00,0x16,0x01,0x14,0x01,0xE0, // 244
|
||||
0x00,0x00,0xE6,0x00,0x12,0x01,0x14,0x01,0xE6, // 245
|
||||
0x00,0x00,0xE4,0x00,0x10,0x01,0x10,0x01,0xE4, // 246
|
||||
0x00,0x00,0x40,0x00,0x40,0x00,0x50,0x01,0x40,0x00,0x40, // 247
|
||||
0x00,0x00,0xE0,0x01,0xD0,0x01,0x30,0x01,0xF0, // 248
|
||||
0x00,0x00,0xF0,0x01,0x02,0x01,0x04,0x01,0xF0,0x01, // 249
|
||||
0x00,0x00,0xF0,0x01,0x00,0x01,0x04,0x01,0xF2,0x01, // 250
|
||||
0x00,0x00,0xF0,0x01,0x06,0x01,0x04,0x01,0xF0,0x01, // 251
|
||||
0x00,0x00,0xF4,0x01,0x00,0x01,0x00,0x01,0xF4,0x01, // 252
|
||||
0x30,0x04,0xC0,0x04,0x04,0x03,0xC2,0x00,0x30, // 253
|
||||
0x00,0x00,0xFE,0x07,0x10,0x01,0x10,0x01,0xE0, // 254
|
||||
0x30,0x04,0xC4,0x04,0x00,0x03,0xC4,0x00,0x30 // 255
|
||||
};
|
|
@ -0,0 +1,3 @@
|
|||
#pragma once
|
||||
|
||||
extern const uint8_t Custom_Font[] PROGMEM;
|
423
main/fonts.h
423
main/fonts.h
|
@ -1,423 +0,0 @@
|
|||
const uint8_t Custom_ArialMT_Plain_10[] PROGMEM = {
|
||||
0x0A, // Width: 10
|
||||
0x0A, // Height: 10
|
||||
0x20, // First Char: 32
|
||||
0xE0, // Numbers of Chars: 224
|
||||
|
||||
// Jump Table:
|
||||
0xFF, 0xFF, 0x00, 0x03, // 32:65535
|
||||
0x00, 0x00, 0x04, 0x03, // 33:0
|
||||
0x00, 0x04, 0x05, 0x04, // 34:4
|
||||
0x00, 0x09, 0x09, 0x06, // 35:9
|
||||
0x00, 0x12, 0x0A, 0x06, // 36:18
|
||||
0x00, 0x1C, 0x10, 0x09, // 37:28
|
||||
0x00, 0x2C, 0x0E, 0x07, // 38:44
|
||||
0x00, 0x3A, 0x01, 0x02, // 39:58
|
||||
0x00, 0x3B, 0x06, 0x03, // 40:59
|
||||
0x00, 0x41, 0x06, 0x03, // 41:65
|
||||
0x00, 0x47, 0x05, 0x04, // 42:71
|
||||
0x00, 0x4C, 0x09, 0x06, // 43:76
|
||||
0x00, 0x55, 0x04, 0x03, // 44:85
|
||||
0x00, 0x59, 0x03, 0x03, // 45:89
|
||||
0x00, 0x5C, 0x04, 0x03, // 46:92
|
||||
0x00, 0x60, 0x05, 0x03, // 47:96
|
||||
0x00, 0x65, 0x0A, 0x06, // 48:101
|
||||
0x00, 0x6F, 0x08, 0x06, // 49:111
|
||||
0x00, 0x77, 0x0A, 0x06, // 50:119
|
||||
0x00, 0x81, 0x0A, 0x06, // 51:129
|
||||
0x00, 0x8B, 0x0B, 0x06, // 52:139
|
||||
0x00, 0x96, 0x0A, 0x06, // 53:150
|
||||
0x00, 0xA0, 0x0A, 0x06, // 54:160
|
||||
0x00, 0xAA, 0x09, 0x06, // 55:170
|
||||
0x00, 0xB3, 0x0A, 0x06, // 56:179
|
||||
0x00, 0xBD, 0x0A, 0x06, // 57:189
|
||||
0x00, 0xC7, 0x04, 0x03, // 58:199
|
||||
0x00, 0xCB, 0x04, 0x03, // 59:203
|
||||
0x00, 0xCF, 0x0A, 0x06, // 60:207
|
||||
0x00, 0xD9, 0x09, 0x06, // 61:217
|
||||
0x00, 0xE2, 0x09, 0x06, // 62:226
|
||||
0x00, 0xEB, 0x0B, 0x06, // 63:235
|
||||
0x00, 0xF6, 0x14, 0x0A, // 64:246
|
||||
0x01, 0x0A, 0x0E, 0x07, // 65:266
|
||||
0x01, 0x18, 0x0C, 0x07, // 66:280
|
||||
0x01, 0x24, 0x0C, 0x07, // 67:292
|
||||
0x01, 0x30, 0x0B, 0x07, // 68:304
|
||||
0x01, 0x3B, 0x0C, 0x07, // 69:315
|
||||
0x01, 0x47, 0x09, 0x06, // 70:327
|
||||
0x01, 0x50, 0x0D, 0x08, // 71:336
|
||||
0x01, 0x5D, 0x0C, 0x07, // 72:349
|
||||
0x01, 0x69, 0x04, 0x03, // 73:361
|
||||
0x01, 0x6D, 0x08, 0x05, // 74:365
|
||||
0x01, 0x75, 0x0E, 0x07, // 75:373
|
||||
0x01, 0x83, 0x0C, 0x06, // 76:387
|
||||
0x01, 0x8F, 0x10, 0x08, // 77:399
|
||||
0x01, 0x9F, 0x0C, 0x07, // 78:415
|
||||
0x01, 0xAB, 0x0E, 0x08, // 79:427
|
||||
0x01, 0xB9, 0x0B, 0x07, // 80:441
|
||||
0x01, 0xC4, 0x0E, 0x08, // 81:452
|
||||
0x01, 0xD2, 0x0C, 0x07, // 82:466
|
||||
0x01, 0xDE, 0x0C, 0x07, // 83:478
|
||||
0x01, 0xEA, 0x0B, 0x06, // 84:490
|
||||
0x01, 0xF5, 0x0C, 0x07, // 85:501
|
||||
0x02, 0x01, 0x0D, 0x07, // 86:513
|
||||
0x02, 0x0E, 0x11, 0x09, // 87:526
|
||||
0x02, 0x1F, 0x0E, 0x07, // 88:543
|
||||
0x02, 0x2D, 0x0D, 0x07, // 89:557
|
||||
0x02, 0x3A, 0x0C, 0x06, // 90:570
|
||||
0x02, 0x46, 0x06, 0x03, // 91:582
|
||||
0x02, 0x4C, 0x06, 0x03, // 92:588
|
||||
0x02, 0x52, 0x04, 0x03, // 93:594
|
||||
0x02, 0x56, 0x09, 0x05, // 94:598
|
||||
0x02, 0x5F, 0x0C, 0x06, // 95:607
|
||||
0x02, 0x6B, 0x03, 0x03, // 96:619
|
||||
0x02, 0x6E, 0x0A, 0x06, // 97:622
|
||||
0x02, 0x78, 0x0A, 0x06, // 98:632
|
||||
0x02, 0x82, 0x0A, 0x05, // 99:642
|
||||
0x02, 0x8C, 0x0A, 0x06, // 100:652
|
||||
0x02, 0x96, 0x0A, 0x06, // 101:662
|
||||
0x02, 0xA0, 0x05, 0x03, // 102:672
|
||||
0x02, 0xA5, 0x0A, 0x06, // 103:677
|
||||
0x02, 0xAF, 0x0A, 0x06, // 104:687
|
||||
0x02, 0xB9, 0x04, 0x02, // 105:697
|
||||
0x02, 0xBD, 0x04, 0x02, // 106:701
|
||||
0x02, 0xC1, 0x08, 0x05, // 107:705
|
||||
0x02, 0xC9, 0x04, 0x02, // 108:713
|
||||
0x02, 0xCD, 0x10, 0x08, // 109:717
|
||||
0x02, 0xDD, 0x0A, 0x06, // 110:733
|
||||
0x02, 0xE7, 0x0A, 0x06, // 111:743
|
||||
0x02, 0xF1, 0x0A, 0x06, // 112:753
|
||||
0x02, 0xFB, 0x0A, 0x06, // 113:763
|
||||
0x03, 0x05, 0x05, 0x03, // 114:773
|
||||
0x03, 0x0A, 0x08, 0x05, // 115:778
|
||||
0x03, 0x12, 0x06, 0x03, // 116:786
|
||||
0x03, 0x18, 0x0A, 0x06, // 117:792
|
||||
0x03, 0x22, 0x09, 0x05, // 118:802
|
||||
0x03, 0x2B, 0x0E, 0x07, // 119:811
|
||||
0x03, 0x39, 0x0A, 0x05, // 120:825
|
||||
0x03, 0x43, 0x09, 0x05, // 121:835
|
||||
0x03, 0x4C, 0x0A, 0x05, // 122:844
|
||||
0x03, 0x56, 0x06, 0x03, // 123:854
|
||||
0x03, 0x5C, 0x04, 0x03, // 124:860
|
||||
0x03, 0x60, 0x05, 0x03, // 125:864
|
||||
0x03, 0x65, 0x09, 0x06, // 126:869
|
||||
0xFF, 0xFF, 0x00, 0x00, // 127:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 128:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 129:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 130:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 131:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 132:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 133:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 134:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 135:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 136:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 137:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 138:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 139:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 140:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 141:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 142:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 143:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 144:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 145:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 146:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 147:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 148:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 149:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 150:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 151:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 152:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 153:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 154:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 155:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 156:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 157:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 158:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 159:65535
|
||||
0xFF, 0xFF, 0x00, 0x03, // 160:65535
|
||||
0x03, 0x6E, 0x04, 0x03, // 161:878
|
||||
0x03, 0x72, 0x0A, 0x06, // 162:882
|
||||
0x03, 0x7C, 0x0C, 0x06, // 163:892
|
||||
0x03, 0x88, 0x0A, 0x06, // 164:904
|
||||
0x03, 0x92, 0x0A, 0x06, // 165:914
|
||||
0x03, 0x9C, 0x04, 0x03, // 166:924
|
||||
0x03, 0xA0, 0x0A, 0x06, // 167:928
|
||||
0x03, 0xAA, 0x05, 0x03, // 168:938
|
||||
0x03, 0xAF, 0x0D, 0x07, // 169:943
|
||||
0x03, 0xBC, 0x07, 0x04, // 170:956
|
||||
0x03, 0xC3, 0x0A, 0x06, // 171:963
|
||||
0x03, 0xCD, 0x09, 0x06, // 172:973
|
||||
0x03, 0xD6, 0x03, 0x03, // 173:982
|
||||
0x03, 0xD9, 0x0D, 0x07, // 174:985
|
||||
0x03, 0xE6, 0x0B, 0x06, // 175:998
|
||||
0x03, 0xF1, 0x07, 0x04, // 176:1009
|
||||
0x03, 0xF8, 0x0A, 0x05, // 177:1016
|
||||
0x04, 0x02, 0x05, 0x03, // 178:1026
|
||||
0x04, 0x07, 0x05, 0x03, // 179:1031
|
||||
0x04, 0x0C, 0x05, 0x03, // 180:1036
|
||||
0x04, 0x11, 0x0A, 0x06, // 181:1041
|
||||
0x04, 0x1B, 0x09, 0x05, // 182:1051
|
||||
0x04, 0x24, 0x03, 0x03, // 183:1060
|
||||
0x04, 0x27, 0x06, 0x03, // 184:1063
|
||||
0x04, 0x2D, 0x05, 0x03, // 185:1069
|
||||
0x04, 0x32, 0x07, 0x04, // 186:1074
|
||||
0x04, 0x39, 0x0A, 0x06, // 187:1081
|
||||
0x04, 0x43, 0x10, 0x08, // 188:1091
|
||||
0x04, 0x53, 0x10, 0x08, // 189:1107
|
||||
0x04, 0x63, 0x10, 0x08, // 190:1123
|
||||
0x04, 0x73, 0x0A, 0x06, // 191:1139
|
||||
0x04, 0x7D, 0x0E, 0x07, // 192:1149
|
||||
0x04, 0x8B, 0x0E, 0x07, // 193:1163
|
||||
0x04, 0x99, 0x0E, 0x07, // 194:1177
|
||||
0x04, 0xA7, 0x0E, 0x07, // 195:1191
|
||||
0x04, 0xB5, 0x0E, 0x07, // 196:1205
|
||||
0x04, 0xC3, 0x0E, 0x07, // 197:1219
|
||||
0x04, 0xD1, 0x12, 0x0A, // 198:1233
|
||||
0x04, 0xE3, 0x0C, 0x07, // 199:1251
|
||||
0x04, 0xEF, 0x0C, 0x07, // 200:1263
|
||||
0x04, 0xFB, 0x0C, 0x07, // 201:1275
|
||||
0x05, 0x07, 0x0C, 0x07, // 202:1287
|
||||
0x05, 0x13, 0x0C, 0x07, // 203:1299
|
||||
0x05, 0x1F, 0x05, 0x03, // 204:1311
|
||||
0x05, 0x24, 0x04, 0x03, // 205:1316
|
||||
0x05, 0x28, 0x04, 0x03, // 206:1320
|
||||
0x05, 0x2C, 0x05, 0x03, // 207:1324
|
||||
0x05, 0x31, 0x0B, 0x07, // 208:1329
|
||||
0x05, 0x3C, 0x0C, 0x07, // 209:1340
|
||||
0x05, 0x48, 0x0E, 0x08, // 210:1352
|
||||
0x05, 0x56, 0x0E, 0x08, // 211:1366
|
||||
0x05, 0x64, 0x0E, 0x08, // 212:1380
|
||||
0x05, 0x72, 0x0E, 0x08, // 213:1394
|
||||
0x05, 0x80, 0x0E, 0x08, // 214:1408
|
||||
0x05, 0x8E, 0x0A, 0x06, // 215:1422
|
||||
0x05, 0x98, 0x0D, 0x08, // 216:1432
|
||||
0x05, 0xA5, 0x0C, 0x07, // 217:1445
|
||||
0x05, 0xB1, 0x0C, 0x07, // 218:1457
|
||||
0x05, 0xBD, 0x0C, 0x07, // 219:1469
|
||||
0x05, 0xC9, 0x0C, 0x07, // 220:1481
|
||||
0x05, 0xD5, 0x0D, 0x07, // 221:1493
|
||||
0x05, 0xE2, 0x0B, 0x07, // 222:1506
|
||||
0x05, 0xED, 0x0C, 0x06, // 223:1517
|
||||
0x05, 0xF9, 0x0A, 0x06, // 224:1529
|
||||
0x06, 0x03, 0x0A, 0x06, // 225:1539
|
||||
0x06, 0x0D, 0x0A, 0x06, // 226:1549
|
||||
0x06, 0x17, 0x0A, 0x06, // 227:1559
|
||||
0x06, 0x21, 0x0A, 0x06, // 228:1569
|
||||
0x06, 0x2B, 0x0A, 0x06, // 229:1579
|
||||
0x06, 0x35, 0x10, 0x09, // 230:1589
|
||||
0x06, 0x45, 0x0A, 0x05, // 231:1605
|
||||
0x06, 0x4F, 0x0A, 0x06, // 232:1615
|
||||
0x06, 0x59, 0x0A, 0x06, // 233:1625
|
||||
0x06, 0x63, 0x0A, 0x06, // 234:1635
|
||||
0x06, 0x6D, 0x0A, 0x06, // 235:1645
|
||||
0x06, 0x77, 0x05, 0x03, // 236:1655
|
||||
0x06, 0x7C, 0x04, 0x03, // 237:1660
|
||||
0x06, 0x80, 0x05, 0x03, // 238:1664
|
||||
0x06, 0x85, 0x05, 0x03, // 239:1669
|
||||
0x06, 0x8A, 0x0A, 0x06, // 240:1674
|
||||
0x06, 0x94, 0x0A, 0x06, // 241:1684
|
||||
0x06, 0x9E, 0x0A, 0x06, // 242:1694
|
||||
0x06, 0xA8, 0x0A, 0x06, // 243:1704
|
||||
0x06, 0xB2, 0x0A, 0x06, // 244:1714
|
||||
0x06, 0xBC, 0x0A, 0x06, // 245:1724
|
||||
0x06, 0xC6, 0x0A, 0x06, // 246:1734
|
||||
0x06, 0xD0, 0x09, 0x05, // 247:1744
|
||||
0x06, 0xD9, 0x0A, 0x06, // 248:1753
|
||||
0x06, 0xE3, 0x0A, 0x06, // 249:1763
|
||||
0x06, 0xED, 0x0A, 0x06, // 250:1773
|
||||
0x06, 0xF7, 0x0A, 0x06, // 251:1783
|
||||
0x07, 0x01, 0x0A, 0x06, // 252:1793
|
||||
0x07, 0x0B, 0x09, 0x05, // 253:1803
|
||||
0x07, 0x14, 0x0A, 0x06, // 254:1812
|
||||
0x07, 0x1E, 0x09, 0x05, // 255:1822
|
||||
|
||||
// Font Data:
|
||||
0x00,0x00,0xF8,0x02, // 33
|
||||
0x38,0x00,0x00,0x00,0x38, // 34
|
||||
0xA0,0x03,0xE0,0x00,0xB8,0x03,0xE0,0x00,0xB8, // 35
|
||||
0x30,0x01,0x28,0x02,0xF8,0x07,0x48,0x02,0x90,0x01, // 36
|
||||
0x00,0x00,0x30,0x00,0x48,0x00,0x30,0x03,0xC0,0x00,0xB0,0x01,0x48,0x02,0x80,0x01, // 37
|
||||
0x80,0x01,0x50,0x02,0x68,0x02,0xA8,0x02,0x18,0x01,0x80,0x03,0x80,0x02, // 38
|
||||
0x38, // 39
|
||||
0xE0,0x03,0x10,0x04,0x08,0x08, // 40
|
||||
0x08,0x08,0x10,0x04,0xE0,0x03, // 41
|
||||
0x28,0x00,0x18,0x00,0x28, // 42
|
||||
0x40,0x00,0x40,0x00,0xF0,0x01,0x40,0x00,0x40, // 43
|
||||
0x00,0x00,0x00,0x06, // 44
|
||||
0x80,0x00,0x80, // 45
|
||||
0x00,0x00,0x00,0x02, // 46
|
||||
0x00,0x03,0xE0,0x00,0x18, // 47
|
||||
0xF0,0x01,0x08,0x02,0x08,0x02,0x08,0x02,0xF0,0x01, // 48
|
||||
0x00,0x00,0x20,0x00,0x10,0x00,0xF8,0x03, // 49
|
||||
0x10,0x02,0x08,0x03,0x88,0x02,0x48,0x02,0x30,0x02, // 50
|
||||
0x10,0x01,0x08,0x02,0x48,0x02,0x48,0x02,0xB0,0x01, // 51
|
||||
0xC0,0x00,0xA0,0x00,0x90,0x00,0x88,0x00,0xF8,0x03,0x80, // 52
|
||||
0x60,0x01,0x38,0x02,0x28,0x02,0x28,0x02,0xC8,0x01, // 53
|
||||
0xF0,0x01,0x28,0x02,0x28,0x02,0x28,0x02,0xD0,0x01, // 54
|
||||
0x08,0x00,0x08,0x03,0xC8,0x00,0x38,0x00,0x08, // 55
|
||||
0xB0,0x01,0x48,0x02,0x48,0x02,0x48,0x02,0xB0,0x01, // 56
|
||||
0x70,0x01,0x88,0x02,0x88,0x02,0x88,0x02,0xF0,0x01, // 57
|
||||
0x00,0x00,0x20,0x02, // 58
|
||||
0x00,0x00,0x20,0x06, // 59
|
||||
0x00,0x00,0x40,0x00,0xA0,0x00,0xA0,0x00,0x10,0x01, // 60
|
||||
0xA0,0x00,0xA0,0x00,0xA0,0x00,0xA0,0x00,0xA0, // 61
|
||||
0x00,0x00,0x10,0x01,0xA0,0x00,0xA0,0x00,0x40, // 62
|
||||
0x10,0x00,0x08,0x00,0x08,0x00,0xC8,0x02,0x48,0x00,0x30, // 63
|
||||
0x00,0x00,0xC0,0x03,0x30,0x04,0xD0,0x09,0x28,0x0A,0x28,0x0A,0xC8,0x0B,0x68,0x0A,0x10,0x05,0xE0,0x04, // 64
|
||||
0x00,0x02,0xC0,0x01,0xB0,0x00,0x88,0x00,0xB0,0x00,0xC0,0x01,0x00,0x02, // 65
|
||||
0x00,0x00,0xF8,0x03,0x48,0x02,0x48,0x02,0x48,0x02,0xF0,0x01, // 66
|
||||
0x00,0x00,0xF0,0x01,0x08,0x02,0x08,0x02,0x08,0x02,0x10,0x01, // 67
|
||||
0x00,0x00,0xF8,0x03,0x08,0x02,0x08,0x02,0x10,0x01,0xE0, // 68
|
||||
0x00,0x00,0xF8,0x03,0x48,0x02,0x48,0x02,0x48,0x02,0x48,0x02, // 69
|
||||
0x00,0x00,0xF8,0x03,0x48,0x00,0x48,0x00,0x08, // 70
|
||||
0x00,0x00,0xE0,0x00,0x10,0x01,0x08,0x02,0x48,0x02,0x50,0x01,0xC0, // 71
|
||||
0x00,0x00,0xF8,0x03,0x40,0x00,0x40,0x00,0x40,0x00,0xF8,0x03, // 72
|
||||
0x00,0x00,0xF8,0x03, // 73
|
||||
0x00,0x03,0x00,0x02,0x00,0x02,0xF8,0x01, // 74
|
||||
0x00,0x00,0xF8,0x03,0x80,0x00,0x60,0x00,0x90,0x00,0x08,0x01,0x00,0x02, // 75
|
||||
0x00,0x00,0xF8,0x03,0x00,0x02,0x00,0x02,0x00,0x02,0x00,0x02, // 76
|
||||
0x00,0x00,0xF8,0x03,0x30,0x00,0xC0,0x01,0x00,0x02,0xC0,0x01,0x30,0x00,0xF8,0x03, // 77
|
||||
0x00,0x00,0xF8,0x03,0x30,0x00,0x40,0x00,0x80,0x01,0xF8,0x03, // 78
|
||||
0x00,0x00,0xF0,0x01,0x08,0x02,0x08,0x02,0x08,0x02,0x08,0x02,0xF0,0x01, // 79
|
||||
0x00,0x00,0xF8,0x03,0x48,0x00,0x48,0x00,0x48,0x00,0x30, // 80
|
||||
0x00,0x00,0xF0,0x01,0x08,0x02,0x08,0x02,0x08,0x03,0x08,0x03,0xF0,0x02, // 81
|
||||
0x00,0x00,0xF8,0x03,0x48,0x00,0x48,0x00,0xC8,0x00,0x30,0x03, // 82
|
||||
0x00,0x00,0x30,0x01,0x48,0x02,0x48,0x02,0x48,0x02,0x90,0x01, // 83
|
||||
0x00,0x00,0x08,0x00,0x08,0x00,0xF8,0x03,0x08,0x00,0x08, // 84
|
||||
0x00,0x00,0xF8,0x01,0x00,0x02,0x00,0x02,0x00,0x02,0xF8,0x01, // 85
|
||||
0x08,0x00,0x70,0x00,0x80,0x01,0x00,0x02,0x80,0x01,0x70,0x00,0x08, // 86
|
||||
0x18,0x00,0xE0,0x01,0x00,0x02,0xF0,0x01,0x08,0x00,0xF0,0x01,0x00,0x02,0xE0,0x01,0x18, // 87
|
||||
0x00,0x02,0x08,0x01,0x90,0x00,0x60,0x00,0x90,0x00,0x08,0x01,0x00,0x02, // 88
|
||||
0x08,0x00,0x10,0x00,0x20,0x00,0xC0,0x03,0x20,0x00,0x10,0x00,0x08, // 89
|
||||
0x08,0x03,0x88,0x02,0xC8,0x02,0x68,0x02,0x38,0x02,0x18,0x02, // 90
|
||||
0x00,0x00,0xF8,0x0F,0x08,0x08, // 91
|
||||
0x18,0x00,0xE0,0x00,0x00,0x03, // 92
|
||||
0x08,0x08,0xF8,0x0F, // 93
|
||||
0x40,0x00,0x30,0x00,0x08,0x00,0x30,0x00,0x40, // 94
|
||||
0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x08, // 95
|
||||
0x08,0x00,0x10, // 96
|
||||
0x00,0x00,0x00,0x03,0xA0,0x02,0xA0,0x02,0xE0,0x03, // 97
|
||||
0x00,0x00,0xF8,0x03,0x20,0x02,0x20,0x02,0xC0,0x01, // 98
|
||||
0x00,0x00,0xC0,0x01,0x20,0x02,0x20,0x02,0x40,0x01, // 99
|
||||
0x00,0x00,0xC0,0x01,0x20,0x02,0x20,0x02,0xF8,0x03, // 100
|
||||
0x00,0x00,0xC0,0x01,0xA0,0x02,0xA0,0x02,0xC0,0x02, // 101
|
||||
0x20,0x00,0xF0,0x03,0x28, // 102
|
||||
0x00,0x00,0xC0,0x05,0x20,0x0A,0x20,0x0A,0xE0,0x07, // 103
|
||||
0x00,0x00,0xF8,0x03,0x20,0x00,0x20,0x00,0xC0,0x03, // 104
|
||||
0x00,0x00,0xE8,0x03, // 105
|
||||
0x00,0x08,0xE8,0x07, // 106
|
||||
0xF8,0x03,0x80,0x00,0xC0,0x01,0x20,0x02, // 107
|
||||
0x00,0x00,0xF8,0x03, // 108
|
||||
0x00,0x00,0xE0,0x03,0x20,0x00,0x20,0x00,0xE0,0x03,0x20,0x00,0x20,0x00,0xC0,0x03, // 109
|
||||
0x00,0x00,0xE0,0x03,0x20,0x00,0x20,0x00,0xC0,0x03, // 110
|
||||
0x00,0x00,0xC0,0x01,0x20,0x02,0x20,0x02,0xC0,0x01, // 111
|
||||
0x00,0x00,0xE0,0x0F,0x20,0x02,0x20,0x02,0xC0,0x01, // 112
|
||||
0x00,0x00,0xC0,0x01,0x20,0x02,0x20,0x02,0xE0,0x0F, // 113
|
||||
0x00,0x00,0xE0,0x03,0x20, // 114
|
||||
0x40,0x02,0xA0,0x02,0xA0,0x02,0x20,0x01, // 115
|
||||
0x20,0x00,0xF8,0x03,0x20,0x02, // 116
|
||||
0x00,0x00,0xE0,0x01,0x00,0x02,0x00,0x02,0xE0,0x03, // 117
|
||||
0x20,0x00,0xC0,0x01,0x00,0x02,0xC0,0x01,0x20, // 118
|
||||
0xE0,0x01,0x00,0x02,0xC0,0x01,0x20,0x00,0xC0,0x01,0x00,0x02,0xE0,0x01, // 119
|
||||
0x20,0x02,0x40,0x01,0x80,0x00,0x40,0x01,0x20,0x02, // 120
|
||||
0x20,0x00,0xC0,0x09,0x00,0x06,0xC0,0x01,0x20, // 121
|
||||
0x20,0x02,0x20,0x03,0xA0,0x02,0x60,0x02,0x20,0x02, // 122
|
||||
0x80,0x00,0x78,0x0F,0x08,0x08, // 123
|
||||
0x00,0x00,0xF8,0x0F, // 124
|
||||
0x08,0x08,0x78,0x0F,0x80, // 125
|
||||
0xC0,0x00,0x40,0x00,0xC0,0x00,0x80,0x00,0xC0, // 126
|
||||
0x00,0x00,0xA0,0x0F, // 161
|
||||
0x00,0x00,0xC0,0x01,0xA0,0x0F,0x78,0x02,0x40,0x01, // 162
|
||||
0x40,0x02,0x70,0x03,0xC8,0x02,0x48,0x02,0x08,0x02,0x10,0x02, // 163
|
||||
0x00,0x00,0xE0,0x01,0x20,0x01,0x20,0x01,0xE0,0x01, // 164
|
||||
0x48,0x01,0x70,0x01,0xC0,0x03,0x70,0x01,0x48,0x01, // 165
|
||||
0x00,0x00,0x38,0x0F, // 166
|
||||
0xD0,0x04,0x28,0x09,0x48,0x09,0x48,0x0A,0x90,0x05, // 167
|
||||
0x08,0x00,0x00,0x00,0x08, // 168
|
||||
0xE0,0x00,0x10,0x01,0x48,0x02,0xA8,0x02,0xA8,0x02,0x10,0x01,0xE0, // 169
|
||||
0x68,0x00,0x68,0x00,0x68,0x00,0x78, // 170
|
||||
0x00,0x00,0x80,0x01,0x40,0x02,0x80,0x01,0x40,0x02, // 171
|
||||
0x20,0x00,0x20,0x00,0x20,0x00,0x20,0x00,0xE0, // 172
|
||||
0x80,0x00,0x80, // 173
|
||||
0xE0,0x00,0x10,0x01,0xE8,0x02,0x68,0x02,0xC8,0x02,0x10,0x01,0xE0, // 174
|
||||
0x02,0x00,0x02,0x00,0x02,0x00,0x02,0x00,0x02,0x00,0x02, // 175
|
||||
0x00,0x00,0x38,0x00,0x28,0x00,0x38, // 176
|
||||
0x40,0x02,0x40,0x02,0xF0,0x03,0x40,0x02,0x40,0x02, // 177
|
||||
0x48,0x00,0x68,0x00,0x58, // 178
|
||||
0x48,0x00,0x58,0x00,0x68, // 179
|
||||
0x00,0x00,0x10,0x00,0x08, // 180
|
||||
0x00,0x00,0xE0,0x0F,0x00,0x02,0x00,0x02,0xE0,0x03, // 181
|
||||
0x70,0x00,0xF8,0x0F,0x08,0x00,0xF8,0x0F,0x08, // 182
|
||||
0x00,0x00,0x40, // 183
|
||||
0x00,0x00,0x00,0x14,0x00,0x18, // 184
|
||||
0x00,0x00,0x10,0x00,0x78, // 185
|
||||
0x30,0x00,0x48,0x00,0x48,0x00,0x30, // 186
|
||||
0x00,0x00,0x40,0x02,0x80,0x01,0x40,0x02,0x80,0x01, // 187
|
||||
0x00,0x00,0x10,0x02,0x78,0x01,0xC0,0x00,0x20,0x01,0x90,0x01,0xC8,0x03,0x00,0x01, // 188
|
||||
0x00,0x00,0x10,0x02,0x78,0x01,0x80,0x00,0x60,0x00,0x50,0x02,0x48,0x03,0xC0,0x02, // 189
|
||||
0x48,0x00,0x58,0x00,0x68,0x03,0x80,0x00,0x60,0x01,0x90,0x01,0xC8,0x03,0x00,0x01, // 190
|
||||
0x00,0x00,0x00,0x06,0x00,0x09,0xA0,0x09,0x00,0x04, // 191
|
||||
0x00,0x02,0xC0,0x01,0xB0,0x00,0x89,0x00,0xB2,0x00,0xC0,0x01,0x00,0x02, // 192
|
||||
0x00,0x02,0xC0,0x01,0xB0,0x00,0x8A,0x00,0xB1,0x00,0xC0,0x01,0x00,0x02, // 193
|
||||
0x00,0x02,0xC0,0x01,0xB2,0x00,0x89,0x00,0xB2,0x00,0xC0,0x01,0x00,0x02, // 194
|
||||
0x00,0x02,0xC2,0x01,0xB1,0x00,0x8A,0x00,0xB1,0x00,0xC0,0x01,0x00,0x02, // 195
|
||||
0x00,0x02,0xC0,0x01,0xB2,0x00,0x88,0x00,0xB2,0x00,0xC0,0x01,0x00,0x02, // 196
|
||||
0x00,0x02,0xC0,0x01,0xBE,0x00,0x8A,0x00,0xBE,0x00,0xC0,0x01,0x00,0x02, // 197
|
||||
0x00,0x03,0xC0,0x00,0xE0,0x00,0x98,0x00,0x88,0x00,0xF8,0x03,0x48,0x02,0x48,0x02,0x48,0x02, // 198
|
||||
0x00,0x00,0xF0,0x01,0x08,0x02,0x08,0x16,0x08,0x1A,0x10,0x01, // 199
|
||||
0x00,0x00,0xF8,0x03,0x49,0x02,0x4A,0x02,0x48,0x02,0x48,0x02, // 200
|
||||
0x00,0x00,0xF8,0x03,0x48,0x02,0x4A,0x02,0x49,0x02,0x48,0x02, // 201
|
||||
0x00,0x00,0xFA,0x03,0x49,0x02,0x4A,0x02,0x48,0x02,0x48,0x02, // 202
|
||||
0x00,0x00,0xF8,0x03,0x4A,0x02,0x48,0x02,0x4A,0x02,0x48,0x02, // 203
|
||||
0x00,0x00,0xF9,0x03,0x02, // 204
|
||||
0x02,0x00,0xF9,0x03, // 205
|
||||
0x01,0x00,0xFA,0x03, // 206
|
||||
0x02,0x00,0xF8,0x03,0x02, // 207
|
||||
0x40,0x00,0xF8,0x03,0x48,0x02,0x48,0x02,0x10,0x01,0xE0, // 208
|
||||
0x00,0x00,0xFA,0x03,0x31,0x00,0x42,0x00,0x81,0x01,0xF8,0x03, // 209
|
||||
0x00,0x00,0xF0,0x01,0x08,0x02,0x09,0x02,0x0A,0x02,0x08,0x02,0xF0,0x01, // 210
|
||||
0x00,0x00,0xF0,0x01,0x08,0x02,0x0A,0x02,0x09,0x02,0x08,0x02,0xF0,0x01, // 211
|
||||
0x00,0x00,0xF0,0x01,0x08,0x02,0x0A,0x02,0x09,0x02,0x0A,0x02,0xF0,0x01, // 212
|
||||
0x00,0x00,0xF0,0x01,0x0A,0x02,0x09,0x02,0x0A,0x02,0x09,0x02,0xF0,0x01, // 213
|
||||
0x00,0x00,0xF0,0x01,0x0A,0x02,0x08,0x02,0x0A,0x02,0x08,0x02,0xF0,0x01, // 214
|
||||
0x10,0x01,0xA0,0x00,0xE0,0x00,0xA0,0x00,0x10,0x01, // 215
|
||||
0x00,0x00,0xF0,0x02,0x08,0x03,0xC8,0x02,0x28,0x02,0x18,0x03,0xE8, // 216
|
||||
0x00,0x00,0xF8,0x01,0x01,0x02,0x02,0x02,0x00,0x02,0xF8,0x01, // 217
|
||||
0x00,0x00,0xF8,0x01,0x02,0x02,0x01,0x02,0x00,0x02,0xF8,0x01, // 218
|
||||
0x00,0x00,0xF8,0x01,0x02,0x02,0x01,0x02,0x02,0x02,0xF8,0x01, // 219
|
||||
0x00,0x00,0xF8,0x01,0x02,0x02,0x00,0x02,0x02,0x02,0xF8,0x01, // 220
|
||||
0x08,0x00,0x10,0x00,0x20,0x00,0xC2,0x03,0x21,0x00,0x10,0x00,0x08, // 221
|
||||
0x00,0x00,0xF8,0x03,0x10,0x01,0x10,0x01,0x10,0x01,0xE0, // 222
|
||||
0x00,0x00,0xF0,0x03,0x08,0x01,0x48,0x02,0xB0,0x02,0x80,0x01, // 223
|
||||
0x00,0x00,0x00,0x03,0xA4,0x02,0xA8,0x02,0xE0,0x03, // 224
|
||||
0x00,0x00,0x00,0x03,0xA8,0x02,0xA4,0x02,0xE0,0x03, // 225
|
||||
0x00,0x00,0x00,0x03,0xA8,0x02,0xA4,0x02,0xE8,0x03, // 226
|
||||
0x00,0x00,0x08,0x03,0xA4,0x02,0xA8,0x02,0xE4,0x03, // 227
|
||||
0x00,0x00,0x00,0x03,0xA8,0x02,0xA0,0x02,0xE8,0x03, // 228
|
||||
0x00,0x00,0x00,0x03,0xAE,0x02,0xAA,0x02,0xEE,0x03, // 229
|
||||
0x00,0x00,0x40,0x03,0xA0,0x02,0xA0,0x02,0xC0,0x01,0xA0,0x02,0xA0,0x02,0xC0,0x02, // 230
|
||||
0x00,0x00,0xC0,0x01,0x20,0x16,0x20,0x1A,0x40,0x01, // 231
|
||||
0x00,0x00,0xC0,0x01,0xA4,0x02,0xA8,0x02,0xC0,0x02, // 232
|
||||
0x00,0x00,0xC0,0x01,0xA8,0x02,0xA4,0x02,0xC0,0x02, // 233
|
||||
0x00,0x00,0xC0,0x01,0xA8,0x02,0xA4,0x02,0xC8,0x02, // 234
|
||||
0x00,0x00,0xC0,0x01,0xA8,0x02,0xA0,0x02,0xC8,0x02, // 235
|
||||
0x00,0x00,0xE4,0x03,0x08, // 236
|
||||
0x08,0x00,0xE4,0x03, // 237
|
||||
0x08,0x00,0xE4,0x03,0x08, // 238
|
||||
0x08,0x00,0xE0,0x03,0x08, // 239
|
||||
0x00,0x00,0xC0,0x01,0x28,0x02,0x38,0x02,0xE0,0x01, // 240
|
||||
0x00,0x00,0xE8,0x03,0x24,0x00,0x28,0x00,0xC4,0x03, // 241
|
||||
0x00,0x00,0xC0,0x01,0x24,0x02,0x28,0x02,0xC0,0x01, // 242
|
||||
0x00,0x00,0xC0,0x01,0x28,0x02,0x24,0x02,0xC0,0x01, // 243
|
||||
0x00,0x00,0xC0,0x01,0x28,0x02,0x24,0x02,0xC8,0x01, // 244
|
||||
0x00,0x00,0xC8,0x01,0x24,0x02,0x28,0x02,0xC4,0x01, // 245
|
||||
0x00,0x00,0xC0,0x01,0x28,0x02,0x20,0x02,0xC8,0x01, // 246
|
||||
0x40,0x00,0x40,0x00,0x50,0x01,0x40,0x00,0x40, // 247
|
||||
0x00,0x00,0xC0,0x02,0xA0,0x03,0x60,0x02,0xA0,0x01, // 248
|
||||
0x00,0x00,0xE0,0x01,0x04,0x02,0x08,0x02,0xE0,0x03, // 249
|
||||
0x00,0x00,0xE0,0x01,0x08,0x02,0x04,0x02,0xE0,0x03, // 250
|
||||
0x00,0x00,0xE8,0x01,0x04,0x02,0x08,0x02,0xE0,0x03, // 251
|
||||
0x00,0x00,0xE0,0x01,0x08,0x02,0x00,0x02,0xE8,0x03, // 252
|
||||
0x20,0x00,0xC0,0x09,0x08,0x06,0xC4,0x01,0x20, // 253
|
||||
0x00,0x00,0xF8,0x0F,0x20,0x02,0x20,0x02,0xC0,0x01, // 254
|
||||
0x20,0x00,0xC8,0x09,0x00,0x06,0xC8,0x01,0x20 // 255
|
||||
};
|
91
main/gps.cpp
91
main/gps.cpp
|
@ -11,49 +11,18 @@
|
|||
HardwareSerial gpsSerial(GPS_SERIAL_NUM);
|
||||
|
||||
SFE_UBLOX_GPS myGNSS;
|
||||
TinyGPSPlus _gps;
|
||||
|
||||
TinyGPSPlus tGPS;
|
||||
|
||||
void gps_time(char* buffer, uint8_t size) {
|
||||
snprintf(buffer, size, "%02d:%02d:%02d", _gps.time.hour(), _gps.time.minute(), _gps.time.second());
|
||||
}
|
||||
|
||||
float gps_latitude() {
|
||||
return _gps.location.lat();
|
||||
}
|
||||
|
||||
float gps_distanceBetween(float last_lat, float last_lon, float lat, float lon) {
|
||||
return _gps.distanceBetween(last_lat, last_lon, lat, lon);
|
||||
}
|
||||
|
||||
float gps_longitude() {
|
||||
return _gps.location.lng();
|
||||
}
|
||||
|
||||
float gps_altitude() {
|
||||
return _gps.altitude.meters();
|
||||
}
|
||||
|
||||
float gps_hdop() {
|
||||
return _gps.hdop.hdop();
|
||||
}
|
||||
|
||||
uint8_t gps_sats() {
|
||||
return _gps.satellites.value();
|
||||
}
|
||||
|
||||
float gps_speed() {
|
||||
return _gps.speed.kmph();
|
||||
}
|
||||
|
||||
uint32_t gps_sentencesWithFix() {
|
||||
return _gps.sentencesWithFix();
|
||||
snprintf(buffer, size, "%02d:%02d:%02d", tGPS.time.hour(), tGPS.time.minute(), tGPS.time.second());
|
||||
}
|
||||
|
||||
void gps_end(void) {
|
||||
gpsSerial.end();
|
||||
}
|
||||
|
||||
void gps_setup(void) {
|
||||
void gps_setup(boolean first_init) {
|
||||
static boolean serial_ready = false;
|
||||
if (serial_ready) {
|
||||
gpsSerial.updateBaudRate(GPS_BAUDRATE);
|
||||
|
@ -65,18 +34,14 @@ void gps_setup(void) {
|
|||
// Drain any waiting garbage
|
||||
while (gpsSerial.read() != -1)
|
||||
;
|
||||
// Flush out line noise from our side
|
||||
//char zeros[] = {0, 0, 0, 0, 0, 0};
|
||||
//gpsSerial.write(zeros, sizeof(zeros));
|
||||
|
||||
if (0)
|
||||
myGNSS.enableDebugging();
|
||||
// myGNSS.enableDebugging();
|
||||
|
||||
bool changed_speed = false;
|
||||
bool changed_speed = false; // Assume we're already at the right speed
|
||||
|
||||
// Check all the possible GPS bitrates to get in sync
|
||||
do {
|
||||
gpsSerial.updateBaudRate(GPS_BAUDRATE);
|
||||
gpsSerial.updateBaudRate(GPS_BAUDRATE); // Try the desired speed first
|
||||
if (myGNSS.begin(gpsSerial)) {
|
||||
Serial.println("GPS connected.");
|
||||
break;
|
||||
|
@ -120,12 +85,11 @@ void gps_setup(void) {
|
|||
Serial.println("Could not connect to GPS. Retrying all speeds...");
|
||||
} while (1);
|
||||
|
||||
myGNSS.setUART1Output(COM_TYPE_NMEA); // We do want NMEA
|
||||
// Configure NMEA messages only once, save to flash
|
||||
if (first_init) {
|
||||
myGNSS.setUART1Output(COM_TYPE_NMEA); // We do want NMEA
|
||||
|
||||
if (0)
|
||||
myGNSS.factoryReset();
|
||||
|
||||
myGNSS.setNavigationFrequency(2); // Produce X solutions per second
|
||||
myGNSS.setNavigationFrequency(2); // Produce X solutions per second
|
||||
|
||||
#if 0
|
||||
// On the Neo6M, these are all off by default anyway:
|
||||
|
@ -133,7 +97,6 @@ void gps_setup(void) {
|
|||
myGNSS.disableNMEAMessage(UBX_NMEA_GAQ, COM_PORT_UART1);
|
||||
myGNSS.disableNMEAMessage(UBX_NMEA_GBQ, COM_PORT_UART1);
|
||||
myGNSS.disableNMEAMessage(UBX_NMEA_GBS, COM_PORT_UART1);
|
||||
myGNSS.disableNMEAMessage(UBX_NMEA_GLL, COM_PORT_UART1);
|
||||
myGNSS.disableNMEAMessage(UBX_NMEA_GLQ, COM_PORT_UART1);
|
||||
myGNSS.disableNMEAMessage(UBX_NMEA_GNQ, COM_PORT_UART1);
|
||||
myGNSS.disableNMEAMessage(UBX_NMEA_GNS, COM_PORT_UART1);
|
||||
|
@ -141,21 +104,39 @@ void gps_setup(void) {
|
|||
myGNSS.disableNMEAMessage(UBX_NMEA_GRS, COM_PORT_UART1);
|
||||
myGNSS.disableNMEAMessage(UBX_NMEA_GSA, COM_PORT_UART1);
|
||||
myGNSS.disableNMEAMessage(UBX_NMEA_GST, COM_PORT_UART1);
|
||||
myGNSS.disableNMEAMessage(UBX_NMEA_GSV, COM_PORT_UART1);
|
||||
myGNSS.disableNMEAMessage(UBX_NMEA_TXT, COM_PORT_UART1);
|
||||
myGNSS.disableNMEAMessage(UBX_NMEA_VLW, COM_PORT_UART1);
|
||||
myGNSS.disableNMEAMessage(UBX_NMEA_VTG, COM_PORT_UART1);
|
||||
myGNSS.disableNMEAMessage(UBX_NMEA_ZDA, COM_PORT_UART1);
|
||||
#endif
|
||||
|
||||
myGNSS.disableNMEAMessage(UBX_NMEA_GSA, COM_PORT_UART1); // Don't need SV list (on by default)
|
||||
myGNSS.enableNMEAMessage(UBX_NMEA_RMC, COM_PORT_UART1); // For Speed
|
||||
myGNSS.enableNMEAMessage(UBX_NMEA_GGA, COM_PORT_UART1); // For Time & Location & SV count
|
||||
// Disable these messages that are on after factory reset
|
||||
myGNSS.disableNMEAMessage(UBX_NMEA_GSV, COM_PORT_UART1);
|
||||
myGNSS.disableNMEAMessage(UBX_NMEA_GLL, COM_PORT_UART1);
|
||||
myGNSS.disableNMEAMessage(UBX_NMEA_VTG, COM_PORT_UART1);
|
||||
myGNSS.disableNMEAMessage(UBX_NMEA_GSA, COM_PORT_UART1);
|
||||
|
||||
myGNSS.enableNMEAMessage(UBX_NMEA_RMC, COM_PORT_UART1); // For Speed
|
||||
myGNSS.enableNMEAMessage(UBX_NMEA_GGA, COM_PORT_UART1); // For Time & Location & SV count
|
||||
}
|
||||
|
||||
if (changed_speed)
|
||||
if (first_init || changed_speed)
|
||||
myGNSS.saveConfiguration(); // Save the current settings to flash and BBR
|
||||
}
|
||||
|
||||
void gps_full_reset(void) {
|
||||
Serial.println("Resetting GPS...");
|
||||
myGNSS.factoryReset();
|
||||
delay(5000);
|
||||
Serial.println("Reconfiguring GPS...");
|
||||
gps_setup(true);
|
||||
delay(1000);
|
||||
// Drain any waiting garbage
|
||||
while (gpsSerial.read() != -1)
|
||||
;
|
||||
// gps_passthrough();
|
||||
// ESP.restart();
|
||||
}
|
||||
|
||||
void gps_passthrough(void) {
|
||||
Serial.println("GPS Passthrough forever...");
|
||||
while (1) {
|
||||
|
@ -171,6 +152,6 @@ void gps_loop(boolean print_it) {
|
|||
char c = gpsSerial.read();
|
||||
if (print_it)
|
||||
Serial.print(c);
|
||||
_gps.encode(c);
|
||||
tGPS.encode(c);
|
||||
}
|
||||
}
|
15
main/gps.h
15
main/gps.h
|
@ -2,18 +2,13 @@
|
|||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <TinyGPS++.h>
|
||||
|
||||
extern TinyGPSPlus tGPS;
|
||||
|
||||
void gps_loop(boolean print_it);
|
||||
void gps_setup(void);
|
||||
void gps_setup(boolean first_init);
|
||||
void gps_time(char *buffer, uint8_t size);
|
||||
float gps_latitude(void);
|
||||
float gps_distanceBetween(float lat1, float long1, float lat2, float long2);
|
||||
float gps_longitude(void);
|
||||
float gps_altitude(void);
|
||||
float gps_hdop(void);
|
||||
uint8_t gps_sats(void);
|
||||
float gps_hdop(void);
|
||||
float gps_speed(void);
|
||||
void gps_passthrough(void);
|
||||
uint32_t gps_sentencesWithFix(void);
|
||||
void gps_end(void);
|
||||
void gps_full_reset(void);
|
322
main/main.cpp
322
main/main.cpp
|
@ -48,7 +48,10 @@
|
|||
#define FPORT_MAPPER 2 // FPort for Uplink messages -- must match Helium Console Decoder script!
|
||||
#define FPORT_STATUS 5
|
||||
#define FPORT_GPSLOST 6
|
||||
|
||||
#define STATUS_BOOT 1
|
||||
#define STATUS_USB_ON 2
|
||||
#define STATUS_USB_OFF 3
|
||||
|
||||
// Defined in ttn.ino
|
||||
void ttn_register(void (*callback)(uint8_t message));
|
||||
|
@ -57,14 +60,14 @@ bool justSendNow = true; // Send one at boot, regardless of deadz
|
|||
unsigned long int last_send_ms = 0; // Time of last uplink
|
||||
unsigned long int last_moved_ms = 0; // Time of last movement
|
||||
unsigned long int last_gpslost_ms = 0; // Time of last gps-lost packet
|
||||
float last_send_lat = 0; // Last known location
|
||||
float last_send_lon = 0; //
|
||||
float dist_moved = 0; // Distance in m from last uplink
|
||||
double last_send_lat = 0; // Last known location
|
||||
double last_send_lon = 0; //
|
||||
double dist_moved = 0; // Distance in m from last uplink
|
||||
|
||||
// Deadzone (no uplink) location and radius
|
||||
float deadzone_lat = DEADZONE_LAT;
|
||||
float deadzone_lon = DEADZONE_LON;
|
||||
float deadzone_radius_m = DEADZONE_RADIUS_M;
|
||||
double deadzone_lat = DEADZONE_LAT;
|
||||
double deadzone_lon = DEADZONE_LON;
|
||||
double deadzone_radius_m = DEADZONE_RADIUS_M;
|
||||
boolean in_deadzone = false;
|
||||
|
||||
/* Defaults that can be overwritten by downlink messages */
|
||||
|
@ -75,10 +78,20 @@ unsigned int rest_tx_interval_s; // prefs REST_TX_INTERVAL
|
|||
|
||||
unsigned int tx_interval_s; // Currently-active time interval
|
||||
|
||||
enum activity_state { ACTIVITY_MOVING, ACTIVITY_REST, ACTIVITY_SLEEP, ACTIVITY_GPS_LOST, ACTIVITY_WOKE };
|
||||
enum activity_state active_state = ACTIVITY_MOVING;
|
||||
enum activity_state {
|
||||
ACTIVITY_MOVING,
|
||||
ACTIVITY_REST,
|
||||
ACTIVITY_SLEEP,
|
||||
ACTIVITY_GPS_LOST,
|
||||
ACTIVITY_WOKE,
|
||||
ACTIVITY_INVALID
|
||||
};
|
||||
enum activity_state active_state = ACTIVITY_INVALID;
|
||||
boolean never_rest = NEVER_REST;
|
||||
|
||||
// Return status from mapper uplink, since we care about the flavor of the failure
|
||||
enum mapper_uplink_result { MAPPER_UPLINK_SUCCESS, MAPPER_UPLINK_BADFIX, MAPPER_UPLINK_NOLORA, MAPPER_UPLINK_NOTYET };
|
||||
|
||||
/* Maybe these moves to prefs eventually? */
|
||||
unsigned int sleep_wait_s = SLEEP_WAIT;
|
||||
unsigned int sleep_tx_interval_s = SLEEP_TX_INTERVAL;
|
||||
|
@ -93,8 +106,9 @@ float min_dist_moved = MIN_DIST;
|
|||
AXP20X_Class axp;
|
||||
bool pmu_irq = false; // true when PMU IRQ pending
|
||||
|
||||
bool ssd1306_found = false;
|
||||
bool oled_found = false;
|
||||
bool axp192_found = false;
|
||||
uint8_t oled_addr = 0; // i2c address of OLED controller
|
||||
|
||||
bool packetQueued;
|
||||
bool isJoined = false;
|
||||
|
@ -105,6 +119,8 @@ bool is_screen_on = true;
|
|||
int screen_idle_off_s = SCREEN_IDLE_OFF_S;
|
||||
uint32_t screen_last_active_ms = 0;
|
||||
boolean in_menu = false;
|
||||
boolean have_usb_power = true;
|
||||
uint8_t usb_power_count = 0;
|
||||
|
||||
// Buffer for Payload frame
|
||||
static uint8_t txBuffer[11];
|
||||
|
@ -122,7 +138,7 @@ unsigned long int ack_req = 0;
|
|||
unsigned long int ack_rx = 0;
|
||||
|
||||
// Store Lat & Long in six bytes of payload
|
||||
void pack_lat_lon(float lat, float lon) {
|
||||
void pack_lat_lon(double lat, double lon) {
|
||||
uint32_t LatitudeBinary;
|
||||
uint32_t LongitudeBinary;
|
||||
LatitudeBinary = ((lat + 90) / 180.0) * 16777215;
|
||||
|
@ -143,25 +159,26 @@ uint8_t battery_byte(void) {
|
|||
|
||||
// Prepare a packet for the Mapper
|
||||
void build_mapper_packet() {
|
||||
float lat;
|
||||
float lon;
|
||||
double lat;
|
||||
double lon;
|
||||
uint16_t altitudeGps;
|
||||
// uint8_t hdopGps;
|
||||
uint8_t sats;
|
||||
uint16_t speed;
|
||||
|
||||
lat = gps_latitude();
|
||||
lon = gps_longitude();
|
||||
lat = tGPS.location.lat();
|
||||
lon = tGPS.location.lng();
|
||||
pack_lat_lon(lat, lon);
|
||||
altitudeGps = (uint16_t)gps_altitude();
|
||||
speed = (uint16_t)gps_speed(); // convert from float
|
||||
sats = gps_sats();
|
||||
altitudeGps = (uint16_t)tGPS.altitude.meters();
|
||||
speed = (uint16_t)tGPS.speed.kmph(); // convert from double
|
||||
if (speed > 255)
|
||||
speed = 255; // don't wrap around.
|
||||
sats = tGPS.satellites.value();
|
||||
|
||||
sprintf(buffer, "Lat: %f, ", lat);
|
||||
Serial.print(buffer);
|
||||
sprintf(buffer, "Long: %f, ", lon);
|
||||
Serial.print(buffer);
|
||||
sprintf(buffer, "Alt: %f, ", gps_altitude());
|
||||
sprintf(buffer, "Alt: %f, ", tGPS.altitude.meters());
|
||||
Serial.print(buffer);
|
||||
sprintf(buffer, "Sats: %d", sats);
|
||||
Serial.println(buffer);
|
||||
|
@ -169,12 +186,16 @@ void build_mapper_packet() {
|
|||
txBuffer[6] = (altitudeGps >> 8) & 0xFF;
|
||||
txBuffer[7] = altitudeGps & 0xFF;
|
||||
|
||||
txBuffer[8] = ((unsigned char *)(&speed))[0];
|
||||
txBuffer[8] = speed & 0xFF;
|
||||
txBuffer[9] = battery_byte();
|
||||
|
||||
txBuffer[10] = sats & 0xFF;
|
||||
}
|
||||
|
||||
// Helium requires a FCount reset sometime before hitting 0xFFFF
|
||||
// 50,000 makes it obvious it was intentional
|
||||
#define MAX_FCOUNT 50000
|
||||
|
||||
boolean send_uplink(uint8_t *txBuffer, uint8_t length, uint8_t fport, boolean confirmed) {
|
||||
if (confirmed) {
|
||||
Serial.println("ACK requested");
|
||||
|
@ -189,10 +210,28 @@ boolean send_uplink(uint8_t *txBuffer, uint8_t length, uint8_t fport, boolean co
|
|||
Serial.println("Surprise send failure!");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Helium requires a re-join / reset of count to avoid 16bit count rollover
|
||||
// Hopefully a device reboot every 50k uplinks is no problem.
|
||||
if (ttn_get_count() > MAX_FCOUNT) {
|
||||
Serial.println("FCount Rollover!");
|
||||
|
||||
// I don't understand why this doesn't show at all
|
||||
screen_print("\n\nRollover Reset!\n");
|
||||
screen_update();
|
||||
delay(1000); // Give some time to read the screen
|
||||
|
||||
ttn_erase_prefs();
|
||||
ESP.restart();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool status_uplink(uint8_t status, uint8_t value) {
|
||||
if (!SEND_STATUS_UPLINKS)
|
||||
return false;
|
||||
|
||||
pack_lat_lon(last_send_lat, last_send_lon);
|
||||
txBuffer[6] = battery_byte();
|
||||
txBuffer[7] = status;
|
||||
|
@ -205,10 +244,13 @@ bool status_uplink(uint8_t status, uint8_t value) {
|
|||
bool gpslost_uplink(void) {
|
||||
uint16_t minutes_lost;
|
||||
|
||||
if (!SEND_GPSLOST_UPLINKS)
|
||||
return false;
|
||||
|
||||
minutes_lost = (last_fix_time - millis()) / 1000 / 60;
|
||||
pack_lat_lon(last_send_lat, last_send_lon);
|
||||
txBuffer[6] = battery_byte();
|
||||
txBuffer[7] = gps_sats();
|
||||
txBuffer[7] = tGPS.satellites.value();
|
||||
txBuffer[8] = (minutes_lost >> 8) & 0xFF;
|
||||
txBuffer[9] = minutes_lost & 0xFF;
|
||||
Serial.printf("Tx: GPSLOST %d\n", minutes_lost);
|
||||
|
@ -217,35 +259,44 @@ bool gpslost_uplink(void) {
|
|||
}
|
||||
|
||||
// Send a packet, if one is warranted
|
||||
bool mapper_uplink() {
|
||||
float now_lat = gps_latitude();
|
||||
float now_long = gps_longitude();
|
||||
enum mapper_uplink_result mapper_uplink() {
|
||||
double now_lat = tGPS.location.lat();
|
||||
double now_lon = tGPS.location.lng();
|
||||
unsigned long int now = millis();
|
||||
|
||||
// Here we try to filter out bogus GPS readings.
|
||||
// It's not correct, and there should be a better indication from GPS that the
|
||||
// fix is invalid
|
||||
if (gps_hdop() <= 0 || gps_hdop() > 50 || now_lat == 0.0 // Not fair to the whole equator
|
||||
|| now_lat > 90.0 || now_lat < -90.0 || now_long == 0.0 // Not fair to King George
|
||||
|| now_long < -180.0 || now_long > 180.0 || gps_altitude() == 0.0 // Not fair to the ocean
|
||||
|| gps_sats() < 4)
|
||||
return false; // Rejected as bogus GPS reading.
|
||||
if (!(tGPS.location.isValid() && tGPS.time.isValid() && tGPS.satellites.isValid() && tGPS.hdop.isValid() &&
|
||||
tGPS.altitude.isValid() && tGPS.speed.isValid()))
|
||||
return MAPPER_UPLINK_BADFIX;
|
||||
|
||||
// Filter out any reports while we have low satellite count. The receiver can old a fix on 3, but it's poor.
|
||||
if (tGPS.satellites.value() < 4)
|
||||
return MAPPER_UPLINK_BADFIX;
|
||||
|
||||
// HDOP is only a hint as to accuracy, but we can assume very bad HDOP is not worth mapping.
|
||||
// https://en.wikipedia.org/wiki/Dilution_of_precision_(navigation) suggests 5 is a good cutoff.
|
||||
if (tGPS.hdop.hdop() > 5.0)
|
||||
return MAPPER_UPLINK_BADFIX;
|
||||
|
||||
// With the exception of a few places, a perfectly zero lat or long probably means we got a bad reading
|
||||
if (now_lat == 0.0 || now_lon == 0.0)
|
||||
return MAPPER_UPLINK_BADFIX;
|
||||
|
||||
// Don't attempt to send or update until we join Helium
|
||||
if (!isJoined)
|
||||
return false;
|
||||
return MAPPER_UPLINK_NOLORA;
|
||||
|
||||
// LoRa is not ready for a new packet, maybe still sending the last one.
|
||||
if (!LMIC_queryTxReady())
|
||||
return false;
|
||||
return MAPPER_UPLINK_NOLORA;
|
||||
|
||||
// Check if there is not a current TX/RX job running
|
||||
if (LMIC.opmode & OP_TXRXPEND)
|
||||
return false;
|
||||
return MAPPER_UPLINK_NOLORA;
|
||||
|
||||
// distance from last transmitted location
|
||||
float dist_moved = gps_distanceBetween(last_send_lat, last_send_lon, now_lat, now_long);
|
||||
float deadzone_dist = gps_distanceBetween(deadzone_lat, deadzone_lon, now_lat, now_long);
|
||||
double dist_moved = tGPS.distanceBetween(last_send_lat, last_send_lon, now_lat, now_lon);
|
||||
double deadzone_dist = tGPS.distanceBetween(deadzone_lat, deadzone_lon, now_lat, now_lon);
|
||||
in_deadzone = (deadzone_dist <= deadzone_radius_m);
|
||||
|
||||
/*
|
||||
|
@ -255,7 +306,7 @@ bool mapper_uplink() {
|
|||
|
||||
// Deadzone means we don't send unless asked
|
||||
if (in_deadzone && !justSendNow)
|
||||
return false;
|
||||
return MAPPER_UPLINK_NOTYET;
|
||||
|
||||
char because = '?';
|
||||
if (justSendNow) {
|
||||
|
@ -270,12 +321,9 @@ bool mapper_uplink() {
|
|||
Serial.println("** TIME");
|
||||
because = 'T';
|
||||
} else {
|
||||
return false; // Nothing to do, go home early
|
||||
return MAPPER_UPLINK_NOTYET; // Nothing to do, go home early
|
||||
}
|
||||
|
||||
// SEND a Packet!
|
||||
// digitalWrite(RED_LED, LOW);
|
||||
|
||||
// The first distance-moved is crazy, since has no origin.. don't put it on
|
||||
// screen.
|
||||
if (dist_moved > 1000000)
|
||||
|
@ -293,14 +341,14 @@ bool mapper_uplink() {
|
|||
|
||||
// Send it!
|
||||
if (!send_uplink(txBuffer, 11, FPORT_MAPPER, confirmed))
|
||||
return false;
|
||||
return MAPPER_UPLINK_NOLORA;
|
||||
|
||||
last_send_ms = now;
|
||||
last_send_lat = now_lat;
|
||||
last_send_lon = now_long;
|
||||
last_send_lon = now_lon;
|
||||
|
||||
screen_last_active_ms = now;
|
||||
return true; // We did it!
|
||||
return MAPPER_UPLINK_SUCCESS; // We did it!
|
||||
}
|
||||
|
||||
void mapper_restore_prefs(void) {
|
||||
|
@ -483,7 +531,7 @@ void lora_msg_callback(uint8_t message) {
|
|||
void scanI2Cdevice(void) {
|
||||
byte err, addr;
|
||||
int nDevices = 0;
|
||||
for (addr = 1; addr < 127; addr++) {
|
||||
for (addr = 1; addr < 0x7F; addr++) {
|
||||
Wire.beginTransmission(addr);
|
||||
err = Wire.endTransmission();
|
||||
if (err == 0) {
|
||||
|
@ -496,16 +544,17 @@ void scanI2Cdevice(void) {
|
|||
#endif
|
||||
nDevices++;
|
||||
|
||||
if (addr == SSD1306_ADDRESS) {
|
||||
ssd1306_found = true;
|
||||
Serial.println("SSD1306 OLED display");
|
||||
if (addr == 0x3C || addr == 0x78 || addr == 0x7E) {
|
||||
oled_addr = addr;
|
||||
oled_found = true;
|
||||
Serial.printf("OLED at %02X\n", oled_addr);
|
||||
}
|
||||
if (addr == AXP192_SLAVE_ADDRESS) {
|
||||
axp192_found = true;
|
||||
Serial.println("AXP192 PMU");
|
||||
}
|
||||
} else if (err == 4) {
|
||||
Serial.print("Unknow i2c device at 0x");
|
||||
Serial.print("Unknown i2c device at 0x");
|
||||
if (addr < 16)
|
||||
Serial.print("0");
|
||||
Serial.println(addr, HEX);
|
||||
|
@ -582,8 +631,8 @@ void axp192Init() {
|
|||
axp.setPowerOutPut(AXP192_LDO2, AXP202_ON); // LORA radio 200mA "LORA_VCC"
|
||||
axp.setPowerOutPut(AXP192_LDO3, AXP202_ON); // GPS power 200mA "GPS_VCC"
|
||||
axp.setLDO3Voltage(3300); // Voltage for GPS Power. (Neo-6 can take 2.7v to 3.6v)
|
||||
axp.setPowerOutPut(AXP192_DCDC1, AXP202_ON); // OLED power, 1200mA max
|
||||
axp.setDCDC1Voltage(3300); // Voltage or the OLED SSD1306
|
||||
axp.setPowerOutPut(AXP192_DCDC1, AXP202_ON); // OLED power, 1200mA max "VCC_2.5V"
|
||||
axp.setDCDC1Voltage(2500); // Voltage or the OLED SSD1306
|
||||
axp.setPowerOutPut(AXP192_DCDC2, AXP202_OFF); // Unconnected
|
||||
axp.setPowerOutPut(AXP192_EXTEN, AXP202_OFF); // "EXTEN" pin, unused
|
||||
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_550MA); // Default 0x1000 = 780mA, more than we can get from USB
|
||||
|
@ -602,16 +651,19 @@ void axp192Init() {
|
|||
Serial.printf("Exten: %s\n", axp.isExtenEnable() ? "ENABLE" : "DISABLE");
|
||||
#endif
|
||||
// Fire an interrupt on falling edge. Note that some IRQs repeat/persist.
|
||||
pinMode(PMU_IRQ, INPUT_PULLUP);
|
||||
pinMode(PMU_IRQ, INPUT);
|
||||
gpio_pullup_en((gpio_num_t)PMU_IRQ);
|
||||
attachInterrupt(
|
||||
PMU_IRQ, [] { pmu_irq = true; }, FALLING);
|
||||
|
||||
// Configure REG 36H: PEK press key parameter set. Index values for
|
||||
// argument!
|
||||
axp.setStartupTime(2); // "Power on time": 512mS
|
||||
axp.setlongPressTime(2); // "Long time key press time": 2S
|
||||
axp.setShutdownTime(2); // "Power off time" = 8S
|
||||
axp.setTimeOutShutdown(1); // "When key press time is longer than power off time, auto power off"
|
||||
axp.setStartupTime(2); // "Power on time": 512mS
|
||||
axp.setlongPressTime(2); // "Long time key press time": 2S
|
||||
axp.setShutdownTime(2); // "Power off time" = 8S
|
||||
axp.setTimeOutShutdown(1); // "When key press time is longer than power off time, auto power off"
|
||||
axp.setVWarningLevel1(2950); // These warning IRQs do not clear until charged, and inhibit other IRQs!
|
||||
axp.setVWarningLevel2(2900); // We effectively disable them by setting them lower than we'd run
|
||||
|
||||
// Serial.printf("AC IN: %fv\n", axp.getAcinVoltage());
|
||||
// Serial.printf("Vbus: %fv\n", axp.getVbusVoltage());
|
||||
|
@ -623,6 +675,7 @@ void axp192Init() {
|
|||
Serial.printf("Battery: %0.3fv\n", axp.getBattVoltage() / 1000.0);
|
||||
Serial.printf("SysIPSOut: %0.3fv\n", axp.getSysIPSOUTVoltage() / 1000.0);
|
||||
Serial.printf("isVBUSPlug? %s\n", axp.isVBUSPlug() ? "Yes" : "No");
|
||||
have_usb_power = axp.isVBUSPlug();
|
||||
Serial.printf("isChargingEnable? %s\n", axp.isChargeingEnable() ? "Yes" : "No");
|
||||
// Doesn't work on AXP192 because it has a different charge current curve:
|
||||
// Serial.printf("ChargeCurrent: %.2fmA\n", axp.getSettingChargeCurrent());
|
||||
|
@ -649,7 +702,14 @@ void axp192Init() {
|
|||
|
||||
// @Kenny_PDY discovered that low-battery voltage inhibits detecting the menu button.
|
||||
// Disable these two IRQs until we figure out why it blocks the PEK button IRQs.
|
||||
axp.enableIRQ(APX202_APS_LOW_VOL_LEVEL1_IRQ | AXP202_APS_LOW_VOL_LEVEL2_IRQ, 0);
|
||||
// Low battery also seems to inhibit the USB present/lost signal we use to wake up.
|
||||
axp.enableIRQ(APX202_APS_LOW_VOL_LEVEL1_IRQ, 0);
|
||||
axp.enableIRQ(AXP202_APS_LOW_VOL_LEVEL2_IRQ, 0);
|
||||
|
||||
// The Charging Current available is less than requested for battery charging.
|
||||
// Another Persistent IRQ. Clear it after showing it once?
|
||||
// TODO: Show it every X minutes? Adjust charge current request?
|
||||
axp.enableIRQ(AXP202_CHARGE_LOW_CUR_IRQ, 0);
|
||||
|
||||
axp.clearIRQ();
|
||||
} else {
|
||||
|
@ -677,8 +737,8 @@ void setup() {
|
|||
wakeup();
|
||||
|
||||
// Make sure WiFi and BT are off
|
||||
WiFi.disconnect(true);
|
||||
WiFi.mode(WIFI_OFF);
|
||||
// WiFi.disconnect(true);
|
||||
WiFi.mode(WIFI_MODE_NULL);
|
||||
btStop();
|
||||
|
||||
Wire.begin(I2C_SDA, I2C_SCL);
|
||||
|
@ -692,7 +752,8 @@ void setup() {
|
|||
axp.setPowerOutPut(AXP192_LDO3, AXP202_OFF); // GPS power off
|
||||
|
||||
// Buttons & LED
|
||||
pinMode(MIDDLE_BUTTON_PIN, INPUT_PULLUP);
|
||||
pinMode(MIDDLE_BUTTON_PIN, INPUT);
|
||||
gpio_pullup_en((gpio_num_t)MIDDLE_BUTTON_PIN);
|
||||
pinMode(RED_LED, OUTPUT);
|
||||
digitalWrite(RED_LED, HIGH); // Off
|
||||
|
||||
|
@ -704,14 +765,14 @@ void setup() {
|
|||
// Don't init display if we don't have one or we are waking headless due to a
|
||||
// timer event
|
||||
if (0 && wakeCause == ESP_SLEEP_WAKEUP_TIMER)
|
||||
ssd1306_found = false; // forget we even have the hardware
|
||||
oled_found = false; // forget we even have the hardware
|
||||
|
||||
// This creates the display object, so if we don't call it.. all screen ops are do-nothing.
|
||||
if (ssd1306_found)
|
||||
screen_setup();
|
||||
if (oled_found)
|
||||
screen_setup(oled_addr);
|
||||
is_screen_on = true;
|
||||
|
||||
// GPS power on, so it has time to setttle.
|
||||
// GPS power on, so it has time to settle.
|
||||
axp.setPowerOutPut(AXP192_LDO3, AXP202_ON);
|
||||
|
||||
// Show logo on first boot (as opposed to wake)
|
||||
|
@ -736,7 +797,11 @@ void setup() {
|
|||
|
||||
// Might have to add a longer delay here for GPS boot-up. Takes longer to sync if we talk to it too early.
|
||||
delay(100);
|
||||
gps_setup(); // Init GPS baudrate and messages
|
||||
gps_setup(true); // Init GPS baudrate and messages
|
||||
|
||||
// This is bad.. we can't find the AXP192 PMIC, so no menu key detect:
|
||||
if (!axp192_found)
|
||||
screen_print("** Missing AXP192! **\n");
|
||||
|
||||
Serial.printf("Deadzone: %f.0m @ %f, %f\n", deadzone_radius_m, deadzone_lat, deadzone_lon);
|
||||
}
|
||||
|
@ -744,43 +809,55 @@ void setup() {
|
|||
// Should be around 0.5mA ESP32 consumption, plus OLED controller and PMIC overhead.
|
||||
void low_power_sleep(uint32_t seconds) {
|
||||
boolean was_screen_on = is_screen_on;
|
||||
if (is_screen_on) {
|
||||
screen_off();
|
||||
is_screen_on = false;
|
||||
}
|
||||
|
||||
digitalWrite(RED_LED, HIGH); // Off
|
||||
Serial.printf("Sleep %d..\n", seconds);
|
||||
Serial.flush();
|
||||
|
||||
screen_off();
|
||||
|
||||
digitalWrite(RED_LED, HIGH); // LED Off
|
||||
|
||||
if (axp192_found) {
|
||||
axp.setPowerOutPut(AXP192_LDO3, AXP202_OFF); // GPS power
|
||||
axp.setChgLEDMode(AXP20X_LED_OFF);
|
||||
axp.setChgLEDMode(AXP20X_LED_OFF); // Blue LED off
|
||||
|
||||
// Turning off DCDC1 consumes MORE power, for reasons unknown
|
||||
// axp.setPowerOutPut(AXP192_DCDC1, AXP202_OFF); // OLED power off
|
||||
// pinMode(I2C_SCL, OUTPUT);
|
||||
// digitalWrite(I2C_SCL, HIGH); // Must enable pull-up on SCL to keep AXP accessible
|
||||
}
|
||||
|
||||
// Wake on either button press
|
||||
gpio_wakeup_enable((gpio_num_t)MIDDLE_BUTTON_PIN, GPIO_INTR_LOW_LEVEL);
|
||||
gpio_wakeup_enable((gpio_num_t)PMU_IRQ, GPIO_INTR_LOW_LEVEL);
|
||||
esp_sleep_enable_gpio_wakeup();
|
||||
|
||||
esp_sleep_enable_timer_wakeup(seconds * 1000ULL * 1000ULL); // call expects usecs
|
||||
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
|
||||
// Some GPIOs need this to stay on?
|
||||
// esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
|
||||
|
||||
esp_light_sleep_start();
|
||||
// If we woke by keypress (7) then turn on the screen
|
||||
if (esp_sleep_get_wakeup_cause() == ESP_SLEEP_WAKEUP_GPIO) {
|
||||
// Try not to puke, but we pretend we moved if they hit a key, to exit SLEEP
|
||||
// Try not to puke, but we pretend we moved if they hit a key, to exit SLEEP and restart timers
|
||||
last_moved_ms = screen_last_active_ms = millis();
|
||||
was_screen_on = true; // Lies
|
||||
Serial.println("(GPIO)");
|
||||
}
|
||||
Serial.println("..woke");
|
||||
|
||||
if (was_screen_on)
|
||||
screen_on();
|
||||
|
||||
if (axp192_found) {
|
||||
axp.setPowerOutPut(AXP192_LDO3, AXP202_ON); // GPS power
|
||||
// axp.setPowerOutPut(AXP192_DCDC1, AXP202_ON); // OLED power
|
||||
// if (oled_found)
|
||||
// screen_setup();
|
||||
}
|
||||
|
||||
if (was_screen_on) {
|
||||
screen_on();
|
||||
is_screen_on = true;
|
||||
}
|
||||
|
||||
delay(100); // GPS doesn't respond right away.. not ready for baud-rate test.
|
||||
gps_setup();
|
||||
delay(100); // GPS doesn't respond right away.. not ready for baud-rate test.
|
||||
gps_setup(false); // Resync with GPS
|
||||
}
|
||||
|
||||
// Power OFF -- does not return
|
||||
|
@ -803,7 +880,7 @@ uint32_t woke_fix_count = 0;
|
|||
|
||||
/* Determine the current activity state */
|
||||
void update_activity() {
|
||||
static enum activity_state last_active_state = ACTIVITY_MOVING;
|
||||
static enum activity_state last_active_state = ACTIVITY_INVALID;
|
||||
|
||||
if (active_state != last_active_state) {
|
||||
switch (active_state) {
|
||||
|
@ -840,22 +917,24 @@ void update_activity() {
|
|||
clean_shutdown();
|
||||
}
|
||||
|
||||
// Here we just woke from a GPS-off long sleep.
|
||||
// When we have a fresh GPS fix, and the fix qualifies for mapper report, we can resume
|
||||
// either mapping or going back to sleep. Until then, we loop in Wake looking for a good GPS signal.
|
||||
// Note that we have to be sensitive to "good fix, but not interesting" and go right back to sleep.
|
||||
// We're only staying awake until we got a good GPS fix or gave up, NOT until we send a mapper report.
|
||||
if (active_state == ACTIVITY_WOKE) {
|
||||
if (gps_sentencesWithFix() != woke_fix_count) {
|
||||
mapper_uplink();
|
||||
if (tGPS.sentencesWithFix() != woke_fix_count && mapper_uplink() != MAPPER_UPLINK_BADFIX)
|
||||
active_state = ACTIVITY_REST;
|
||||
} else if (now - woke_time_ms > gps_lost_wait_s * 1000) {
|
||||
else if (now - woke_time_ms > gps_lost_wait_s * 1000)
|
||||
active_state = ACTIVITY_GPS_LOST;
|
||||
}
|
||||
return; // else stay in WOKE
|
||||
return; // else stay in WOKE until we make a good report
|
||||
}
|
||||
|
||||
if (active_state == ACTIVITY_SLEEP && !in_menu) {
|
||||
Serial.printf("Sleep %d...", tx_interval_s);
|
||||
low_power_sleep(tx_interval_s);
|
||||
active_state = ACTIVITY_WOKE;
|
||||
woke_time_ms = millis();
|
||||
woke_fix_count = gps_sentencesWithFix();
|
||||
woke_fix_count = tGPS.sentencesWithFix();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -872,8 +951,21 @@ void update_activity() {
|
|||
active_state = ACTIVITY_MOVING;
|
||||
}
|
||||
|
||||
{
|
||||
boolean had_usb_power = have_usb_power;
|
||||
have_usb_power = (axp192_found && axp.isVBUSPlug());
|
||||
|
||||
if (have_usb_power && !had_usb_power) {
|
||||
usb_power_count++;
|
||||
status_uplink(STATUS_USB_ON, usb_power_count);
|
||||
}
|
||||
if (!have_usb_power && had_usb_power) {
|
||||
status_uplink(STATUS_USB_OFF, usb_power_count);
|
||||
}
|
||||
}
|
||||
|
||||
// If we have USB power, keep GPS on all the time; don't sleep
|
||||
if (1 && axp192_found && axp.isVBUSPlug()) {
|
||||
if (have_usb_power) {
|
||||
if (active_state == ACTIVITY_SLEEP)
|
||||
active_state = ACTIVITY_REST;
|
||||
}
|
||||
|
@ -924,9 +1016,9 @@ const char *find_irq_name(void) {
|
|||
else if (axp.isVbusOverVoltageIRQ())
|
||||
irq_name = "VbusOverVoltage";
|
||||
else if (axp.isVbusPlugInIRQ())
|
||||
irq_name = "VbusPlugIn";
|
||||
irq_name = "USB Connected"; // "VbusPlugIn";
|
||||
else if (axp.isVbusRemoveIRQ())
|
||||
irq_name = "VbusRemove";
|
||||
irq_name = "USB Removed"; // "VbusRemove";
|
||||
else if (axp.isVbusLowVHOLDIRQ())
|
||||
irq_name = "VbusLowVHOLD";
|
||||
else if (axp.isBattPlugInIRQ())
|
||||
|
@ -949,10 +1041,6 @@ const char *find_irq_name(void) {
|
|||
irq_name = "ChipOvertemperature";
|
||||
else if (axp.isChargingCurrentLessIRQ()) {
|
||||
irq_name = "ChargingCurrentLess";
|
||||
// The Charging Current (770mA max feed) is less than requested
|
||||
// Persistent IRQ. Clear it after showing it once.
|
||||
// TODO: Show it every X minutes? Adjust charge current request?
|
||||
axp.enableIRQ(AXP202_CHARGE_LOW_CUR_IRQ, 0);
|
||||
} else if (axp.isDC2VoltageLessIRQ())
|
||||
irq_name = "DC2VoltageLess";
|
||||
else if (axp.isDC3VoltageLessIRQ())
|
||||
|
@ -1039,25 +1127,27 @@ void menu_gps_passthrough(void) {
|
|||
gps_passthrough();
|
||||
// Does not return.
|
||||
}
|
||||
|
||||
void menu_experiment(void) {
|
||||
#if 0
|
||||
static boolean power_toggle = true;
|
||||
static int gps_mv = 3300;
|
||||
|
||||
Serial.printf("%f mA %f mW\n", axp.getBattChargeCurrent() - axp.getBattDischargeCurrent(), axp.getBattInpower());
|
||||
gps_mv += 100;
|
||||
if (gps_mv > 3600)
|
||||
gps_mv = 2700;
|
||||
|
||||
axp.setPowerOutPut(AXP192_LDO3,
|
||||
power_toggle ? AXP202_ON : AXP202_OFF); // GPS main power
|
||||
power_toggle = !power_toggle;
|
||||
#endif
|
||||
Serial.printf("GPS Voltage: %d\n", gps_mv);
|
||||
snprintf(buffer, sizeof(buffer), "\nGPS %dmv", gps_mv);
|
||||
screen_print(buffer);
|
||||
|
||||
Serial.println("Sleeping for 5...");
|
||||
low_power_sleep(5);
|
||||
Serial.println("Woke.");
|
||||
axp.setLDO3Voltage(gps_mv); // Voltage for GPS Power. (Neo-6 can take 2.7v to 3.6v)
|
||||
}
|
||||
|
||||
void menu_deadzone_here(void) {
|
||||
deadzone_lat = gps_latitude();
|
||||
deadzone_lon = gps_longitude();
|
||||
deadzone_radius_m = DEADZONE_RADIUS_M;
|
||||
if (tGPS.location.isValid()) {
|
||||
deadzone_lat = tGPS.location.lat();
|
||||
deadzone_lon = tGPS.location.lng();
|
||||
deadzone_radius_m = DEADZONE_RADIUS_M;
|
||||
}
|
||||
}
|
||||
void menu_no_deadzone(void) {
|
||||
deadzone_radius_m = 0.0;
|
||||
|
@ -1067,6 +1157,10 @@ void menu_stay_on(void) {
|
|||
screen_stay_on = !screen_stay_on;
|
||||
}
|
||||
|
||||
void menu_gps_reset(void) {
|
||||
gps_full_reset();
|
||||
}
|
||||
|
||||
dr_t sf_list[] = {DR_SF7, DR_SF8, DR_SF9, DR_SF10};
|
||||
#define SF_ENTRIES (sizeof(sf_list) / sizeof(sf_list[0]))
|
||||
uint8_t sf_index = 0;
|
||||
|
@ -1087,7 +1181,7 @@ struct menu_entry menu[] = {
|
|||
{"Distance -", menu_distance_minus}, {"Time +", menu_time_plus}, {"Time -", menu_time_minus},
|
||||
{"Change SF", menu_change_sf}, {"Full Reset", menu_flush_prefs}, {"USB GPS", menu_gps_passthrough},
|
||||
{"Deadzone Here", menu_deadzone_here}, {"No Deadzone", menu_no_deadzone}, {"Stay On", menu_stay_on},
|
||||
{"Experiment", menu_experiment}};
|
||||
{"GPS Reset", menu_gps_reset}, {"Experiment", menu_experiment}};
|
||||
#define MENU_ENTRIES (sizeof(menu) / sizeof(menu[0]))
|
||||
|
||||
const char *menu_prev;
|
||||
|
@ -1116,7 +1210,7 @@ void menu_selected(void) {
|
|||
}
|
||||
|
||||
void update_screen(void) {
|
||||
screen_header(tx_interval_s, min_dist_moved, sf_name, gps_sats(), in_deadzone, screen_stay_on, never_rest);
|
||||
screen_header(tx_interval_s, min_dist_moved, sf_name, in_deadzone, screen_stay_on, never_rest);
|
||||
screen_body(in_menu, menu_prev, menu_cur, menu_next, is_highlighted);
|
||||
}
|
||||
|
||||
|
@ -1127,10 +1221,10 @@ void loop() {
|
|||
uint32_t now = millis();
|
||||
|
||||
gps_loop(0 /* active_state == ACTIVITY_WOKE */); // Update GPS
|
||||
now_fix_count = gps_sentencesWithFix();
|
||||
now_fix_count = tGPS.sentencesWithFix(); // Did we get a new fix?
|
||||
if (now_fix_count != last_fix_count) {
|
||||
last_fix_count = now_fix_count;
|
||||
last_fix_time = now;
|
||||
last_fix_time = now; // Note the time of most recent fix
|
||||
}
|
||||
|
||||
ttn_loop();
|
||||
|
@ -1154,7 +1248,7 @@ void loop() {
|
|||
else if (axp.isPEKLongtPressIRQ()) // want to turn OFF
|
||||
menu_power_off();
|
||||
else {
|
||||
snprintf(buffer, sizeof(buffer), "\n* %s ", irq_name);
|
||||
snprintf(buffer, sizeof(buffer), "\n* %s ", irq_name);
|
||||
screen_print(buffer);
|
||||
}
|
||||
axp.clearIRQ();
|
||||
|
@ -1208,7 +1302,7 @@ void loop() {
|
|||
last_gpslost_ms = 0; // Reset if we regained GPS
|
||||
}
|
||||
|
||||
if (mapper_uplink()) {
|
||||
if (mapper_uplink() == MAPPER_UPLINK_SUCCESS) {
|
||||
// Good send, light Blue LED
|
||||
if (axp192_found)
|
||||
axp.setChgLEDMode(AXP20X_LED_LOW_LEVEL);
|
||||
|
|
158
main/screen.cpp
158
main/screen.cpp
|
@ -25,18 +25,22 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
#include <Wire.h>
|
||||
|
||||
#include "OLEDDisplay.h"
|
||||
#include "SH1106Wire.h"
|
||||
#include "SSD1306Wire.h"
|
||||
#include "configuration.h"
|
||||
#include "credentials.h"
|
||||
#include "fonts.h"
|
||||
#include "gps.h"
|
||||
#include "images.h"
|
||||
#include "font.h"
|
||||
|
||||
#define SCREEN_HEADER_HEIGHT 24
|
||||
#define SCREEN_HEADER_HEIGHT 23
|
||||
|
||||
SSD1306Wire *display;
|
||||
OLEDDisplay *display;
|
||||
uint8_t _screen_line = SCREEN_HEADER_HEIGHT - 1;
|
||||
|
||||
enum display_types { DISPLAY_UNKNOWN, DISPLAY_SSD1306, DISPLAY_SH1106 };
|
||||
enum display_types display_type = DISPLAY_UNKNOWN;
|
||||
|
||||
void screen_show_logo() {
|
||||
if (!display)
|
||||
return;
|
||||
|
@ -99,58 +103,154 @@ void screen_update() {
|
|||
display->display();
|
||||
}
|
||||
|
||||
void screen_setup() {
|
||||
/*
|
||||
* The SSD1306 and SH1106 controllers are almost the same, but different.
|
||||
* Most importantly here, the SH1106 allows reading from the frame buffer, while the SSD1306 does not.
|
||||
* We exploit this by writing two bytes and reading them back. A mismatch probably means SSD1306.
|
||||
* Probably.
|
||||
*/
|
||||
enum display_types display_get_type(uint8_t id) {
|
||||
uint8_t err;
|
||||
uint8_t b1, b2;
|
||||
|
||||
Wire.begin(I2C_SDA, I2C_SCL);
|
||||
Wire.setClock(7000000);
|
||||
|
||||
Wire.beginTransmission(id);
|
||||
uint8_t a[] = {
|
||||
0, // co=0 DC=0 000000 to start command
|
||||
0x00, // Lower Column Address = 0
|
||||
0x10, // Higher Column Address = 0
|
||||
0xB0 // Set Page Address 0
|
||||
};
|
||||
Wire.write(a, sizeof(a));
|
||||
if ((err = Wire.endTransmission(false)) != 0) {
|
||||
Serial.printf("err=%d EndTransmission=%d(%s)", err, Wire.lastError(), Wire.getErrorText(Wire.lastError()));
|
||||
return DISPLAY_UNKNOWN;
|
||||
}
|
||||
|
||||
Wire.beginTransmission(id);
|
||||
uint8_t b[] = {0x40, 'M', 'P'}; // co=0 DC=1 & 000000, then two bytes of data
|
||||
Wire.write(b, sizeof(b));
|
||||
if ((err = Wire.endTransmission(false)) != 0) {
|
||||
Serial.printf("err=%d EndTransmission=%d(%s)", err, Wire.lastError(), Wire.getErrorText(Wire.lastError()));
|
||||
return DISPLAY_UNKNOWN;
|
||||
}
|
||||
|
||||
Wire.beginTransmission(id);
|
||||
uint8_t c[] = {0, 0, 0x10}; // Back to Lower & Higher Column address 0
|
||||
Wire.write(c, sizeof(c));
|
||||
if ((err = Wire.endTransmission(false)) != 0) {
|
||||
Serial.printf("err=%d EndTransmission=%d(%s)", err, Wire.lastError(), Wire.getErrorText(Wire.lastError()));
|
||||
return DISPLAY_UNKNOWN;
|
||||
}
|
||||
|
||||
Wire.beginTransmission(id);
|
||||
Wire.write(0x40); // Data next
|
||||
if ((err = Wire.endTransmission(false)) != 0) {
|
||||
Serial.printf("err=%d EndTransmission=%d(%s)", err, Wire.lastError(), Wire.getErrorText(Wire.lastError()));
|
||||
return DISPLAY_UNKNOWN;
|
||||
}
|
||||
err = Wire.requestFrom((int)id, (int)3, (int)1);
|
||||
if (err != 3) {
|
||||
return DISPLAY_UNKNOWN;
|
||||
}
|
||||
Wire.read(); // Must discard 1 byte
|
||||
b1 = Wire.read();
|
||||
b2 = Wire.read();
|
||||
Wire.endTransmission();
|
||||
|
||||
// If we read back what we wrote, memory is readable:
|
||||
if (b1 == 'M' && b2 == 'P')
|
||||
return DISPLAY_SH1106;
|
||||
else
|
||||
return DISPLAY_SSD1306;
|
||||
}
|
||||
|
||||
void screen_setup(uint8_t addr) {
|
||||
/* Attempt to determine which kind of display we're dealing with */
|
||||
if (display_type == DISPLAY_UNKNOWN)
|
||||
display_type = display_get_type(addr);
|
||||
|
||||
// Display instance
|
||||
display = new SSD1306Wire(SSD1306_ADDRESS, I2C_SDA, I2C_SCL);
|
||||
if (display_type == DISPLAY_SSD1306)
|
||||
display = new SSD1306Wire(addr, I2C_SDA, I2C_SCL);
|
||||
else if (display_type == DISPLAY_SH1106)
|
||||
display = new SH1106Wire(addr, I2C_SDA, I2C_SCL);
|
||||
else
|
||||
return;
|
||||
display->init();
|
||||
display->flipScreenVertically();
|
||||
display->setFont(Custom_ArialMT_Plain_10);
|
||||
display->setFont(Custom_Font);
|
||||
|
||||
// Scroll buffer
|
||||
display->setLogBuffer(4, 30);
|
||||
}
|
||||
|
||||
void screen_end() {
|
||||
if (display) {
|
||||
screen_off();
|
||||
display->end();
|
||||
delete display;
|
||||
}
|
||||
}
|
||||
|
||||
#include <axp20x.h>
|
||||
extern AXP20X_Class axp; // TODO: This is evil
|
||||
|
||||
void screen_header(unsigned int tx_interval_s, float min_dist_moved, char *cached_sf_name, int sats,
|
||||
boolean in_deadzone, boolean stay_on, boolean never_rest) {
|
||||
void screen_header(unsigned int tx_interval_s, float min_dist_moved, char *cached_sf_name, boolean in_deadzone,
|
||||
boolean stay_on, boolean never_rest) {
|
||||
if (!display)
|
||||
return;
|
||||
|
||||
char buffer[40];
|
||||
uint32_t sats = tGPS.satellites.value();
|
||||
boolean no_gps = (sats < 3);
|
||||
uint16_t devid_hint = ((DEVEUI[7] << 4) | (DEVEUI[6] & 0xF0) >> 4);
|
||||
|
||||
display->clear();
|
||||
|
||||
// Cycle display every 3 seconds
|
||||
if (millis() % 6000 < 3000) {
|
||||
// 2 bytes of Device EUI with Voltage and Current
|
||||
snprintf(buffer, sizeof(buffer), "#%03X", ((DEVEUI[7] << 4) | (DEVEUI[6] & 0xF0) >> 4));
|
||||
// Voltage and Current
|
||||
snprintf(buffer, sizeof(buffer), "%.2fV %.0fmA", axp.getBattVoltage() / 1000,
|
||||
axp.getBattChargeCurrent() - axp.getBattDischargeCurrent());
|
||||
|
||||
// display->setTextAlignment(TEXT_ALIGN_CENTER);
|
||||
// display->drawString(display->getWidth() / 2, 2, buffer);
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
display->drawString(0, 2, buffer);
|
||||
|
||||
snprintf(buffer, sizeof(buffer), "%.2fV %.0fmA", axp.getBattVoltage() / 1000,
|
||||
axp.getBattChargeCurrent() - axp.getBattDischargeCurrent());
|
||||
} else {
|
||||
// Message count and time
|
||||
// snprintf(buffer, sizeof(buffer), "%4d", ttn_get_count() % 10000);
|
||||
// display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
// display->drawString(0, 2, buffer);
|
||||
// ID & Time
|
||||
if (no_gps) {
|
||||
snprintf(buffer, sizeof(buffer), "#%03X", devid_hint);
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
display->drawString(0, 2, buffer);
|
||||
|
||||
if (sats < 3)
|
||||
snprintf(buffer, sizeof(buffer), "*** NO GPS ***");
|
||||
else
|
||||
gps_time(buffer, sizeof(buffer));
|
||||
display->setTextAlignment(TEXT_ALIGN_CENTER);
|
||||
display->drawString(display->getWidth() / 2, 2, "*** NO GPS ***");
|
||||
|
||||
snprintf(buffer, sizeof(buffer), "(%d)", sats);
|
||||
display->setTextAlignment(TEXT_ALIGN_RIGHT);
|
||||
display->drawString(display->getWidth(), 2, buffer);
|
||||
|
||||
} else {
|
||||
snprintf(buffer, sizeof(buffer), "#%03X %02d:%02d:%02d", devid_hint, tGPS.time.hour(), tGPS.time.minute(),
|
||||
tGPS.time.second());
|
||||
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
display->drawString(0, 2, buffer);
|
||||
}
|
||||
}
|
||||
|
||||
display->setTextAlignment(TEXT_ALIGN_CENTER);
|
||||
display->drawString(display->getWidth() / 2, 2, buffer);
|
||||
|
||||
// Satellite count
|
||||
display->setTextAlignment(TEXT_ALIGN_RIGHT);
|
||||
display->drawString(display->getWidth() - SATELLITE_IMAGE_WIDTH - 4, 2, itoa(sats, buffer, 10));
|
||||
display->drawXbm(display->getWidth() - SATELLITE_IMAGE_WIDTH, 0, SATELLITE_IMAGE_WIDTH, SATELLITE_IMAGE_HEIGHT,
|
||||
SATELLITE_IMAGE);
|
||||
// HDOP & Satellite count
|
||||
if (!no_gps) {
|
||||
snprintf(buffer, sizeof(buffer), "%2.1f %d", tGPS.hdop.hdop(), sats);
|
||||
display->setTextAlignment(TEXT_ALIGN_RIGHT);
|
||||
display->drawString(display->getWidth() - SATELLITE_IMAGE_WIDTH - 4, 2, buffer);
|
||||
display->drawXbm(display->getWidth() - SATELLITE_IMAGE_WIDTH, 0, SATELLITE_IMAGE_WIDTH, SATELLITE_IMAGE_HEIGHT,
|
||||
SATELLITE_IMAGE);
|
||||
}
|
||||
|
||||
// Second status row:
|
||||
snprintf(buffer, sizeof(buffer), "%us %.0fm %c%c%c", tx_interval_s, min_dist_moved, in_deadzone ? 'D' : ' ',
|
||||
|
|
|
@ -9,11 +9,12 @@ void screen_update(void);
|
|||
|
||||
void screen_body(boolean in_menu, const char *menu_prev, const char *menu_cur, const char *menu_next,
|
||||
boolean highlighted);
|
||||
void screen_header(unsigned int tx_interval_s, float min_dist_moved, char *cached_sf_name, int sats,
|
||||
boolean in_deadzone, boolean stay_on, boolean never_rest);
|
||||
void screen_header(unsigned int tx_interval_s, float min_dist_moved, char *cached_sf_name, boolean in_deadzone,
|
||||
boolean stay_on, boolean never_rest);
|
||||
|
||||
void screen_off(void);
|
||||
void screen_on(void);
|
||||
|
||||
void screen_show_logo(void);
|
||||
void screen_setup(void);
|
||||
void screen_setup(uint8_t addr);
|
||||
void screen_end(void);
|
||||
|
|
34
main/ttn.cpp
34
main/ttn.cpp
|
@ -105,7 +105,8 @@ void forceTxSingleChannelDr() {
|
|||
ttn_sf(ttn_tx_sf);
|
||||
}
|
||||
|
||||
// DevEUI generator using devices's MAC address - from https://github.com/cyberman54/ESP32-Paxcounter/blob/master/src/lorawan.cpp
|
||||
// DevEUI generator using devices's MAC address - from
|
||||
// https://github.com/cyberman54/ESP32-Paxcounter/blob/master/src/lorawan.cpp
|
||||
void gen_lora_deveui(uint8_t* pdeveui) {
|
||||
uint8_t *p = pdeveui, dmac[6];
|
||||
int i = 0;
|
||||
|
@ -275,7 +276,7 @@ bool ttn_setup() {
|
|||
return (1 == os_init_ex((const void*)&lmic_pins));
|
||||
}
|
||||
|
||||
void ttn_join() {
|
||||
void ttn_join(void) {
|
||||
// Reset the MAC state. Session and pending data transfers will be discarded.
|
||||
LMIC_reset();
|
||||
|
||||
|
@ -324,9 +325,21 @@ void ttn_join() {
|
|||
// other regions, this will need to be changed.
|
||||
LMIC_selectSubBand(1);
|
||||
|
||||
#elif defined(CFG_au915) && defined(CFG_au915_fsb6)
|
||||
|
||||
// AU915 FSB6
|
||||
// CH 40-47 (923.2 - 924.6 MHz)
|
||||
// Helium DualPlan was live in Australia 2022-11-17 to 2023-04-18
|
||||
// DualPlan allowed AU915 devices to co-exist with AS923 by taking advantage
|
||||
// of some AU915 FSB6 frequencies overlapping AS923 frequencies.
|
||||
// If a device joined on the first two channels of FSB6, it was treated as
|
||||
// an AS923 device. On the last 6 channels, an AU915 device.
|
||||
LMIC_selectSubBand(5);
|
||||
|
||||
#elif defined(CFG_au915)
|
||||
|
||||
// set sub band for AU915
|
||||
// AU915 FSB2
|
||||
// CH 8-15 (916.8 - 918.2 MHz uplink)
|
||||
// https://github.com/TheThingsNetwork/gateway-conf/blob/master/AU-global_conf.json
|
||||
LMIC_selectSubBand(1);
|
||||
|
||||
|
@ -382,14 +395,16 @@ void ttn_join() {
|
|||
uint32_t netId = p.getUInt("netId", UINT32_MAX);
|
||||
uint32_t devAddr = p.getUInt("devAddr", UINT32_MAX);
|
||||
uint8_t nwkKey[16], artKey[16];
|
||||
bool keysgood = p.getBytes("nwkKey", nwkKey, sizeof(nwkKey)) == sizeof(nwkKey) && p.getBytes("artKey", artKey, sizeof(artKey)) == sizeof(artKey);
|
||||
bool keysgood = devAddr != UINT32_MAX && netId != UINT32_MAX &&
|
||||
p.getBytes("nwkKey", nwkKey, sizeof(nwkKey)) == sizeof(nwkKey) &&
|
||||
p.getBytes("artKey", artKey, sizeof(artKey)) == sizeof(artKey);
|
||||
p.end(); // close our prefs
|
||||
|
||||
if (!keysgood) {
|
||||
// We have not yet joined a network, start a full join attempt
|
||||
// Make LMiC initialize the default channels, choose a channel, and
|
||||
// schedule the OTAA join
|
||||
Serial.println("No session saved, joining from scratch");
|
||||
Serial.println("Joining from scratch");
|
||||
screen_print("Joining...\n");
|
||||
LMIC_startJoining();
|
||||
} else {
|
||||
|
@ -410,7 +425,7 @@ void ttn_get_sf_name(char* b, size_t len) {
|
|||
u1_t sf, bw;
|
||||
sf = getSf(txrps) + 6; // 1 == SF7
|
||||
bw = getBw(txrps);
|
||||
|
||||
|
||||
/*
|
||||
snprintf(b, len, "%3d.%02d SF%d BW%d",
|
||||
LMIC.freq / 1000000,
|
||||
|
@ -454,9 +469,10 @@ void ttn_write_prefs() {
|
|||
static void ttn_set_cnt() {
|
||||
LMIC_setSeqnoUp(count);
|
||||
|
||||
// We occasionally mirror our count to flash, to ensure that if we lose power we will at least start with a count that is almost correct
|
||||
// (otherwise the TNN network will discard packets until count once again reaches the value they've seen). We limit these writes to a max rate
|
||||
// of one write every 5 minutes. Which should let the FLASH last for 300 years (given the ESP32 NVS algoritm)
|
||||
// We occasionally mirror our count to flash, to ensure that if we lose power we will at least start with a count that
|
||||
// is almost correct (otherwise the TNN network will discard packets until count once again reaches the value they've
|
||||
// seen). We limit these writes to a max rate of one write every 5 minutes. Which should let the FLASH last for 300
|
||||
// years (given the ESP32 NVS algorithm)
|
||||
static uint32_t lastWriteMsec = UINT32_MAX; // Ensure we write at least once
|
||||
uint32_t now = millis();
|
||||
if (now < lastWriteMsec || (now - lastWriteMsec) > 5 * 60 * 1000L) { // write if we roll over (50 days) or 5 mins
|
||||
|
|
|
@ -12,31 +12,35 @@
|
|||
src_dir = main
|
||||
|
||||
[env]
|
||||
platform = espressif32
|
||||
platform = espressif32@^3.5.0
|
||||
board = ttgo-t-beam
|
||||
framework = arduino
|
||||
build_flags = -Wall
|
||||
-Wextra
|
||||
-Wno-missing-field-initializers -O3
|
||||
-D CFG_us915=1
|
||||
; -D CFG_eu868=1
|
||||
; -D CFG_eu868=1
|
||||
; -D CFG_au915=1
|
||||
; -D CFG_au915_fsb6=1
|
||||
; -D CFG_as923=1
|
||||
-D CFG_sx1276_radio=1
|
||||
-D ARDUINO_LMIC_PROJECT_CONFIG_H_SUPPRESS
|
||||
-D ARDUINO_TTGO_LoRa32_V1
|
||||
|
||||
lib_deps =
|
||||
mcci-catena/MCCI LoRaWAN LMIC library
|
||||
thingpulse/ESP8266 and ESP32 OLED driver for SSD1306 displays
|
||||
lewisxhe/AXP202X_Library
|
||||
mikalhart/TinyGPSPlus
|
||||
mcci-catena/MCCI LoRaWAN LMIC library@^4.1.1
|
||||
thingpulse/ESP8266 and ESP32 OLED driver for SSD1306 displays@^4.3.0
|
||||
lewisxhe/AXP202X_Library@^1.1.3
|
||||
mikalhart/TinyGPSPlus@^1.0.3
|
||||
|
||||
monitor_speed = 115200
|
||||
; monitor_port = COM17
|
||||
; upload_speed = 921600
|
||||
; upload_port = COM17
|
||||
|
||||
[env:release]
|
||||
|
||||
[env:debug]
|
||||
debug_build_flags =
|
||||
-D DEBUG
|
||||
-D DEBUG
|
||||
-D LMIC_DEBUG_LEVEL=3
|
||||
|
|
|
@ -13,7 +13,8 @@
|
|||
"string": "cpp",
|
||||
"unordered_map": "cpp",
|
||||
"unordered_set": "cpp",
|
||||
"initializer_list": "cpp"
|
||||
"initializer_list": "cpp",
|
||||
"*.tcc": "cpp"
|
||||
}
|
||||
}
|
||||
}
|
Ładowanie…
Reference in New Issue