Add build instructions
Some checks failed
Continuous Integration / Rust Checks (map[args:--all -- --check --color always command:fmt]) (push) Has been cancelled
Continuous Integration / Rust Checks (map[args:--all-targets --all-features --workspace -- -D warnings command:clippy]) (push) Has been cancelled
Continuous Integration / Rust Checks (map[args:--release command:build]) (push) Has been cancelled

This commit is contained in:
Richard Patching 2025-04-16 21:00:32 +01:00
commit 4a32d32080
19 changed files with 705 additions and 0 deletions

16
.cargo/config.toml Normal file
View File

@ -0,0 +1,16 @@
[build]
target = "xtensa-esp32-espidf"
[target.xtensa-esp32-espidf]
linker = "ldproxy"
runner = "espflash flash --monitor"
rustflags = [ "--cfg", "espidf_time64"]
[unstable]
build-std = ["std", "panic_abort"]
[env]
MCU="esp32"
# Note: this variable is not used by the pio builder (`cargo build --features pio`)
ESP_IDF_VERSION = "v5.2.3"

34
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@ -0,0 +1,34 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: bug
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Flash firmware to '...'
2. Connect '....'
3. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Hardware Setup**
- ESP32 Board: [e.g., ESP32-DevKitC]
- GPS Module: [e.g., NEO-6M]
- Display: [e.g., 1.8" TFT]
- Connected peripherals:
**Software Environment**
- Rust version: [e.g., 1.77]
- ESP-IDF version:
- Operating System:
**Additional context**
Add any other context about the problem here.

View File

@ -0,0 +1,20 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: enhancement
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is.
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

View File

@ -0,0 +1,35 @@
---
name: Hardware issue
about: Report a hardware-related problem or compatibility issue
title: '[HARDWARE] '
labels: hardware
assignees: ''
---
**Hardware Configuration**
- ESP32 Board Model:
- GPS Module:
- Display Type:
- Power Supply:
- Other Connected Components:
**Issue Description**
A clear description of the hardware issue.
**Expected Behavior**
What you expected to happen.
**Actual Behavior**
What actually happened.
**Photos/Diagrams**
If applicable, add photos or diagrams to help explain your problem.
**Environment**
- Temperature:
- Indoor/Outdoor:
- Weather Conditions (if relevant):
**Additional Context**
Add any other context about the problem here.

27
.github/pull_request_template.md vendored Normal file
View File

@ -0,0 +1,27 @@
## Description
Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context.
Fixes # (issue)
## Type of change
Please delete options that are not relevant.
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
- [ ] This change requires a documentation update
## How Has This Been Tested?
Please describe the tests that you ran to verify your changes.
- [ ] Test A
- [ ] Test B
## Checklist:
- [ ] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [ ] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my feature works
- [ ] New and existing unit tests pass locally with my changes

42
.github/workflows/rust_ci.yml vendored Normal file
View File

@ -0,0 +1,42 @@
name: Continuous Integration
on:
push:
branches:
- main
paths-ignore:
- "**/README.md"
pull_request:
workflow_dispatch:
env:
CARGO_TERM_COLOR: always
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
jobs:
rust-checks:
name: Rust Checks
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
action:
- command: build
args: --release
- command: fmt
args: --all -- --check --color always
- command: clippy
args: --all-targets --all-features --workspace -- -D warnings
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Rust
uses: esp-rs/xtensa-toolchain@v1.5
with:
default: true
buildtargets: esp32
ldproxy: true
- name: Enable caching
uses: Swatinem/rust-cache@v2
- name: Run command
run: cargo ${{ matrix.action.command }} ${{ matrix.action.args }}

31
.gitignore vendored Normal file
View File

@ -0,0 +1,31 @@
# Rust
/target
**/*.rs.bk
Cargo.lock
# IDE
/.vscode
/.idea
*.swp
*.swo
# Build
/.embuild
/dist
# Environment
.env
.env.local
.env.*.local
# System
.DS_Store
Thumbs.db
# Debug
*.log
*.debug
# Backup
*.bak
*~

53
CODE_OF_CONDUCT.md Normal file
View File

@ -0,0 +1,53 @@
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, religion, or sexual identity
and orientation.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes
* Focusing on what is best not just for us as individuals, but for the overall community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information without explicit permission
* Other conduct which could reasonably be considered inappropriate in a professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
[INSERT CONTACT METHOD].
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org),
version 2.0, available at
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.

31
Cargo.toml Normal file
View File

@ -0,0 +1,31 @@
[package]
name = "aniker"
version = "0.1.0"
authors = ["Richard Patching <richard@justaddpixels.com>"]
edition = "2021"
resolver = "2"
rust-version = "1.77"
[[bin]]
name = "aniker"
harness = false # do not use the built in cargo test harness -> resolve rust-analyzer errors
[profile.release]
opt-level = "s"
[profile.dev]
debug = true # Symbols are nice and they don't increase the size on Flash
opt-level = "z"
[features]
default = []
experimental = ["esp-idf-svc/experimental"]
[dependencies]
log = "0.4"
esp-idf-svc = { version = "0.51", features = ["critical-section", "embassy-time-driver", "embassy-sync"] }
aniker-gps = { path = "../aniker-gps" }
[build-dependencies]
embuild = "0.33"

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2024 Richard Patching
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

48
README.md Normal file
View File

@ -0,0 +1,48 @@
# Aniker - ESP32 GPS Anchor Alarm
## Hardware Requirements
### Required Components
- ESP32 development board
- NEO-6M GPS module
- 1.8" TFT SPI Display (128x160 resolution)
- Connecting wires
- Power supply (USB or battery - specifications TBD)
### Display Specifications
- Resolution: 128x160 pixels
- Interface: SPI
- Size: 1.8 inch
- Controller: ST7735 (common for this display type)
- Color Depth: 16-bit (65K colors)
### GPS Module Specifications (NEO-6M)
- Operating voltage: 3.3V
- Communication: UART interface
- Update rate: 1Hz (default)
- Position accuracy: 2.5m
- Default baud rate: 9600bps
### Wiring Guide
#### NEO-6M GPS Connection
| NEO-6M Pin | ESP32 Pin | Description |
|------------|-----------|-------------|
| VCC | 3.3V | Power |
| GND | GND | Ground |
| TX | GPIO16* | UART RX |
| RX | GPIO17* | UART TX |
#### TFT Display Connection (SPI)
| TFT Pin | ESP32 Pin | Description |
|---------|-----------|-----------------|
| VCC | 3.3V | Power |
| GND | GND | Ground |
| SCL | GPIO18 | SPI Clock |
| SDA | GPIO23 | MOSI |
| RES | GPIO21 | Reset |
| DC | GPIO22 | Data/Command |
| CS | GPIO5 | Chip Select |
| BLK | GPIO4 | Backlight |
*Note: GPIO pins are configurable in the software

3
build.rs Normal file
View File

@ -0,0 +1,3 @@
fn main() {
embuild::espidf::sysenv::output();
}

View File

@ -0,0 +1,35 @@
# Display Configuration
[tft]
# Hardware Configuration
width = 128
height = 160
rotation = 0 # 0, 90, 180, or 270 degrees
# SPI Configuration
spi_clock_speed = 20000000 # 20MHz
spi_mode = 0
# Pin Assignments
mosi_pin = 23
sclk_pin = 18
cs_pin = 5
dc_pin = 22
rst_pin = 21
blk_pin = 4
# Display Settings
default_brightness = 255 # 0-255
refresh_rate = 1000 # ms
timeout = 30000 # Screen timeout in ms, 0 for always on
# UI Settings
font_size = 2
text_color = 0xFFFF # White
background_color = 0x0000 # Black
alert_color = 0xF800 # Red
# Power Management
enable_power_save = false
dim_timeout = 10000 # ms before dimming
power_save_brightness = 64 # 0-255

19
config/gps_config.toml Normal file
View File

@ -0,0 +1,19 @@
# GPS Module Configuration
[neo6m]
# UART Configuration
uart_num = 1
baud_rate = 9600
tx_pin = 17
rx_pin = 16
# GPS Settings
update_rate = 1000 # ms
min_satellites = 4 # Minimum satellites for valid fix
# Anchor Alarm Settings
default_radius = 50 # meters
alarm_check_interval = 5000 # ms
# Power Management
power_save_mode = false # Future implementation

113
docs/NEO-6M_SETUP.md Normal file
View File

@ -0,0 +1,113 @@
# NEO-6M GPS Module Setup Guide
## Overview
The NEO-6M is a cost-effective GPS module that provides reliable positioning data for the Aniker anchor alarm system. This guide covers the basic setup and configuration of the NEO-6M with the ESP32.
## Module Features
- High sensitivity: -161 dBm tracking
- Time-To-First-Fix:
- Cold start: 27s
- Hot start: 1s
- Position accuracy: 2.5m CEP (Circular Error Probable)
- Velocity accuracy: 0.1m/s
- Operating temperature: -40°C to 85°C
## Physical Setup
### Power Requirements
- Input voltage: 3.3V DC
- Current consumption: ~45mA at continuous operation
- Backup power (optional): 2.0V to 3.6V for faster satellite acquisition
### Pin Connections
1. **Power Pins**
- VCC → ESP32 3.3V
- GND → ESP32 GND
2. **Communication Pins**
- TX → ESP32 GPIO16 (RX)
- RX → ESP32 GPIO17 (TX)
### Antenna Considerations
- The module comes with a ceramic patch antenna
- Place the antenna facing upward with clear view of the sky
- Avoid metal objects directly above the antenna
- Keep antenna away from sources of interference
## Initial Testing
### LED Indicators
- Power LED: Should be constantly on
- Signal LED: Will blink when receiving data from satellites
### Expected Behavior
1. When first powered on, the module will begin searching for satellites
2. Initial position fix may take 30-60 seconds in optimal conditions
3. Signal LED will begin blinking once satellites are acquired
## Troubleshooting
### Common Issues
1. **No Power LED**
- Check 3.3V power connection
- Verify ground connection
- Check for short circuits
2. **No Signal Reception**
- Ensure clear view of sky
- Check antenna connection
- Move away from sources of interference
- Try outdoor testing first
3. **Intermittent Data**
- Check wire connections
- Verify baud rate settings
- Check for interference sources
### Testing Tips
- First test outdoors with clear sky view
- Allow up to 5 minutes for first fix
- Use serial monitor to verify data reception
- Verify correct UART configuration
## Software Configuration
### Default Settings
- Baud rate: 9600bps
- Update rate: 1Hz
- NMEA messages: GGA, RMC, GSA, GSV
### Serial Communication
```rust
// Example configuration in Rust
let config = uart::config::Config {
baudrate: 9600,
data_bits: uart::config::DataBits::DataBits8,
parity: uart::config::Parity::ParityNone,
stop_bits: uart::config::StopBits::STOP1,
};
```
## Performance Expectations
### Typical Performance
- Time to first fix: 30-60 seconds
- Position accuracy: 2.5m (open sky)
- Update rate: 1Hz
- Operating temperature: -40°C to 85°C
### Environmental Factors
- Performance degrades under cloud cover
- Indoor operation is not reliable
- Metal objects can cause interference
- Marine environment considerations:
- Salt spray protection needed
- Weatherproofing recommended
- Stable mounting required
## Future Improvements
- [ ] Add power saving modes
- [ ] Implement faster update rates
- [ ] Add configuration interface
- [ ] Optimize for marine use

73
docs/TFT_SETUP.md Normal file
View File

@ -0,0 +1,73 @@
# 1.8" TFT Display Setup Guide
## Overview
The 1.8" TFT display (128x160) is used as the primary visual interface for the Aniker anchor alarm system. It displays GPS coordinates, anchor status, and alarm conditions.
## Display Specifications
### Technical Details
- Display Type: TFT LCD
- Resolution: 128x160 pixels
- Interface: SPI
- Controller: ST7735 (typical)
- Viewing Angle: ~160°
- Operating Voltage: 3.3V
- Backlight: LED
- Color Depth: 16-bit (65K colors)
### Physical Characteristics
- Screen Size: 1.8 inches diagonal
- Active Area: ~28mm x 35mm
- Module Size: ~34mm x 45mm (approximate)
- Interface: 8-pin connection
## Hardware Setup
### Power Requirements
- Logic Voltage: 3.3V
- Current Draw: ~100mA with backlight on
- Backlight Control: PWM capable
### Pin Connections
1. **Power Pins**
- VCC → ESP32 3.3V
- GND → ESP32 GND
- BLK → ESP32 GPIO4 (Backlight control)
2. **SPI Interface**
- SCL → ESP32 GPIO18 (SPI Clock)
- SDA → ESP32 GPIO23 (MOSI)
- RES → ESP32 GPIO21 (Reset)
- DC → ESP32 GPIO22 (Data/Command)
- CS → ESP32 GPIO5 (Chip Select)
### Display Orientation
- The display can be mounted in 4 orientations (0°, 90°, 180°, 270°)
- Software configuration available for orientation adjustment
- Default orientation: Portrait (0°)
## Software Integration
### Basic Configuration
```rust
// Example display configuration
let spi = SPIInterface::new(
spi,
gpio23, // MOSI
gpio18, // SCK
gpio5, // CS
gpio22, // DC
gpio21, // RST
);
let display = ST7735::new(
spi,
gpio4, // BLK
false, // is_inverted
160, // height
128, // width
);
```
### Display Layout
The screen is organized into several regions:

2
rust-toolchain.toml Normal file
View File

@ -0,0 +1,2 @@
[toolchain]
channel = "esp"

10
sdkconfig.defaults Normal file
View File

@ -0,0 +1,10 @@
# Rust often needs a bit of an extra main task stack size compared to C (the default is 3K)
CONFIG_ESP_MAIN_TASK_STACK_SIZE=8000
# Use this to set FreeRTOS kernel tick frequency to 1000 Hz (100 Hz by default).
# This allows to use 1 ms granularity for thread sleeps (10 ms by default).
#CONFIG_FREERTOS_HZ=1000
# Workaround for https://github.com/espressif/esp-idf/issues/7631
#CONFIG_MBEDTLS_CERTIFICATE_BUNDLE=n
#CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_FULL=n

92
src/main.rs Normal file
View File

@ -0,0 +1,92 @@
use aniker_gps::{parse_gga, GpsError};
use esp_idf_svc::hal::delay::FreeRtos;
use log::info;
const APP_VERSION: &str = env!("CARGO_PKG_VERSION");
fn main() {
// Initialize ESP-IDF
esp_idf_svc::sys::link_patches();
esp_idf_svc::log::EspLogger::initialize_default();
info!("Aniker GPS Test Application v{}", APP_VERSION);
info!("----------------------------------------");
info!("Aniker GPS Test Application Starting...");
// Example GPS sentences from different locations around the world:
// 1. Sydney Opera House, Australia
// 2. Mount Everest Base Camp, Nepal
// 3. Machu Picchu, Peru
// 4. Eiffel Tower, Paris, France
// 5. Table Mountain, Cape Town, South Africa
let test_sentences = vec![
// Sydney Opera House
"$GPGGA,023000,3357.3845,S,15112.7983,E,1,08,1.1,5.0,M,39.2,M,,*6D",
// Mount Everest Base Camp
"$GPGGA,023100,2759.1333,N,08656.9568,E,1,09,1.0,5364.0,M,-95.1,M,,*51",
// Machu Picchu
"$GPGGA,023200,1308.9511,S,07210.9327,W,1,07,1.2,2430.0,M,-15.3,M,,*62",
// Eiffel Tower
"$GPGGA,023300,4851.5156,N,00220.2978,E,1,10,0.9,33.0,M,47.0,M,,*68",
// Table Mountain
"$GPGGA,023400,3357.2828,S,01825.3214,E,1,08,1.0,1085.0,M,-33.0,M,,*6C",
];
// Process each test sentence
for (i, sentence) in test_sentences.iter().enumerate() {
let mut sentence = sentence.to_string();
info!("Processing location {}", i + 1);
info!("Raw NMEA: {}", sentence);
match parse_gga(&mut sentence) {
Ok(position) => {
info!("Successfully parsed GPS data:");
info!(
" Latitude: {} {}",
position.lat.abs(),
if position.lat >= 0.0 { "N" } else { "S" }
);
info!(
" Longitude: {} {}",
position.long.abs(),
if position.long >= 0.0 { "E" } else { "W" }
);
info!(" Altitude: {:.1} meters", position.alt);
// Add a descriptive location name
let location = match i {
0 => "Sydney Opera House, Australia",
1 => "Mount Everest Base Camp, Nepal",
2 => "Machu Picchu, Peru",
3 => "Eiffel Tower, Paris, France",
4 => "Table Mountain, Cape Town, South Africa",
_ => "Unknown Location",
};
info!(" Location: {}", location);
}
Err(e) => {
info!("Error parsing GPS data:");
match e {
GpsError::InvalidMessageType => {
info!(" Invalid message type, expected GGA")
}
GpsError::InvalidLength => info!(" Invalid GGA sentence length"),
GpsError::ParseError(msg) => info!(" Parse error: {}", msg),
GpsError::Other(msg) => info!(" Other error: {}", msg),
}
}
}
info!("----------------------------------------");
// Add a small delay between processing sentences
FreeRtos::delay_ms(2000);
}
info!("Aniker GPS Test Application Complete");
// Keep the application running
loop {
FreeRtos::delay_ms(1000);
}
}