clean-up
28
SmartEVSE-3/.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -1,28 +0,0 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**Upload your config**
|
||||
Press the "raw" button in the SmartEVSE webserver and upload the json settings file, so we can look at your configuration.
|
||||
|
||||
**Upload a debug log**
|
||||
Flash the debug version of the firmware (see https://github.com/dingo35/SmartEVSE-3.5/blob/master/SmartEVSE-3/HowToFlash.txt), telnet to your device, capture the debug log, cut it so that it shows JUST BEFORE and JUST AFTER the problem arises, and upload it here.
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
1. What Mode are you in? Normal, Smart or Solar?
|
||||
2. What steps do you take so the problem arises?
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen; expected Charging Current?
|
||||
|
||||
**Screenshots**
|
||||
Only add screenshots if it adds any information, e.g. when you are reporting a problem on the webserver screen.
|
||||
@@ -1,21 +0,0 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
ALSO, if your feature request relates to any reported issues previously, please LINK them here!
|
||||
|
||||
**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.
|
||||
130
SmartEVSE-3/.github/workflows/pio-build.yaml
vendored
@@ -1,130 +0,0 @@
|
||||
name: PlatformIO CI
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
major:
|
||||
required: true
|
||||
type: string
|
||||
minor:
|
||||
required: true
|
||||
type: string
|
||||
patch:
|
||||
required: true
|
||||
type: string
|
||||
prerelease:
|
||||
required: false
|
||||
type: string
|
||||
outputs:
|
||||
artifact:
|
||||
description: "The first output string"
|
||||
value: ${{ jobs.build.outputs.artifact }}
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- release/*
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Get current branch
|
||||
id: branch
|
||||
run: echo "branch=${GITHUB_REF##*/}" >> $GITHUB_OUTPUT
|
||||
- name: Get current datetime
|
||||
id: datetime
|
||||
run: echo "datetime=$(date +'%Y%m%dT%H%M%S')" >> $GITHUB_OUTPUT
|
||||
- name: Get current time
|
||||
id: time
|
||||
run: echo "time=$(date +'%H%M%S')" >> $GITHUB_OUTPUT
|
||||
- name: Get version
|
||||
id: version
|
||||
shell: bash
|
||||
run: |
|
||||
if [ -z "${{ inputs.major }}" ]
|
||||
then
|
||||
echo "version=${{ steps.time.outputs.time }}" >> $GITHUB_OUTPUT
|
||||
else
|
||||
if [ -z "${{ inputs.prerelease }}" ]
|
||||
then
|
||||
echo "version=${{ inputs.major }}.${{ inputs.minor }}.${{ inputs.patch }}" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "version=${{ inputs.major }}.${{ inputs.minor }}.${{ inputs.patch }}-${{ inputs.prerelease }}" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
fi
|
||||
- uses: actions/checkout@v3
|
||||
- name: Cache pip
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ~/.cache/pip
|
||||
key: '${{ runner.os }}-pip-${{ hashFiles(''**/requirements.txt'') }}'
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pip-
|
||||
- name: Cache PlatformIO
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ~/.platformio
|
||||
key: '${{ runner.os }}-${{ hashFiles(''**/lockfiles'') }}'
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.10'
|
||||
- name: Install PlatformIO
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install --upgrade platformio
|
||||
- name: Install libs
|
||||
run: |
|
||||
cd SmartEVSE-3
|
||||
pio lib install
|
||||
- name: Build normal version
|
||||
env:
|
||||
super_secret: ${{ secrets.SECRET_RSA_KEY }}
|
||||
run: |
|
||||
PLATFORMIO_BUILD_FLAGS='-DVERSION=\"v${{ steps.version.outputs.version }}\" -DDBG=0' pio run -d SmartEVSE-3/
|
||||
# Create a temporary file
|
||||
secret_file=$(mktemp)
|
||||
# Write the secret to the temporary file, because passing it as command line argument might reveal it for users using ps -a
|
||||
echo "$super_secret" > "$secret_file"
|
||||
# Create signature file
|
||||
openssl dgst -sign "$secret_file" -keyform PEM -sha256 -out firmware.sign -binary ./SmartEVSE-3/.pio/build/release/firmware.bin
|
||||
# throw it all in one file
|
||||
cat firmware.sign ./SmartEVSE-3/.pio/build/release/firmware.bin > ./SmartEVSE-3/.pio/build/release/firmware.signed.bin
|
||||
# Remove the temporary file
|
||||
rm -f "$secret_file"
|
||||
- name: Upload firmware.bin
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: dists_zip
|
||||
path: ./SmartEVSE-3/.pio/build/release/*.bin
|
||||
retention-days: 10
|
||||
- name: Upload HowToFlash.txt
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: dists_zip
|
||||
path: ./SmartEVSE-3/HowToFlash.txt
|
||||
retention-days: 10
|
||||
- name: Build debug version
|
||||
env:
|
||||
super_secret: ${{ secrets.SECRET_RSA_KEY }}
|
||||
run: |
|
||||
PLATFORMIO_BUILD_FLAGS='-DVERSION=\"v${{ steps.version.outputs.version }}\" -DDBG=1' pio run -d SmartEVSE-3/
|
||||
# Create a temporary file
|
||||
secret_file=$(mktemp)
|
||||
# Write the secret to the temporary file, because passing it as command line argument might reveal it for users using ps -a
|
||||
echo "$super_secret" > "$secret_file"
|
||||
# Create signature file
|
||||
openssl dgst -sign "$secret_file" -keyform PEM -sha256 -out firmware.sign -binary ./SmartEVSE-3/.pio/build/release/firmware.bin
|
||||
# throw it all in one file
|
||||
cat firmware.sign ./SmartEVSE-3/.pio/build/release/firmware.bin > ./SmartEVSE-3/.pio/build/release/firmware.signed.bin
|
||||
# Remove the temporary file
|
||||
rm -f "$secret_file"
|
||||
mv ./SmartEVSE-3/.pio/build/release/firmware.bin ./SmartEVSE-3/.pio/build/release/firmware.debug.bin
|
||||
mv ./SmartEVSE-3/.pio/build/release/firmware.signed.bin ./SmartEVSE-3/.pio/build/release/firmware.debug.signed.bin
|
||||
- name: Upload Artifact debug firmware
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: dists_zip
|
||||
path: ./SmartEVSE-3/.pio/build/release/*.bin
|
||||
retention-days: 10
|
||||
|
||||
outputs:
|
||||
artifact: dists_zip
|
||||
62
SmartEVSE-3/.github/workflows/pio-release.yaml
vendored
@@ -1,62 +0,0 @@
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v*'
|
||||
|
||||
name: Create Release
|
||||
jobs:
|
||||
version:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- id: get_version
|
||||
uses: battila7/get-version-action@v2
|
||||
outputs:
|
||||
major: ${{ steps.get_version.outputs.major }}
|
||||
minor: ${{ steps.get_version.outputs.minor }}
|
||||
patch: ${{ steps.get_version.outputs.patch }}
|
||||
prerelease: ${{ steps.get_version.outputs.prerelease }}
|
||||
build:
|
||||
needs: version
|
||||
uses: ./.github/workflows/pio-build.yaml
|
||||
with:
|
||||
major: ${{ needs.version.outputs.major }}
|
||||
minor: ${{ needs.version.outputs.minor }}
|
||||
patch: ${{ needs.version.outputs.patch }}
|
||||
prerelease: ${{ needs.version.outputs.prerelease }}
|
||||
secrets: inherit
|
||||
release:
|
||||
permissions: write-all
|
||||
needs: build
|
||||
name: Upload Release Asset
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Get current tag
|
||||
id: tag
|
||||
run: echo "tag=${GITHUB_REF##*/}" >> $GITHUB_OUTPUT
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/download-artifact@v3
|
||||
id: download
|
||||
with:
|
||||
path: dist
|
||||
- name: Create Release
|
||||
id: create_release
|
||||
uses: actions/create-release@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
tag_name: ${{ github.ref }}
|
||||
release_name: Release ${{ github.ref }}
|
||||
draft: false
|
||||
prerelease: true
|
||||
- name: Zip
|
||||
run: zip -j ${{ steps.tag.outputs.tag }}-dist.zip ./dist/${{ needs.build.outputs.artifact }}/*
|
||||
- name: Upload Release Asset
|
||||
id: upload-release-asset
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
asset_path: ./${{ steps.tag.outputs.tag }}-dist.zip
|
||||
asset_name: ${{ steps.tag.outputs.tag }}-dist.zip
|
||||
asset_content_type: application/zip
|
||||
11
SmartEVSE-3/.gitignore
vendored
@@ -1,11 +0,0 @@
|
||||
.pio
|
||||
.log
|
||||
sdkconfig.*
|
||||
*/.vscode/.browse.c_cpp.db*
|
||||
*/.vscode/c_cpp_properties.json
|
||||
*/.vscode/launch.json
|
||||
*/.vscode/ipch
|
||||
|
||||
.DS_Store
|
||||
*/.DS_Store
|
||||
.idea
|
||||
@@ -1,21 +0,0 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021 SmartEVSE
|
||||
|
||||
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.
|
||||
@@ -1,65 +0,0 @@
|
||||
SmartEVSE v3
|
||||
=========
|
||||
|
||||
Smart Electric Vehicle Charge Controller
|
||||
|
||||

|
||||
|
||||
# What is it?
|
||||
|
||||
It's an open source EVSE (Electric Vehicle Supply Equipment). It supports 1-3 phase charging, fixed charging cable or charging socket. Locking actuator support (5 different types). And it can directly drive a mains contactor for supplying power to the EV. It features a display from which all module parameters can be configured.<br>
|
||||
Up to 8 modules can be connected together to charge up to eight EV's from one mains connection without overloading it.<br>
|
||||
The mains connection can be monitored by the (optional) sensorbox or a modbus kWh meter. This allows smart charging.
|
||||
Communication between the SmartEVSE(s) / Sensorbox or kWh meters is done over RS485(modbus).
|
||||
|
||||
|
||||
# Features
|
||||
|
||||
- Fits into a standard DIN rail enclosure.
|
||||
- Measures the current consumption of other appliances, and automatically lowers or increases the charging current to the EV. (sensorbox required)
|
||||
- The load balancing feature let's you connect up to 8 SmartEVSE's to one mains supply.
|
||||
- Two switched 230VAC outputs, for contactors.
|
||||
- Powered RS485 communication bus for sensorbox / Modbus kWh Meters.
|
||||
- Can be used with fixed cable, or socket and charging cable.
|
||||
- Automatically selects current capacity of the connected cable (13/16/32A)
|
||||
- Locking actuator support, locks the charging cable in the socket.
|
||||
- RFID reader support, restrict the use of the charging station to max 20 RFID cards.
|
||||
- An optional modbus kWh meter will measure power and charged energy, and display this on the LCD.
|
||||
- Built-in temperature sensor.
|
||||
- RGB led output for status information while charging.
|
||||
- All module parameters can be configured using the display and buttons.
|
||||
- WiFi status page.
|
||||
- Firmware upgradable through USB-C port or through the built in webserver.
|
||||
- REST API for communication with external software (e.g. HomeAssistant)
|
||||
- MQTT API
|
||||
- Rudimentary support for home batteries
|
||||
- Supporting delayed charging
|
||||
|
||||
# Connecting the SmartESVE to WiFi
|
||||
|
||||
In order to connect the SmartEVSE to your local WiFi network, a temporarily hotspot is created by the SmartESVE to which you can connect using a phone/tablet.
|
||||
Here you can then scan for your local WiFi, and enter your Wifi network password. Then the SmartEVSE will use this information to connect to your local Wifi network.
|
||||
|
||||
The steps to connect the SmartEVSE to Wifi are as follows:
|
||||
- in the SmartEVSE menu, go to the option WIFI, then select SetupWiFi.
|
||||
- after 10 seconds, a hotspot/access point SmartESVE-xxxx is started. (xxxx is the serial nr of your SmartEVSE)
|
||||
- Using a phone or tablet, connect to this access point.
|
||||
- You will be asked to enter a password. This password is visible on the top right corner of the SmartEVSE's display. (PW:xxxxxxxx)
|
||||
- Once connected you will be able to select your local WiFi network, and enter the password for this network.
|
||||
- click SAVE, the SmartEVSE will try to connect to your local WiFi network.
|
||||
- Enter the menu of your SmartEVSE again. The SmartEVSE should now display the IP address on the top row of the display.
|
||||
- use this IP address in a webbrowser to connect to the webserver of the controller. You can also use http://smartevse-xxxx.local (replace xxxx with the serial nr of your controller)
|
||||
|
||||
# Updating Firmware
|
||||
|
||||
Connect the SmartEVSE controller to your WiFi network (using the menu of the SmartEVSE), and then browse to http://IPaddress/update where IPaddress is the IP which is shown on the display.
|
||||
You can also use http://smartevse-xxxx.local/update where xxxx is the serial nr of your controller.<br>
|
||||
Here you can select the firmware.bin and press update to update the firmware.<br>
|
||||
It's also possible to update the spiffs partition from this page. (for v3.0.1 this is not needed)<br>
|
||||
After updating the firmware, you can access the status page again using the normal url: http://smartevse-xxxx.local (replace xxxx with the serial nr of your controller)<br>
|
||||
|
||||
# Documentation
|
||||
|
||||
[Hardware installation](docs/installation.md)<br>
|
||||
[Configuration](docs/configuration.md)<br>
|
||||
[Operation](docs/operation.md)<br>
|
||||
5
SmartEVSE-3/SmartEVSE-3/.gitignore
vendored
@@ -1,5 +0,0 @@
|
||||
.pio
|
||||
.vscode/.browse.c_cpp.db*
|
||||
.vscode/c_cpp_properties.json
|
||||
.vscode/launch.json
|
||||
.vscode/ipch
|
||||
@@ -1,3 +0,0 @@
|
||||
cmake_minimum_required(VERSION 3.16.0)
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(SmartEVSE32)
|
||||
@@ -1,5 +0,0 @@
|
||||
-surf to http://your-smartevse/update
|
||||
-select the firmware.bin from this archive, OR if you want the debug version (via telnet over your wifi),
|
||||
rename firmware.debug.bin to firmware.bin and select that. YOU CANNOT FLASH A FILE WITH ANOTHER NAME!
|
||||
-if you get FAIL, check your wifi connection and try again;
|
||||
-after OK, wait 10-30 seconds and your new firmware including the webserver should be online!
|
||||
@@ -1,13 +0,0 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIB4DCCAYWgAwIBAgIUZNoNpf/c2H+t54PnIoe4PgiahV0wCgYIKoZIzj0EAwIw
|
||||
RTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGElu
|
||||
dGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yNDA1MDQwNjEyMDNaFw0yNDA2MDMw
|
||||
NjEyMDNaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYD
|
||||
VQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwWTATBgcqhkjOPQIBBggqhkjO
|
||||
PQMBBwNCAAQLQqPNIgyYn4J8SE3LRBVhkDyLAT6cumGL73QGB+OzEsj6cv2B0kGs
|
||||
jpvUrsclwmCVLVo0T6FxHR4Pw/Fy3qgvo1MwUTAdBgNVHQ4EFgQUpqjPZrPqhA23
|
||||
ghR5bdmj0gceVRgwHwYDVR0jBBgwFoAUpqjPZrPqhA23ghR5bdmj0gceVRgwDwYD
|
||||
VR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNJADBGAiEA2IitVasCjmRsbz9ZcG4U
|
||||
jn3tudAVCXs9Fet7AVLNvDkCIQDJGRWuWmctvD/7DBPUra822bIlWhwFKljWpNTW
|
||||
wZAdFg==
|
||||
-----END CERTIFICATE-----
|
||||
|
Before Width: | Height: | Size: 12 KiB |
@@ -1,5 +0,0 @@
|
||||
-----BEGIN EC PRIVATE KEY-----
|
||||
MHcCAQEEICtA0BJEavg6pVMl6lcPOA5I7qqm4W/CoFbJSP/osM3poAoGCCqGSM49
|
||||
AwEHoUQDQgAEC0KjzSIMmJ+CfEhNy0QVYZA8iwE+nLphi+90BgfjsxLI+nL9gdJB
|
||||
rI6b1K7HJcJglS1aNE+hcR0eD8Pxct6oLw==
|
||||
-----END EC PRIVATE KEY-----
|
||||
@@ -1,14 +0,0 @@
|
||||
-----BEGIN PUBLIC KEY-----
|
||||
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAtjEWhkfKPAUrtX1GueYq
|
||||
JmDp4qSHBG6ndwikAHvteKgWQABDpwaemZdxh7xVCuEdjEkaecinNOZ0LpSCF3QO
|
||||
qflnXkvpYVxjdTpKBxo7vP5QEa3I6keJfwpoMzGuT8XOK7id6FHJhtYEXcaufALi
|
||||
mR/NXT11ikHLtluATymPdoSscMiwry0qX03yIek91lDypBNl5uvD2jxn9smlijfq
|
||||
9j0lwtpLBWJPU8vsU0uzuj7Qq5pWZFKsjiNWfbvNJXuLsupOazf5sh0yeQzL1CBL
|
||||
RUsBlYVoChTmSOyvi6kO5vW/6GLOafJF0FTdOQ+Gf3/IB6M1ErSxlqxQhHq0pb7Y
|
||||
INl7+aFCmlRjyLlMjb8xdtuedlZKv8mLd37AyPAihrq9gV74xq6c7w2y+h9213p8
|
||||
jgcmo/HvOlGaXEIOVCUu102teOckXjTni2yhEtFISCaWuaIdb5P9e0uBIy1e+Bi6
|
||||
/7A3aut5MQP07DO99BFETXyFF6EixhTF8fpwVZ5vXeIDvKKEDUGuzAziUEGIZpic
|
||||
UQ2fmTzIaTBbNlCMeTQFIpZCosM947aGKNBp672wdf996SRwg9E2VWzW2Z1UuwWV
|
||||
BPVQkHb1Hsy7C9fg5JcLKB9zEfyUH0Tm9Iur1vsuA5++JNl2+T55192wqyF0R9sb
|
||||
YtSTUJNSiSwqWt1m0FLOJD0CAwEAAQ==
|
||||
-----END PUBLIC KEY-----
|
||||
@@ -1,173 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>SmartEVSEv3</title>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<style>
|
||||
#container { margin-right: auto; margin-left: auto; max-width: 900px; }
|
||||
#info { background: #e0f0f0; border-radius: .5em; padding: 2em; }
|
||||
#wrapper { margin-top: 1em; }
|
||||
</style>
|
||||
<script>
|
||||
let OWNER_FACT="SmartEVSE";
|
||||
let REPO_FACT="SmartEVSE-3";
|
||||
let OWNER_COMM="dingo35";
|
||||
let REPO_COMM="SmartEVSE-3.5";
|
||||
function update_comm() {
|
||||
window.location.href = "/autoupdate?url=community&debug=0";
|
||||
}
|
||||
function update_fact() {
|
||||
window.location.href = "/autoupdate?url=factory&debug=0";
|
||||
}
|
||||
function update_comm_debug() {
|
||||
window.location.href = "/autoupdate?url=community&debug=1";
|
||||
}
|
||||
function update_fact_debug() {
|
||||
window.location.href = "/autoupdate?url=factory&debug=1";
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body onload="loadData()">
|
||||
<div id="container">
|
||||
<div id="info">
|
||||
Current version: <span id="version"></span>
|
||||
=======================================================
|
||||
DOWNLOADING
|
||||
<br><br>
|
||||
<table style='text-align: left'>
|
||||
<tr>
|
||||
<th>Distribution:</th>
|
||||
<th>Status:</th>
|
||||
<th>Github repo:</th>
|
||||
<th>Latest version:</th>
|
||||
<th>Flash:</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Factory</td>
|
||||
<td>stable</td>
|
||||
<td><a href="https://github.com/"
|
||||
onclick="location.href=this.href + OWNER_FACT + '/' + REPO_FACT + '/releases';return false;"><script>document.write(OWNER_FACT)</script></a></td>
|
||||
<td><div id="latest_fact"></div></td>
|
||||
<td><button onclick="update_fact()" style="width: 100px; display:inline-block;">Standard</button>
|
||||
<td><button onclick="update_fact_debug()" style="width: 100px; display:inline-block;">Debug</button>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Community          </td>
|
||||
<td>bleeding edge       </td>
|
||||
<td><a href="https://github.com/"
|
||||
onclick="location.href=this.href + OWNER_COMM + '/' + REPO_COMM + '/releases';return false;"><script>document.write(OWNER_COMM)</script></a></td>
|
||||
<td><div id="latest_comm"></div></td>
|
||||
<td><button onclick="update_comm()" style="width: 100px; display:inline-block;">Standard</button>
|
||||
<td><button onclick="update_comm_debug()" style="width: 100px; display:inline-block;">Debug</button>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
=======================================================
|
||||
<br>
|
||||
FLASHING
|
||||
<br><br>
|
||||
Flash one of:<ul>
|
||||
<li>firmware.bin or firmware.signed.bin (to update the firmware);</li>
|
||||
<li>firmware.debug.bin or firmware.debug.signed.bin (if you want to telnet to your SmartEVSE to see debug messages);</li>
|
||||
<li>rfix.txt (if you want to bulk upload allowed NFC tags for the RFID reader);</li>
|
||||
</ul>
|
||||
You should only flash files with those exact names.<br>No need to flash spiffs.bin for versions 3.6.0-RC1 and newer!<br>No need to rename firmware.debug.bin anymore for versions 3.6.0-RC2 and newer!<br>Signed firmware is verified to be original and can be handled by versions 3.6.2 and newer.
|
||||
</div>
|
||||
<div id="wrapper">
|
||||
<input type="file" id="el1" style="display: none"/>
|
||||
<button id="el2">choose file...</button>
|
||||
<div id="el3"></div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
<script type="module">
|
||||
// Octokit.js
|
||||
// https://github.com/octokit/core.js#readme
|
||||
import { Octokit } from "https://esm.sh/@octokit/core";
|
||||
window.loadData=loadData;
|
||||
|
||||
function loadData() {
|
||||
document.getElementById("version").innerHTML = sessionStorage.getItem("version");
|
||||
getLatestVersion(OWNER_FACT, REPO_FACT, 'latest_fact');
|
||||
getLatestVersion(OWNER_COMM, REPO_COMM, 'latest_comm');
|
||||
}
|
||||
|
||||
async function getLatestVersion(owner, repo, element) {
|
||||
const octokit = new Octokit({
|
||||
})
|
||||
|
||||
try {
|
||||
const result = await octokit.request('GET /repos/{owner}/{repo}/releases/latest', {
|
||||
owner: owner,
|
||||
repo: repo,
|
||||
headers: {
|
||||
'X-GitHub-Api-Version': '2022-11-28'
|
||||
}
|
||||
})
|
||||
|
||||
//asset_id=result.data.assets.filter(function(entry){ return entry.name==="firmware.signed.bin";})[0].id;
|
||||
//console.log(asset_id);
|
||||
//console.log(JSON.stringify(result.data.assets));
|
||||
document.getElementById(element).innerHTML = result.data.tag_name;
|
||||
} catch (error) {
|
||||
console.error(error.message);
|
||||
}
|
||||
}
|
||||
|
||||
// Copyright (c) 2020 Cesanta Software Limited
|
||||
// All rights reserved
|
||||
|
||||
// Helper function to display upload status
|
||||
var setStatus = function(text) {
|
||||
document.getElementById('el3').innerText = text;
|
||||
};
|
||||
|
||||
// When user clicks on a button, trigger file selection dialog
|
||||
var button = document.getElementById('el2');
|
||||
button.onclick = function(ev) {
|
||||
input.click();
|
||||
};
|
||||
|
||||
// Send a large blob of data chunk by chunk
|
||||
var sendFileData = function(name, data, chunkSize) {
|
||||
var sendChunk = function(offset) {
|
||||
var chunk = data.subarray(offset, offset + chunkSize) || '';
|
||||
var opts = {method: 'POST', body: chunk};
|
||||
var url = '/update?offset=' + offset + '&file=' + encodeURIComponent(name) + '&size=' + data.length;
|
||||
var ok;
|
||||
if (offset + chunk.length == data.length) {
|
||||
setStatus('Upload of ' + name + ' finished, you can close this page.');
|
||||
window.location.href = "/";
|
||||
}
|
||||
else
|
||||
setStatus('Uploading ' + name + ', bytes ' + offset + '..' + (offset + chunk.length) + ' of ' + data.length);
|
||||
fetch(url, opts)
|
||||
.then(function(res) {
|
||||
if (res.ok && chunk.length > 0) sendChunk(offset + chunk.length);
|
||||
ok = res.ok;
|
||||
return res.text();
|
||||
})
|
||||
.then(function(text) {
|
||||
if (!ok) setStatus('Error: ' + text);
|
||||
});
|
||||
};
|
||||
sendChunk(0);
|
||||
};
|
||||
|
||||
// If user selected a file, read it into memory and trigger sendFileData()
|
||||
var input = document.getElementById('el1');
|
||||
input.onchange = function(ev) {
|
||||
if (!ev.target.files[0]) return;
|
||||
var f = ev.target.files[0], r = new FileReader();
|
||||
r.readAsArrayBuffer(f);
|
||||
r.onload = function() {
|
||||
ev.target.value = '';
|
||||
sendFileData(f.name, new Uint8Array(r.result), 20480);
|
||||
};
|
||||
};
|
||||
</script>
|
||||
</html>
|
||||
@@ -1,43 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>SmartEVSEv3</title>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<script>
|
||||
function fetchProgress() {
|
||||
fetch('/autoupdate_progress')
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
// code to handle the response
|
||||
var mainContainer = document.getElementById("myData");
|
||||
var div = document.createElement("div");
|
||||
mainContainer.innerHTML = '';
|
||||
if (data.progress == -1) { //sucess
|
||||
div.innerHTML = 'Firmware update succesfully completed, will reboot.';
|
||||
}
|
||||
else {
|
||||
if (data.progress == -2) { //fail
|
||||
div.innerHTML = 'ERROR: Firmware update fail; rebooting.';
|
||||
} else {
|
||||
div.innerHTML = 'Firmware update progress: ' + data.progress + '/' + data.size;
|
||||
}
|
||||
}
|
||||
mainContainer.appendChild(div);
|
||||
})
|
||||
.catch(err => {
|
||||
console.error('Error: ', err)
|
||||
})
|
||||
}
|
||||
window.addEventListener('load', function () {
|
||||
// Your document is loaded.
|
||||
var fetchInterval = 1000; // 1 seconds.
|
||||
// Invoke the request every 1 seconds.
|
||||
setInterval(fetchProgress, fetchInterval);
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="myData"></div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
; Project: Smart EVSE
|
||||
;
|
||||
;
|
||||
;
|
||||
; Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
; of this software and associated documentation files (the "Software"), to deal
|
||||
; in the Software without restriction, including without limitation the rights
|
||||
; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
; copies of the Software, and to permit persons to whom the Software is
|
||||
; furnished to do so, subject to the following conditions:
|
||||
;
|
||||
; The above copyright notice and this permission notice shall be included in
|
||||
; all copies or substantial portions of the Software.
|
||||
;
|
||||
; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
; THE SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __ONEWIRE_H
|
||||
#define __ONEWIRE_H
|
||||
|
||||
extern Preferences preferences;
|
||||
|
||||
void ReadRFIDlist(void);
|
||||
void DeleteAllRFID(void);
|
||||
void CheckRFID(void);
|
||||
void LoadandStoreRFID(unsigned int *RFIDparam);
|
||||
|
||||
#endif // #ifndef __ONEWIRE_H
|
||||
@@ -1,39 +0,0 @@
|
||||
|
||||
This directory is intended for project header files.
|
||||
|
||||
A header file is a file containing C declarations and macro definitions
|
||||
to be shared between several project source files. You request the use of a
|
||||
header file in your project source file (C, C++, etc) located in `src` folder
|
||||
by including it, with the C preprocessing directive `#include'.
|
||||
|
||||
```src/main.c
|
||||
|
||||
#include "header.h"
|
||||
|
||||
int main (void)
|
||||
{
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Including a header file produces the same results as copying the header file
|
||||
into each source file that needs it. Such copying would be time-consuming
|
||||
and error-prone. With a header file, the related declarations appear
|
||||
in only one place. If they need to be changed, they can be changed in one
|
||||
place, and programs that include the header file will automatically use the
|
||||
new version when next recompiled. The header file eliminates the labor of
|
||||
finding and changing all the copies as well as the risk that a failure to
|
||||
find one copy will result in inconsistencies within a program.
|
||||
|
||||
In C, the usual convention is to give header files names that end with `.h'.
|
||||
It is most portable to use only letters, digits, dashes, and underscores in
|
||||
header file names, and at most one dot.
|
||||
|
||||
Read more about using header files in official GCC documentation:
|
||||
|
||||
* Include Syntax
|
||||
* Include Operation
|
||||
* Once-Only Headers
|
||||
* Computed Includes
|
||||
|
||||
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html
|
||||
@@ -1,592 +0,0 @@
|
||||
/*
|
||||
; Project: Smart EVSE v3
|
||||
;
|
||||
;
|
||||
; Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
; of this software and associated documentation files (the "Software"), to deal
|
||||
; in the Software without restriction, including without limitation the rights
|
||||
; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
; copies of the Software, and to permit persons to whom the Software is
|
||||
; furnished to do so, subject to the following conditions:
|
||||
;
|
||||
; The above copyright notice and this permission notice shall be included in
|
||||
; all copies or substantial portions of the Software.
|
||||
;
|
||||
; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
; THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __EVSE_MAIN
|
||||
|
||||
#define __EVSE_MAIN
|
||||
|
||||
#ifndef DBG
|
||||
//the wifi-debugger is available by telnetting to your SmartEVSE device
|
||||
#define DBG 0 //comment or set to 0 for production release, 0 = no debug 1 = debug over telnet, 2 = debug over usb serial
|
||||
#endif
|
||||
|
||||
#ifndef FAKE_RFID
|
||||
//set FAKE_RFID to 1 to emulate an rfid reader with rfid of card = 123456
|
||||
//showing the rfid card is simulated by executing http://smartevse-xxx.lan/debug?showrfid=1
|
||||
//don't forget to first store the card before it can activate charging
|
||||
#define FAKE_RFID 0
|
||||
#endif
|
||||
|
||||
#ifndef AUTOMATED_TESTING
|
||||
//set AUTOMATED_TESTING to 1 to make hardware-related paramaters like MaxCurrent and MaxCircuit updatable via REST API
|
||||
//e.g. by executing curl -X POST http://smartevse-xxx.lan/automated_testing?maxcurrent=100
|
||||
#define AUTOMATED_TESTING 0
|
||||
#endif
|
||||
|
||||
#ifndef FAKE_SUNNY_DAY
|
||||
//set this to 1 to emulate a sunny day where your solar charger is injecting current in the grid:
|
||||
#define FAKE_SUNNY_DAY 0
|
||||
//disclaimer: might not work for CT1 calibration/uncalibration stuff, since I can't test that
|
||||
//the number of Amperes you want to have fake injected into Lx
|
||||
#endif
|
||||
|
||||
#if FAKE_SUNNY_DAY
|
||||
#define INJECT_CURRENT_L1 10
|
||||
#define INJECT_CURRENT_L2 0
|
||||
#define INJECT_CURRENT_L3 0
|
||||
#endif
|
||||
|
||||
#ifndef MQTT
|
||||
#define MQTT 1 // Uncomment or set to 0 to disable MQTT support in code
|
||||
#endif
|
||||
|
||||
#ifndef MODEM
|
||||
//the wifi-debugger is available by telnetting to your SmartEVSE device
|
||||
#define MODEM 0 //0 = no modem 1 = modem
|
||||
#endif
|
||||
|
||||
#ifndef VERSION
|
||||
//please note that this version will only be displayed with the correct time/date if the program is recompiled
|
||||
//so the webserver will show correct version if evse.cpp is recompiled
|
||||
//the lcd display will show correct version if glcd.cpp is recompiled
|
||||
#define VERSION (__TIME__ " @" __DATE__)
|
||||
#endif
|
||||
|
||||
|
||||
#if DBG == 0
|
||||
//used to steer RemoteDebug
|
||||
#define DEBUG_DISABLED 1
|
||||
#define _LOG_W( ... ) //dummy
|
||||
#define _LOG_I( ... ) //dummy
|
||||
#define _LOG_D( ... ) //dummy
|
||||
#define _LOG_V( ... ) //dummy
|
||||
#define _LOG_A( ... ) //dummy
|
||||
#define _LOG_W_NO_FUNC( ... ) //dummy
|
||||
#define _LOG_I_NO_FUNC( ... ) //dummy
|
||||
#define _LOG_D_NO_FUNC( ... ) //dummy
|
||||
#define _LOG_V_NO_FUNC( ... ) //dummy
|
||||
#define _LOG_A_NO_FUNC( ... ) //dummy
|
||||
#endif
|
||||
|
||||
#if DBG == 1
|
||||
#define _LOG_A(fmt, ...) if (Debug.isActive(Debug.ANY)) Debug.printf("(%s)(C%d) " fmt, __func__, xPortGetCoreID(), ##__VA_ARGS__) //Always = Errors!!!
|
||||
#define _LOG_P(fmt, ...) if (Debug.isActive(Debug.PROFILER)) Debug.printf("(%s)(C%d) " fmt, __func__, xPortGetCoreID(), ##__VA_ARGS__)
|
||||
#define _LOG_V(fmt, ...) if (Debug.isActive(Debug.VERBOSE)) Debug.printf("(%s)(C%d) " fmt, __func__, xPortGetCoreID(), ##__VA_ARGS__) //Verbose
|
||||
#define _LOG_D(fmt, ...) if (Debug.isActive(Debug.DEBUG)) Debug.printf("(%s)(C%d) " fmt, __func__, xPortGetCoreID(), ##__VA_ARGS__) //Debug
|
||||
#define _LOG_I(fmt, ...) if (Debug.isActive(Debug.INFO)) Debug.printf("(%s)(C%d) " fmt, __func__, xPortGetCoreID(), ##__VA_ARGS__) //Info
|
||||
#define _LOG_W(fmt, ...) if (Debug.isActive(Debug.WARNING)) Debug.printf("(%s)(C%d) " fmt, __func__, xPortGetCoreID(), ##__VA_ARGS__) //Warning
|
||||
#define _LOG_E(fmt, ...) if (Debug.isActive(Debug.ERROR)) Debug.printf("(%s)(C%d) " fmt, __func__, xPortGetCoreID(), ##__VA_ARGS__) //Error not used!
|
||||
#define _LOG_A_NO_FUNC(fmt, ...) if (Debug.isActive(Debug.ANY)) Debug.printf(fmt, ##__VA_ARGS__)
|
||||
#define _LOG_P_NO_FUNC(fmt, ...) if (Debug.isActive(Debug.PROFILER)) Debug.printf(fmt, ##__VA_ARGS__)
|
||||
#define _LOG_V_NO_FUNC(fmt, ...) if (Debug.isActive(Debug.VERBOSE)) Debug.printf(fmt, ##__VA_ARGS__)
|
||||
#define _LOG_D_NO_FUNC(fmt, ...) if (Debug.isActive(Debug.DEBUG)) Debug.printf(fmt, ##__VA_ARGS__)
|
||||
#define _LOG_I_NO_FUNC(fmt, ...) if (Debug.isActive(Debug.INFO)) Debug.printf(fmt, ##__VA_ARGS__)
|
||||
#define _LOG_W_NO_FUNC(fmt, ...) if (Debug.isActive(Debug.WARNING)) Debug.printf(fmt, ##__VA_ARGS__)
|
||||
#define _LOG_E_NO_FUNC(fmt, ...) if (Debug.isActive(Debug.ERROR)) Debug.printf(fmt, ##__VA_ARGS__)
|
||||
#include "RemoteDebug.h" //https://github.com/JoaoLopesF/RemoteDebug
|
||||
extern RemoteDebug Debug;
|
||||
#endif
|
||||
|
||||
#if DBG == 2
|
||||
#define DEBUG_DISABLED 1
|
||||
#define _LOG_W( ... ) log_w ( __VA_ARGS__ )
|
||||
#define _LOG_I( ... ) log_i ( __VA_ARGS__ )
|
||||
#define _LOG_D( ... ) log_d ( __VA_ARGS__ )
|
||||
#define _LOG_V( ... ) log_v ( __VA_ARGS__ )
|
||||
#define _LOG_A( ... ) log_n ( __VA_ARGS__ )
|
||||
#define _LOG_W_NO_FUNC( ... ) Serial.printf ( __VA_ARGS__ )
|
||||
#define _LOG_I_NO_FUNC( ... ) Serial.printf ( __VA_ARGS__ )
|
||||
#define _LOG_D_NO_FUNC( ... ) Serial.printf ( __VA_ARGS__ )
|
||||
#define _LOG_V_NO_FUNC( ... ) Serial.printf ( __VA_ARGS__ )
|
||||
#define _LOG_A_NO_FUNC( ... ) Serial.printf ( __VA_ARGS__ )
|
||||
#endif
|
||||
|
||||
// Pin definitions left side ESP32
|
||||
#define PIN_TEMP 36
|
||||
#define PIN_CP_IN 39
|
||||
#define PIN_PP_IN 34
|
||||
#define PIN_LOCK_IN 35
|
||||
#define PIN_SSR 32
|
||||
#define PIN_LCD_SDO_B3 33 // = SPI_MOSI
|
||||
#define PIN_LCD_A0_B2 25
|
||||
#define PIN_LCD_CLK 26 // = SPI_SCK
|
||||
#define PIN_SSR2 27
|
||||
#define PIN_LCD_LED 14
|
||||
#define PIN_LEDB 12
|
||||
#define PIN_RCM_FAULT 13
|
||||
|
||||
// Pin definitions right side ESP32
|
||||
#define PIN_RS485_RX 23
|
||||
#define PIN_RS485_DIR 22
|
||||
//#define PIN_RXD
|
||||
//#define PIN_TXD
|
||||
#define PIN_RS485_TX 21
|
||||
#define PIN_CP_OUT 19
|
||||
#define PIN_ACTB 18
|
||||
#define PIN_LCD_RST 5
|
||||
#define PIN_ACTA 17
|
||||
#define PIN_SW_IN 16
|
||||
#define PIN_LEDG 4
|
||||
#define PIN_IO0_B1 0
|
||||
#define PIN_LEDR 2
|
||||
#define PIN_CPOFF 15
|
||||
|
||||
#define SPI_MOSI 33 // SPI connections to LCD
|
||||
#define SPI_MISO -1
|
||||
#define SPI_SCK 26
|
||||
#define SPI_SS -1
|
||||
|
||||
#define CP_CHANNEL 0
|
||||
#define RED_CHANNEL 2 // PWM channel 2 (0 and 1 are used by CP signal)
|
||||
#define GREEN_CHANNEL 3
|
||||
#define BLUE_CHANNEL 4
|
||||
#define LCD_CHANNEL 5 // LED Backlight LCD
|
||||
|
||||
#define PWM_5 50 // 5% of PWM
|
||||
#define PWM_95 950 // 95% of PWM
|
||||
#define PWM_100 1000 // 100% of PWM
|
||||
|
||||
#define ICAL 1024 // Irms Calibration value (for Current transformers)
|
||||
#define MAX_MAINS 25 // max Current the Mains connection can supply
|
||||
#define MAX_SUMMAINS 600 // only used for capacity rate limiting, max current over the sum of all phases
|
||||
#define MAX_CURRENT 13 // max charging Current for the EV
|
||||
#ifndef MIN_CURRENT
|
||||
#define MIN_CURRENT 6 // minimum Current the EV will accept
|
||||
#endif
|
||||
#define MODE 0 // Normal EVSE mode
|
||||
#define LOCK 0 // No Cable lock
|
||||
#define MAX_CIRCUIT 16 // Max current of the EVSE circuit breaker
|
||||
#define CONFIG 0 // Configuration: 0= TYPE 2 socket, 1= Fixed Cable
|
||||
#define LOADBL 0 // Load Balancing disabled
|
||||
#define SWITCH 0 // 0= Charge on plugin, 1= (Push)Button on IO2 is used to Start/Stop charging.
|
||||
#define RC_MON 0 // Residual Current Monitoring on IO3. Disabled=0, RCM14=1
|
||||
#define CHARGEDELAY 60 // Seconds to wait after overcurrent, before trying again
|
||||
#define BACKLIGHT 120 // Seconds delay for the LCD backlight to turn off.
|
||||
#define RFIDLOCKTIME 60 // Seconds delay for the EVSE to lock again (RFIDreader = EnableOne)
|
||||
#define START_CURRENT 4 // Start charging when surplus current on sum of all phases exceeds 4A (Solar)
|
||||
#define STOP_TIME 10 // Stop charging after 10 minutes at MIN charge current (Solar)
|
||||
#define IMPORT_CURRENT 0 // Allow the use of grid power when solar charging (Amps)
|
||||
#define MAINS_METER 0 // Mains Meter, 0=Disabled, 1= Sensorbox, 2=Phoenix, 3= Finder, 4= Eastron, 5=Custom
|
||||
#define GRID 0 // Grid, 0= 4-Wire CW, 1= 4-Wire CCW, 2= 3-Wire CW, 3= 3-Wire CCW
|
||||
#define MAINS_METER_ADDRESS 10
|
||||
#define PV_METER 0
|
||||
#define PV_METER_ADDRESS 11
|
||||
#define EV_METER 0
|
||||
#define EV_METER_ADDRESS 12
|
||||
#define MIN_METER_ADDRESS 10
|
||||
#define MAX_METER_ADDRESS 247
|
||||
#define EMCUSTOM_ENDIANESS 0
|
||||
#define EMCUSTOM_DATATYPE 0
|
||||
#define EMCUSTOM_FUNCTION 4
|
||||
#define EMCUSTOM_UREGISTER 0
|
||||
#define EMCUSTOM_UDIVISOR 8
|
||||
#define EMCUSTOM_IREGISTER 0
|
||||
#define EMCUSTOM_IDIVISOR 8
|
||||
#define EMCUSTOM_PREGISTER 0
|
||||
#define EMCUSTOM_PDIVISOR 8
|
||||
#define EMCUSTOM_EREGISTER 0
|
||||
#define EMCUSTOM_EDIVISOR 8
|
||||
#define RFID_READER 0
|
||||
#define ACCESS_BIT 1
|
||||
#define WIFI_MODE 0
|
||||
#define AP_PASSWORD "00000000"
|
||||
#define CARD_OFFSET 0
|
||||
#define INITIALIZED 0
|
||||
#define ENABLE_C2 ALWAYS_ON
|
||||
#define MAX_TEMPERATURE 65
|
||||
#define DELAYEDSTARTTIME 0 // The default StartTime for delayed charged, 0 = not delaying
|
||||
#define DELAYEDSTOPTIME 0 // The default StopTime for delayed charged, 0 = not stopping
|
||||
#define SOLARSTARTTIME 40 // Seconds to keep chargecurrent at 6A
|
||||
#define PUBLIC_KEY "5c7a848c3445793002487608a65fa259cefb16790f7c2f4a1d10af702393f7db\0";
|
||||
|
||||
|
||||
// Mode settings
|
||||
#define MODE_NORMAL 0
|
||||
#define MODE_SMART 1
|
||||
#define MODE_SOLAR 2
|
||||
|
||||
#define MODBUS_BAUDRATE 9600
|
||||
#define MODBUS_TIMEOUT 4
|
||||
#define ACK_TIMEOUT 1000 // 1000ms timeout
|
||||
#define NR_EVSES 8
|
||||
#define BROADCAST_ADR 0x09
|
||||
#define COMM_TIMEOUT 11 // Timeout for MainsMeter
|
||||
#define COMM_EVTIMEOUT 8*NR_EVSES // Timeout for EV Energy Meters
|
||||
|
||||
#define STATE_A 0 // A Vehicle not connected
|
||||
#define STATE_B 1 // B Vehicle connected / not ready to accept energy
|
||||
#define STATE_C 2 // C Vehicle connected / ready to accept energy / ventilation not required
|
||||
#define STATE_D 3 // D Vehicle connected / ready to accept energy / ventilation required (not implemented)
|
||||
#define STATE_COMM_B 4 // E State change request A->B (set by node)
|
||||
#define STATE_COMM_B_OK 5 // F State change A->B OK (set by master)
|
||||
#define STATE_COMM_C 6 // G State change request B->C (set by node)
|
||||
#define STATE_COMM_C_OK 7 // H State change B->C OK (set by master)
|
||||
#define STATE_ACTSTART 8 // I Activation mode in progress
|
||||
#define STATE_B1 9 // J Vehicle connected / EVSE not ready to deliver energy: no PWM signal
|
||||
#define STATE_C1 10 // K Vehicle charging / EVSE not ready to deliver energy: no PWM signal (temp state when stopping charge from EVSE)
|
||||
#define STATE_MODEM_REQUEST 11 // L Vehicle connected / requesting ISO15118 communication, 0% duty
|
||||
#define STATE_MODEM_WAIT 12 // M Vehicle connected / requesting ISO15118 communication, 5% duty
|
||||
#define STATE_MODEM_DONE 13 // Modem communication succesful, SoCs extracted. Here, re-plug vehicle
|
||||
#define STATE_MODEM_DENIED 14 // Modem access denied based on EVCCID, re-plug vehicle and try again
|
||||
|
||||
#define NOSTATE 255
|
||||
|
||||
#define PILOT_12V 1 // State A - vehicle disconnected
|
||||
#define PILOT_9V 2 // State B - vehicle connected
|
||||
#define PILOT_6V 3 // State C - EV charge
|
||||
#define PILOT_3V 4
|
||||
#define PILOT_DIODE 5
|
||||
#define PILOT_NOK 0
|
||||
|
||||
|
||||
#define NO_ERROR 0
|
||||
#define LESS_6A 1
|
||||
#define CT_NOCOMM 2
|
||||
#define TEMP_HIGH 4
|
||||
#define EV_NOCOMM 8
|
||||
#define RCM_TRIPPED 16 // RCM tripped. >6mA DC residual current detected.
|
||||
#define NO_SUN 32
|
||||
#define Test_IO 64
|
||||
#define BL_FLASH 128
|
||||
|
||||
#define STATE_A_LED_BRIGHTNESS 40
|
||||
#define STATE_B_LED_BRIGHTNESS 255
|
||||
#define ERROR_LED_BRIGHTNESS 255
|
||||
#define WAITING_LED_BRIGHTNESS 255
|
||||
#define LCD_BRIGHTNESS 255
|
||||
|
||||
|
||||
#define CP_ON digitalWrite(PIN_CPOFF, LOW);
|
||||
#define CP_OFF digitalWrite(PIN_CPOFF, HIGH);
|
||||
|
||||
#define PILOT_CONNECTED digitalWrite(PIN_CPOFF, LOW);
|
||||
#define PILOT_DISCONNECTED digitalWrite(PIN_CPOFF, HIGH);
|
||||
|
||||
#define CONTACTOR1_ON _LOG_A("Switching Contactor1 ON.\n"); digitalWrite(PIN_SSR, HIGH);
|
||||
#define CONTACTOR1_OFF _LOG_A("Switching Contactor1 OFF.\n"); digitalWrite(PIN_SSR, LOW);
|
||||
|
||||
#define CONTACTOR2_ON _LOG_A("Switching Contactor2 ON.\n"); digitalWrite(PIN_SSR2, HIGH);
|
||||
#define CONTACTOR2_OFF _LOG_A("Switching Contactor2 OFF.\n"); digitalWrite(PIN_SSR2, LOW);
|
||||
|
||||
#define BACKLIGHT_ON digitalWrite(PIN_LCD_LED, HIGH);
|
||||
#define BACKLIGHT_OFF digitalWrite(PIN_LCD_LED, LOW);
|
||||
|
||||
#define ACTUATOR_LOCK { _LOG_A("Locking Actuator.\n"); digitalWrite(PIN_ACTB, HIGH); digitalWrite(PIN_ACTA, LOW); }
|
||||
#define ACTUATOR_UNLOCK { _LOG_A("Unlocking Actuator.\n"); digitalWrite(PIN_ACTB, LOW); digitalWrite(PIN_ACTA, HIGH); }
|
||||
#define ACTUATOR_OFF { digitalWrite(PIN_ACTB, HIGH); digitalWrite(PIN_ACTA, HIGH); }
|
||||
|
||||
#define ONEWIRE_LOW { digitalWrite(PIN_SW_IN, LOW); pinMode(PIN_SW_IN, OUTPUT); } // SW set to 0, set to output (driven low)
|
||||
#define ONEWIRE_HIGH { digitalWrite(PIN_SW_IN, HIGH); pinMode(PIN_SW_IN, OUTPUT); } // SW set to 1, set to output (driven high)
|
||||
#define ONEWIRE_FLOATHIGH pinMode(PIN_SW_IN, INPUT_PULLUP ); // SW input (floating high)
|
||||
|
||||
#define RCMFAULT digitalRead(PIN_RCM_FAULT)
|
||||
#define FREE(x) free(x); x = NULL;
|
||||
#define FW_DOWNLOAD_PATH "http://smartevse-3.s3.eu-west-2.amazonaws.com"
|
||||
|
||||
#define MODBUS_INVALID 0
|
||||
#define MODBUS_OK 1
|
||||
#define MODBUS_REQUEST 2
|
||||
#define MODBUS_RESPONSE 3
|
||||
#define MODBUS_EXCEPTION 4
|
||||
|
||||
#define MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS 0x02
|
||||
#define MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE 0x03
|
||||
|
||||
#define MODBUS_EVSE_STATUS_START 0x0000
|
||||
#define MODBUS_EVSE_STATUS_COUNT 12
|
||||
#define MODBUS_EVSE_CONFIG_START 0x0100
|
||||
#define MODBUS_EVSE_CONFIG_COUNT 10
|
||||
#define MODBUS_SYS_CONFIG_START 0x0200
|
||||
#define MODBUS_SYS_CONFIG_COUNT 26
|
||||
|
||||
#define MODBUS_MAX_REGISTER_READ MODBUS_SYS_CONFIG_COUNT
|
||||
#define MODBUS_BUFFER_SIZE MODBUS_MAX_REGISTER_READ * 2 + 10
|
||||
|
||||
// EVSE status
|
||||
#define STATUS_STATE 64 // 0x0000: State
|
||||
#define STATUS_ERROR 65 // 0x0001: Error
|
||||
#define STATUS_CURRENT 66 // 0x0002: Charging current (A * 10)
|
||||
#define STATUS_MODE 67 // 0x0003: EVSE Mode
|
||||
#define STATUS_SOLAR_TIMER 68 // 0x0004: Solar Timer
|
||||
#define STATUS_ACCESS 69 // 0x0005: Access bit
|
||||
#define STATUS_CONFIG_CHANGED 70 // 0x0006: Configuration changed
|
||||
#define STATUS_MAX 71 // 0x0007: Maximum charging current (RO)
|
||||
#define STATUS_PHASE_COUNT 72 // 0x0008: Number of used phases (RO) (ToDo)
|
||||
#define STATUS_REAL_CURRENT 73 // 0x0009: Real charging current (RO) (ToDo)
|
||||
#define STATUS_TEMP 74 // 0x000A: Temperature (RO)
|
||||
#define STATUS_SERIAL 75 // 0x000B: Serial number (RO)
|
||||
|
||||
// Node specific configuration
|
||||
#define MENU_ENTER 1
|
||||
#define MENU_CONFIG 2 // 0x0100: Configuration
|
||||
#define MENU_LOCK 3 // 0x0101: Cable lock
|
||||
#define MENU_MIN 4 // 0x0102: MIN Charge Current the EV will accept
|
||||
#define MENU_MAX 5 // 0x0103: MAX Charge Current for this EVSE
|
||||
#define MENU_LOADBL 6 // 0x0104: Load Balance
|
||||
#define MENU_SWITCH 7 // 0x0105: External Start/Stop button
|
||||
#define MENU_RCMON 8 // 0x0106: Residual Current Monitor
|
||||
#define MENU_RFIDREADER 9 // 0x0107: Use RFID reader
|
||||
#define MENU_EVMETER 10 // 0x0108: Type of EV electric meter
|
||||
#define MENU_EVMETERADDRESS 11 // 0x0109: Address of EV electric meter
|
||||
|
||||
// System configuration (same on all SmartEVSE in a LoadBalancing setup)
|
||||
#define MENU_MODE 12 // 0x0200: EVSE mode
|
||||
#define MENU_CIRCUIT 13 // 0x0201: EVSE Circuit max Current
|
||||
#define MENU_GRID 14 // 0x0202: Grid type to which the Sensorbox is connected
|
||||
#define MENU_CAL 15 // 0x0203: CT calibration value
|
||||
#define MENU_MAINS 16 // 0x0204: Max Mains Current
|
||||
#define MENU_START 17 // 0x0205: Surplus energy start Current
|
||||
#define MENU_STOP 18 // 0x0206: Stop solar charging at 6A after this time
|
||||
#define MENU_IMPORT 19 // 0x0207: Allow grid power when solar charging
|
||||
#define MENU_MAINSMETER 20 // 0x0208: Type of Mains electric meter
|
||||
#define MENU_MAINSMETERADDRESS 21 // 0x0209: Address of Mains electric meter
|
||||
#define MENU_EMCUSTOM_ENDIANESS 22 // 0x020D: Byte order of custom electric meter
|
||||
#define MENU_EMCUSTOM_DATATYPE 23 // 0x020E: Data type of custom electric meter
|
||||
#define MENU_EMCUSTOM_FUNCTION 24 // 0x020F: Modbus Function (3/4) of custom electric meter
|
||||
#define MENU_EMCUSTOM_UREGISTER 25 // 0x0210: Register for Voltage (V) of custom electric meter
|
||||
#define MENU_EMCUSTOM_UDIVISOR 26 // 0x0211: Divisor for Voltage (V) of custom electric meter (10^x)
|
||||
#define MENU_EMCUSTOM_IREGISTER 27 // 0x0212: Register for Current (A) of custom electric meter
|
||||
#define MENU_EMCUSTOM_IDIVISOR 28 // 0x0213: Divisor for Current (A) of custom electric meter (10^x)
|
||||
#define MENU_EMCUSTOM_PREGISTER 29 // 0x0214: Register for Power (W) of custom electric meter
|
||||
#define MENU_EMCUSTOM_PDIVISOR 30 // 0x0215: Divisor for Power (W) of custom electric meter (10^x)
|
||||
#define MENU_EMCUSTOM_EREGISTER 31 // 0x0216: Register for Energy (kWh) of custom electric meter
|
||||
#define MENU_EMCUSTOM_EDIVISOR 32 // 0x0217: Divisor for Energy (kWh) of custom electric meter (10^x)
|
||||
#define MENU_EMCUSTOM_READMAX 33 // 0x0218: Maximum register read (ToDo)
|
||||
#define MENU_WIFI 34 // 0x0219: WiFi mode
|
||||
#define MENU_C2 35
|
||||
#define MENU_MAX_TEMP 36
|
||||
#define MENU_SUMMAINS 37
|
||||
#define MENU_OFF 38 // so access bit is reset and charging stops when pressing < button 2 seconds
|
||||
#define MENU_ON 39 // so access bit is set and charging starts when pressing > button 2 seconds
|
||||
#define MENU_EXIT 40
|
||||
|
||||
#define MENU_STATE 50
|
||||
|
||||
#define _RSTB_0 digitalWrite(PIN_LCD_RST, LOW);
|
||||
#define _RSTB_1 digitalWrite(PIN_LCD_RST, HIGH);
|
||||
#define _A0_0 digitalWrite(PIN_LCD_A0_B2, LOW);
|
||||
#define _A0_1 digitalWrite(PIN_LCD_A0_B2, HIGH);
|
||||
|
||||
#define EM_SENSORBOX 1 // Mains meter types
|
||||
#define EM_PHOENIX_CONTACT 2
|
||||
#define EM_FINDER_7E 3
|
||||
#define EM_EASTRON3P 4
|
||||
#define EM_EASTRON3P_INV 5
|
||||
#define EM_ABB 6
|
||||
#define EM_SOLAREDGE 7
|
||||
#define EM_WAGO 8
|
||||
#define EM_API 9
|
||||
#define EM_EASTRON1P 10
|
||||
#define EM_FINDER_7M 11
|
||||
#define EM_UNUSED_SLOT1 12
|
||||
#define EM_UNUSED_SLOT2 13
|
||||
#define EM_UNUSED_SLOT3 14
|
||||
#define EM_UNUSED_SLOT4 15
|
||||
#define EM_CUSTOM 16
|
||||
|
||||
#define ENDIANESS_LBF_LWF 0
|
||||
#define ENDIANESS_LBF_HWF 1
|
||||
#define ENDIANESS_HBF_LWF 2
|
||||
#define ENDIANESS_HBF_HWF 3
|
||||
|
||||
#define OWNER_FACT "SmartEVSE"
|
||||
#define REPO_FACT "SmartEVSE-3"
|
||||
#define OWNER_COMM "dingo35"
|
||||
#define REPO_COMM "SmartEVSE-3.5"
|
||||
|
||||
typedef enum mb_datatype {
|
||||
MB_DATATYPE_INT32 = 0,
|
||||
MB_DATATYPE_FLOAT32 = 1,
|
||||
MB_DATATYPE_INT16 = 2,
|
||||
MB_DATATYPE_MAX,
|
||||
} MBDataType;
|
||||
|
||||
|
||||
extern portMUX_TYPE rtc_spinlock; //TODO: Will be placed in the appropriate position after the rtc module is finished.
|
||||
|
||||
#define RTC_ENTER_CRITICAL() portENTER_CRITICAL(&rtc_spinlock)
|
||||
#define RTC_EXIT_CRITICAL() portEXIT_CRITICAL(&rtc_spinlock)
|
||||
|
||||
|
||||
extern String APpassword;
|
||||
extern struct tm timeinfo;
|
||||
|
||||
|
||||
extern uint16_t ICal; // CT calibration value
|
||||
extern uint8_t Mode; // EVSE mode
|
||||
extern uint8_t LoadBl; // Load Balance Setting (Disable, Master or Node)
|
||||
extern uint8_t Grid;
|
||||
extern uint8_t MainsMeterAddress;
|
||||
extern uint8_t EVMeter; // Type of EV electric meter (0: Disabled / Constants EM_*)
|
||||
extern uint8_t EVMeterAddress;
|
||||
#if FAKE_RFID
|
||||
extern uint8_t Show_RFID;
|
||||
#endif
|
||||
|
||||
extern int16_t Irms[3]; // Momentary current per Phase (Amps *10) (23 = 2.3A)
|
||||
extern int16_t Irms_EV[3]; // Momentary current per Phase (Amps *10) (23 = 2.3A)
|
||||
|
||||
extern uint8_t State;
|
||||
extern uint8_t ErrorFlags;
|
||||
extern uint8_t NextState;
|
||||
|
||||
extern int16_t Isum;
|
||||
extern uint16_t Balanced[NR_EVSES]; // Amps value per EVSE
|
||||
|
||||
extern uint8_t LCDTimer;
|
||||
extern uint16_t BacklightTimer; // remaining seconds the LCD backlight is active
|
||||
extern uint8_t ButtonState; // Holds latest push Buttons state (LSB 2:0)
|
||||
extern uint8_t OldButtonState; // Holds previous push Buttons state (LSB 2:0)
|
||||
extern uint8_t LCDNav;
|
||||
extern uint8_t LCDupdate;
|
||||
extern uint8_t SubMenu;
|
||||
extern uint32_t ScrollTimer;
|
||||
extern uint8_t ChargeDelay; // Delays charging in seconds.
|
||||
extern uint8_t TestState;
|
||||
extern uint8_t Access_bit;
|
||||
extern uint16_t CardOffset;
|
||||
|
||||
extern uint8_t GridActive; // When the CT's are used on Sensorbox2, it enables the GRID menu option.
|
||||
extern uint8_t CalActive; // When the CT's are used on Sensorbox(1.5 or 2), it enables the CAL menu option.
|
||||
extern uint16_t Iuncal;
|
||||
extern uint16_t SolarStopTimer;
|
||||
extern int32_t EnergyCharged;
|
||||
extern int32_t EnergyCapacity;
|
||||
extern int16_t PowerMeasured;
|
||||
extern uint8_t RFIDstatus;
|
||||
extern bool LocalTimeSet;
|
||||
extern uint32_t serialnr;
|
||||
|
||||
extern uint8_t MenuItems[MENU_EXIT];
|
||||
|
||||
enum EnableC2_t { NOT_PRESENT, ALWAYS_OFF, SOLAR_OFF, ALWAYS_ON, AUTO };
|
||||
enum Modem_t { NOTPRESENT, EXPERIMENT };
|
||||
const static char StrEnableC2[][12] = { "Not present", "Always Off", "Solar Off", "Always On", "Auto" };
|
||||
const static char StrModem[][12] = { "Not present", "Experiment" };
|
||||
enum Single_Phase_t { FALSE, GOING_TO_SWITCH, AFTER_SWITCH };
|
||||
extern Single_Phase_t Switching_To_Single_Phase;
|
||||
extern uint8_t Nr_Of_Phases_Charging;
|
||||
|
||||
const struct {
|
||||
char LCD[10];
|
||||
char Desc[52];
|
||||
uint16_t Min;
|
||||
uint16_t Max;
|
||||
uint16_t Default;
|
||||
} MenuStr[MENU_EXIT + 1] = {
|
||||
{"", "Not in menu", 0, 0, 0},
|
||||
{"", "Hold 2 sec", 0, 0, 0},
|
||||
|
||||
// Node specific configuration
|
||||
/* LCD, Desc, Min, Max, Default */
|
||||
{"CONFIG", "Fixed Cable or Type 2 Socket", 0, 1, CONFIG},
|
||||
{"LOCK", "Cable locking actuator type", 0, 2, LOCK},
|
||||
{"MIN", "MIN Charge Current the EV will accept (per phase)", MIN_CURRENT, 16, MIN_CURRENT},
|
||||
{"MAX", "MAX Charge Current for this EVSE (per phase)", 6, 80, MAX_CURRENT},
|
||||
{"PWR SHARE", "Share Power between multiple SmartEVSEs (2-8)", 0, NR_EVSES, LOADBL},
|
||||
{"SWITCH", "Switch function control on pin SW", 0, 4, SWITCH},
|
||||
{"RCMON", "Residual Current Monitor on pin RCM", 0, 1, RC_MON},
|
||||
{"RFID", "RFID reader, learn/remove cards", 0, 5, RFID_READER},
|
||||
{"EV METER","Type of EV electric meter", 0, EM_CUSTOM, EV_METER},
|
||||
{"EV ADDR", "Address of EV electric meter", MIN_METER_ADDRESS, MAX_METER_ADDRESS, EV_METER_ADDRESS},
|
||||
|
||||
// System configuration
|
||||
/* LCD, Desc, Min, Max, Default */
|
||||
{"MODE", "Normal, Smart or Solar EVSE mode", 0, 2, MODE},
|
||||
{"CIRCUIT", "EVSE Circuit max Current", 10, 160, MAX_CIRCUIT},
|
||||
{"GRID", "Grid type to which the Sensorbox is connected", 0, 1, GRID},
|
||||
{"CAL", "Calibrate CT1 (CT2+3 will also change)", (unsigned int) (ICAL * 0.3), (unsigned int) (ICAL * 2.0), ICAL}, // valid range is 0.3 - 2.0 times measured value
|
||||
{"MAINS", "Max MAINS Current (per phase)", 10, 200, MAX_MAINS},
|
||||
{"START", "Surplus energy start Current (sum of phases)", 0, 48, START_CURRENT},
|
||||
{"STOP", "Stop solar charging at 6A after this time", 0, 60, STOP_TIME},
|
||||
{"IMPORT", "Allow grid power when solar charging (sum of phase)",0, 48, IMPORT_CURRENT},
|
||||
{"MAINS MET","Type of mains electric meter", 0, EM_CUSTOM, MAINS_METER},
|
||||
{"MAINS ADR","Address of mains electric meter", MIN_METER_ADDRESS, MAX_METER_ADDRESS, MAINS_METER_ADDRESS},
|
||||
{"BYTE ORD","Byte order of custom electric meter", 0, 3, EMCUSTOM_ENDIANESS},
|
||||
{"DATA TYPE","Data type of custom electric meter", 0, MB_DATATYPE_MAX - 1, EMCUSTOM_DATATYPE},
|
||||
{"FUNCTION","Modbus Function of custom electric meter", 3, 4, EMCUSTOM_FUNCTION},
|
||||
{"VOL REGI","Register for Voltage (V) of custom electric meter", 0, 65530, EMCUSTOM_UREGISTER},
|
||||
{"VOL DIVI","Divisor for Voltage (V) of custom electric meter", 0, 7, EMCUSTOM_UDIVISOR},
|
||||
{"CUR REGI","Register for Current (A) of custom electric meter", 0, 65530, EMCUSTOM_IREGISTER},
|
||||
{"CUR DIVI","Divisor for Current (A) of custom electric meter", 0, 7, EMCUSTOM_IDIVISOR},
|
||||
{"POW REGI","Register for Power (W) of custom electric meter", 0, 65534, EMCUSTOM_PREGISTER},
|
||||
{"POW DIVI","Divisor for Power (W) of custom electric meter", 0, 7, EMCUSTOM_PDIVISOR},
|
||||
{"ENE REGI","Register for Energy (kWh) of custom electric meter", 0, 65534, EMCUSTOM_EREGISTER},
|
||||
{"ENE DIVI","Divisor for Energy (kWh) of custom electric meter", 0, 7, EMCUSTOM_EDIVISOR},
|
||||
{"READ MAX","Max register read at once of custom electric meter", 3, 255, 3},
|
||||
{"WIFI", "Connect to WiFi access point", 0, 2, WIFI_MODE},
|
||||
{"CONTACT 2","Contactor2 (C2) behaviour", 0, sizeof(StrEnableC2) / sizeof(StrEnableC2[0])-1, ENABLE_C2},
|
||||
{"MAX TEMP","Maximum temperature for the EVSE module", 40, 75, MAX_TEMPERATURE},
|
||||
{"SUM MAINS","Capacity Rate limit on sum of MAINS Current (A)", 10, 600, MAX_SUMMAINS},
|
||||
{"", "Hold 2 sec to stop charging", 0, 0, 0},
|
||||
{"", "Hold 2 sec to start charging", 0, 0, 0},
|
||||
|
||||
{"EXIT", "EXIT", 0, 0, 0}
|
||||
};
|
||||
|
||||
|
||||
struct EMstruct {
|
||||
uint8_t Desc[10];
|
||||
uint8_t Endianness; // 0: low byte first, low word first, 1: low byte first, high word first, 2: high byte first, low word first, 3: high byte first, high word first
|
||||
uint8_t Function; // 3: holding registers, 4: input registers
|
||||
MBDataType DataType; // How data is represented on this Modbus meter
|
||||
uint16_t URegister; // Single phase voltage (V)
|
||||
int8_t UDivisor; // 10^x
|
||||
uint16_t IRegister; // Single phase current (A)
|
||||
int8_t IDivisor; // 10^x
|
||||
uint16_t PRegister; // Total power (W) -- only used for EV/PV meter momentary power
|
||||
int8_t PDivisor; // 10^x
|
||||
uint16_t ERegister; // Total imported energy (kWh); equals total energy if meter doesnt support exported energy
|
||||
int8_t EDivisor; // 10^x
|
||||
uint16_t ERegister_Exp; // Total exported energy (kWh)
|
||||
int8_t EDivisor_Exp; // 10^x
|
||||
};
|
||||
|
||||
extern struct EMstruct EMConfig[EM_CUSTOM + 1];
|
||||
|
||||
struct DelayedTimeStruct {
|
||||
uint32_t epoch2; // in case of Delayed Charging the StartTime in epoch2; if zero we are NOT Delayed Charging
|
||||
// epoch2 is the number of seconds since 1/1/2023 00:00 UTC, which equals epoch 1672531200
|
||||
// we avoid using epoch so we don't need expensive 64bits arithmetics with difftime
|
||||
// and we can store dates until 7/2/2159
|
||||
int32_t diff; // StartTime minus current time in seconds
|
||||
};
|
||||
|
||||
#define EPOCH2_OFFSET 1672531200
|
||||
|
||||
extern struct DelayedTimeStruct DelayedStartTime;
|
||||
|
||||
void CheckAPpassword(void);
|
||||
void read_settings();
|
||||
void write_settings(void);
|
||||
void setSolarStopTimer(uint16_t Timer);
|
||||
void setState(uint8_t NewState);
|
||||
void setAccess(bool Access);
|
||||
void SetCPDuty(uint32_t DutyCycle);
|
||||
uint8_t setItemValue(uint8_t nav, uint16_t val);
|
||||
uint16_t getItemValue(uint8_t nav);
|
||||
void ConfigureModbusMode(uint8_t newmode);
|
||||
|
||||
void handleWIFImode(void);
|
||||
|
||||
#endif
|
||||
@@ -1,42 +0,0 @@
|
||||
/*
|
||||
; Project: Smart EVSE
|
||||
;
|
||||
;
|
||||
;
|
||||
; Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
; of this software and associated documentation files (the "Software"), to deal
|
||||
; in the Software without restriction, including without limitation the rights
|
||||
; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
; copies of the Software, and to permit persons to whom the Software is
|
||||
; furnished to do so, subject to the following conditions:
|
||||
;
|
||||
; The above copyright notice and this permission notice shall be included in
|
||||
; all copies or substantial portions of the Software.
|
||||
;
|
||||
; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
; THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __GLCD_H
|
||||
#define __GLCD_H
|
||||
|
||||
#define GLCD_MERGE 0b00001000
|
||||
#define GLCD_HIRES_FONT
|
||||
#define GLCD_FULL_CHARSET
|
||||
#define GLCD_ALIGN_LEFT 0
|
||||
#define GLCD_ALIGN_CENTER 1
|
||||
#define GLCD_ALIGN_RIGHT 2
|
||||
|
||||
extern void GLCDHelp(void);
|
||||
extern void GLCD(void);
|
||||
extern void GLCDMenu(unsigned char Buttons);
|
||||
extern void GLCD_init(void);
|
||||
extern void GLCD_version(void);
|
||||
|
||||
|
||||
#endif // #ifndef __GLCD_H
|
||||
@@ -1,71 +0,0 @@
|
||||
/*
|
||||
; Project: Smart EVSE
|
||||
;
|
||||
;
|
||||
;
|
||||
; Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
; of this software and associated documentation files (the "Software"), to deal
|
||||
; in the Software without restriction, including without limitation the rights
|
||||
; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
; copies of the Software, and to permit persons to whom the Software is
|
||||
; furnished to do so, subject to the following conditions:
|
||||
;
|
||||
; The above copyright notice and this permission notice shall be included in
|
||||
; all copies or substantial portions of the Software.
|
||||
;
|
||||
; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
; THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __EVSE_MODBUS
|
||||
#define __EVSE_MODBUS
|
||||
|
||||
struct ModBus {
|
||||
uint8_t Address;
|
||||
uint8_t Function;
|
||||
uint16_t Register;
|
||||
uint16_t RegisterCount;
|
||||
uint16_t Value;
|
||||
uint8_t *Data;
|
||||
uint8_t DataLength;
|
||||
uint8_t Type;
|
||||
uint8_t RequestAddress;
|
||||
uint8_t RequestFunction;
|
||||
uint16_t RequestRegister;
|
||||
uint8_t Exception;
|
||||
};
|
||||
|
||||
// definition of MBserver / MBclient class is done in evse.cpp
|
||||
extern ModbusServerRTU MBserver;
|
||||
extern ModbusClientRTU MBclient;
|
||||
|
||||
void RS485SendBuf(uint8_t *buffer, uint8_t len);
|
||||
uint8_t mapModbusRegister2ItemID();
|
||||
|
||||
// ########################### Modbus main functions ###########################
|
||||
|
||||
void ModbusReadInputRequest(uint8_t address, uint8_t function, uint16_t reg, uint16_t quantity);
|
||||
void ModbusReadInputResponse(uint8_t address, uint8_t function, uint16_t *values, uint8_t count);
|
||||
void ModbusWriteSingleRequest(uint8_t address, uint16_t reg, uint16_t value);
|
||||
void ModbusWriteMultipleRequest(uint8_t address, uint16_t reg, uint16_t *values, uint8_t count);
|
||||
void ModbusException(uint8_t address, uint8_t function, uint8_t exception);
|
||||
void ModbusDecode(uint8_t *buf, uint8_t len);
|
||||
|
||||
// ########################### EVSE modbus functions ###########################
|
||||
|
||||
signed int receiveMeasurement(uint8_t *buf, uint8_t pos, uint8_t Endianness, MBDataType dataType, signed char Divisor);
|
||||
void requestMeasurement(uint8_t Meter, uint8_t Address, uint16_t Register, uint8_t Count);
|
||||
void requestCurrentMeasurement(uint8_t Meter, uint8_t Address);
|
||||
uint8_t receiveCurrentMeasurement(uint8_t *buf, uint8_t Meter, signed int *var);
|
||||
|
||||
//void ReadItemValueResponse(void);
|
||||
//void WriteItemValueResponse(void);
|
||||
//void WriteMultipleItemValueResponse(void);
|
||||
|
||||
|
||||
#endif
|
||||
@@ -1,40 +0,0 @@
|
||||
/*
|
||||
; Project: Smart EVSE
|
||||
;
|
||||
;
|
||||
;
|
||||
; 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.
|
||||
*/
|
||||
|
||||
// This is a guard condition so that contents of this file are not included
|
||||
// more than once.
|
||||
#ifndef UTILS_H
|
||||
#define UTILS_H
|
||||
|
||||
extern unsigned long pow_10[10];
|
||||
|
||||
uint32_t MacId();
|
||||
unsigned char crc8(unsigned char *buf, unsigned char len);
|
||||
unsigned int crc16(unsigned char *buf, unsigned char len);
|
||||
void sprintfl(char *str, const char *Format, signed long Value, unsigned char Divisor, unsigned char Decimal);
|
||||
unsigned char triwave8(unsigned char in);
|
||||
unsigned char scale8(unsigned char i, unsigned char scale);
|
||||
unsigned char ease8InOutQuad(unsigned char i);
|
||||
|
||||
#endif /* UTILS_H */
|
||||
@@ -1,45 +0,0 @@
|
||||
This directory is intended for project specific (private) libraries.
|
||||
PlatformIO will compile them to static libraries and link into executable file.
|
||||
|
||||
The source code of each library should be placed in a an own separate directory
|
||||
("lib/your_library_name/[here are source files]").
|
||||
|
||||
For example, see a structure of the following two libraries `Foo` and `Bar`:
|
||||
|
||||
|--lib
|
||||
| |
|
||||
| |--Bar
|
||||
| | |--docs
|
||||
| | |--examples
|
||||
| | |--src
|
||||
| | |- Bar.c
|
||||
| | |- Bar.h
|
||||
| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
|
||||
| |
|
||||
| |--Foo
|
||||
| | |- Foo.c
|
||||
| | |- Foo.h
|
||||
| |
|
||||
| |- README --> THIS FILE
|
||||
|
|
||||
|- platformio.ini
|
||||
|--src
|
||||
|- main.c
|
||||
|
||||
and a contents of `src/main.c`:
|
||||
```
|
||||
#include <Foo.h>
|
||||
#include <Bar.h>
|
||||
|
||||
int main (void)
|
||||
{
|
||||
...
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
PlatformIO Library Dependency Finder will find automatically dependent
|
||||
libraries scanning project source files.
|
||||
|
||||
More information about PlatformIO Library Dependency Finder
|
||||
- https://docs.platformio.org/page/librarymanager/ldf.html
|
||||
@@ -1,29 +0,0 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
1.
|
||||
2.
|
||||
3.
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**Arduino Information:**
|
||||
- OS: [e.g. Windows, MacOS, Linux]
|
||||
- IDE [e.g. Arduino IDE, Eclipse, VSCode]
|
||||
- IDE Version [e.g. 1.8.6]
|
||||
- Board [e.g ESP32]
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
||||
@@ -1,17 +0,0 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**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.
|
||||
@@ -1 +0,0 @@
|
||||
.DS_Store
|
||||
@@ -1,21 +0,0 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018 Joao Lopes
|
||||
|
||||
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.
|
||||
@@ -1,737 +0,0 @@
|
||||
# RemoteDebug Library
|
||||
|
||||
A library for Arduino to debug projects over WiFi, with web app or telnet client,
|
||||
with Print commands like Serial Monitor.
|
||||
|
||||

|
||||
|
||||
[](https://www.ardu-badge.com/RemoteDebug)
|
||||
[](#releases)
|
||||
[](https://www.codacy.com/app/JoaoLopesF/RemoteDebug?utm_source=github.com&utm_medium=referral&utm_content=JoaoLopesF/RemoteDebug&utm_campaign=Badge_Grade)
|
||||
[](https://github.com/arduino)
|
||||
[](https://github.com/JoaoLopesF/RemoteDebug/blob/master/LICENSE.txt)
|
||||
[](#github)
|
||||
[](http://github.com/JoaoLopesF/RemoteDebug/issues)
|
||||
[](http://github.com/JoaoLopesF/RemoteDebug)
|
||||
<!--  -->
|
||||
|
||||

|
||||
|
||||
## A library to remotely debug over a WiFi connection by telnet or web browser
|
||||
|
||||
### RemoteDebug setup a TCP/IP server, that you connect to debugging, as an alternative to the serial connection
|
||||
|
||||
## Contents
|
||||
|
||||
- [About](#about)
|
||||
- [How it looks](#how-it-looks)
|
||||
- [Github](#github)
|
||||
- [News](#news)
|
||||
- [Benefits](#benefits)
|
||||
- [HTML5 web app](#web-app)
|
||||
- [Telnet client](#telnet)
|
||||
- [Wishlist](#wishlist)
|
||||
- [Install](#install)
|
||||
- [Using](#usage)
|
||||
- [Known issues](#known-issues)
|
||||
- [Releases](#releases)
|
||||
- [Thanks](#thanks)
|
||||
|
||||
## About
|
||||
|
||||
By default the Arduino only has as debug possibility via the Serial port.
|
||||
This has a few disadvantages:
|
||||
|
||||
- requires a physical cable to the Arduino device (if the device is far away or in a remote location this is not easy)
|
||||
- debugging multiple Arduinos at the same time requires many serial ports and a lot of cables
|
||||
|
||||
With the ESP8266 (NodeMCU) or ESP32 we now have network connectivity (WiFi) which can be used for streaming debugging information in real-time.
|
||||
|
||||
This library is good for IoT projects, home automation, mobile robots (can debug it in moviment with a cable ?) or
|
||||
another WiFi projects.
|
||||
|
||||
In fact, this library was born of a need to debug an IoT project of home automation.
|
||||
In this project there was a central module and three auxiliary modules,
|
||||
and these were far from each other. One was hard to reach, under the roof of the house.
|
||||
To debug this project, accompanying the exchange of messages in realtime,
|
||||
is impossible to do with traditional way, by USB cable.
|
||||
|
||||
The MiP_ESP8266_Library and my ESP32 WiFi robot are example of projects that uses __RemoteDebug__.
|
||||
See it in: [MiP_ESP8266_Library](https://github.com/Tiogaplanet/MiP_ESP8266_Library) and [ESPlorer_v1](https://github.com/JoaoLopesF/ESPlorer_v1)
|
||||
|
||||
__RemoteDebug__ is improved with client buffering (is last send is <= 10ms),
|
||||
to avoid mysterious delays of WiFi networking on ESP32 and ESP8266 boards
|
||||
|
||||
Note: If your project not use WiFi, you can use my another library,
|
||||
the __[SerialDebug](https://github.com/JoaoLopesF/SerialDebug)__ library,
|
||||
this library works with any Arduino board.
|
||||
|
||||
Note II: __RemoteDebug__ library is now only to Espressif boards, as ESP32 and ESP8266,
|
||||
If need for another WiFi boards, please add an issue about this
|
||||
and we will see if it is possible made the port for your board.
|
||||
|
||||
## How it looks
|
||||
|
||||
Image: In RemoteDebugApp (web app)
|
||||
|
||||

|
||||
|
||||
Image: In telnet client
|
||||
|
||||

|
||||
|
||||
Youtube (RemoteDebug v2):
|
||||
|
||||
[](https://youtu.be/T4nxdsFUGgg)
|
||||
|
||||
Youtube (3 telnet connections with RemoteDebug) v1:
|
||||
|
||||
[](http://www.youtube.com/watch?v=lOo-MAD8gPo)
|
||||
|
||||
## Github
|
||||
|
||||
Contribute to this library development by creating an account on GitHub.
|
||||
|
||||
Please give a star, if you find this library useful,
|
||||
this help an another people, discover it too.
|
||||
|
||||
Please add an issue for problems or suggestion.
|
||||
|
||||
## News
|
||||
|
||||
- RemoteDebugApp Beta
|
||||
|
||||
- Now have another repository, [RemoteDebugApp](https://github.com/JoaoLopesF/RemoteDebugApp)
|
||||
It is for local copy of web app in internet.
|
||||
It is updated with lastest version of web app,
|
||||
after it is publised in web server: [http://joaolopesf.net/remotedebugapp](http://joaolopesf.net/remotedebugapp/).
|
||||
Download it, for use when internet is offline.
|
||||
As it is a local copy, the app will check for new versions periodically.
|
||||
|
||||
- An HTML5 web app to use for debugging in web browser, instead telnet client,
|
||||
that uses web socket to comunicate.
|
||||
|
||||
- Now RemoteDebug v3 have a web socket server too,
|
||||
to support the RemoteDebugApp connection.
|
||||
|
||||
- RemoteDebugApp is in beta,
|
||||
if you have any problems or suggestions, please add issue about this.
|
||||
|
||||
- The telnet connection remains, to any want this,
|
||||
or to internet offline uses.
|
||||
|
||||
- Version 2.1.1
|
||||
|
||||
- Now __RemoteDebug__ have a code converter, for help you to convert your codes:
|
||||
to do it, please access the [RemoteDebugConverter](https://github.com/JoaoLopesF/RemoteDebugConverter)
|
||||
|
||||
- Version 2.0.0
|
||||
|
||||
- Now __RemoteDebug__ can have the same simple software debugger, that __SerialDebug__ library have.
|
||||
This is done, installing another library, the __[RemoteDebugger](https://github.com/JoaoLopesF/RemoteDebugger)__
|
||||
The __RemoteDebugger__ act as an add on to __RemoteDebug__.
|
||||
To support this addon, the changes in __RemoteDebug__, is minimum, just a few callbacks
|
||||
It is done to no add extra overhead to projects that no need an debugger.
|
||||
To more informations please access the __[RemoteDebugger](https://github.com/JoaoLopesF/RemoteDebugger)__ github repository.
|
||||
|
||||
- Now __RemoteDebug__ have a new color system, using more colors, as done in __SerialDebugApp__
|
||||
|
||||
Note: due the __RemoteDebug__ library, is migrate to Arduino 1.5 format, with folder "src",
|
||||
please delete and reinstall the library to avoid duplication of RemoteDebug sources files.
|
||||
|
||||
- Version 1.5.*
|
||||
|
||||
In 1.5.0 version, we have debug* and rdebug* macros (see below), that put automatically,
|
||||
the name of function that called, and core id (core id is only for ESP32)
|
||||
|
||||
## Benefits
|
||||
|
||||
__SerialDebug__ is better than Arduino default debugging by Serial.print commands:
|
||||
|
||||
### This is more __optimized__
|
||||
|
||||
Being or not debugging via USB cable,
|
||||
the Serial.print command allways is processed,
|
||||
waste CPU time on microcontroller.
|
||||
In other words, the debug commands are processed,
|
||||
with someone connected in the serial or not.
|
||||
|
||||
With __RemoteDebug__, all debug output is processed only
|
||||
if exists anyone debugging via telnet or web app connection.
|
||||
|
||||
And with the debug levels of resource, the volume displayed
|
||||
of messages are reduced for higher levels.
|
||||
For example, only process all messages,
|
||||
if the level is the lowest, the verbose,
|
||||
|
||||
__RemoteDebug__ is otimized to reduce overheads,
|
||||
in CPU and memory and include client buffering feature.
|
||||
|
||||
### Have __debug levels__
|
||||
|
||||
During the development, we can put a lot of debug messages...
|
||||
|
||||
But with __RemoteDebug__, we can put a level in each one.
|
||||
|
||||
For all messages (except levels always (debugA) or error (debugE),
|
||||
the message only is processed and showed,
|
||||
if debug level is equal or higher than it level
|
||||
|
||||
__RemoteDebug__ have 6 debug levels, in order of priority:
|
||||
|
||||
Alway showed:
|
||||
|
||||
__Error__: Critical errors
|
||||
|
||||
__Always__: Important messages
|
||||
|
||||
Another levels (showed if level is equal or higher that actual one):
|
||||
|
||||
__Warning__: Error conditions but not critical
|
||||
|
||||
__Info__: Information messages
|
||||
|
||||
__Debug__: Extra information
|
||||
|
||||
__Verbose__: More information than the usual
|
||||
|
||||
So We can change the level to verbose, to see all messages.
|
||||
Or to debug to see only debug or higher level, etc.
|
||||
|
||||
Is very good to reduce a quantity of messages that a project can generate,
|
||||
to help debugging.
|
||||
|
||||
### It is __easy__ to migrate
|
||||
|
||||
__RemoteDebug__ have a converter to help migrate your Arduino codes,
|
||||
from Serial.prints to this library.
|
||||
|
||||
[RemoteDebugConverter](https://github.com/JoaoLopesF/RemoteDebugConverter)
|
||||
|
||||
Even if you want to do this manually, it's very simple. Please see topic [Using](#usage) above.
|
||||
|
||||
### Have __auto__ function name and simple __profiler__
|
||||
|
||||
A simple debug:
|
||||
|
||||
```cpp
|
||||
debugV("* Run time: %02u:%02u:%02u (VERBOSE)", mRunHours, mRunMinutes, mRunSeconds);
|
||||
````
|
||||
|
||||
Can generate this output in serial monitor:
|
||||
|
||||
(V p:3065 loop C1) * Run time: 00:41:23 (VERBOSE)
|
||||
|
||||
Where: V: is the level
|
||||
p: is a profiler time, elased, between this and previous debug
|
||||
loop: is a function name, that executed this debug
|
||||
C1: is a core that executed this debug (and a function of this) (only for ESP32)
|
||||
The remaining is the message formatted (printf)
|
||||
|
||||
For ESP32, the core id in each debug is very good to optimizer multicore programming.
|
||||
|
||||
### Have __commands__ to execute from telnet or web app
|
||||
|
||||
For example:
|
||||
|
||||
- Show help (__?__)
|
||||
- Change the level of debug (__v__,__d__,__i__,__w__,__e__),
|
||||
to show less or more messages.
|
||||
- See memory (__m__)
|
||||
- Reset the board (__reset__)
|
||||
|
||||
See about __RemoteDebug__ commands below.
|
||||
|
||||
You can add your own commands, see the examples please
|
||||
|
||||
If your project have __[RemoteDebugger](https://github.com/JoaoLopesF/RemoteDebugger)__ installed,
|
||||
have a new commands, e.g. call a function, see/change variables, ...
|
||||
|
||||
### Have a simple __software debugger__
|
||||
|
||||
Now __RemoteDebug__ (version >= 2.0.0), have an simple software debuggger,
|
||||
based in codes of SerialDebug library.
|
||||
|
||||
This is another library, that act as an addon to __RemoteDebug__.
|
||||
|
||||
Please acess the RemoteDebugger repository to more informations: __[RemoteDebugger](https://github.com/JoaoLopesF/RemoteDebugger)__
|
||||
|
||||
### Ready for __production__ (release compiler)
|
||||
|
||||
For release your device, just uncomment DEBUG_DISABLED in your project
|
||||
Done this, and no more debug processing.
|
||||
And better for DEBUG_DISABLED, __RemoteDebug__ have ZERO overhead,
|
||||
due is nothing of this is compiled.
|
||||
|
||||
## Web app
|
||||
|
||||
As SerialDebug, now RemoteDebug (v3) have an app,the RemoteDebugApp,
|
||||
to debug in web browser.
|
||||
|
||||
This app is an HTM5 web app, with websocket to comunicate to Arduino board.
|
||||
For it, RemoteDebug v3 have a web socket server (can be disabled).
|
||||
It used a local copy of [arduinoWebSockets](https://github.com/Links2004/arduinoWebSockets) library,
|
||||
due it not in Arduino Library manager.
|
||||
|
||||
As a large web page on web server, the solution for Arduino is save it in a storage,
|
||||
like SPIFFS. But not have automatically updates new version in data saved this way,
|
||||
this SPIFFS data is good for a project but not for a library.
|
||||
|
||||
Due it, this app not is stored and served by board,
|
||||
instead the app is in web: [http://joaolopesf.net/remotedebugapp](http://joaolopesf.net/remotedebugapp)
|
||||
Note: this not uses SSL (https), due web server socket on Arduino, not supports SSL (wss).
|
||||
But after page load, all traffic is in local network, no data is exposed on internet.
|
||||
|
||||
The RemoteDebugApp is a modern HTML5 and needs a modern browsers to work.
|
||||
Internet Explorer 11 and Safari 10 are an examples that not supported.
|
||||
But you can use anothers, as Chrome, Edge, Firefox.
|
||||
|
||||
The web app is in beta, please add an issue,
|
||||
for problems or suggestions.
|
||||
|
||||
Now have another repository, [RemoteDebugApp](https://github.com/JoaoLopesF/RemoteDebugApp)
|
||||
It is for local copy of web app in internet.
|
||||
It is updated with lastest version of web app,
|
||||
after it is publised in web server: [http://joaolopesf.net/remotedebugapp](http://joaolopesf.net/remotedebugapp/).
|
||||
Download it, for use when internet is offline.
|
||||
As it is a local copy, the app will check for new versions periodically,
|
||||
for you can download a new version.
|
||||
|
||||
The telnet remains work, for when want this,
|
||||
or for fails on web app.
|
||||
|
||||
## Telnet
|
||||
|
||||
Telnet is a standard way of remotely connecting to a server and
|
||||
is supported on all operating systems (Windows, Mac, Linux...).
|
||||
|
||||
MacOSx and Linux have a native telnet client.
|
||||
|
||||
For Windows, a typical telnet client is the __Putty__: [putty](https://www.putty.org/) .
|
||||
|
||||
Have a good tool for mobiles: the __Fing__, please find it in your mobile store.
|
||||
Its show all devices in local network (WiFi), show ports opened and can execute the telnet client too (external App)
|
||||
|
||||
__RemoteDebug__ sets-up a telnet server which is listening to any telnet client that wants to connect. After connection, logging is streamed to the telnet client.
|
||||
|
||||
__RemoteDebug__ is very simple to use, after a few lines of initialization code, you can use the well-known "print" commands to stream your logging to the remote client.
|
||||
|
||||
### Debug levels
|
||||
|
||||
__RemoteDebug__ supports the filtering of logging based on __debug levels__:
|
||||
|
||||
Only show for it actual debug level:
|
||||
|
||||
- Verbose
|
||||
- Debug
|
||||
- Info
|
||||
- Warnings
|
||||
|
||||
Note: These levels are in the order of most-logging -> least-logging.
|
||||
|
||||
Or for always show (not depends of actual debug level):
|
||||
|
||||
- Any
|
||||
- Errors
|
||||
|
||||
Note: All debugs is processed and showed only if have a client connection.
|
||||
|
||||
The telnet client or web app can set the debug level by typing a few simple commands.
|
||||
|
||||
### Profiler
|
||||
|
||||
__RemoteDebug__ includes a simple profiler. It can be enabled by the connected client (telnet or web app)
|
||||
or the Arduino code itself.
|
||||
|
||||
When enabled, it shows the time between 2 debug statements, using different colors depending on the elapsed time.
|
||||
|
||||
A typical example would be to insert logging just before and after a function after which you can see how much the is spent in the function.
|
||||
|
||||
### Lightweight
|
||||
|
||||
__RemoteDebug__ is designed to give minimal overhead (connected or not) and
|
||||
only process debugs,if there is a client (telnet or web app) connected.
|
||||
|
||||
### Custom commands
|
||||
|
||||
__RemoteDebug__ supports custom commands that can be entered in the client (telnet or web app).
|
||||
These trigger the execution of a custom function in the Arduino code. For example this can be used to send back a status on request of the client.
|
||||
|
||||
### DISCLAIMER
|
||||
|
||||
The current version of __RemoteDebug__ does not yet include any encrypted authentication,
|
||||
only plain text and is intended only for development, not use in production/release.
|
||||
|
||||
Future versions, if is possible, will include a secure way for authentication and further testing to support production environments.
|
||||
|
||||
## Wishlist
|
||||
|
||||
- An app to RemoteDebug like SerialDebug have.
|
||||
- Http page to begin/stop the telnet server or websocket server.
|
||||
- Authentication as telnet support (kerberos, etc.) to support production environment
|
||||
|
||||
## Install
|
||||
|
||||
Just download or clone this repository.
|
||||
|
||||
Or for Arduino IDE, you can use the library manager to install and update the library.
|
||||
<!-- For install help, please see: [https://www.arduino.cc/en/Guide/Libraries](https://www.arduino.cc/en/Guide/Libraries) -->
|
||||
For install help, please click on this: [](https://www.ardu-badge.com/RemoteDebug)
|
||||
|
||||
<!---->
|
||||
|
||||
For another IDE, or not using the library manager of Arduino IDE,
|
||||
I suggest you use a [Github Desktop](https://desktop.github.com/) app to clone,it help to keep updated.
|
||||
|
||||
Please open the projects in example folder, to see it working.
|
||||
|
||||
## Usage
|
||||
|
||||
### includes
|
||||
|
||||
```cpp
|
||||
#include "RemoteDebug.h" //https://github.com/JoaoLopesF/RemoteDebug
|
||||
```
|
||||
|
||||
### instance
|
||||
|
||||
RemoteDebug Debug;
|
||||
|
||||
### setup
|
||||
|
||||
In the setup function after WiFi initialization
|
||||
|
||||
```cpp
|
||||
// Initialize the server (telnet or web socket) of RemoteDebug
|
||||
|
||||
Debug.begin(HOST_NAME);
|
||||
|
||||
// OR
|
||||
|
||||
Debug.begin(HOST_NAME, startingDebugLevel);
|
||||
|
||||
// Options
|
||||
|
||||
Debug.setResetCmdEnabled(true); // Enable the reset command
|
||||
|
||||
// Debug.showProfiler(true); // To show profiler - time between messages of Debug
|
||||
|
||||
```
|
||||
|
||||
Note: to enable the debugger, by RemoteDebugger, please acess this github repository:
|
||||
__[RemoteDebugger](https://github.com/JoaoLopesF/RemoteDebugger)__
|
||||
|
||||
In the tail of loop function
|
||||
|
||||
```cpp
|
||||
// Remote debug over WiFi
|
||||
|
||||
Debug.handle();
|
||||
|
||||
// Or
|
||||
|
||||
debugHandle(); // Equal to SerialDebug
|
||||
|
||||
```
|
||||
|
||||
In any place of you code:
|
||||
|
||||
```cpp
|
||||
#ifndef DEBUG_DISABLED
|
||||
if (Debug.isActive(Debug.<level>)) {
|
||||
Debug.printf("bla bla bla: %d %s", number, str); // OR
|
||||
Debug.printf("bla bla bla: %d %s", number, str.c_str()); // Note: if type is String need c_str() // OR
|
||||
Debug.println("bla bla bla 2 ln");
|
||||
Debug.printf("float: %f\n", value); // Not works in ESP8266 :-(
|
||||
// Note: to show floats with printf (ESP8266 only),
|
||||
// you can use my ArduinoUtil library -> https://github.com/JoaoLopesF/ArduinoUtil
|
||||
Debug.printf("float: %s\n", Util.formatFloat(value, 0, 5).c_str());
|
||||
}
|
||||
#endif
|
||||
```
|
||||
|
||||
Note: Using isActive, you need surround the code by DEBUG_DISABLE precompile condition,
|
||||
to avoid compile it for production/release
|
||||
|
||||
Or short way (equal to SerialDebug) (prefered if only one debug at time):
|
||||
|
||||
```cpp
|
||||
debugA("This is a any (always showed) - var %d", var);
|
||||
debugV("This is a verbose - var %d", var);
|
||||
debugD("This is a debug - var %d", var);
|
||||
debugI("This is a information - var %d", var);
|
||||
debugW("This is a warning - var %d", var);
|
||||
debugE("This is a error - var %d", var);
|
||||
|
||||
debugV("This is a println");
|
||||
```
|
||||
|
||||
Or if your project uses several Serial.print commands to generate a single debug message
|
||||
for example:
|
||||
|
||||
```cpp
|
||||
Serial.print("a = ");
|
||||
Serial.print(a);
|
||||
Serial.print(" b = ");
|
||||
Serial.print(b);
|
||||
Serial.print(" c = ");
|
||||
Serial.println(c);
|
||||
```
|
||||
|
||||
can be use rdebug* macros:
|
||||
|
||||
```cpp
|
||||
rdebugV("a = ");
|
||||
rdebugV(a);
|
||||
rdebugV(" b = ");
|
||||
rdebugV(b);
|
||||
rdebugV(" c = ");
|
||||
rdebugVln(c);
|
||||
```
|
||||
|
||||
Note: in future, I suggest that you migrate this to a single debug command:
|
||||
|
||||
```cpp
|
||||
debugV(a = %d b = %d c = %d", a, b, c);
|
||||
```
|
||||
|
||||
An example of use debug levels: (supposing the data is a lot of characters)
|
||||
|
||||
```cpp
|
||||
if (Debug.isActive(Debug.VERBOSE)) { // Debug message long
|
||||
Debug.printf("routine: data received: %s\n", data.c_str()); // Note: if type is String need c_str()
|
||||
} else if (Debug.isActive(Debug.DEBUG)) { // Debug message short
|
||||
Debug.printf("routine: data received: %s ...\n", data.substring(0, 20).c_str()); // %.20s not working :-|
|
||||
}
|
||||
```
|
||||
|
||||
Starting at version 1.5.0, debug macros (debug* and rdebug*), automatically put the name of function that called the macro,
|
||||
and core id (core id only for ESP32).
|
||||
|
||||
So:
|
||||
|
||||
```cpp
|
||||
void foo() {
|
||||
|
||||
uint8_t var = 1;
|
||||
debugV("this is a debug - var %u", var);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
It will show in client (telnet or web app):
|
||||
|
||||
(V p:^0000ms) (foo)(C1) this is a debug - var 1
|
||||
|
||||
Where:
|
||||
|
||||
V -> verbose
|
||||
p -> profiler time
|
||||
(foo) -> this is a function name that calls the debug macro
|
||||
(C1) -> It is running it Core 1 (only for ESP32)
|
||||
|
||||
An example of use debug with serial enabled
|
||||
|
||||
Useful to see messages if setup or
|
||||
in cause the ESP8266/ESP32 is rebooting (client connection stop before received all messages)
|
||||
Only for this purposes I suggest it
|
||||
|
||||
```cpp
|
||||
// Setup after Debug.begin
|
||||
|
||||
Debug.setSerialEnabled(true); // All messages too send to serial too, and can be see in serial monitor
|
||||
```
|
||||
|
||||
For reduce overheads RemoteDebug is disconnect the client (telnet or web app), if it not active.
|
||||
|
||||
- Please press enter or any key if you need keep the connection
|
||||
- The default is 5 minutes (You can change it in RemoteDebug.h)
|
||||
- You can use mDNS to register each node with different name, it helps to connect without know the IP.
|
||||
|
||||
Please not forget to use if clause with Debug.isActive (if not using debug macros)
|
||||
|
||||
---> This is very important to reduce overheads and work of debug levels
|
||||
|
||||
Please see the samples, basic or advanced, to learn how to use
|
||||
|
||||
In advanced sample, I used WifiManager library, ArduinoOTA and mDNS, please see it.
|
||||
|
||||
## Releases
|
||||
|
||||
### 3.0.5 - 2019-03-23
|
||||
|
||||
- Ajustment on debugA macro, thanks @jetpax and @cmidgley to add this issue.
|
||||
|
||||
### 3.0.4 - 2019-03-19
|
||||
|
||||
- All public configurations (#defines) have moved to RemoteDebugCfg.h, to facilitate changes for anybody.
|
||||
- Changed examples, with warnings on change any #define in project,
|
||||
with workarounds if it not work. (thanks to @22MarioZ for added this issue)
|
||||
|
||||
### 3.0.3 - 2019-03-18
|
||||
|
||||
- Adjustments if web socket is disabled
|
||||
|
||||
### 3.0.2 - 2019-03-16
|
||||
|
||||
- Adjustments in examples, added one for debugger
|
||||
|
||||
### 3.0.1 - 2019-03-13
|
||||
|
||||
- Adjustments in silente mode
|
||||
- Commands from RemoteDebugApp now is treated
|
||||
- Adjusts to RemoteDebugger support connection by web sockets
|
||||
|
||||
### 3.0.0 - 2019-03-10
|
||||
|
||||
- If not disabled, add a web socket server to comunicate with RemoteDebugApp (HTML5 web app)
|
||||
- The standard telnet still working, to debug with internet offline
|
||||
- Ajustment on debugA macro, thanks @jetpax to add this issue
|
||||
|
||||
### 2.1.2 - 2019-03-08
|
||||
|
||||
- Add empty rprint* macros, if debug is disabled
|
||||
|
||||
### 2.1.1 - 2019-03-06
|
||||
|
||||
- Create option DEBUG_DISABLE_AUTO_FUNC
|
||||
- Create macros to be used for code converter: rprint and rprintln
|
||||
RemoteDebug now have an code converters to help migrate codes
|
||||
|
||||
### 2.1.0 - 2019-03-04
|
||||
|
||||
- Create precompiler DEBUG_DISABLED to compile for production/release,
|
||||
equal that have in SerialDebug
|
||||
- Adjustments in examples
|
||||
|
||||
### 2.0.1 - 2019-03-01
|
||||
|
||||
- Adjustments for the debugger: it still disable until dbg command, equal to SerialDebug
|
||||
- The callback will to be called before print debug messages now
|
||||
- And only if debugger is enabled in RemoteDebugger (command dbg)
|
||||
- Changed handle debugger logic
|
||||
|
||||
### 2.0.0 - 2019-02-28
|
||||
|
||||
- Added support to RemoteDebug addon library: the RemoteDebugger, an simple software debugger, based on SerialDebug
|
||||
- New color system
|
||||
|
||||
### 1.5.9 - 2019-02-18
|
||||
|
||||
- Bug -> sometimes the command is process twice
|
||||
- Workaround -> check time
|
||||
|
||||
### 1.5.8 - 2019-02-08
|
||||
|
||||
- New macros to compatibility with SerialDebug (can use RemoteDebug or SerialDebug) thanks to @phrxmd
|
||||
|
||||
### 1.5.7 - 2018-11-03
|
||||
|
||||
- Fixed bug for MAX_TIME_INACTIVE, thanks to @achuchev to add this issue
|
||||
|
||||
### 1.5.6 - 2018-10-19
|
||||
|
||||
- Adjustments based on pull request from @jeroenst (to allow serial output with telnet password and setPassword method)
|
||||
|
||||
### 1.5.5 - 2018-10-19
|
||||
|
||||
- Serial output is now not allowed if telnet password is enabled
|
||||
- Few adjustments
|
||||
|
||||
### 1.5.4 - 2018-10-05
|
||||
|
||||
- Few adjustment in write logic
|
||||
|
||||
### 1.5.3 - 2018-09-04
|
||||
|
||||
- Serial output adjustments (due bug in password logic)
|
||||
|
||||
### 1.5.2
|
||||
|
||||
- Correct rdebug macro (thanks @stritti)
|
||||
|
||||
### 1.5.1 - 2018-08-28
|
||||
|
||||
- New silent mode (command s)
|
||||
|
||||
### 1.5.0 - 2018-08=26
|
||||
|
||||
- Auto function name and ESP32 core id for rdebug* macros
|
||||
- begin method have a option for port number
|
||||
- Few adjustments
|
||||
- Added new rdebug?ln to put auto new line
|
||||
|
||||
### 1.4.0 - 2018-08-18
|
||||
|
||||
- Simple text password request feature (disabled by default)
|
||||
|
||||
Notes:
|
||||
It is very simple feature, only text, no cryptography,
|
||||
and the password is echoed in screen (I not discovery yet how disable it)
|
||||
|
||||
telnet use advanced authentication (kerberos, etc.)
|
||||
Such as now RemoteDebug is not for production (releases),
|
||||
this kind of authentication will not be done now.
|
||||
|
||||
### 1.3.1 - 2018-08-18
|
||||
|
||||
- Adjustments in precompiler macros
|
||||
|
||||
### 1.3.0 - 2018-08-17
|
||||
|
||||
- Bug in write with latest ESP8266 SDK
|
||||
- Port number can be modified in project Arduino (.ino file)
|
||||
- Few adjustments as ESP32 includes
|
||||
|
||||
### 1.2.2
|
||||
|
||||
- Adjustments, as avoid ESP32 include errors
|
||||
- Telnet port of server can be modified by project
|
||||
Just put it in your .ino, before the include:
|
||||
|
||||
### 1.2.0
|
||||
|
||||
- Shortcuts and client buffering to avoid mysterious delay of ESP networking
|
||||
|
||||
### 1.1.0
|
||||
|
||||
- Adjustments and now runs in Esp32 too.
|
||||
|
||||
### 1.0.0
|
||||
|
||||
- Adjustments and improvements from Beta versions.
|
||||
|
||||
New features:
|
||||
|
||||
- Filter
|
||||
- Colors
|
||||
- Support to Windows telnet client
|
||||
|
||||
### 0.9
|
||||
|
||||
- First Beta
|
||||
|
||||
## Known issues
|
||||
|
||||
- Sometimes (rarely) the connection over telnet becomes very slow.
|
||||
Especially right after uploading firmware.
|
||||
Reset command in telnet connection or turn off/on can be resolve it.
|
||||
But I need find why it occurs
|
||||
|
||||
## Thanks
|
||||
|
||||
First thanks a lot for Igrr for bring to us the Arduino ESP8266 and to Espressif to Arduino ESP32
|
||||
|
||||
Thanks to Links2004 for a good web server socket, used for web app connection.
|
||||
|
||||
For the logo: thanks to a freepik and pngtree sites for free icons that have in logo
|
||||
|
||||
Resources:
|
||||
|
||||
- Example of TelnetServer code in http://www.rudiswiki.de/wiki9/WiFiTelnetServer
|
||||
- arduinoWebSockets library in https://github.com/Links2004/arduinoWebSockets
|
||||
|
||||
## End of README
|
||||
|
||||
Hit counter on this file, starting at 2019-03-03:
|
||||
[](http://hits.dwyl.io/JoaoLopesF/RemoteDebug)
|
||||
@@ -1,634 +0,0 @@
|
||||
////////
|
||||
// Library: Remote debug - debug over WiFi - for Esp8266 (NodeMCU) or ESP32
|
||||
// Author : Joao Lopes
|
||||
// File : RemoteDebug_Advanced.ino
|
||||
// Notes :
|
||||
//
|
||||
// Attention: This library is only for help development. Please not use this in production
|
||||
//
|
||||
// Sample to show how to use advanced features of Arduino and RemoteDebug library
|
||||
//
|
||||
// Example of use:
|
||||
//
|
||||
//#ifndef DEBUG_DISABLED
|
||||
// if (Debug.isActive(Debug.<level>)) { // <--- This is very important to reduce overheads and work of debug levels
|
||||
// Debug.printf("bla bla bla: %d %s\n", number, str);
|
||||
// Debug.println("bla bla bla");
|
||||
// }
|
||||
//#endif
|
||||
//
|
||||
// Or short way (prefered if only one debug at time)
|
||||
//
|
||||
// debugA("This is a any (always showed) - var %d", var);
|
||||
//
|
||||
// debugV("This is a verbose - var %d", var);
|
||||
// debugD("This is a debug - var %d", var);
|
||||
// debugI("This is a information - var %d", var);
|
||||
// debugW("This is a warning - var %d", var);
|
||||
// debugE("This is a error - var %d", var);
|
||||
//
|
||||
// debugV("This is println");
|
||||
//
|
||||
///////
|
||||
|
||||
////// Defines
|
||||
|
||||
// Host name (please change it)
|
||||
|
||||
#define HOST_NAME "remotedebug"
|
||||
|
||||
// Board especific libraries
|
||||
|
||||
#if defined ESP8266 || defined ESP32
|
||||
|
||||
// Use mDNS ? (comment this do disable it)
|
||||
|
||||
#define USE_MDNS true
|
||||
|
||||
// Arduino OTA (uncomment this to enable)
|
||||
|
||||
//#define USE_ARDUINO_OTA true
|
||||
|
||||
#else
|
||||
|
||||
// RemoteDebug library is now only to Espressif boards,
|
||||
// as ESP32 and ESP82266,
|
||||
// If need for another WiFi boards,
|
||||
// please add an issue about this
|
||||
// and we will see if it is possible made the port for your board.
|
||||
// access: https://github.com/JoaoLopesF/RemoteDebug/issues
|
||||
|
||||
#error "The board must be ESP8266 or ESP32"
|
||||
|
||||
#endif // ESP
|
||||
|
||||
// Web server (uncomment this to need this)
|
||||
|
||||
//#define WEB_SERVER_ENABLED true
|
||||
|
||||
////// Includes
|
||||
|
||||
#if defined ESP8266
|
||||
|
||||
// Includes of ESP8266
|
||||
|
||||
#include <ESP8266WiFi.h>
|
||||
|
||||
#ifdef USE_MDNS
|
||||
#include <DNSServer.h>
|
||||
#include <ESP8266mDNS.h>
|
||||
#endif
|
||||
|
||||
#ifdef WEB_SERVER_ENABLED
|
||||
#include <ESP8266WebServer.h>
|
||||
#endif
|
||||
|
||||
#elif defined ESP32
|
||||
|
||||
// Includes of ESP32
|
||||
|
||||
#include <WiFi.h>
|
||||
|
||||
#ifdef USE_MDNS
|
||||
#include <DNSServer.h>
|
||||
#include "ESPmDNS.h"
|
||||
#endif
|
||||
|
||||
#ifdef WEB_SERVER_ENABLED
|
||||
#include <WebServer.h>
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#error "For now, RemoteDebug support only boards Espressif, as ESP8266 and ESP32"
|
||||
|
||||
#endif // ESP
|
||||
|
||||
// Arduino OTA
|
||||
|
||||
#ifdef USE_ARDUINO_OTA
|
||||
#include <ArduinoOTA.h>
|
||||
#endif
|
||||
|
||||
// HTTP Web server
|
||||
|
||||
#ifdef WEB_SERVER_ENABLED
|
||||
|
||||
#if defined ESP8266
|
||||
|
||||
ESP8266WebServer HTTPServer(80);
|
||||
|
||||
#elif defined ESP32
|
||||
|
||||
WebServer HTTPServer(80);
|
||||
|
||||
#endif
|
||||
|
||||
#endif // WEB_SERVER_ENABLED
|
||||
|
||||
///// Remote debug over WiFi - not recommended for production/release, only for development
|
||||
|
||||
// Options for RemoteDebug of this project
|
||||
|
||||
// Attention: read this, before you change any option
|
||||
//
|
||||
// If yot changed it and not works, the compiler is using catching old compiled files
|
||||
// To workaround this:
|
||||
// - If have a clean project option in IDE (as Eclipse/Platformio), do it
|
||||
// - or force compiler to compiler all (changing any configuration of board)
|
||||
// - or to this change globally in RemoteDebugCfg.h (on library directory)
|
||||
// - And upload again
|
||||
//
|
||||
// thanks to @22MarioZ for added this issue
|
||||
|
||||
// Disable all debug ?
|
||||
// Important to compile for prodution/release
|
||||
// Disable all debug ? Good to release builds (production)
|
||||
// as nothing of RemoteDebug is compiled, zero overhead :-)
|
||||
// Uncomment the line below, to do it:
|
||||
//#define DEBUG_DISABLED true
|
||||
|
||||
// Disable te auto function feature of RemoteDebug
|
||||
// Good if your code already have func name on debug messages
|
||||
// Uncomment the line below, to do it:
|
||||
//#define DEBUG_DISABLE_AUTO_FUNC true
|
||||
|
||||
// Disable Websocket? This is used with RemoteDebugApp connection
|
||||
// Uncomment the line below, to do it:
|
||||
//#define WEBSOCKET_DISABLED true
|
||||
|
||||
#ifndef WEBSOCKET_DISABLED // Only if Web socket enabled (RemoteDebugApp)
|
||||
// If enabled, you can change the port here (8232 is default)
|
||||
// Uncomment the line below, to do it:
|
||||
//#define WEBSOCKET_PORT 8232
|
||||
|
||||
// Internally, the RemoteDebug uses a local copy of the arduinoWebSockets library (https://github.com/Links2004/arduinoWebSockets)
|
||||
// Due it not in Arduino Library Manager
|
||||
// If your project already use this library,
|
||||
// Uncomment the line below, to do it:
|
||||
//#define USE_LIB_WEBSOCKET true
|
||||
#endif
|
||||
|
||||
// Include libraries
|
||||
|
||||
#include "RemoteDebug.h" //https://github.com/JoaoLopesF/RemoteDebug
|
||||
|
||||
#ifndef DEBUG_DISABLED // Only if debug is not disabled (for production/release)
|
||||
|
||||
// Instance of RemoteDebug
|
||||
|
||||
RemoteDebug Debug;
|
||||
|
||||
#endif
|
||||
|
||||
// WiFi credentials
|
||||
// Note: if commented, is used the smartConfig
|
||||
// That allow to it in mobile app
|
||||
// See more details in http://www.iotsharing.com/2017/05/how-to-use-smartconfig-on-esp32.html
|
||||
|
||||
//#define WIFI_SSID "..." // your network SSID (name)
|
||||
//#define WIFI_PASS "..." // your network key
|
||||
|
||||
/////// Variables
|
||||
|
||||
// Time
|
||||
|
||||
uint32_t mTimeToSec = 0;
|
||||
uint32_t mTimeSeconds = 0;
|
||||
|
||||
////// Setup
|
||||
|
||||
void setup() {
|
||||
|
||||
// Initialize the Serial (use only in setup codes)
|
||||
|
||||
Serial.begin(230400);
|
||||
|
||||
// Buildin led
|
||||
|
||||
#ifdef LED_BUILTIN
|
||||
pinMode(LED_BUILTIN, OUTPUT);
|
||||
digitalWrite(LED_BUILTIN, LOW);
|
||||
#endif
|
||||
|
||||
// Connect WiFi
|
||||
|
||||
connectWiFi();
|
||||
|
||||
// Host name of WiFi
|
||||
|
||||
#ifdef ESP8266
|
||||
WiFi.hostname(HOST_NAME);
|
||||
#endif
|
||||
|
||||
#ifdef USE_ARDUINO_OTA
|
||||
// Update over air (OTA)
|
||||
|
||||
initializeOTA();
|
||||
#endif
|
||||
|
||||
// Register host name in mDNS
|
||||
|
||||
#if defined USE_MDNS && defined HOST_NAME
|
||||
|
||||
if (MDNS.begin(HOST_NAME)) {
|
||||
Serial.print("* MDNS responder started. Hostname -> ");
|
||||
Serial.println(HOST_NAME);
|
||||
}
|
||||
|
||||
// Register the services
|
||||
|
||||
#ifdef WEB_SERVER_ENABLED
|
||||
MDNS.addService("http", "tcp", 80); // Web server
|
||||
#endif
|
||||
|
||||
#ifndef DEBUG_DISABLED
|
||||
MDNS.addService("telnet", "tcp", 23); // Telnet server of RemoteDebug, register as telnet
|
||||
#endif
|
||||
|
||||
#endif // MDNS
|
||||
|
||||
// HTTP web server
|
||||
|
||||
#ifdef WEB_SERVER_ENABLED
|
||||
HTTPServer.on("/", handleRoot);
|
||||
|
||||
HTTPServer.onNotFound(handleNotFound);
|
||||
|
||||
HTTPServer.begin();
|
||||
|
||||
Serial.println("* HTTP server started");
|
||||
#endif
|
||||
|
||||
#ifndef DEBUG_DISABLED // Only for development
|
||||
|
||||
// Initialize RemoteDebug
|
||||
|
||||
Debug.begin(HOST_NAME); // Initialize the WiFi server
|
||||
|
||||
//Debug.setPassword("r3m0t0."); // Password for WiFi client connection (telnet or webapp) ?
|
||||
|
||||
Debug.setResetCmdEnabled(true); // Enable the reset command
|
||||
|
||||
Debug.showProfiler(true); // Profiler (Good to measure times, to optimize codes)
|
||||
|
||||
Debug.showColors(true); // Colors
|
||||
|
||||
// Debug.setSerialEnabled(true); // if you wants serial echo - only recommended if ESP is plugged in USB
|
||||
|
||||
// Project commands
|
||||
|
||||
String helpCmd = "bench1 - Benchmark 1\n";
|
||||
helpCmd.concat("bench2 - Benchmark 2");
|
||||
|
||||
Debug.setHelpProjectsCmds(helpCmd);
|
||||
Debug.setCallBackProjectCmds(&processCmdRemoteDebug);
|
||||
|
||||
// End of setup - show IP
|
||||
|
||||
Serial.println("* Arduino RemoteDebug Library");
|
||||
Serial.println("*");
|
||||
Serial.print("* WiFI connected. IP address: ");
|
||||
Serial.println(WiFi.localIP());
|
||||
Serial.println("*");
|
||||
Serial.println("* Please use the telnet client (telnet for Mac/Unix or putty and others for Windows)");
|
||||
Serial.println("* or the RemoteDebugApp (in browser: http://joaolopesf.net/remotedebugapp)");
|
||||
Serial.println("*");
|
||||
Serial.println("* This sample will send messages of debug in all levels.");
|
||||
Serial.println("*");
|
||||
Serial.println("* Please try change debug level in client (telnet or web app), to see how it works");
|
||||
Serial.println("*");
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
void loop() {
|
||||
|
||||
#ifndef DEBUG_DISABLED
|
||||
// Time of begin of this loop
|
||||
uint32_t timeBeginLoop = millis();
|
||||
#endif
|
||||
|
||||
|
||||
// Each second
|
||||
|
||||
if (millis() >= mTimeToSec) {
|
||||
|
||||
// Time
|
||||
|
||||
mTimeToSec = millis() + 1000;
|
||||
|
||||
mTimeSeconds++;
|
||||
|
||||
// Blink the led
|
||||
|
||||
#ifdef LED_BUILTIN
|
||||
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
|
||||
#endif
|
||||
|
||||
// Debug the time (verbose level)
|
||||
|
||||
debugV("* Time: %u seconds (VERBOSE)", mTimeSeconds);
|
||||
|
||||
if (mTimeSeconds % 5 == 0) { // Each 5 seconds
|
||||
|
||||
// Debug levels
|
||||
|
||||
debugV("* This is a message of debug level VERBOSE");
|
||||
debugD("* This is a message of debug level DEBUG");
|
||||
debugI("* This is a message of debug level INFO");
|
||||
debugW("* This is a message of debug level WARNING");
|
||||
debugE("* This is a message of debug level ERROR");
|
||||
|
||||
|
||||
// RemoteDebug isActive? Use this RemoteDebug sintaxe if you need process anything only for debug
|
||||
// It is good to avoid overheads (this is only use that is suggest to use isActive)
|
||||
// Note this need be surrounded by DEBUG_DISABLED precompiler condition to not compile for production/release
|
||||
|
||||
#ifndef DEBUG_DISABLED
|
||||
|
||||
if (Debug.isActive(Debug.VERBOSE)) {
|
||||
|
||||
debugV("Calling a foo function");
|
||||
debugV("At time of %d sec.\n", mTimeSeconds);
|
||||
|
||||
// Call a function
|
||||
|
||||
foo();
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
////// Services on Wifi
|
||||
|
||||
#ifdef USE_ARDUINO_OTA
|
||||
// Update over air (OTA)
|
||||
|
||||
ArduinoOTA.handle();
|
||||
#endif
|
||||
|
||||
#ifdef WEB_SERVER_ENABLED
|
||||
// Web server
|
||||
|
||||
HTTPServer.handleClient();
|
||||
#endif
|
||||
|
||||
#ifndef DEBUG_DISABLED
|
||||
// RemoteDebug handle (for WiFi connections)
|
||||
|
||||
Debug.handle();
|
||||
#endif
|
||||
|
||||
// Give a time for ESP
|
||||
|
||||
yield();
|
||||
|
||||
#ifndef DEBUG_DISABLED
|
||||
// Show a debug - warning if time of these loop is over 50 (info) or 100 ms (warning)
|
||||
|
||||
uint32_t time = (millis() - timeBeginLoop);
|
||||
|
||||
if (time > 100) {
|
||||
debugI("* Time elapsed for the loop: %u ms.", time);
|
||||
} else if (time > 200) {
|
||||
debugW("* Time elapsed for the loop: %u ms.", time);
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Function example to show a new auto function name of debug* macros
|
||||
|
||||
void foo() {
|
||||
|
||||
uint8_t var = 1;
|
||||
|
||||
debugV("this is a debug - var %u", var);
|
||||
debugV("This is a println");
|
||||
}
|
||||
|
||||
#ifndef DEBUG_DISABLED
|
||||
|
||||
// Process commands from RemoteDebug
|
||||
|
||||
void processCmdRemoteDebug() {
|
||||
|
||||
String lastCmd = Debug.getLastCommand();
|
||||
|
||||
if (lastCmd == "bench1") {
|
||||
|
||||
// Benchmark 1 - Printf
|
||||
|
||||
debugA("* Benchmark 1 - one Printf");
|
||||
|
||||
|
||||
uint32_t timeBegin = millis();
|
||||
uint8_t times = 50;
|
||||
|
||||
for (uint8_t i = 1; i <= times; i++) {
|
||||
debugA("%u - 1234567890 - AAAA", i);
|
||||
|
||||
}
|
||||
|
||||
debugA("* Time elapsed for %u printf: %ld ms.\n", times,
|
||||
(millis() - timeBegin));
|
||||
|
||||
} else if (lastCmd == "bench2") {
|
||||
|
||||
// Benchmark 2 - Print/println
|
||||
|
||||
debugA("* Benchmark 2 - Print/Println");
|
||||
|
||||
uint32_t timeBegin = millis();
|
||||
uint8_t times = 50;
|
||||
|
||||
for (uint8_t i = 1; i <= times; i++) {
|
||||
if (Debug.isActive(Debug.ANY)) {
|
||||
Debug.print(i);
|
||||
Debug.print(" - 1234567890");
|
||||
Debug.println(" - AAAA");
|
||||
}
|
||||
}
|
||||
|
||||
debugA("* Time elapsed for %u printf: %ld ms.\n", times,
|
||||
(millis() - timeBegin));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
////// WiFi
|
||||
|
||||
void connectWiFi() {
|
||||
|
||||
////// Connect WiFi
|
||||
|
||||
#ifdef EM_DEPURACAO
|
||||
Serial.println("*** connectWiFi: begin conection ...");
|
||||
#endif
|
||||
|
||||
#ifdef ESP32
|
||||
// ESP32 // TODO: is really necessary ?
|
||||
WiFi.enableSTA(true);
|
||||
delay(100);
|
||||
#endif
|
||||
|
||||
// Connect with SSID and password stored
|
||||
|
||||
#ifndef WIFI_SSID
|
||||
WiFi.begin();
|
||||
#else
|
||||
WiFi.begin(WIFI_SSID, WIFI_PASS);
|
||||
#endif
|
||||
|
||||
// Wait connection
|
||||
|
||||
uint32_t timeout = millis() + 20000; // Time out
|
||||
|
||||
while (WiFi.status() != WL_CONNECTED && millis() < timeout) {
|
||||
delay(250);
|
||||
Serial.print(".");
|
||||
}
|
||||
|
||||
// Not connected yet?
|
||||
|
||||
if (WiFi.status() != WL_CONNECTED) {
|
||||
|
||||
#ifndef WIFI_SSID
|
||||
// SmartConfig
|
||||
|
||||
WiFi.beginSmartConfig();
|
||||
|
||||
// Wait for SmartConfig packet from mobile
|
||||
|
||||
Serial.println("connectWiFi: Waiting for SmartConfig.");
|
||||
|
||||
while (!WiFi.smartConfigDone()) {
|
||||
delay(500);
|
||||
Serial.print(".");
|
||||
}
|
||||
|
||||
Serial.println("");
|
||||
Serial.println("connectWiFi: SmartConfig received.");
|
||||
|
||||
// Wait for WiFi to connect to AP
|
||||
|
||||
Serial.println("connectWiFi: Waiting for WiFi");
|
||||
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
delay(500);
|
||||
Serial.print(".");
|
||||
}
|
||||
#else
|
||||
Serial.println("Not possible connect to WiFi, rebooting");
|
||||
ESP.restart();
|
||||
#endif
|
||||
}
|
||||
|
||||
// End
|
||||
|
||||
Serial.println("");
|
||||
Serial.print("connectWiFi: connect a ");
|
||||
Serial.println(WiFi.SSID());
|
||||
Serial.print("IP: ");
|
||||
Serial.println(WiFi.localIP().toString());
|
||||
|
||||
}
|
||||
|
||||
#ifdef USE_ARDUINO_OTA
|
||||
|
||||
// Initialize o Arduino OTA
|
||||
|
||||
void initializeOTA() {
|
||||
|
||||
// TODO: option to authentication (password)
|
||||
|
||||
#if defined ESP8266
|
||||
|
||||
ArduinoOTA.onStart([]() {
|
||||
Serial.println("* OTA: Start");
|
||||
});
|
||||
ArduinoOTA.onEnd([]() {
|
||||
Serial.println("\n*OTA: End");
|
||||
});
|
||||
ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
|
||||
Serial.printf("*OTA: Progress: %u%%\r", (progress / (total / 100)));
|
||||
});
|
||||
ArduinoOTA.onError([](ota_error_t error) {
|
||||
Serial.printf("*OTA: Error[%u]: ", error);
|
||||
if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
|
||||
else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
|
||||
else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
|
||||
else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
|
||||
else if (error == OTA_END_ERROR) Serial.println("End Failed");
|
||||
});
|
||||
|
||||
#elif defined ESP32
|
||||
|
||||
// ArduinoOTA
|
||||
|
||||
ArduinoOTA.onStart([]() {
|
||||
String type;
|
||||
if (ArduinoOTA.getCommand() == U_FLASH)
|
||||
type = "sketch";
|
||||
else // U_SPIFFS
|
||||
type = "filesystem";
|
||||
Serial.println("Start updating " + type);
|
||||
}).onEnd([]() {
|
||||
Serial.println("\nEnd");
|
||||
}).onProgress([](unsigned int progress, unsigned int total) {
|
||||
Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
|
||||
}).onError([](ota_error_t error) {
|
||||
Serial.printf("Error[%u]: ", error);
|
||||
if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
|
||||
else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
|
||||
else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
|
||||
else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
|
||||
else if (error == OTA_END_ERROR) Serial.println("End Failed");
|
||||
});
|
||||
|
||||
#endif
|
||||
|
||||
// Begin
|
||||
|
||||
ArduinoOTA.begin();
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef WEB_SERVER_ENABLED
|
||||
|
||||
/////////// Handles
|
||||
|
||||
void handleRoot() {
|
||||
|
||||
// Root web page
|
||||
|
||||
HTTPServer.send(200, "text/plain", "hello from esp - RemoteDebug Sample!");
|
||||
}
|
||||
|
||||
void handleNotFound(){
|
||||
|
||||
// Page not Found
|
||||
|
||||
String message = "File Not Found\n\n";
|
||||
message.concat("URI: ");
|
||||
message.concat(HTTPServer.uri());
|
||||
message.concat("\nMethod: ");
|
||||
message.concat((HTTPServer.method() == HTTP_GET)?"GET":"POST");
|
||||
message.concat("\nArguments: ");
|
||||
message.concat(HTTPServer.args());
|
||||
message.concat("\n");
|
||||
for (uint8_t i=0; i<HTTPServer.args(); i++){
|
||||
message.concat(" " + HTTPServer.argName(i) + ": " + HTTPServer.arg(i) + "\n");
|
||||
}
|
||||
HTTPServer.send(404, "text/plain", message);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/////////// End
|
||||
@@ -1,244 +0,0 @@
|
||||
////////
|
||||
// Library: Remote debug - debug over WiFi - for Esp8266 (NodeMCU) or ESP32
|
||||
// Author : Joao Lopes
|
||||
// File : RemoteDebug_Basic.ino
|
||||
// Notes :
|
||||
//
|
||||
// Attention: This library is only for help development. Please not use this in production
|
||||
//
|
||||
// First sample to show how to use it - basic one
|
||||
//
|
||||
// Example of use:
|
||||
//
|
||||
//#ifndef DEBUG_DISABLED
|
||||
// if (Debug.isActive(Debug.<level>)) { // <--- This is very important to reduce overheads and work of debug levels
|
||||
// Debug.printf("bla bla bla: %d %s\n", number, str);
|
||||
// Debug.println("bla bla bla");
|
||||
// }
|
||||
//#endif
|
||||
//
|
||||
// Or short way (prefered if only one debug at time)
|
||||
//
|
||||
// debugA("This is a any (always showed) - var %d", var);
|
||||
//
|
||||
// debugV("This is a verbose - var %d", var);
|
||||
// debugD("This is a debug - var %d", var);
|
||||
// debugI("This is a information - var %d", var);
|
||||
// debugW("This is a warning - var %d", var);
|
||||
// debugE("This is a error - var %d", var);
|
||||
//
|
||||
// debugV("This is println");
|
||||
//
|
||||
//
|
||||
///////
|
||||
|
||||
////// Defines
|
||||
|
||||
// Host name (please change it)
|
||||
|
||||
#define HOST_NAME "remotedebug"
|
||||
|
||||
// Board especific libraries
|
||||
|
||||
#if defined ESP8266 || defined ESP32
|
||||
|
||||
// Use mDNS ? (comment this do disable it)
|
||||
|
||||
#define USE_MDNS true
|
||||
|
||||
// Arduino OTA (uncomment this to enable)
|
||||
|
||||
//#define USE_ARDUINO_OTA true
|
||||
|
||||
#else
|
||||
|
||||
// RemoteDebug library is now only to Espressif boards,
|
||||
// as ESP32 and ESP82266,
|
||||
// If need for another WiFi boards,
|
||||
// please add an issue about this
|
||||
// and we will see if it is possible made the port for your board.
|
||||
// access: https://github.com/JoaoLopesF/RemoteDebug/issues
|
||||
|
||||
#error "The board must be ESP8266 or ESP32"
|
||||
|
||||
#endif // ESP
|
||||
|
||||
//////// Libraries
|
||||
|
||||
#if defined ESP8266
|
||||
|
||||
// Includes of ESP8266
|
||||
|
||||
#include <ESP8266WiFi.h>
|
||||
|
||||
#ifdef USE_MDNS
|
||||
#include <DNSServer.h>
|
||||
#include <ESP8266mDNS.h>
|
||||
#endif
|
||||
|
||||
#elif defined ESP32
|
||||
|
||||
// Includes of ESP32
|
||||
|
||||
#include <WiFi.h>
|
||||
|
||||
#ifdef USE_MDNS
|
||||
#include <DNSServer.h>
|
||||
#include "ESPmDNS.h"
|
||||
#endif
|
||||
|
||||
#endif // ESP
|
||||
|
||||
// Remote debug over WiFi - not recommended for production, only for development
|
||||
|
||||
#include "RemoteDebug.h" //https://github.com/JoaoLopesF/RemoteDebug
|
||||
|
||||
RemoteDebug Debug;
|
||||
|
||||
// SSID and password
|
||||
|
||||
const char* ssid = "........";
|
||||
const char* password = "........";
|
||||
|
||||
// Time
|
||||
|
||||
uint32_t mLastTime = 0;
|
||||
uint32_t mTimeSeconds = 0;
|
||||
|
||||
////// Setup
|
||||
|
||||
void setup() {
|
||||
|
||||
// Initialize the Serial (use only in setup codes)
|
||||
|
||||
Serial.begin(230400);
|
||||
|
||||
// Buildin led of ESP
|
||||
|
||||
pinMode(LED_BUILTIN, OUTPUT);
|
||||
digitalWrite(LED_BUILTIN, LOW);
|
||||
|
||||
// Debug
|
||||
|
||||
Serial.println("**** Setup: initializing ...");
|
||||
|
||||
// WiFi connection
|
||||
|
||||
WiFi.begin(ssid, password);
|
||||
Serial.println("");
|
||||
|
||||
// Wait for connection
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
delay(500);
|
||||
Serial.print(".");
|
||||
}
|
||||
|
||||
Serial.println("");
|
||||
Serial.print("Connected to ");
|
||||
Serial.println(ssid);
|
||||
Serial.print("IP address: ");
|
||||
Serial.println(WiFi.localIP());
|
||||
|
||||
// Register host name in WiFi and mDNS
|
||||
|
||||
String hostNameWifi = HOST_NAME;
|
||||
hostNameWifi.concat(".local");
|
||||
|
||||
#ifdef ESP8266 // Only for it
|
||||
WiFi.hostname(hostNameWifi);
|
||||
#endif
|
||||
|
||||
#ifdef USE_MDNS // Use the MDNS ?
|
||||
|
||||
if (MDNS.begin(HOST_NAME)) {
|
||||
Serial.print("* MDNS responder started. Hostname -> ");
|
||||
Serial.println(HOST_NAME);
|
||||
}
|
||||
|
||||
MDNS.addService("telnet", "tcp", 23);
|
||||
|
||||
#endif
|
||||
|
||||
// Initialize RemoteDebug
|
||||
|
||||
Debug.begin(HOST_NAME); // Initialize the WiFi server
|
||||
|
||||
Debug.setResetCmdEnabled(true); // Enable the reset command
|
||||
|
||||
Debug.showProfiler(true); // Profiler (Good to measure times, to optimize codes)
|
||||
Debug.showColors(true); // Colors
|
||||
|
||||
// End off setup
|
||||
|
||||
Serial.println("* Arduino RemoteDebug Library");
|
||||
Serial.println("*");
|
||||
Serial.print("* WiFI connected. IP address: ");
|
||||
Serial.println(WiFi.localIP());
|
||||
Serial.println("*");
|
||||
Serial.println("* Please use the telnet client (telnet for Mac/Unix or putty and others for Windows)");
|
||||
Serial.println("* or the RemoteDebugApp (in browser: http://joaolopesf.net/remotedebugapp)");
|
||||
Serial.println("*");
|
||||
Serial.println("* This sample will send messages of debug in all levels.");
|
||||
Serial.println("*");
|
||||
Serial.println("* Please try change debug level in client (telnet or web app), to see how it works");
|
||||
Serial.println("*");
|
||||
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// Each second
|
||||
|
||||
if ((millis() - mLastTime) >= 1000) {
|
||||
|
||||
// Time
|
||||
|
||||
mLastTime = millis();
|
||||
|
||||
mTimeSeconds++;
|
||||
|
||||
// Blink the led
|
||||
|
||||
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
|
||||
|
||||
// Debug the time (verbose level)
|
||||
|
||||
debugV("* Time: %u seconds (VERBOSE)", mTimeSeconds);
|
||||
|
||||
if (mTimeSeconds % 5 == 0) { // Each 5 seconds
|
||||
|
||||
// Debug levels
|
||||
|
||||
debugV("* This is a message of debug level VERBOSE");
|
||||
debugD("* This is a message of debug level DEBUG");
|
||||
debugI("* This is a message of debug level INFO");
|
||||
debugW("* This is a message of debug level WARNING");
|
||||
debugE("* This is a message of debug level ERROR");
|
||||
|
||||
// Call a function
|
||||
|
||||
foo();
|
||||
}
|
||||
}
|
||||
|
||||
// RemoteDebug handle
|
||||
|
||||
Debug.handle();
|
||||
|
||||
// Give a time for ESP
|
||||
|
||||
yield();
|
||||
|
||||
}
|
||||
|
||||
// Function example to show a new auto function name of debug* macros
|
||||
|
||||
void foo() {
|
||||
|
||||
uint8_t var = 1;
|
||||
|
||||
debugV("this is a debug - var %u", var);
|
||||
debugV("This is a println");
|
||||
}
|
||||
|
||||
/////////// End
|
||||
@@ -1,893 +0,0 @@
|
||||
////////
|
||||
// Library: Remote debug - debug over WiFi - for Esp8266 (NodeMCU) or ESP32
|
||||
// Author : Joao Lopes
|
||||
// File : RemoteDebugger.ino
|
||||
// Notes :
|
||||
//
|
||||
// Attention: This library is only for help development. Please not use this in production
|
||||
//
|
||||
// This example use the RemoteDebugger library: ao addon to Remotedebug with an simple software debug, based on SerialDebug library
|
||||
// Attention: this library must be installed too
|
||||
// Please open github repo to informations: //https://github.com/JoaoLopesF/RemoteDebugger
|
||||
//
|
||||
// Example of use:
|
||||
//
|
||||
//#ifndef DEBUG_DISABLED
|
||||
// if (Debug.isActive(Debug.<level>)) { // <--- This is very important to reduce overheads and work of debug levels
|
||||
// Debug.printf("bla bla bla: %d %s\n", number, str);
|
||||
// Debug.println("bla bla bla");
|
||||
// }
|
||||
//#endif
|
||||
//
|
||||
// Or short way (prefered if only one debug at time)
|
||||
//
|
||||
// debugA("This is a any (always showed) - var %d", var);
|
||||
//
|
||||
// debugV("This is a verbose - var %d", var);
|
||||
// debugD("This is a debug - var %d", var);
|
||||
// debugI("This is a information - var %d", var);
|
||||
// debugW("This is a warning - var %d", var);
|
||||
// debugE("This is a error - var %d", var);
|
||||
//
|
||||
// debugV("This is println");
|
||||
//
|
||||
///////
|
||||
|
||||
////// Defines
|
||||
|
||||
// Host name (please change it)
|
||||
|
||||
#define HOST_NAME "remotedebug"
|
||||
|
||||
// Board especific libraries
|
||||
|
||||
#if defined ESP8266 || defined ESP32
|
||||
|
||||
// Use mDNS ? (comment this do disable it)
|
||||
|
||||
#define USE_MDNS true
|
||||
|
||||
// Arduino OTA (uncomment this to enable)
|
||||
|
||||
//#define USE_ARDUINO_OTA true
|
||||
|
||||
#else
|
||||
|
||||
// RemoteDebug library is now only to Espressif boards,
|
||||
// as ESP32 and ESP82266,
|
||||
// If need for another WiFi boards,
|
||||
// please add an issue about this
|
||||
// and we will see if it is possible made the port for your board.
|
||||
// access: https://github.com/JoaoLopesF/RemoteDebug/issues
|
||||
|
||||
#error "The board must be ESP8266 or ESP32"
|
||||
|
||||
#endif // ESP
|
||||
|
||||
// Web server (uncomment this to need this)
|
||||
|
||||
//#define WEB_SERVER_ENABLED true
|
||||
|
||||
////// Includes
|
||||
|
||||
#if defined ESP8266
|
||||
|
||||
// Includes of ESP8266
|
||||
|
||||
#include <ESP8266WiFi.h>
|
||||
|
||||
#ifdef USE_MDNS
|
||||
#include <DNSServer.h>
|
||||
#include <ESP8266mDNS.h>
|
||||
#endif
|
||||
|
||||
#ifdef WEB_SERVER_ENABLED
|
||||
#include <ESP8266WebServer.h>
|
||||
#endif
|
||||
|
||||
#elif defined ESP32
|
||||
|
||||
// Includes of ESP32
|
||||
|
||||
#include <WiFi.h>
|
||||
|
||||
#ifdef USE_MDNS
|
||||
#include <DNSServer.h>
|
||||
#include "ESPmDNS.h"
|
||||
#endif
|
||||
|
||||
#ifdef WEB_SERVER_ENABLED
|
||||
#include <WebServer.h>
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#error "Now RemoteDebug support only boards Espressif, as ESP8266 and ESP32"
|
||||
|
||||
#endif // ESP
|
||||
|
||||
// Arduino OTA
|
||||
|
||||
#ifdef USE_ARDUINO_OTA
|
||||
#include <ArduinoOTA.h>
|
||||
#endif
|
||||
|
||||
// HTTP Web server
|
||||
|
||||
#ifdef WEB_SERVER_ENABLED
|
||||
|
||||
#if defined ESP8266
|
||||
|
||||
ESP8266WebServer HTTPServer(80);
|
||||
|
||||
#elif defined ESP32
|
||||
|
||||
WebServer HTTPServer(80);
|
||||
|
||||
#endif
|
||||
|
||||
#endif // WEB_SERVER_ENABLED
|
||||
|
||||
// Remote debug over WiFi - not recommended for production/release, only for development
|
||||
|
||||
// Options for RemoteDebug of this project
|
||||
|
||||
// Attention: read this, before you change any option
|
||||
//
|
||||
// If yot changed it and not works, the compiler is using catching old compiled files
|
||||
// To workaround this:
|
||||
// - If have a clean project option (as Eclipse/Platformio), do it
|
||||
// - or force compiler to compiler all (changing any configuration of board)
|
||||
// - or to this change globally in RemoteDebugCfg.h (on library directory)
|
||||
// - And upload again
|
||||
//
|
||||
// thanks to @22MarioZ for added this issue
|
||||
|
||||
// Disable all debug ?
|
||||
// Important to compile for prodution/release
|
||||
// Disable all debug ? Good to release builds (production)
|
||||
// as nothing of RemoteDebug is compiled, zero overhead :-)
|
||||
// Uncomment the line below, to do it:
|
||||
//#define DEBUG_DISABLED true
|
||||
|
||||
// Disable te auto function feature of RemoteDebug
|
||||
// Good if your code already have func name on debug messages
|
||||
// Uncomment the line below, to do it:
|
||||
//#define DEBUG_DISABLE_AUTO_FUNC true
|
||||
|
||||
// Disable Websocket? This is used with RemoteDebugApp connection
|
||||
// Uncomment the line below, to do it:
|
||||
//#define WEBSOCKET_DISABLED true
|
||||
|
||||
#ifndef WEBSOCKET_DISABLED // Only if Web socket enabled (RemoteDebugApp)
|
||||
// If enabled, you can change the port here (8232 is default)
|
||||
// Uncomment the line below, to do it:
|
||||
//#define WEBSOCKET_PORT 8232
|
||||
|
||||
// Internally, the RemoteDebug uses a local copy of the arduinoWebSockets library (https://github.com/Links2004/arduinoWebSockets)
|
||||
// Due it not in Arduino Library Manager
|
||||
// If your project already use this library,
|
||||
// Uncomment the line below, to do it:
|
||||
//#define USE_LIB_WEBSOCKET true
|
||||
#endif
|
||||
|
||||
|
||||
#include "RemoteDebug.h" //https://github.com/JoaoLopesF/RemoteDebug
|
||||
|
||||
#ifndef DEBUG_DISABLED // Only if debug is not disabled (for production/release)
|
||||
|
||||
// RemoteDebug addon library: RemoteDebugger, an Simple software debugger - based on SerialDebug Library
|
||||
|
||||
#include "RemoteDebugger.h" //https://github.com/JoaoLopesF/RemoteDebugger
|
||||
|
||||
// Instance of RemoteDebug
|
||||
|
||||
RemoteDebug Debug;
|
||||
|
||||
#endif
|
||||
|
||||
// WiFi credentials
|
||||
// Note: if commented, is used the smartConfig
|
||||
// That allow to it in mobile app
|
||||
// See more details in http://www.iotsharing.com/2017/05/how-to-use-smartconfig-on-esp32.html
|
||||
|
||||
//#define WIFI_SSID "..." // your network SSID (name)
|
||||
//#define WIFI_PASS "..." // your network key
|
||||
|
||||
/////// Variables
|
||||
|
||||
// Time
|
||||
|
||||
uint32_t mTimeToSec = 0;
|
||||
|
||||
uint8_t mRunSeconds = 0;
|
||||
uint8_t mRunMinutes = 0;
|
||||
uint8_t mRunHours = 0;
|
||||
|
||||
// Globals for example of debugger
|
||||
|
||||
boolean mBoolean = false;
|
||||
char mChar = 'X';
|
||||
byte mByte = 'Y';
|
||||
int mInt = 1;
|
||||
unsigned int mUInt = 2;
|
||||
long mLong = 3;
|
||||
unsigned long mULong = 4;
|
||||
float mFloat = 5.0f;
|
||||
double mDouble = 6.0;
|
||||
|
||||
String mString = "This is a string";
|
||||
String mStringLarge = "This is a large stringggggggggggggggggggggggggggggggggggggggggggggg";
|
||||
|
||||
char mCharArray[] = "This is a char array";
|
||||
char mCharArrayLarge[] = "This is a large char arrayyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy";
|
||||
|
||||
int mIntArray[5] = {1 ,2 ,3, 4, 5};
|
||||
|
||||
//const char mCharArrayConst[] = "This is const";
|
||||
|
||||
////// Setup
|
||||
|
||||
void setup() {
|
||||
|
||||
// Initialize the Serial (use only in setup codes)
|
||||
|
||||
Serial.begin(230400);
|
||||
|
||||
// Buildin led
|
||||
|
||||
#ifdef LED_BUILTIN
|
||||
pinMode(LED_BUILTIN, OUTPUT);
|
||||
digitalWrite(LED_BUILTIN, LOW);
|
||||
#endif
|
||||
|
||||
// Connect WiFi
|
||||
|
||||
connectWiFi();
|
||||
|
||||
// Host name of WiFi
|
||||
|
||||
#ifdef ESP8266
|
||||
WiFi.hostname(HOST_NAME);
|
||||
#endif
|
||||
|
||||
#ifdef USE_ARDUINO_OTA
|
||||
// Update over air (OTA)
|
||||
|
||||
initializeOTA();
|
||||
#endif
|
||||
|
||||
// Register host name in mDNS
|
||||
|
||||
#if defined USE_MDNS && defined HOST_NAME
|
||||
|
||||
if (MDNS.begin(HOST_NAME)) {
|
||||
Serial.print("* MDNS responder started. Hostname -> ");
|
||||
Serial.println(HOST_NAME);
|
||||
}
|
||||
|
||||
// Register the services
|
||||
|
||||
#ifdef WEB_SERVER_ENABLED
|
||||
MDNS.addService("http", "tcp", 80); // Web server
|
||||
#endif
|
||||
|
||||
#ifndef DEBUG_DISABLED
|
||||
MDNS.addService("telnet", "tcp", 23);// Telnet server RemoteDebug
|
||||
#endif
|
||||
|
||||
#endif // MDNS
|
||||
|
||||
// HTTP web server
|
||||
|
||||
#ifdef WEB_SERVER_ENABLED
|
||||
HTTPServer.on("/", handleRoot);
|
||||
|
||||
HTTPServer.onNotFound(handleNotFound);
|
||||
|
||||
HTTPServer.begin();
|
||||
|
||||
Serial.println("* HTTP server started");
|
||||
#endif
|
||||
|
||||
#ifndef DEBUG_DISABLED // Only for development
|
||||
|
||||
// Initialize RemoteDebug
|
||||
|
||||
Debug.begin(HOST_NAME); // Initialize the WiFi server
|
||||
|
||||
//Debug.setPassword("r3m0t0."); // Password on telnet connection ?
|
||||
|
||||
Debug.setResetCmdEnabled(true); // Enable the reset command
|
||||
|
||||
Debug.showProfiler(true); // Profiler (Good to measure times, to optimize codes)
|
||||
|
||||
Debug.showColors(true); // Colors
|
||||
|
||||
// Debug.setSerialEnabled(true); // if you wants serial echo - only recommended if ESP is plugged in USB
|
||||
|
||||
// Project commands
|
||||
|
||||
String helpCmd = "bench1 - Benchmark 1\n";
|
||||
helpCmd.concat("bench2 - Benchmark 2");
|
||||
|
||||
Debug.setHelpProjectsCmds(helpCmd);
|
||||
Debug.setCallBackProjectCmds(&processCmdRemoteDebug);
|
||||
|
||||
// Init the simple software debugger, based on SerialDebug library
|
||||
|
||||
#ifndef DEBUG_DISABLE_DEBUGGER
|
||||
|
||||
Debug.initDebugger(debugGetDebuggerEnabled, debugHandleDebugger, debugGetHelpDebugger, debugProcessCmdDebugger); // Set the callbacks
|
||||
|
||||
debugInitDebugger(&Debug); // Init the debugger
|
||||
|
||||
// Add Functions and global variables to RemoteDebuggger
|
||||
|
||||
// Notes: descriptions is optionals
|
||||
|
||||
// Add functions that can called from SerialDebug
|
||||
|
||||
if (debugAddFunctionVoid("benchInt", &benchInt) >= 0) {
|
||||
debugSetLastFunctionDescription("To run a benchmark of integers");
|
||||
}
|
||||
if (debugAddFunctionVoid("benchFloat", &benchFloat) >= 0) {
|
||||
debugSetLastFunctionDescription("To run a benchmark of float");
|
||||
}
|
||||
if (debugAddFunctionVoid("benchGpio", &benchGpio) >= 0) {
|
||||
debugSetLastFunctionDescription("To run a benchmark of Gpio operations");
|
||||
}
|
||||
if (debugAddFunctionVoid("benchAll", &benchAll) >= 0) {
|
||||
debugSetLastFunctionDescription("To run all benchmarks");
|
||||
}
|
||||
|
||||
if (debugAddFunctionStr("funcArgStr", &funcArgStr) >= 0) {
|
||||
debugSetLastFunctionDescription("To run with String arg");
|
||||
}
|
||||
if (debugAddFunctionChar("funcArgChar", &funcArgChar) >= 0) {
|
||||
debugSetLastFunctionDescription("To run with Character arg");
|
||||
}
|
||||
if (debugAddFunctionInt("funcArgInt", &funcArgInt) >= 0) {
|
||||
debugSetLastFunctionDescription("To run with Integer arg");
|
||||
}
|
||||
|
||||
// Add global variables that can showed/changed from SerialDebug
|
||||
// Note: Only global, if pass local for SerialDebug, can be dangerous
|
||||
|
||||
if (debugAddGlobalUInt8_t("mRunSeconds", &mRunSeconds) >= 0) {
|
||||
debugSetLastGlobalDescription("Seconds of run time");
|
||||
}
|
||||
if (debugAddGlobalUInt8_t("mRunMinutes", &mRunMinutes) >= 0) {
|
||||
debugSetLastGlobalDescription("Minutes of run time");
|
||||
}
|
||||
if (debugAddGlobalUInt8_t("mRunHours", &mRunHours) >= 0) {
|
||||
debugSetLastGlobalDescription("Hours of run time");
|
||||
}
|
||||
|
||||
// Note: easy way, no descriptions ....
|
||||
|
||||
debugAddGlobalBoolean("mBoolean", &mBoolean);
|
||||
debugAddGlobalChar("mChar", &mChar);
|
||||
debugAddGlobalByte("mByte", &mByte);
|
||||
debugAddGlobalInt("mInt", &mInt);
|
||||
debugAddGlobalUInt("mUInt", &mUInt);
|
||||
debugAddGlobalLong("mLong", &mLong);
|
||||
debugAddGlobalULong("mULong", &mULong);
|
||||
debugAddGlobalFloat("mFloat", &mFloat);
|
||||
debugAddGlobalDouble("mDouble", &mDouble);
|
||||
|
||||
debugAddGlobalString("mString", &mString);
|
||||
|
||||
// Note: For char arrays, not use the '&'
|
||||
|
||||
debugAddGlobalCharArray("mCharArray", mCharArray);
|
||||
|
||||
// Note, here inform to show only 20 characteres of this string or char array
|
||||
|
||||
debugAddGlobalString("mStringLarge", &mStringLarge, 20);
|
||||
|
||||
debugAddGlobalCharArray("mCharArrayLarge",
|
||||
mCharArrayLarge, 20);
|
||||
|
||||
// For arrays, need add for each item (not use loop for it, due the name can not by a variable)
|
||||
// Notes: Is good added arrays in last order, to help see another variables
|
||||
// In next versions, we can have a helper to do it in one command
|
||||
|
||||
debugAddGlobalInt("mIntArray[0]", &mIntArray[0]);
|
||||
debugAddGlobalInt("mIntArray[1]", &mIntArray[1]);
|
||||
debugAddGlobalInt("mIntArray[2]", &mIntArray[2]);
|
||||
debugAddGlobalInt("mIntArray[3]", &mIntArray[3]);
|
||||
debugAddGlobalInt("mIntArray[4]", &mIntArray[4]);
|
||||
|
||||
// Add watches for some global variables
|
||||
// Note: watches can be added/changed in serial monitor too
|
||||
|
||||
// Watch -> mBoolean when changed (put 0 on value)
|
||||
|
||||
debugAddWatchBoolean("mBoolean", DEBUG_WATCH_CHANGED, 0);
|
||||
|
||||
// Watch -> mRunSeconds == 10
|
||||
|
||||
debugAddWatchUInt8_t("mRunSeconds", DEBUG_WATCH_EQUAL, 10);
|
||||
|
||||
// Watch -> mRunMinutes > 3
|
||||
|
||||
debugAddWatchUInt8_t("mRunMinutes", DEBUG_WATCH_GREAT, 3);
|
||||
|
||||
// Watch -> mRunMinutes == mRunSeconds (just for test)
|
||||
|
||||
debugAddWatchCross("mRunMinutes", DEBUG_WATCH_EQUAL, "mRunSeconds");
|
||||
|
||||
#endif
|
||||
|
||||
// End of setup - show IP
|
||||
|
||||
Serial.println("* Arduino RemoteDebug Library");
|
||||
Serial.println("*");
|
||||
Serial.print("* WiFI connected. IP address: ");
|
||||
Serial.println(WiFi.localIP());
|
||||
Serial.println("*");
|
||||
Serial.println("* Please use the telnet client (telnet for Mac/Unix or putty and others for Windows)");
|
||||
Serial.println("* or the RemoteDebugApp (in browser: http://joaolopesf.net/remotedebugapp)");
|
||||
Serial.println("*");
|
||||
Serial.println("* This sample will send messages of debug in all levels.");
|
||||
Serial.println("*");
|
||||
Serial.println("* Please try change debug level in client (telnet or web app), to see how it works");
|
||||
Serial.println("*");
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
void loop() {
|
||||
|
||||
#ifndef DEBUG_DISABLED
|
||||
// Time of begin of this loop
|
||||
uint32_t timeBeginLoop = millis();
|
||||
#endif
|
||||
|
||||
// Each second
|
||||
|
||||
if (millis() >= mTimeToSec) {
|
||||
|
||||
// Time
|
||||
|
||||
mTimeToSec = millis() + 1000;
|
||||
|
||||
// Count run time (just a test - for real suggest the TimeLib and NTP, if board have WiFi)
|
||||
|
||||
mRunSeconds++;
|
||||
|
||||
if (mRunSeconds == 60) {
|
||||
mRunMinutes++;
|
||||
mRunSeconds = 0;
|
||||
}
|
||||
if (mRunMinutes == 60) {
|
||||
mRunHours++;
|
||||
mRunMinutes = 0;
|
||||
}
|
||||
if (mRunHours == 24) {
|
||||
mRunHours = 0;
|
||||
}
|
||||
|
||||
// Blink the led
|
||||
|
||||
#ifdef LED_BUILTIN
|
||||
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
|
||||
#endif
|
||||
|
||||
// Debug the time (verbose level)
|
||||
|
||||
debugV("* Time: %u seconds (VERBOSE)", mRunSeconds);
|
||||
|
||||
if (mRunSeconds % 5 == 0) { // Each 5 seconds
|
||||
|
||||
// Debug levels
|
||||
|
||||
debugV("* This is a message of debug level VERBOSE");
|
||||
debugD("* This is a message of debug level DEBUG");
|
||||
debugI("* This is a message of debug level INFO");
|
||||
debugW("* This is a message of debug level WARNING");
|
||||
debugE("* This is a message of debug level ERROR");
|
||||
|
||||
|
||||
// RemoteDebug isActive? Use this RemoteDebug sintaxe if you need process anything only for debug
|
||||
// It is good to avoid overheads (this is only use that is suggest to use isActive)
|
||||
// Note this need be surrounded by DEBUG_DISABLED precompiler condition to not compile for production/release
|
||||
|
||||
#ifndef DEBUG_DISABLED
|
||||
|
||||
if (Debug.isActive(Debug.VERBOSE)) {
|
||||
|
||||
Debug.println("Calling a foo function");
|
||||
Debug.printf("At time of %d sec.\n", mRunSeconds);
|
||||
|
||||
// Call a function
|
||||
|
||||
foo();
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
////// Services on Wifi
|
||||
|
||||
#ifdef USE_ARDUINO_OTA
|
||||
// Update over air (OTA)
|
||||
|
||||
ArduinoOTA.handle();
|
||||
#endif
|
||||
|
||||
#ifdef WEB_SERVER_ENABLED
|
||||
// Web server
|
||||
|
||||
HTTPServer.handleClient();
|
||||
#endif
|
||||
|
||||
#ifndef DEBUG_DISABLED
|
||||
// Remote debug over telnet
|
||||
|
||||
Debug.handle();
|
||||
#endif
|
||||
|
||||
// Give a time for ESP
|
||||
|
||||
yield();
|
||||
|
||||
#ifndef DEBUG_DISABLED
|
||||
// Show a debug - warning if time of these loop is over 50 (info) or 100 ms (warning)
|
||||
|
||||
uint32_t time = (millis() - timeBeginLoop);
|
||||
|
||||
if (time > 100) {
|
||||
debugI("* Time elapsed for the loop: %u ms.", time);
|
||||
} else if (time > 200) {
|
||||
debugW("* Time elapsed for the loop: %u ms.", time);
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Function example to show a new auto function name of debug* macros
|
||||
|
||||
void foo() {
|
||||
|
||||
uint8_t var = 1;
|
||||
|
||||
debugV("this is a debug - var %u", var);
|
||||
debugV("This is a println");
|
||||
}
|
||||
|
||||
#ifndef DEBUG_DISABLED
|
||||
|
||||
// Process commands from RemoteDebug
|
||||
|
||||
void processCmdRemoteDebug() {
|
||||
|
||||
String lastCmd = Debug.getLastCommand();
|
||||
|
||||
if (lastCmd == "bench1") {
|
||||
|
||||
// Benchmark 1 - Printf
|
||||
|
||||
debugA("* Benchmark 1 - one Printf");
|
||||
|
||||
|
||||
uint32_t timeBegin = millis();
|
||||
uint8_t times = 50;
|
||||
|
||||
for (uint8_t i = 1; i <= times; i++) {
|
||||
debugA("%u - 1234567890 - AAAA", i);
|
||||
|
||||
}
|
||||
|
||||
debugA("* Time elapsed for %u printf: %ld ms.\n", times,
|
||||
(millis() - timeBegin));
|
||||
|
||||
} else if (lastCmd == "bench2") {
|
||||
|
||||
// Benchmark 2 - Print/println
|
||||
|
||||
debugA("* Benchmark 2 - Print/Println");
|
||||
|
||||
uint32_t timeBegin = millis();
|
||||
uint8_t times = 50;
|
||||
|
||||
for (uint8_t i = 1; i <= times; i++) {
|
||||
if (Debug.isActive(Debug.ANY)) {
|
||||
Debug.print(i);
|
||||
Debug.print(" - 1234567890");
|
||||
Debug.println(" - AAAA");
|
||||
}
|
||||
}
|
||||
|
||||
debugA("* Time elapsed for %u printf: %ld ms.\n", times,
|
||||
(millis() - timeBegin));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
////// Benchmarks - simple
|
||||
|
||||
// Note: how it as called by SerialDebug, must be return type void and no args
|
||||
// Note: Flash F variables is not used during the tests, due it is slow to use in loops
|
||||
|
||||
#define BENCHMARK_EXECS 10000
|
||||
|
||||
// Simple benckmark of integers
|
||||
|
||||
void benchInt() {
|
||||
|
||||
int test = 0;
|
||||
|
||||
for (int i = 0; i < BENCHMARK_EXECS; i++) {
|
||||
|
||||
// Some integer operations
|
||||
|
||||
test++;
|
||||
test += 2;
|
||||
test -= 2;
|
||||
test *= 2;
|
||||
test /= 2;
|
||||
}
|
||||
|
||||
// Note: Debug always is used here
|
||||
|
||||
debugA("*** Benchmark of integers. %u exec.", BENCHMARK_EXECS);
|
||||
|
||||
}
|
||||
|
||||
// Simple benckmark of floats
|
||||
|
||||
void benchFloat() {
|
||||
|
||||
float test = 0;
|
||||
|
||||
for (int i = 0; i < BENCHMARK_EXECS; i++) {
|
||||
|
||||
// Some float operations
|
||||
|
||||
test++;
|
||||
test += 2;
|
||||
test -= 2;
|
||||
test *= 2;
|
||||
test /= 2;
|
||||
}
|
||||
|
||||
// Note: Debug always is used here
|
||||
|
||||
debugA("*** Benchmark of floats, %u exec.", BENCHMARK_EXECS);
|
||||
|
||||
}
|
||||
|
||||
// Simple benckmark of GPIO
|
||||
|
||||
void benchGpio() {
|
||||
|
||||
// const int execs = (BENCHMARK_EXECS / 10); // Reduce it
|
||||
const int execs = BENCHMARK_EXECS;
|
||||
|
||||
for (int i = 0; i < execs; i++) {
|
||||
|
||||
// Some GPIO operations
|
||||
|
||||
digitalWrite(LED_BUILTIN, HIGH);
|
||||
digitalRead(LED_BUILTIN);
|
||||
digitalWrite(LED_BUILTIN, LOW);
|
||||
|
||||
analogRead(A0);
|
||||
analogRead(A0);
|
||||
analogRead(A0);
|
||||
|
||||
}
|
||||
|
||||
// Note: Debug always is used here
|
||||
|
||||
debugA("*** Benchmark of GPIO. %u exec.", execs);
|
||||
|
||||
}
|
||||
|
||||
// Run all benchmarks
|
||||
|
||||
void benchAll() {
|
||||
|
||||
benchInt();
|
||||
benchFloat();
|
||||
benchGpio();
|
||||
|
||||
// Note: Debug always is used here
|
||||
|
||||
debugA("*** All Benchmark done.");
|
||||
|
||||
}
|
||||
|
||||
// Example functions with argument (only 1) to call from serial monitor
|
||||
// Note others types is not yet available in this version of SerialDebug
|
||||
|
||||
void funcArgStr (String str) {
|
||||
|
||||
debugA("*** called with arg.: %s", str.c_str());
|
||||
}
|
||||
void funcArgChar (char character) {
|
||||
|
||||
debugA("*** called with arg.: %c", character);
|
||||
}
|
||||
void funcArgInt (int number) {
|
||||
|
||||
debugA("*** called with arg.: %d", number);
|
||||
}
|
||||
|
||||
////// WiFi
|
||||
|
||||
void connectWiFi() {
|
||||
|
||||
////// Connect WiFi
|
||||
|
||||
#ifdef EM_DEPURACAO
|
||||
Serial.println("*** connectWiFi: begin conection ...");
|
||||
#endif
|
||||
|
||||
#ifdef ESP32
|
||||
// ESP32 // TODO: is really necessary ?
|
||||
WiFi.enableSTA(true);
|
||||
delay(100);
|
||||
#endif
|
||||
|
||||
// Connect with SSID and password stored
|
||||
|
||||
#ifndef WIFI_SSID
|
||||
WiFi.begin();
|
||||
#else
|
||||
WiFi.begin(WIFI_SSID, WIFI_PASS);
|
||||
#endif
|
||||
|
||||
// Wait connection
|
||||
|
||||
uint32_t timeout = millis() + 20000; // Time out
|
||||
|
||||
while (WiFi.status() != WL_CONNECTED && millis() < timeout) {
|
||||
delay(250);
|
||||
Serial.print(".");
|
||||
}
|
||||
|
||||
// Not connected yet?
|
||||
|
||||
if (WiFi.status() != WL_CONNECTED) {
|
||||
|
||||
#ifndef WIFI_SSID
|
||||
// SmartConfig
|
||||
|
||||
WiFi.beginSmartConfig();
|
||||
|
||||
// Wait for SmartConfig packet from mobile
|
||||
|
||||
Serial.println("connectWiFi: Waiting for SmartConfig.");
|
||||
|
||||
while (!WiFi.smartConfigDone()) {
|
||||
delay(500);
|
||||
Serial.print(".");
|
||||
}
|
||||
|
||||
Serial.println("");
|
||||
Serial.println("connectWiFi: SmartConfig received.");
|
||||
|
||||
// Wait for WiFi to connect to AP
|
||||
|
||||
Serial.println("connectWiFi: Waiting for WiFi");
|
||||
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
delay(500);
|
||||
Serial.print(".");
|
||||
}
|
||||
#else
|
||||
Serial.println("Not possible connect to WiFi, rebooting");
|
||||
ESP.restart();
|
||||
#endif
|
||||
}
|
||||
|
||||
// End
|
||||
|
||||
Serial.println("");
|
||||
Serial.print("connectWiFi: connect a ");
|
||||
Serial.println(WiFi.SSID());
|
||||
Serial.print("IP: ");
|
||||
Serial.println(WiFi.localIP().toString());
|
||||
|
||||
}
|
||||
|
||||
#ifdef USE_ARDUINO_OTA
|
||||
|
||||
// Initialize o Arduino OTA
|
||||
|
||||
void initializeOTA() {
|
||||
|
||||
// TODO: option to authentication (password)
|
||||
|
||||
#if defined ESP8266
|
||||
|
||||
ArduinoOTA.onStart([]() {
|
||||
Serial.println("* OTA: Start");
|
||||
});
|
||||
ArduinoOTA.onEnd([]() {
|
||||
Serial.println("\n*OTA: End");
|
||||
});
|
||||
ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
|
||||
Serial.printf("*OTA: Progress: %u%%\r", (progress / (total / 100)));
|
||||
});
|
||||
ArduinoOTA.onError([](ota_error_t error) {
|
||||
Serial.printf("*OTA: Error[%u]: ", error);
|
||||
if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
|
||||
else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
|
||||
else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
|
||||
else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
|
||||
else if (error == OTA_END_ERROR) Serial.println("End Failed");
|
||||
});
|
||||
|
||||
#elif defined ESP32
|
||||
|
||||
// ArduinoOTA
|
||||
|
||||
ArduinoOTA.onStart([]() {
|
||||
String type;
|
||||
if (ArduinoOTA.getCommand() == U_FLASH)
|
||||
type = "sketch";
|
||||
else // U_SPIFFS
|
||||
type = "filesystem";
|
||||
Serial.println("Start updating " + type);
|
||||
}).onEnd([]() {
|
||||
Serial.println("\nEnd");
|
||||
}).onProgress([](unsigned int progress, unsigned int total) {
|
||||
Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
|
||||
}).onError([](ota_error_t error) {
|
||||
Serial.printf("Error[%u]: ", error);
|
||||
if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
|
||||
else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
|
||||
else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
|
||||
else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
|
||||
else if (error == OTA_END_ERROR) Serial.println("End Failed");
|
||||
});
|
||||
|
||||
#endif
|
||||
|
||||
// Begin
|
||||
|
||||
ArduinoOTA.begin();
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef WEB_SERVER_ENABLED
|
||||
|
||||
/////////// Handles
|
||||
|
||||
void handleRoot() {
|
||||
|
||||
// Root web page
|
||||
|
||||
HTTPServer.send(200, "text/plain", "hello from esp - RemoteDebug Sample!");
|
||||
}
|
||||
|
||||
void handleNotFound(){
|
||||
|
||||
// Page not Found
|
||||
|
||||
String message = "File Not Found\n\n";
|
||||
message.concat("URI: ");
|
||||
message.concat(HTTPServer.uri());
|
||||
message.concat("\nMethod: ");
|
||||
message.concat((HTTPServer.method() == HTTP_GET)?"GET":"POST");
|
||||
message.concat("\nArguments: ");
|
||||
message.concat(HTTPServer.args());
|
||||
message.concat("\n");
|
||||
for (uint8_t i=0; i<HTTPServer.args(); i++){
|
||||
message.concat(" " + HTTPServer.argName(i) + ": " + HTTPServer.arg(i) + "\n");
|
||||
}
|
||||
HTTPServer.send(404, "text/plain", message);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/////////// End
|
||||
|
Before Width: | Height: | Size: 344 KiB |
|
Before Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 163 KiB |
|
Before Width: | Height: | Size: 89 KiB |
|
Before Width: | Height: | Size: 270 KiB |
|
Before Width: | Height: | Size: 462 KiB |
@@ -1,14 +0,0 @@
|
||||
{
|
||||
"name": "RemoteDebug",
|
||||
"keywords": "Debug, Remote, Telnet, WiFi",
|
||||
"description": "A library for Arduino to debug projects over WiFi, with web app or telnet client, with Print commands like Serial Monitor.",
|
||||
"repository":
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://github.com/JoaoLopesF/RemoteDebug.git"
|
||||
},
|
||||
"version": "3.0.5",
|
||||
"frameworks": "arduino",
|
||||
"platforms": "*"
|
||||
}
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
name=RemoteDebug
|
||||
version=3.0.5
|
||||
author=Joao Lopes
|
||||
maintainer=Joao Lopes
|
||||
sentence=A library for Arduino to debug projects over WiFi, with web app or telnet client, with Print commands like Serial Monitor.
|
||||
paragraph=
|
||||
category=Communication
|
||||
url=https://github.com/JoaoLopesF/RemoteDebug
|
||||
architectures=*
|
||||
@@ -1,459 +0,0 @@
|
||||
/*
|
||||
* Header for RemoteDebug
|
||||
*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2019 Joao Lopes
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef REMOTEDEBUG_H
|
||||
#define REMOTEDEBUG_H
|
||||
#pragma once
|
||||
|
||||
///// RemoteDebug configuration
|
||||
|
||||
#include "RemoteDebugCfg.h"
|
||||
|
||||
// Debug enabled ?
|
||||
|
||||
#ifndef DEBUG_DISABLED
|
||||
|
||||
//////// Defines
|
||||
|
||||
// New color system (comment this to return to old system) - 2019-02-27
|
||||
|
||||
#define COLOR_NEW_SYSTEM true
|
||||
|
||||
// ANSI Colors
|
||||
|
||||
#define COLOR_RESET "\x1B[0m"
|
||||
|
||||
#define COLOR_BLACK "\x1B[0;30m"
|
||||
#define COLOR_RED "\x1B[0;31m"
|
||||
#define COLOR_GREEN "\x1B[0;32m"
|
||||
#define COLOR_YELLOW "\x1B[0;33m"
|
||||
#define COLOR_BLUE "\x1B[0;34m"
|
||||
#define COLOR_MAGENTA "\x1B[0;35m"
|
||||
#define COLOR_CYAN "\x1B[0;36m"
|
||||
#define COLOR_WHITE "\x1B[0;37m"
|
||||
|
||||
#define COLOR_DARK_BLACK "\x1B[1;30m"
|
||||
|
||||
#define COLOR_LIGHT_RED "\x1B[1;31m"
|
||||
#define COLOR_LIGHT_GREEN "\x1B[1;32m"
|
||||
#define COLOR_LIGHT_YELLOW "\x1B[1;33m"
|
||||
#define COLOR_LIGHT_BLUE "\x1B[1;34m"
|
||||
#define COLOR_LIGHT_MAGENTA "\x1B[1;35m"
|
||||
#define COLOR_LIGHT_CYAN "\x1B[1;36m"
|
||||
#define COLOR_LIGHT_WHITE "\x1B[1;37m"
|
||||
|
||||
#define COLOR_BACKGROUND_BLACK "\x1B[40m"
|
||||
#define COLOR_BACKGROUND_RED "\x1B[41m"
|
||||
#define COLOR_BACKGROUND_GREEN "\x1B[42m"
|
||||
#define COLOR_BACKGROUND_YELLOW "\x1B[43m"
|
||||
#define COLOR_BACKGROUND_BLUE "\x1B[44m"
|
||||
#define COLOR_BACKGROUND_MAGENTA "\x1B[45m"
|
||||
#define COLOR_BACKGROUND_CYAN "\x1B[46m"
|
||||
#define COLOR_BACKGROUND_WHITE "\x1B[47m"
|
||||
|
||||
#ifdef COLOR_NEW_SYSTEM
|
||||
// New system of Colors
|
||||
// Note: this colors is not equals to SerialDebug colors, due using standard 16 colors of Ansi, for compatibility
|
||||
#define COLOR_VERBOSE COLOR_GREEN
|
||||
#define COLOR_DEBUG COLOR_LIGHT_GREEN
|
||||
//#define COLOR_INFO COLOR_YELLOW
|
||||
//#define COLOR_WARNING COLOR_CYAN
|
||||
//#define COLOR_ERROR COLOR_RED
|
||||
#define COLOR_INFO COLOR_LIGHT_YELLOW
|
||||
#define COLOR_WARNING COLOR_LIGHT_CYAN
|
||||
#define COLOR_ERROR COLOR_LIGHT_RED
|
||||
#define COLOR_RAW COLOR_WHITE // COLOR_MAGENTA
|
||||
#endif
|
||||
|
||||
//////// Includes
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "Print.h"
|
||||
|
||||
// ESP8266 or ESP32 ?
|
||||
|
||||
#if defined(ESP8266)
|
||||
|
||||
#include <ESP8266WiFi.h>
|
||||
|
||||
#elif defined(ESP32)
|
||||
|
||||
#include <WiFi.h>
|
||||
|
||||
#else
|
||||
|
||||
#error "Only for ESP8266 or ESP32"
|
||||
|
||||
#endif
|
||||
|
||||
////// Shortcuts macros
|
||||
|
||||
// Auto function for debug macros?
|
||||
|
||||
#ifndef DEBUG_DISABLE_AUTO_FUNC // With auto func
|
||||
|
||||
#ifdef ESP32
|
||||
|
||||
// ESP32 -> Multicore - show core id ?
|
||||
|
||||
#define DEBUG_AUTO_CORE true // debug show core id ? (comment to disable it)
|
||||
|
||||
#ifdef DEBUG_AUTO_CORE
|
||||
|
||||
#define rdebugA(fmt, ...) if (Debug.isActive(Debug.ANY)) Debug.printf("(%s)(C%d) " fmt, __func__, xPortGetCoreID(), ##__VA_ARGS__)
|
||||
#define rdebugP(fmt, ...) if (Debug.isActive(Debug.PROFILER)) Debug.printf("(%s)(C%d) " fmt, __func__, xPortGetCoreID(), ##__VA_ARGS__)
|
||||
#define rdebugV(fmt, ...) if (Debug.isActive(Debug.VERBOSE)) Debug.printf("(%s)(C%d) " fmt, __func__, xPortGetCoreID(), ##__VA_ARGS__)
|
||||
#define rdebugD(fmt, ...) if (Debug.isActive(Debug.DEBUG)) Debug.printf("(%s)(C%d) " fmt, __func__, xPortGetCoreID(), ##__VA_ARGS__)
|
||||
#define rdebugI(fmt, ...) if (Debug.isActive(Debug.INFO)) Debug.printf("(%s)(C%d) " fmt, __func__, xPortGetCoreID(), ##__VA_ARGS__)
|
||||
#define rdebugW(fmt, ...) if (Debug.isActive(Debug.WARNING)) Debug.printf("(%s)(C%d) " fmt, __func__, xPortGetCoreID(), ##__VA_ARGS__)
|
||||
#define rdebugE(fmt, ...) if (Debug.isActive(Debug.ERROR)) Debug.printf("(%s)(C%d) " fmt, __func__, xPortGetCoreID(), ##__VA_ARGS__)
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef DEBUG_AUTO_CORE // No auto core or for ESP8266
|
||||
|
||||
#define rdebugA(fmt, ...) if (Debug.isActive(Debug.ANY)) Debug.printf("(%s) " fmt, __func__, ##__VA_ARGS__)
|
||||
#define rdebugP(fmt, ...) if (Debug.isActive(Debug.PROFILER)) Debug.printf("(%s) " fmt, __func__, ##__VA_ARGS__)
|
||||
#define rdebugV(fmt, ...) if (Debug.isActive(Debug.VERBOSE)) Debug.printf("(%s) " fmt, __func__, ##__VA_ARGS__)
|
||||
#define rdebugD(fmt, ...) if (Debug.isActive(Debug.DEBUG)) Debug.printf("(%s) " fmt, __func__, ##__VA_ARGS__)
|
||||
#define rdebugI(fmt, ...) if (Debug.isActive(Debug.INFO)) Debug.printf("(%s) " fmt, __func__, ##__VA_ARGS__)
|
||||
#define rdebugW(fmt, ...) if (Debug.isActive(Debug.WARNING)) Debug.printf("(%s) " fmt, __func__, ##__VA_ARGS__)
|
||||
#define rdebugE(fmt, ...) if (Debug.isActive(Debug.ERROR)) Debug.printf("(%s) " fmt, __func__, ##__VA_ARGS__)
|
||||
|
||||
#endif
|
||||
|
||||
#else // Without auto func
|
||||
|
||||
#define rdebugA(fmt, ...) if (Debug.isActive(Debug.ANY)) Debug.printf(fmt, ##__VA_ARGS__)
|
||||
#define rdebugP(fmt, ...) if (Debug.isActive(Debug.PROFILER)) Debug.printf(fmt, ##__VA_ARGS__)
|
||||
#define rdebugV(fmt, ...) if (Debug.isActive(Debug.VERBOSE)) Debug.printf(fmt, ##__VA_ARGS__)
|
||||
#define rdebugD(fmt, ...) if (Debug.isActive(Debug.DEBUG)) Debug.printf(fmt, ##__VA_ARGS__)
|
||||
#define rdebugI(fmt, ...) if (Debug.isActive(Debug.INFO)) Debug.printf(fmt, ##__VA_ARGS__)
|
||||
#define rdebugW(fmt, ...) if (Debug.isActive(Debug.WARNING)) Debug.printf(fmt, ##__VA_ARGS__)
|
||||
#define rdebugE(fmt, ...) if (Debug.isActive(Debug.ERROR)) Debug.printf(fmt, ##__VA_ARGS__)
|
||||
|
||||
#endif
|
||||
|
||||
// With newline
|
||||
|
||||
#define rdebugAln(fmt, ...) rdebugA(fmt "\n", ##__VA_ARGS__)
|
||||
#define rdebugPln(fmt, ...) rdebugP(fmt "\n", ##__VA_ARGS__)
|
||||
#define rdebugVln(fmt, ...) rdebugV(fmt "\n", ##__VA_ARGS__)
|
||||
#define rdebugDln(fmt, ...) rdebugD(fmt "\n", ##__VA_ARGS__)
|
||||
#define rdebugIln(fmt, ...) rdebugI(fmt "\n", ##__VA_ARGS__)
|
||||
#define rdebugWln(fmt, ...) rdebugW(fmt "\n", ##__VA_ARGS__)
|
||||
#define rdebugEln(fmt, ...) rdebugE(fmt "\n", ##__VA_ARGS__)
|
||||
|
||||
// For old versions compatibility
|
||||
|
||||
#define rdebug(fmt, ...) rdebugA(fmt, ##__VA_ARGS__)
|
||||
|
||||
// Another way - for compatibility
|
||||
|
||||
#define DEBUG(fmt, ...) rdebugA(fmt, ##__VA_ARGS__)
|
||||
|
||||
#define DEBUG_A(fmt, ...) rdebugA(fmt, ##__VA_ARGS__)
|
||||
#define DEBUG_P(fmt, ...) rdebugP(fmt, ##__VA_ARGS__)
|
||||
#define DEBUG_V(fmt, ...) rdebugV(fmt, ##__VA_ARGS__)
|
||||
#define DEBUG_D(fmt, ...) rdebugD(fmt, ##__VA_ARGS__)
|
||||
#define DEBUG_I(fmt, ...) rdebugI(fmt, ##__VA_ARGS__)
|
||||
#define DEBUG_W(fmt, ...) rdebugW(fmt, ##__VA_ARGS__)
|
||||
#define DEBUG_E(fmt, ...) rdebugE(fmt, ##__VA_ARGS__)
|
||||
|
||||
// New way: To compatibility with SerialDebug (can use RemoteDebug or SerialDebug)
|
||||
// This is my favorite :)
|
||||
|
||||
#define debugV(fmt, ...) rdebugVln(fmt, ##__VA_ARGS__)
|
||||
#define debugD(fmt, ...) rdebugDln(fmt, ##__VA_ARGS__)
|
||||
#define debugI(fmt, ...) rdebugIln(fmt, ##__VA_ARGS__)
|
||||
#define debugW(fmt, ...) rdebugWln(fmt, ##__VA_ARGS__)
|
||||
#define debugE(fmt, ...) rdebugEln(fmt, ##__VA_ARGS__)
|
||||
#define debugA(fmt, ...) rdebugAln(fmt, ##__VA_ARGS__)
|
||||
|
||||
#define debugHandle() Debug.handle()
|
||||
|
||||
// Macros used by code converter for codes with several prints to only message
|
||||
// due the converter cannot
|
||||
// convert severals Serial.print in one debug* macro.
|
||||
|
||||
#define rprintV(x, ...) if (Debug.isActive(Debug.VERBOSE)) Debug.print(x, ##__VA_ARGS__)
|
||||
#define rprintD(x, ...) if (Debug.isActive(Debug.DEBUG)) Debug.print(x, ##__VA_ARGS__)
|
||||
#define rprintI(x, ...) if (Debug.isActive(Debug.INFO)) Debug.print(x, ##__VA_ARGS__)
|
||||
#define rprintW(x, ...) if (Debug.isActive(Debug.WARNING)) Debug.print(x, ##__VA_ARGS__)
|
||||
#define rprintE(x, ...) if (Debug.isActive(Debug.ERROR)) Debug.print(x, ##__VA_ARGS__)
|
||||
#define rprintA(x, ...) if (Debug.isActive(Debug.ANY)) Debug.print(x, ##__VA_ARGS__)
|
||||
|
||||
|
||||
#define rprintVln(x, ...) if (Debug.isActive(Debug.VERBOSE)) Debug.println(x, ##__VA_ARGS__)
|
||||
#define rprintDln(x, ...) if (Debug.isActive(Debug.DEBUG)) Debug.println(x, ##__VA_ARGS__)
|
||||
#define rprintIln(x, ...) if (Debug.isActive(Debug.INFO)) Debug.println(x, ##__VA_ARGS__)
|
||||
#define rprintWln(x, ...) if (Debug.isActive(Debug.WARNING)) Debug.println(x, ##__VA_ARGS__)
|
||||
#define rprintEln(x, ...) if (Debug.isActive(Debug.ERROR)) Debug.println(x, ##__VA_ARGS__)
|
||||
#define rprintAln(x, ...) if (Debug.isActive(Debug.ANY)) Debug.println(x, ##__VA_ARGS__)
|
||||
|
||||
///// Class
|
||||
|
||||
class RemoteDebug: public Print
|
||||
{
|
||||
public:
|
||||
|
||||
// Constructor
|
||||
|
||||
RemoteDebug();
|
||||
|
||||
// Methods
|
||||
|
||||
bool begin(String hostName, uint16_t port, uint8_t startingDebugLevel = DEBUG);
|
||||
bool begin(String hostName, uint8_t startingDebugLevel = DEBUG);
|
||||
|
||||
void setPassword(String password);
|
||||
|
||||
void stop();
|
||||
|
||||
void handle();
|
||||
|
||||
void disconnect(boolean onlyTelnetClient = false);
|
||||
|
||||
void setSerialEnabled(boolean enable);
|
||||
|
||||
void setResetCmdEnabled(boolean enable);
|
||||
|
||||
void setHelpProjectsCmds(String help);
|
||||
void setCallBackProjectCmds(void (*callback)());
|
||||
String getLastCommand();
|
||||
void clearLastCommand();
|
||||
|
||||
void showTime(boolean show);
|
||||
void showProfiler(boolean show, uint32_t minTime = 0);
|
||||
void showDebugLevel(boolean show);
|
||||
void showColors(boolean show);
|
||||
|
||||
void showRaw(boolean show);
|
||||
|
||||
void setCallBackNewClient(void (*callback)());
|
||||
|
||||
#ifdef ALPHA_VERSION // In test, not good yet
|
||||
void autoProfilerLevel(uint32_t millisElapsed);
|
||||
#endif
|
||||
|
||||
void setFilter(String filter);
|
||||
void setNoFilter();
|
||||
|
||||
boolean isActive(uint8_t debugLevel = DEBUG);
|
||||
|
||||
void silence(boolean activate, boolean showMessage = true, boolean fromBreak = false, uint32_t timeout = 0);
|
||||
boolean isSilence();
|
||||
|
||||
void onConnection(boolean connected);
|
||||
|
||||
boolean isConnected();
|
||||
|
||||
#ifdef DEBUGGER_ENABLED
|
||||
// For Simple software debugger - based on SerialDebug Library
|
||||
void initDebugger(boolean (*callbackEnabled)(), void (*callbackHandle)(const boolean), String (*callbackGetHelp)(), void (*callbackProcessCmd)());
|
||||
WiFiClient* getTelnetClient();
|
||||
#endif
|
||||
|
||||
#ifndef WEBSOCKET_DISABLED // For web socket server (app)
|
||||
void wsOnReceive(const char* command);
|
||||
void wsSendInfo();
|
||||
void wsSendLevelInfo();
|
||||
#endif
|
||||
boolean wsIsConnected();
|
||||
|
||||
// Print
|
||||
|
||||
virtual size_t write(uint8_t);
|
||||
|
||||
virtual size_t write(const uint8_t *buffer, size_t size); // Insert due a write bug w/ latest Esp8266 SDK - 17/08/18
|
||||
|
||||
// Debug levels
|
||||
|
||||
static const uint8_t PROFILER = 0; // Used for show time of execution of pieces of code(profiler)
|
||||
static const uint8_t VERBOSE = 1; // Used for show verboses messages
|
||||
static const uint8_t DEBUG = 2; // Used for show debug messages
|
||||
static const uint8_t INFO = 3; // Used for show info messages
|
||||
static const uint8_t WARNING = 4; // Used for show warning messages
|
||||
static const uint8_t ERROR = 5; // Used for show error messages
|
||||
static const uint8_t ANY = 6; // Used for show always messages, for any current debug level
|
||||
|
||||
// Expand characters as CR/LF to \\r, \\n
|
||||
|
||||
String expand(String string);
|
||||
|
||||
// Destructor
|
||||
|
||||
~RemoteDebug();
|
||||
|
||||
private:
|
||||
|
||||
// Variables
|
||||
|
||||
String _hostName = ""; // Host name
|
||||
|
||||
boolean _connected = false; // Client is connected ?
|
||||
|
||||
String _password = ""; // Password
|
||||
|
||||
boolean _passwordOk = false; // Password request ? - 18/07/18
|
||||
uint8_t _passwordAttempt = 0;
|
||||
|
||||
boolean _silence = false; // Silence mode ?
|
||||
uint32_t _silenceTimeout = 0; // Silence timeout
|
||||
|
||||
uint8_t _clientDebugLevel = DEBUG; // Level setted by user in web app or telnet client
|
||||
uint8_t _lastDebugLevel = DEBUG; // Last Level setted by active()
|
||||
|
||||
uint32_t _lastTimePrint = millis(); // Last time print a line
|
||||
|
||||
uint8_t _levelBeforeProfiler=DEBUG; // Last Level before Profiler level
|
||||
uint32_t _levelProfilerDisable = 0; // time in millis to disable the profiler level
|
||||
uint32_t _autoLevelProfiler = 0; // Automatic change to profiler level if time between handles is greater than n millis
|
||||
|
||||
boolean _showTime = false; // Show time in millis
|
||||
|
||||
boolean _showProfiler = false; // Show time between messages
|
||||
uint32_t _minTimeShowProfiler = 0; // Minimal time to show profiler
|
||||
|
||||
boolean _showDebugLevel = true; // Show debug Level
|
||||
|
||||
boolean _showColors = false; // Show colors
|
||||
|
||||
boolean _showRaw = false; // Show in raw mode ?
|
||||
|
||||
boolean _serialEnabled = false; // Send to serial too (not recommended)
|
||||
|
||||
boolean _resetCommandEnabled=false; // Enable command to reset the board
|
||||
|
||||
boolean _newLine = true; // New line write ?
|
||||
|
||||
String _command = ""; // Command received
|
||||
String _lastCommand = ""; // Last Command received
|
||||
uint32_t _lastTimeCommand = millis();// Last time command received
|
||||
String _helpProjectCmds = ""; // Help of comands setted by project (sketch)
|
||||
void (*_callbackProjectCmds)() = NULL; // Callable for projects commands
|
||||
void (*_callbackNewClient)() = NULL; // Callable for when have a new client connected
|
||||
|
||||
String _filter = ""; // Filter
|
||||
boolean _filterActive = false;
|
||||
|
||||
String _bufferPrint = ""; // Buffer of print write to WiFi
|
||||
|
||||
#ifdef CLIENT_BUFFERING
|
||||
String _bufferSend = ""; // Buffer to send data to web app or telnet client
|
||||
uint16_t _sizeBufferSend = 0; // Size of it
|
||||
uint32_t _lastTimeSend = 0; // Last time command send data
|
||||
#endif
|
||||
|
||||
#ifdef DEBUGGER_ENABLED
|
||||
// // For Simple software debugger - based on SerialDebug Library
|
||||
boolean (*_callbackDbgEnabled)() = NULL;// Callable for debugger enabled
|
||||
void (*_callbackDbgHandle)(const boolean) = NULL; // Callable for handle of debugger
|
||||
String (*_callbackDbgHelp)() = NULL; // Callable for get debugger help
|
||||
void (*_callbackDbgProcessCmd)() = NULL;// Callable for process commands of debugger
|
||||
#endif
|
||||
|
||||
//////// Privates
|
||||
|
||||
void showHelp();
|
||||
void processCommand();
|
||||
String formatNumber(uint32_t value, uint8_t size, char insert='0');
|
||||
boolean isCRLF(char character);
|
||||
uint32_t getFreeMemory();
|
||||
|
||||
#ifdef ALPHA_VERSION // In test, not good yet
|
||||
void sendTelnetCommand(uint8_t command, uint8_t option);
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
#else // DEBUG_DISABLED
|
||||
|
||||
// Disable debug macros
|
||||
|
||||
#define rdebugAln(...)
|
||||
#define rdebugPln(...)
|
||||
#define rdebugVln(...)
|
||||
#define rdebugDln(...)
|
||||
#define rdebugIln(...)
|
||||
#define rdebugWln(...)
|
||||
#define rdebugEln(...)
|
||||
#define rdebug(...)
|
||||
|
||||
#define DEBUG(...)
|
||||
|
||||
#define DEBUG_A(...)
|
||||
#define DEBUG_P(...)
|
||||
#define DEBUG_V(...)
|
||||
#define DEBUG_D(...)
|
||||
#define DEBUG_I(...)
|
||||
#define DEBUG_W(...)
|
||||
#define DEBUG_E(...)
|
||||
|
||||
#define debugA(...)
|
||||
#define debugP(...)
|
||||
#define debugV(...)
|
||||
#define debugD(...)
|
||||
#define debugI(...)
|
||||
#define debugW(...)
|
||||
#define debugE(...)
|
||||
|
||||
#define rprintA(...)
|
||||
#define rprintV(...)
|
||||
#define rprintD(...)
|
||||
#define rprintI(...)
|
||||
#define rprintW(...)
|
||||
#define rprintE(...)
|
||||
|
||||
#define rprintAln(...)
|
||||
#define rprintVln(...)
|
||||
#define rprintDln(...)
|
||||
#define rprintIln(...)
|
||||
#define rprintWln(...)
|
||||
#define rprintEln(...)
|
||||
|
||||
#define debugHandle()
|
||||
|
||||
// Note all of Debug. codes need uses "#ifndef DEBUG_DISABLED"
|
||||
// For example, the initialization codes and:
|
||||
|
||||
//#ifndef DEBUG_DISABLED
|
||||
//if (Debug.isActive(Debug.VERBOSE)) {
|
||||
// Debug.printf("bla bla bla: %d %s", number, str); // OR
|
||||
// Debug.printf("bla bla bla: %d %s", number, str.c_str()); // Note: if type is String need c_str() // OR
|
||||
// Debug.println("bla bla bla 2 ln");
|
||||
//}
|
||||
//#endif
|
||||
|
||||
#endif // DEBUG_DISABLED
|
||||
|
||||
#endif // H
|
||||
|
||||
//////// End
|
||||
@@ -1,135 +0,0 @@
|
||||
|
||||
/*
|
||||
* Header for RemoteDebugCfg
|
||||
*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2019 Joao Lopes
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* All configurations have moved to RemoteDebugCfg.h,
|
||||
* to facilitate changes
|
||||
*/
|
||||
|
||||
///////////// User config, to not lost in library updates
|
||||
|
||||
#ifndef REMOTEDEBUGCFG_H_
|
||||
#define REMOTEDEBUGCFG_H_
|
||||
#pragma once
|
||||
|
||||
///////////// For RemoteDebug ///////////////////
|
||||
|
||||
///// Debug disable for compile to production/release
|
||||
///// as nothing of RemotedDebug is compiled, zero overhead :-)
|
||||
//#define DEBUG_DISABLED true
|
||||
|
||||
// Debug enabled ?
|
||||
|
||||
#ifndef DEBUG_DISABLED
|
||||
|
||||
///// Port for telnet server
|
||||
#define TELNET_PORT 23
|
||||
|
||||
// Disable auto function for debug macros? (uncomment this if not want this)
|
||||
//#define DEBUG_DISABLE_AUTO_FUNC true
|
||||
|
||||
// Simple password request - left commented if not need this - 18/07/18
|
||||
// Notes:
|
||||
// It is very simple feature, only text, no cryptography,
|
||||
// and the password is echoed in screen (I not discovery yet how disable it)
|
||||
// telnet use advanced authentication (kerberos, etc.)
|
||||
// Such now as RemoteDebug now is not for production releases,
|
||||
// this kind of authentication will not be done now.
|
||||
// Can be by project, just call setPassword method
|
||||
#define REMOTEDEBUG_PWD_ATTEMPTS 3
|
||||
|
||||
// Maximum time for inactivity (em milliseconds)
|
||||
// Default: 10 minutes
|
||||
// Comment it if you not want this
|
||||
// Can be by project, just define it before include this file
|
||||
//#define MAX_TIME_INACTIVE 600000
|
||||
|
||||
// Buffered print write to WiFi -> length of buffer
|
||||
// Can be by project, just define it before include this file
|
||||
#define BUFFER_PRINT 170
|
||||
|
||||
// Should the help text be displayed on connection.
|
||||
// Enabled by default, comment to disable
|
||||
#define SHOW_HELP true
|
||||
|
||||
// Buffering (sends in interval of time to avoid ESP misterious delays)
|
||||
// Uncomment this to disable it
|
||||
#define CLIENT_BUFFERING true
|
||||
#ifdef CLIENT_BUFFERING
|
||||
#define DELAY_TO_SEND 10 // Time to send buffer
|
||||
#define MAX_SIZE_SEND 1460 // Maximum size of packet (limit of TCP/IP)
|
||||
#endif
|
||||
|
||||
// Enable if you test features yet in development
|
||||
//#define ALPHA_VERSION true
|
||||
|
||||
// Debugger support enabled ?
|
||||
// Comment this to disable it
|
||||
#define DEBUGGER_ENABLED true
|
||||
#ifdef DEBUGGER_ENABLED
|
||||
#define DEBUGGER_HANDLE_TIME 850 // Interval to call handle of debugger - equal to implemented in debugger
|
||||
// App have debugger elements on screen ?
|
||||
// Note: app not have it yet
|
||||
//#define DEBUGGER_SEND_INFO true
|
||||
#endif
|
||||
|
||||
///// Websocket server to support debug over web browser (RemoteDebugApp)
|
||||
// Uncomment this to disable it
|
||||
#define WEBSOCKET_DISABLED true
|
||||
|
||||
///////////// For RemoteDebugWS ///////////////////
|
||||
|
||||
#ifndef WEBSOCKET_DISABLED
|
||||
|
||||
// Websocket port
|
||||
#define WEBSOCKET_PORT 8232
|
||||
|
||||
// Library arduinoWebSockets already installed, uncomment to use it
|
||||
// Do this if you receive errors of multiple definition ...
|
||||
//#define USE_LIB_WEBSOCKET true
|
||||
#endif
|
||||
|
||||
///////////// For RemoteDebugger ///////////////////
|
||||
|
||||
// Enable Flash variables support - F()
|
||||
// Used internally in SerialDebug and in public API
|
||||
// If is a low memory board, like AVR, all strings in SerialDebug is using flash memory
|
||||
// If have RAM memory, this is more fast than flash
|
||||
//#define DEBUG_USE_FLASH_F true
|
||||
|
||||
// For Espressif boards, default is not flash support for printf,
|
||||
// due it have a lot of memory and Serial.printf is not compatible with it
|
||||
// If you need more memory, can force it:
|
||||
//#define DEBUG_USE_FLASH_F true
|
||||
|
||||
#endif /* DEBUG_DISABLED */
|
||||
|
||||
#endif /* REMOTEDEBUGCFG_H_ */
|
||||
|
||||
////// End
|
||||
@@ -1,88 +0,0 @@
|
||||
/*
|
||||
* telnet.h - Telnet Defines
|
||||
*
|
||||
* Note: only used is uncommented
|
||||
* */
|
||||
|
||||
#ifndef TELNET_H
|
||||
#define TELNET_TELNET_H
|
||||
|
||||
#define TELNET_IAC 255
|
||||
#define TELNET_DONT 254
|
||||
#define TELNET_DO 253
|
||||
#define TELNET_WONT 252
|
||||
#define TELNET_WILL 251
|
||||
|
||||
// #define TELNET_SE 240 // Subnegotiation End
|
||||
// #define TELNET_NOP 241 // No Operation
|
||||
// #define TELNET_DM 242 // Data Mark
|
||||
// #define TELNET_BRK 243 // Break
|
||||
// #define TELNET_IP 244 // Interrupt process
|
||||
// #define TELNET_AO 245 // Abort output
|
||||
// #define TELNET_AYT 246 // Are You There
|
||||
// #define TELNET_EC 247 // Erase Character
|
||||
// #define TELNET_EL 248 // Erase Line
|
||||
//#define TELNET_GA 249 // Go Ahead
|
||||
// #define TELNET_SB 250 // Subnegotiation Begin
|
||||
|
||||
// #define TELNET_BINARY 0 // 8-bit data path
|
||||
#define TELNET_ECHO 1 // echo
|
||||
// #define TELNET_RCP 2 // prepare to reconnect
|
||||
#define TELNET_SGA 3 // suppress go ahead
|
||||
// #define TELNET_NAMS 4 // approximate message size
|
||||
// #define TELNET_STATUS 5 // give status
|
||||
// #define TELNET_TM 6 // timing mark
|
||||
// #define TELNET_RCTE 7 // remote controlled transmission and echo
|
||||
// #define TELNET_NAOL 8 // negotiate about output line width
|
||||
// #define TELNET_NAOP 9 // negotiate about output page size
|
||||
// #define TELNET_NAOCRD 10 // negotiate about CR disposition
|
||||
// #define TELNET_NAOHTS 11 // negotiate about horizontal tabstops
|
||||
// #define TELNET_NAOHTD 12 // negotiate about horizontal tab disposition
|
||||
// #define TELNET_NAOFFD 13 // negotiate about formfeed disposition
|
||||
// #define TELNET_NAOVTS 14 // negotiate about vertical tab stops
|
||||
// #define TELNET_NAOVTD 15 // negotiate about vertical tab disposition
|
||||
// #define TELNET_NAOLFD 16 // negotiate about output LF disposition
|
||||
// #define TELNET_XASCII 17 // extended ascii character set
|
||||
// #define TELNET_LOGOUT 18 // force logout
|
||||
// #define TELNET_BM 19 // byte macro
|
||||
// #define TELNET_DET 20 // data entry terminal
|
||||
// #define TELNET_SUPDUP 21 // supdup protocol
|
||||
// #define TELNET_SUPDUPOUTPUT 22 // supdup output
|
||||
// #define TELNET_SNDLOC 23 // send location
|
||||
// #define TELNET_TTYPE 24 // terminal type
|
||||
// #define TELNET_EOR 25 // end or record
|
||||
// #define TELNET_TUID 26 // TACACS user identification
|
||||
// #define TELNET_OUTMRK 27 // output marking
|
||||
// #define TELNET_TTYLOC 28 // terminal location number
|
||||
// #define TELNET_VT3270REGIME 29 // 3270 regime
|
||||
// #define TELNET_X3PAD 30 // X.3 PAD
|
||||
// #define TELNET_NAWS 31 // window size
|
||||
// #define TELNET_TSPEED 32 // terminal speed
|
||||
// #define TELNET_LFLOW 33 // remote flow control
|
||||
// #define TELNET_LINEMODE 34 // Linemode option
|
||||
// #define TELNET_XDISPLOC 35 // X Display Location
|
||||
// #define TELNET_OLD_ENVIRON 36 // Old - Environment variables
|
||||
// #define TELNET_AUTHENTICATION 37 // Authenticate
|
||||
// #define TELNET_ENCRYPT 38 // Encryption option
|
||||
// #define TELNET_NEW_ENVIRON 39 // New - Environment variables
|
||||
// #define TELNET_TN3270E 40 // TN3270E
|
||||
// #define TELNET_XAUTH 41 // XAUTH
|
||||
// #define TELNET_CHARSET 42 // CHARSET
|
||||
// #define TELNET_RSP 43 // Telnet Remote Serial Port
|
||||
// #define TELNET_COM_PORT_OPTION 44 // Com Port Control Option
|
||||
#define TELNET_SUPPRESS_LOCAL_ECHO 45 // Telnet Suppress Local Echo
|
||||
// #define TELNET_TLS 46 // Telnet Start TLS
|
||||
// #define TELNET_KERMIT 47 // KERMIT
|
||||
// #define TELNET_SEND_URL 48 // SEND-URL
|
||||
// #define TELNET_FORWARD_X 49 // FORWARD_X
|
||||
// #define TELNET_PRAGMA_LOGON 138 // TELOPT PRAGMA LOGON
|
||||
// #define TELNET_SSPI_LOGON 139 // TELOPT SSPI LOGON
|
||||
// #define TELNET_PRAGMA_HEARTBEAT 140 // TELOPT PRAGMA HEARTBEAT
|
||||
// #define TELNET_EXOPL 255 // Extended-Options-List
|
||||
// #define TELNET_NOOPT 0
|
||||
|
||||
// #define TELNET_IS 0
|
||||
// #define TELNET_SEND 1
|
||||
|
||||
#endif // TELNET_H
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
This is free and unencumbered software released into the public domain.
|
||||
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
distribute this software, either in source code form or as a compiled
|
||||
binary, for any purpose, commercial or non-commercial, and by any
|
||||
means.
|
||||
|
||||
In jurisdictions that recognize copyright laws, the author or authors
|
||||
of this software dedicate any and all copyright interest in the
|
||||
software to the public domain. We make this dedication for the benefit
|
||||
of the public at large and to the detriment of our heirs and
|
||||
successors. We intend this dedication to be an overt act of
|
||||
relinquishment in perpetuity of all present and future rights to this
|
||||
software under copyright law.
|
||||
|
||||
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 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.
|
||||
|
||||
For more information, please refer to <http://unlicense.org>
|
||||
@@ -1,518 +0,0 @@
|
||||
[](https://github.com/chrisjoyce911/esp32FOTA/actions/)
|
||||
|
||||
[](https://www.ardu-badge.com/esp32FOTA)
|
||||
[](https://registry.platformio.org/libraries/chrisjoyce911/esp32FOTA)
|
||||
|
||||
|
||||
|
||||
# esp32FOTA library for Arduino
|
||||
|
||||
## Purpose
|
||||
|
||||
A simple library to add support for Over-The-Air (OTA) updates to your project.
|
||||
|
||||
## Features
|
||||
|
||||
- [x] Zlib or gzip compressed firmware support
|
||||
- [x] SPIFFS/LittleFS partition Update [#25], [#47], [#60], [#92] (thanks to all participants)
|
||||
- [x] Any fs::FS support (SPIFFS/LITTLEFS/SD) for cert/signature storage [#79], [#74], [#91], [#92] (thanks to all participants)
|
||||
- [x] Seamless http/https
|
||||
- [x] Web update (requires web server)
|
||||
- [x] Batch firmware sync
|
||||
- [x] Force firmware update [#8]
|
||||
- [x] https support [#26] ( Thanks to @fbambusi )
|
||||
- [x] Signature check of downloaded firmware-image [#65]
|
||||
- [x] Signature verification
|
||||
- [x] Semantic versioning support
|
||||
- [ ] Checking for update via bin headers [#15]
|
||||
|
||||
## How it works
|
||||
|
||||
This library tries to access a JSON file hosted on a webserver, and reviews it to decide if a newer firmware has been published, if so it will download it and install it.
|
||||
|
||||
There are a few things that need to be in place for an update to work.
|
||||
|
||||
- A webserver with the firmware information in a JSON file
|
||||
- Firmware version
|
||||
- Firmware type
|
||||
- Firmware bin (can optionnally be compressed with zlib or gzip)
|
||||
- For https or signature check: SPIFFS with root_ca.pem (https) and rsa_key.pem (signature check)
|
||||
|
||||
You can supply http or https URLs. If you are using https, you need the root_ca.pem in your SPIFFS partition. For the actual firmware it will use https when you define port 443 or 4433. Otherwise it will use plain http.
|
||||
|
||||
## Usage
|
||||
|
||||
### Hosted JSON
|
||||
|
||||
This is hosted by a webserver and contains information about the latest firmware:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "esp32-fota-http",
|
||||
"version": 2,
|
||||
"host": "192.168.0.100",
|
||||
"port": 80,
|
||||
"bin": "/fota/esp32-fota-http-2.bin"
|
||||
}
|
||||
```
|
||||
|
||||
Version information can be either a single number or a semantic version string. Alternatively, a full URL path can be provided:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "esp32-fota-http",
|
||||
"version": "2.5.1",
|
||||
"url": "http://192.168.0.100/fota/esp32-fota-http-2.bin"
|
||||
}
|
||||
```
|
||||
|
||||
A single JSON file can provide information on multiple firmware types by combining them together into an array. When this is loaded, the firmware manifest with a type matching the one passed to the esp32FOTA constructor will be selected:
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"type":"esp32-fota-http",
|
||||
"version":"0.0.2",
|
||||
"url":"http://192.168.0.100/fota/esp32-fota-http-2.bin"
|
||||
},
|
||||
{
|
||||
"type":"esp32-other-hardware",
|
||||
"version":"0.0.3",
|
||||
"url":"http://192.168.0.100/fota/esp32-other-hardware.bin"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
|
||||
A single JSON file can also contain several versions of a single firmware type:
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"type":"esp32-fota-http",
|
||||
"version":"0.0.2",
|
||||
"url":"http://192.168.0.100/fota/esp32-fota-0.0.2.bin"
|
||||
},
|
||||
{
|
||||
"type":"esp32-fota-http",
|
||||
"version":"0.0.3",
|
||||
"url":"http://192.168.0.100/fota/esp32-fota-0.0.3.bin",
|
||||
"spiffs":"http://192.168.0.100/fota/esp32-fota-0.0.3.spiffs.bin"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
#### Filesystem image (spiffs/littlefs)
|
||||
|
||||
Adding `spiffs` key to the JSON entry will end up with the filesystem being updated first, then the firmware.
|
||||
|
||||
Obviously don't use the filesystem you're updating to store certificates needed by the update, spiffs partition
|
||||
doesn't have redundancy like OTA0/OTA1 and won't recover from a failed update without a restart and format.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "esp32-fota-http",
|
||||
"version": 2,
|
||||
"host": "192.168.0.100",
|
||||
"port": 80,
|
||||
"bin": "/fota/esp32-fota-http-2.bin",
|
||||
"spiffs": "/fota/default_spiffs.bin"
|
||||
}
|
||||
```
|
||||
|
||||
Other accepted keys for filesystems are `spiffs`, `littlefs` and `fatfs`.
|
||||
Picking one or another doesn't make any difference yet.
|
||||
|
||||
|
||||
#### Firmware types
|
||||
|
||||
Types are used to compare with the current loaded firmware, this is used to make sure that when loaded, the device will still do the intended job.
|
||||
|
||||
As an example, a device used as a data logger should ony be updated with new versions of the data logger.
|
||||
|
||||
##### examples
|
||||
|
||||
- TTGO-T8-ESP32-Logger
|
||||
- TTGO-T8-ESP32-Temp
|
||||
- TTGO-T8-ESP32-Relay
|
||||
|
||||
|
||||
### Debug
|
||||
|
||||
Messages depends of build level. If you pass -D CORE_DEBUG_LEVEL=3 to build flags, it enable the messages
|
||||
|
||||
### Sketch
|
||||
|
||||
In this early init example, a version 1 of 'esp32-fota-http' is in use, it would be updated when using the JSON example.
|
||||
|
||||
```cpp
|
||||
#include <esp32FOTA.hpp>
|
||||
|
||||
const char *ssid = "";
|
||||
const char *password = "";
|
||||
|
||||
esp32FOTA esp32FOTA("esp32-fota-http", "1.0.0");
|
||||
|
||||
const char* manifest_url = "http://server/fota/fota.json";
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
setup_wifi();
|
||||
esp32FOTA.setManifestURL( manifest_url );
|
||||
// esp32FOTA.useDeviceId( true ); // optionally append the device ID to the HTTP query
|
||||
}
|
||||
|
||||
void setup_wifi()
|
||||
{
|
||||
delay(10);
|
||||
Serial.print("Connecting to ");
|
||||
WiFi.begin(ssid, password);
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
delay(500);
|
||||
Serial.print(".");
|
||||
}
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
esp32FOTA.handle();
|
||||
// or ...
|
||||
// bool updatedNeeded = esp32FOTA.execHTTPcheck();
|
||||
// if (updatedNeeded) {
|
||||
// esp32FOTA.execOTA();
|
||||
// }
|
||||
delay(2000);
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
Late init is possible using `FOTAConfig_t`, allowing more complex configurations:
|
||||
|
||||
```cpp
|
||||
#include <SPIFFS.h> // include filesystem *before* esp32FOTA librart
|
||||
#include <esp32FOTA.hpp>
|
||||
|
||||
esp32FOTA FOTA;
|
||||
|
||||
const char* manifest_url = "http://server/fota/fota.json";
|
||||
const char* fota_name = "esp32-fota-http";
|
||||
|
||||
// CryptoFileAsset *MyRootCA = new CryptoFileAsset( "/root_ca.pem", &SPIFFS );
|
||||
// CryptoFileAsset *MyRSAKey = new CryptoFileAsset( "/rsa_key.pub", &SD );
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin( 115200 );
|
||||
setup_wifi();
|
||||
|
||||
{
|
||||
auto cfg = FOTA.getConfig();
|
||||
cfg.name = fota_name;
|
||||
cfg.manifest_url = manifest_url;
|
||||
cfg.sem = SemverClass( 1, 0, 0 ); // major, minor, patch
|
||||
cfg.check_sig = false; // verify signed firmware with rsa public key
|
||||
cfg.unsafe = true; // disable certificate check when using TLS
|
||||
//cfg.root_ca = MyRootCA;
|
||||
//cfg.pub_key = MyRSAKey;
|
||||
//cfg.use_device_id = false;
|
||||
FOTA.setConfig( cfg );
|
||||
}
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
esp32FOTA.handle();
|
||||
// or ...
|
||||
// bool updatedNeeded = esp32FOTA.execHTTPcheck();
|
||||
// if (updatedNeeded) {
|
||||
// esp32FOTA.execOTA();
|
||||
// }
|
||||
delay(2000);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
### Zlib/gzip support
|
||||
|
||||
⚠️ This feature cannot be used with signature check.
|
||||
|
||||
|
||||
For firmwares compressed with `pigz` utility (see , file extension must be `.zz`:
|
||||
|
||||
```cpp
|
||||
#include <flashz.hpp> // http://github.com/vortigont/esp32-flashz
|
||||
#include <esp32FOTA.hpp>
|
||||
```
|
||||
|
||||
```bash
|
||||
$ pigz -9kzc esp32-fota-http-2.bin > esp32-fota-http-2.bin.zz
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "esp32-fota-http",
|
||||
"version": "2.5.1",
|
||||
"url": "http://192.168.0.100/fota/esp32-fota-http-2.bin.zz"
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
For firmwares compressed with `gzip` utility, file extension must be `.gz`
|
||||
|
||||
```cpp
|
||||
#include <ESP32-targz.h> // http://github.com/tobozo/ESP32-targz
|
||||
#include <esp32FOTA.hpp>
|
||||
```
|
||||
|
||||
```bash
|
||||
$ gzip -c esp32-fota-http-2.bin > esp32-fota-http-2.bin.gz
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "esp32-fota-http",
|
||||
"version": "2.5.1",
|
||||
"url": "http://192.168.0.100/fota/esp32-fota-http-2.bin.gz"
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
### Root Certificates
|
||||
|
||||
Certificates and signatures can be stored in different places: any fs::FS filesystem or progmem as const char*.
|
||||
|
||||
Filesystems:
|
||||
|
||||
```C++
|
||||
CryptoFileAsset *MyRootCA = new CryptoFileAsset( "/root_ca.pem", &SPIFFS );
|
||||
```
|
||||
|
||||
```C++
|
||||
CryptoFileAsset *MyRootCA = new CryptoFileAsset( "/root_ca.pem", &LittleFS );
|
||||
```
|
||||
|
||||
```C++
|
||||
CryptoFileAsset *MyRootCA = new CryptoFileAsset( "/root_ca.pem", &SD );
|
||||
```
|
||||
|
||||
Progmem:
|
||||
|
||||
```C++
|
||||
const char* root_ca = R"ROOT_CA(
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh
|
||||
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
|
||||
QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT
|
||||
MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
|
||||
b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG
|
||||
9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB
|
||||
CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97
|
||||
nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt
|
||||
43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P
|
||||
T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4
|
||||
gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO
|
||||
BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR
|
||||
TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw
|
||||
DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr
|
||||
hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg
|
||||
06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF
|
||||
PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls
|
||||
YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
|
||||
CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
|
||||
-----END CERTIFICATE-----
|
||||
)ROOT_CA";
|
||||
|
||||
// mixed sources is possible
|
||||
CryptoMemAsset *MyRootCA = new CryptoMemAsset("Root CA", root_ca, strlen(root_ca)+1 );
|
||||
CryptoFileAsset *MyPubKey = new CryptoFileAsset("RSA Key", "/rsa_key.pub", &SD);
|
||||
|
||||
```
|
||||
|
||||
Then later in the `setup()`:
|
||||
|
||||
```C++
|
||||
|
||||
const char* manifest_url = "http://server/fota/fota.json";
|
||||
|
||||
void setup()
|
||||
{
|
||||
// (...)
|
||||
esp32FOTA.setManifestURL( manifest_url );
|
||||
esp32FOTA.setRootCA( MyRootCA );
|
||||
esp32FOTA.setPubKey( MyPubKey );
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
# Update callbacks
|
||||
|
||||
|
||||
## Progress callback
|
||||
|
||||
Can be used to draw a progress bar e.g. on a TFT.
|
||||
|
||||
The callback signature is: `void my_progress_callback( size_t progress, size_t size);`, lambda functions are accepted.
|
||||
|
||||
Use `esp32FOTA.setProgressCb( my_progress_callback )` to attach the callback.
|
||||
|
||||
This method is aliased to Update.h `onProgress()` feature and defaults to printing dots in the serial console.
|
||||
|
||||
```C++
|
||||
void my_progress_callback( size_t progress, size_t size )
|
||||
{
|
||||
if( progress == size || progress == 0 ) Serial.println();
|
||||
Serial.print(".");
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
// (...)
|
||||
|
||||
// usage with callback function:
|
||||
esp32FOTA.setProgressCb( my_progress_callback ) ;
|
||||
|
||||
// usage with lambda function:
|
||||
esp32FOTA.setProgressCb( [](size_t progress, size_t size) {
|
||||
if( progress == size || progress == 0 ) Serial.println();
|
||||
Serial.print(".");
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## Update begin-fail callback
|
||||
|
||||
- Description: fired when Update.begin() failed
|
||||
- Callback type: `void(int partition)`
|
||||
- Callback setter: `setUpdateBeginFailCb( cb )`
|
||||
- Usage:
|
||||
|
||||
```cpp
|
||||
esp32FOTA.setUpdateBeginFailCb( [](int partition) {
|
||||
Serial.printf("Update could not begin with %s partition\n", partition==U_SPIFFS ? "spiffs" : "firmware" );
|
||||
});
|
||||
```
|
||||
|
||||
## Update end callback
|
||||
|
||||
- Description: fired after Update.end() and before signature check
|
||||
- Callback type: `void(int partition)`
|
||||
- Callback setter: `setUpdateEndCb( cb )`
|
||||
- Usage:
|
||||
|
||||
```cpp
|
||||
esp32FOTA.setUpdateEndCb( [](int partition) {
|
||||
Serial.printf("Update could not finish with %s partition\n", partition==U_SPIFFS ? "spiffs" : "firmware" );
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
## Update check-fail callback
|
||||
|
||||
- Description: fired when partition or signature check failed
|
||||
- Callback type: `void(int partition, int update_error_code)`
|
||||
- Callback setter: `setUpdateCheckFailCb( cb )`
|
||||
- Usage:
|
||||
|
||||
```cpp
|
||||
esp32FOTA.setUpdateCheckFailCb( [](int partition, int error_code) {
|
||||
Serial.printf("Update could validate %s partition (error %d)\n", partition==U_SPIFFS ? "spiffs" : "firmware", error_code );
|
||||
// error codes:
|
||||
// -1 : partition not found
|
||||
// -2 : validation (signature check) failed
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
## Update finished callback
|
||||
|
||||
- Description: fired update is complete
|
||||
- Callback type: `void(int partition, bool needs_restart)`
|
||||
- Callback setter: `setUpdateFinishedCb( cb )`
|
||||
- Usage:
|
||||
|
||||
```cpp
|
||||
esp32FOTA.setUpdateFinishedCb( [](int partition, bool restart_after) {
|
||||
Serial.printf("Update could not begin with %s partition\n", partition==U_SPIFFS ? "spiffs" : "firmware" );
|
||||
// do some stuff e.g. notify a MQTT server the update completed successfully
|
||||
if( restart_after ) {
|
||||
ESP.restart();
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
### Verified images via signature
|
||||
|
||||
You can now sign your firmware image with an RSA public/private key pair and have the ESP32 check if the signature is correct before
|
||||
it switches over to the new image.
|
||||
|
||||
In order to use this feature just set the boolean `validate` to `true` in the constructor. Next create a key-pair to sign your firmware image:
|
||||
```
|
||||
openssl genrsa -out priv_key.pem 4096
|
||||
openssl rsa -in priv_key.pem -pubout > rsa_key.pub
|
||||
```
|
||||
|
||||
Compile your code so you get your OTA update file (e.g. `firmware.bin`). Now it's time to create the signature:
|
||||
```
|
||||
# Create signature file
|
||||
openssl dgst -sign priv_key.pem -keyform PEM -sha256 -out firmware.sign -binary firmware.bin
|
||||
|
||||
# throw it all in one file
|
||||
cat firmware.sign firmware.bin > firmware.img
|
||||
```
|
||||
|
||||
Upload `firmware.img` to your OTA server and point to it in your `firmware.json`
|
||||
|
||||
Last step, create an SPIFFS partition with your `rsa_key.pub` in it. The OTA update should not touch this partition during the update. You'll only need to distribute this partition once.
|
||||
|
||||
On the next update-check the ESP32 will download the `firmware.img` extract the first 512 bytes with the signature and check it together with the public key against the new image. If the signature check runs OK, it'll reset into the new firmware.
|
||||
|
||||
|
||||
|
||||
[#8]: https://github.com/chrisjoyce911/esp32FOTA/issues/8
|
||||
[#15]: https://github.com/chrisjoyce911/esp32FOTA/issues/15
|
||||
[#25]: https://github.com/chrisjoyce911/esp32FOTA/issues/25
|
||||
[#26]: https://github.com/chrisjoyce911/esp32FOTA/issues/26
|
||||
[#60]: https://github.com/chrisjoyce911/esp32FOTA/issues/60
|
||||
[#65]: https://github.com/chrisjoyce911/esp32FOTA/issues/65
|
||||
[#74]: https://github.com/chrisjoyce911/esp32FOTA/issues/74
|
||||
[#47]: https://github.com/chrisjoyce911/esp32FOTA/pull/47
|
||||
[#79]: https://github.com/chrisjoyce911/esp32FOTA/pull/79
|
||||
[#91]: https://github.com/chrisjoyce911/esp32FOTA/pull/91
|
||||
[#92]: https://github.com/chrisjoyce911/esp32FOTA/pull/92
|
||||
|
||||
|
||||
### Libraries
|
||||
|
||||
This library relies on [semver.c by h2non](https://github.com/h2non/semver.c) for semantic versioning support. semver.c is licensed under [MIT](https://github.com/h2non/semver.c/blob/master/LICENSE).
|
||||
|
||||
Optional dependencies (zlib/gzip support):
|
||||
* [esp32-flashz](https://github.com/vortigont/esp32-flashz)
|
||||
* [esp32-targz](https://github.com/tobozo/ESP32-targz)
|
||||
|
||||
|
||||
### Thanks to
|
||||
|
||||
* @nuclearcat
|
||||
* @thinksilicon
|
||||
* @tuan-karma
|
||||
* @hpsaturn
|
||||
* @tobozo
|
||||
* @vortigont
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
/**
|
||||
esp32 firmware OTA
|
||||
|
||||
Purpose: Perform an OTA update from a bin located on a webserver (HTTP Only)
|
||||
|
||||
Setup:
|
||||
Step 1 : Set your WiFi (ssid & password)
|
||||
Step 2 : set esp32fota()
|
||||
|
||||
Upload:
|
||||
Step 1 : Menu > Sketch > Export Compiled Library. The bin file will be saved in the sketch folder (Menu > Sketch > Show Sketch folder)
|
||||
Step 2 : Upload it to your webserver
|
||||
Step 3 : Update your firmware JSON file ( see firwmareupdate )
|
||||
|
||||
*/
|
||||
|
||||
#include <esp32fota.h>
|
||||
#include <WiFi.h>
|
||||
|
||||
|
||||
// esp32fota esp32fota("<Type of Firme for this device>", <this version>, <validate signature>);
|
||||
esp32FOTA esp32FOTA("esp32-fota-http", 1, false);
|
||||
|
||||
const char* manifest_url = "http://server/fota/fota.json";
|
||||
|
||||
void setup_wifi()
|
||||
{
|
||||
delay(10);
|
||||
Serial.print("Connecting to WiFi");
|
||||
WiFi.begin(); // no WiFi creds in this demo :-)
|
||||
|
||||
while (WiFi.status() != WL_CONNECTED)
|
||||
{
|
||||
delay(500);
|
||||
Serial.print(".");
|
||||
}
|
||||
|
||||
Serial.println("");
|
||||
Serial.println(WiFi.localIP());
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
esp32FOTA.setManifestURL( manifest_url );
|
||||
esp32FOTA.printConfig();
|
||||
setup_wifi();
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
|
||||
bool updatedNeeded = esp32FOTA.execHTTPcheck();
|
||||
if (updatedNeeded)
|
||||
{
|
||||
esp32FOTA.execOTA();
|
||||
}
|
||||
|
||||
delay(2000);
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
/**
|
||||
esp32 firmware OTA
|
||||
|
||||
Purpose: Perform an OTA update from a bin located on a webserver (HTTPS)
|
||||
|
||||
Setup:
|
||||
Step 1 : Set your WiFi (ssid & password)
|
||||
Step 2 : set esp32fota()
|
||||
Step 3 : Provide SPIFFS filesystem with root_ca.pem of your webserver
|
||||
|
||||
Upload:
|
||||
Step 1 : Menu > Sketch > Export Compiled Library. The bin file will be saved in the sketch folder (Menu > Sketch > Show Sketch folder)
|
||||
Step 2 : Upload it to your webserver
|
||||
Step 3 : Update your firmware JSON file ( see firwmareupdate )
|
||||
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#include <WiFi.h>
|
||||
|
||||
#include <FS.h>
|
||||
#include <SPIFFS.h>
|
||||
#include <esp32fota.h>
|
||||
|
||||
|
||||
// esp32fota esp32fota("<Type of Firme for this device>", <this version>, <validate signature>);
|
||||
esp32FOTA esp32FOTA("esp32-fota-http", 1, false);
|
||||
const char* manifest_url = "https://server/fota/fota.json";
|
||||
|
||||
CryptoFileAsset *MyRootCA = new CryptoFileAsset( "/root_ca.pem", &SPIFFS );
|
||||
|
||||
void setup_wifi()
|
||||
{
|
||||
delay(10);
|
||||
Serial.print("Connecting to WiFi");
|
||||
|
||||
WiFi.begin(); // no WiFi creds in this demo :-)
|
||||
|
||||
while (WiFi.status() != WL_CONNECTED)
|
||||
{
|
||||
delay(500);
|
||||
Serial.print(".");
|
||||
}
|
||||
|
||||
Serial.println("");
|
||||
Serial.println(WiFi.localIP());
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
// Provide spiffs with root_ca.pem to validate server certificate
|
||||
SPIFFS.begin(true);
|
||||
esp32FOTA.setManifestURL( manifest_url );
|
||||
esp32FOTA.setRootCA( MyRootCA );
|
||||
esp32FOTA.printConfig();
|
||||
setup_wifi();
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
|
||||
bool updatedNeeded = esp32FOTA.execHTTPcheck();
|
||||
if (updatedNeeded)
|
||||
{
|
||||
esp32FOTA.execOTA();
|
||||
}
|
||||
|
||||
delay(2000);
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
/**
|
||||
esp32 firmware OTA
|
||||
|
||||
Purpose: Perform an OTA update from a bin located on a webserver (HTTPS) without having a root cert
|
||||
|
||||
Setup:
|
||||
Step 1 : Set your WiFi (ssid & password)
|
||||
Step 2 : set esp32fota()
|
||||
|
||||
Upload:
|
||||
Step 1 : Menu > Sketch > Export Compiled Library. The bin file will be saved in the sketch folder (Menu > Sketch > Show Sketch folder)
|
||||
Step 2 : Upload it to your webserver
|
||||
Step 3 : Update your firmware JSON file ( see firwmareupdate )
|
||||
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#include <WiFi.h>
|
||||
|
||||
#include <FS.h>
|
||||
#include <SPIFFS.h>
|
||||
#include <esp32fota.h>
|
||||
|
||||
|
||||
// esp32fota esp32fota("<Type of Firmware for this device>", <this version>, <validate signature>, <allow insecure https>);
|
||||
esp32FOTA esp32FOTA("esp32-fota-http", 1, false, true);
|
||||
const char* manifest_url = "http://server/fota/fota.json";
|
||||
|
||||
void setup_wifi()
|
||||
{
|
||||
delay(10);
|
||||
Serial.print("Connecting to WiFi");
|
||||
|
||||
WiFi.begin(); // no WiFi creds in this demo :-)
|
||||
|
||||
while (WiFi.status() != WL_CONNECTED)
|
||||
{
|
||||
delay(500);
|
||||
Serial.print(".");
|
||||
}
|
||||
|
||||
Serial.println("");
|
||||
Serial.println(WiFi.localIP());
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
esp32FOTA.setManifestURL( manifest_url );
|
||||
esp32FOTA.printConfig();
|
||||
setup_wifi();
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
|
||||
bool updatedNeeded = esp32FOTA.execHTTPcheck();
|
||||
if (updatedNeeded)
|
||||
{
|
||||
esp32FOTA.execOTA();
|
||||
}
|
||||
|
||||
delay(2000);
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
/**
|
||||
esp32 firmware OTA
|
||||
|
||||
Purpose: Perform an OTA update from a bin located on a webserver (HTTP Only)
|
||||
|
||||
Setup:
|
||||
Step 1 : Set your WiFi (ssid & password)
|
||||
Step 2 : set esp32fota()
|
||||
|
||||
Upload:
|
||||
Step 1 : Menu > Sketch > Export Compiled Library. The bin file will be saved in the sketch folder (Menu > Sketch > Show Sketch folder)
|
||||
Step 2 : Upload it to your webserver
|
||||
Step 3 : Update your firmware JSON file ( see firwmareupdate )
|
||||
|
||||
*/
|
||||
#include <Arduino.h>
|
||||
#include <WiFi.h>
|
||||
|
||||
#include <FS.h>
|
||||
#include <SPIFFS.h>
|
||||
|
||||
#include <esp32fota.h>
|
||||
|
||||
|
||||
// esp32fota esp32fota("<Type of Firme for this device>", <this version>, <validate signature>);
|
||||
esp32FOTA esp32FOTA("esp32-fota-http", 1, true);
|
||||
|
||||
const char* manifest_url = "http://server/fota/fota.json";
|
||||
CryptoFileAsset *MyRSAKey = new CryptoFileAsset( "/rsa_key.pub", &SPIFFS );
|
||||
|
||||
void setup_wifi()
|
||||
{
|
||||
delay(10);
|
||||
Serial.print("Connecting to WiFi");
|
||||
|
||||
// Need to provide SPIFFS with rsa_key.pub inside.
|
||||
SPIFFS.begin( true );
|
||||
|
||||
WiFi.begin(); // no WiFi creds in this demo :-)
|
||||
|
||||
while (WiFi.status() != WL_CONNECTED)
|
||||
{
|
||||
delay(500);
|
||||
Serial.print(".");
|
||||
}
|
||||
|
||||
Serial.println("");
|
||||
Serial.println(WiFi.localIP());
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
esp32FOTA.setManifestURL( manifest_url );
|
||||
esp32FOTA.setPubKey( MyRSAKey );
|
||||
esp32FOTA.printConfig();
|
||||
setup_wifi();
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
|
||||
bool updatedNeeded = esp32FOTA.execHTTPcheck();
|
||||
if (updatedNeeded)
|
||||
{
|
||||
esp32FOTA.execOTA();
|
||||
}
|
||||
|
||||
delay(2000);
|
||||
}
|
||||
@@ -1,129 +0,0 @@
|
||||
/**
|
||||
esp32 firmware OTA
|
||||
|
||||
Purpose: Perform an OTA update from a bin located on a webserver (HTTPS)
|
||||
|
||||
*/
|
||||
|
||||
// declare filesystem first !
|
||||
|
||||
//#include <SD.h>
|
||||
//#include <SD_MMC.h>
|
||||
//#include <SPIFFS.h>
|
||||
#include <LittleFS.h>
|
||||
//#include <PSRamFS.h>
|
||||
|
||||
//#include <flashz.hpp> // optional esp32-flashz for zlib compressed firmwares
|
||||
//#include <ESP32-targz.h> // optional ESP32-targz for gzip compressed firmwares
|
||||
#include <esp32fota.h> // fota pulls WiFi library
|
||||
|
||||
|
||||
|
||||
// esp32fota settings
|
||||
const int firmware_version = 1;
|
||||
#if !defined FOTA_URL
|
||||
#define FOTA_URL "http://server/fota/fota.json"
|
||||
#endif
|
||||
const char* firmware_name = "esp32-fota-http";
|
||||
const bool check_signature = false;
|
||||
const bool disable_security = false;
|
||||
// for debug only
|
||||
const char* description = "Basic example with any filesystem";
|
||||
|
||||
CryptoFileAsset *MyRootCA = new CryptoFileAsset( "/root_ca.pem", &LittleFS );
|
||||
// CryptoFileAsset *MyRootCA = new CryptoFileAsset( "/root_ca.pem", &SPIFFS );
|
||||
// CryptoMemAsset *MyRootCA = new CryptoMemAsset("Certificates Chain", root_ca, strlen(root_ca)+1 );
|
||||
|
||||
// CryptoFileAsset *MyRSAKey = new CryptoFileAsset( "/rsa_key.pub", &SPIFFS );
|
||||
CryptoFileAsset *MyRSAKey = new CryptoFileAsset( "/rsa_key.pub", &LittleFS );
|
||||
// CryptoMemAsset *MyRSAKey = new CryptoMemAsset("RSA Public Key", rsa_key_pub, strlen(rsa_key_pub)+1 );
|
||||
|
||||
|
||||
esp32FOTA FOTA; // empty constructor
|
||||
|
||||
|
||||
bool WiFiConnected()
|
||||
{
|
||||
return (WiFi.status() == WL_CONNECTED);
|
||||
}
|
||||
|
||||
|
||||
void setup_wifi()
|
||||
{
|
||||
delay(10);
|
||||
Serial.print("Connecting to WiFi ");
|
||||
Serial.println( WiFi.macAddress() );
|
||||
|
||||
WiFi.begin(); // no WiFi creds in this demo :-)
|
||||
|
||||
while ( !WiFiConnected() )
|
||||
{
|
||||
delay(500);
|
||||
Serial.print(".");
|
||||
}
|
||||
|
||||
Serial.println("");
|
||||
Serial.println(WiFi.localIP());
|
||||
|
||||
}
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
// Provide filesystem with root_ca.pem to validate server certificate
|
||||
if( ! LittleFS.begin( false ) ) {
|
||||
Serial.println("LittleFS Mounting failed, aborting!");
|
||||
while(1) vTaskDelay(1);
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
auto cfg = FOTA.getConfig();
|
||||
|
||||
cfg.name = (char*)firmware_name;
|
||||
cfg.manifest_url = (char*)FOTA_URL;
|
||||
cfg.sem = SemverClass( firmware_version );
|
||||
cfg.check_sig = check_signature;
|
||||
cfg.unsafe = disable_security;
|
||||
cfg.root_ca = MyRootCA;
|
||||
cfg.pub_key = MyRSAKey;
|
||||
|
||||
FOTA.setConfig( cfg );
|
||||
}
|
||||
|
||||
FOTA.printConfig();
|
||||
// FOTA.setStatusChecker( WiFiConnected );
|
||||
|
||||
|
||||
// /!\ FOTA.checkURL is deprecated, use setManifestURL( String ) instead
|
||||
//FOTA.setManifestURL( FOTA_URL );
|
||||
//FOTA.setRootCA( MyRootCA );
|
||||
//FOTA.setPubKey( MyRSAKey );
|
||||
// use this when more than one filesystem is used in the sketch
|
||||
// FOTA.setCertFileSystem( &SD );
|
||||
|
||||
// show progress when an update occurs (e.g. on a TFT display)
|
||||
FOTA.setProgressCb( [](size_t progress, size_t size) {
|
||||
if( progress == size || progress == 0 ) Serial.println();
|
||||
Serial.print(".");
|
||||
});
|
||||
|
||||
// add some custom headers to the http queries
|
||||
FOTA.setExtraHTTPHeader("Authorization", "Basic <credentials>");
|
||||
|
||||
setup_wifi();
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
|
||||
bool updatedNeeded = FOTA.execHTTPcheck();
|
||||
if (updatedNeeded)
|
||||
{
|
||||
FOTA.execOTA();
|
||||
}
|
||||
|
||||
delay(20000);
|
||||
}
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh
|
||||
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
|
||||
QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT
|
||||
MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
|
||||
b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG
|
||||
9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB
|
||||
CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97
|
||||
nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt
|
||||
43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P
|
||||
T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4
|
||||
gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO
|
||||
BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR
|
||||
TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw
|
||||
DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr
|
||||
hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg
|
||||
06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF
|
||||
PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls
|
||||
YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
|
||||
CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
|
||||
-----END CERTIFICATE-----
|
||||
@@ -1,84 +0,0 @@
|
||||
/**
|
||||
esp32 firmware OTA
|
||||
|
||||
Purpose: Perform an OTA update to both firmware and filesystem from binaries located
|
||||
on a webserver (HTTPS) without checking for certificate validity
|
||||
|
||||
Usage: If the ESP32 had a previous successful WiFi connection, then no need to set the ssid/password
|
||||
to run this sketch, the credentials are still cached :-)
|
||||
Sketch 1 will FOTA to Sketch 2, then Sketch 3, and so on until all versions in firmware.json are
|
||||
exhausted.
|
||||
|
||||
|
||||
*/
|
||||
|
||||
#include <ESP32-targz.h> // optional ESP32-targz for gzip compressed firmwares
|
||||
#include <esp32FOTA.hpp>
|
||||
#include <debug/test_fota_common.h>
|
||||
|
||||
// esp32fota settings
|
||||
int firmware_version_major = 1;
|
||||
int firmware_version_minor = 1;
|
||||
int firmware_version_patch = 0;
|
||||
|
||||
// #define FOTA_URL "http://server/fota/fota.json"
|
||||
|
||||
const char* firmware_name = "esp32-fota-http";
|
||||
const bool check_signature = false;
|
||||
const bool disable_security = true;
|
||||
// for debug only
|
||||
const char* title = "1.1";
|
||||
const char* description = "Basic example with no security and no filesystem";
|
||||
|
||||
|
||||
esp32FOTA FOTA;
|
||||
|
||||
|
||||
void setup_wifi()
|
||||
{
|
||||
delay(10);
|
||||
|
||||
Serial.print("MAC Address ");
|
||||
Serial.println( WiFi.macAddress() );
|
||||
|
||||
WiFi.begin(); // no WiFi creds in this demo :-)
|
||||
|
||||
while (WiFi.status() != WL_CONNECTED)
|
||||
{
|
||||
delay(500);
|
||||
Serial.print(".");
|
||||
}
|
||||
|
||||
Serial.println("");
|
||||
Serial.println(WiFi.localIP());
|
||||
}
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
|
||||
PrintFOTAInfo();
|
||||
|
||||
{
|
||||
auto cfg = FOTA.getConfig();
|
||||
cfg.name = (char*)firmware_name;
|
||||
cfg.manifest_url = (char*)FOTA_URL;
|
||||
cfg.sem = SemverClass( firmware_version_major, firmware_version_minor, firmware_version_patch );
|
||||
cfg.check_sig = check_signature;
|
||||
cfg.unsafe = disable_security;
|
||||
//cfg.root_ca = MyRootCA;
|
||||
//cfg.pub_key = MyRSAKey;
|
||||
FOTA.setConfig( cfg );
|
||||
}
|
||||
FOTA.printConfig();
|
||||
|
||||
setup_wifi();
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
FOTA.handle();
|
||||
delay(20000);
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
/**
|
||||
esp32 firmware OTA
|
||||
|
||||
Purpose: Perform an OTA update to both firmware and filesystem from binaries located
|
||||
on a webserver (HTTPS) without checking for certificate validity
|
||||
|
||||
Usage: If the ESP32 had a previous successful WiFi connection, then no need to set the ssid/password
|
||||
to run this sketch, the credentials are still cached :-)
|
||||
Sketch 1 will FOTA to Sketch 2, then Sketch 3, and so on until all versions in firmware.json are
|
||||
exhausted.
|
||||
|
||||
|
||||
*/
|
||||
|
||||
#include <flashz.hpp> // optional esp32-flashz for gzipped firmwares
|
||||
#include <esp32FOTA.hpp>
|
||||
#include <debug/test_fota_common.h>
|
||||
|
||||
// esp32fota settings
|
||||
int firmware_version_major = 1;
|
||||
int firmware_version_minor = 2;
|
||||
int firmware_version_patch = 0;
|
||||
|
||||
// #define FOTA_URL "http://server/fota/fota.json"
|
||||
|
||||
const char* firmware_name = "esp32-fota-http";
|
||||
const bool check_signature = false;
|
||||
const bool disable_security = true;
|
||||
// for debug only
|
||||
const char* title = "1.2";
|
||||
const char* description = "Basic *gzipped* example with no security and no filesystem";
|
||||
|
||||
|
||||
esp32FOTA FOTA;
|
||||
|
||||
|
||||
void setup_wifi()
|
||||
{
|
||||
delay(10);
|
||||
|
||||
Serial.print("MAC Address ");
|
||||
Serial.println( WiFi.macAddress() );
|
||||
|
||||
WiFi.begin(); // no WiFi creds in this demo :-)
|
||||
|
||||
while (WiFi.status() != WL_CONNECTED)
|
||||
{
|
||||
delay(500);
|
||||
Serial.print(".");
|
||||
}
|
||||
|
||||
Serial.println("");
|
||||
Serial.println(WiFi.localIP());
|
||||
}
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
|
||||
PrintFOTAInfo();
|
||||
|
||||
{
|
||||
auto cfg = FOTA.getConfig();
|
||||
cfg.name = (char*)firmware_name;
|
||||
cfg.manifest_url = (char*)FOTA_URL;
|
||||
cfg.sem = SemverClass( firmware_version_major, firmware_version_minor, firmware_version_patch );
|
||||
cfg.check_sig = check_signature;
|
||||
cfg.unsafe = disable_security;
|
||||
//cfg.root_ca = MyRootCA;
|
||||
//cfg.pub_key = MyRSAKey;
|
||||
FOTA.setConfig( cfg );
|
||||
}
|
||||
FOTA.printConfig();
|
||||
|
||||
setup_wifi();
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
bool updatedNeeded = FOTA.execHTTPcheck();
|
||||
if (updatedNeeded) {
|
||||
FOTA.execOTA();
|
||||
}
|
||||
|
||||
delay(20000);
|
||||
}
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
/**
|
||||
esp32 firmware OTA
|
||||
|
||||
Purpose: Perform an OTA update to both firmware and filesystem from binaries located
|
||||
on a webserver (HTTPS) without checking for certificate validity
|
||||
|
||||
Usage: If the ESP32 had a previous successful WiFi connection, then no need to set the ssid/password
|
||||
to run this sketch, the credentials are still cached :-)
|
||||
Sketch 1 will FOTA to Sketch 2, then Sketch 3, and so on until all versions in firmware.json are
|
||||
exhausted.
|
||||
|
||||
|
||||
*/
|
||||
|
||||
#include <esp32FOTA.hpp>
|
||||
#include <debug/test_fota_common.h>
|
||||
|
||||
// esp32fota settings
|
||||
int firmware_version_major = 1;
|
||||
int firmware_version_minor = 3;
|
||||
int firmware_version_patch = 0;
|
||||
|
||||
// #define FOTA_URL "http://server/fota/fota.json"
|
||||
|
||||
const char* firmware_name = "esp32-fota-http";
|
||||
const bool check_signature = false;
|
||||
const bool disable_security = true;
|
||||
// for debug only
|
||||
const char* title = "1.3";
|
||||
const char* description = "Basic *gzipped* example with no security and no filesystem";
|
||||
|
||||
|
||||
esp32FOTA FOTA;
|
||||
|
||||
|
||||
void setup_wifi()
|
||||
{
|
||||
delay(10);
|
||||
|
||||
Serial.print("MAC Address ");
|
||||
Serial.println( WiFi.macAddress() );
|
||||
|
||||
WiFi.begin(); // no WiFi creds in this demo :-)
|
||||
|
||||
while (WiFi.status() != WL_CONNECTED)
|
||||
{
|
||||
delay(500);
|
||||
Serial.print(".");
|
||||
}
|
||||
|
||||
Serial.println("");
|
||||
Serial.println(WiFi.localIP());
|
||||
}
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
|
||||
PrintFOTAInfo();
|
||||
|
||||
{
|
||||
auto cfg = FOTA.getConfig();
|
||||
cfg.name = (char*)firmware_name;
|
||||
cfg.manifest_url = (char*)FOTA_URL;
|
||||
cfg.sem = SemverClass( firmware_version_major, firmware_version_minor, firmware_version_patch );
|
||||
cfg.check_sig = check_signature;
|
||||
cfg.unsafe = disable_security;
|
||||
//cfg.root_ca = MyRootCA;
|
||||
//cfg.pub_key = MyRSAKey;
|
||||
FOTA.setConfig( cfg );
|
||||
}
|
||||
FOTA.printConfig();
|
||||
|
||||
setup_wifi();
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
bool updatedNeeded = FOTA.execHTTPcheck();
|
||||
if (updatedNeeded) {
|
||||
FOTA.execOTA();
|
||||
}
|
||||
|
||||
delay(20000);
|
||||
}
|
||||
|
||||
@@ -1,99 +0,0 @@
|
||||
/**
|
||||
esp32 firmware OTA
|
||||
|
||||
Purpose: Perform an OTA update firmware from a bin located on a webserver (HTTPS)
|
||||
while using filesystem to check for certificate validity
|
||||
|
||||
*/
|
||||
|
||||
#include <SPIFFS.h> // include filesystem **before** esp32fota !!
|
||||
#include <esp32fota.h>
|
||||
#include <debug/test_fota_common.h>
|
||||
|
||||
// esp32fota settings
|
||||
int firmware_version_major = 2;
|
||||
int firmware_version_minor = 0;
|
||||
int firmware_version_patch = 0;
|
||||
|
||||
// #define FOTA_URL "http://server/fota/fota.json"
|
||||
|
||||
const char* firmware_name = "esp32-fota-http";
|
||||
const bool check_signature = false;
|
||||
const bool disable_security = false;
|
||||
// for debug only
|
||||
const char* title = "2";
|
||||
const char* description = "SPIFFS example with security";
|
||||
|
||||
|
||||
esp32FOTA FOTA;
|
||||
|
||||
|
||||
// CryptoFileAsset *MyRootCA = new CryptoFileAsset( "/root_ca.pem", &LittleFS );
|
||||
CryptoFileAsset *MyRootCA = new CryptoFileAsset( "/root_ca.pem", &SPIFFS );
|
||||
// CryptoMemAsset *MyRootCA = new CryptoMemAsset("Certificates Chain", root_ca, strlen(root_ca)+1 );
|
||||
|
||||
// CryptoFileAsset *MyRSAKey = new CryptoFileAsset( "/rsa_key.pub", &SPIFFS );
|
||||
// CryptoFileAsset *MyRSAKey = new CryptoFileAsset( "/rsa_key.pub", &LittleFS );
|
||||
// CryptoMemAsset *MyRSAKey = new CryptoMemAsset("RSA Public Key", pub_key, strlen(pub_key)+1 );
|
||||
|
||||
|
||||
void setup_wifi()
|
||||
{
|
||||
delay(10);
|
||||
Serial.print("MAC Address ");
|
||||
Serial.println( WiFi.macAddress() );
|
||||
|
||||
WiFi.begin(); // no WiFi creds in this demo :-)
|
||||
|
||||
while (WiFi.status() != WL_CONNECTED)
|
||||
{
|
||||
delay(500);
|
||||
Serial.print(".");
|
||||
}
|
||||
|
||||
Serial.println("");
|
||||
Serial.println(WiFi.localIP());
|
||||
}
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
|
||||
PrintFOTAInfo();
|
||||
|
||||
// Provide filesystem with root_ca.pem to validate server certificate
|
||||
if( ! SPIFFS.begin( false ) ) {
|
||||
Serial.println("SPIFFS Mounting failed, aborting!");
|
||||
while(1) vTaskDelay(1);
|
||||
}
|
||||
|
||||
{
|
||||
auto cfg = FOTA.getConfig();
|
||||
cfg.name = (char*)firmware_name;
|
||||
cfg.manifest_url = (char*)FOTA_URL;
|
||||
cfg.sem = SemverClass( firmware_version_major, firmware_version_minor, firmware_version_patch );
|
||||
cfg.check_sig = check_signature;
|
||||
cfg.unsafe = disable_security;
|
||||
cfg.root_ca = MyRootCA;
|
||||
//cfg.pub_key = MyRSAKey;
|
||||
FOTA.setConfig( cfg );
|
||||
}
|
||||
FOTA.printConfig();
|
||||
|
||||
setup_wifi();
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
bool updatedNeeded = FOTA.execHTTPcheck();
|
||||
if (updatedNeeded) {
|
||||
FOTA.execOTA();
|
||||
}
|
||||
|
||||
delay(20000);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh
|
||||
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
|
||||
QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT
|
||||
MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
|
||||
b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG
|
||||
9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB
|
||||
CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97
|
||||
nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt
|
||||
43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P
|
||||
T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4
|
||||
gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO
|
||||
BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR
|
||||
TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw
|
||||
DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr
|
||||
hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg
|
||||
06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF
|
||||
PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls
|
||||
YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
|
||||
CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
|
||||
-----END CERTIFICATE-----
|
||||
@@ -1,93 +0,0 @@
|
||||
/**
|
||||
esp32 firmware OTA
|
||||
|
||||
Purpose: Perform an OTA update to both firmware and filesystem from binaries located
|
||||
on a webserver (HTTPS) while using progmem to check for certificate validity
|
||||
|
||||
|
||||
*/
|
||||
|
||||
#include <esp32fota.h>
|
||||
#include <debug/test_fota_common.h>
|
||||
|
||||
#include "root_ca.h"
|
||||
|
||||
// esp32fota settings
|
||||
int firmware_version_major = 3;
|
||||
int firmware_version_minor = 0;
|
||||
int firmware_version_patch = 0;
|
||||
|
||||
// #define FOTA_URL "http://server/fota/fota.json"
|
||||
|
||||
const char* firmware_name = "esp32-fota-http";
|
||||
const bool check_signature = false;
|
||||
const bool disable_security = false;
|
||||
// for debug only
|
||||
const char* title = "3";
|
||||
const char* description = "PROGMEM example with security";
|
||||
|
||||
|
||||
esp32FOTA FOTA;
|
||||
|
||||
// CryptoFileAsset *MyRootCA = new CryptoFileAsset( "/root_ca.pem", &LittleFS );
|
||||
// CryptoFileAsset *MyRootCA = new CryptoFileAsset( "/root_ca.pem", &SPIFFS );
|
||||
CryptoMemAsset *MyRootCA = new CryptoMemAsset("Certificates Chain", root_ca, strlen(root_ca)+1 );
|
||||
|
||||
// CryptoFileAsset *MyRSAKey = new CryptoFileAsset( "/rsa_key.pub", &SPIFFS );
|
||||
// CryptoFileAsset *MyRSAKey = new CryptoFileAsset( "/rsa_key.pub", &LittleFS );
|
||||
// CryptoMemAsset *MyRSAKey = new CryptoMemAsset("RSA Public Key", pub_key, strlen(pub_key)+1 );
|
||||
|
||||
|
||||
void setup_wifi()
|
||||
{
|
||||
delay(10);
|
||||
Serial.print("Connecting to WiFi ");
|
||||
Serial.println( WiFi.macAddress() );
|
||||
|
||||
WiFi.begin(); // no WiFi creds in this demo :-)
|
||||
|
||||
while (WiFi.status() != WL_CONNECTED)
|
||||
{
|
||||
delay(500);
|
||||
Serial.print(".");
|
||||
}
|
||||
|
||||
Serial.println("");
|
||||
Serial.println(WiFi.localIP());
|
||||
|
||||
FOTA.setRootCA( MyRootCA );
|
||||
}
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
|
||||
PrintFOTAInfo();
|
||||
|
||||
{
|
||||
auto cfg = FOTA.getConfig();
|
||||
cfg.name = (char*)firmware_name;
|
||||
cfg.manifest_url = (char*)FOTA_URL;
|
||||
cfg.sem = SemverClass( firmware_version_major, firmware_version_minor, firmware_version_patch );
|
||||
cfg.check_sig = check_signature;
|
||||
cfg.unsafe = disable_security;
|
||||
cfg.root_ca = MyRootCA;
|
||||
//cfg.pub_key = MyRSAKey;
|
||||
FOTA.setConfig( cfg );
|
||||
}
|
||||
FOTA.printConfig();
|
||||
|
||||
setup_wifi();
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
bool updatedNeeded = FOTA.execHTTPcheck();
|
||||
if (updatedNeeded) {
|
||||
FOTA.execOTA();
|
||||
}
|
||||
|
||||
delay(20000);
|
||||
}
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
|
||||
const char* /*github_*/root_ca = R"ROOT_CA(
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh
|
||||
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
|
||||
QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT
|
||||
MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
|
||||
b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG
|
||||
9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB
|
||||
CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97
|
||||
nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt
|
||||
43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P
|
||||
T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4
|
||||
gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO
|
||||
BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR
|
||||
TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw
|
||||
DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr
|
||||
hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg
|
||||
06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF
|
||||
PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls
|
||||
YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
|
||||
CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
|
||||
-----END CERTIFICATE-----
|
||||
)ROOT_CA";
|
||||
@@ -1,99 +0,0 @@
|
||||
/**
|
||||
esp32 firmware OTA
|
||||
|
||||
Purpose: Perform an OTA update firmware from a bin located on a webserver (HTTPS)
|
||||
while using filesystem to check for certificate validity
|
||||
|
||||
*/
|
||||
|
||||
#include <LittleFS.h> // include filesystem **before** esp32fota !!
|
||||
#include <esp32fota.h>
|
||||
#include <debug/test_fota_common.h>
|
||||
|
||||
// esp32fota settings
|
||||
int firmware_version_major = 4;
|
||||
int firmware_version_minor = 0;
|
||||
int firmware_version_patch = 0;
|
||||
|
||||
// #define FOTA_URL "http://server/fota/fota.json"
|
||||
|
||||
const char* firmware_name = "esp32-fota-http";
|
||||
const bool check_signature = true;
|
||||
const bool disable_security = false;
|
||||
// for debug only
|
||||
const char* title = "4";
|
||||
const char* description = "LittleFS example with enforced security";
|
||||
|
||||
|
||||
esp32FOTA FOTA;
|
||||
|
||||
CryptoFileAsset *MyRootCA = new CryptoFileAsset( "/root_ca.pem", &LittleFS );
|
||||
// CryptoFileAsset *MyRootCA = new CryptoFileAsset( "/root_ca.pem", &SPIFFS );
|
||||
// CryptoMemAsset *MyRootCA = new CryptoMemAsset("Certificates Chain", root_ca, strlen(root_ca)+1 );
|
||||
|
||||
// CryptoFileAsset *MyRSAKey = new CryptoFileAsset( "/rsa_key.pub", &SPIFFS );
|
||||
CryptoFileAsset *MyRSAKey = new CryptoFileAsset( "/rsa_key.pub", &LittleFS );
|
||||
// CryptoMemAsset *MyRSAKey = new CryptoMemAsset("RSA Public Key", pub_key, strlen(pub_key)+1 );
|
||||
|
||||
|
||||
void setup_wifi()
|
||||
{
|
||||
delay(10);
|
||||
|
||||
Serial.print("MAC Address ");
|
||||
Serial.println( WiFi.macAddress() );
|
||||
|
||||
WiFi.begin(); // no WiFi creds in this demo :-)
|
||||
|
||||
while (WiFi.status() != WL_CONNECTED)
|
||||
{
|
||||
delay(500);
|
||||
Serial.print(".");
|
||||
}
|
||||
|
||||
Serial.println("");
|
||||
Serial.println(WiFi.localIP());
|
||||
}
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
|
||||
PrintFOTAInfo();
|
||||
|
||||
// Provide filesystem with root_ca.pem to validate server certificate
|
||||
if( ! LittleFS.begin( false ) ) {
|
||||
Serial.println("LittleFS Mounting failed, aborting!");
|
||||
while(1) vTaskDelay(1);
|
||||
}
|
||||
|
||||
{
|
||||
auto cfg = FOTA.getConfig();
|
||||
cfg.name = (char*)firmware_name;
|
||||
cfg.manifest_url = (char*)FOTA_URL;
|
||||
cfg.sem = SemverClass( firmware_version_major, firmware_version_minor, firmware_version_patch );
|
||||
cfg.check_sig = check_signature;
|
||||
cfg.unsafe = disable_security;
|
||||
cfg.root_ca = MyRootCA;
|
||||
cfg.pub_key = MyRSAKey;
|
||||
FOTA.setConfig( cfg );
|
||||
}
|
||||
FOTA.printConfig();
|
||||
|
||||
setup_wifi();
|
||||
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
bool updatedNeeded = FOTA.execHTTPcheck();
|
||||
if (updatedNeeded) {
|
||||
FOTA.execOTA();
|
||||
}
|
||||
|
||||
delay(20000);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh
|
||||
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
|
||||
QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT
|
||||
MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
|
||||
b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG
|
||||
9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB
|
||||
CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97
|
||||
nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt
|
||||
43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P
|
||||
T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4
|
||||
gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO
|
||||
BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR
|
||||
TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw
|
||||
DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr
|
||||
hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg
|
||||
06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF
|
||||
PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls
|
||||
YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
|
||||
CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
|
||||
-----END CERTIFICATE-----
|
||||
@@ -1,93 +0,0 @@
|
||||
/**
|
||||
esp32 firmware OTA
|
||||
|
||||
Purpose: Perform an OTA update to both firmware and filesystem from binaries located
|
||||
on a webserver (HTTPS) while using progmem to check for certificate validity
|
||||
|
||||
|
||||
*/
|
||||
|
||||
#include <esp32fota.h>
|
||||
#include <debug/test_fota_common.h>
|
||||
|
||||
#include "root_ca.h"
|
||||
#include "pub_key.h"
|
||||
|
||||
// esp32fota settings
|
||||
int firmware_version_major = 5;
|
||||
int firmware_version_minor = 0;
|
||||
int firmware_version_patch = 0;
|
||||
|
||||
// #define FOTA_URL "http://server/fota/fota.json"
|
||||
|
||||
const char* firmware_name = "esp32-fota-http";
|
||||
const bool check_signature = true;
|
||||
const bool disable_security = false;
|
||||
// for debug only
|
||||
const char* title = "5";
|
||||
const char* description = "PROGMEM example with enforced security";
|
||||
|
||||
|
||||
esp32FOTA FOTA;
|
||||
|
||||
// CryptoFileAsset *MyRootCA = new CryptoFileAsset( "/root_ca.pem", &LittleFS );
|
||||
// CryptoFileAsset *MyRootCA = new CryptoFileAsset( "/root_ca.pem", &SPIFFS );
|
||||
CryptoMemAsset *MyRootCA = new CryptoMemAsset("Certificates Chain", root_ca, strlen(root_ca)+1 );
|
||||
|
||||
// CryptoFileAsset *MyRSAKey = new CryptoFileAsset( "/rsa_key.pub", &SPIFFS );
|
||||
// CryptoFileAsset *MyRSAKey = new CryptoFileAsset( "/rsa_key.pub", &LittleFS );
|
||||
CryptoMemAsset *MyRSAKey = new CryptoMemAsset("RSA Public Key", pub_key, strlen(pub_key)+1 );
|
||||
|
||||
|
||||
void setup_wifi()
|
||||
{
|
||||
delay(10);
|
||||
Serial.print("Connecting to WiFi ");
|
||||
Serial.println( WiFi.macAddress() );
|
||||
|
||||
WiFi.begin(); // no WiFi creds in this demo :-)
|
||||
|
||||
while (WiFi.status() != WL_CONNECTED)
|
||||
{
|
||||
delay(500);
|
||||
Serial.print(".");
|
||||
}
|
||||
|
||||
Serial.println("");
|
||||
Serial.println(WiFi.localIP());
|
||||
}
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
|
||||
PrintFOTAInfo();
|
||||
|
||||
{
|
||||
auto cfg = FOTA.getConfig();
|
||||
cfg.name = (char*)firmware_name;
|
||||
cfg.manifest_url = (char*)FOTA_URL;
|
||||
cfg.sem = SemverClass( firmware_version_major, firmware_version_minor, firmware_version_patch );
|
||||
cfg.check_sig = check_signature;
|
||||
cfg.unsafe = disable_security;
|
||||
cfg.root_ca = MyRootCA;
|
||||
cfg.pub_key = MyRSAKey;
|
||||
FOTA.setConfig( cfg );
|
||||
}
|
||||
FOTA.printConfig();
|
||||
|
||||
setup_wifi();
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
bool updatedNeeded = FOTA.execHTTPcheck();
|
||||
if (updatedNeeded) {
|
||||
FOTA.execOTA();
|
||||
}
|
||||
|
||||
delay(20000);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
|
||||
const char* /*github_*/pub_key = R"ROOT_CA(
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh
|
||||
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
|
||||
QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT
|
||||
MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
|
||||
b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG
|
||||
9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB
|
||||
CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97
|
||||
nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt
|
||||
43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P
|
||||
T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4
|
||||
gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO
|
||||
BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR
|
||||
TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw
|
||||
DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr
|
||||
hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg
|
||||
06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF
|
||||
PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls
|
||||
YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
|
||||
CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
|
||||
-----END CERTIFICATE-----
|
||||
)ROOT_CA";
|
||||
@@ -1,25 +0,0 @@
|
||||
|
||||
const char* /*github_*/root_ca = R"ROOT_CA(
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh
|
||||
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
|
||||
QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT
|
||||
MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
|
||||
b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG
|
||||
9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB
|
||||
CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97
|
||||
nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt
|
||||
43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P
|
||||
T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4
|
||||
gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO
|
||||
BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR
|
||||
TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw
|
||||
DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr
|
||||
hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg
|
||||
06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF
|
||||
PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls
|
||||
YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
|
||||
CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
|
||||
-----END CERTIFICATE-----
|
||||
)ROOT_CA";
|
||||
@@ -1,20 +0,0 @@
|
||||
// Just a dummy script prevent an endless OTA loop to occur
|
||||
// It validates the last step in the test suite by printing a message in the serial.
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin( 115200 );
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
Serial.println("**************************");
|
||||
Serial.println("Test suite COMPLETE :-)");
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
/**
|
||||
esp32 firmware OTA
|
||||
|
||||
Purpose: Perform an OTA update from a bin located on a webserver
|
||||
|
||||
Setup:
|
||||
Step 1 : Set your WiFi (ssid & password)
|
||||
Step 2 : set esp32fota()
|
||||
|
||||
Upload:
|
||||
Step 1 : Menu > Sketch > Export Compiled Library. The bin file will be saved in the sketch folder (Menu > Sketch > Show Sketch folder)
|
||||
Step 2 : Upload it to your webserver
|
||||
Step 3 : Update your firmware JSON file ( see firwmareupdate )
|
||||
|
||||
*/
|
||||
|
||||
#include <esp32fota.h>
|
||||
#include <WiFi.h>
|
||||
|
||||
|
||||
// esp32fota esp32fota("<Type of Firmware for this device>", <this version>, <validate signature>);
|
||||
esp32FOTA esp32FOTA("esp32-fota-http", 1, false);
|
||||
|
||||
const char* manifest_url = "http://server/fota/fota.json";
|
||||
|
||||
void setup_wifi()
|
||||
{
|
||||
delay(10);
|
||||
Serial.print("Connecting to WiFi");
|
||||
|
||||
WiFi.begin(); // no WiFi creds in this demo :-)
|
||||
|
||||
while (WiFi.status() != WL_CONNECTED)
|
||||
{
|
||||
delay(500);
|
||||
Serial.print(".");
|
||||
}
|
||||
|
||||
Serial.println("");
|
||||
Serial.println(WiFi.localIP());
|
||||
}
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
esp32FOTA.setManifestURL( manifest_url );
|
||||
esp32FOTA.printConfig();
|
||||
setup_wifi();
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
delay(2000);
|
||||
esp32FOTA.forceUpdate("192.168.0.100", 80, "/fota/esp32-fota-http-2.bin", true ); // check signature: true
|
||||
|
||||
// Alternatively, forceUpdate can be called with a complete URL:
|
||||
//esp32FOTA.forceUpdate("http://192.168.0.100/fota/esp32-fota-http-2.bin", true ); // check signature: true
|
||||
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
/**
|
||||
esp32 firmware OTA
|
||||
|
||||
Purpose: Perform an OTA update from a bin located on a webserver (HTTP Only)
|
||||
|
||||
Setup:
|
||||
Step 1 : Set your WiFi (ssid & password)
|
||||
Step 2 : set esp32fota()
|
||||
|
||||
Upload:
|
||||
Step 1 : Menu > Sketch > Export Compiled Library. The bin file will be saved in the sketch folder (Menu > Sketch > Show Sketch folder)
|
||||
Step 2 : Upload it to your webserver
|
||||
Step 3 : Update your firmware JSON file ( see firwmareupdate )
|
||||
|
||||
*/
|
||||
|
||||
#include <esp32fota.h>
|
||||
#include <WiFi.h>
|
||||
|
||||
|
||||
// esp32fota esp32fota("<Type of Firme for this device>", <this version>, <validate signature>);
|
||||
esp32FOTA esp32FOTA("esp32-fota-http", 1, false);
|
||||
const char* manifest_url = "http://server/fota/fota.json";
|
||||
|
||||
void setup_wifi()
|
||||
{
|
||||
delay(10);
|
||||
Serial.print("Connecting to WiFi");
|
||||
|
||||
WiFi.begin(); // no WiFi creds in this demo :-)
|
||||
|
||||
while (WiFi.status() != WL_CONNECTED)
|
||||
{
|
||||
delay(500);
|
||||
Serial.print(".");
|
||||
}
|
||||
|
||||
Serial.println("");
|
||||
Serial.println(WiFi.localIP());
|
||||
}
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
esp32FOTA.setManifestURL( manifest_url );
|
||||
esp32FOTA.useDeviceId( true );
|
||||
esp32FOTA.printConfig();
|
||||
setup_wifi();
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
bool updatedNeeded = esp32FOTA.execHTTPcheck();
|
||||
if (updatedNeeded)
|
||||
{
|
||||
esp32FOTA.execOTA();
|
||||
}
|
||||
|
||||
delay(2000);
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"type": "esp32-fota-http",
|
||||
"version": 2,
|
||||
"host": "192.168.0.100",
|
||||
"port": 80,
|
||||
"bin": "/fota/esp32-fota-http-2.bin"
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
#######################################
|
||||
# Syntax Coloring Map For esp32FOTA
|
||||
#######################################
|
||||
|
||||
#######################################
|
||||
# Datatypes (KEYWORD1)
|
||||
#######################################
|
||||
|
||||
esp32FOTA KEYWORD1
|
||||
useDeviceID KEYWORD1
|
||||
checkURL KEYWORD1
|
||||
|
||||
#######################################
|
||||
# Methods and Functions (KEYWORD2)
|
||||
#######################################
|
||||
|
||||
execOTA KEYWORD2
|
||||
execHTTPcheck KEYWORD2
|
||||
|
||||
#######################################
|
||||
# Constants (LITERAL1)
|
||||
#######################################
|
||||
@@ -1,30 +0,0 @@
|
||||
{
|
||||
"name": "esp32FOTA",
|
||||
"version": "0.2.7",
|
||||
"keywords": "firmware, OTA, Over The Air Updates, ArduinoOTA",
|
||||
"description": "Allows for firmware to be updated from a webserver, the device can check for updates at any time. Uses a simple JSON file to outline if a new firmware is avaiable.",
|
||||
"examples": "examples/*/*.ino",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/chrisjoyce911/esp32FOTA.git"
|
||||
},
|
||||
"authors": [
|
||||
{
|
||||
"name": "Chris Joyce",
|
||||
"email": "chris@joyce.id.au",
|
||||
"url": "https://github.com/chrisjoyce911",
|
||||
"maintainer": true
|
||||
}
|
||||
],
|
||||
"frameworks": "arduino",
|
||||
"headers": "esp32FOTA.hpp",
|
||||
"platforms": [
|
||||
"esp32",
|
||||
"espressif32"
|
||||
],
|
||||
"dependencies": [
|
||||
"WiFiClientSecure",
|
||||
"HTTPClient",
|
||||
"ArduinoJson"
|
||||
]
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
name=esp32FOTA
|
||||
version=0.2.7
|
||||
author=Chris Joyce
|
||||
maintainer=Chris Joyce <chris@joyce.id.au>
|
||||
sentence=A simple library for firmware OTA updates
|
||||
paragraph=Allows for firmware to be updated from a webserver, the device can check for updates at any time. Uses a simple JSON file to outline if a new firmware is available.
|
||||
category=Communication
|
||||
url=https://github.com/chrisjoyce911/esp32FOTA
|
||||
architectures=esp32,espressif32
|
||||
includes=esp32FOTA.hpp
|
||||
depends=ArduinoJson
|
||||
@@ -1,52 +0,0 @@
|
||||
; CanAirIO Sensorlib
|
||||
;
|
||||
; Full guide and details: https://github.com/kike-canaries/canairio_sensorlib
|
||||
|
||||
|
||||
[platformio]
|
||||
src_dir = ./tests/
|
||||
;lib_dir = ./
|
||||
|
||||
[env]
|
||||
framework = arduino
|
||||
upload_speed = 1500000
|
||||
monitor_speed = 115200
|
||||
monitor_filters = time
|
||||
build_flags =
|
||||
-D CORE_DEBUG_LEVEL=0
|
||||
lib_deps =
|
||||
bblanchon/ArduinoJson @ ^6
|
||||
esp32FOTA
|
||||
; vortigont/esp32-flashz
|
||||
; tobozo/ESP32-targz
|
||||
|
||||
[esp32_common]
|
||||
platform = espressif32
|
||||
board = esp32dev
|
||||
framework = ${env.framework}
|
||||
upload_speed = ${env.upload_speed}
|
||||
monitor_speed = ${env.monitor_speed}
|
||||
lib_deps = ${env.lib_deps}
|
||||
build_flags =
|
||||
${env.build_flags}
|
||||
|
||||
[env:esp32_http]
|
||||
extends = esp32_common
|
||||
build_src_filter = -<*> +<test_http>
|
||||
|
||||
[env:esp32_http_debug]
|
||||
extends = esp32_common
|
||||
build_flags =
|
||||
-D CORE_DEBUG_LEVEL=4
|
||||
build_src_filter = -<*> +<test_http>
|
||||
|
||||
[env:esp32_https]
|
||||
extends = esp32_common
|
||||
build_src_filter = -<*> +<test_https>
|
||||
|
||||
[env:esp32_https_debug]
|
||||
extends = esp32_common
|
||||
build_flags =
|
||||
-D CORE_DEBUG_LEVEL=4
|
||||
build_src_filter = -<*> +<test_https>
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
// esp32fota settings
|
||||
extern int firmware_version_major;
|
||||
extern int firmware_version_minor;
|
||||
extern int firmware_version_patch;
|
||||
|
||||
#if !defined FOTA_URL
|
||||
#define FOTA_URL "http://server/fota/fota.json"
|
||||
#endif
|
||||
|
||||
extern const char* firmware_name;
|
||||
extern const bool check_signature;
|
||||
extern const bool disable_security;
|
||||
// for debug only
|
||||
extern const char* description;
|
||||
extern const char* title;
|
||||
|
||||
extern esp32FOTA FOTA;
|
||||
|
||||
const char* fota_debug_fmt = R"DBG_FMT(
|
||||
|
||||
***************** STAGE %s *****************
|
||||
|
||||
Description : %s
|
||||
Firmware type : %s
|
||||
Firmware version : %i.%i.%i
|
||||
Signature check : %s
|
||||
TLS Cert check : %s
|
||||
Compression : %s
|
||||
|
||||
********************************************
|
||||
|
||||
)DBG_FMT";
|
||||
|
||||
|
||||
void PrintFOTAInfo()
|
||||
{
|
||||
Serial.printf( fota_debug_fmt,
|
||||
title,
|
||||
description,
|
||||
firmware_name,
|
||||
firmware_version_major,
|
||||
firmware_version_minor,
|
||||
firmware_version_patch,
|
||||
check_signature ?"Enabled":"Disabled",
|
||||
disable_security ?"Disabled":"Enabled",
|
||||
FOTA.zlibSupported() ?"Enabled":"Disabled"
|
||||
);
|
||||
}
|
||||
@@ -1,395 +0,0 @@
|
||||
/*
|
||||
esp32 firmware OTA
|
||||
Date: December 2018
|
||||
Author: Chris Joyce <https://github.com/chrisjoyce911/esp32FOTA/esp32FOTA>
|
||||
Purpose: Perform an OTA update from a bin located on a webserver (HTTP Only)
|
||||
|
||||
Date: 2021-12-21
|
||||
Author: Moritz Meintker <https://thinksilicon.de>
|
||||
Remarks: Re-written/removed a bunch of functions around HTTPS. The library is
|
||||
now URL-agnostic. This means if you provide an https://-URL it will
|
||||
use the root_ca.pem (needs to be provided via PROGMEM/SPIFFS/LittleFS or SD)
|
||||
to verify the server certificate and then download the ressource through an
|
||||
encrypted connection unless you set the allow_insecure_https option.
|
||||
Otherwise it will just use plain HTTP which will still offer to sign
|
||||
your firmware image.
|
||||
|
||||
Date: 2022-09-12
|
||||
Author: tobozo <https://github.com/tobozo>
|
||||
Changes:
|
||||
- Abstracted away filesystem
|
||||
- Refactored some code blocks
|
||||
- Added spiffs/littlefs/fatfs updatability
|
||||
- Made crypto assets (pub key, rootca) loadable from multiple sources
|
||||
Roadmap:
|
||||
- Firmware/FlashFS update order (SPIFFS/LittleFS first or last?)
|
||||
- Archive support for gz/targz formats
|
||||
- firmware.gz + spiffs.gz in manifest
|
||||
- bundle.tar.gz [ firmware + filesystem ] in manifest
|
||||
- Update from Stream (e.g deported update via SD, http or gzupdater)
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define esp32fota_h
|
||||
|
||||
extern "C" {
|
||||
#include "semver/semver.h"
|
||||
}
|
||||
|
||||
#include <map>
|
||||
#include <WiFiClientSecure.h>
|
||||
#include <HTTPClient.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include <FS.h>
|
||||
|
||||
// inherit includes from sketch, detect SPIFFS first for legacy support
|
||||
#if __has_include(<SPIFFS.h>) || defined _SPIFFS_H_
|
||||
#if !defined(DISABLE_ALL_LIBRARY_WARNINGS)
|
||||
#pragma message "Using SPIFFS for certificate validation"
|
||||
#endif
|
||||
#include <SPIFFS.h>
|
||||
#define FOTA_FS &SPIFFS
|
||||
#elif __has_include(<LittleFS.h>) || defined _LiffleFS_H_
|
||||
#if !defined(DISABLE_ALL_LIBRARY_WARNINGS)
|
||||
#pragma message "Using LittleFS for certificate validation"
|
||||
#endif
|
||||
#include <LittleFS.h>
|
||||
#define FOTA_FS &LittleFS
|
||||
#elif __has_include(<SD.h>) || defined _SD_H_
|
||||
#if !defined(DISABLE_ALL_LIBRARY_WARNINGS)
|
||||
#pragma message "Using SD for certificate validation"
|
||||
#endif
|
||||
#include <SD.h>
|
||||
#define FOTA_FS &SD
|
||||
#elif __has_include(<SD_MMC.h>) || defined _SD_MMC_H_
|
||||
#if !defined(DISABLE_ALL_LIBRARY_WARNINGS)
|
||||
#pragma message "Using SD_MMC for certificate validation"
|
||||
#endif
|
||||
#include <SD_MMC.h>
|
||||
#define FOTA_FS &SD_MMC
|
||||
#elif defined _LIFFLEFS_H_ // older externally linked, hard to identify and unsupported versions of SPIFFS
|
||||
#if !defined(DISABLE_ALL_LIBRARY_WARNINGS)
|
||||
#pragma message "this version of LittleFS is unsupported, use #include <LittleFS.h> instead, if using platformio add LittleFS(esp32)@^2.0.0 to lib_deps"
|
||||
#endif
|
||||
#elif __has_include(<PSRamFS.h>) || defined _PSRAMFS_H_
|
||||
#if !defined(DISABLE_ALL_LIBRARY_WARNINGS)
|
||||
#pragma message "Using PSRamFS for certificate validation"
|
||||
#endif
|
||||
#include <PSRamFS.h>
|
||||
#define FOTA_FS &PSRamFS
|
||||
#else
|
||||
//#if !defined(DISABLE_ALL_LIBRARY_WARNINGS)
|
||||
// #pragma message "No filesystem provided, certificate validation will be unavailable (hint: include SD, SPIFFS or LittleFS before including this library)"
|
||||
//#endif
|
||||
#define FOTA_FS nullptr
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
#if __has_include(<flashz.hpp>)
|
||||
#pragma message "Using FlashZ as Update agent"
|
||||
#include <flashz.hpp>
|
||||
#define F_Compression "zlib"
|
||||
#define F_hasZlib() true
|
||||
#define F_Update FlashZ::getInstance()
|
||||
#define F_UpdateEnd() (mode_z ? F_Update.endz() : F_Update.end())
|
||||
#define F_abort() if (mode_z) F_Update.abortz(); else F_Update.abort()
|
||||
#define F_writeStream() (mode_z ? F_Update.writezStream(*_stream, updateSize) : F_Update.writeStream(*_stream))
|
||||
// #define DEBUG_ESP32_FLASHZ
|
||||
#if !defined DEBUG_ESP32_FLASHZ
|
||||
#define F_isZlibStream() (_stream->peek() == ZLIB_HEADER && ((partition == U_SPIFFS && _flashFileSystemUrl.indexOf("zz")>-1) || (partition == U_FLASH && _firmwareUrl.indexOf("zz")>-1)))
|
||||
#define F_canBegin() (mode_z ? F_Update.beginz(UPDATE_SIZE_UNKNOWN, partition) : F_Update.begin(updateSize, partition))
|
||||
#else
|
||||
__attribute__((unused)) static bool F_canBegin_cb(bool mode_z, int updateSize, int partition) { // implement debug here
|
||||
return (mode_z ? F_Update.beginz(UPDATE_SIZE_UNKNOWN, partition) : F_Update.begin(updateSize, partition));
|
||||
}
|
||||
__attribute__((unused)) static bool F_isZlibStream_cb( Stream* stream, int partition, String flashFileSystemUrl, String firmwareUrl ) { // implement debug here
|
||||
return (stream->peek() == ZLIB_HEADER && ((partition == U_SPIFFS && flashFileSystemUrl.indexOf("zz")>-1) || (partition == U_FLASH && firmwareUrl.indexOf("zz")>-1)));
|
||||
}
|
||||
#define F_isZlibStream() F_isZlibStream_cb( _stream, partition, _flashFileSystemUrl, _firmwareUrl )
|
||||
#define F_canBegin() F_canBegin_cb(mode_z, updateSize, partition)
|
||||
#endif
|
||||
|
||||
#elif __has_include("ESP32-targz.h")
|
||||
#pragma message "Using GzUpdateClass as Update agent"
|
||||
#include <ESP32-targz.h>
|
||||
#define F_Compression "gzip"
|
||||
#define F_hasZlib() true
|
||||
#define F_Update GzUpdateClass::getInstance()
|
||||
#define F_UpdateEnd() (mode_z ? F_Update.endgz() : F_Update.end())
|
||||
#define F_abort() if (mode_z) F_Update.abortgz(); else F_Update.abort()
|
||||
#define F_writeStream() (mode_z ? F_Update.writeGzStream(*_stream, updateSize) : F_Update.writeStream(*_stream))
|
||||
// #define DEBUG_ESP32_TARGZ
|
||||
#if !defined DEBUG_ESP32_TARGZ
|
||||
#define F_isZlibStream() (_stream->peek() == 0x1f && ((partition == U_SPIFFS && _flashFileSystemUrl.indexOf("gz")>-1) || (partition == U_FLASH && _firmwareUrl.indexOf("gz")>-1)) )
|
||||
#define F_canBegin() (mode_z ? F_Update.begingz(UPDATE_SIZE_UNKNOWN, partition) : F_Update.begin(updateSize, partition))
|
||||
#else
|
||||
__attribute__((unused)) static bool F_canBegin_cb(bool mode_z, int updateSize, int partition) { // implement debug here
|
||||
return (mode_z ? F_Update.begingz(UPDATE_SIZE_UNKNOWN, partition) : F_Update.begin(updateSize, partition));
|
||||
}
|
||||
__attribute__((unused)) static bool F_isZlibStream_cb( Stream* stream, int partition, String flashFileSystemUrl, String firmwareUrl ) { // implement debug here
|
||||
return (stream->peek() == 0x1f && ((partition == U_SPIFFS && flashFileSystemUrl.indexOf("gz")>-1) || (partition == U_FLASH && firmwareUrl.indexOf("gz")>-1)) );
|
||||
}
|
||||
#define F_isZlibStream() F_isZlibStream_cb( _stream, partition, _flashFileSystemUrl, _firmwareUrl )
|
||||
#define F_canBegin() F_canBegin_cb(mode_z, updateSize, partition)
|
||||
#endif
|
||||
#else
|
||||
#include <Update.h>
|
||||
#define F_Compression "none"
|
||||
#define F_Update Update
|
||||
#define F_hasZlib() false
|
||||
#define F_isZlibStream() false
|
||||
#define F_canBegin() F_Update.begin(updateSize, partition)
|
||||
#define F_UpdateEnd() F_Update.end()
|
||||
#define F_abort() F_Update.abort()
|
||||
#define F_writeStream() F_Update.writeStream(*_stream);
|
||||
#endif
|
||||
|
||||
#define FW_SIGNATURE_LENGTH 512
|
||||
|
||||
struct SemverClass
|
||||
{
|
||||
public:
|
||||
SemverClass( const char* version );
|
||||
SemverClass( int major, int minor=0, int patch=0 );
|
||||
~SemverClass() { semver_free(&_ver); }
|
||||
semver_t* ver();
|
||||
private:
|
||||
semver_t _ver = semver_t();
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
// Filesystem/memory helper for signature check and pem validation.
|
||||
// This is abstracted away to allow storage alternatives such as
|
||||
// PROGMEM, SD, SPIFFS, LittleFS or FatFS
|
||||
// Intended to be used by esp32FOTA.setPubKey() and esp32FOTA.setRootCA()
|
||||
class CryptoAsset
|
||||
{
|
||||
public:
|
||||
virtual size_t size() = 0;
|
||||
virtual const char* get() = 0;
|
||||
};
|
||||
|
||||
class CryptoFileAsset : public CryptoAsset
|
||||
{
|
||||
public:
|
||||
CryptoFileAsset( const char* _path, fs::FS* _fs ) : path(_path), fs(_fs), contents(""), len(0) { }
|
||||
size_t size();
|
||||
const char* get() { return contents.c_str(); }
|
||||
private:
|
||||
const char* path;
|
||||
fs::FS* fs;
|
||||
std::string contents;
|
||||
size_t len;
|
||||
bool fs_read_file();
|
||||
};
|
||||
|
||||
class CryptoMemAsset : public CryptoAsset
|
||||
{
|
||||
public:
|
||||
CryptoMemAsset( const char* _name, const char* _bytes, size_t _len ) : name(_name), bytes(_bytes), len(_len) { }
|
||||
size_t size() { return len; };
|
||||
const char* get() { return bytes; }
|
||||
private:
|
||||
const char* name;
|
||||
const char* bytes;
|
||||
size_t len;
|
||||
};
|
||||
|
||||
|
||||
struct FOTAConfig_t
|
||||
{
|
||||
char* name { nullptr };
|
||||
char* manifest_url { nullptr };
|
||||
SemverClass sem {0};
|
||||
bool check_sig { false };
|
||||
bool unsafe { false };
|
||||
bool use_device_id { false };
|
||||
CryptoAsset* root_ca { nullptr };
|
||||
CryptoAsset* pub_key { nullptr };
|
||||
size_t signature_len {FW_SIGNATURE_LENGTH};
|
||||
FOTAConfig_t() = default;
|
||||
};
|
||||
|
||||
|
||||
enum FOTAStreamType_t
|
||||
{
|
||||
FOTA_HTTP_STREAM,
|
||||
FOTA_FILE_STREAM,
|
||||
FOTA_SERIAL_STREAM
|
||||
};
|
||||
|
||||
|
||||
// Main Class
|
||||
class esp32FOTA
|
||||
{
|
||||
public:
|
||||
|
||||
esp32FOTA();
|
||||
~esp32FOTA();
|
||||
|
||||
esp32FOTA( FOTAConfig_t cfg );
|
||||
esp32FOTA(const char* firwmareType, int firwmareVersion, bool validate = false, bool allow_insecure_https = false );
|
||||
esp32FOTA(const String &firwmareType, int firwmareVersion, bool validate = false, bool allow_insecure_https = false )
|
||||
: esp32FOTA(firwmareType.c_str(), firwmareVersion, validate, allow_insecure_https){};
|
||||
esp32FOTA(const char* firwmareType, const char* firmwareSemanticVersion, bool validate = false, bool allow_insecure_https = false );
|
||||
esp32FOTA(const String &firwmareType, const String &firmwareSemanticVersion, bool validate = false, bool allow_insecure_https = false )
|
||||
: esp32FOTA(firwmareType.c_str(), firmwareSemanticVersion.c_str(), validate, allow_insecure_https){};
|
||||
|
||||
template <typename T> void setPubKey( T* asset ) { _cfg.pub_key = (CryptoAsset*)asset; _cfg.check_sig = true; }
|
||||
template <typename T> void setRootCA( T* asset ) { _cfg.root_ca = (CryptoAsset*)asset; _cfg.unsafe = false; }
|
||||
|
||||
bool forceUpdate(const char* firmwareHost, uint16_t firmwarePort, const char* firmwarePath, bool validate );
|
||||
bool forceUpdate(const char* firmwareURL, bool validate );
|
||||
bool forceUpdate(bool validate );
|
||||
|
||||
bool forceUpdateSPIFFS(const char* firmwareURL, bool validate );
|
||||
|
||||
void handle();
|
||||
|
||||
bool execOTA();
|
||||
bool execSPIFFSOTA();
|
||||
bool execOTA( int partition, bool restart_after = true );
|
||||
bool execHTTPcheck();
|
||||
|
||||
void useDeviceId( bool use=true ) { _cfg.use_device_id = use; }
|
||||
|
||||
// config setter
|
||||
void setConfig( FOTAConfig_t cfg );
|
||||
void printConfig( FOTAConfig_t *cfg=nullptr );
|
||||
|
||||
// Manually specify the manifest url, this is provided as a transition between legagy and new config system
|
||||
void setManifestURL( const char* manifest_url ) { setString( &_cfg.manifest_url, manifest_url ); }
|
||||
void setManifestURL( const String &manifest_url ) { setManifestURL( manifest_url.c_str() ); }
|
||||
|
||||
// use this to set "Authorization: Basic" or other specific headers to be sent with the queries
|
||||
void setExtraHTTPHeader( String name, String value ) { extraHTTPHeaders[name] = value; }
|
||||
|
||||
// set the signature len
|
||||
void setSignatureLen( size_t len );
|
||||
|
||||
// /!\ Only use this to change filesystem for **default** RootCA and PubKey paths.
|
||||
// Otherwise use setPubKey() and setRootCA()
|
||||
void setCertFileSystem( fs::FS *cert_filesystem = nullptr );
|
||||
|
||||
// this is passed to Update.onProgress()
|
||||
typedef std::function<void(size_t,size_t)> ProgressCallback_cb; // size_t progress, size_t size
|
||||
void setProgressCb(ProgressCallback_cb fn) { onOTAProgress = fn; } // callback setter
|
||||
|
||||
// when Update.begin() returned false
|
||||
typedef std::function<void(int)> UpdateBeginFail_cb; // int partition (U_FLASH or U_SPIFFS)
|
||||
void setUpdateBeginFailCb(UpdateBeginFail_cb fn) { onUpdateBeginFail = fn; } // callback setter
|
||||
|
||||
// after Update.end() and before validate_sig()
|
||||
typedef std::function<void(int)> UpdateEnd_cb; // int partition (U_FLASH or U_SPIFFS)
|
||||
void setUpdateEndCb(UpdateEnd_cb fn) { onUpdateEnd = fn; } // callback setter
|
||||
|
||||
// validate_sig() error handling, mixed situations
|
||||
typedef std::function<void(int,int)> UpdateCheckFail_cb; // int partition (U_FLASH or U_SPIFFS), int error_code
|
||||
void setUpdateCheckFailCb(UpdateCheckFail_cb fn) { onUpdateCheckFail = fn; } // callback setter
|
||||
|
||||
// update successful
|
||||
typedef std::function<void(int,bool)> UpdateFinished_cb; // int partition (U_FLASH or U_SPIFFS), bool restart_after
|
||||
void setUpdateFinishedCb(UpdateFinished_cb fn) { onUpdateFinished = fn; } // callback setter
|
||||
|
||||
// stream getter
|
||||
typedef std::function<int64_t(esp32FOTA*,int)> getStream_cb; // esp32FOTA* this, int partition (U_FLASH or U_SPIFFS), returns stream size
|
||||
void setStreamGetter( getStream_cb fn ) { getStream = fn; } // callback setter
|
||||
|
||||
// stream ender
|
||||
typedef std::function<void(esp32FOTA*)> endStream_cb; // esp32FOTA* this
|
||||
void setStreamEnder( endStream_cb fn ) { endStream = fn; } // callback setter
|
||||
|
||||
// connection check
|
||||
typedef std::function<bool()> isConnected_cb; //
|
||||
void setStatusChecker( isConnected_cb fn ) { isConnected = fn; } // callback setter
|
||||
|
||||
// updating from a File or from Serial?
|
||||
void setStreamType( FOTAStreamType_t stream_type ) { _stream_type = stream_type; }
|
||||
void setStreamTimeout( uint32_t timeout ) { _stream_timeout = timeout; }
|
||||
|
||||
const char* getManifestURL() { return _manifestUrl.c_str(); }
|
||||
const char* getFirmwareURL() { return _firmwareUrl.c_str(); }
|
||||
const char* getFlashFS_URL() { return _flashFileSystemUrl.c_str(); }
|
||||
const char* getPath(int part) { return part==U_SPIFFS ? getFlashFS_URL() : getFirmwareURL(); }
|
||||
|
||||
bool zlibSupported() { return mode_z; }
|
||||
|
||||
int getPayloadVersion();
|
||||
void getPayloadVersion(char * version_string);
|
||||
|
||||
FOTAConfig_t getConfig() { return _cfg; };
|
||||
FOTAStreamType_t getStreamType() { return _stream_type; }
|
||||
HTTPClient* getHTTPCLient() { return &_http; }
|
||||
WiFiClientSecure* getWiFiClient() { return &_client; }
|
||||
fs::File* getFotaFilePtr() { return &_file; }
|
||||
Stream* getFotaStreamPtr() { return _stream; }
|
||||
fs::FS* getFotaFS() { return _fs; }
|
||||
|
||||
// internals but need to be exposed to the callbacks
|
||||
bool setupHTTP( const char* url );
|
||||
void setFotaStream( Stream* stream ) { _stream = stream; }
|
||||
|
||||
//[[deprecated("Use setManifestURL( String ) or cfg.manifest_url with setConfig( FOTAConfig_t )")]] String checkURL = "";
|
||||
//[[deprecated("Use cfg.use_device_id with setConfig( FOTAConfig_t )")]] bool useDeviceID = false;
|
||||
|
||||
bool validate_sig( const esp_partition_t* partition, unsigned char *signature, uint32_t firmware_size );
|
||||
|
||||
private:
|
||||
|
||||
HTTPClient _http;
|
||||
WiFiClientSecure _client;
|
||||
Stream *_stream;
|
||||
fs::File _file;
|
||||
|
||||
bool mode_z = F_hasZlib();
|
||||
|
||||
FOTAStreamType_t _stream_type = FOTA_HTTP_STREAM; // defaults to HTTP
|
||||
uint32_t _stream_timeout = 10000; // max wait for stream->available()
|
||||
|
||||
void setupStream();
|
||||
void stopStream();
|
||||
void setString( char **dest, const char* src ); // mem allocator
|
||||
|
||||
FOTAConfig_t _cfg;
|
||||
|
||||
SemverClass _payload_sem = SemverClass(0,0,0);
|
||||
|
||||
String _manifestUrl;
|
||||
String _firmwareUrl;
|
||||
String _flashFileSystemUrl;
|
||||
|
||||
fs::FS *_fs = FOTA_FS; // default filesystem for certificate validation
|
||||
|
||||
// custom callbacks provided by user
|
||||
ProgressCallback_cb onOTAProgress; // this is passed to Update.onProgress()
|
||||
UpdateBeginFail_cb onUpdateBeginFail; // when Update.begin() returned false
|
||||
UpdateEnd_cb onUpdateEnd; // after Update.end() and before validate_sig()
|
||||
UpdateCheckFail_cb onUpdateCheckFail; // validate_sig() error handling, mixed situations
|
||||
UpdateFinished_cb onUpdateFinished; // update successful
|
||||
getStream_cb getStream; // optional stream getter, defaults to http.getStreamPtr()
|
||||
endStream_cb endStream; // optional stream closer, defaults to http.end()
|
||||
isConnected_cb isConnected; // optional connection checker, defaults to WiFi.status()==WL_CONNECTED
|
||||
|
||||
std::map<String,String> extraHTTPHeaders; // this holds the extra http headers defined by the user
|
||||
|
||||
String getDeviceID();
|
||||
bool checkJSONManifest(JsonVariant JSONDocument);
|
||||
void debugSemVer( const char* label, semver_t* version );
|
||||
void getPartition( int update_partition );
|
||||
|
||||
|
||||
// temporary partition holder for signature check operations
|
||||
const esp_partition_t* _target_partition = nullptr;
|
||||
|
||||
// This is kept for legacy behaviour, use setPubKey() and setRootCA() with
|
||||
// CryptoMemAsset ot CryptoFileAsset instead
|
||||
void setupCryptoAssets();
|
||||
const char* rsa_key_pub_default_path = "/rsa_key.pub";
|
||||
const char* root_ca_pem_default_path = "/root_ca.pem";
|
||||
|
||||
};
|
||||
@@ -1,14 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
// This is kept for legacy but should not be used in new releases
|
||||
// as filename an project name don't match (esp32FOTA vs esp32fota)
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include "esp32FOTA.hpp"
|
||||
|
||||
#else
|
||||
|
||||
#error esp32FOTA requires a C++ compiler, please change file extension to .cc or .cpp
|
||||
|
||||
#endif
|
||||
@@ -1,233 +0,0 @@
|
||||
# semver.c [](https://travis-ci.org/h2non/semver.c) [](https://github.com/h2non/semver.c/releases)
|
||||
|
||||
[Semantic version](http://semver.org) v2.0 parser and render written in [ANSI C](https://en.wikipedia.org/wiki/ANSI_C) with zero dependencies.
|
||||
|
||||
## Features
|
||||
|
||||
- [x] Standard compliant (otherwise, open an issue)
|
||||
- [x] Version metadata parsing
|
||||
- [x] Version prerelease parsing
|
||||
- [x] Version comparison helpers
|
||||
- [x] Supports comparison operators
|
||||
- [x] Version render
|
||||
- [x] Version bump
|
||||
- [x] Version sanitizer
|
||||
- [x] 100% test coverage
|
||||
- [x] No regexp (ANSI C doesn't support it)
|
||||
- [x] Numeric conversion for sorting/filtering
|
||||
|
||||
## Versions
|
||||
|
||||
- [v0](https://github.com/h2non/semver.c/tree/89e66f36544e0250def32640b84b7e15c8585da4) - Legacy version. Beta. Not maintained anymore.
|
||||
- [v1](https://github.com/h2non/semver.c) - Current stable version.
|
||||
|
||||
## Usage
|
||||
|
||||
Basic comparison:
|
||||
```c
|
||||
#include <stdio.h>
|
||||
#include <semver.h>
|
||||
|
||||
char current[] = "1.5.10";
|
||||
char compare[] = "2.3.0";
|
||||
|
||||
int
|
||||
main(int argc, char *argv[]) {
|
||||
semver_t current_version = {};
|
||||
semver_t compare_version = {};
|
||||
|
||||
if (semver_parse(current, ¤t_version)
|
||||
|| semver_parse(compare, &compare_version)) {
|
||||
fprintf(stderr,"Invalid semver string\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int resolution = semver_compare(compare_version, current_version);
|
||||
|
||||
if (resolution == 0) {
|
||||
printf("Versions %s is equal to: %s\n", compare, current);
|
||||
}
|
||||
else if (resolution == -1) {
|
||||
printf("Version %s is lower than: %s\n", compare, current);
|
||||
}
|
||||
else {
|
||||
printf("Version %s is higher than: %s\n", compare, current);
|
||||
}
|
||||
|
||||
// Free allocated memory when we're done
|
||||
semver_free(¤t_version);
|
||||
semver_free(&compare_version);
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
Satisfies version:
|
||||
|
||||
```c
|
||||
#include <stdio.h>
|
||||
#include <semver.h>
|
||||
|
||||
semver_t current = {};
|
||||
semver_t compare = {};
|
||||
|
||||
int
|
||||
main(int argc, char *argv[]) {
|
||||
semver_parse("1.3.10", ¤t);
|
||||
semver_parse("1.5.2", &compare);
|
||||
|
||||
// Use caret operator for the comparison
|
||||
char operator[] = "^";
|
||||
|
||||
if (semver_satisfies(current, compare, operator)) {
|
||||
printf("Version %s can be satisfied by %s", "1.3.10", "1.5.2");
|
||||
}
|
||||
|
||||
// Free allocated memory when we're done
|
||||
semver_free(¤t);
|
||||
semver_free(&compare);
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
## Installation
|
||||
|
||||
Clone this repository:
|
||||
|
||||
```bash
|
||||
$ git clone https://github.com/h2non/semver.c
|
||||
```
|
||||
|
||||
Or install with [clib](https://github.com/clibs/clib):
|
||||
|
||||
```bash
|
||||
$ clib install h2non/semver.c
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
#### struct semver_t { int major, int minor, int patch, char * prerelease, char * metadata }
|
||||
|
||||
semver base struct.
|
||||
|
||||
#### semver_parse(const char *str, semver_t *ver) => int
|
||||
|
||||
Parses a string as semver expression.
|
||||
|
||||
**Returns**:
|
||||
|
||||
- `-1` - In case of invalid semver or parsing error.
|
||||
- `0` - All was fine!
|
||||
|
||||
#### semver_compare(semver_t a, semver_t b) => int
|
||||
|
||||
Compare versions `a` with `b`.
|
||||
|
||||
Returns:
|
||||
- `-1` in case of lower version.
|
||||
- `0` in case of equal versions.
|
||||
- `1` in case of higher version.
|
||||
|
||||
#### semver_satisfies(semver_t a, semver_t b, char *operator) => int
|
||||
|
||||
Checks if both versions can be satisfied
|
||||
based on the given comparison operator.
|
||||
|
||||
**Allowed operators**:
|
||||
|
||||
- `=` - Equality
|
||||
- `>=` - Higher or equal to
|
||||
- `<=` - Lower or equal to
|
||||
- `<` - Lower than
|
||||
- `>` - Higher than
|
||||
- `^` - Caret operator comparison ([more info](https://docs.npmjs.com/misc/semver#caret-ranges-1-2-3-0-2-5-0-0-4))
|
||||
- `~` - Tilde operator comparison ([more info](https://docs.npmjs.com/misc/semver#tilde-ranges-1-2-3-1-2-1))
|
||||
|
||||
**Returns**:
|
||||
|
||||
- `1` - Can be satisfied
|
||||
- `0` - Cannot be satisfied
|
||||
|
||||
#### semver_satisfies_caret(semver_t a, semver_t b) => int
|
||||
|
||||
Checks if version `x` can be satisfied by `y`
|
||||
performing a comparison with caret operator.
|
||||
|
||||
See: https://docs.npmjs.com/misc/semver#caret-ranges-1-2-3-0-2-5-0-0-4
|
||||
|
||||
**Returns**:
|
||||
|
||||
- `1` - Can be satisfied
|
||||
- `0` - Cannot be satisfied
|
||||
|
||||
#### semver_satisfies_patch(semver_t a, semver_t b) => int
|
||||
|
||||
Checks if version `x` can be satisfied by `y`
|
||||
performing a comparison with tilde operator.
|
||||
|
||||
See: https://docs.npmjs.com/misc/semver#tilde-ranges-1-2-3-1-2-1
|
||||
|
||||
**Returns**:
|
||||
|
||||
- `1` - Can be satisfied
|
||||
- `0` - Cannot be satisfied
|
||||
|
||||
|
||||
#### semver_eq(semver_t a, semver_t b) => int
|
||||
|
||||
Equality comparison.
|
||||
|
||||
#### semver_ne(semver_t a, semver_t b) => int
|
||||
|
||||
Non equal comparison.
|
||||
|
||||
#### semver_gt(semver_t a, semver_t b) => int
|
||||
|
||||
Greater than comparison.
|
||||
|
||||
#### semver_lt(semver_t a, semver_t b) => int
|
||||
|
||||
Lower than comparison.
|
||||
|
||||
#### semver_gte(semver_t a, semver_t b) => int
|
||||
|
||||
Greater than or equal comparison.
|
||||
|
||||
#### semver_lte(semver_t a, semver_t b) => int
|
||||
|
||||
Lower than or equal comparison.
|
||||
|
||||
#### semver_render(semver_t *v, char *dest) => void
|
||||
|
||||
Render as string.
|
||||
|
||||
#### semver_numeric(semver_t *v) => int
|
||||
|
||||
Render as numeric value. Useful for ordering and filtering.
|
||||
|
||||
#### semver_bump(semver_t *a) => void
|
||||
|
||||
Bump major version.
|
||||
|
||||
#### semver_bump_minor(semver_t *a) => void
|
||||
|
||||
Bump minor version.
|
||||
|
||||
#### semver_bump_patch(semver_t *a) => void
|
||||
|
||||
Bump patch version.
|
||||
|
||||
#### semver_free(semver_t *a) => void
|
||||
|
||||
Helper to free allocated memory from heap.
|
||||
|
||||
#### semver_is_valid(char *str) => int
|
||||
|
||||
Checks if the given string is a valid semver expression.
|
||||
|
||||
#### semver_clean(char *str) => int
|
||||
|
||||
Removes invalid semver characters in a given string.
|
||||
|
||||
## License
|
||||
|
||||
MIT - Tomas Aparicio
|
||||
@@ -1,638 +0,0 @@
|
||||
/*
|
||||
* semver.c
|
||||
*
|
||||
* Copyright (c) 2015-2017 Tomas Aparicio
|
||||
* MIT licensed
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "semver.h"
|
||||
|
||||
#define SLICE_SIZE 50
|
||||
#define DELIMITER "."
|
||||
#define PR_DELIMITER "-"
|
||||
#define MT_DELIMITER "+"
|
||||
#define NUMBERS "0123456789"
|
||||
#define ALPHA "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
#define DELIMITERS DELIMITER PR_DELIMITER MT_DELIMITER
|
||||
#define VALID_CHARS NUMBERS ALPHA DELIMITERS
|
||||
|
||||
static const size_t MAX_SIZE = sizeof(char) * 255;
|
||||
static const int MAX_SAFE_INT = (unsigned int) -1 >> 1;
|
||||
|
||||
/**
|
||||
* Define comparison operators, storing the
|
||||
* ASCII code per each symbol in hexadecimal notation.
|
||||
*/
|
||||
|
||||
enum operators {
|
||||
SYMBOL_GT = 0x3e,
|
||||
SYMBOL_LT = 0x3c,
|
||||
SYMBOL_EQ = 0x3d,
|
||||
SYMBOL_TF = 0x7e,
|
||||
SYMBOL_CF = 0x5e
|
||||
};
|
||||
|
||||
/**
|
||||
* Private helpers
|
||||
*/
|
||||
|
||||
/*
|
||||
* Remove [begin:len-begin] from str by moving len data from begin+len to begin.
|
||||
* If len is negative cut out to the end of the string.
|
||||
*/
|
||||
static int
|
||||
strcut (char *str, int begin, int len) {
|
||||
size_t l;
|
||||
l = strlen(str);
|
||||
|
||||
if((int)l < 0 || (int)l > MAX_SAFE_INT) return -1;
|
||||
|
||||
if (len < 0) len = l - begin + 1;
|
||||
if (begin + len > (int)l) len = l - begin;
|
||||
memmove(str + begin, str + begin + len, l - len + 1 - begin);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static int
|
||||
contains (const char c, const char *matrix, size_t len) {
|
||||
size_t x;
|
||||
for (x = 0; x < len; x++)
|
||||
if ((char) matrix[x] == c) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
has_valid_chars (const char *str, const char *matrix) {
|
||||
size_t i, len, mlen;
|
||||
len = strlen(str);
|
||||
mlen = strlen(matrix);
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
if (contains(str[i], matrix, mlen) == 0)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
binary_comparison (int x, int y) {
|
||||
if (x == y) return 0;
|
||||
if (x > y) return 1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
parse_int (const char *s) {
|
||||
int valid, num;
|
||||
valid = has_valid_chars(s, NUMBERS);
|
||||
if (valid == 0) return -1;
|
||||
|
||||
num = strtol(s, NULL, 10);
|
||||
if (num > MAX_SAFE_INT) return -1;
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return a string allocated on the heap with the content from sep to end and
|
||||
* terminate buf at sep.
|
||||
*/
|
||||
static char *
|
||||
parse_slice (char *buf, char sep) {
|
||||
char *pr, *part;
|
||||
int plen;
|
||||
|
||||
/* Find separator in buf */
|
||||
pr = strchr(buf, sep);
|
||||
if (pr == NULL) return NULL;
|
||||
/* Length from separator to end of buf */
|
||||
plen = strlen(pr);
|
||||
|
||||
/* Copy from buf into new string */
|
||||
part = (char*)calloc(plen + 1, sizeof(*part));
|
||||
if (part == NULL) return NULL;
|
||||
memcpy(part, pr + 1, plen);
|
||||
/* Null terminate new string */
|
||||
part[plen] = '\0';
|
||||
|
||||
/* Terminate buf where separator was */
|
||||
*pr = '\0';
|
||||
|
||||
return part;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a string as semver expression.
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* `0` - Parsed successfully
|
||||
* `-1` - In case of error
|
||||
*/
|
||||
|
||||
int
|
||||
semver_parse (const char *str, semver_t *ver) {
|
||||
int valid, res;
|
||||
size_t len;
|
||||
char *buf;
|
||||
valid = semver_is_valid(str);
|
||||
if (!valid) return -1;
|
||||
|
||||
len = strlen(str);
|
||||
buf = (char*)calloc(len + 1, sizeof(*buf));
|
||||
if (buf == NULL) return -1;
|
||||
strcpy(buf, str);
|
||||
|
||||
ver->metadata = parse_slice(buf, MT_DELIMITER[0]);
|
||||
ver->prerelease = parse_slice(buf, PR_DELIMITER[0]);
|
||||
|
||||
res = semver_parse_version(buf, ver);
|
||||
free(buf);
|
||||
#if DEBUG > 0
|
||||
printf("[debug] semver.c %s = %d.%d.%d, %s %s\n", str, ver->major, ver->minor, ver->patch, ver->prerelease, ver->metadata);
|
||||
#endif
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a given string as semver expression.
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* `0` - Parsed successfully
|
||||
* `-1` - Parse error or invalid
|
||||
*/
|
||||
|
||||
int
|
||||
semver_parse_version (const char *str, semver_t *ver) {
|
||||
size_t len;
|
||||
int index, value;
|
||||
char *slice, *next, *endptr;
|
||||
slice = (char *) str;
|
||||
index = 0;
|
||||
|
||||
while (slice != NULL && index++ < 4) {
|
||||
next = strchr(slice, DELIMITER[0]);
|
||||
if (next == NULL)
|
||||
len = strlen(slice);
|
||||
else
|
||||
len = next - slice;
|
||||
if (len > SLICE_SIZE) return -1;
|
||||
|
||||
/* Cast to integer and store */
|
||||
value = strtol(slice, &endptr, 10);
|
||||
if (endptr != next && *endptr != '\0') return -1;
|
||||
|
||||
switch (index) {
|
||||
case 1: ver->major = value; break;
|
||||
case 2: ver->minor = value; break;
|
||||
case 3: ver->patch = value; break;
|
||||
}
|
||||
|
||||
/* Continue with the next slice */
|
||||
if (next == NULL)
|
||||
slice = NULL;
|
||||
else
|
||||
slice = next + 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
compare_prerelease (char *x, char *y) {
|
||||
char *lastx, *lasty, *xptr, *yptr, *endptr;
|
||||
int xlen, ylen, xisnum, yisnum, xnum, ynum;
|
||||
int xn, yn, min, res;
|
||||
if (x == NULL && y == NULL) return 0;
|
||||
if (y == NULL && x) return -1;
|
||||
if (x == NULL && y) return 1;
|
||||
|
||||
lastx = x;
|
||||
lasty = y;
|
||||
xlen = strlen(x);
|
||||
ylen = strlen(y);
|
||||
|
||||
while (1) {
|
||||
if ((xptr = strchr(lastx, DELIMITER[0])) == NULL)
|
||||
xptr = x + xlen;
|
||||
if ((yptr = strchr(lasty, DELIMITER[0])) == NULL)
|
||||
yptr = y + ylen;
|
||||
|
||||
xnum = strtol(lastx, &endptr, 10);
|
||||
xisnum = endptr == xptr ? 1 : 0;
|
||||
ynum = strtol(lasty, &endptr, 10);
|
||||
yisnum = endptr == yptr ? 1 : 0;
|
||||
|
||||
if (xisnum && !yisnum) return -1;
|
||||
if (!xisnum && yisnum) return 1;
|
||||
|
||||
if (xisnum && yisnum) {
|
||||
/* Numerical comparison */
|
||||
if (xnum != ynum) return xnum < ynum ? -1 : 1;
|
||||
} else {
|
||||
/* String comparison */
|
||||
xn = xptr - lastx;
|
||||
yn = yptr - lasty;
|
||||
min = xn < yn ? xn : yn;
|
||||
if ((res = strncmp(lastx, lasty, min))) return res < 0 ? -1 : 1;
|
||||
if (xn != yn) return xn < yn ? -1 : 1;
|
||||
}
|
||||
|
||||
lastx = xptr + 1;
|
||||
lasty = yptr + 1;
|
||||
if (lastx == x + xlen + 1 && lasty == y + ylen + 1) break;
|
||||
if (lastx == x + xlen + 1) return -1;
|
||||
if (lasty == y + ylen + 1) return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
semver_compare_prerelease (semver_t x, semver_t y) {
|
||||
return compare_prerelease(x.prerelease, y.prerelease);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a major, minor and patch binary comparison (x, y).
|
||||
* This function is mostly used internally
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* `0` - If versiona are equal
|
||||
* `1` - If x is higher than y
|
||||
* `-1` - If x is lower than y
|
||||
*/
|
||||
|
||||
int
|
||||
semver_compare_version (semver_t x, semver_t y) {
|
||||
int res;
|
||||
|
||||
if ((res = binary_comparison(x.major, y.major)) == 0) {
|
||||
if ((res = binary_comparison(x.minor, y.minor)) == 0) {
|
||||
return binary_comparison(x.patch, y.patch);
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare two semantic versions (x, y).
|
||||
*
|
||||
* Returns:
|
||||
* - `1` if x is higher than y
|
||||
* - `0` if x is equal to y
|
||||
* - `-1` if x is lower than y
|
||||
*/
|
||||
|
||||
int
|
||||
semver_compare (semver_t x, semver_t y) {
|
||||
int res;
|
||||
|
||||
if ((res = semver_compare_version(x, y)) == 0) {
|
||||
return semver_compare_prerelease(x, y);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a `greater than` comparison
|
||||
*/
|
||||
|
||||
int
|
||||
semver_gt (semver_t x, semver_t y) {
|
||||
return semver_compare(x, y) == 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a `lower than` comparison
|
||||
*/
|
||||
|
||||
int
|
||||
semver_lt (semver_t x, semver_t y) {
|
||||
return semver_compare(x, y) == -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a `equality` comparison
|
||||
*/
|
||||
|
||||
int
|
||||
semver_eq (semver_t x, semver_t y) {
|
||||
return semver_compare(x, y) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a `non equal to` comparison
|
||||
*/
|
||||
|
||||
int
|
||||
semver_neq (semver_t x, semver_t y) {
|
||||
return semver_compare(x, y) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a `greater than or equal` comparison
|
||||
*/
|
||||
|
||||
int
|
||||
semver_gte (semver_t x, semver_t y) {
|
||||
return semver_compare(x, y) >= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a `lower than or equal` comparison
|
||||
*/
|
||||
|
||||
int
|
||||
semver_lte (semver_t x, semver_t y) {
|
||||
return semver_compare(x, y) <= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if version `x` can be satisfied by `y`
|
||||
* performing a comparison with caret operator.
|
||||
*
|
||||
* See: https://docs.npmjs.com/misc/semver#caret-ranges-1-2-3-0-2-5-0-0-4
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* `1` - Can be satisfied
|
||||
* `0` - Cannot be satisfied
|
||||
*/
|
||||
|
||||
int
|
||||
semver_satisfies_caret (semver_t x, semver_t y) {
|
||||
/* Major versions must always match. */
|
||||
if (x.major == y.major) {
|
||||
/* If major version is 0, minor versions must match */
|
||||
if (x.major == 0) {
|
||||
/* If minor version is 0, patch must match */
|
||||
if (x.minor == 0){
|
||||
return (x.minor == y.minor) && (x.patch == y.patch);
|
||||
}
|
||||
/* If minor version is not 0, patch must be >= */
|
||||
else if (x.minor == y.minor){
|
||||
return x.patch >= y.patch;
|
||||
}
|
||||
else{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else if (x.minor > y.minor){
|
||||
return 1;
|
||||
}
|
||||
else if (x.minor == y.minor)
|
||||
{
|
||||
return x.patch >= y.patch;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if version `x` can be satisfied by `y`
|
||||
* performing a comparison with tilde operator.
|
||||
*
|
||||
* See: https://docs.npmjs.com/misc/semver#tilde-ranges-1-2-3-1-2-1
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* `1` - Can be satisfied
|
||||
* `0` - Cannot be satisfied
|
||||
*/
|
||||
|
||||
int
|
||||
semver_satisfies_patch (semver_t x, semver_t y) {
|
||||
return x.major == y.major
|
||||
&& x.minor == y.minor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if both versions can be satisfied
|
||||
* based on the given comparison operator.
|
||||
*
|
||||
* Allowed operators:
|
||||
*
|
||||
* - `=` - Equality
|
||||
* - `>=` - Higher or equal to
|
||||
* - `<=` - Lower or equal to
|
||||
* - `<` - Lower than
|
||||
* - `>` - Higher than
|
||||
* - `^` - Caret comparison (see https://docs.npmjs.com/misc/semver#caret-ranges-1-2-3-0-2-5-0-0-4)
|
||||
* - `~` - Tilde comparison (see https://docs.npmjs.com/misc/semver#tilde-ranges-1-2-3-1-2-1)
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* `1` - Can be satisfied
|
||||
* `0` - Cannot be satisfied
|
||||
*/
|
||||
|
||||
int
|
||||
semver_satisfies (semver_t x, semver_t y, const char *op) {
|
||||
int first, second;
|
||||
/* Extract the comparison operator */
|
||||
first = op[0];
|
||||
second = op[1];
|
||||
|
||||
/* Caret operator */
|
||||
if (first == SYMBOL_CF)
|
||||
return semver_satisfies_caret(x, y);
|
||||
|
||||
/* Tilde operator */
|
||||
if (first == SYMBOL_TF)
|
||||
return semver_satisfies_patch(x, y);
|
||||
|
||||
/* Strict equality */
|
||||
if (first == SYMBOL_EQ)
|
||||
return semver_eq(x, y);
|
||||
|
||||
/* Greater than or equal comparison */
|
||||
if (first == SYMBOL_GT) {
|
||||
if (second == SYMBOL_EQ) {
|
||||
return semver_gte(x, y);
|
||||
}
|
||||
return semver_gt(x, y);
|
||||
}
|
||||
|
||||
/* Lower than or equal comparison */
|
||||
if (first == SYMBOL_LT) {
|
||||
if (second == SYMBOL_EQ) {
|
||||
return semver_lte(x, y);
|
||||
}
|
||||
return semver_lt(x, y);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Free heep allocated memory of a given semver.
|
||||
* This is just a convenient function that you
|
||||
* should call when you're done.
|
||||
*/
|
||||
|
||||
void
|
||||
semver_free (semver_t *x) {
|
||||
if (x->metadata) {
|
||||
free(x->metadata);
|
||||
x->metadata = NULL;
|
||||
}
|
||||
if (x->prerelease) {
|
||||
free(x->prerelease);
|
||||
x->prerelease = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders
|
||||
*/
|
||||
|
||||
static void
|
||||
concat_num (char * str, int x, const char * sep) {
|
||||
char buf[SLICE_SIZE] = {0};
|
||||
if (sep == NULL) sprintf(buf, "%d", x);
|
||||
else sprintf(buf, "%s%d", sep, x);
|
||||
strcat(str, buf);
|
||||
}
|
||||
|
||||
static void
|
||||
concat_char (char * str, char * x, const char * sep) {
|
||||
char buf[SLICE_SIZE] = {0};
|
||||
sprintf(buf, "%s%s", sep, x);
|
||||
strcat(str, buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a given semver as string
|
||||
*/
|
||||
|
||||
void
|
||||
semver_render (semver_t *x, char *dest) {
|
||||
concat_num(dest, x->major, NULL);
|
||||
concat_num(dest, x->minor, DELIMITER);
|
||||
concat_num(dest, x->patch, DELIMITER);
|
||||
if (x->prerelease) concat_char(dest, x->prerelease, PR_DELIMITER);
|
||||
if (x->metadata) concat_char(dest, x->metadata, MT_DELIMITER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Version bump helpers
|
||||
*/
|
||||
|
||||
void
|
||||
semver_bump (semver_t *x) {
|
||||
x->major++;
|
||||
}
|
||||
|
||||
void
|
||||
semver_bump_minor (semver_t *x) {
|
||||
x->minor++;
|
||||
}
|
||||
|
||||
void
|
||||
semver_bump_patch (semver_t *x) {
|
||||
x->patch++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helpers
|
||||
*/
|
||||
|
||||
static int
|
||||
has_valid_length (const char *s) {
|
||||
return strlen(s) <= MAX_SIZE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a given semver string is valid
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* `1` - Valid expression
|
||||
* `0` - Invalid
|
||||
*/
|
||||
|
||||
int
|
||||
semver_is_valid (const char *s) {
|
||||
return has_valid_length(s)
|
||||
&& has_valid_chars(s, VALID_CHARS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes non-valid characters in the given string.
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* `0` - Valid
|
||||
* `-1` - Invalid input
|
||||
*/
|
||||
|
||||
int
|
||||
semver_clean (char *s) {
|
||||
size_t i, len, mlen;
|
||||
int res;
|
||||
if (has_valid_length(s) == 0) return -1;
|
||||
|
||||
len = strlen(s);
|
||||
mlen = strlen(VALID_CHARS);
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
if (contains(s[i], VALID_CHARS, mlen) == 0) {
|
||||
res = strcut(s, i, 1);
|
||||
if(res == -1) return -1;
|
||||
--len; --i;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
char_to_int (const char * str) {
|
||||
int buf;
|
||||
size_t i,len, mlen;
|
||||
buf = 0;
|
||||
len = strlen(str);
|
||||
mlen = strlen(VALID_CHARS);
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
if (contains(str[i], VALID_CHARS, mlen))
|
||||
buf += (int) str[i];
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a given semver as numeric value.
|
||||
* Useful for ordering and filtering.
|
||||
*/
|
||||
|
||||
int
|
||||
semver_numeric (semver_t *x) {
|
||||
int num;
|
||||
char buf[SLICE_SIZE * 3];
|
||||
memset(&buf, 0, SLICE_SIZE * 3);
|
||||
|
||||
if (x->major) concat_num(buf, x->major, NULL);
|
||||
if (x->major || x->minor) concat_num(buf, x->minor, NULL);
|
||||
if (x->major || x->minor || x->patch) concat_num(buf, x->patch, NULL);
|
||||
|
||||
num = parse_int(buf);
|
||||
if(num == -1) return -1;
|
||||
|
||||
if (x->prerelease) num += char_to_int(x->prerelease);
|
||||
if (x->metadata) num += char_to_int(x->metadata);
|
||||
|
||||
return num;
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
/*
|
||||
* semver.h
|
||||
*
|
||||
* Copyright (c) 2015-2017 Tomas Aparicio
|
||||
* MIT licensed
|
||||
*/
|
||||
|
||||
#ifndef __SEMVER_H
|
||||
#define __SEMVER_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef SEMVER_VERSION
|
||||
#define SEMVER_VERSION "0.2.0"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* semver_t struct
|
||||
*/
|
||||
|
||||
typedef struct semver_version_s {
|
||||
int major;
|
||||
int minor;
|
||||
int patch;
|
||||
char * metadata;
|
||||
char * prerelease;
|
||||
} semver_t;
|
||||
|
||||
/**
|
||||
* Set prototypes
|
||||
*/
|
||||
|
||||
int semver_satisfies (semver_t x, semver_t y, const char *op);
|
||||
int semver_satisfies_caret (semver_t x, semver_t y);
|
||||
int semver_satisfies_patch (semver_t x, semver_t y);
|
||||
int semver_compare (semver_t x, semver_t y);
|
||||
int semver_compare_version (semver_t x, semver_t y);
|
||||
int semver_compare_prerelease (semver_t x, semver_t y);
|
||||
int semver_gt (semver_t x, semver_t y);
|
||||
int semver_gte (semver_t x, semver_t y);
|
||||
int semver_lt (semver_t x, semver_t y);
|
||||
int semver_lte (semver_t x, semver_t y);
|
||||
int semver_eq (semver_t x, semver_t y);
|
||||
int semver_neq (semver_t x, semver_t y);
|
||||
int semver_parse (const char *str, semver_t *ver);
|
||||
int semver_parse_version (const char *str, semver_t *ver);
|
||||
void semver_render (semver_t *x, char *dest);
|
||||
int semver_numeric (semver_t *x);
|
||||
void semver_bump (semver_t *x);
|
||||
void semver_bump_minor (semver_t *x);
|
||||
void semver_bump_patch (semver_t *x);
|
||||
void semver_free (semver_t *x);
|
||||
int semver_is_valid (const char *s);
|
||||
int semver_clean (char *s);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,117 +0,0 @@
|
||||
# Shamelessly translated mongsoose 7.13 pack.c to python to provide portability for platformio core software
|
||||
|
||||
# perhaps Copyright (c) Cesanta Software Limited, I'm not sure because I'm not a lawyer
|
||||
# might also be Copyright me or Copyright ChatGPT
|
||||
# All rights reserved.
|
||||
# but not sure by whom
|
||||
|
||||
# This program is used to pack arbitrary data into a C binary. It takes
|
||||
# a list of files as an input, and produces a .c data file that contains
|
||||
# contents of all these files as a collection of byte arrays.
|
||||
#
|
||||
# Usage:
|
||||
# 2. Convert list of files into single .c:
|
||||
# ./pack file1.data file2.data > fs.c
|
||||
#
|
||||
# 3. In your application code, you can access files using this function:
|
||||
# const char *mg_unpack(const char *file_name, size_t *size);
|
||||
#
|
||||
# 4. Build your app with fs.c:
|
||||
# cc -o my_app my_app.c fs.c
|
||||
|
||||
import errno
|
||||
import sys
|
||||
import os
|
||||
import stat
|
||||
import time
|
||||
|
||||
code = """static int scmp(const char *a, const char *b) {
|
||||
while (*a && (*a == *b)) a++, b++;
|
||||
return *(const unsigned char *) a - *(const unsigned char *) b;
|
||||
}
|
||||
const char *mg_unlist(size_t no) {
|
||||
return packed_files[no].name;
|
||||
}
|
||||
const char *mg_unpack(const char *name, size_t *size, time_t *mtime) {
|
||||
const struct packed_file *p;
|
||||
for (p = packed_files; p->name != NULL; p++) {
|
||||
if (scmp(p->name, name) != 0) continue;
|
||||
if (size != NULL) *size = p->size - 1;
|
||||
if (mtime != NULL) *mtime = p->mtime;
|
||||
return (const char *) p->data;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
"""
|
||||
|
||||
def main(argv):
|
||||
i = 0
|
||||
strip_prefix = ""
|
||||
|
||||
print("#include <stddef.h>")
|
||||
print("#include <string.h>")
|
||||
print("#include <time.h>")
|
||||
print("")
|
||||
print("#if defined(__cplusplus)\nextern \"C\" {\n#endif")
|
||||
print("const char *mg_unlist(size_t no);")
|
||||
print("const char *mg_unpack(const char *, size_t *, time_t *);")
|
||||
print("#if defined(__cplusplus)\n}\n#endif\n\n", end='')
|
||||
|
||||
while i < len(argv):
|
||||
if argv[i] == "-s":
|
||||
strip_prefix = argv[i + 1]
|
||||
i += 2
|
||||
elif argv[i] == "-h" or argv[i] == "--help":
|
||||
sys.stderr.write("Usage: %s[-s STRIP_PREFIX] files...\n" % argv[0])
|
||||
sys.exit(os.EX_USAGE)
|
||||
else:
|
||||
ascii = [''] * 12
|
||||
with open(argv[i], "rb") as fp:
|
||||
print("static const unsigned char v%d[] = {" % (i + 1))
|
||||
j = 0
|
||||
while True:
|
||||
ch = fp.read(1)
|
||||
if not ch:
|
||||
break
|
||||
ch = ord(ch)
|
||||
if j == len(ascii):
|
||||
print(" // %s" % ''.join(ascii))
|
||||
j = 0
|
||||
ascii[j] = chr(ch) if ch >= 32 and ch <= 126 and ch != 92 else '.'
|
||||
print(" %3u," % ch, end='')
|
||||
j += 1
|
||||
print(" 0 // %s\n};" % ''.join(ascii))
|
||||
|
||||
i += 1
|
||||
|
||||
print("")
|
||||
print("static const struct packed_file {")
|
||||
print(" const char *name;")
|
||||
print(" const unsigned char *data;")
|
||||
print(" size_t size;")
|
||||
print(" time_t mtime;")
|
||||
print("} packed_files[] = {")
|
||||
|
||||
i = 0
|
||||
while i < len(argv):
|
||||
if argv[i] == "-s":
|
||||
i += 1
|
||||
continue
|
||||
st = os.stat(argv[i])
|
||||
name = argv[i]
|
||||
n = len(strip_prefix)
|
||||
if argv[i] == "-s":
|
||||
i += 1
|
||||
continue
|
||||
if name.startswith(strip_prefix):
|
||||
name = name[n:]
|
||||
print(" {\"/%s\", v%d, sizeof(v%d), %lu}," % (name, i + 1, i + 1, st.st_mtime))
|
||||
i += 1
|
||||
|
||||
print(" {NULL, NULL, 0, 0}")
|
||||
print("};\n")
|
||||
print(code, end='')
|
||||
|
||||
if __name__ == "__main__":
|
||||
main(sys.argv[1:])
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
#this script will be run by platformio.ini from its native directory
|
||||
import os, sys, gzip, shutil
|
||||
|
||||
#check for the two files we need to be able to keep updating the firmware by the /update endpoint:
|
||||
if not os.path.isfile("data/update2.html"):
|
||||
print("Missing file: data/update2.html")
|
||||
sys.exit(1)
|
||||
if os.path.isdir("pack.tmp"):
|
||||
shutil.rmtree('pack.tmp')
|
||||
try:
|
||||
filelist = []
|
||||
os.makedirs('pack.tmp/data')
|
||||
# now gzip the stuff except zones.csv since this file is not served by mongoose but directly accessed:
|
||||
for file in os.listdir("data"):
|
||||
filename = os.fsdecode(file)
|
||||
if filename == "zones.csv" or filename == "cert.pem" or filename == "key.pem" or filename == "rsa_key.pub":
|
||||
shutil.copy('data/' + filename, 'pack.tmp/data/' + filename)
|
||||
filelist.append('data/' + filename)
|
||||
continue
|
||||
else:
|
||||
with open('data/' + filename, 'rb') as f_in, gzip.open('pack.tmp/data/' + filename + '.gz', 'wb') as f_out:
|
||||
f_out.writelines(f_in)
|
||||
filelist.append('data/' + filename + '.gz')
|
||||
continue
|
||||
os.chdir('pack.tmp')
|
||||
cmdstring = 'python ../pack.py ' + ' '.join(filelist)
|
||||
os.system(cmdstring + '>../src/packed_fs.c')
|
||||
os.chdir('..')
|
||||
except Exception as e:
|
||||
print(f"An error occurred: {str(e)}")
|
||||
sys.exit(100)
|
||||
if shutil.rmtree("pack.tmp"):
|
||||
print("Failed to clean up temporary files")
|
||||
sys.exit(9)
|
||||
@@ -1,8 +0,0 @@
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
nvs, data, nvs, 0x9000, 0x5000,
|
||||
otadata, data, ota, 0xe000, 0x2000,
|
||||
ota_0, app, ota_0, 0x10000, 0x1B0000,
|
||||
ota_1, app, ota_1, 0x1c0000, 0x1B0000,
|
||||
spiffs, data, spiffs, 0x370000, 0x80000,
|
||||
coredump, data, coredump,0x3F0000, 64K
|
||||
# Serialnr, per device key, (wifi) settings are stored in the nvs (arduino: preferences) partition
|
||||
@@ -1,42 +0,0 @@
|
||||
; PlatformIO Project Configuration File
|
||||
;
|
||||
; Build options: build flags, source filter
|
||||
; Upload options: custom upload port, speed and extra flags
|
||||
; Library options: dependencies, extra library storages
|
||||
; Advanced options: extra scripting
|
||||
;
|
||||
; Please visit documentation for the other options and examples
|
||||
; https://docs.platformio.org/page/projectconf.html
|
||||
|
||||
[platformio]
|
||||
description = SmartEVSE v3 (ESP32)
|
||||
default_envs = release
|
||||
|
||||
[env]
|
||||
platform = espressif32 @ 6.6.0
|
||||
board = esp32dev
|
||||
framework = arduino
|
||||
monitor_port = /dev/ttyUSB0
|
||||
monitor_speed = 115200
|
||||
upload_speed = 2000000
|
||||
board_build.f_flash = 80000000L
|
||||
board_build.flash_mode = dio
|
||||
lib_ignore =
|
||||
LittleFS_esp32
|
||||
lib_deps =
|
||||
https://github.com/tzapu/WiFiManager.git
|
||||
miq19/eModbus@1.7.1
|
||||
bblanchon/ArduinoJson@^6.21.4
|
||||
monitor_filters = esp32_exception_decoder
|
||||
board_build.partitions = partitions_custom.csv
|
||||
extra_scripts = pre:packfs.py
|
||||
|
||||
[env:release]
|
||||
build_flags =
|
||||
-DCORE_DEBUG_LEVEL=5
|
||||
-DLOG_LEVEL=5
|
||||
-DMG_ENABLE_PACKED_FS=1
|
||||
-DMG_TLS=MG_TLS_MBED
|
||||
-Wall
|
||||
-Wextra
|
||||
-Wunused-variable
|
||||
@@ -1 +0,0 @@
|
||||
.pio/build/release
|
||||
@@ -1,6 +0,0 @@
|
||||
# This file was automatically generated for projects
|
||||
# without default 'CMakeLists.txt' file.
|
||||
|
||||
FILE(GLOB_RECURSE app_sources ${CMAKE_SOURCE_DIR}/src/*.*)
|
||||
|
||||
idf_component_register(SRCS ${app_sources})
|
||||
@@ -1,341 +0,0 @@
|
||||
/*
|
||||
; Project: Smart EVSE
|
||||
;
|
||||
;
|
||||
;
|
||||
; 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.
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <Preferences.h>
|
||||
|
||||
#include "evse.h"
|
||||
#include "utils.h"
|
||||
#include "OneWire.h"
|
||||
|
||||
unsigned char RFID[8] = {0, 0, 0, 0, 0, 0, 0, 0};
|
||||
unsigned char RFIDlist[600]; // holds up to 100 RFIDs
|
||||
|
||||
|
||||
// ############################# OneWire functions #############################
|
||||
|
||||
|
||||
|
||||
// Reset 1-Wire device on SW input
|
||||
// returns: 1 Device found
|
||||
// 0 No device found
|
||||
// 255 Error. Line is pulled low (short, or external button pressed?)
|
||||
//
|
||||
unsigned char OneWireReset(void) {
|
||||
unsigned char r;
|
||||
|
||||
if (digitalRead(PIN_SW_IN) == LOW) return 255; // Error, pulled low by external device?
|
||||
|
||||
ONEWIRE_LOW; // Drive wire low
|
||||
delayMicroseconds(480);
|
||||
RTC_ENTER_CRITICAL(); // Disable interrupts
|
||||
ONEWIRE_FLOATHIGH; // don't drive high, but use pullup
|
||||
delayMicroseconds(70);
|
||||
if (digitalRead(PIN_SW_IN) == HIGH) r = 0; // sample pin to see if there is a OneWire device..
|
||||
else r = 1;
|
||||
RTC_EXIT_CRITICAL(); // Restore interrupts
|
||||
delayMicroseconds(410);
|
||||
return r;
|
||||
}
|
||||
|
||||
void OneWireWriteBit(unsigned char v) {
|
||||
|
||||
if (v & 1) { // write a '1'
|
||||
RTC_ENTER_CRITICAL(); // Disable interrupts
|
||||
ONEWIRE_LOW; // Drive low
|
||||
delayMicroseconds(10);
|
||||
ONEWIRE_HIGH; // Drive high
|
||||
RTC_EXIT_CRITICAL(); // Restore interrupts
|
||||
delayMicroseconds(55);
|
||||
} else { // write a '0'
|
||||
RTC_ENTER_CRITICAL(); // Disable interrupts
|
||||
ONEWIRE_LOW; // Drive low
|
||||
delayMicroseconds(65);
|
||||
ONEWIRE_HIGH; // Drive high
|
||||
RTC_EXIT_CRITICAL(); // Restore interrupts
|
||||
delayMicroseconds(5);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned char OneWireReadBit(void) {
|
||||
unsigned char r;
|
||||
|
||||
RTC_ENTER_CRITICAL(); // Disable interrupts
|
||||
ONEWIRE_LOW;
|
||||
delayMicroseconds(3);
|
||||
ONEWIRE_FLOATHIGH;
|
||||
delayMicroseconds(10);
|
||||
if (digitalRead(PIN_SW_IN) == HIGH) r = 1; // sample pin
|
||||
else r = 0;
|
||||
RTC_EXIT_CRITICAL(); // Restore interrupts
|
||||
delayMicroseconds(53);
|
||||
return r;
|
||||
}
|
||||
|
||||
void OneWireWrite(unsigned char v) {
|
||||
unsigned char bitmask;
|
||||
for (bitmask = 0x01; bitmask ; bitmask <<= 1) {
|
||||
OneWireWriteBit( (bitmask & v) ? 1u : 0);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned char OneWireRead(void) {
|
||||
unsigned char bitmask, r = 0;
|
||||
|
||||
for (bitmask = 0x01; bitmask ; bitmask <<= 1) {
|
||||
if ( OneWireReadBit()) r |= bitmask;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
#if FAKE_RFID
|
||||
unsigned char OneWireReadCardId(void) {
|
||||
if (!RFIDstatus && Show_RFID) { //if ready to accept new card and it is shown
|
||||
RFID[0] = 0x01; //Family Code
|
||||
RFID[1] = 0x01; //RFID id = "01 02 03 04 05 06"
|
||||
RFID[2] = 0x02;
|
||||
RFID[3] = 0x03;
|
||||
RFID[4] = 0x04;
|
||||
RFID[5] = 0x05;
|
||||
RFID[6] = 0x06;
|
||||
RFID[7] = 0xf0; //crc8 code TODO is this ok?
|
||||
Show_RFID = 0; //this makes "showing" the RFID a one shot event
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
return 0; //card is already read, no new card
|
||||
}
|
||||
|
||||
#else
|
||||
unsigned char OneWireReadCardId(void) {
|
||||
unsigned char x;
|
||||
|
||||
if (OneWireReset() == 1) { // RFID card detected
|
||||
OneWireWrite(0x33); // OneWire ReadRom Command
|
||||
for (x=0 ; x<8 ; x++) RFID[x] = OneWireRead(); // read Family code (0x01) RFID ID (6 bytes) and crc8
|
||||
if (crc8(RFID,8)) {
|
||||
RFID[0] = 0; // CRC incorrect, clear first byte of RFID buffer
|
||||
return 0;
|
||||
} else {
|
||||
for (x=1 ; x<7 ; x++) _LOG_A("%02x",RFID[x]);
|
||||
_LOG_A("\r\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// ############################## RFID functions ##############################
|
||||
|
||||
|
||||
|
||||
// Write a list of 20 RFID's to the eeprom
|
||||
//
|
||||
void WriteRFIDlist(void) {
|
||||
|
||||
if (preferences.begin("RFIDlist", false) ) { // read/write
|
||||
preferences.putBytes("RFID", RFIDlist, 600); // write 600 bytes to storage
|
||||
preferences.putUChar("RFIDinit", 2); // data initialized to 600byte mode
|
||||
preferences.end();
|
||||
} else {
|
||||
_LOG_A("Error opening preferences!\n");
|
||||
}
|
||||
|
||||
|
||||
_LOG_I("\nRFID list saved\n");
|
||||
}
|
||||
|
||||
// Read a list of 20 RFID's from preferences
|
||||
//
|
||||
void ReadRFIDlist(void) {
|
||||
uint8_t initialized = 0;
|
||||
|
||||
if (preferences.begin("RFIDlist", true) ) { // read only
|
||||
initialized = preferences.getUChar("RFIDinit", 0);
|
||||
switch (initialized) {
|
||||
case 1: // we were initialized to old 120 bytes mode
|
||||
preferences.getBytes("RFID", RFIDlist, 120); // read 120 bytes from storage
|
||||
//we are now going to convert from RFIDlist 120bytes to RFIDlist 600bytes
|
||||
for (int i = 120; i < 600; i++) RFIDlist[i] = 0xff;
|
||||
preferences.remove("RFID");
|
||||
preferences.end();
|
||||
WriteRFIDlist();
|
||||
break;
|
||||
case 0:
|
||||
DeleteAllRFID(); // when unitialized, delete all cardIDs
|
||||
setItemValue(MENU_RFIDREADER, 0); // RFID Reader Disabled
|
||||
break;
|
||||
case 2: // extended RFIDlist with room for 100tags of 6 bytes = 600 bytes
|
||||
preferences.getBytes("RFID", RFIDlist, 600); // read 600 bytes from storage
|
||||
preferences.end();
|
||||
break;
|
||||
}
|
||||
|
||||
} else {
|
||||
_LOG_A("Error opening preferences!\n") ;
|
||||
}
|
||||
}
|
||||
|
||||
// scan for matching RFID in RFIDlist
|
||||
// returns offset+6 when found, 0 when not found
|
||||
uint16_t MatchRFID(void) {
|
||||
uint16_t offset = 0, r;
|
||||
|
||||
do {
|
||||
r = memcmp(RFID + 1, RFIDlist + offset, 6); // compare read RFID with list of stored RFID's
|
||||
offset += 6;
|
||||
} while (r !=0 && offset < 594);
|
||||
|
||||
if (r == 0) return offset; // return offset + 6 in RFIDlist
|
||||
else return 0;
|
||||
}
|
||||
|
||||
|
||||
// Store RFID card in memory and eeprom
|
||||
// returns 1 when successful
|
||||
// returns 2 when already stored
|
||||
// returns 0 when all slots are full.
|
||||
unsigned char StoreRFID(void) {
|
||||
uint16_t offset = 0, r;
|
||||
unsigned char empty[6] = {0xff,0xff,0xff,0xff,0xff,0xff};
|
||||
|
||||
// first check if the Card ID was already stored.
|
||||
if ( MatchRFID() ) return 2; // already stored, that's ok.
|
||||
|
||||
do {
|
||||
r = memcmp(empty, RFIDlist + offset, 6);
|
||||
offset += 6;
|
||||
} while (r !=0 && offset < 600);
|
||||
if (r != 0) return 0; // no more room to store RFID
|
||||
offset -= 6;
|
||||
_LOG_A("offset %u ",offset);
|
||||
memcpy(RFIDlist + offset, RFID+1, 6);
|
||||
|
||||
_LOG_I("\nRFIDlist:");
|
||||
for (r=0; r<600; r++) _LOG_I_NO_FUNC("%02x",RFIDlist[r]);
|
||||
|
||||
WriteRFIDlist();
|
||||
return 1;
|
||||
}
|
||||
|
||||
//load and store parameter RFIDparm into global variable RFID
|
||||
void LoadandStoreRFID(unsigned int *RFIDparam) {
|
||||
for (int i = 0; i < 8; i++)
|
||||
RFID[i]=RFIDparam[i];
|
||||
StoreRFID();
|
||||
}
|
||||
|
||||
// Delete RFID card in memory and eeprom
|
||||
// returns 1 when successful, 0 when RFID was not found
|
||||
unsigned char DeleteRFID(void) {
|
||||
uint16_t offset = 0, r;
|
||||
|
||||
offset = MatchRFID(); // find RFID in list
|
||||
if (offset) {
|
||||
offset -= 6;
|
||||
for (r = 0; r < 6; r++) RFIDlist[offset + r] = 0xff;
|
||||
} else return 0;
|
||||
|
||||
_LOG_A("deleted %u ",offset);
|
||||
for (r=0; r<600; r++) _LOG_A("%02x",RFIDlist[r]);
|
||||
|
||||
WriteRFIDlist();
|
||||
return 1;
|
||||
}
|
||||
|
||||
void DeleteAllRFID(void) {
|
||||
uint16_t i;
|
||||
|
||||
for (i = 0; i < 600; i++) RFIDlist[i] = 0xff;
|
||||
WriteRFIDlist();
|
||||
_LOG_I("All RFID cards erased!\n");
|
||||
}
|
||||
|
||||
void CheckRFID(void) {
|
||||
uint16_t x;
|
||||
// When RFID is enabled, a OneWire RFID reader is expected on the SW input
|
||||
uint8_t RFIDReader = getItemValue(MENU_RFIDREADER);
|
||||
if (RFIDReader) { // RFID Reader set to Enabled, Learn or Delete
|
||||
if (OneWireReadCardId() ) { // Read card ID
|
||||
switch (RFIDReader) {
|
||||
case 1: // EnableAll. All learned cards accepted for locking /unlocking
|
||||
x = MatchRFID();
|
||||
if (x && !RFIDstatus) {
|
||||
_LOG_A("RFID card found!\n");
|
||||
if (Access_bit) {
|
||||
setAccess(false); // Access Off, Switch back to state B1/C1
|
||||
} else setAccess(true);
|
||||
|
||||
RFIDstatus = 1;
|
||||
} else if (!x) RFIDstatus = 7; // invalid card
|
||||
BacklightTimer = BACKLIGHT;
|
||||
break;
|
||||
case 2: // EnableOne. Only the card that unlocks, can re-lock the EVSE
|
||||
x = MatchRFID();
|
||||
if (x && !RFIDstatus) {
|
||||
_LOG_A("RFID card found!\n");
|
||||
if (!Access_bit) {
|
||||
CardOffset = x; // store cardoffset from current card
|
||||
setAccess(true); // Access On
|
||||
} else if (CardOffset == x) {
|
||||
setAccess(false); // Access Off, Switch back to state B1/C1
|
||||
}
|
||||
RFIDstatus = 1;
|
||||
} else if (!x) RFIDstatus = 7; // invalid card
|
||||
BacklightTimer = BACKLIGHT;
|
||||
break;
|
||||
case 3: // Learn Card
|
||||
x = StoreRFID();
|
||||
if (x == 1) {
|
||||
_LOG_A("RFID card stored!\n");
|
||||
RFIDstatus = 2;
|
||||
} else if (x == 2 && !RFIDstatus) {
|
||||
_LOG_A("RFID card was already stored!\n");
|
||||
RFIDstatus = 4;
|
||||
} else if (!RFIDstatus) {
|
||||
_LOG_A("RFID storage full! Delete card first\n");
|
||||
RFIDstatus = 6;
|
||||
}
|
||||
break;
|
||||
case 4: // Delete Card
|
||||
x = DeleteRFID();
|
||||
if (x) {
|
||||
_LOG_A("RFID card deleted!\n");
|
||||
RFIDstatus = 3;
|
||||
} else if (!RFIDstatus) {
|
||||
_LOG_A("RFID card not in list!\n");
|
||||
RFIDstatus = 5;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else RFIDstatus = 0;
|
||||
}
|
||||
}
|
||||
@@ -1,266 +0,0 @@
|
||||
#include "glcd.h"
|
||||
|
||||
#ifdef GLCD_FULL_CHARSET
|
||||
const unsigned char font[0x100][5] = {
|
||||
#else
|
||||
const unsigned char font[0x7F][5] = {
|
||||
#endif
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x00
|
||||
{0x00, 0x12, 0x1F, 0x10, 0x00}, // 0x01 <20>
|
||||
{0x00, 0x19, 0x1D, 0x17, 0x12}, // 0x02 <20>
|
||||
{0x00, 0x11, 0x15, 0x1F, 0x0A}, // 0x03 <20>
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x04
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x05
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x06
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x07
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x08
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x09
|
||||
{0x08, 0x1C, 0x1C, 0x1C, 0x08}, // 0x0A Energy blob
|
||||
{0x63, 0x55, 0x49, 0x41, 0x63}, // 0x0B Sum
|
||||
{0x00, 0x02, 0x05, 0x02, 0x00}, // 0x0C <20>
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x0D
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x0E
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x0F
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x10
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x11
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x12
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x13
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x14
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x15
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x16
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x17
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x18
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x19
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x1A
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x1B
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x1C
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x1D
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x1E
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x1F
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x20 Space
|
||||
{0x00, 0x00, 0x5F, 0x00, 0x00}, // 0x21 !
|
||||
{0x00, 0x07, 0x00, 0x07, 0x00}, // 0x22 "
|
||||
{0x14, 0x7F, 0x14, 0x7F, 0x14}, // 0x23 #
|
||||
{0x24, 0x2A, 0x7F, 0x2A, 0x12}, // 0x24 $
|
||||
{0x23, 0x13, 0x08, 0x64, 0x62}, // 0x25 %
|
||||
{0x36, 0x49, 0x56, 0x20, 0x50}, // 0x26 &
|
||||
{0x00, 0x08, 0x07, 0x03, 0x00}, // 0x27 '
|
||||
{0x00, 0x1C, 0x22, 0x41, 0x00}, // 0x28 (
|
||||
{0x00, 0x41, 0x22, 0x1C, 0x00}, // 0x29 )
|
||||
{0x2A, 0x1C, 0x7F, 0x1C, 0x2A}, // 0x2A *
|
||||
{0x08, 0x08, 0x3E, 0x08, 0x08}, // 0x2B +
|
||||
{0x00, 0x80, 0x70, 0x30, 0x00}, // 0x2C ,
|
||||
{0x08, 0x08, 0x08, 0x08, 0x08}, // 0x2D -
|
||||
{0x00, 0x00, 0x60, 0x60, 0x00}, // 0x2E .
|
||||
{0x20, 0x10, 0x08, 0x04, 0x02}, // 0x2F /
|
||||
{0x3E, 0x51, 0x49, 0x45, 0x3E}, // 0x30 0
|
||||
{0x00, 0x42, 0x7F, 0x40, 0x00}, // 0x31 1
|
||||
{0x72, 0x49, 0x49, 0x49, 0x46}, // 0x32 2
|
||||
{0x21, 0x41, 0x49, 0x4D, 0x33}, // 0x33 3
|
||||
{0x18, 0x14, 0x12, 0x7F, 0x10}, // 0x34 4
|
||||
{0x27, 0x45, 0x45, 0x45, 0x39}, // 0x35 5
|
||||
{0x3C, 0x4A, 0x49, 0x49, 0x31}, // 0x36 6
|
||||
{0x41, 0x21, 0x11, 0x09, 0x07}, // 0x37 7
|
||||
{0x36, 0x49, 0x49, 0x49, 0x36}, // 0x38 8
|
||||
{0x46, 0x49, 0x49, 0x29, 0x1E}, // 0x39 9
|
||||
{0x00, 0x00, 0x14, 0x00, 0x00}, // 0x3A :
|
||||
{0x00, 0x40, 0x34, 0x00, 0x00}, // 0x3B ;
|
||||
{0x00, 0x08, 0x14, 0x22, 0x41}, // 0x3C <
|
||||
{0x14, 0x14, 0x14, 0x14, 0x14}, // 0x3D =
|
||||
{0x00, 0x41, 0x22, 0x14, 0x08}, // 0x3E >
|
||||
{0x02, 0x01, 0x59, 0x09, 0x06}, // 0x3F ?
|
||||
{0x3E, 0x41, 0x5D, 0x59, 0x4E}, // 0x40 @
|
||||
{0x7C, 0x12, 0x11, 0x12, 0x7C}, // 0x41 A
|
||||
{0x7F, 0x49, 0x49, 0x49, 0x36}, // 0x42 B
|
||||
{0x3E, 0x41, 0x41, 0x41, 0x22}, // 0x43 C
|
||||
{0x7F, 0x41, 0x41, 0x41, 0x3E}, // 0x44 D
|
||||
{0x7F, 0x49, 0x49, 0x49, 0x41}, // 0x45 E
|
||||
{0x7F, 0x09, 0x09, 0x09, 0x01}, // 0x46 F
|
||||
{0x3E, 0x41, 0x41, 0x51, 0x73}, // 0x47 G
|
||||
{0x7F, 0x08, 0x08, 0x08, 0x7F}, // 0x48 H
|
||||
{0x00, 0x41, 0x7F, 0x41, 0x00}, // 0x49 I
|
||||
{0x20, 0x40, 0x41, 0x3F, 0x01}, // 0x4A J
|
||||
{0x7F, 0x08, 0x14, 0x22, 0x41}, // 0x4B K
|
||||
{0x7F, 0x40, 0x40, 0x40, 0x40}, // 0x4C L
|
||||
{0x7F, 0x02, 0x1C, 0x02, 0x7F}, // 0x4D M
|
||||
{0x7F, 0x04, 0x08, 0x10, 0x7F}, // 0x4E N
|
||||
{0x3E, 0x41, 0x41, 0x41, 0x3E}, // 0x4F O
|
||||
{0x7F, 0x09, 0x09, 0x09, 0x06}, // 0x50 P
|
||||
{0x3E, 0x41, 0x51, 0x21, 0x5E}, // 0x51 Q
|
||||
{0x7F, 0x09, 0x19, 0x29, 0x46}, // 0x52 R
|
||||
{0x26, 0x49, 0x49, 0x49, 0x32}, // 0x53 S
|
||||
{0x03, 0x01, 0x7F, 0x01, 0x03}, // 0x54 T
|
||||
{0x3F, 0x40, 0x40, 0x40, 0x3F}, // 0x55 U
|
||||
{0x1F, 0x20, 0x40, 0x20, 0x1F}, // 0x56 V
|
||||
{0x3F, 0x40, 0x38, 0x40, 0x3F}, // 0x57 W
|
||||
{0x63, 0x14, 0x08, 0x14, 0x63}, // 0x58 X
|
||||
{0x03, 0x04, 0x78, 0x04, 0x03}, // 0x59 Y
|
||||
{0x61, 0x59, 0x49, 0x4D, 0x43}, // 0x5A Z
|
||||
{0x00, 0x7F, 0x41, 0x41, 0x41}, // 0x5B [
|
||||
{0x02, 0x04, 0x08, 0x10, 0x20}, // 0x5C Backslash
|
||||
{0x00, 0x41, 0x41, 0x41, 0x7F}, // 0x5D ]
|
||||
{0x04, 0x02, 0x01, 0x02, 0x04}, // 0x5E ^
|
||||
{0x40, 0x40, 0x40, 0x40, 0x40}, // 0x5F _
|
||||
{0x00, 0x03, 0x07, 0x08, 0x00}, // 0x60 `
|
||||
{0x20, 0x54, 0x54, 0x78, 0x40}, // 0x61 a
|
||||
{0x7F, 0x28, 0x44, 0x44, 0x38}, // 0x62 b
|
||||
{0x38, 0x44, 0x44, 0x44, 0x28}, // 0x63 c
|
||||
{0x38, 0x44, 0x44, 0x28, 0x7F}, // 0x64 d
|
||||
{0x38, 0x54, 0x54, 0x54, 0x18}, // 0x65 e
|
||||
{0x00, 0x08, 0x7E, 0x09, 0x02}, // 0x66 f
|
||||
{0x18, 0xA4, 0xA4, 0x9C, 0x78}, // 0x67 g
|
||||
{0x7F, 0x08, 0x04, 0x04, 0x78}, // 0x68 h
|
||||
{0x00, 0x44, 0x7D, 0x40, 0x00}, // 0x69 i
|
||||
{0x20, 0x40, 0x40, 0x3D, 0x00}, // 0x6A j
|
||||
{0x7F, 0x10, 0x28, 0x44, 0x00}, // 0x6B k
|
||||
{0x00, 0x41, 0x7F, 0x40, 0x00}, // 0x6C l
|
||||
{0x7C, 0x04, 0x78, 0x04, 0x78}, // 0x6D m
|
||||
{0x7C, 0x08, 0x04, 0x04, 0x78}, // 0x6E n
|
||||
{0x38, 0x44, 0x44, 0x44, 0x38}, // 0x6F o
|
||||
{0xFC, 0x18, 0x24, 0x24, 0x18}, // 0x70 p
|
||||
{0x18, 0x24, 0x24, 0x18, 0xFC}, // 0x71 q
|
||||
{0x7C, 0x08, 0x04, 0x04, 0x08}, // 0x72 r
|
||||
{0x48, 0x54, 0x54, 0x54, 0x24}, // 0x73 s
|
||||
{0x04, 0x04, 0x3F, 0x44, 0x24}, // 0x74 t
|
||||
{0x3C, 0x40, 0x40, 0x20, 0x7C}, // 0x75 u
|
||||
{0x1C, 0x20, 0x40, 0x20, 0x1C}, // 0x76 v
|
||||
{0x3C, 0x40, 0x30, 0x40, 0x3C}, // 0x77 w
|
||||
{0x44, 0x28, 0x10, 0x28, 0x44}, // 0x78 x
|
||||
{0x4C, 0x90, 0x90, 0x90, 0x7C}, // 0x79 y
|
||||
{0x44, 0x64, 0x54, 0x4C, 0x44}, // 0x7A z
|
||||
{0x00, 0x08, 0x36, 0x41, 0x00}, // 0x7B {
|
||||
{0x00, 0x00, 0x77, 0x00, 0x00}, // 0x7C |
|
||||
{0x00, 0x41, 0x36, 0x08, 0x00}, // 0x7D }
|
||||
{0x02, 0x01, 0x02, 0x04, 0x02}, // 0x7E ~
|
||||
#ifdef GLCD_FULL_CHARSET
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x7F Delete
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x80
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x81
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x82
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x83
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x84
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x85
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x86
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x87
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x88
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x89
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x8A
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x8B
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x8C
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x8D
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x8E
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x8F
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x90
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x91
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x92
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x93
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x94
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x95
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x96
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x97
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x98
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x99
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x9A
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x9B
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x9C
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x9D
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x9E
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x9F
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0xA0
|
||||
{0x00, 0x00, 0xFA, 0x00, 0x00}, // 0xA1 <20>
|
||||
{0x3C, 0x24, 0xFF, 0x24, 0x24}, // 0xA2 <20>
|
||||
{0x48, 0x7E, 0x49, 0x43, 0x66}, // 0xA3 <20>
|
||||
{0x1C, 0x36, 0x55, 0x41, 0x22}, // 0xA4 <20>
|
||||
{0x2B, 0x2F, 0xFC, 0x2F, 0x2B}, // 0xA5 <20>
|
||||
{0x08, 0x55, 0x56, 0x55, 0x20}, // 0xA6 <20>
|
||||
{0x00, 0x66, 0x89, 0x95, 0x6A}, // 0xA7 <20>
|
||||
{0x00, 0x59, 0x7A, 0x69, 0x00}, // 0xA8 <20>
|
||||
{0x38, 0x7C, 0x6C, 0x44, 0x38}, // 0xA9 <20>
|
||||
{0x26, 0x29, 0x29, 0x2F, 0x28}, // 0xAA <20>
|
||||
{0x08, 0x14, 0x2A, 0x14, 0x22}, // 0xAB <20>
|
||||
{0x08, 0x08, 0x08, 0x08, 0x38}, // 0xAC <20>
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0xAD <20>
|
||||
{0x38, 0x7C, 0x5C, 0x64, 0x38}, // 0xAE <20>
|
||||
{0x00, 0x01, 0x01, 0x01, 0x00}, // 0xAF <20>
|
||||
{0x00, 0x02, 0x05, 0x02, 0x00}, // 0xB0 <20>
|
||||
{0x44, 0x44, 0x5F, 0x44, 0x44}, // 0xB1 <20>
|
||||
{0x00, 0x19, 0x1D, 0x17, 0x12}, // 0xB2 <20>
|
||||
{0x00, 0x11, 0x15, 0x1F, 0x0A}, // 0xB3 <20>
|
||||
{0x44, 0x65, 0x56, 0x4D, 0x44}, // 0xB4 <20>
|
||||
{0x40, 0x7E, 0x20, 0x1E, 0x20}, // 0xB5 <20>
|
||||
{0x06, 0x09, 0x7F, 0x01, 0x7F}, // 0xB6 <20>
|
||||
{0x00, 0x00, 0x08, 0x00, 0x00}, // 0xB7 <20>
|
||||
{0x00, 0x69, 0x7A, 0x59, 0x00}, // 0xB8 <20>
|
||||
{0x00, 0x12, 0x1F, 0x10, 0x00}, // 0xB9 <20>
|
||||
{0x26, 0x29, 0x29, 0x29, 0x26}, // 0xBA <20>
|
||||
{0x22, 0x14, 0x2A, 0x14, 0x08}, // 0xBB <20>
|
||||
{0x3E, 0x41, 0x7F, 0x49, 0x41}, // 0xBC <20>
|
||||
{0x38, 0x44, 0x38, 0x54, 0x18}, // 0xBD <20>
|
||||
{0x04, 0x09, 0x70, 0x09, 0x04}, // 0xBE <20>
|
||||
{0x30, 0x48, 0x4D, 0x40, 0x20}, // 0xBF <20>
|
||||
{0x70, 0x28, 0x25, 0x2A, 0x70}, // 0xC0 <20>
|
||||
{0x70, 0x2A, 0x25, 0x28, 0x70}, // 0xC1 <20>
|
||||
{0x70, 0x2A, 0x25, 0x2A, 0x70}, // 0xC2 <20>
|
||||
{0x70, 0x2A, 0x25, 0x2A, 0x71}, // 0xC3 <20>
|
||||
{0x70, 0x29, 0x24, 0x29, 0x70}, // 0xC4 <20>
|
||||
{0x70, 0x28, 0x25, 0x28, 0x70}, // 0xC5 <20>
|
||||
{0x7C, 0x12, 0x7F, 0x49, 0x41}, // 0xC6 <20>
|
||||
{0x1E, 0xA1, 0xA1, 0x61, 0x12}, // 0xC7 <20>
|
||||
{0x7C, 0x54, 0x55, 0x46, 0x00}, // 0xC8 <20>
|
||||
{0x7C, 0x56, 0x55, 0x44, 0x00}, // 0xC9 <20>
|
||||
{0x7C, 0x56, 0x55, 0x46, 0x00}, // 0xCA <20>
|
||||
{0x7C, 0x55, 0x54, 0x45, 0x00}, // 0xCB <20>
|
||||
{0x00, 0x44, 0x7D, 0x46, 0x00}, // 0xCC <20>
|
||||
{0x00, 0x46, 0x7D, 0x44, 0x00}, // 0xCD <20>
|
||||
{0x00, 0x46, 0x7D, 0x46, 0x00}, // 0xCE <20>
|
||||
{0x00, 0x45, 0x7C, 0x45, 0x00}, // 0xCF <20>
|
||||
{0x7F, 0x49, 0x41, 0x41, 0x3E}, // 0xD0 <20>
|
||||
{0x7C, 0x0E, 0x19, 0x32, 0x7D}, // 0xD1 <20>
|
||||
{0x38, 0x44, 0x45, 0x46, 0x38}, // 0xD2 <20>
|
||||
{0x38, 0x46, 0x45, 0x44, 0x38}, // 0xD3 <20>
|
||||
{0x38, 0x46, 0x45, 0x46, 0x38}, // 0xD4 <20>
|
||||
{0x38, 0x46, 0x45, 0x46, 0x39}, // 0xD5 <20>
|
||||
{0x38, 0x45, 0x44, 0x45, 0x38}, // 0xD6 <20>
|
||||
{0x00, 0x14, 0x08, 0x14, 0x00}, // 0xD7 <20>
|
||||
{0x3C, 0x32, 0x2A, 0x26, 0x1E}, // 0xD8 <20>
|
||||
{0x3C, 0x40, 0x41, 0x42, 0x3C}, // 0xD9 <20>
|
||||
{0x3C, 0x42, 0x41, 0x40, 0x3C}, // 0xDA <20>
|
||||
{0x3C, 0x42, 0x41, 0x42, 0x3C}, // 0xDB <20>
|
||||
{0x3C, 0x41, 0x40, 0x41, 0x3C}, // 0xDC <20>
|
||||
{0x04, 0x0A, 0x71, 0x08, 0x04}, // 0xDD <20>
|
||||
{0x7E, 0x24, 0x24, 0x24, 0x18}, // 0xDE <20>
|
||||
{0x7C, 0x2A, 0x2A, 0x3E, 0x14}, // 0xDF <20>
|
||||
{0x20, 0x54, 0x55, 0x7A, 0x40}, // 0xE0 <20>
|
||||
{0x20, 0x56, 0x55, 0x78, 0x40}, // 0xE1 <20>
|
||||
{0x20, 0x56, 0x55, 0x7A, 0x40}, // 0xE2 <20>
|
||||
{0x20, 0x56, 0x55, 0x7A, 0x41}, // 0xE3 <20>
|
||||
{0x20, 0x55, 0x54, 0x79, 0x40}, // 0xE4 <20>
|
||||
{0x20, 0x54, 0x55, 0x78, 0x40}, // 0xE5 <20>
|
||||
{0x20, 0x54, 0x38, 0x54, 0x18}, // 0xE6 <20>
|
||||
{0x18, 0x3C, 0xA4, 0xE4, 0x24}, // 0xE7 <20>
|
||||
{0x38, 0x54, 0x55, 0x56, 0x18}, // 0xE8 <20>
|
||||
{0x38, 0x56, 0x55, 0x54, 0x18}, // 0xE9 <20>
|
||||
{0x38, 0x56, 0x55, 0x56, 0x18}, // 0xEA <20>
|
||||
{0x38, 0x55, 0x54, 0x55, 0x18}, // 0xEB <20>
|
||||
{0x00, 0x44, 0x7D, 0x42, 0x00}, // 0xEC <20>
|
||||
{0x00, 0x46, 0x7D, 0x40, 0x00}, // 0xED <20>
|
||||
{0x00, 0x46, 0x7D, 0x42, 0x00}, // 0xEE <20>
|
||||
{0x00, 0x45, 0x7C, 0x41, 0x00}, // 0xEF <20>
|
||||
{0x38, 0x45, 0x45, 0x47, 0x38}, // 0xF0 <20>
|
||||
{0x7C, 0x0A, 0x05, 0x06, 0x79}, // 0xF1 <20>
|
||||
{0x38, 0x44, 0x45, 0x46, 0x38}, // 0xF2 <20>
|
||||
{0x38, 0x46, 0x45, 0x44, 0x38}, // 0xF3 <20>
|
||||
{0x38, 0x46, 0x45, 0x46, 0x38}, // 0xF4 <20>
|
||||
{0x38, 0x46, 0x45, 0x46, 0x39}, // 0xF5 <20>
|
||||
{0x38, 0x45, 0x44, 0x45, 0x38}, // 0xF6 <20>
|
||||
{0x08, 0x08, 0x6B, 0x6B, 0x08}, // 0xF7 <20>
|
||||
{0x3C, 0x32, 0x2A, 0x26, 0x1E}, // 0xF8 <20>
|
||||
{0x3C, 0x40, 0x41, 0x22, 0x7C}, // 0xF9 <20>
|
||||
{0x3C, 0x42, 0x41, 0x20, 0x7C}, // 0xFA <20>
|
||||
{0x3C, 0x42, 0x41, 0x22, 0x7C}, // 0xFB <20>
|
||||
{0x3C, 0x41, 0x40, 0x21, 0x7C}, // 0xFC <20>
|
||||
{0x4C, 0x92, 0x91, 0x90, 0x7C}, // 0xFD <20>
|
||||
{0xFF, 0x22, 0x22, 0x22, 0x1C}, // 0xFE <20>
|
||||
{0x4C, 0x91, 0x90, 0x91, 0x7C}, // 0xFF <20>
|
||||
#endif
|
||||
};
|
||||
@@ -1,270 +0,0 @@
|
||||
#include "glcd.h"
|
||||
|
||||
#ifdef GLCD_HIRES_FONT
|
||||
|
||||
#ifdef GLCD_FULL_CHARSET
|
||||
const unsigned char font2[0x100][23] = {
|
||||
#else
|
||||
const unsigned char font2[0x7F][23] = {
|
||||
#endif
|
||||
{0x0}, // 0x00
|
||||
{0x0}, // 0x01
|
||||
{0x0}, // 0x02
|
||||
{0x0}, // 0x03
|
||||
{0x0}, // 0x04
|
||||
{0x0}, // 0x05
|
||||
{0x0}, // 0x06
|
||||
{0x0}, // 0x07
|
||||
{0x0}, // 0x08
|
||||
{0x0}, // 0x09
|
||||
{0x0}, // 0x0A
|
||||
{0x0}, // 0x0B
|
||||
{0x0}, // 0x0C
|
||||
{0x0}, // 0x0D
|
||||
{0x0}, // 0x0E
|
||||
{0x0}, // 0x0F
|
||||
{0x0}, // 0x10
|
||||
{0x0}, // 0x11
|
||||
{0x0}, // 0x12
|
||||
{0x0}, // 0x13
|
||||
{0x0}, // 0x14
|
||||
{0x0}, // 0x15
|
||||
{0x0}, // 0x16
|
||||
{0x0}, // 0x17
|
||||
{0x0}, // 0x18
|
||||
{0x0}, // 0x19
|
||||
{0x0}, // 0x1A
|
||||
{0x0}, // 0x1B
|
||||
{0x0}, // 0x1C
|
||||
{0x0}, // 0x1D
|
||||
{0x0}, // 0x1E
|
||||
{0x0}, // 0x1F
|
||||
{0x3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x20 Space
|
||||
{0x4, 0x7C, 0x00, 0xFF, 0x33, 0xFF, 0x33, 0x7C, 0x00}, // 0x21 !
|
||||
{0x6, 0x3C, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x3C, 0x00}, // 0x22 "
|
||||
{0xB, 0x00, 0x02, 0x10, 0x1E, 0x90, 0x1F, 0xF0, 0x03, 0x7E, 0x02, 0x1E, 0x1E, 0x90, 0x1F, 0xF0, 0x03, 0x7E, 0x02, 0x1E, 0x00, 0x10, 0x00}, // 0x23 #
|
||||
{0x8, 0x78, 0x04, 0xFC, 0x0C, 0xCC, 0x0C, 0xFF, 0x3F, 0xFF, 0x3F, 0xCC, 0x0C, 0xCC, 0x0F, 0x88, 0x07}, // 0x24 $
|
||||
{0xB, 0x00, 0x30, 0x38, 0x38, 0x38, 0x1C, 0x38, 0x0E, 0x00, 0x07, 0x80, 0x03, 0xC0, 0x01, 0xE0, 0x38, 0x70, 0x38, 0x38, 0x38, 0x1C, 0x00}, // 0x25 %
|
||||
{0x9, 0x00, 0x1F, 0xB8, 0x3F, 0xFC, 0x31, 0xC6, 0x21, 0xE2, 0x37, 0x3E, 0x1E, 0x1C, 0x1C, 0x00, 0x36, 0x00, 0x22}, // 0x26 &
|
||||
{0x3, 0x27, 0x00, 0x3F, 0x00, 0x1F, 0x00}, // 0x27 '
|
||||
{0x6, 0xF0, 0x03, 0xFC, 0x0F, 0xFE, 0x1F, 0x07, 0x38, 0x01, 0x20, 0x01, 0x20}, // 0x28 (
|
||||
{0x6, 0x01, 0x20, 0x01, 0x20, 0x07, 0x38, 0xFE, 0x1F, 0xFC, 0x0F, 0xF0, 0x03}, // 0x29 )
|
||||
{0x8, 0x98, 0x0C, 0xB8, 0x0E, 0xE0, 0x03, 0xF8, 0x0F, 0xF8, 0x0F, 0xE0, 0x03, 0xB8, 0x0E, 0x98, 0x0C}, // 0x2A *
|
||||
{0x8, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0xF0, 0x0F, 0xF0, 0x0F, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01}, // 0x2B +
|
||||
{0x3, 0x00, 0xB8, 0x00, 0xF8, 0x00, 0x78}, // 0x2C ,
|
||||
{0x8, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01}, // 0x2D -
|
||||
{0x3, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38}, // 0x2E .
|
||||
{0xB, 0x00, 0x18, 0x00, 0x1C, 0x00, 0x0E, 0x00, 0x07, 0x80, 0x03, 0xC0, 0x01, 0xE0, 0x00, 0x70, 0x00, 0x38, 0x00, 0x1C, 0x00, 0x0E, 0x00}, // 0x2F /
|
||||
{0xB, 0xF8, 0x07, 0xFE, 0x1F, 0x06, 0x1E, 0x03, 0x33, 0x83, 0x31, 0xC3, 0x30, 0x63, 0x30, 0x33, 0x30, 0x1E, 0x18, 0xFE, 0x1F, 0xF8, 0x07}, // 0x30 0
|
||||
{0xB, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x30, 0x0C, 0x30, 0x0E, 0x30, 0xFF, 0x3F, 0xFF, 0x3F, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x00}, // 0x31 1
|
||||
{0xB, 0x1C, 0x30, 0x1E, 0x38, 0x07, 0x3C, 0x03, 0x3E, 0x03, 0x37, 0x83, 0x33, 0xC3, 0x31, 0xE3, 0x30, 0x77, 0x30, 0x3E, 0x30, 0x1C, 0x30}, // 0x32 2
|
||||
{0xB, 0x0C, 0x0C, 0x0E, 0x1C, 0x07, 0x38, 0xC3, 0x30, 0xC3, 0x30, 0xC3, 0x30, 0xC3, 0x30, 0xC3, 0x30, 0xE7, 0x39, 0x7E, 0x1F, 0x3C, 0x0E}, // 0x33 3
|
||||
{0xB, 0xC0, 0x03, 0xE0, 0x03, 0x70, 0x03, 0x38, 0x03, 0x1C, 0x03, 0x0E, 0x03, 0x07, 0x03, 0xFF, 0x3F, 0xFF, 0x3F, 0x00, 0x03, 0x00, 0x03}, // 0x34 4
|
||||
{0xB, 0x3F, 0x0C, 0x7F, 0x1C, 0x63, 0x38, 0x63, 0x30, 0x63, 0x30, 0x63, 0x30, 0x63, 0x30, 0x63, 0x30, 0xE3, 0x38, 0xC3, 0x1F, 0x83, 0x0F}, // 0x35 5
|
||||
{0xB, 0xC0, 0x0F, 0xF0, 0x1F, 0xF8, 0x39, 0xDC, 0x30, 0xCE, 0x30, 0xC7, 0x30, 0xC3, 0x30, 0xC3, 0x30, 0xC3, 0x39, 0x80, 0x1F, 0x00, 0x0F}, // 0x36 6
|
||||
{0xB, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x30, 0x03, 0x3C, 0x03, 0x0F, 0xC3, 0x03, 0xF3, 0x00, 0x3F, 0x00, 0x0F, 0x00, 0x03, 0x00}, // 0x37 7
|
||||
{0xB, 0x00, 0x0F, 0xBC, 0x1F, 0xFE, 0x39, 0xE7, 0x30, 0xC3, 0x30, 0xC3, 0x30, 0xC3, 0x30, 0xE7, 0x30, 0xFE, 0x39, 0xBC, 0x1F, 0x00, 0x0F}, // 0x38 8
|
||||
{0xB, 0x3C, 0x00, 0x7E, 0x00, 0xE7, 0x30, 0xC3, 0x30, 0xC3, 0x30, 0xC3, 0x38, 0xC3, 0x1C, 0xC3, 0x0E, 0xE7, 0x07, 0xFE, 0x03, 0xFC, 0x00}, // 0x39 9
|
||||
{0x3, 0x70, 0x1C, 0x70, 0x1C, 0x70, 0x1C}, // 0x3A :
|
||||
{0x3, 0x70, 0x9C, 0x70, 0xFC, 0x70, 0x7C}, // 0x3B ;
|
||||
{0x8, 0xC0, 0x00, 0xE0, 0x01, 0xF0, 0x03, 0x38, 0x07, 0x1C, 0x0E, 0x0E, 0x1C, 0x07, 0x38, 0x03, 0x30}, // 0x3C <
|
||||
{0x9, 0x60, 0x06, 0x60, 0x06, 0x60, 0x06, 0x60, 0x06, 0x60, 0x06, 0x60, 0x06, 0x60, 0x06, 0x60, 0x06, 0x60, 0x06}, // 0x3D =
|
||||
{0x8, 0x03, 0x30, 0x07, 0x38, 0x0E, 0x1C, 0x1C, 0x0E, 0x38, 0x07, 0xF0, 0x03, 0xE0, 0x01, 0xC0, 0x00}, // 0x3E >
|
||||
{0xA, 0x1C, 0x00, 0x1E, 0x00, 0x07, 0x00, 0x03, 0x00, 0x83, 0x37, 0xC3, 0x37, 0xE3, 0x00, 0x77, 0x00, 0x3E, 0x00, 0x1C, 0x00}, // 0x3F ?
|
||||
{0xB, 0xF8, 0x0F, 0xFE, 0x1F, 0x07, 0x18, 0xF3, 0x33, 0xFB, 0x37, 0x1B, 0x36, 0xFB, 0x37, 0xFB, 0x37, 0x07, 0x36, 0xFE, 0x03, 0xF8, 0x01}, // 0x40 @
|
||||
{0xA, 0x00, 0x38, 0x00, 0x3F, 0xE0, 0x07, 0xFC, 0x06, 0x1F, 0x06, 0x1F, 0x06, 0xFC, 0x06, 0xE0, 0x07, 0x00, 0x3F, 0x00, 0x38}, // 0x41 A
|
||||
{0xA, 0xFF, 0x3F, 0xFF, 0x3F, 0xC3, 0x30, 0xC3, 0x30, 0xC3, 0x30, 0xC3, 0x30, 0xE7, 0x30, 0xFE, 0x39, 0xBC, 0x1F, 0x00, 0x0F}, // 0x42 B
|
||||
{0xA, 0xF0, 0x03, 0xFC, 0x0F, 0x0E, 0x1C, 0x07, 0x38, 0x03, 0x30, 0x03, 0x30, 0x03, 0x30, 0x07, 0x38, 0x0E, 0x1C, 0x0C, 0x0C}, // 0x43 C
|
||||
{0xA, 0xFF, 0x3F, 0xFF, 0x3F, 0x03, 0x30, 0x03, 0x30, 0x03, 0x30, 0x03, 0x30, 0x07, 0x38, 0x0E, 0x1C, 0xFC, 0x0F, 0xF0, 0x03}, // 0x44 D
|
||||
{0xA, 0xFF, 0x3F, 0xFF, 0x3F, 0xC3, 0x30, 0xC3, 0x30, 0xC3, 0x30, 0xC3, 0x30, 0xC3, 0x30, 0xC3, 0x30, 0x03, 0x30, 0x03, 0x30}, // 0x45 E
|
||||
{0xA, 0xFF, 0x3F, 0xFF, 0x3F, 0xC3, 0x00, 0xC3, 0x00, 0xC3, 0x00, 0xC3, 0x00, 0xC3, 0x00, 0xC3, 0x00, 0x03, 0x00, 0x03, 0x00}, // 0x46 F
|
||||
{0xA, 0xF0, 0x03, 0xFC, 0x0F, 0x0E, 0x1C, 0x07, 0x38, 0x03, 0x30, 0xC3, 0x30, 0xC3, 0x30, 0xC3, 0x30, 0xC7, 0x3F, 0xC6, 0x3F}, // 0x47 G
|
||||
{0xA, 0xFF, 0x3F, 0xFF, 0x3F, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xFF, 0x3F, 0xFF, 0x3F}, // 0x48 H
|
||||
{0x6, 0x03, 0x30, 0x03, 0x30, 0xFF, 0x3F, 0xFF, 0x3F, 0x03, 0x30, 0x03, 0x30}, // 0x49 I
|
||||
{0xA, 0x00, 0x0E, 0x00, 0x1E, 0x00, 0x38, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x38, 0xFF, 0x1F, 0xFF, 0x07}, // 0x4A J
|
||||
{0xA, 0xFF, 0x3F, 0xFF, 0x3F, 0xC0, 0x00, 0xE0, 0x01, 0xF0, 0x03, 0x38, 0x07, 0x1C, 0x0E, 0x0E, 0x1C, 0x07, 0x38, 0x03, 0x30}, // 0x4B K
|
||||
{0xA, 0xFF, 0x3F, 0xFF, 0x3F, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30}, // 0x4C L
|
||||
{0xA, 0xFF, 0x3F, 0xFF, 0x3F, 0x1E, 0x00, 0x78, 0x00, 0xE0, 0x01, 0xE0, 0x01, 0x78, 0x00, 0x1E, 0x00, 0xFF, 0x3F, 0xFF, 0x3F}, // 0x4D M
|
||||
{0xA, 0xFF, 0x3F, 0xFF, 0x3F, 0x0E, 0x00, 0x38, 0x00, 0xF0, 0x00, 0xC0, 0x03, 0x00, 0x07, 0x00, 0x1C, 0xFF, 0x3F, 0xFF, 0x3F}, // 0x4E N
|
||||
{0xA, 0xF0, 0x03, 0xFC, 0x0F, 0x0E, 0x1C, 0x07, 0x38, 0x03, 0x30, 0x03, 0x30, 0x07, 0x38, 0x0E, 0x1C, 0xFC, 0x0F, 0xF0, 0x03}, // 0x4F O
|
||||
{0xA, 0xFF, 0x3F, 0xFF, 0x3F, 0x83, 0x01, 0x83, 0x01, 0x83, 0x01, 0x83, 0x01, 0x83, 0x01, 0xC7, 0x01, 0xFE, 0x00, 0x7C, 0x00}, // 0x50 P
|
||||
{0xA, 0xF0, 0x03, 0xFC, 0x0F, 0x0E, 0x1C, 0x07, 0x38, 0x03, 0x30, 0x03, 0x36, 0x07, 0x3E, 0x0E, 0x1C, 0xFC, 0x3F, 0xF0, 0x33}, // 0x51 Q
|
||||
{0xA, 0xFF, 0x3F, 0xFF, 0x3F, 0x83, 0x01, 0x83, 0x01, 0x83, 0x03, 0x83, 0x07, 0x83, 0x0F, 0xC7, 0x1D, 0xFE, 0x38, 0x7C, 0x30}, // 0x52 R
|
||||
{0xA, 0x3C, 0x0C, 0x7E, 0x1C, 0xE7, 0x38, 0xC3, 0x30, 0xC3, 0x30, 0xC3, 0x30, 0xC3, 0x30, 0xC7, 0x39, 0x8E, 0x1F, 0x0C, 0x0F}, // 0x53 S
|
||||
{0x8, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0xFF, 0x3F, 0xFF, 0x3F, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00}, // 0x54 T
|
||||
{0xA, 0xFF, 0x07, 0xFF, 0x1F, 0x00, 0x38, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x38, 0xFF, 0x1F, 0xFF, 0x07}, // 0x55 U
|
||||
{0xA, 0x07, 0x00, 0x3F, 0x00, 0xF8, 0x01, 0xC0, 0x0F, 0x00, 0x3E, 0x00, 0x3E, 0xC0, 0x0F, 0xF8, 0x01, 0x3F, 0x00, 0x07, 0x00}, // 0x56 V
|
||||
{0xA, 0xFF, 0x3F, 0xFF, 0x3F, 0x00, 0x1C, 0x00, 0x06, 0x80, 0x03, 0x80, 0x03, 0x00, 0x06, 0x00, 0x1C, 0xFF, 0x3F, 0xFF, 0x3F}, // 0x57 W
|
||||
{0xA, 0x03, 0x30, 0x0F, 0x3C, 0x1C, 0x0E, 0x30, 0x03, 0xE0, 0x01, 0xE0, 0x01, 0x30, 0x03, 0x1C, 0x0E, 0x0F, 0x3C, 0x03, 0x30}, // 0x58 X
|
||||
{0xA, 0x03, 0x00, 0x0F, 0x00, 0x3C, 0x00, 0xF0, 0x00, 0xC0, 0x3F, 0xC0, 0x3F, 0xF0, 0x00, 0x3C, 0x00, 0x0F, 0x00, 0x03, 0x00}, // 0x59 Y
|
||||
{0xA, 0x03, 0x30, 0x03, 0x3C, 0x03, 0x3E, 0x03, 0x33, 0xC3, 0x31, 0xE3, 0x30, 0x33, 0x30, 0x1F, 0x30, 0x0F, 0x30, 0x03, 0x30}, // 0x5A Z
|
||||
{0x6, 0xFF, 0x3F, 0xFF, 0x3F, 0x03, 0x30, 0x03, 0x30, 0x03, 0x30, 0x03, 0x30}, // 0x5B [
|
||||
{0xB, 0x0E, 0x00, 0x1C, 0x00, 0x38, 0x00, 0x70, 0x00, 0xE0, 0x00, 0xC0, 0x01, 0x80, 0x03, 0x00, 0x07, 0x00, 0x0E, 0x00, 0x1C, 0x00, 0x18}, // 0x5C Backslash
|
||||
{0x6, 0x03, 0x30, 0x03, 0x30, 0x03, 0x30, 0x03, 0x30, 0xFF, 0x3F, 0xFF, 0x3F}, // 0x5D ]
|
||||
{0xB, 0x60, 0x00, 0x70, 0x00, 0x38, 0x00, 0x1C, 0x00, 0x0E, 0x00, 0x07, 0x00, 0x0E, 0x00, 0x1C, 0x00, 0x38, 0x00, 0x70, 0x00, 0x60, 0x00}, // 0x5E ^
|
||||
{0xB, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC0}, // 0x5F _
|
||||
{0x3, 0x3E, 0x00, 0x7E, 0x00, 0x4E, 0x00}, // 0x60 `
|
||||
{0xA, 0x00, 0x1C, 0x40, 0x3E, 0x60, 0x33, 0x60, 0x33, 0x60, 0x33, 0x60, 0x33, 0x60, 0x33, 0x60, 0x33, 0xE0, 0x3F, 0xC0, 0x3F}, // 0x61 a
|
||||
{0xA, 0xFF, 0x3F, 0xFF, 0x3F, 0xC0, 0x30, 0x60, 0x30, 0x60, 0x30, 0x60, 0x30, 0x60, 0x30, 0xE0, 0x38, 0xC0, 0x1F, 0x80, 0x0F}, // 0x62 b
|
||||
{0xA, 0x80, 0x0F, 0xC0, 0x1F, 0xE0, 0x38, 0x60, 0x30, 0x60, 0x30, 0x60, 0x30, 0x60, 0x30, 0x60, 0x30, 0xC0, 0x18, 0x80, 0x08}, // 0x63 c
|
||||
{0xA, 0x80, 0x0F, 0xC0, 0x1F, 0xE0, 0x38, 0x60, 0x30, 0x60, 0x30, 0x60, 0x30, 0xE0, 0x30, 0xC0, 0x30, 0xFF, 0x3F, 0xFF, 0x3F}, // 0x64 d
|
||||
{0xA, 0x80, 0x0F, 0xC0, 0x1F, 0xE0, 0x3B, 0x60, 0x33, 0x60, 0x33, 0x60, 0x33, 0x60, 0x33, 0x60, 0x33, 0xC0, 0x13, 0x80, 0x01}, // 0x65 e
|
||||
{0x8, 0xC0, 0x00, 0xC0, 0x00, 0xFC, 0x3F, 0xFE, 0x3F, 0xC7, 0x00, 0xC3, 0x00, 0xC3, 0x00, 0x03, 0x00}, // 0x66 f
|
||||
{0xA, 0x80, 0x03, 0xC0, 0xC7, 0xE0, 0xCE, 0x60, 0xCC, 0x60, 0xCC, 0x60, 0xCC, 0x60, 0xCC, 0x60, 0xE6, 0xE0, 0x7F, 0xE0, 0x3F}, // 0x67 g
|
||||
{0x9, 0xFF, 0x3F, 0xFF, 0x3F, 0xC0, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0xE0, 0x00, 0xC0, 0x3F, 0x80, 0x3F}, // 0x68 h
|
||||
{0x6, 0x00, 0x30, 0x60, 0x30, 0xEC, 0x3F, 0xEC, 0x3F, 0x00, 0x30, 0x00, 0x30}, // 0x69 i
|
||||
{0x6, 0x00, 0x60, 0x00, 0xE0, 0x00, 0xC0, 0x60, 0xC0, 0xEC, 0xFF, 0xEC, 0x7F}, // 0x6A j
|
||||
{0x8, 0xFF, 0x3F, 0xFF, 0x3F, 0x00, 0x03, 0x80, 0x07, 0xC0, 0x0F, 0xE0, 0x1C, 0x60, 0x38, 0x00, 0x30}, // 0x6B k
|
||||
{0x6, 0x00, 0x30, 0x03, 0x30, 0xFF, 0x3F, 0xFF, 0x3F, 0x00, 0x30, 0x00, 0x30}, // 0x6C l
|
||||
{0xA, 0xE0, 0x3F, 0xC0, 0x3F, 0xE0, 0x00, 0xE0, 0x00, 0xC0, 0x3F, 0xC0, 0x3F, 0xE0, 0x00, 0xE0, 0x00, 0xC0, 0x3F, 0x80, 0x3F}, // 0x6D m
|
||||
{0x9, 0xE0, 0x3F, 0xE0, 0x3F, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0xE0, 0x00, 0xC0, 0x3F, 0x80, 0x3F}, // 0x6E n
|
||||
{0xA, 0x80, 0x0F, 0xC0, 0x1F, 0xE0, 0x38, 0x60, 0x30, 0x60, 0x30, 0x60, 0x30, 0x60, 0x30, 0xE0, 0x38, 0xC0, 0x1F, 0x80, 0x0F}, // 0x6F o
|
||||
{0xA, 0xE0, 0xFF, 0xE0, 0xFF, 0x60, 0x0C, 0x60, 0x18, 0x60, 0x18, 0x60, 0x18, 0x60, 0x18, 0xE0, 0x1C, 0xC0, 0x0F, 0x80, 0x07}, // 0x70 p
|
||||
{0xA, 0x80, 0x07, 0xC0, 0x0F, 0xE0, 0x1C, 0x60, 0x18, 0x60, 0x18, 0x60, 0x18, 0x60, 0x18, 0x60, 0x0C, 0xE0, 0xFF, 0xE0, 0xFF}, // 0x71 q
|
||||
{0x9, 0xE0, 0x3F, 0xE0, 0x3F, 0xC0, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0xE0, 0x00, 0xC0, 0x00}, // 0x72 r
|
||||
{0x8, 0xC0, 0x11, 0xE0, 0x33, 0x60, 0x33, 0x60, 0x33, 0x60, 0x33, 0x60, 0x33, 0x60, 0x3F, 0x40, 0x1E}, // 0x73 s
|
||||
{0x8, 0x60, 0x00, 0x60, 0x00, 0xFE, 0x1F, 0xFE, 0x3F, 0x60, 0x30, 0x60, 0x30, 0x60, 0x30, 0x00, 0x30}, // 0x74 t
|
||||
{0xA, 0xE0, 0x0F, 0xE0, 0x1F, 0x00, 0x38, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x18, 0xE0, 0x3F, 0xE0, 0x3F}, // 0x75 u
|
||||
{0xA, 0x60, 0x00, 0xE0, 0x01, 0x80, 0x07, 0x00, 0x1E, 0x00, 0x38, 0x00, 0x38, 0x00, 0x1E, 0x80, 0x07, 0xE0, 0x01, 0x60, 0x00}, // 0x76 v
|
||||
{0xA, 0xE0, 0x07, 0xE0, 0x1F, 0x00, 0x38, 0x00, 0x1C, 0xE0, 0x0F, 0xE0, 0x0F, 0x00, 0x1C, 0x00, 0x38, 0xE0, 0x1F, 0xE0, 0x07}, // 0x77 w
|
||||
{0x9, 0x60, 0x30, 0xE0, 0x38, 0xC0, 0x1D, 0x80, 0x0F, 0x00, 0x07, 0x80, 0x0F, 0xC0, 0x1D, 0xE0, 0x38, 0x60, 0x30}, // 0x78 x
|
||||
{0x8, 0x60, 0x00, 0xE0, 0x81, 0x80, 0xE7, 0x00, 0x7E, 0x00, 0x1E, 0x80, 0x07, 0xE0, 0x01, 0x60, 0x00}, // 0x79 y
|
||||
{0x9, 0x60, 0x30, 0x60, 0x38, 0x60, 0x3C, 0x60, 0x36, 0x60, 0x33, 0xE0, 0x31, 0xE0, 0x30, 0x60, 0x30, 0x20, 0x30}, // 0x7A z
|
||||
{0x8, 0x80, 0x00, 0xC0, 0x01, 0xFC, 0x1F, 0x7E, 0x3F, 0x07, 0x70, 0x03, 0x60, 0x03, 0x60, 0x03, 0x60}, // 0x7B {
|
||||
{0x2, 0xBF, 0x3F, 0xBF, 0x3F}, // 0x7C |
|
||||
{0x8, 0x03, 0x60, 0x03, 0x60, 0x03, 0x60, 0x07, 0x70, 0x7E, 0x3F, 0xFC, 0x1F, 0xC0, 0x01, 0x80, 0x00}, // 0x7D }
|
||||
{0xA, 0x10, 0x00, 0x18, 0x00, 0x0C, 0x00, 0x04, 0x00, 0x0C, 0x00, 0x18, 0x00, 0x10, 0x00, 0x18, 0x00, 0x0C, 0x00, 0x04, 0x00}, // 0x7E ~
|
||||
#ifdef GLCD_FULL_CHARSET
|
||||
{0xA, 0x00, 0x0F, 0x80, 0x0F, 0xC0, 0x0C, 0x60, 0x0C, 0x30, 0x0C, 0x30, 0x0C, 0x60, 0x0C, 0xC0, 0x0C, 0x80, 0x0F, 0x00, 0x0F}, // 0x7F Delete
|
||||
{0x0}, // 0x80
|
||||
{0x0}, // 0x81
|
||||
{0x0}, // 0x82
|
||||
{0x0}, // 0x83
|
||||
{0x0}, // 0x84
|
||||
{0x0}, // 0x85
|
||||
{0x0}, // 0x86
|
||||
{0x0}, // 0x87
|
||||
{0x0}, // 0x88
|
||||
{0x0}, // 0x89
|
||||
{0x0}, // 0x8A
|
||||
{0x0}, // 0x8B
|
||||
{0x0}, // 0x8C
|
||||
{0x0}, // 0x8D
|
||||
{0x0}, // 0x8E
|
||||
{0x0}, // 0x8F
|
||||
{0x0}, // 0x90
|
||||
{0x0}, // 0x91
|
||||
{0x0}, // 0x92
|
||||
{0x0}, // 0x93
|
||||
{0x0}, // 0x94
|
||||
{0x0}, // 0x95
|
||||
{0x0}, // 0x96
|
||||
{0x0}, // 0x97
|
||||
{0x0}, // 0x98
|
||||
{0x0}, // 0x99
|
||||
{0x0}, // 0x9A
|
||||
{0x0}, // 0x9B
|
||||
{0x0}, // 0x9C
|
||||
{0x0}, // 0x9D
|
||||
{0x0}, // 0x9E
|
||||
{0x0}, // 0x9F
|
||||
{0x0}, // 0xA0
|
||||
{0x4, 0x80, 0x0F, 0xF3, 0x3F, 0xF3, 0x3F, 0x80, 0x0F}, // 0xA1 <20>
|
||||
{0x8, 0xE0, 0x03, 0xF0, 0x07, 0x38, 0x0E, 0xFE, 0x3F, 0xFE, 0x3F, 0x18, 0x0C, 0x38, 0x0E, 0x30, 0x06}, // 0xA2 <20>
|
||||
{0x9, 0x00, 0x18, 0x80, 0x1C, 0xF8, 0x1F, 0xFC, 0x0B, 0x8C, 0x18, 0x8C, 0x18, 0x1C, 0x18, 0x18, 0x18, 0x00, 0x08}, // 0xA3 <20>
|
||||
{0x9, 0x20, 0x01, 0xF0, 0x03, 0xFC, 0x0F, 0x2E, 0x1D, 0x27, 0x39, 0x23, 0x31, 0x23, 0x30, 0x07, 0x38, 0x0E, 0x1C}, // 0xA4 <20>
|
||||
{0xA, 0x03, 0x00, 0x0F, 0x0A, 0x3C, 0x0A, 0xF0, 0x0A, 0xC0, 0x3F, 0xC0, 0x3F, 0xF0, 0x0A, 0x3C, 0x0A, 0x0F, 0x0A, 0x03, 0x00}, // 0xA5 <20>
|
||||
{0xA, 0x60, 0x0C, 0xF0, 0x1C, 0xF9, 0x39, 0x9B, 0x31, 0x9E, 0x31, 0x9E, 0x31, 0x9B, 0x31, 0xB9, 0x3B, 0x30, 0x1F, 0x20, 0x0E}, // 0xA6 <20>
|
||||
{0x8, 0xDC, 0x08, 0xFE, 0x19, 0x22, 0x11, 0x22, 0x11, 0x22, 0x11, 0x22, 0x11, 0xE6, 0x1F, 0xC4, 0x0E}, // 0xA7 <20>
|
||||
{0x8, 0xC0, 0x11, 0xE2, 0x33, 0x66, 0x33, 0x6C, 0x33, 0x6C, 0x33, 0x66, 0x33, 0x62, 0x3F, 0x40, 0x1E}, // 0xA8 <20>
|
||||
{0xB, 0xF0, 0x07, 0xF8, 0x0F, 0x1C, 0x1C, 0xCC, 0x19, 0xEC, 0x1B, 0x2C, 0x1A, 0x6C, 0x1B, 0x4C, 0x19, 0x1C, 0x1C, 0xF8, 0x0F, 0xF0, 0x07}, // 0xA9 <20>
|
||||
{0xA, 0x70, 0x00, 0xFA, 0x06, 0xDB, 0x06, 0xDB, 0x06, 0xDB, 0x06, 0xDB, 0x06, 0xDB, 0x06, 0xDB, 0x06, 0xFF, 0x06, 0xFE, 0x00}, // 0xAA <20>
|
||||
{0x9, 0x80, 0x00, 0xC0, 0x01, 0x60, 0x03, 0x20, 0x02, 0x00, 0x00, 0x80, 0x00, 0xC0, 0x01, 0x60, 0x03, 0x20, 0x02}, // 0xAB <20>
|
||||
{0xA, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0xF8, 0x03, 0xF8, 0x03}, // 0xAC <20>
|
||||
{0x6, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00}, // 0xAD <20>
|
||||
{0xB, 0xF0, 0x07, 0xF8, 0x0F, 0x1C, 0x1C, 0xEC, 0x1B, 0xEC, 0x1B, 0xAC, 0x18, 0xEC, 0x1B, 0x4C, 0x1B, 0x1C, 0x1C, 0xF8, 0x0F, 0xF0, 0x07}, // 0xAE <20>
|
||||
{0x4, 0x0C, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x0C, 0x00}, // 0xAF <20>
|
||||
{0x6, 0x1E, 0x00, 0x3F, 0x00, 0x33, 0x00, 0x33, 0x00, 0x3F, 0x00, 0x1E, 0x00}, // 0xB0 <20>
|
||||
{0x6, 0xC0, 0x18, 0xC0, 0x18, 0xF0, 0x1B, 0xF0, 0x1B, 0xC0, 0x18, 0xC0, 0x18}, // 0xB1 <20>
|
||||
{0x5, 0x19, 0x00, 0x1D, 0x00, 0x15, 0x00, 0x17, 0x00, 0x12, 0x00}, // 0xB2 <20>
|
||||
{0x5, 0x11, 0x00, 0x15, 0x00, 0x15, 0x00, 0x1F, 0x00, 0x0A, 0x00}, // 0xB3 <20>
|
||||
{0xA, 0x18, 0x30, 0x18, 0x38, 0x19, 0x3C, 0x1B, 0x36, 0x1E, 0x33, 0x9E, 0x31, 0xDB, 0x30, 0x79, 0x30, 0x38, 0x30, 0x18, 0x30}, // 0xB4 <20>
|
||||
{0x9, 0xF0, 0xFF, 0xF0, 0xFF, 0x00, 0x0E, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x06, 0xF0, 0x0F, 0xF0, 0x0F}, // 0xB5 <20>
|
||||
{0xA, 0x38, 0x00, 0x7C, 0x00, 0xC6, 0x00, 0x82, 0x00, 0xFE, 0x3F, 0xFE, 0x3F, 0x02, 0x00, 0xFE, 0x3F, 0xFE, 0x3F, 0x02, 0x00}, // 0xB6 <20>
|
||||
{0x3, 0x80, 0x01, 0xC0, 0x03, 0x80, 0x01}, // 0xB7 <20>
|
||||
{0x9, 0x60, 0x30, 0x62, 0x38, 0x66, 0x3C, 0x6C, 0x36, 0x6C, 0x33, 0xE6, 0x31, 0xE2, 0x30, 0x60, 0x30, 0x20, 0x30}, // 0xB8 <20>
|
||||
{0x3, 0x02, 0x00, 0x1F, 0x00, 0x1F, 0x00}, // 0xB9 <20>
|
||||
{0xA, 0x3C, 0x00, 0x7E, 0x06, 0xE7, 0x06, 0xC3, 0x06, 0xC3, 0x06, 0xC3, 0x06, 0xC3, 0x06, 0xE7, 0x06, 0x7E, 0x06, 0x3C, 0x00}, // 0xBA <20>
|
||||
{0x9, 0x20, 0x02, 0x60, 0x03, 0xC0, 0x01, 0x80, 0x00, 0x00, 0x00, 0x20, 0x02, 0x60, 0x03, 0xC0, 0x01, 0x80, 0x00}, // 0xBB <20>
|
||||
{0xA, 0xF0, 0x03, 0xFC, 0x0F, 0x0E, 0x1C, 0x07, 0x38, 0x03, 0x30, 0xFF, 0x3F, 0xFF, 0x3F, 0xC3, 0x30, 0xC3, 0x30, 0xC3, 0x30}, // 0xBC <20>
|
||||
{0xA, 0x80, 0x0F, 0xC0, 0x1F, 0xE0, 0x38, 0x60, 0x30, 0xC0, 0x1F, 0xE0, 0x3B, 0x60, 0x33, 0x60, 0x33, 0xC0, 0x13, 0x80, 0x01}, // 0xBD <20>
|
||||
{0xA, 0x08, 0x00, 0x18, 0x00, 0x33, 0x00, 0x63, 0x00, 0xC0, 0x3F, 0xC0, 0x3F, 0x63, 0x00, 0x33, 0x00, 0x18, 0x00, 0x08, 0x00}, // 0xBE <20>
|
||||
{0xA, 0x00, 0x0E, 0x00, 0x1F, 0x80, 0x3B, 0xC0, 0x31, 0xFB, 0x30, 0x7B, 0x30, 0x00, 0x30, 0x00, 0x38, 0x00, 0x1E, 0x00, 0x0E}, // 0xBF <20>
|
||||
{0xA, 0x00, 0x38, 0x00, 0x3E, 0x80, 0x0F, 0xE1, 0x0D, 0x7B, 0x0C, 0x7E, 0x0C, 0xE4, 0x0D, 0x80, 0x0F, 0x00, 0x3E, 0x00, 0x38}, // 0xC0 <20>
|
||||
{0xA, 0x00, 0x38, 0x00, 0x3E, 0x80, 0x0F, 0xE4, 0x0D, 0x7E, 0x0C, 0x7B, 0x0C, 0xE1, 0x0D, 0x80, 0x0F, 0x00, 0x3E, 0x00, 0x38}, // 0xC1 <20>
|
||||
{0xA, 0x00, 0x38, 0x00, 0x3E, 0x84, 0x0F, 0xE6, 0x0D, 0x7B, 0x0C, 0x7B, 0x0C, 0xE6, 0x0D, 0x84, 0x0F, 0x00, 0x3E, 0x00, 0x38}, // 0xC2 <20>
|
||||
{0xA, 0x00, 0x38, 0x00, 0x3E, 0x82, 0x0F, 0xE3, 0x0D, 0x79, 0x0C, 0x7B, 0x0C, 0xE2, 0x0D, 0x83, 0x0F, 0x01, 0x3E, 0x00, 0x38}, // 0xC3 <20>
|
||||
{0xA, 0x00, 0x38, 0x00, 0x3E, 0x83, 0x0F, 0xE3, 0x0D, 0x78, 0x0C, 0x78, 0x0C, 0xE3, 0x0D, 0x83, 0x0F, 0x00, 0x3E, 0x00, 0x38}, // 0xC4 <20>
|
||||
{0xA, 0x00, 0x38, 0x00, 0x3E, 0x80, 0x0F, 0xE2, 0x0D, 0x75, 0x0C, 0x75, 0x0C, 0xE2, 0x0D, 0x80, 0x0F, 0x00, 0x3E, 0x00, 0x38}, // 0xC5 <20>
|
||||
{0xA, 0x00, 0x3C, 0x80, 0x3F, 0xF0, 0x07, 0x7C, 0x06, 0x1F, 0x06, 0xFF, 0x3F, 0xFF, 0x3F, 0xC3, 0x30, 0xC3, 0x30, 0x03, 0x30}, // 0xC6 <20>
|
||||
{0xA, 0xF0, 0x01, 0xFC, 0x07, 0x0E, 0xCE, 0x07, 0xDC, 0x03, 0xF8, 0x03, 0xF8, 0x03, 0x18, 0x07, 0x1C, 0x1E, 0x0E, 0x1C, 0x06}, // 0xC7 <20>
|
||||
{0xA, 0xF8, 0x3F, 0xF8, 0x3F, 0x99, 0x31, 0x9B, 0x31, 0x9E, 0x31, 0x9C, 0x31, 0x98, 0x31, 0x98, 0x31, 0x18, 0x30, 0x18, 0x30}, // 0xC8 <20>
|
||||
{0xA, 0xF8, 0x3F, 0xF8, 0x3F, 0x98, 0x31, 0x98, 0x31, 0x9C, 0x31, 0x9E, 0x31, 0x9B, 0x31, 0x99, 0x31, 0x18, 0x30, 0x18, 0x30}, // 0xC9 <20>
|
||||
{0xA, 0xF8, 0x3F, 0xF8, 0x3F, 0x9C, 0x31, 0x9E, 0x31, 0x9B, 0x31, 0x9B, 0x31, 0x9E, 0x31, 0x9C, 0x31, 0x18, 0x30, 0x18, 0x30}, // 0xCA <20>
|
||||
{0xA, 0xF8, 0x3F, 0xF8, 0x3F, 0x9B, 0x31, 0x9B, 0x31, 0x98, 0x31, 0x98, 0x31, 0x9B, 0x31, 0x9B, 0x31, 0x18, 0x30, 0x18, 0x30}, // 0xCB <20>
|
||||
{0x6, 0x19, 0x30, 0x1B, 0x30, 0xFE, 0x3F, 0xFC, 0x3F, 0x18, 0x30, 0x18, 0x30}, // 0xCC <20>
|
||||
{0x6, 0x18, 0x30, 0x18, 0x30, 0xFC, 0x3F, 0xFE, 0x3F, 0x1B, 0x30, 0x19, 0x30}, // 0xCD <20>
|
||||
{0x6, 0x1C, 0x30, 0x1E, 0x30, 0xFB, 0x3F, 0xFB, 0x3F, 0x1E, 0x30, 0x1C, 0x30}, // 0xCE <20>
|
||||
{0x6, 0x1B, 0x30, 0x1B, 0x30, 0xF8, 0x3F, 0xF8, 0x3F, 0x1B, 0x30, 0x1B, 0x30}, // 0xCF <20>
|
||||
{0xA, 0xC0, 0x00, 0xFF, 0x3F, 0xFF, 0x3F, 0xC3, 0x30, 0x03, 0x30, 0x03, 0x30, 0x07, 0x38, 0x0E, 0x1C, 0xFC, 0x0F, 0xF0, 0x03}, // 0xD0 <20>
|
||||
{0xA, 0xF8, 0x3F, 0xF8, 0x3F, 0x72, 0x00, 0xE3, 0x00, 0xC1, 0x01, 0x83, 0x03, 0x02, 0x07, 0x03, 0x0E, 0xF9, 0x3F, 0xF8, 0x3F}, // 0xD1 <20>
|
||||
{0xA, 0xE0, 0x0F, 0xF0, 0x1F, 0x39, 0x38, 0x1B, 0x30, 0x1E, 0x30, 0x1C, 0x30, 0x18, 0x30, 0x38, 0x38, 0xF0, 0x1F, 0xE0, 0x0F}, // 0xD2 <20>
|
||||
{0xA, 0xE0, 0x0F, 0xF0, 0x1F, 0x38, 0x38, 0x18, 0x30, 0x1C, 0x30, 0x1E, 0x30, 0x1B, 0x30, 0x39, 0x38, 0xF0, 0x1F, 0xE0, 0x0F}, // 0xD3 <20>
|
||||
{0xA, 0xE0, 0x0F, 0xF0, 0x1F, 0x3C, 0x38, 0x1E, 0x30, 0x1B, 0x30, 0x1B, 0x30, 0x1E, 0x30, 0x3C, 0x38, 0xF0, 0x1F, 0xE0, 0x0F}, // 0xD4 <20>
|
||||
{0xA, 0xE0, 0x0F, 0xF0, 0x1F, 0x3A, 0x38, 0x1B, 0x30, 0x19, 0x30, 0x1B, 0x30, 0x1A, 0x30, 0x3B, 0x38, 0xF1, 0x1F, 0xE0, 0x0F}, // 0xD5 <20>
|
||||
{0xA, 0xE0, 0x0F, 0xF0, 0x1F, 0x3B, 0x38, 0x1B, 0x30, 0x18, 0x30, 0x18, 0x30, 0x1B, 0x30, 0x3B, 0x38, 0xF0, 0x1F, 0xE0, 0x0F}, // 0xD6 <20>
|
||||
{0x8, 0x10, 0x04, 0x30, 0x06, 0x60, 0x03, 0xC0, 0x01, 0xC0, 0x01, 0x60, 0x03, 0x30, 0x06, 0x10, 0x04}, // 0xD7 <20>
|
||||
{0xA, 0xF0, 0x2F, 0xF8, 0x3F, 0x1C, 0x18, 0x0C, 0x3E, 0x8C, 0x37, 0xEC, 0x31, 0x7C, 0x30, 0x18, 0x38, 0xFC, 0x1F, 0xF4, 0x0F}, // 0xD8 <20>
|
||||
{0xA, 0xF8, 0x07, 0xF8, 0x1F, 0x01, 0x38, 0x03, 0x30, 0x06, 0x30, 0x04, 0x30, 0x00, 0x30, 0x00, 0x38, 0xF8, 0x1F, 0xF8, 0x07}, // 0xD9 <20>
|
||||
{0xA, 0xF8, 0x07, 0xF8, 0x1F, 0x00, 0x38, 0x00, 0x30, 0x04, 0x30, 0x06, 0x30, 0x03, 0x30, 0x01, 0x38, 0xF8, 0x1F, 0xF8, 0x07}, // 0xDA <20>
|
||||
{0xA, 0xF8, 0x07, 0xF8, 0x1F, 0x04, 0x38, 0x06, 0x30, 0x03, 0x30, 0x03, 0x30, 0x06, 0x30, 0x04, 0x38, 0xF8, 0x1F, 0xF8, 0x07}, // 0xDB <20>
|
||||
{0xA, 0xE0, 0x0F, 0xE0, 0x1F, 0x0C, 0x38, 0x0C, 0x30, 0x00, 0x30, 0x00, 0x30, 0x0C, 0x30, 0x0C, 0x18, 0xE0, 0x3F, 0xE0, 0x3F}, // 0xDC <20>
|
||||
{0xA, 0x08, 0x00, 0x18, 0x00, 0x30, 0x00, 0x60, 0x00, 0xC4, 0x3F, 0xC6, 0x3F, 0x63, 0x00, 0x31, 0x00, 0x18, 0x00, 0x08, 0x00}, // 0xDD <20>
|
||||
{0x8, 0x03, 0x30, 0xFF, 0x3F, 0xFF, 0x3F, 0x1B, 0x36, 0x18, 0x06, 0x18, 0x06, 0xF8, 0x07, 0xF0, 0x03}, // 0xDE <20>
|
||||
{0x8, 0xC0, 0xFF, 0xE0, 0xFF, 0x30, 0x21, 0x10, 0x21, 0x10, 0x21, 0x30, 0x33, 0xE0, 0x3F, 0xC0, 0x1E}, // 0xDF <20>
|
||||
{0xA, 0x00, 0x1C, 0x40, 0x3E, 0x60, 0x33, 0x62, 0x33, 0x66, 0x33, 0x6C, 0x33, 0x68, 0x33, 0x60, 0x33, 0xE0, 0x3F, 0xC0, 0x3F}, // 0xE0 <20>
|
||||
{0xA, 0x00, 0x1C, 0x40, 0x3E, 0x60, 0x33, 0x68, 0x33, 0x6C, 0x33, 0x66, 0x33, 0x62, 0x33, 0x60, 0x33, 0xE0, 0x3F, 0xC0, 0x3F}, // 0xE1 <20>
|
||||
{0xA, 0x00, 0x1C, 0x40, 0x3E, 0x68, 0x33, 0x6C, 0x33, 0x66, 0x33, 0x66, 0x33, 0x6C, 0x33, 0x68, 0x33, 0xE0, 0x3F, 0xC0, 0x3F}, // 0xE2 <20>
|
||||
{0xA, 0x00, 0x1C, 0x40, 0x3E, 0x68, 0x33, 0x6C, 0x33, 0x64, 0x33, 0x6C, 0x33, 0x68, 0x33, 0x6C, 0x33, 0xE4, 0x3F, 0xC0, 0x3F}, // 0xE3 <20>
|
||||
{0xA, 0x00, 0x1C, 0x40, 0x3E, 0x6C, 0x33, 0x6C, 0x33, 0x60, 0x33, 0x60, 0x33, 0x6C, 0x33, 0x6C, 0x33, 0xE0, 0x3F, 0xC0, 0x3F}, // 0xE4 <20>
|
||||
{0xA, 0x00, 0x1C, 0x40, 0x3E, 0x60, 0x33, 0x64, 0x33, 0x6A, 0x33, 0x6A, 0x33, 0x64, 0x33, 0x60, 0x33, 0xE0, 0x3F, 0xC0, 0x3F}, // 0xE5 <20>
|
||||
{0xA, 0x80, 0x1C, 0xC0, 0x3E, 0x40, 0x22, 0x40, 0x22, 0xC0, 0x1F, 0x80, 0x3F, 0x40, 0x22, 0x40, 0x22, 0xC0, 0x33, 0x80, 0x11}, // 0xE6 <20>
|
||||
{0xA, 0x80, 0x0F, 0xC0, 0x1F, 0xE0, 0xB8, 0x60, 0xB0, 0x60, 0xF0, 0x60, 0xF0, 0x60, 0x30, 0xE0, 0x38, 0xC0, 0x18, 0x80, 0x08}, // 0xE7 <20>
|
||||
{0xA, 0x80, 0x0F, 0xC0, 0x1F, 0xE0, 0x33, 0x62, 0x33, 0x66, 0x33, 0x6C, 0x33, 0x68, 0x33, 0x60, 0x33, 0xC0, 0x13, 0x80, 0x03}, // 0xE8 <20>
|
||||
{0xA, 0x80, 0x0F, 0xC0, 0x1F, 0xE0, 0x3B, 0x60, 0x33, 0x68, 0x33, 0x6C, 0x33, 0x66, 0x33, 0x62, 0x33, 0xC0, 0x13, 0x80, 0x03}, // 0xE9 <20>
|
||||
{0xA, 0x80, 0x0F, 0xC0, 0x1F, 0xE8, 0x33, 0x6C, 0x33, 0x66, 0x33, 0x66, 0x33, 0x6C, 0x33, 0x68, 0x33, 0xC0, 0x13, 0x80, 0x03}, // 0xEA <20>
|
||||
{0xA, 0x80, 0x0F, 0xC0, 0x1F, 0xEC, 0x33, 0x6C, 0x33, 0x60, 0x33, 0x60, 0x33, 0x6C, 0x33, 0x6C, 0x33, 0xC0, 0x13, 0x80, 0x03}, // 0xEB <20>
|
||||
{0x6, 0x00, 0x30, 0x62, 0x30, 0xE6, 0x3F, 0xEC, 0x3F, 0x08, 0x30, 0x00, 0x30}, // 0xEC <20>
|
||||
{0x6, 0x00, 0x30, 0x68, 0x30, 0xEC, 0x3F, 0xE6, 0x3F, 0x02, 0x30, 0x00, 0x30}, // 0xED <20>
|
||||
{0x6, 0x08, 0x30, 0x6C, 0x30, 0xE6, 0x3F, 0xE6, 0x3F, 0x0C, 0x30, 0x08, 0x30}, // 0xEE <20>
|
||||
{0x6, 0x0C, 0x30, 0x6C, 0x30, 0xE0, 0x3F, 0xEC, 0x3F, 0x0C, 0x30, 0x00, 0x30}, // 0xEF <20>
|
||||
{0x6, 0x78, 0x1C, 0xFC, 0x3E, 0xCC, 0x33, 0x8C, 0x33, 0x0C, 0x3F, 0x18, 0x1E}, // 0xF0 <20>
|
||||
{0x9, 0xE0, 0x3F, 0xE8, 0x3F, 0x6C, 0x00, 0x64, 0x00, 0x6C, 0x00, 0x68, 0x00, 0xEC, 0x00, 0xC4, 0x3F, 0x80, 0x3F}, // 0xF1 <20>
|
||||
{0xA, 0x80, 0x0F, 0xC0, 0x1F, 0xE0, 0x38, 0x62, 0x30, 0x66, 0x30, 0x6C, 0x30, 0x68, 0x30, 0xE0, 0x38, 0xC0, 0x1F, 0x80, 0x0F}, // 0xF2 <20>
|
||||
{0xA, 0x80, 0x0F, 0xC0, 0x1F, 0xE0, 0x38, 0x68, 0x30, 0x6C, 0x30, 0x66, 0x30, 0x62, 0x30, 0xE0, 0x38, 0xC0, 0x1F, 0x80, 0x0F}, // 0xF3 <20>
|
||||
{0xA, 0x80, 0x0F, 0xC0, 0x1F, 0xE8, 0x38, 0x6C, 0x30, 0x66, 0x30, 0x66, 0x30, 0x6C, 0x30, 0xE8, 0x38, 0xC0, 0x1F, 0x80, 0x0F}, // 0xF4 <20>
|
||||
{0xA, 0x80, 0x0F, 0xC8, 0x1F, 0xEC, 0x38, 0x64, 0x30, 0x6C, 0x30, 0x68, 0x30, 0x6C, 0x30, 0xE4, 0x38, 0xC0, 0x1F, 0x80, 0x0F}, // 0xF5 <20>
|
||||
{0xA, 0x80, 0x0F, 0xC0, 0x1F, 0xEC, 0x38, 0x6C, 0x30, 0x60, 0x30, 0x60, 0x30, 0x6C, 0x30, 0xEC, 0x38, 0xC0, 0x1F, 0x80, 0x0F}, // 0xF6 <20>
|
||||
{0x8, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0xB0, 0x0D, 0xB0, 0x0D, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01}, // 0xF7 <20>
|
||||
{0xA, 0x80, 0x2F, 0xC0, 0x3F, 0xE0, 0x18, 0x60, 0x3C, 0x60, 0x36, 0x60, 0x33, 0xE0, 0x31, 0xC0, 0x38, 0xE0, 0x1F, 0xA0, 0x0F}, // 0xF8 <20>
|
||||
{0xA, 0xE0, 0x0F, 0xE0, 0x1F, 0x00, 0x38, 0x02, 0x30, 0x06, 0x30, 0x0C, 0x30, 0x08, 0x30, 0x00, 0x18, 0xE0, 0x3F, 0xE0, 0x3F}, // 0xF9 <20>
|
||||
{0xA, 0xE0, 0x0F, 0xE0, 0x1F, 0x00, 0x38, 0x08, 0x30, 0x0C, 0x30, 0x06, 0x30, 0x02, 0x30, 0x00, 0x18, 0xE0, 0x3F, 0xE0, 0x3F}, // 0xFA <20>
|
||||
{0xA, 0xE0, 0x0F, 0xE0, 0x1F, 0x08, 0x38, 0x0C, 0x30, 0x06, 0x30, 0x06, 0x30, 0x0C, 0x30, 0x08, 0x18, 0xE0, 0x3F, 0xE0, 0x3F}, // 0xFB <20>
|
||||
{0xA, 0xE0, 0x0F, 0xE0, 0x1F, 0x0C, 0x38, 0x0C, 0x30, 0x00, 0x30, 0x00, 0x30, 0x0C, 0x30, 0x0C, 0x18, 0xE0, 0x3F, 0xE0, 0x3F}, // 0xFC <20>
|
||||
{0x8, 0x60, 0x00, 0xE0, 0x81, 0x80, 0xE7, 0x10, 0x7E, 0x18, 0x1E, 0x8C, 0x07, 0xE4, 0x01, 0x60, 0x00}, // 0xFD <20>
|
||||
{0x8, 0x0C, 0x30, 0xFC, 0x3F, 0xFC, 0x3F, 0x6C, 0x36, 0x60, 0x06, 0x60, 0x06, 0xE0, 0x07, 0xC0, 0x03}, // 0xFE <20>
|
||||
{0x8, 0x60, 0x00, 0xEC, 0x81, 0x8C, 0xE7, 0x00, 0x7E, 0x00, 0x1E, 0x8C, 0x07, 0xEC, 0x01, 0x60, 0x00}, // 0xFF <20>
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,690 +0,0 @@
|
||||
/*
|
||||
; Project: Smart EVSE
|
||||
;
|
||||
;
|
||||
;
|
||||
; 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.
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "ModbusServerRTU.h"
|
||||
#include "ModbusClientRTU.h"
|
||||
#include "driver/uart.h"
|
||||
|
||||
#include "evse.h"
|
||||
#include "modbus.h"
|
||||
#include "utils.h"
|
||||
|
||||
extern struct ModBus MB;
|
||||
|
||||
// ########################## Modbus helper functions ##########################
|
||||
|
||||
/**
|
||||
* Send single value over modbus
|
||||
*
|
||||
* @param uint8_t address
|
||||
* @param uint8_t function
|
||||
* @param uint16_t register
|
||||
* @param uint16_t data
|
||||
*/
|
||||
void ModbusSend8(uint8_t address, uint8_t function, uint16_t reg, uint16_t data) {
|
||||
// 0x12345678 is a token to keep track of modbus requests/responses.
|
||||
// token: first byte address, second byte function, third and fourth reg
|
||||
uint32_t token;
|
||||
token = reg;
|
||||
token += address << 24;
|
||||
token += function << 16;
|
||||
Error err = MBclient.addRequest(token, address, function, reg, data);
|
||||
if (err!=SUCCESS) {
|
||||
ModbusError e(err);
|
||||
_LOG_A("Error creating request: 0x%02x - %s\n", (int)e, (const char *)e);
|
||||
}
|
||||
else {
|
||||
_LOG_V("Sent packet");
|
||||
}
|
||||
_LOG_V_NO_FUNC(" address: 0x%02x, function: 0x%02x, reg: 0x%04x, token:0x%08x, data: 0x%04x.\n", address, function, reg, token, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Combine Bytes received over modbus
|
||||
*
|
||||
* @param pointer to var
|
||||
* @param pointer to buf
|
||||
* @param uint8_t pos
|
||||
* @param uint8_t endianness:\n
|
||||
* 0: low byte first, low word first (little endian)\n
|
||||
* 1: low byte first, high word first\n
|
||||
* 2: high byte first, low word first\n
|
||||
* 3: high byte first, high word first (big endian)
|
||||
* @param MBDataType dataType: used to determine how many bytes should be combined
|
||||
*/
|
||||
void combineBytes(void *var, uint8_t *buf, uint8_t pos, uint8_t endianness, MBDataType dataType) {
|
||||
char *pBytes;
|
||||
pBytes = (char *)var;
|
||||
|
||||
// ESP32 is little endian
|
||||
switch(endianness) {
|
||||
case ENDIANESS_LBF_LWF: // low byte first, low word first (little endian)
|
||||
*pBytes++ = (uint8_t)buf[pos + 0];
|
||||
*pBytes++ = (uint8_t)buf[pos + 1];
|
||||
if (dataType != MB_DATATYPE_INT16) {
|
||||
*pBytes++ = (uint8_t)buf[pos + 2];
|
||||
*pBytes = (uint8_t)buf[pos + 3];
|
||||
}
|
||||
break;
|
||||
case ENDIANESS_LBF_HWF: // low byte first, high word first
|
||||
if (dataType != MB_DATATYPE_INT16) {
|
||||
*pBytes++ = (uint8_t)buf[pos + 2];
|
||||
*pBytes++ = (uint8_t)buf[pos + 3];
|
||||
}
|
||||
*pBytes++ = (uint8_t)buf[pos + 0];
|
||||
*pBytes = (uint8_t)buf[pos + 1];
|
||||
break;
|
||||
case ENDIANESS_HBF_LWF: // high byte first, low word first
|
||||
*pBytes++ = (uint8_t)buf[pos + 1];
|
||||
*pBytes++ = (uint8_t)buf[pos + 0];
|
||||
if (dataType != MB_DATATYPE_INT16) {
|
||||
*pBytes++ = (uint8_t)buf[pos + 3];
|
||||
*pBytes = (uint8_t)buf[pos + 2];
|
||||
}
|
||||
break;
|
||||
case ENDIANESS_HBF_HWF: // high byte first, high word first (big endian)
|
||||
if (dataType != MB_DATATYPE_INT16) {
|
||||
*pBytes++ = (uint8_t)buf[pos + 3];
|
||||
*pBytes++ = (uint8_t)buf[pos + 2];
|
||||
}
|
||||
*pBytes++ = (uint8_t)buf[pos + 1];
|
||||
*pBytes = (uint8_t)buf[pos + 0];
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ########################### Modbus main functions ###########################
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Request read holding (FC=3) or read input register (FC=04) to a device over modbus
|
||||
*
|
||||
* @param uint8_t address
|
||||
* @param uint8_t function
|
||||
* @param uint16_t register
|
||||
* @param uint16_t quantity
|
||||
*/
|
||||
void ModbusReadInputRequest(uint8_t address, uint8_t function, uint16_t reg, uint16_t quantity) {
|
||||
MB.RequestAddress = address;
|
||||
MB.RequestFunction = function;
|
||||
MB.RequestRegister = reg;
|
||||
ModbusSend8(address, function, reg, quantity);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Response read holding (FC=3) or read input register (FC=04) to a device over modbus
|
||||
*
|
||||
* @param uint8_t address
|
||||
* @param uint8_t function
|
||||
* @param uint16_t pointer to values
|
||||
* @param uint8_t count of values
|
||||
*/
|
||||
void ModbusReadInputResponse(uint8_t address, uint8_t function, uint16_t *values, uint8_t count) {
|
||||
_LOG_A("ModbusReadInputResponse, to do!\n");
|
||||
//ModbusSend(address, function, count * 2u, values, count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Request write single register (FC=06) to a device over modbus
|
||||
*
|
||||
* @param uint8_t address
|
||||
* @param uint16_t register
|
||||
* @param uint16_t value
|
||||
*/
|
||||
void ModbusWriteSingleRequest(uint8_t address, uint16_t reg, uint16_t value) {
|
||||
MB.RequestAddress = address;
|
||||
MB.RequestFunction = 0x06;
|
||||
MB.RequestRegister = reg;
|
||||
ModbusSend8(address, 0x06, reg, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Request write multiple register (FC=16) to a device over modbus
|
||||
*
|
||||
* @param uint8_t address
|
||||
* @param uint16_t register
|
||||
* @param uint8_t pointer to data
|
||||
* @param uint8_t count of data
|
||||
*/
|
||||
void ModbusWriteMultipleRequest(uint8_t address, uint16_t reg, uint16_t *values, uint8_t count) {
|
||||
|
||||
MB.RequestAddress = address;
|
||||
MB.RequestFunction = 0x10;
|
||||
MB.RequestRegister = reg;
|
||||
// 0x12345678 is a token to keep track of modbus requests/responses.
|
||||
// token: first byte address, second byte function, third and fourth reg
|
||||
uint32_t token;
|
||||
token = reg;
|
||||
token += address << 24;
|
||||
token += 0x10 << 16;
|
||||
Error err = MBclient.addRequest(token, address, 0x10, reg, (uint16_t) count, count * 2u, values);
|
||||
if (err!=SUCCESS) {
|
||||
ModbusError e(err);
|
||||
_LOG_A("Error creating request: 0x%02x - %s\n", (int)e, (const char *)e);
|
||||
}
|
||||
_LOG_V("Sent packet address: 0x%02x, function: 0x10, reg: 0x%04x, token: 0x%08x count: %u, values:", address, reg, token, count);
|
||||
for (uint16_t i = 0; i < count; i++) {
|
||||
_LOG_V_NO_FUNC(" %04x", values[i]);
|
||||
}
|
||||
_LOG_V_NO_FUNC("\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* Response an exception
|
||||
*
|
||||
* @param uint8_t address
|
||||
* @param uint8_t function
|
||||
* @param uint8_t exeption
|
||||
*/
|
||||
void ModbusException(uint8_t address, uint8_t function, uint8_t exception) {
|
||||
//uint16_t temp[1];
|
||||
_LOG_A("ModbusException, to do!\n");
|
||||
//ModbusSend(address, function, exception, temp, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode received modbus packet
|
||||
*
|
||||
* @param uint8_t pointer to buffer
|
||||
* @param uint8_t length of buffer
|
||||
*/
|
||||
void ModbusDecode(uint8_t * buf, uint8_t len) {
|
||||
// Clear old values
|
||||
MB.Address = 0;
|
||||
MB.Function = 0;
|
||||
MB.Register = 0;
|
||||
MB.RegisterCount = 0;
|
||||
MB.Value = 0;
|
||||
MB.DataLength = 0;
|
||||
MB.Type = MODBUS_INVALID;
|
||||
MB.Exception = 0;
|
||||
|
||||
_LOG_V("Received packet (%i bytes)", len);
|
||||
for (uint8_t x=0; x<len; x++) {
|
||||
_LOG_V_NO_FUNC(" %02x", buf[x]);
|
||||
}
|
||||
_LOG_V_NO_FUNC("\n");
|
||||
|
||||
// Modbus error packets length is 5 bytes
|
||||
if (len == 3) {
|
||||
MB.Type = MODBUS_EXCEPTION;
|
||||
// Modbus device address
|
||||
MB.Address = buf[0];
|
||||
// Modbus function
|
||||
MB.Function = buf[1];
|
||||
// Modbus Exception code
|
||||
MB.Exception = buf[2];
|
||||
_LOG_A("Modbus Exception 0x%02x, Address=0x%02x, Function=0x%02x.\n", MB.Exception, MB.Address, MB.Function);
|
||||
// Modbus data packets minimum length is 8 bytes
|
||||
} else if (len >= 6) {
|
||||
// Modbus device address
|
||||
MB.Address = buf[0];
|
||||
// Modbus function
|
||||
MB.Function = buf[1];
|
||||
|
||||
_LOG_V(" valid Modbus packet: Address 0x%02x Function 0x%02x", MB.Address, MB.Function);
|
||||
switch (MB.Function) {
|
||||
case 0x03: // (Read holding register)
|
||||
case 0x04: // (Read input register)
|
||||
if (len == 6) {
|
||||
// request packet
|
||||
MB.Type = MODBUS_REQUEST;
|
||||
// Modbus register
|
||||
MB.Register = (uint16_t)(buf[2] <<8) | buf[3];
|
||||
// Modbus register count
|
||||
MB.RegisterCount = (uint16_t)(buf[4] <<8) | buf[5];
|
||||
} else {
|
||||
// Modbus datacount
|
||||
MB.DataLength = buf[2];
|
||||
if (MB.DataLength == len - 3) {
|
||||
// packet length OK
|
||||
// response packet
|
||||
MB.Type = MODBUS_RESPONSE;
|
||||
} else {
|
||||
_LOG_W("Invalid modbus FC=04 packet\n");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x06:
|
||||
// (Write single register)
|
||||
if (len == 6) {
|
||||
// request and response packet are the same
|
||||
MB.Type = MODBUS_OK;
|
||||
// Modbus register
|
||||
MB.Register = (uint16_t)(buf[2] <<8) | buf[3];
|
||||
// Modbus register count
|
||||
MB.RegisterCount = 1;
|
||||
// value
|
||||
MB.Value = (uint16_t)(buf[4] <<8) | buf[5];
|
||||
} else {
|
||||
_LOG_W("Invalid modbus FC=06 packet\n");
|
||||
}
|
||||
break;
|
||||
case 0x10:
|
||||
// (Write multiple register))
|
||||
// Modbus register
|
||||
MB.Register = (uint16_t)(buf[2] <<8) | buf[3];
|
||||
// Modbus register count
|
||||
MB.RegisterCount = (uint16_t)(buf[4] <<8) | buf[5];
|
||||
if (len == 6) {
|
||||
// response packet
|
||||
MB.Type = MODBUS_RESPONSE;
|
||||
} else {
|
||||
// Modbus datacount
|
||||
MB.DataLength = buf[6];
|
||||
if (MB.DataLength == len - 7) {
|
||||
// packet length OK
|
||||
// request packet
|
||||
MB.Type = MODBUS_REQUEST;
|
||||
} else {
|
||||
_LOG_W("Invalid modbus FC=16 packet\n");
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// MB.Data
|
||||
if (MB.Type && MB.DataLength) {
|
||||
// Set pointer to Data
|
||||
MB.Data = buf;
|
||||
// Modbus data is always at the end ahead the checksum
|
||||
MB.Data = MB.Data + (len - MB.DataLength);
|
||||
}
|
||||
|
||||
// Request - Response check
|
||||
switch (MB.Type) {
|
||||
case MODBUS_REQUEST:
|
||||
MB.RequestAddress = MB.Address;
|
||||
MB.RequestFunction = MB.Function;
|
||||
MB.RequestRegister = MB.Register;
|
||||
break;
|
||||
case MODBUS_RESPONSE:
|
||||
// If address and function identical with last send or received request, it is a valid response
|
||||
if (MB.Address == MB.RequestAddress && MB.Function == MB.RequestFunction) {
|
||||
if (MB.Function == 0x03 || MB.Function == 0x04)
|
||||
MB.Register = MB.RequestRegister;
|
||||
}
|
||||
MB.RequestAddress = 0;
|
||||
MB.RequestFunction = 0;
|
||||
MB.RequestRegister = 0;
|
||||
break;
|
||||
case MODBUS_OK:
|
||||
// If address and function identical with last send or received request, it is a valid response
|
||||
if (MB.Address == MB.RequestAddress && MB.Function == MB.RequestFunction && MB.Address != BROADCAST_ADR) {
|
||||
MB.Type = MODBUS_RESPONSE;
|
||||
MB.RequestAddress = 0;
|
||||
MB.RequestFunction = 0;
|
||||
MB.RequestRegister = 0;
|
||||
} else {
|
||||
MB.Type = MODBUS_REQUEST;
|
||||
MB.RequestAddress = MB.Address;
|
||||
MB.RequestFunction = MB.Function;
|
||||
MB.RequestRegister = MB.Register;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(MB.Type) {
|
||||
_LOG_V_NO_FUNC(" Register 0x%04x", MB.Register);
|
||||
}
|
||||
switch (MB.Type) {
|
||||
case MODBUS_REQUEST:
|
||||
_LOG_V_NO_FUNC(" Request\n");
|
||||
break;
|
||||
case MODBUS_RESPONSE:
|
||||
_LOG_V_NO_FUNC(" Response\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ########################### EVSE modbus functions ###########################
|
||||
|
||||
|
||||
/**
|
||||
* Send measurement request over modbus
|
||||
*
|
||||
* @param uint8_t Meter
|
||||
* @param uint8_t Address
|
||||
* @param uint16_t Register
|
||||
* @param uint8_t Count
|
||||
*/
|
||||
void requestMeasurement(uint8_t Meter, uint8_t Address, uint16_t Register, uint8_t Count) {
|
||||
ModbusReadInputRequest(Address, EMConfig[Meter].Function, Register, (EMConfig[Meter].DataType == MB_DATATYPE_INT16 ? Count : (Count * 2u)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode measurement value
|
||||
*
|
||||
* @param pointer to buf
|
||||
* @param uint8_t Count
|
||||
* @param uint8_t Endianness
|
||||
* @param MBDataType dataType
|
||||
* @param signed char Divisor
|
||||
* @return signed int Measurement
|
||||
*/
|
||||
signed int receiveMeasurement(uint8_t *buf, uint8_t Count, uint8_t Endianness, MBDataType dataType, signed char Divisor) {
|
||||
float dCombined;
|
||||
signed int lCombined;
|
||||
|
||||
if (dataType == MB_DATATYPE_FLOAT32) {
|
||||
combineBytes(&dCombined, buf, Count * (dataType == MB_DATATYPE_INT16 ? 2u : 4u), Endianness, dataType);
|
||||
if (Divisor >= 0) {
|
||||
lCombined = (signed int)(dCombined / (signed int)pow_10[(unsigned)Divisor]);
|
||||
} else {
|
||||
lCombined = (signed int)(dCombined * (signed int)pow_10[(unsigned)-Divisor]);
|
||||
}
|
||||
} else {
|
||||
combineBytes(&lCombined, buf, Count * (dataType == MB_DATATYPE_INT16 ? 2u : 4u), Endianness, dataType);
|
||||
if (dataType == MB_DATATYPE_INT16) {
|
||||
lCombined = (signed int)((int16_t)lCombined); /* sign extend 16bit into 32bit */
|
||||
}
|
||||
if (Divisor >= 0) {
|
||||
lCombined = lCombined / (signed int)pow_10[(unsigned)Divisor];
|
||||
} else {
|
||||
lCombined = lCombined * (signed int)pow_10[(unsigned)-Divisor];
|
||||
}
|
||||
}
|
||||
|
||||
return lCombined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send current measurement request over modbus
|
||||
*
|
||||
* @param uint8_t Meter
|
||||
* @param uint8_t Address
|
||||
*/
|
||||
void requestCurrentMeasurement(uint8_t Meter, uint8_t Address) {
|
||||
switch(Meter) {
|
||||
case EM_API:
|
||||
break;
|
||||
case EM_SENSORBOX:
|
||||
ModbusReadInputRequest(Address, 4, 0, 20);
|
||||
break;
|
||||
case EM_EASTRON1P:
|
||||
case EM_EASTRON3P:
|
||||
case EM_EASTRON3P_INV:
|
||||
// Phase 1-3 current: Register 0x06 - 0x0B (unsigned)
|
||||
// Phase 1-3 power: Register 0x0C - 0x11 (signed)
|
||||
ModbusReadInputRequest(Address, 4, 0x06, 12);
|
||||
break;
|
||||
case EM_ABB:
|
||||
// Phase 1-3 current: Register 0x5B0C - 0x5B11 (unsigned)
|
||||
// Phase 1-3 power: Register 0x5B16 - 0x5B1B (signed)
|
||||
ModbusReadInputRequest(Address, 3, 0x5B0C, 16);
|
||||
break;
|
||||
case EM_SOLAREDGE:
|
||||
// Read 3 Current values + scaling factor
|
||||
ModbusReadInputRequest(Address, EMConfig[Meter].Function, EMConfig[Meter].IRegister, 4);
|
||||
break;
|
||||
case EM_FINDER_7M:
|
||||
// Phase 1-3 current: Register 2516 - 2521 (unsigned)
|
||||
// Phase 1-3 power: Register 2530 - 2535 (signed)
|
||||
ModbusReadInputRequest(Address, 4, 2516, 20);
|
||||
break;
|
||||
default:
|
||||
// Read 3 Current values
|
||||
requestMeasurement(Meter, Address, EMConfig[Meter].IRegister, 3);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read current measurement from modbus
|
||||
*
|
||||
* @param pointer to buf
|
||||
* @param uint8_t Meter
|
||||
* @param pointer to Current (mA)
|
||||
* @return uint8_t error
|
||||
*/
|
||||
uint8_t receiveCurrentMeasurement(uint8_t *buf, uint8_t Meter, signed int *var) {
|
||||
uint8_t x, offset;
|
||||
|
||||
// No CAL option in Menu
|
||||
CalActive = 0;
|
||||
|
||||
switch(Meter) {
|
||||
case EM_API:
|
||||
break;
|
||||
case EM_SENSORBOX:
|
||||
// return immediately if the data contains no new P1 or CT measurement
|
||||
if (buf[3] == 0) return 0; // error!!
|
||||
// determine if there is P1 data present, otherwise use CT data
|
||||
if (buf[3] & 0x80) offset = 4; // P1 data present
|
||||
else offset = 7; // Use CTs
|
||||
// offset 16 is Smart meter P1 current
|
||||
for (x = 0; x < 3; x++) {
|
||||
// SmartEVSE works with Amps * 10
|
||||
var[x] = receiveMeasurement(buf, offset + x, EMConfig[Meter].Endianness, EMConfig[Meter].DataType, EMConfig[Meter].IDivisor - 3u);
|
||||
// When using CT's , adjust the measurements with calibration value
|
||||
if (offset == 7) {
|
||||
if (x == 0) Iuncal = abs((var[x] / 10)); // Store uncalibrated CT1 measurement (10mA)
|
||||
var[x] = var[x] * (signed int)ICal / ICAL;
|
||||
// When MaxMains is set to >100A, it's assumed 200A:50ma CT's are used.
|
||||
if (getItemValue(MENU_MAINS) > 100) var[x] = var[x] * 2; // Multiply measured currents with 2
|
||||
// very small negative currents are shown as zero.
|
||||
if ((var[x] > -1) && (var[x] < 1)) var[x] = 0;
|
||||
CalActive = 1; // Enable CAL option in Menu
|
||||
}
|
||||
}
|
||||
// Set Sensorbox 2 to 3/4 Wire configuration (and phase Rotation) (v2.16)
|
||||
if (buf[1] >= 0x10 && offset == 7) {
|
||||
GridActive = 1; // Enable the GRID menu option
|
||||
if ((buf[1] & 0x3) != (Grid << 1) && (LoadBl < 2)) ModbusWriteSingleRequest(0x0A, 0x800, Grid << 1);
|
||||
} else GridActive = 0;
|
||||
break;
|
||||
case EM_SOLAREDGE:
|
||||
{
|
||||
// Need to handle the extra scaling factor
|
||||
int scalingFactor = -(int)receiveMeasurement(
|
||||
buf,
|
||||
3,
|
||||
EMConfig[Meter].Endianness,
|
||||
EMConfig[Meter].DataType,
|
||||
0
|
||||
);
|
||||
// Now decode the three Current values using that scaling factor
|
||||
for (x = 0; x < 3; x++) {
|
||||
var[x] = receiveMeasurement(
|
||||
buf,
|
||||
x,
|
||||
EMConfig[Meter].Endianness,
|
||||
EMConfig[Meter].DataType,
|
||||
scalingFactor - 3
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
for (x = 0; x < 3; x++) {
|
||||
var[x] = receiveMeasurement(
|
||||
buf,
|
||||
x,
|
||||
EMConfig[Meter].Endianness,
|
||||
EMConfig[Meter].DataType,
|
||||
EMConfig[Meter].IDivisor - 3
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Get sign from power measurement on some electric meters
|
||||
switch(Meter) {
|
||||
case EM_EASTRON1P: // for some reason the EASTRON1P also needs to loop through the 3 var[x]
|
||||
// if you only loop through x=0, the minus sign of the current is incorrect
|
||||
// when exporting current
|
||||
case EM_EASTRON3P:
|
||||
for (x = 0; x < 3; x++) {
|
||||
if (receiveMeasurement(buf, x + 3u, EMConfig[Meter].Endianness, EMConfig[Meter].DataType, EMConfig[Meter].PDivisor) < 0) var[x] = -var[x];
|
||||
}
|
||||
break;
|
||||
case EM_EASTRON3P_INV:
|
||||
for (x = 0; x < 3; x++) {
|
||||
if (receiveMeasurement(buf, x + 3u, EMConfig[Meter].Endianness, EMConfig[Meter].DataType, EMConfig[Meter].PDivisor) > 0) var[x] = -var[x];
|
||||
}
|
||||
break;
|
||||
case EM_ABB:
|
||||
for (x = 0; x < 3; x++) {
|
||||
if (receiveMeasurement(buf, x + 5u, EMConfig[Meter].Endianness, EMConfig[Meter].DataType, EMConfig[Meter].PDivisor) < 0) var[x] = -var[x];
|
||||
}
|
||||
break;
|
||||
case EM_FINDER_7M:
|
||||
for (x = 0; x < 3; x++) {
|
||||
if (receiveMeasurement(buf, x + 7u, EMConfig[Meter].Endianness, EMConfig[Meter].DataType, EMConfig[Meter].PDivisor) < 0) var[x] = -var[x];
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// all OK
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Map a Modbus register to an item ID (MENU_xxx or STATUS_xxx)
|
||||
*
|
||||
* @return uint8_t ItemID
|
||||
*/
|
||||
uint8_t mapModbusRegister2ItemID() {
|
||||
uint16_t RegisterStart, ItemStart, Count;
|
||||
|
||||
// Register 0x00*: Status
|
||||
if (MB.Register < (MODBUS_EVSE_STATUS_START + MODBUS_EVSE_STATUS_COUNT)) {
|
||||
RegisterStart = MODBUS_EVSE_STATUS_START;
|
||||
ItemStart = STATUS_STATE;
|
||||
Count = MODBUS_EVSE_STATUS_COUNT;
|
||||
|
||||
// Register 0x01*: Node specific configuration
|
||||
} else if (MB.Register >= MODBUS_EVSE_CONFIG_START && MB.Register < (MODBUS_EVSE_CONFIG_START + MODBUS_EVSE_CONFIG_COUNT)) {
|
||||
RegisterStart = MODBUS_EVSE_CONFIG_START;
|
||||
ItemStart = MENU_CONFIG;
|
||||
Count = MODBUS_EVSE_CONFIG_COUNT;
|
||||
|
||||
// Register 0x02*: System configuration (same on all SmartEVSE in a LoadBalancing setup)
|
||||
} else if (MB.Register >= MODBUS_SYS_CONFIG_START && MB.Register < (MODBUS_SYS_CONFIG_START + MODBUS_SYS_CONFIG_COUNT)) {
|
||||
RegisterStart = MODBUS_SYS_CONFIG_START;
|
||||
ItemStart = MENU_MODE;
|
||||
Count = MODBUS_SYS_CONFIG_COUNT;
|
||||
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (MB.RegisterCount <= (RegisterStart + Count) - MB.Register) {
|
||||
return (MB.Register - RegisterStart + ItemStart);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read item values and send modbus response
|
||||
*/
|
||||
/*
|
||||
void ReadItemValueResponse(void) {
|
||||
uint8_t ItemID;
|
||||
uint8_t i;
|
||||
uint16_t values[MODBUS_MAX_REGISTER_READ];
|
||||
|
||||
ItemID = mapModbusRegister2ItemID();
|
||||
if (ItemID) {
|
||||
for (i = 0; i < MB.RegisterCount; i++) {
|
||||
values[i] = getItemValue(ItemID + i);
|
||||
}
|
||||
ModbusReadInputResponse(MB.Address, MB.Function, values, MB.RegisterCount);
|
||||
} else {
|
||||
ModbusException(MB.Address, MB.Function, MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Write item values and send modbus response
|
||||
*/
|
||||
/*
|
||||
void WriteItemValueResponse(void) {
|
||||
uint8_t ItemID;
|
||||
uint8_t OK = 0;
|
||||
|
||||
ItemID = mapModbusRegister2ItemID();
|
||||
if (ItemID) {
|
||||
OK = setItemValue(ItemID, MB.Value);
|
||||
}
|
||||
|
||||
if (OK && ItemID < STATUS_STATE) write_settings();
|
||||
|
||||
if (MB.Address != BROADCAST_ADR || LoadBl == 0) {
|
||||
if (!ItemID) {
|
||||
ModbusException(MB.Address, MB.Function, MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS);
|
||||
} else if (!OK) {
|
||||
ModbusException(MB.Address, MB.Function, MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE);
|
||||
} else {
|
||||
ModbusWriteSingleResponse(MB.Address, MB.Register, MB.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Write multiple item values and send modbus response
|
||||
*/
|
||||
/*
|
||||
void WriteMultipleItemValueResponse(void) {
|
||||
uint8_t ItemID;
|
||||
uint16_t i, OK = 0, value;
|
||||
|
||||
ItemID = mapModbusRegister2ItemID();
|
||||
if (ItemID) {
|
||||
for (i = 0; i < MB.RegisterCount; i++) {
|
||||
value = (MB.Data[i * 2] <<8) | MB.Data[(i * 2) + 1];
|
||||
OK += setItemValue(ItemID + i, value);
|
||||
}
|
||||
}
|
||||
|
||||
if (OK && ItemID < STATUS_STATE) write_settings();
|
||||
|
||||
if (MB.Address != BROADCAST_ADR || LoadBl == 0) {
|
||||
if (!ItemID) {
|
||||
ModbusException(MB.Address, MB.Function, MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS);
|
||||
} else if (!OK) {
|
||||
ModbusException(MB.Address, MB.Function, MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE);
|
||||
} else {
|
||||
ModbusWriteMultipleResponse(MB.Address, MB.Register, OK);
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
@@ -1,150 +0,0 @@
|
||||
/*
|
||||
; Project: Smart EVSE
|
||||
;
|
||||
;
|
||||
;
|
||||
; 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.
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "evse.h"
|
||||
#include "utils.h"
|
||||
|
||||
unsigned long pow_10[10] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000};
|
||||
|
||||
|
||||
// read Mac, and reverse to ID
|
||||
uint32_t MacId() {
|
||||
|
||||
uint32_t id = 0;
|
||||
|
||||
for (int i=0; i<17; i=i+8) {
|
||||
id |= ((ESP.getEfuseMac() >> (40 - i)) & 0xff) << i;
|
||||
}
|
||||
return id >> 2; // low two bits are unused.
|
||||
}
|
||||
|
||||
|
||||
unsigned char crc8(unsigned char *buf, unsigned char len) {
|
||||
unsigned char crc = 0, i, mix, inbyte;
|
||||
|
||||
while (len--) {
|
||||
inbyte = *buf++;
|
||||
for (i = 8; i; i--) {
|
||||
mix = (crc ^ inbyte) & 0x01;
|
||||
crc >>= 1;
|
||||
if (mix) crc ^= 0x8C;
|
||||
inbyte >>= 1;
|
||||
}
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates 16-bit CRC of given data
|
||||
* used for Frame Check Sequence on data frame
|
||||
*
|
||||
* @param unsigned char pointer to buffer
|
||||
* @param unsigned char length of buffer
|
||||
* @return unsigned int CRC
|
||||
*/
|
||||
/*
|
||||
unsigned int crc16(unsigned char *buf, unsigned char len) {
|
||||
unsigned int pos, crc = 0xffff;
|
||||
unsigned char i;
|
||||
|
||||
// Poly used is x^16+x^15+x^2+x
|
||||
for (pos = 0; pos < len; pos++) {
|
||||
crc ^= (unsigned int)buf[pos]; // XOR byte into least sig. byte of crc
|
||||
|
||||
for (i = 8; i != 0; i--) { // Loop over each bit
|
||||
if ((crc & 0x0001) != 0) { // If the LSB is set
|
||||
crc >>= 1; // Shift right and XOR 0xA001
|
||||
crc ^= 0xA001;
|
||||
} else // Else LSB is not set
|
||||
crc >>= 1; // Just shift right
|
||||
}
|
||||
}
|
||||
|
||||
return crc;
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Insert rounded value into string in printf style
|
||||
*
|
||||
* @param pointer to string
|
||||
* @param string Format
|
||||
* @param signed long Value to round and insert
|
||||
* @param unsinged char Divisor where to set decimal point
|
||||
* @param unsigned char Decimal place count
|
||||
*/
|
||||
void sprintfl(char *str, const char *Format, signed long Value, unsigned char Divisor, unsigned char Decimal) {
|
||||
signed long val;
|
||||
|
||||
val = Value / (signed long) pow_10[Divisor - Decimal - 1];
|
||||
// Round value
|
||||
if(val < 0) val -= 5;
|
||||
else val += 5;
|
||||
val /= 10;
|
||||
// Split value
|
||||
if(Decimal > 0) sprintf(str, Format, (signed int) (val / (signed long) pow_10[Decimal]), (unsigned int) (abs(val) % pow_10[Decimal]));
|
||||
else sprintf(str, Format, (signed int) val);
|
||||
}
|
||||
|
||||
/* triwave8: triangle (sawtooth) wave generator. Useful for
|
||||
turning a one-byte ever-increasing value into a
|
||||
one-byte value that oscillates up and down.
|
||||
|
||||
input output
|
||||
0..127 0..254 (positive slope)
|
||||
128..255 254..0 (negative slope)
|
||||
*/
|
||||
unsigned char triwave8(unsigned char in) {
|
||||
if (in & 0x80) {
|
||||
in = 255u - in;
|
||||
}
|
||||
unsigned char out = in << 1;
|
||||
return out;
|
||||
}
|
||||
|
||||
unsigned char scale8(unsigned char i, unsigned char scale) {
|
||||
return (((unsigned int) i) * (1 + (unsigned int) (scale))) >> 8;
|
||||
}
|
||||
|
||||
/* easing functions; see http://easings.net
|
||||
|
||||
ease8InOutQuad: 8-bit quadratic ease-in / ease-out function
|
||||
*/
|
||||
unsigned char ease8InOutQuad(unsigned char i) {
|
||||
unsigned char j = i;
|
||||
if (j & 0x80) {
|
||||
j = 255u - j;
|
||||
}
|
||||
unsigned char jj = scale8(j, j);
|
||||
unsigned char jj2 = jj << 1;
|
||||
if (i & 0x80) {
|
||||
jj2 = 255u - jj2;
|
||||
}
|
||||
return jj2;
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
|
||||
This directory is intended for PlatformIO Unit Testing and project tests.
|
||||
|
||||
Unit Testing is a software testing method by which individual units of
|
||||
source code, sets of one or more MCU program modules together with associated
|
||||
control data, usage procedures, and operating procedures, are tested to
|
||||
determine whether they are fit for use. Unit testing finds problems early
|
||||
in the development cycle.
|
||||
|
||||
More information about PlatformIO Unit Testing:
|
||||
- https://docs.platformio.org/page/plus/unit-testing.html
|
||||
@@ -1,19 +0,0 @@
|
||||
FEED="HomeBatteryCurrent"
|
||||
|
||||
if [ $# -eq 0 ]; then
|
||||
echo "Usage: $0 4-digit-topic-nr-of-your-smartevse."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Enter your current in deci-Ampères:"
|
||||
OLD_CURRENT=20
|
||||
while true; do
|
||||
read -t 8 CURRENT
|
||||
if [ $CURRENT"x" == "x" ]; then
|
||||
CURRENT=$OLD_CURRENT
|
||||
else
|
||||
OLD_CURRENT=$CURRENT
|
||||
fi
|
||||
echo $FEED-CURRENT=$CURRENT.
|
||||
mosquitto_pub -h 127.0.0.1 -t "SmartEVSE-$1/Set/$FEED" -m $CURRENT
|
||||
done
|
||||
@@ -1,22 +0,0 @@
|
||||
FEED="EVMeter"
|
||||
|
||||
if [ $# -eq 0 ]; then
|
||||
echo "Usage: $0 4-digit-topic-nr-of-your-smartevse."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Enter your current in deci-Ampères:"
|
||||
OLD_CURRENT=20
|
||||
#energy in Wh:
|
||||
ENERGY=0
|
||||
while true; do
|
||||
read -t 5 CURRENT
|
||||
if [ $CURRENT"x" == "x" ]; then
|
||||
CURRENT=$OLD_CURRENT
|
||||
else
|
||||
OLD_CURRENT=$CURRENT
|
||||
fi
|
||||
echo $FEED-CURRENT=$CURRENT.
|
||||
mosquitto_pub -h 127.0.0.1 -t "SmartEVSE-$1/Set/$FEED" -m $CURRENT:$CURRENT:$CURRENT:11000:$ENERGY
|
||||
ENERGY=$((ENERGY + 100))
|
||||
done
|
||||
@@ -1,20 +0,0 @@
|
||||
FEED="MainsMeter"
|
||||
|
||||
if [ $# -eq 0 ]; then
|
||||
echo "Usage: $0 4-digit-topic-nr-of-your-smartevse."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Enter your current in deci-Ampères:"
|
||||
OLD_CURRENT=20
|
||||
while true; do
|
||||
read -t 1 CURRENT
|
||||
if [ $CURRENT"x" == "x" ]; then
|
||||
CURRENT=$OLD_CURRENT
|
||||
else
|
||||
OLD_CURRENT=$CURRENT
|
||||
fi
|
||||
echo $FEED-CURRENT=$CURRENT.
|
||||
mosquitto_pub -h 127.0.0.1 -t "SmartEVSE-$1/Set/$FEED" -m $CURRENT:$CURRENT:$CURRENT
|
||||
sleep 1
|
||||
done
|
||||
@@ -1,743 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# This script is meant to automate testing of SmartEVSEv3 firmware
|
||||
# Needs jq binary
|
||||
|
||||
#serialnrs (4 digits):
|
||||
|
||||
if [ "$#" -ne 3 ]; then
|
||||
echo "Usage: $0 <serialnr_of_master> <serialnr_of_slave> <test_selection> ; serialnr is 4 digits."
|
||||
echo
|
||||
echo "Make sure you compiled your test version with -DAUTOMATED_TESTING=1 !!"
|
||||
echo
|
||||
echo "Known BUGS: Only run one test at a time; running multiple tests leads to false <fails>"
|
||||
echo
|
||||
echo "WARNING: ONLY USE THIS SCRIPT ON SMARTEVSEs ON A TEST BENCH"
|
||||
echo "NEVER USE THIS SCRIPT ON A LIVE SMARTEVSE; IT _WILL_ BLOW YOUR FUSES AND YOUR BREAKERS!!!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
COUNT=`pgrep tests | wc -l`
|
||||
if [ $COUNT -ne 2 ]; then
|
||||
echo "Tests are already running in the background, exiting"
|
||||
killall tests.sh
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ $3 -eq 0 ]; then #all tests selected
|
||||
SEL=$((0xFFFF))
|
||||
else
|
||||
SEL=$3
|
||||
fi
|
||||
|
||||
DBG=1 #1 means debug mode on, 0 means debug mode off
|
||||
|
||||
# please give values in deci-Ampère:
|
||||
MASTER_SOCKET_HARDWIRED=320
|
||||
SLAVE_SOCKET_HARDWIRED=130
|
||||
MASTER_MAC_ID=$1
|
||||
SLAVE_MAC_ID=$2
|
||||
|
||||
MASTER="smartevse-"$1".local"
|
||||
SLAVE="smartevse-"$2".local"
|
||||
|
||||
control_c()
|
||||
# run if user hits control-c
|
||||
{
|
||||
echo -en "\n*** Ouch! Exiting ***\n"
|
||||
#kill all running subprocesses
|
||||
pkill -P $$
|
||||
exit $?
|
||||
}
|
||||
|
||||
# trap keyboard interrupt (control-c)
|
||||
trap control_c SIGINT
|
||||
|
||||
|
||||
#curl suppress data
|
||||
CURLPOST="curl -s -o /dev/null -X POST -d''"
|
||||
|
||||
# Colors for echo
|
||||
# Reset
|
||||
NC='\033[0m' # Text Reset
|
||||
|
||||
# Regular Colors
|
||||
Black='\033[0;30m' # Black
|
||||
Red='\033[0;31m' # Red
|
||||
Green='\033[0;32m' # Green
|
||||
Yellow='\033[0;33m' # Yellow
|
||||
Blue='\033[0;34m' # Blue
|
||||
Purple='\033[0;35m' # Purple
|
||||
Cyan='\033[0;36m' # Cyan
|
||||
White='\033[0;37m' # White
|
||||
|
||||
ABORT=0
|
||||
|
||||
init_devices () {
|
||||
for device in $SLAVE $MASTER; do
|
||||
#go to Normal Mode for init
|
||||
$CURLPOST $device/reboot
|
||||
sleep 1
|
||||
$CURLPOST "$device/automated_testing?loadbl=0&mainsmeter=1"
|
||||
$CURLPOST $device/settings?mode=1
|
||||
done
|
||||
read -p "Make sure all EVSE's are set to NOT CHARGING, then press <ENTER>" dummy
|
||||
sleep 5
|
||||
}
|
||||
|
||||
init_currents () {
|
||||
#first load all settings before the test
|
||||
for device in $SLAVE $MASTER; do
|
||||
$CURLPOST "$device/automated_testing?config=1¤t_max=60¤t_max_circuit=70¤t_main=80"
|
||||
$CURLPOST "$device/settings?current_max_sum_mains=600&enable_C2=0"
|
||||
#$CURLPOST $device/settings?enable_C2=0 #TODO cycle through all tests with different settings !!!
|
||||
done
|
||||
}
|
||||
|
||||
#takes 3 arguments, actual value, test value and margin
|
||||
print_results() {
|
||||
if [ $DBG -eq 1 ]; then
|
||||
printf "CHARGECUR=$1, TARGET=$2."
|
||||
fi
|
||||
if [ $1 -ge $(( $2 - $3 )) ] && [ $1 -le $(( $2 + $3 )) ]; then
|
||||
printf "$Green Passed $NC LBL=$loadbl_master, Mode=$MODE: $device chargecurrent is limited to $TESTSTRING.\n"
|
||||
else
|
||||
printf "$Red Failed $NC LBL=$loadbl_master, Mode=$MODE: $device chargecurrent is $1 dA and should be limited to $2 dA (with a margin of $3 dA) because of $TESTSTRING.\n"
|
||||
fi
|
||||
}
|
||||
|
||||
#takes 4 arguments, actual value, test value, margin, string_to_test
|
||||
print_results2() {
|
||||
if [ $DBG -eq 1 ]; then
|
||||
printf "$4=$1, TARGET=$2."
|
||||
fi
|
||||
if [ $1 -ge $(( $2 - $3 )) ] && [ $1 -le $(( $2 + $3 )) ]; then
|
||||
printf "$Green Passed $NC LBL=$loadbl_master, Mode=$MODE: $device $4 is as expected when testing $TESTSTRING.\n"
|
||||
else
|
||||
printf "$Red Failed $NC LBL=$loadbl_master, Mode=$MODE: $device $4=$1 should be $4=$2 when testing $TESTSTRING.\n"
|
||||
fi
|
||||
}
|
||||
|
||||
check_all_charge_currents () {
|
||||
for device in $MASTER $SLAVE; do
|
||||
check_charging
|
||||
print_results "$CHARGECUR" "$TESTVALUE10" "0"
|
||||
done
|
||||
}
|
||||
|
||||
set_loadbalancing () {
|
||||
#make sure we switch lbl in the right order so we dont get modbus errors
|
||||
if [ $loadbl_master -eq 0 ]; then
|
||||
loadbl_slave=0
|
||||
$CURLPOST $SLAVE/automated_testing?loadbl=$loadbl_slave
|
||||
$CURLPOST $MASTER/automated_testing?loadbl=$loadbl_master
|
||||
fi
|
||||
if [ $loadbl_master -eq 1 ]; then
|
||||
$CURLPOST $MASTER/automated_testing?loadbl=$loadbl_master
|
||||
sleep 1
|
||||
loadbl_slave=2
|
||||
$CURLPOST $SLAVE/automated_testing?loadbl=$loadbl_slave
|
||||
fi
|
||||
}
|
||||
|
||||
MODESTR=("Off" "Normal" "Solar" "Smart")
|
||||
|
||||
set_mode () {
|
||||
$CURLPOST $MASTER/settings?mode=$mode_master
|
||||
if [ $loadbl_slave -eq 0 ]; then
|
||||
$CURLPOST $SLAVE/settings?mode=$mode_master
|
||||
fi
|
||||
MODE=${MODESTR[$mode_master]}
|
||||
printf "Testing LBL=$loadbl_master, mode=$MODE on $TESTSTRING.\r"
|
||||
TESTVALUE10=$((TESTVALUE * 10))
|
||||
}
|
||||
|
||||
overload_mains () {
|
||||
# echo $TESTVALUE10 >feed_mains_$device
|
||||
#now overload the mains by 1A
|
||||
echo $(( TESTVALUE10 + 10 )) >feed_mains_$device
|
||||
#settle switching modes AND stabilizing charging speeds
|
||||
printf "Watch the charge current of device $device going down in 1-2A steps!\r"
|
||||
sleep 10
|
||||
#now stabilize the mains to MaxMains
|
||||
echo $(( TESTVALUE10 )) >feed_mains_$device
|
||||
}
|
||||
|
||||
set_mainsmeter_to_api () {
|
||||
if [ ! -e "feed_mains_$device" ]; then
|
||||
mkfifo feed_mains_$device
|
||||
fi
|
||||
if [ $device == $MASTER ]; then
|
||||
MAC_ID=$MASTER_MAC_ID
|
||||
else
|
||||
MAC_ID=$SLAVE_MAC_ID
|
||||
fi
|
||||
./feed_mains.sh $MAC_ID <feed_mains_$device >/dev/null &
|
||||
echo $TESTVALUE10 >feed_mains_$device
|
||||
$CURLPOST $device/automated_testing?mainsmeter=9
|
||||
}
|
||||
|
||||
run_test_loadbl0 () {
|
||||
init_devices
|
||||
init_currents
|
||||
for device in $MASTER $SLAVE; do
|
||||
set_mainsmeter_to_api
|
||||
done
|
||||
read -p "Make sure all EVSE's are set to CHARGING, then press <ENTER>" dummy
|
||||
|
||||
loadbl_master=0
|
||||
set_loadbalancing
|
||||
for mode_master in 3 2; do
|
||||
set_mode
|
||||
for device in $MASTER $SLAVE; do
|
||||
$CURLPOST $device$CONFIG_COMMAND
|
||||
overload_mains
|
||||
check_charging
|
||||
#we start charging at maxcurrent and then step down for approx. 1A per 670ms
|
||||
print_results "$CHARGECUR" "${TARGET[$mode_master]}" "$MARGIN"
|
||||
done
|
||||
done
|
||||
#set MainsMeter to Sensorbox
|
||||
for device in $MASTER $SLAVE; do
|
||||
$CURLPOST $device/automated_testing?mainsmeter=1
|
||||
done
|
||||
#kill all running subprocesses
|
||||
pkill -P $$
|
||||
}
|
||||
|
||||
run_test_loadbl1 () {
|
||||
init_devices
|
||||
init_currents
|
||||
device=$MASTER
|
||||
set_mainsmeter_to_api
|
||||
loadbl_master=1
|
||||
set_loadbalancing
|
||||
read -p "Make sure all EVSE's are set to CHARGING, then press <ENTER>" dummy
|
||||
#if we are in loadbl 0 we don't test the slave device
|
||||
for mode_master in 3 2; do
|
||||
set_mode
|
||||
$CURLPOST $device$CONFIG_COMMAND
|
||||
overload_mains
|
||||
TOTCUR=0
|
||||
for device in $SLAVE $MASTER; do
|
||||
check_charging
|
||||
TOTCUR=$((TOTCUR + CHARGECUR))
|
||||
done
|
||||
#we started charging at maxcurrent and then stepped down for approx. 1A per 670ms
|
||||
print_results "$TOTCUR" "${TARGET[$mode_master]}" "$MARGIN"
|
||||
done
|
||||
#set MainsMeter to Sensorbox
|
||||
for device in $MASTER $SLAVE; do
|
||||
$CURLPOST $device/automated_testing?mainsmeter=1
|
||||
done
|
||||
#kill all running subprocesses
|
||||
pkill -P $$
|
||||
}
|
||||
|
||||
check_charging () {
|
||||
#make sure we are actually charging
|
||||
CURL=$(curl -s -X GET $device/settings)
|
||||
STATE_ID=$(echo $CURL | jq ".evse.state_id")
|
||||
print_results2 "$STATE_ID" "2" "0" "STATE_ID"
|
||||
CHARGECUR=$(echo $CURL | jq ".settings.charge_current")
|
||||
}
|
||||
|
||||
#TEST1: MODESWITCH TEST: test if mode changes on master reflects on slave and vice versa
|
||||
NR=$((2**0))
|
||||
if [ $((SEL & NR)) -ne 0 ]; then
|
||||
TESTSTRING="Modeswitch"
|
||||
printf "Starting $TESTSTRING test #$NR:\n"
|
||||
init_devices
|
||||
$CURLPOST $MASTER/automated_testing?loadbl=1
|
||||
$CURLPOST $SLAVE/automated_testing?loadbl=2
|
||||
for mode_master in 1 2 3; do
|
||||
$CURLPOST $MASTER/settings?mode=$mode_master
|
||||
sleep 5
|
||||
mode_slave=$(curl -s -X GET $SLAVE/settings | jq ".mode_id")
|
||||
if [ "x"$mode_slave == "x"$mode_master ]; then
|
||||
printf "$Green Passed $NC Master switching to mode $mode_master, slave follows.\n"
|
||||
else
|
||||
printf "$Red Failed $NC Master switching to mode $mode_master, slave is at $mode_slave.\n"
|
||||
ABORT=1
|
||||
fi
|
||||
done
|
||||
|
||||
if [ $ABORT -ne 0 ]; then
|
||||
exit $ABORT
|
||||
fi
|
||||
|
||||
for mode_slave in 1 2 3; do
|
||||
$CURLPOST $SLAVE/settings?mode=$mode_slave
|
||||
sleep 5
|
||||
mode_master=$(curl -s -X GET $MASTER/settings | jq ".mode_id")
|
||||
if [ "x"$mode_slave == "x"$mode_master ]; then
|
||||
printf "$Green Passed $NC Slave switching to $mode_slave, master follows.\n"
|
||||
else
|
||||
printf "$Red Failed $NC Slave switching to $mode_slave, master is at $mode_master.\n"
|
||||
ABORT=1
|
||||
fi
|
||||
done
|
||||
|
||||
#if we cannot rely on correct switching of modes between master and slave, we will have to abort testing
|
||||
if [ $ABORT -ne 0 ]; then
|
||||
printf "Since one of the previous tests failed we abort testing."
|
||||
exit $ABORT
|
||||
fi
|
||||
fi
|
||||
|
||||
#TEST2: SOCKET HARDWIRING TEST: test if Socket resistors in test bench limit our current // Configuration (0:Socket / 1:Fixed Cable)
|
||||
# needs setting [MASTER|SLAVE]_SOCKET_HARDWIRED to the correct values of your test bench
|
||||
NR=$((2**1))
|
||||
if [ $((SEL & NR)) -ne 0 ]; then
|
||||
TESTSTRING="Socket Hardwiring"
|
||||
printf "Starting $TESTSTRING test #$NR:\n"
|
||||
printf "Make sure your Sensorbox is on MAX power delivery to the grid, or Solar tests will fail!\n"
|
||||
init_devices
|
||||
init_currents
|
||||
#first load all settings before the test
|
||||
for device in $SLAVE $MASTER; do
|
||||
$CURLPOST $device/automated_testing?config=0
|
||||
done
|
||||
read -p "Make sure all EVSE's are set to CHARGING, then press <ENTER>" dummy
|
||||
|
||||
for loadbl_master in 0 1; do
|
||||
set_loadbalancing
|
||||
#if we are in loadbl 0 we test the slave device in loadbl 0 also
|
||||
for mode_master in 1 2 3; do
|
||||
set_mode
|
||||
#settle switching modes AND stabilizing charging speeds
|
||||
sleep 10
|
||||
for device in $SLAVE $MASTER; do
|
||||
check_charging
|
||||
if [ $device == $MASTER ]; then
|
||||
print_results "$CHARGECUR" "$MASTER_SOCKET_HARDWIRED" "0"
|
||||
else
|
||||
print_results "$CHARGECUR" "$SLAVE_SOCKET_HARDWIRED" "0"
|
||||
fi
|
||||
done
|
||||
done
|
||||
done
|
||||
|
||||
#for all other tests we don't want socket resistors to limit our currents, so switch to Fixed Cable
|
||||
for device in $MASTER $SLAVE; do
|
||||
$CURLPOST $device/automated_testing?config=1
|
||||
done
|
||||
fi
|
||||
|
||||
#TEST4: MAXCURRENT TEST: test if MaxCurrent is obeyed
|
||||
NR=$((2**2))
|
||||
if [ $((SEL & NR)) -ne 0 ]; then
|
||||
TESTSTRING="MaxCurrent"
|
||||
printf "Starting $TESTSTRING test #$NR:\n"
|
||||
printf "Make sure your Sensorbox is on MAX power delivery to the grid, or Solar tests will fail!\n"
|
||||
init_devices
|
||||
init_currents
|
||||
|
||||
read -p "Make sure all EVSE's are set to CHARGING, then press <ENTER>" dummy
|
||||
|
||||
for loadbl_master in 0 1; do
|
||||
set_loadbalancing
|
||||
#if we are in loadbl 0 we test the slave device in loadbl 0 also
|
||||
TESTVALUE=12
|
||||
for mode_master in 1 3 2; do
|
||||
set_mode
|
||||
for device in $MASTER $SLAVE; do
|
||||
$CURLPOST $device/automated_testing?current_max=$TESTVALUE
|
||||
done
|
||||
#settle switching modes AND stabilizing charging speeds
|
||||
sleep 10
|
||||
check_all_charge_currents
|
||||
#increase testvalue to test if the device responds to that
|
||||
TESTVALUE=$(( TESTVALUE + 1 ))
|
||||
done
|
||||
done
|
||||
fi
|
||||
|
||||
#TEST8: MAXCIRCUIT TEST: test if MaxCircuit is obeyed
|
||||
NR=$((2**3))
|
||||
if [ $((SEL & NR)) -ne 0 ]; then
|
||||
TESTSTRING="MaxCirCuit"
|
||||
printf "Starting $TESTSTRING test #$NR:\n"
|
||||
printf "Make sure your Sensorbox is on MAX power delivery to the grid, or Solar tests will fail!\n"
|
||||
init_devices
|
||||
init_currents
|
||||
read -p "Make sure all EVSE's are set to CHARGING, then press <ENTER>" dummy
|
||||
|
||||
for loadbl_master in 0 1; do
|
||||
set_loadbalancing
|
||||
#if we are in loadbl 0 we test the slave device in loadbl 0 also
|
||||
TESTVALUE=20
|
||||
for mode_master in 1 3 2; do
|
||||
set_mode
|
||||
for device in $MASTER $SLAVE; do
|
||||
$CURLPOST $device/automated_testing?current_max_circuit=$TESTVALUE
|
||||
done
|
||||
#settle switching modes AND stabilizing charging speeds
|
||||
sleep 13
|
||||
|
||||
if [ $loadbl_master -eq 0 ]; then
|
||||
check_all_charge_currents
|
||||
else
|
||||
TOTCUR=0
|
||||
for device in $SLAVE $MASTER; do
|
||||
check_charging
|
||||
TOTCUR=$((TOTCUR + CHARGECUR))
|
||||
done
|
||||
print_results "$TOTCUR" "$TESTVALUE10" "0"
|
||||
fi
|
||||
#increase testvalue to test if the device responds to that
|
||||
TESTVALUE=$(( TESTVALUE + 1 ))
|
||||
done
|
||||
done
|
||||
fi
|
||||
|
||||
#TEST16: MAXMAINS TEST: test if MaxMains is obeyed when using EM_API for loadbl=0
|
||||
NR=$((2**4))
|
||||
if [ $((SEL & NR)) -ne 0 ]; then
|
||||
TESTSTRING="MaxMains via EM_API for loadbl=0"
|
||||
printf "Starting $TESTSTRING test #$NR:\n"
|
||||
#the margin for which we will accept the lowering/upping of the charge current, in dA
|
||||
MARGIN=20
|
||||
TESTVALUE=25
|
||||
#Target values for Off, Normal, Solar, Smart mode RESPECTIVELY:
|
||||
TARGET=(0 0 300 450)
|
||||
CONFIG_COMMAND="/automated_testing?current_main=$TESTVALUE"
|
||||
run_test_loadbl0
|
||||
fi
|
||||
|
||||
#TEST32: MAXMAINS TEST: test if MaxMains is obeyed when using EM_API
|
||||
NR=$((2**5))
|
||||
if [ $((SEL & NR)) -ne 0 ]; then
|
||||
TESTSTRING="MaxMains via EM_API for loadbl=1"
|
||||
printf "Starting $TESTSTRING test #$NR:\n"
|
||||
#the margin for which we will accept the lowering/upping of the charge current, in dA
|
||||
MARGIN=20
|
||||
TESTVALUE=25
|
||||
#Target values for Off, Normal, Solar, Smart mode RESPECTIVELY:
|
||||
TARGET=(0 0 420 560)
|
||||
CONFIG_COMMAND="/automated_testing?current_main=$TESTVALUE"
|
||||
run_test_loadbl1
|
||||
fi
|
||||
|
||||
#TEST64: MAXSUMMAINS TEST: test if MaxSumMains is obeyed when using EM_API for loadbl=0
|
||||
NR=$((2**6))
|
||||
if [ $((SEL & NR)) -ne 0 ]; then
|
||||
TESTSTRING="MaxSumMains via EM_API for loadbl=0"
|
||||
printf "Starting $TESTSTRING test #$NR:\n"
|
||||
#the margin for which we will accept the lowering/upping of the charge current, in dA
|
||||
MARGIN=20
|
||||
TESTVALUE=50
|
||||
#Target values for Off, Normal, Solar, Smart mode RESPECTIVELY:
|
||||
TARGET=(0 0 310 455)
|
||||
CONFIG_COMMAND="/settings?current_max_sum_mains=$((TESTVALUE * 3))"
|
||||
run_test_loadbl0
|
||||
fi
|
||||
|
||||
#TEST128: MAXSUMMAINS TEST: test if MaxSumMains is obeyed when using EM_API for loadbl=1
|
||||
NR=$((2**7))
|
||||
if [ $((SEL & NR)) -ne 0 ]; then
|
||||
TESTSTRING="MaxSumMains via EM_API for loadbl=1"
|
||||
printf "Starting $TESTSTRING test #$NR:\n"
|
||||
#the margin for which we will accept the lowering/upping of the charge current, in dA
|
||||
MARGIN=20
|
||||
TESTVALUE=50
|
||||
TARGET=(0 0 425 560)
|
||||
CONFIG_COMMAND="/settings?current_max_sum_mains=$((TESTVALUE * 3))"
|
||||
run_test_loadbl1
|
||||
fi
|
||||
|
||||
#TEST256: STARTCURRENT TEST: test if StartCurrent is obeyed in Solar Mode for loadbl=0
|
||||
NR=$((2**8))
|
||||
if [ $((SEL & NR)) -ne 0 ]; then
|
||||
TESTSTRING="StartCurrent, StopTimer and ImportCurrent via EM_API for loadbl=0"
|
||||
printf "Starting $TESTSTRING test #$NR:\n"
|
||||
#the margin for which we will accept the lowering/upping of the charge current, in dA
|
||||
MARGIN=20
|
||||
#make mains_overload feed mains_current with 3A to the grid
|
||||
TESTVALUE=-3
|
||||
#note that startcurrent shown as -4A on the display is stored as 4A !
|
||||
#CONFIG_COMMAND="/settings?solar_start_current=4"
|
||||
init_devices
|
||||
init_currents
|
||||
for device in $MASTER $SLAVE; do
|
||||
set_mainsmeter_to_api
|
||||
$CURLPOST "$device/settings?solar_start_current=4&solar_max_import=15&solar_stop_time=1"
|
||||
done
|
||||
read -p "Make sure all EVSE's are set to CHARGING, then press <ENTER>" dummy
|
||||
|
||||
loadbl_master=0
|
||||
set_loadbalancing
|
||||
#SOLAR mode
|
||||
mode_master=2
|
||||
set_mode
|
||||
for device in $MASTER $SLAVE; do
|
||||
echo 60 >feed_mains_$device
|
||||
done
|
||||
printf "Feeding total of 18A....chargecurrent should drop to 6A, then triggers stoptimer and when it expires, stops charging because over import limit of 15A\r"
|
||||
TESTSTRING="SolarStopTimer should have been activated on overload on ImportCurrent"
|
||||
sleep 50
|
||||
for device in $MASTER $SLAVE; do
|
||||
TIMER=$(curl -s -X GET $device/settings | jq ".evse.solar_stop_timer")
|
||||
print_results2 "$TIMER" "28" "15" "SOLAR_STOP_TIMER"
|
||||
done
|
||||
TESTSTRING="Charging should stop after expiring SolarStopTimer"
|
||||
printf "$TESTSTRING\r"
|
||||
sleep 40
|
||||
for device in $MASTER $SLAVE; do
|
||||
STATE_ID=$(curl -s -X GET $device/settings | jq ".evse.state_id")
|
||||
print_results2 "$STATE_ID" "10" "0" "STATE_ID"
|
||||
echo -20 >feed_mains_$device
|
||||
done
|
||||
TESTSTRING="Feeding total of -6A....should trigger ready-timer 60s"
|
||||
printf "$TESTSTRING\r"
|
||||
sleep 65
|
||||
read -p "To start charging, set EVSE's to NO CHARGING and then to CHARGING again, then press <ENTER>" dummy
|
||||
TESTSTRING="Feeding total of 18A should drop the charging current"
|
||||
printf "$TESTSTRING\r"
|
||||
for device in $MASTER $SLAVE; do
|
||||
check_charging
|
||||
#dropping the charge current by a few amps
|
||||
echo 60 >feed_mains_$device
|
||||
done
|
||||
sleep 3
|
||||
TESTSTRING="Feeding total of 15A should stabilize the charging current"
|
||||
printf "$TESTSTRING\r"
|
||||
for device in $MASTER $SLAVE; do
|
||||
check_charging
|
||||
print_results "$CHARGECUR" "475" "30"
|
||||
echo 50 >feed_mains_$device
|
||||
done
|
||||
sleep 10
|
||||
for device in $MASTER $SLAVE; do
|
||||
check_charging
|
||||
print_results "$CHARGECUR" "450" "35"
|
||||
done
|
||||
#set MainsMeter to Sensorbox
|
||||
for device in $MASTER $SLAVE; do
|
||||
$CURLPOST $device/automated_testing?mainsmeter=1
|
||||
done
|
||||
#kill all running subprocesses
|
||||
pkill -P $$
|
||||
fi
|
||||
|
||||
#TEST512: STARTCURRENT TEST: test if StartCurrent is obeyed in Solar Mode for loadbl=1
|
||||
NR=$((2**9))
|
||||
if [ $((SEL & NR)) -ne 0 ]; then
|
||||
TESTSTRING="StartCurrent, StopTimer and ImportCurrent via EM_API for loadbl=1"
|
||||
printf "Starting $TESTSTRING test #$NR:\n"
|
||||
#the margin for which we will accept the lowering/upping of the charge current, in dA
|
||||
MARGIN=20
|
||||
#make mains_overload feed mains_current with 3A to the grid
|
||||
TESTVALUE=-3
|
||||
#note that startcurrent shown as -4A on the display is stored as 4A !
|
||||
#CONFIG_COMMAND="/settings?solar_start_current=4"
|
||||
init_devices
|
||||
init_currents
|
||||
for device in $MASTER; do
|
||||
set_mainsmeter_to_api
|
||||
$CURLPOST "$device/settings?solar_start_current=4&solar_max_import=15&solar_stop_time=1"
|
||||
done
|
||||
|
||||
loadbl_master=1
|
||||
set_loadbalancing
|
||||
#SOLAR mode
|
||||
sleep 2
|
||||
mode_master=2
|
||||
set_mode
|
||||
sleep 2
|
||||
printf "\n"
|
||||
read -p "Make sure all EVSE's are set to CHARGING, then press <ENTER>" dummy
|
||||
TESTSTRING="Feeding total of 3A so we should wait for the sun"
|
||||
printf "$TESTSTRING\r"
|
||||
echo 10 >feed_mains_$MASTER
|
||||
sleep 5
|
||||
for device in $MASTER $SLAVE; do
|
||||
STATE_ID=$(curl -s -X GET $device/settings | jq ".evse.state_id")
|
||||
print_results2 "$STATE_ID" "9" "0" "STATE_ID"
|
||||
done
|
||||
TESTSTRING="Feeding total of -6A....should trigger ready-timer 60s"
|
||||
printf "$TESTSTRING\r"
|
||||
echo -20 >feed_mains_$MASTER
|
||||
sleep 70
|
||||
read -p "To start charging, set EVSE's to NO CHARGING and then to CHARGING again, then press <ENTER>" dummy
|
||||
sleep 2
|
||||
for device in $MASTER $SLAVE; do
|
||||
check_charging
|
||||
done
|
||||
TESTSTRING="Feeding total of 18A should drop the charging current"
|
||||
printf "$TESTSTRING\r"
|
||||
echo 60 >feed_mains_$MASTER
|
||||
sleep 10
|
||||
for device in $MASTER $SLAVE; do
|
||||
check_charging
|
||||
print_results "$CHARGECUR" "225" "20"
|
||||
done
|
||||
TESTSTRING="Feeding total of 15A should stabilize the charging current"
|
||||
printf "$TESTSTRING\r"
|
||||
echo 50 >feed_mains_$MASTER
|
||||
sleep 10
|
||||
for device in $MASTER $SLAVE; do
|
||||
check_charging
|
||||
print_results "$CHARGECUR" "210" "20"
|
||||
done
|
||||
printf "Feeding total of 18A....chargecurrent should drop to 6A, then triggers stoptimer and when it expires, stops charging because over import limit of 15A\r"
|
||||
TESTSTRING="SolarStopTimer should have been activated on overload on ImportCurrent"
|
||||
echo 60 >feed_mains_$MASTER
|
||||
sleep 60
|
||||
for device in $MASTER $SLAVE; do
|
||||
TIMER=$(curl -s -X GET $device/settings | jq ".evse.solar_stop_timer")
|
||||
print_results2 "$TIMER" "15" "5" "SOLAR_STOP_TIMER"
|
||||
done
|
||||
TESTSTRING="Charging should stop after expiring SolarStopTimer"
|
||||
printf "$TESTSTRING\r"
|
||||
sleep 40
|
||||
for device in $MASTER $SLAVE; do
|
||||
STATE_ID=$(curl -s -X GET $device/settings | jq ".evse.state_id")
|
||||
print_results2 "$STATE_ID" "9" "0" "STATE_ID"
|
||||
done
|
||||
TESTSTRING="Feeding total of -6A....should trigger ready-timer 60s"
|
||||
printf "$TESTSTRING\r"
|
||||
echo -20 >feed_mains_$MASTER
|
||||
sleep 63
|
||||
read -p "To start charging, set EVSE's to NO CHARGING and then to CHARGING again, then press <ENTER>" dummy
|
||||
sleep 2
|
||||
for device in $MASTER $SLAVE; do
|
||||
check_charging
|
||||
done
|
||||
#set MainsMeter to Sensorbox
|
||||
for device in $MASTER $SLAVE; do
|
||||
$CURLPOST $device/automated_testing?mainsmeter=1
|
||||
done
|
||||
#kill all running subprocesses
|
||||
pkill -P $$
|
||||
fi
|
||||
|
||||
#TEST1024: shortened version of test512
|
||||
NR=$((2**10))
|
||||
if [ $((SEL & NR)) -ne 0 ]; then
|
||||
TESTSTRING="StartCurrent, StopTimer and ImportCurrent via EM_API for loadbl=1"
|
||||
printf "Starting $TESTSTRING test #$NR:\n"
|
||||
#the margin for which we will accept the lowering/upping of the charge current, in dA
|
||||
MARGIN=20
|
||||
TESTVALUE=-3
|
||||
TESTVALUE10=$((TESTVALUE*10))
|
||||
#note that startcurrent shown as -4A on the display is stored as 4A !
|
||||
#CONFIG_COMMAND="/settings?solar_start_current=4"
|
||||
init_devices
|
||||
init_currents
|
||||
for device in $MASTER; do
|
||||
set_mainsmeter_to_api
|
||||
$CURLPOST "$device/settings?solar_start_current=4&solar_max_import=15&solar_stop_time=1"
|
||||
done
|
||||
#to speed up testing lower max_current
|
||||
for device in $MASTER $SLAVE; do
|
||||
$CURLPOST $device/automated_testing?current_max=9
|
||||
done
|
||||
sleep 1
|
||||
loadbl_master=1
|
||||
set_loadbalancing
|
||||
#SOLAR mode
|
||||
sleep 2
|
||||
mode_master=2
|
||||
set_mode
|
||||
sleep 2
|
||||
printf "\n"
|
||||
read -p "Make sure all EVSE's are set to CHARGING, then press <ENTER>" dummy
|
||||
printf "Feeding total of 18A....chargecurrent should drop to 6A, then triggers stoptimer and when it expires, stops charging because over import limit of 15A\r"
|
||||
TESTSTRING="SolarStopTimer should have been activated on overload on ImportCurrent"
|
||||
echo 60 >feed_mains_$MASTER
|
||||
sleep 40
|
||||
for device in $MASTER $SLAVE; do
|
||||
TIMER=$(curl -s -X GET $device/settings | jq ".evse.solar_stop_timer")
|
||||
print_results2 "$TIMER" "26" "5" "SOLAR_STOP_TIMER"
|
||||
done
|
||||
TESTSTRING="Charging should stop after expiring SolarStopTimer"
|
||||
printf "$TESTSTRING\r"
|
||||
sleep 40
|
||||
for device in $MASTER $SLAVE; do
|
||||
STATE_ID=$(curl -s -X GET $device/settings | jq ".evse.state_id")
|
||||
print_results2 "$STATE_ID" "9" "0" "STATE_ID"
|
||||
done
|
||||
TESTSTRING="Feeding total of -6A....should trigger ready-timer 60s"
|
||||
printf "$TESTSTRING\r"
|
||||
echo -20 >feed_mains_$MASTER
|
||||
sleep 63
|
||||
read -p "To start charging, set EVSE's to NO CHARGING and then to CHARGING again, then press <ENTER>" dummy
|
||||
sleep 2
|
||||
for device in $MASTER $SLAVE; do
|
||||
check_charging
|
||||
done
|
||||
#set MainsMeter to Sensorbox
|
||||
for device in $MASTER $SLAVE; do
|
||||
$CURLPOST $device/automated_testing?mainsmeter=1
|
||||
done
|
||||
#kill all running subprocesses
|
||||
pkill -P $$
|
||||
fi
|
||||
|
||||
#TEST2048: modified version of test1024, only testing a master without any slaves
|
||||
NR=$((2**11))
|
||||
if [ $((SEL & NR)) -ne 0 ]; then
|
||||
TESTSTRING="StartCurrent, StopTimer and ImportCurrent via EM_API for loadbl=1 with only Master"
|
||||
printf "Starting $TESTSTRING test #$NR:\n"
|
||||
#the margin for which we will accept the lowering/upping of the charge current, in dA
|
||||
MARGIN=20
|
||||
#make mains_overload feed mains_current with 3A per phase to the grid
|
||||
TESTVALUE=-3
|
||||
TESTVALUE10=$((TESTVALUE*10))
|
||||
#note that startcurrent shown as -4A on the display is stored as 4A !
|
||||
#CONFIG_COMMAND="/settings?solar_start_current=4"
|
||||
init_devices
|
||||
init_currents
|
||||
for device in $MASTER; do
|
||||
set_mainsmeter_to_api
|
||||
$CURLPOST "$device/settings?solar_start_current=4&solar_max_import=15&solar_stop_time=1"
|
||||
done
|
||||
#to speed up testing lower max_current
|
||||
for device in $MASTER $SLAVE; do
|
||||
$CURLPOST $device/automated_testing?current_max=9
|
||||
done
|
||||
loadbl_master=1
|
||||
set_loadbalancing
|
||||
#put slave into multi=disabled
|
||||
$CURLPOST $SLAVE/automated_testing?loadbl=0
|
||||
#SOLAR mode
|
||||
sleep 2
|
||||
mode_master=2
|
||||
set_mode
|
||||
sleep 2
|
||||
printf "\n"
|
||||
read -p "Make sure all EVSE's are set to CHARGING, then press <ENTER>" dummy
|
||||
printf "Feeding total of 18A....chargecurrent should drop to 6A, then triggers stoptimer and when it expires, stops charging because over import limit of 15A\r"
|
||||
TESTSTRING="SolarStopTimer should have been activated on overload on ImportCurrent"
|
||||
echo 60 >feed_mains_$MASTER
|
||||
sleep 65
|
||||
for device in $MASTER; do
|
||||
TIMER=$(curl -s -X GET $device/settings | jq ".evse.solar_stop_timer")
|
||||
print_results2 "$TIMER" "8" "5" "SOLAR_STOP_TIMER"
|
||||
done
|
||||
TESTSTRING="Charging should stop after expiring SolarStopTimer"
|
||||
printf "$TESTSTRING\r"
|
||||
sleep 40
|
||||
for device in $MASTER; do
|
||||
STATE_ID=$(curl -s -X GET $device/settings | jq ".evse.state_id")
|
||||
print_results2 "$STATE_ID" "9" "0" "STATE_ID"
|
||||
done
|
||||
TESTSTRING="Feeding total of -6A....should trigger ready-timer 60s"
|
||||
printf "$TESTSTRING\r"
|
||||
echo -20 >feed_mains_$MASTER
|
||||
sleep 63
|
||||
read -p "To start charging, set EVSE's to NO CHARGING and then to CHARGING again, then press <ENTER>" dummy
|
||||
sleep 2
|
||||
for device in $MASTER; do
|
||||
check_charging
|
||||
done
|
||||
#set MainsMeter to Sensorbox
|
||||
for device in $MASTER $SLAVE; do
|
||||
$CURLPOST $device/automated_testing?mainsmeter=1
|
||||
done
|
||||
#kill all running subprocesses
|
||||
pkill -P $$
|
||||
fi
|
||||
|
||||
exit 0
|
||||