Compare commits
No commits in common. "master" and "v1.0.1" have entirely different histories.
12
.github/FUNDING.yml
vendored
@ -1,12 +0,0 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: [pascallanger]
|
||||
patreon: # Replace with a single Patreon username
|
||||
open_collective: # Replace with a single Open Collective username
|
||||
ko_fi: # Replace with a single Ko-fi username
|
||||
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||
liberapay: # Replace with a single Liberapay username
|
||||
issuehunt: # Replace with a single IssueHunt username
|
||||
otechie: # Replace with a single Otechie username
|
||||
custom: https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=VF2K9T23DRY56&lc=US&item_name=DIY%20Multiprotocol¤cy_code=EUR&bn=PP%2dDonationsBF%3abtn_donate_SM%2egif%3aNonHosted
|
378
.github/workflows/main.yml
vendored
@ -1,378 +0,0 @@
|
||||
# Workflow for testing MULTI-Module firmware builds
|
||||
|
||||
name: MULTI Test, Build, Deploy, Release
|
||||
|
||||
on:
|
||||
# Trigger the workflow on pushes, except those that are tagged (avoids double-testing releases)
|
||||
push:
|
||||
branches:
|
||||
- '**'
|
||||
tags-ignore:
|
||||
- '**'
|
||||
paths:
|
||||
- '.github/workflows/**'
|
||||
- 'buildroot/bin/**'
|
||||
- 'Multiprotocol/**'
|
||||
|
||||
# Trigger the workflow on pull requests to the master branch
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
paths:
|
||||
- '.github/workflows/**'
|
||||
- 'buildroot/bin/**'
|
||||
- 'Multiprotocol/**'
|
||||
|
||||
# Triggers the workflow on release creation
|
||||
release:
|
||||
types:
|
||||
- created
|
||||
|
||||
# Allows the workflow to be triggered manually from the Actions tab
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
# Configure the board matrix
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- board: "multi4in1:avr:multiatmega328p:bootloader=none"
|
||||
name: "ATmega328p"
|
||||
- board: "multi4in1:avr:multiatmega328p:bootloader=optiboot"
|
||||
name: "ATmega328p (Optiboot)"
|
||||
- board: "multi4in1:avr:multixmega32d4"
|
||||
name: "OrangeRX"
|
||||
- board: "multi4in1:STM32F1:multistm32f103c8:debug_option=none"
|
||||
name: "STM32F103 (64KB)"
|
||||
- board: "multi4in1:STM32F1:multistm32f103cb:debug_option=none"
|
||||
name: "STM32F103 (128KB)"
|
||||
- board: "multi4in1:STM32F1:multistm32f103cb:debug_option=native"
|
||||
name: "STM32F103 (128KB, USB Debug)"
|
||||
- board: "multi4in1:STM32F1:multistm32f103cb:debug_option=ftdi"
|
||||
name: "STM32F103 (128KB, Serial Debug)"
|
||||
- board: "multi4in1:STM32F1:multi5in1t18int"
|
||||
name: "T18 5-in-1 (128KB)"
|
||||
|
||||
# Set the build name using the friendly board name
|
||||
name: "[Test] ${{ matrix.name }}"
|
||||
|
||||
# Set the environment variables
|
||||
env:
|
||||
BOARD: ${{ matrix.board }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install Arduino CLI
|
||||
uses: arduino/setup-arduino-cli@v2
|
||||
with:
|
||||
version: "0.32.2"
|
||||
|
||||
- name: Prepare build environment
|
||||
run: |
|
||||
echo "Github Ref: $GITHUB_REF"
|
||||
echo "Event name: ${{ github.event_name }}"
|
||||
echo "Event action: ${{ github.event.action }}"
|
||||
echo "Tag name: ${{ github.event.release.tag_name }}"
|
||||
|
||||
arduino-cli config init --additional-urls https://raw.githubusercontent.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/master/package_multi_4in1_board_index.json,https://raw.githubusercontent.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/devel/source/package_multi_4in1_board_devel_index.json
|
||||
arduino-cli core update-index
|
||||
|
||||
if [[ "$BOARD" =~ ":avr:" ]]; then
|
||||
arduino-cli core install arduino:avr;
|
||||
fi
|
||||
|
||||
if [[ "$BOARD" =~ "multi4in1-devel:avr" ]]; then
|
||||
arduino-cli core install multi4in1-devel:avr
|
||||
elif [[ "$BOARD" =~ "multi4in1:avr" ]]; then
|
||||
arduino-cli core install multi4in1:avr
|
||||
fi
|
||||
|
||||
if [[ "$BOARD" =~ "multi4in1-devel:STM32F1:" ]]; then
|
||||
arduino-cli core install multi4in1-devel:STM32F1
|
||||
elif [[ "$BOARD" =~ "multi4in1:STM32F1:" ]]; then
|
||||
arduino-cli core install multi4in1:STM32F1
|
||||
fi
|
||||
|
||||
chmod +x ${GITHUB_WORKSPACE}/buildroot/bin/*
|
||||
echo "${GITHUB_WORKSPACE}/buildroot/bin" >> $GITHUB_PATH
|
||||
|
||||
mkdir ./build
|
||||
mkdir ./binaries
|
||||
|
||||
- name: Configure MULTI-Module firmware options
|
||||
run: |
|
||||
# Load the build functions
|
||||
source ./buildroot/bin/buildFunctions;
|
||||
|
||||
# Get the version
|
||||
getMultiVersion
|
||||
echo "MULTI_VERSION=$(echo $MULTI_VERSION)" >> $GITHUB_ENV
|
||||
|
||||
# Get all the protocols for this board
|
||||
getAllProtocols
|
||||
echo "A7105_PROTOCOLS=$(echo $A7105_PROTOCOLS)" >> $GITHUB_ENV
|
||||
echo "CC2500_PROTOCOLS=$(echo $CC2500_PROTOCOLS)" >> $GITHUB_ENV
|
||||
echo "CYRF6936_PROTOCOLS=$(echo $CYRF6936_PROTOCOLS)" >> $GITHUB_ENV
|
||||
echo "NRF24L01_PROTOCOLS=$(echo $NRF24L01_PROTOCOLS)" >> $GITHUB_ENV
|
||||
echo "SX1276_PROTOCOLS=$(echo $SX1276_PROTOCOLS)" >> $GITHUB_ENV
|
||||
echo "CCNRF_INO_PROTOCOLS=$(echo $CCNRF_INO_PROTOCOLS)" >> $GITHUB_ENV
|
||||
echo "ALL_PROTOCOLS=$(echo $ALL_PROTOCOLS)" >> $GITHUB_ENV
|
||||
|
||||
# Get all the RF modules for this board
|
||||
getAllRFModules
|
||||
echo "ALL_RFMODULES=$(echo $ALL_RFMODULES)" >> $GITHUB_ENV
|
||||
|
||||
# Disable CHECK_FOR_BOOTLOADER when not needed
|
||||
if [[ "$BOARD" =~ ":avr:multiatmega328p:bootloader=none" ]]; then
|
||||
opt_disable CHECK_FOR_BOOTLOADER;
|
||||
fi
|
||||
|
||||
# Trim the build down for the Atmega328p board
|
||||
if [[ "$BOARD" =~ ":avr:multiatmega328p:" ]]; then
|
||||
opt_disable $ALL_PROTOCOLS
|
||||
opt_enable FRSKYX_CC2500_INO AFHDS2A_A7105_INO MJXQ_NRF24L01_INO DSM_CYRF6936_INO;
|
||||
fi
|
||||
|
||||
# Trim the enabled protocols down for the STM32F103CB board with debugging or the STM32F103C8 board in general
|
||||
if [[ "$BOARD" =~ ":STM32F1:multistm32f103cb:debug_option=ftdi" ]] || [[ "$BOARD" =~ ":STM32F1:multistm32f103cb:debug_option=native" ]] || [[ "$BOARD" =~ ":STM32F1:multistm32f103c8" ]]; then
|
||||
opt_disable $ALL_PROTOCOLS;
|
||||
opt_enable FRSKYX_CC2500_INO AFHDS2A_A7105_INO MJXQ_NRF24L01_INO DSM_CYRF6936_INO;
|
||||
fi
|
||||
|
||||
- name: Save default firmware configuration
|
||||
run: |
|
||||
cat Multiprotocol/_Config.h
|
||||
cp Multiprotocol/_Config.h ./_Config.h.bak
|
||||
|
||||
- name: Build default configuration
|
||||
run: |
|
||||
# Skip the default build for boards where it's too large now
|
||||
if [[ "$BOARD" =~ ":STM32F1:multistm32f103cb:debug_option=none" ]] || [[ "$BOARD" =~ ":STM32F1:multi5in1t18int" ]]; then
|
||||
printf "Not testing default build for $BOARD.";
|
||||
else
|
||||
source ./buildroot/bin/buildFunctions;
|
||||
buildMulti
|
||||
fi
|
||||
|
||||
- name: Build serial only
|
||||
run: |
|
||||
# Skip the serial-only build for boards where it's too large now
|
||||
if [[ "$BOARD" =~ ":STM32F1:multistm32f103cb:debug_option=none" ]] || [[ "$BOARD" =~ ":STM32F1:multi5in1t18int" ]]; then
|
||||
printf "Not testing serial-only build for $BOARD.";
|
||||
else
|
||||
source ./buildroot/bin/buildFunctions;
|
||||
cp ./_Config.h.bak Multiprotocol/_Config.h
|
||||
opt_disable ENABLE_PPM;
|
||||
buildMulti;
|
||||
fi
|
||||
|
||||
- name: Build PPM only
|
||||
run: |
|
||||
# Skip the PPM-only build for boards where it's too large now
|
||||
if [[ "$BOARD" =~ ":STM32F1:multistm32f103cb:debug_option=none" ]] || [[ "$BOARD" =~ ":STM32F1:multi5in1t18int" ]]; then
|
||||
printf "Not testing PPM-only build for $BOARD.";
|
||||
else
|
||||
source ./buildroot/bin/buildFunctions;
|
||||
cp ./_Config.h.bak Multiprotocol/_Config.h
|
||||
opt_disable ENABLE_SERIAL;
|
||||
buildMulti;
|
||||
fi
|
||||
|
||||
- name: Build each RF module individually
|
||||
run: |
|
||||
# Skip the per-RF module builds for boards which have fixed modules
|
||||
if [[ "$BOARD" =~ ":STM32F1:multi5in1t18int" ]]; then
|
||||
printf "Not testing individual RF module builds for $BOARD.";
|
||||
else
|
||||
source ./buildroot/bin/buildFunctions;
|
||||
cp ./_Config.h.bak Multiprotocol/_Config.h;
|
||||
buildEachRFModule;
|
||||
fi
|
||||
|
||||
- name: Build each protocol individually
|
||||
run: |
|
||||
source ./buildroot/bin/buildFunctions;
|
||||
cp ./_Config.h.bak Multiprotocol/_Config.h;
|
||||
buildEachProtocol;
|
||||
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
# Configure the board matrix
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- board: "multi4in1:avr:multiatmega328p:bootloader=none"
|
||||
name: "ATmega328p"
|
||||
release: "atmega328p"
|
||||
- board: "multi4in1:avr:multiatmega328p:bootloader=optiboot"
|
||||
name: "ATmega328p (Optiboot)"
|
||||
release: "atmega328p-optiboot"
|
||||
- board: "multi4in1:avr:multixmega32d4"
|
||||
name: "OrangeRX"
|
||||
release: "orangerx"
|
||||
- board: "multi4in1:STM32F1:multistm32f103c8:debug_option=none"
|
||||
name: "STM32F103 CC2500 (64KB)"
|
||||
release: "stm32f103-cc2500-64k"
|
||||
- board: "multi4in1:STM32F1:multistm32f103cb:debug_option=none"
|
||||
name: "STM32F103 CC2500 (128KB)"
|
||||
release: "stm32f103-cc2500-128k"
|
||||
- board: "multi4in1:STM32F1:multistm32f103cb:debug_option=none"
|
||||
name: "STM32F103 (128KB)"
|
||||
release: "stm32f103-128k-4in1"
|
||||
- board: "multi4in1:STM32F1:multistm32f103cb:debug_option=native"
|
||||
name: "STM32F103 (128KB, USB Debug)"
|
||||
release: "stm32f103-128k-usb-debug"
|
||||
- board: "multi4in1:STM32F1:multistm32f103cb:debug_option=ftdi"
|
||||
name: "STM32F103 (128KB, Serial Debug)"
|
||||
release: "stm32f103-128k-serial-debug"
|
||||
- board: "multi4in1:STM32F1:multistm32f103cb:debug_option=none"
|
||||
name: "STM32F103 5-in-1 (128KB)"
|
||||
release: "stm32f103-128k-5in1"
|
||||
- board: "multi4in1:STM32F1:multistm32f103cb:debug_option=none"
|
||||
name: "T-Lite 5-in-1 (128KB)"
|
||||
release: "tlite-5in1"
|
||||
- board: "multi4in1:STM32F1:multi5in1t18int"
|
||||
name: "T18 5-in-1 (128KB)"
|
||||
release: "t18-5in1"
|
||||
- board: "none"
|
||||
name: "Scripts"
|
||||
release: "scripts"
|
||||
|
||||
# Set the build name using the friendly board name
|
||||
name: "[Build] ${{ matrix.name }}"
|
||||
|
||||
# Set the environment variables
|
||||
env:
|
||||
BOARD: ${{ matrix.board }}
|
||||
RELEASE: ${{ matrix.release }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install Arduino CLI
|
||||
uses: arduino/setup-arduino-cli@v2
|
||||
with:
|
||||
version: "0.32.2"
|
||||
|
||||
- name: Prepare build environment
|
||||
run: |
|
||||
echo "Github Ref: $GITHUB_REF"
|
||||
echo "Event name: ${{ github.event_name }}"
|
||||
echo "Event action: ${{ github.event.action }}"
|
||||
echo "Tag name: ${{ github.event.release.tag_name }}"
|
||||
|
||||
arduino-cli config init --additional-urls https://raw.githubusercontent.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/master/package_multi_4in1_board_index.json,https://raw.githubusercontent.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/devel/source/package_multi_4in1_board_devel_index.json
|
||||
arduino-cli core update-index
|
||||
|
||||
if [[ "$BOARD" =~ ":avr:" ]]; then
|
||||
arduino-cli core install arduino:avr;
|
||||
fi
|
||||
|
||||
if [[ "$BOARD" =~ "multi4in1-devel:avr" ]]; then
|
||||
arduino-cli core install multi4in1-devel:avr
|
||||
elif [[ "$BOARD" =~ "multi4in1:avr" ]]; then
|
||||
arduino-cli core install multi4in1:avr
|
||||
fi
|
||||
|
||||
if [[ "$BOARD" =~ "multi4in1-devel:STM32F1:" ]]; then
|
||||
arduino-cli core install multi4in1-devel:STM32F1
|
||||
elif [[ "$BOARD" =~ "multi4in1:STM32F1:" ]]; then
|
||||
arduino-cli core install multi4in1:STM32F1
|
||||
fi
|
||||
|
||||
chmod +x ${GITHUB_WORKSPACE}/buildroot/bin/*
|
||||
echo "${GITHUB_WORKSPACE}/buildroot/bin" >> $GITHUB_PATH
|
||||
|
||||
mkdir ./build
|
||||
mkdir ./binaries
|
||||
|
||||
- name: Configure MULTI-Module firmware options
|
||||
run: |
|
||||
# Load the build functions
|
||||
source ./buildroot/bin/buildFunctions;
|
||||
|
||||
# Get the version
|
||||
getMultiVersion
|
||||
echo "MULTI_VERSION=$(echo $MULTI_VERSION)" >> $GITHUB_ENV
|
||||
|
||||
# Get all the protocols for this board
|
||||
getAllProtocols
|
||||
echo "A7105_PROTOCOLS=$(echo $A7105_PROTOCOLS)" >> $GITHUB_ENV
|
||||
echo "CC2500_PROTOCOLS=$(echo $CC2500_PROTOCOLS)" >> $GITHUB_ENV
|
||||
echo "CYRF6936_PROTOCOLS=$(echo $CYRF6936_PROTOCOLS)" >> $GITHUB_ENV
|
||||
echo "NRF24L01_PROTOCOLS=$(echo $NRF24L01_PROTOCOLS)" >> $GITHUB_ENV
|
||||
echo "SX1276_PROTOCOLS=$(echo $SX1276_PROTOCOLS)" >> $GITHUB_ENV
|
||||
echo "CCNRF_INO_PROTOCOLS=$(echo $CCNRF_INO_PROTOCOLS)" >> $GITHUB_ENV
|
||||
echo "ALL_PROTOCOLS=$(echo $ALL_PROTOCOLS)" >> $GITHUB_ENV
|
||||
|
||||
# Disable CHECK_FOR_BOOTLOADER when not needed
|
||||
if [[ "$BOARD" =~ ":avr:multiatmega328p:bootloader=none" ]]; then
|
||||
opt_disable CHECK_FOR_BOOTLOADER;
|
||||
fi
|
||||
|
||||
- name: Save default firmware configuration
|
||||
run: |
|
||||
cat Multiprotocol/_Config.h
|
||||
cp Multiprotocol/_Config.h ./_Config.h.bak
|
||||
|
||||
- name: Build release files
|
||||
run: |
|
||||
source ./buildroot/bin/buildFunctions;
|
||||
cp ./_Config.h.bak Multiprotocol/_Config.h;
|
||||
buildReleaseFiles;
|
||||
ls -al ./binaries;
|
||||
|
||||
NUM_FILES=$(ls -l ./binaries | grep ^- | wc -l);
|
||||
if [ $NUM_FILES -gt 0 ]; then
|
||||
echo "HAVE_FILES=true" >> $GITHUB_ENV
|
||||
else
|
||||
echo "HAVE_FILES=false" >> $GITHUB_ENV
|
||||
fi
|
||||
|
||||
- name: 'Upload Artifacts'
|
||||
if: env.HAVE_FILES == 'true'
|
||||
uses: actions/upload-artifact/@v4
|
||||
with:
|
||||
name: multi-${{ matrix.release }}
|
||||
path: ./binaries/
|
||||
|
||||
deploy:
|
||||
name: "[Deploy] Attach Build Artifacts"
|
||||
runs-on: ubuntu-latest
|
||||
needs: [test, build]
|
||||
steps:
|
||||
- name: Combine and upload build artifacts
|
||||
uses: actions/upload-artifact/merge@v4
|
||||
with:
|
||||
name: multi-test-build
|
||||
pattern: multi-*
|
||||
delete-merged: true
|
||||
retention-days: 90
|
||||
|
||||
release:
|
||||
name: "[Release] Publish Files to Release"
|
||||
if: github.event_name == 'release' && github.event.action == 'created'
|
||||
runs-on: ubuntu-latest
|
||||
needs: deploy
|
||||
steps:
|
||||
- name: Download artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: multi-test-build
|
||||
path: ./artifacts/
|
||||
|
||||
- name: Display downloaded artifacts
|
||||
run: ls -R ./artifacts/
|
||||
|
||||
- name: Deploy artifacts to release
|
||||
uses: AButler/upload-release-assets@v3.0
|
||||
with:
|
||||
files: './artifacts/*'
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
@ -1,2 +0,0 @@
|
||||
:02000000FFFF00
|
||||
:00000001FF
|
@ -1,34 +0,0 @@
|
||||
:107E0000112484B714BE9FEF9BB99CE395B991E010
|
||||
:107E100098B98370A9F08AEF80938500109284004E
|
||||
:107E200085E08093810096BBB09BFECF10928100CD
|
||||
:107E300093B186B181709C73892B8D3109F0B3D0D9
|
||||
:107E400082E08093C00088E18093C10086E0809347
|
||||
:107E5000C20081E28093C400259AC0E0D0E093E0A4
|
||||
:107E6000F92EEE24E39425E0D22E31E1C32EA9D0E1
|
||||
:107E7000813481F4A6D08EBBABD08EB3823811F49E
|
||||
:107E800085E006C08EB3813811F484E001C083E040
|
||||
:107E900091D086C0823411F484E103C0853419F492
|
||||
:107EA00085E09DD07DC0853541F48BD0C82F89D029
|
||||
:107EB000D0E0D82BCC0FDD1F72C0863521F484E0D2
|
||||
:107EC0008ED080E0E5CF843609F03DC07AD079D0FD
|
||||
:107ED000B82E77D0C11520E7D20718F000E011E0E6
|
||||
:107EE00004C0FE01F7BEE895F9CF6BD0F80181938D
|
||||
:107EF0008F01BE12FACFCE01905781159E4018F423
|
||||
:107F0000FE01F7BEE89564D0C115FEE7DF0708F073
|
||||
:107F100047C007B600FCFDCFFE01A0E0B1E08D91A7
|
||||
:107F20009D910C01E7BEE89511243296A03821E01E
|
||||
:107F3000B207A9F7FE01D7BEE89507B600FCFDCF52
|
||||
:107F4000C7BEE8952DC08437B1F43BD03AD0B82EE7
|
||||
:107F500038D03ED0FE01AC2EAB0C8F010F5F1F4F0F
|
||||
:107F6000849128D0A01205C02196BA94CB0DD11DC2
|
||||
:107F700017C0F801F2CF853739F42AD08EE11AD034
|
||||
:107F800085E918D08FE084CF813549F421D080E194
|
||||
:107F900011D08091C00086FFFCCF05D001C018D061
|
||||
:107FA00080E108D064CFE0E0F0E084918F3F09F0F9
|
||||
:107FB000099408959091C00095FFFCCF8093C6006E
|
||||
:107FC00008958091C00087FFFCCF8091C60008957E
|
||||
:107FD000F8DF803211F085E1EDDF84E1EBCFCF9364
|
||||
:107FE000C82FEFDFC150E9F7CF91F2CFA8950895E0
|
||||
:0C7FF000E0E6F0E098E1908380830895C3
|
||||
:0400000300007E007B
|
||||
:00000001FF
|
@ -1,504 +0,0 @@
|
||||
# Makefile for ATmegaBOOT
|
||||
# E.Lins, 18.7.2005
|
||||
# $Id$
|
||||
#
|
||||
# Instructions
|
||||
#
|
||||
# To make bootloader .hex file:
|
||||
# make diecimila
|
||||
# make lilypad
|
||||
# make ng
|
||||
# etc...
|
||||
#
|
||||
# To burn bootloader .hex file:
|
||||
# make diecimila_isp
|
||||
# make lilypad_isp
|
||||
# make ng_isp
|
||||
# etc...
|
||||
|
||||
# program name should not be changed...
|
||||
PROGRAM = optiboot
|
||||
|
||||
# The default behavior is to build using tools that are in the users
|
||||
# current path variables, but we can also build using an installed
|
||||
# Arduino user IDE setup, or the Arduino source tree.
|
||||
# Uncomment this next lines to build within the arduino environment,
|
||||
# using the arduino-included avrgcc toolset (mac and pc)
|
||||
# ENV ?= arduino
|
||||
# ENV ?= arduinodev
|
||||
# OS ?= macosx
|
||||
# OS ?= windows
|
||||
|
||||
|
||||
# enter the parameters for the avrdude isp tool -b19200
|
||||
#
|
||||
# These are the parameters for a usb-based STK500v2 programmer.
|
||||
# Exact type unknown. (historical Makefile values.)
|
||||
ISPTOOL = stk500v2
|
||||
ISPPORT = usb
|
||||
ISPSPEED = -b 57600
|
||||
#
|
||||
#
|
||||
# These are parameters for using an Arduino with the ArduinoISP sketch
|
||||
# as the programmer. On a mac, for a particular Uno as programmer.
|
||||
#ISPTOOL = stk500v1 -C /Applications/arduino/arduino-0022/hardware/tools/avr/etc/avrdude.conf
|
||||
#ISPPORT = /dev/tty.usbmodemfd3141
|
||||
#ISPSPEED = -b19200
|
||||
|
||||
MCU_TARGET = atmega168
|
||||
LDSECTIONS = -Wl,--section-start=.text=0x3e00 -Wl,--section-start=.version=0x3ffe
|
||||
|
||||
# Build environments
|
||||
# Start of some ugly makefile-isms to allow optiboot to be built
|
||||
# in several different environments. See the README.TXT file for
|
||||
# details.
|
||||
|
||||
# default
|
||||
fixpath = $(1)
|
||||
|
||||
ifeq ($(ENV), arduino)
|
||||
# For Arduino, we assume that we're connected to the optiboot directory
|
||||
# included with the arduino distribution, which means that the full set
|
||||
# of avr-tools are "right up there" in standard places.
|
||||
TOOLROOT = ../../../tools
|
||||
GCCROOT = $(TOOLROOT)/avr/bin/
|
||||
AVRDUDE_CONF = -C$(TOOLROOT)/avr/etc/avrdude.conf
|
||||
|
||||
ifeq ($(OS), windows)
|
||||
# On windows, SOME of the tool paths will need to have backslashes instead
|
||||
# of forward slashes (because they use windows cmd.exe for execution instead
|
||||
# of a unix/mingw shell?) We also have to ensure that a consistent shell
|
||||
# is used even if a unix shell is installed (ie as part of WINAVR)
|
||||
fixpath = $(subst /,\,$1)
|
||||
SHELL = cmd.exe
|
||||
endif
|
||||
|
||||
else ifeq ($(ENV), arduinodev)
|
||||
# Arduino IDE source code environment. Use the unpacked compilers created
|
||||
# by the build (you'll need to do "ant build" first.)
|
||||
ifeq ($(OS), macosx)
|
||||
TOOLROOT = ../../../../build/macosx/work/Arduino.app/Contents/Resources/Java/hardware/tools
|
||||
endif
|
||||
ifeq ($(OS), windows)
|
||||
TOOLROOT = ../../../../build/windows/work/hardware/tools
|
||||
endif
|
||||
|
||||
GCCROOT = $(TOOLROOT)/avr/bin/
|
||||
AVRDUDE_CONF = -C$(TOOLROOT)/avr/etc/avrdude.conf
|
||||
|
||||
else
|
||||
GCCROOT =
|
||||
AVRDUDE_CONF =
|
||||
endif
|
||||
#
|
||||
# End of build environment code.
|
||||
|
||||
|
||||
# the efuse should really be 0xf8; since, however, only the lower
|
||||
# three bits of that byte are used on the atmega168, avrdude gets
|
||||
# confused if you specify 1's for the higher bits, see:
|
||||
# http://tinker.it/now/2007/02/24/the-tale-of-avrdude-atmega168-and-extended-bits-fuses/
|
||||
#
|
||||
# similarly, the lock bits should be 0xff instead of 0x3f (to
|
||||
# unlock the bootloader section) and 0xcf instead of 0x2f (to
|
||||
# lock it), but since the high two bits of the lock byte are
|
||||
# unused, avrdude would get confused.
|
||||
|
||||
ISPFUSES = $(GCCROOT)avrdude $(AVRDUDE_CONF) -c $(ISPTOOL) \
|
||||
-p $(MCU_TARGET) -P $(ISPPORT) $(ISPSPEED) \
|
||||
-e -u -U lock:w:0x3f:m -U efuse:w:0x$(EFUSE):m \
|
||||
-U hfuse:w:0x$(HFUSE):m -U lfuse:w:0x$(LFUSE):m
|
||||
ISPFLASH = $(GCCROOT)avrdude $(AVRDUDE_CONF) -c $(ISPTOOL) \
|
||||
-p $(MCU_TARGET) -P $(ISPPORT) $(ISPSPEED) \
|
||||
-U flash:w:$(PROGRAM)_$(TARGET).hex -U lock:w:0x2f:m
|
||||
|
||||
STK500 = "C:\Program Files\Atmel\AVR Tools\STK500\Stk500.exe"
|
||||
STK500-1 = $(STK500) -e -d$(MCU_TARGET) -pf -vf -if$(PROGRAM)_$(TARGET).hex \
|
||||
-lFF -LFF -f$(HFUSE)$(LFUSE) -EF8 -ms -q -cUSB -I200kHz -s -wt
|
||||
STK500-2 = $(STK500) -d$(MCU_TARGET) -ms -q -lCF -LCF -cUSB -I200kHz -s -wt
|
||||
|
||||
OBJ = $(PROGRAM).o
|
||||
OPTIMIZE = -Os -fno-inline-small-functions -fno-split-wide-types
|
||||
# -mshort-calls
|
||||
|
||||
DEFS =
|
||||
LIBS =
|
||||
|
||||
CC = $(GCCROOT)avr-gcc
|
||||
|
||||
# Override is only needed by avr-lib build system.
|
||||
|
||||
override CFLAGS = -g -Wall $(OPTIMIZE) -mmcu=$(MCU_TARGET) -DF_CPU=$(AVR_FREQ) $(DEFS)
|
||||
override LDFLAGS = $(LDSECTIONS) -Wl,--relax -Wl,--gc-sections -nostartfiles -nostdlib
|
||||
|
||||
OBJCOPY = $(GCCROOT)avr-objcopy
|
||||
OBJDUMP = $(call fixpath,$(GCCROOT)avr-objdump)
|
||||
|
||||
SIZE = $(GCCROOT)avr-size
|
||||
|
||||
|
||||
|
||||
#Voice board test
|
||||
# ATmega328
|
||||
#
|
||||
#atmega328: TARGET = atmega328p
|
||||
#atmega328: MCU_TARGET = atmega328p
|
||||
#atmega328: CFLAGS += '-DLED_START_FLASHES=0' '-DBAUD_RATE=38400'
|
||||
#atmega328: AVR_FREQ = 12000000L
|
||||
#atmega328: LDSECTIONS = -Wl,--section-start=.text=0x7e00 -Wl,--section-start=.version=0x7ffe
|
||||
#atmega328: $(PROGRAM)_atmega328.hex
|
||||
#atmega328: $(PROGRAM)_atmega328.lst
|
||||
|
||||
atmega328: TARGET = atmega328
|
||||
atmega328: MCU_TARGET = atmega328p
|
||||
atmega328: CFLAGS += '-DLED_START_FLASHES=0' '-DBAUD_RATE=57600'
|
||||
atmega328: AVR_FREQ = 16000000L
|
||||
atmega328: LDSECTIONS = -Wl,--section-start=.text=0x7e00 -Wl,--section-start=.version=0x7ffe
|
||||
atmega328: $(PROGRAM)_atmega328_16.hex
|
||||
atmega328: $(PROGRAM)_atmega328_16.lst
|
||||
|
||||
|
||||
xmega32D4: TARGET = atxmega32d4
|
||||
xmega32D4: MCU_TARGET = atxmega32d4
|
||||
xmega32D4: CFLAGS += '-DLED_START_FLASHES=0' '-DBAUD_RATE=57600'
|
||||
xmega32D4: AVR_FREQ = 32000000L
|
||||
xmega32D4: LDSECTIONS = -Wl,--section-start=.text=0x8000
|
||||
xmega32D4: $(PROGRAM)_xmega32d4.hex
|
||||
xmega32D4: $(PROGRAM)_xmega32d4.lst
|
||||
|
||||
|
||||
# Test platforms
|
||||
# Virtual boot block test
|
||||
virboot328: TARGET = atmega328
|
||||
virboot328: MCU_TARGET = atmega328p
|
||||
virboot328: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=38400' '-DVIRTUAL_BOOT'
|
||||
virboot328: AVR_FREQ = 16000000L
|
||||
virboot328: LDSECTIONS = -Wl,--section-start=.text=0x7e00 -Wl,--section-start=.version=0x7ffe
|
||||
virboot328: $(PROGRAM)_atmega328.hex
|
||||
virboot328: $(PROGRAM)_atmega328.lst
|
||||
|
||||
# 20MHz clocked platforms
|
||||
#
|
||||
# These are capable of 230400 baud, or 38400 baud on PC (Arduino Avrdude issue)
|
||||
#
|
||||
|
||||
pro20: TARGET = pro_20mhz
|
||||
pro20: MCU_TARGET = atmega168
|
||||
pro20: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=38400'
|
||||
pro20: AVR_FREQ = 20000000L
|
||||
pro20: $(PROGRAM)_pro_20mhz.hex
|
||||
pro20: $(PROGRAM)_pro_20mhz.lst
|
||||
|
||||
pro20_isp: pro20
|
||||
pro20_isp: TARGET = pro_20mhz
|
||||
# 2.7V brownout
|
||||
pro20_isp: HFUSE = DD
|
||||
# Full swing xtal (20MHz) 258CK/14CK+4.1ms
|
||||
pro20_isp: LFUSE = C6
|
||||
# 512 byte boot
|
||||
pro20_isp: EFUSE = 04
|
||||
pro20_isp: isp
|
||||
|
||||
# 16MHz clocked platforms
|
||||
#
|
||||
# These are capable of 230400 baud, or 38400 baud on PC (Arduino Avrdude issue)
|
||||
#
|
||||
|
||||
pro16: TARGET = pro_16MHz
|
||||
pro16: MCU_TARGET = atmega168
|
||||
pro16: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=38400'
|
||||
pro16: AVR_FREQ = 16000000L
|
||||
pro16: $(PROGRAM)_pro_16MHz.hex
|
||||
pro16: $(PROGRAM)_pro_16MHz.lst
|
||||
|
||||
pro16_isp: pro16
|
||||
pro16_isp: TARGET = pro_16MHz
|
||||
# 2.7V brownout
|
||||
pro16_isp: HFUSE = DD
|
||||
# Full swing xtal (20MHz) 258CK/14CK+4.1ms
|
||||
pro16_isp: LFUSE = C6
|
||||
# 512 byte boot
|
||||
pro16_isp: EFUSE = 04
|
||||
pro16_isp: isp
|
||||
|
||||
# Diecimila, Duemilanove with m168, and NG use identical bootloaders
|
||||
# Call it "atmega168" for generality and clarity, keep "diecimila" for
|
||||
# backward compatibility of makefile
|
||||
#
|
||||
atmega168: TARGET = atmega168
|
||||
atmega168: MCU_TARGET = atmega168
|
||||
atmega168: CFLAGS += '-DLED_START_FLASHES=0' '-DBAUD_RATE=38400'
|
||||
atmega168: AVR_FREQ = 12000000L
|
||||
atmega168: $(PROGRAM)_atmega168.hex
|
||||
atmega168: $(PROGRAM)_atmega168.lst
|
||||
|
||||
atmega168_isp: atmega168
|
||||
atmega168_isp: TARGET = atmega168
|
||||
# 2.7V brownout
|
||||
atmega168_isp: HFUSE = DD
|
||||
# Low power xtal (16MHz) 16KCK/14CK+65ms
|
||||
atmega168_isp: LFUSE = FF
|
||||
# 512 byte boot
|
||||
atmega168_isp: EFUSE = 04
|
||||
atmega168_isp: isp
|
||||
|
||||
diecimila: TARGET = diecimila
|
||||
diecimila: MCU_TARGET = atmega168
|
||||
diecimila: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=38400'
|
||||
diecimila: AVR_FREQ = 16000000L
|
||||
diecimila: $(PROGRAM)_diecimila.hex
|
||||
diecimila: $(PROGRAM)_diecimila.lst
|
||||
|
||||
diecimila_isp: diecimila
|
||||
diecimila_isp: TARGET = diecimila
|
||||
# 2.7V brownout
|
||||
diecimila_isp: HFUSE = DD
|
||||
# Low power xtal (16MHz) 16KCK/14CK+65ms
|
||||
diecimila_isp: LFUSE = FF
|
||||
# 512 byte boot
|
||||
diecimila_isp: EFUSE = 04
|
||||
diecimila_isp: isp
|
||||
|
||||
atmega328_isp: atmega328
|
||||
atmega328_isp: TARGET = atmega328
|
||||
atmega328_isp: MCU_TARGET = atmega328p
|
||||
# 512 byte boot, SPIEN
|
||||
atmega328_isp: HFUSE = DE
|
||||
# Low power xtal (16MHz) 16KCK/14CK+65ms
|
||||
atmega328_isp: LFUSE = FF
|
||||
# 2.7V brownout
|
||||
atmega328_isp: EFUSE = FD
|
||||
atmega328_isp: isp
|
||||
|
||||
atmega1284: TARGET = atmega1284p
|
||||
atmega1284: MCU_TARGET = atmega1284p
|
||||
atmega1284: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=38400' '-DBIGBOOT'
|
||||
atmega1284: AVR_FREQ = 16000000L
|
||||
atmega1284: LDSECTIONS = -Wl,--section-start=.text=0x1fc00 -Wl,--section-start=.version=0x1fffe
|
||||
atmega1284: $(PROGRAM)_atmega1284p.hex
|
||||
atmega1284: $(PROGRAM)_atmega1284p.lst
|
||||
|
||||
atmega1284_isp: atmega1284
|
||||
atmega1284_isp: TARGET = atmega1284p
|
||||
atmega1284_isp: MCU_TARGET = atmega1284p
|
||||
# 1024 byte boot
|
||||
atmega1284_isp: HFUSE = DE
|
||||
# Low power xtal (16MHz) 16KCK/14CK+65ms
|
||||
atmega1284_isp: LFUSE = FF
|
||||
# 2.7V brownout
|
||||
atmega1284_isp: EFUSE = FD
|
||||
atmega1284_isp: isp
|
||||
|
||||
# Sanguino has a minimum boot size of 1024 bytes, so enable extra functions
|
||||
#
|
||||
sanguino: TARGET = atmega644p
|
||||
sanguino: MCU_TARGET = atmega644p
|
||||
sanguino: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=38400' '-DBIGBOOT'
|
||||
sanguino: AVR_FREQ = 16000000L
|
||||
sanguino: LDSECTIONS = -Wl,--section-start=.text=0xfc00 -Wl,--section-start=.version=0xfffe
|
||||
sanguino: $(PROGRAM)_atmega644p.hex
|
||||
sanguino: $(PROGRAM)_atmega644p.lst
|
||||
|
||||
sanguino_isp: sanguino
|
||||
sanguino_isp: TARGET = atmega644p
|
||||
sanguino_isp: MCU_TARGET = atmega644p
|
||||
# 1024 byte boot
|
||||
sanguino_isp: HFUSE = DE
|
||||
# Low power xtal (16MHz) 16KCK/14CK+65ms
|
||||
sanguino_isp: LFUSE = FF
|
||||
# 2.7V brownout
|
||||
sanguino_isp: EFUSE = FD
|
||||
sanguino_isp: isp
|
||||
|
||||
# Mega has a minimum boot size of 1024 bytes, so enable extra functions
|
||||
#mega: TARGET = atmega1280
|
||||
mega1280: MCU_TARGET = atmega1280
|
||||
mega1280: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=38400' '-DBIGBOOT'
|
||||
mega1280: AVR_FREQ = 16000000L
|
||||
mega1280: LDSECTIONS = -Wl,--section-start=.text=0x1fc00 -Wl,--section-start=.version=0x1fffe
|
||||
mega1280: $(PROGRAM)_atmega1280.hex
|
||||
mega1280: $(PROGRAM)_atmega1280.lst
|
||||
|
||||
mega1280_isp: mega
|
||||
mega1280_isp: TARGET = atmega1280
|
||||
mega1280_isp: MCU_TARGET = atmega1280
|
||||
# 1024 byte boot
|
||||
mega1280_isp: HFUSE = DE
|
||||
# Low power xtal (16MHz) 16KCK/14CK+65ms
|
||||
mega1280_isp: LFUSE = FF
|
||||
# 2.7V brownout
|
||||
mega1280_isp: EFUSE = FD
|
||||
mega1280_isp: isp
|
||||
|
||||
# ATmega8
|
||||
#
|
||||
atmega8: TARGET = atmega8
|
||||
atmega8: MCU_TARGET = atmega8
|
||||
atmega8: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=38400'
|
||||
atmega8: AVR_FREQ = 16000000L
|
||||
atmega8: LDSECTIONS = -Wl,--section-start=.text=0x1e00 -Wl,--section-start=.version=0x1ffe
|
||||
atmega8: $(PROGRAM)_atmega8.hex
|
||||
atmega8: $(PROGRAM)_atmega8.lst
|
||||
|
||||
atmega8_isp: atmega8
|
||||
atmega8_isp: TARGET = atmega8
|
||||
atmega8_isp: MCU_TARGET = atmega8
|
||||
# SPIEN, CKOPT, Bootsize=512B
|
||||
atmega8_isp: HFUSE = CC
|
||||
# 2.7V brownout, Low power xtal (16MHz) 16KCK/14CK+65ms
|
||||
atmega8_isp: LFUSE = BF
|
||||
atmega8_isp: isp
|
||||
|
||||
# ATmega88
|
||||
#
|
||||
atmega88: TARGET = atmega88
|
||||
atmega88: MCU_TARGET = atmega88
|
||||
atmega88: CFLAGS += '-DLED_START_FLASHES=0' '-DBAUD_RATE=38400'
|
||||
atmega88: AVR_FREQ = 12000000L
|
||||
atmega88: LDSECTIONS = -Wl,--section-start=.text=0x1e00 -Wl,--section-start=.version=0x1ffe
|
||||
atmega88: $(PROGRAM)_atmega88.hex
|
||||
atmega88: $(PROGRAM)_atmega88.lst
|
||||
|
||||
atmega88_isp: atmega88
|
||||
atmega88_isp: TARGET = atmega88
|
||||
atmega88_isp: MCU_TARGET = atmega88
|
||||
# 2.7V brownout
|
||||
atmega88_isp: HFUSE = DD
|
||||
# Low power xtal (16MHz) 16KCK/14CK+65ms
|
||||
atemga88_isp: LFUSE = FF
|
||||
# 512 byte boot
|
||||
atmega88_isp: EFUSE = 04
|
||||
atmega88_isp: isp
|
||||
|
||||
|
||||
# 8MHz clocked platforms
|
||||
#
|
||||
# These are capable of 38400 baud
|
||||
#
|
||||
|
||||
lilypad: TARGET = lilypad
|
||||
lilypad: MCU_TARGET = atmega168
|
||||
lilypad: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=38400'
|
||||
lilypad: AVR_FREQ = 8000000L
|
||||
lilypad: $(PROGRAM)_lilypad.hex
|
||||
lilypad: $(PROGRAM)_lilypad.lst
|
||||
|
||||
lilypad_isp: lilypad
|
||||
lilypad_isp: TARGET = lilypad
|
||||
# 2.7V brownout
|
||||
lilypad_isp: HFUSE = DD
|
||||
# Internal 8MHz osc (8MHz) Slow rising power
|
||||
lilypad_isp: LFUSE = E2
|
||||
# 512 byte boot
|
||||
lilypad_isp: EFUSE = 04
|
||||
lilypad_isp: isp
|
||||
|
||||
lilypad_resonator: TARGET = lilypad_resonator
|
||||
lilypad_resonator: MCU_TARGET = atmega168
|
||||
lilypad_resonator: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=38400'
|
||||
lilypad_resonator: AVR_FREQ = 8000000L
|
||||
lilypad_resonator: $(PROGRAM)_lilypad_resonator.hex
|
||||
lilypad_resonator: $(PROGRAM)_lilypad_resonator.lst
|
||||
|
||||
lilypad_resonator_isp: lilypad_resonator
|
||||
lilypad_resonator_isp: TARGET = lilypad_resonator
|
||||
# 2.7V brownout
|
||||
lilypad_resonator_isp: HFUSE = DD
|
||||
# Full swing xtal (20MHz) 258CK/14CK+4.1ms
|
||||
lilypad_resonator_isp: LFUSE = C6
|
||||
# 512 byte boot
|
||||
lilypad_resonator_isp: EFUSE = 04
|
||||
lilypad_resonator_isp: isp
|
||||
|
||||
pro8: TARGET = pro_8MHz
|
||||
pro8: MCU_TARGET = atmega168
|
||||
pro8: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=38400'
|
||||
pro8: AVR_FREQ = 8000000L
|
||||
pro8: $(PROGRAM)_pro_8MHz.hex
|
||||
pro8: $(PROGRAM)_pro_8MHz.lst
|
||||
|
||||
pro8_isp: pro8
|
||||
pro8_isp: TARGET = pro_8MHz
|
||||
# 2.7V brownout
|
||||
pro8_isp: HFUSE = DD
|
||||
# Full swing xtal (20MHz) 258CK/14CK+4.1ms
|
||||
pro8_isp: LFUSE = C6
|
||||
# 512 byte boot
|
||||
pro8_isp: EFUSE = 04
|
||||
pro8_isp: isp
|
||||
|
||||
atmega328_pro8: TARGET = atmega328_pro_8MHz
|
||||
atmega328_pro8: MCU_TARGET = atmega328p
|
||||
atmega328_pro8: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=38400'
|
||||
atmega328_pro8: AVR_FREQ = 8000000L
|
||||
atmega328_pro8: LDSECTIONS = -Wl,--section-start=.text=0x7e00 -Wl,--section-start=.version=0x7ffe
|
||||
atmega328_pro8: $(PROGRAM)_atmega328_pro_8MHz.hex
|
||||
atmega328_pro8: $(PROGRAM)_atmega328_pro_8MHz.lst
|
||||
|
||||
atmega328_pro8_isp: atmega328_pro8
|
||||
atmega328_pro8_isp: TARGET = atmega328_pro_8MHz
|
||||
atmega328_pro8_isp: MCU_TARGET = atmega328p
|
||||
# 512 byte boot, SPIEN
|
||||
atmega328_pro8_isp: HFUSE = DE
|
||||
# Low power xtal (16MHz) 16KCK/14CK+65ms
|
||||
atmega328_pro8_isp: LFUSE = FF
|
||||
# 2.7V brownout
|
||||
atmega328_pro8_isp: EFUSE = DE
|
||||
atmega328_pro8_isp: isp
|
||||
|
||||
# 1MHz clocked platforms
|
||||
#
|
||||
# These are capable of 9600 baud
|
||||
#
|
||||
|
||||
luminet: TARGET = luminet
|
||||
luminet: MCU_TARGET = attiny84
|
||||
luminet: CFLAGS += '-DLED_START_FLASHES=3' '-DSOFT_UART' '-DBAUD_RATE=9600'
|
||||
luminet: CFLAGS += '-DVIRTUAL_BOOT_PARTITION'
|
||||
luminet: AVR_FREQ = 1000000L
|
||||
luminet: LDSECTIONS = -Wl,--section-start=.text=0x1d00 -Wl,--section-start=.version=0x1efe
|
||||
luminet: $(PROGRAM)_luminet.hex
|
||||
luminet: $(PROGRAM)_luminet.lst
|
||||
|
||||
luminet_isp: luminet
|
||||
luminet_isp: TARGET = luminet
|
||||
luminet_isp: MCU_TARGET = attiny84
|
||||
# Brownout disabled
|
||||
luminet_isp: HFUSE = DF
|
||||
# 1MHz internal oscillator, slowly rising power
|
||||
luminet_isp: LFUSE = 62
|
||||
# Self-programming enable
|
||||
luminet_isp: EFUSE = FE
|
||||
luminet_isp: isp
|
||||
|
||||
#
|
||||
# Generic build instructions
|
||||
#
|
||||
#
|
||||
|
||||
isp: $(TARGET)
|
||||
$(ISPFUSES)
|
||||
$(ISPFLASH)
|
||||
|
||||
isp-stk500: $(PROGRAM)_$(TARGET).hex
|
||||
$(STK500-1)
|
||||
$(STK500-2)
|
||||
|
||||
%.elf: $(OBJ)
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||
$(SIZE) $@
|
||||
|
||||
clean:
|
||||
rm -rf *.o *.elf *.lst *.map *.sym *.lss *.eep *.srec *.bin *.hex
|
||||
|
||||
%.lst: %.elf
|
||||
$(OBJDUMP) -h -S $< > $@
|
||||
|
||||
%.hex: %.elf
|
||||
$(OBJCOPY) -j .text -j .data -j .version --set-section-flags .version=alloc,load -O ihex $< $@
|
||||
|
||||
%.srec: %.elf
|
||||
$(OBJCOPY) -j .text -j .data -j .version --set-section-flags .version=alloc,load -O srec $< $@
|
||||
|
||||
%.bin: %.elf
|
||||
$(OBJCOPY) -j .text -j .data -j .version --set-section-flags .version=alloc,load -O binary $< $@
|
@ -1,848 +0,0 @@
|
||||
/* Modified to use out for SPM access
|
||||
** Peter Knight, Optiboot project http://optiboot.googlecode.com
|
||||
**
|
||||
** Todo: Tidy up
|
||||
**
|
||||
** "_short" routines execute 1 cycle faster and use 1 less word of flash
|
||||
** by using "out" instruction instead of "sts".
|
||||
**
|
||||
** Additional elpm variants that trust the value of RAMPZ
|
||||
*/
|
||||
|
||||
/* Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007 Eric B. Weddington
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of the copyright holders nor the names of
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE. */
|
||||
|
||||
/* $Id: boot.h,v 1.27.2.3 2008/09/30 13:58:48 arcanum Exp $ */
|
||||
|
||||
#ifndef _AVR_BOOT_H_
|
||||
#define _AVR_BOOT_H_ 1
|
||||
|
||||
/** \file */
|
||||
/** \defgroup avr_boot <avr/boot.h>: Bootloader Support Utilities
|
||||
\code
|
||||
#include <avr/io.h>
|
||||
#include <avr/boot.h>
|
||||
\endcode
|
||||
|
||||
The macros in this module provide a C language interface to the
|
||||
bootloader support functionality of certain AVR processors. These
|
||||
macros are designed to work with all sizes of flash memory.
|
||||
|
||||
Global interrupts are not automatically disabled for these macros. It
|
||||
is left up to the programmer to do this. See the code example below.
|
||||
Also see the processor datasheet for caveats on having global interrupts
|
||||
enabled during writing of the Flash.
|
||||
|
||||
\note Not all AVR processors provide bootloader support. See your
|
||||
processor datasheet to see if it provides bootloader support.
|
||||
|
||||
\todo From email with Marek: On smaller devices (all except ATmega64/128),
|
||||
__SPM_REG is in the I/O space, accessible with the shorter "in" and "out"
|
||||
instructions - since the boot loader has a limited size, this could be an
|
||||
important optimization.
|
||||
|
||||
\par API Usage Example
|
||||
The following code shows typical usage of the boot API.
|
||||
|
||||
\code
|
||||
#include <inttypes.h>
|
||||
#include <avr/interrupt.h>
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
void boot_program_page (uint32_t page, uint8_t *buf)
|
||||
{
|
||||
uint16_t i;
|
||||
uint8_t sreg;
|
||||
|
||||
// Disable interrupts.
|
||||
|
||||
sreg = SREG;
|
||||
cli();
|
||||
|
||||
eeprom_busy_wait ();
|
||||
|
||||
boot_page_erase (page);
|
||||
boot_spm_busy_wait (); // Wait until the memory is erased.
|
||||
|
||||
for (i=0; i<SPM_PAGESIZE; i+=2)
|
||||
{
|
||||
// Set up little-endian word.
|
||||
|
||||
uint16_t w = *buf++;
|
||||
w += (*buf++) << 8;
|
||||
|
||||
boot_page_fill (page + i, w);
|
||||
}
|
||||
|
||||
boot_page_write (page); // Store buffer in flash page.
|
||||
boot_spm_busy_wait(); // Wait until the memory is written.
|
||||
|
||||
// Reenable RWW-section again. We need this if we want to jump back
|
||||
// to the application after bootloading.
|
||||
|
||||
boot_rww_enable ();
|
||||
|
||||
// Re-enable interrupts (if they were ever enabled).
|
||||
|
||||
SREG = sreg;
|
||||
}\endcode */
|
||||
|
||||
#include <avr/eeprom.h>
|
||||
#include <avr/io.h>
|
||||
#include <inttypes.h>
|
||||
#include <limits.h>
|
||||
|
||||
/* Check for SPM Control Register in processor. */
|
||||
#if defined (SPMCSR)
|
||||
# define __SPM_REG SPMCSR
|
||||
#elif defined (SPMCR)
|
||||
# define __SPM_REG SPMCR
|
||||
#else
|
||||
# error AVR processor does not provide bootloader support!
|
||||
#endif
|
||||
|
||||
|
||||
/* Check for SPM Enable bit. */
|
||||
#if defined(SPMEN)
|
||||
# define __SPM_ENABLE SPMEN
|
||||
#elif defined(SELFPRGEN)
|
||||
# define __SPM_ENABLE SELFPRGEN
|
||||
#else
|
||||
# error Cannot find SPM Enable bit definition!
|
||||
#endif
|
||||
|
||||
/** \ingroup avr_boot
|
||||
\def BOOTLOADER_SECTION
|
||||
|
||||
Used to declare a function or variable to be placed into a
|
||||
new section called .bootloader. This section and its contents
|
||||
can then be relocated to any address (such as the bootloader
|
||||
NRWW area) at link-time. */
|
||||
|
||||
#define BOOTLOADER_SECTION __attribute__ ((section (".bootloader")))
|
||||
|
||||
/* Create common bit definitions. */
|
||||
#ifdef ASB
|
||||
#define __COMMON_ASB ASB
|
||||
#else
|
||||
#define __COMMON_ASB RWWSB
|
||||
#endif
|
||||
|
||||
#ifdef ASRE
|
||||
#define __COMMON_ASRE ASRE
|
||||
#else
|
||||
#define __COMMON_ASRE RWWSRE
|
||||
#endif
|
||||
|
||||
/* Define the bit positions of the Boot Lock Bits. */
|
||||
|
||||
#define BLB12 5
|
||||
#define BLB11 4
|
||||
#define BLB02 3
|
||||
#define BLB01 2
|
||||
|
||||
/** \ingroup avr_boot
|
||||
\def boot_spm_interrupt_enable()
|
||||
Enable the SPM interrupt. */
|
||||
|
||||
#define boot_spm_interrupt_enable() (__SPM_REG |= (uint8_t)_BV(SPMIE))
|
||||
|
||||
/** \ingroup avr_boot
|
||||
\def boot_spm_interrupt_disable()
|
||||
Disable the SPM interrupt. */
|
||||
|
||||
#define boot_spm_interrupt_disable() (__SPM_REG &= (uint8_t)~_BV(SPMIE))
|
||||
|
||||
/** \ingroup avr_boot
|
||||
\def boot_is_spm_interrupt()
|
||||
Check if the SPM interrupt is enabled. */
|
||||
|
||||
#define boot_is_spm_interrupt() (__SPM_REG & (uint8_t)_BV(SPMIE))
|
||||
|
||||
/** \ingroup avr_boot
|
||||
\def boot_rww_busy()
|
||||
Check if the RWW section is busy. */
|
||||
|
||||
#define boot_rww_busy() (__SPM_REG & (uint8_t)_BV(__COMMON_ASB))
|
||||
|
||||
/** \ingroup avr_boot
|
||||
\def boot_spm_busy()
|
||||
Check if the SPM instruction is busy. */
|
||||
|
||||
#define boot_spm_busy() (__SPM_REG & (uint8_t)_BV(__SPM_ENABLE))
|
||||
|
||||
/** \ingroup avr_boot
|
||||
\def boot_spm_busy_wait()
|
||||
Wait while the SPM instruction is busy. */
|
||||
|
||||
#define boot_spm_busy_wait() do{}while(boot_spm_busy())
|
||||
|
||||
#define __BOOT_PAGE_ERASE (_BV(__SPM_ENABLE) | _BV(PGERS))
|
||||
#define __BOOT_PAGE_WRITE (_BV(__SPM_ENABLE) | _BV(PGWRT))
|
||||
#define __BOOT_PAGE_FILL _BV(__SPM_ENABLE)
|
||||
#define __BOOT_RWW_ENABLE (_BV(__SPM_ENABLE) | _BV(__COMMON_ASRE))
|
||||
#define __BOOT_LOCK_BITS_SET (_BV(__SPM_ENABLE) | _BV(BLBSET))
|
||||
|
||||
#define __boot_page_fill_short(address, data) \
|
||||
(__extension__({ \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"movw r0, %3\n\t" \
|
||||
"out %0, %1\n\t" \
|
||||
"spm\n\t" \
|
||||
"clr r1\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_IO_ADDR(__SPM_REG)), \
|
||||
"r" ((uint8_t)__BOOT_PAGE_FILL), \
|
||||
"z" ((uint16_t)address), \
|
||||
"r" ((uint16_t)data) \
|
||||
: "r0" \
|
||||
); \
|
||||
}))
|
||||
|
||||
#define __boot_page_fill_normal(address, data) \
|
||||
(__extension__({ \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"movw r0, %3\n\t" \
|
||||
"sts %0, %1\n\t" \
|
||||
"spm\n\t" \
|
||||
"clr r1\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_MEM_ADDR(__SPM_REG)), \
|
||||
"r" ((uint8_t)__BOOT_PAGE_FILL), \
|
||||
"z" ((uint16_t)address), \
|
||||
"r" ((uint16_t)data) \
|
||||
: "r0" \
|
||||
); \
|
||||
}))
|
||||
|
||||
#define __boot_page_fill_alternate(address, data)\
|
||||
(__extension__({ \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"movw r0, %3\n\t" \
|
||||
"sts %0, %1\n\t" \
|
||||
"spm\n\t" \
|
||||
".word 0xffff\n\t" \
|
||||
"nop\n\t" \
|
||||
"clr r1\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_MEM_ADDR(__SPM_REG)), \
|
||||
"r" ((uint8_t)__BOOT_PAGE_FILL), \
|
||||
"z" ((uint16_t)address), \
|
||||
"r" ((uint16_t)data) \
|
||||
: "r0" \
|
||||
); \
|
||||
}))
|
||||
|
||||
#define __boot_page_fill_extended(address, data) \
|
||||
(__extension__({ \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"movw r0, %4\n\t" \
|
||||
"movw r30, %A3\n\t" \
|
||||
"sts %1, %C3\n\t" \
|
||||
"sts %0, %2\n\t" \
|
||||
"spm\n\t" \
|
||||
"clr r1\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_MEM_ADDR(__SPM_REG)), \
|
||||
"i" (_SFR_MEM_ADDR(RAMPZ)), \
|
||||
"r" ((uint8_t)__BOOT_PAGE_FILL), \
|
||||
"r" ((uint32_t)address), \
|
||||
"r" ((uint16_t)data) \
|
||||
: "r0", "r30", "r31" \
|
||||
); \
|
||||
}))
|
||||
|
||||
#define __boot_page_fill_extended_short(address, data) \
|
||||
(__extension__({ \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"movw r0, %4\n\t" \
|
||||
"movw r30, %A3\n\t" \
|
||||
"out %1, %C3\n\t" \
|
||||
"out %0, %2\n\t" \
|
||||
"spm\n\t" \
|
||||
"clr r1\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_IO_ADDR(__SPM_REG)), \
|
||||
"i" (_SFR_IO_ADDR(RAMPZ)), \
|
||||
"r" ((uint8_t)__BOOT_PAGE_FILL), \
|
||||
"r" ((uint32_t)address), \
|
||||
"r" ((uint16_t)data) \
|
||||
: "r0", "r30", "r31" \
|
||||
); \
|
||||
}))
|
||||
|
||||
#define __boot_page_erase_short(address) \
|
||||
(__extension__({ \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"out %0, %1\n\t" \
|
||||
"spm\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_IO_ADDR(__SPM_REG)), \
|
||||
"r" ((uint8_t)__BOOT_PAGE_ERASE), \
|
||||
"z" ((uint16_t)address) \
|
||||
); \
|
||||
}))
|
||||
|
||||
|
||||
#define __boot_page_erase_normal(address) \
|
||||
(__extension__({ \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"sts %0, %1\n\t" \
|
||||
"spm\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_MEM_ADDR(__SPM_REG)), \
|
||||
"r" ((uint8_t)__BOOT_PAGE_ERASE), \
|
||||
"z" ((uint16_t)address) \
|
||||
); \
|
||||
}))
|
||||
|
||||
#define __boot_page_erase_alternate(address) \
|
||||
(__extension__({ \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"sts %0, %1\n\t" \
|
||||
"spm\n\t" \
|
||||
".word 0xffff\n\t" \
|
||||
"nop\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_MEM_ADDR(__SPM_REG)), \
|
||||
"r" ((uint8_t)__BOOT_PAGE_ERASE), \
|
||||
"z" ((uint16_t)address) \
|
||||
); \
|
||||
}))
|
||||
|
||||
#define __boot_page_erase_extended(address) \
|
||||
(__extension__({ \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"movw r30, %A3\n\t" \
|
||||
"sts %1, %C3\n\t" \
|
||||
"sts %0, %2\n\t" \
|
||||
"spm\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_MEM_ADDR(__SPM_REG)), \
|
||||
"i" (_SFR_MEM_ADDR(RAMPZ)), \
|
||||
"r" ((uint8_t)__BOOT_PAGE_ERASE), \
|
||||
"r" ((uint32_t)address) \
|
||||
: "r30", "r31" \
|
||||
); \
|
||||
}))
|
||||
#define __boot_page_erase_extended_short(address) \
|
||||
(__extension__({ \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"movw r30, %A3\n\t" \
|
||||
"out %1, %C3\n\t" \
|
||||
"out %0, %2\n\t" \
|
||||
"spm\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_IO_ADDR(__SPM_REG)), \
|
||||
"i" (_SFR_IO_ADDR(RAMPZ)), \
|
||||
"r" ((uint8_t)__BOOT_PAGE_ERASE), \
|
||||
"r" ((uint32_t)address) \
|
||||
: "r30", "r31" \
|
||||
); \
|
||||
}))
|
||||
|
||||
#define __boot_page_write_short(address) \
|
||||
(__extension__({ \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"out %0, %1\n\t" \
|
||||
"spm\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_IO_ADDR(__SPM_REG)), \
|
||||
"r" ((uint8_t)__BOOT_PAGE_WRITE), \
|
||||
"z" ((uint16_t)address) \
|
||||
); \
|
||||
}))
|
||||
|
||||
#define __boot_page_write_normal(address) \
|
||||
(__extension__({ \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"sts %0, %1\n\t" \
|
||||
"spm\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_MEM_ADDR(__SPM_REG)), \
|
||||
"r" ((uint8_t)__BOOT_PAGE_WRITE), \
|
||||
"z" ((uint16_t)address) \
|
||||
); \
|
||||
}))
|
||||
|
||||
#define __boot_page_write_alternate(address) \
|
||||
(__extension__({ \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"sts %0, %1\n\t" \
|
||||
"spm\n\t" \
|
||||
".word 0xffff\n\t" \
|
||||
"nop\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_MEM_ADDR(__SPM_REG)), \
|
||||
"r" ((uint8_t)__BOOT_PAGE_WRITE), \
|
||||
"z" ((uint16_t)address) \
|
||||
); \
|
||||
}))
|
||||
|
||||
#define __boot_page_write_extended(address) \
|
||||
(__extension__({ \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"movw r30, %A3\n\t" \
|
||||
"sts %1, %C3\n\t" \
|
||||
"sts %0, %2\n\t" \
|
||||
"spm\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_MEM_ADDR(__SPM_REG)), \
|
||||
"i" (_SFR_MEM_ADDR(RAMPZ)), \
|
||||
"r" ((uint8_t)__BOOT_PAGE_WRITE), \
|
||||
"r" ((uint32_t)address) \
|
||||
: "r30", "r31" \
|
||||
); \
|
||||
}))
|
||||
#define __boot_page_write_extended_short(address) \
|
||||
(__extension__({ \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"movw r30, %A3\n\t" \
|
||||
"out %1, %C3\n\t" \
|
||||
"out %0, %2\n\t" \
|
||||
"spm\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_IO_ADDR(__SPM_REG)), \
|
||||
"i" (_SFR_IO_ADDR(RAMPZ)), \
|
||||
"r" ((uint8_t)__BOOT_PAGE_WRITE), \
|
||||
"r" ((uint32_t)address) \
|
||||
: "r30", "r31" \
|
||||
); \
|
||||
}))
|
||||
|
||||
#define __boot_rww_enable_short() \
|
||||
(__extension__({ \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"out %0, %1\n\t" \
|
||||
"spm\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_IO_ADDR(__SPM_REG)), \
|
||||
"r" ((uint8_t)__BOOT_RWW_ENABLE) \
|
||||
); \
|
||||
}))
|
||||
|
||||
#define __boot_rww_enable() \
|
||||
(__extension__({ \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"sts %0, %1\n\t" \
|
||||
"spm\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_MEM_ADDR(__SPM_REG)), \
|
||||
"r" ((uint8_t)__BOOT_RWW_ENABLE) \
|
||||
); \
|
||||
}))
|
||||
|
||||
#define __boot_rww_enable_alternate() \
|
||||
(__extension__({ \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"sts %0, %1\n\t" \
|
||||
"spm\n\t" \
|
||||
".word 0xffff\n\t" \
|
||||
"nop\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_MEM_ADDR(__SPM_REG)), \
|
||||
"r" ((uint8_t)__BOOT_RWW_ENABLE) \
|
||||
); \
|
||||
}))
|
||||
|
||||
/* From the mega16/mega128 data sheets (maybe others):
|
||||
|
||||
Bits by SPM To set the Boot Loader Lock bits, write the desired data to
|
||||
R0, write "X0001001" to SPMCR and execute SPM within four clock cycles
|
||||
after writing SPMCR. The only accessible Lock bits are the Boot Lock bits
|
||||
that may prevent the Application and Boot Loader section from any
|
||||
software update by the MCU.
|
||||
|
||||
If bits 5..2 in R0 are cleared (zero), the corresponding Boot Lock bit
|
||||
will be programmed if an SPM instruction is executed within four cycles
|
||||
after BLBSET and SPMEN (or SELFPRGEN) are set in SPMCR. The Z-pointer is
|
||||
don't care during this operation, but for future compatibility it is
|
||||
recommended to load the Z-pointer with $0001 (same as used for reading the
|
||||
Lock bits). For future compatibility It is also recommended to set bits 7,
|
||||
6, 1, and 0 in R0 to 1 when writing the Lock bits. When programming the
|
||||
Lock bits the entire Flash can be read during the operation. */
|
||||
|
||||
#define __boot_lock_bits_set_short(lock_bits) \
|
||||
(__extension__({ \
|
||||
uint8_t value = (uint8_t)(~(lock_bits)); \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"ldi r30, 1\n\t" \
|
||||
"ldi r31, 0\n\t" \
|
||||
"mov r0, %2\n\t" \
|
||||
"out %0, %1\n\t" \
|
||||
"spm\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_IO_ADDR(__SPM_REG)), \
|
||||
"r" ((uint8_t)__BOOT_LOCK_BITS_SET), \
|
||||
"r" (value) \
|
||||
: "r0", "r30", "r31" \
|
||||
); \
|
||||
}))
|
||||
|
||||
#define __boot_lock_bits_set(lock_bits) \
|
||||
(__extension__({ \
|
||||
uint8_t value = (uint8_t)(~(lock_bits)); \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"ldi r30, 1\n\t" \
|
||||
"ldi r31, 0\n\t" \
|
||||
"mov r0, %2\n\t" \
|
||||
"sts %0, %1\n\t" \
|
||||
"spm\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_MEM_ADDR(__SPM_REG)), \
|
||||
"r" ((uint8_t)__BOOT_LOCK_BITS_SET), \
|
||||
"r" (value) \
|
||||
: "r0", "r30", "r31" \
|
||||
); \
|
||||
}))
|
||||
|
||||
#define __boot_lock_bits_set_alternate(lock_bits) \
|
||||
(__extension__({ \
|
||||
uint8_t value = (uint8_t)(~(lock_bits)); \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"ldi r30, 1\n\t" \
|
||||
"ldi r31, 0\n\t" \
|
||||
"mov r0, %2\n\t" \
|
||||
"sts %0, %1\n\t" \
|
||||
"spm\n\t" \
|
||||
".word 0xffff\n\t" \
|
||||
"nop\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_MEM_ADDR(__SPM_REG)), \
|
||||
"r" ((uint8_t)__BOOT_LOCK_BITS_SET), \
|
||||
"r" (value) \
|
||||
: "r0", "r30", "r31" \
|
||||
); \
|
||||
}))
|
||||
|
||||
/*
|
||||
Reading lock and fuse bits:
|
||||
|
||||
Similarly to writing the lock bits above, set BLBSET and SPMEN (or
|
||||
SELFPRGEN) bits in __SPMREG, and then (within four clock cycles) issue an
|
||||
LPM instruction.
|
||||
|
||||
Z address: contents:
|
||||
0x0000 low fuse bits
|
||||
0x0001 lock bits
|
||||
0x0002 extended fuse bits
|
||||
0x0003 high fuse bits
|
||||
|
||||
Sounds confusing, doesn't it?
|
||||
|
||||
Unlike the macros in pgmspace.h, no need to care for non-enhanced
|
||||
cores here as these old cores do not provide SPM support anyway.
|
||||
*/
|
||||
|
||||
/** \ingroup avr_boot
|
||||
\def GET_LOW_FUSE_BITS
|
||||
address to read the low fuse bits, using boot_lock_fuse_bits_get
|
||||
*/
|
||||
#define GET_LOW_FUSE_BITS (0x0000)
|
||||
/** \ingroup avr_boot
|
||||
\def GET_LOCK_BITS
|
||||
address to read the lock bits, using boot_lock_fuse_bits_get
|
||||
*/
|
||||
#define GET_LOCK_BITS (0x0001)
|
||||
/** \ingroup avr_boot
|
||||
\def GET_EXTENDED_FUSE_BITS
|
||||
address to read the extended fuse bits, using boot_lock_fuse_bits_get
|
||||
*/
|
||||
#define GET_EXTENDED_FUSE_BITS (0x0002)
|
||||
/** \ingroup avr_boot
|
||||
\def GET_HIGH_FUSE_BITS
|
||||
address to read the high fuse bits, using boot_lock_fuse_bits_get
|
||||
*/
|
||||
#define GET_HIGH_FUSE_BITS (0x0003)
|
||||
|
||||
/** \ingroup avr_boot
|
||||
\def boot_lock_fuse_bits_get(address)
|
||||
|
||||
Read the lock or fuse bits at \c address.
|
||||
|
||||
Parameter \c address can be any of GET_LOW_FUSE_BITS,
|
||||
GET_LOCK_BITS, GET_EXTENDED_FUSE_BITS, or GET_HIGH_FUSE_BITS.
|
||||
|
||||
\note The lock and fuse bits returned are the physical values,
|
||||
i.e. a bit returned as 0 means the corresponding fuse or lock bit
|
||||
is programmed.
|
||||
*/
|
||||
#define boot_lock_fuse_bits_get_short(address) \
|
||||
(__extension__({ \
|
||||
uint8_t __result; \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"ldi r30, %3\n\t" \
|
||||
"ldi r31, 0\n\t" \
|
||||
"out %1, %2\n\t" \
|
||||
"lpm %0, Z\n\t" \
|
||||
: "=r" (__result) \
|
||||
: "i" (_SFR_IO_ADDR(__SPM_REG)), \
|
||||
"r" ((uint8_t)__BOOT_LOCK_BITS_SET), \
|
||||
"M" (address) \
|
||||
: "r0", "r30", "r31" \
|
||||
); \
|
||||
__result; \
|
||||
}))
|
||||
|
||||
#define boot_lock_fuse_bits_get(address) \
|
||||
(__extension__({ \
|
||||
uint8_t __result; \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"ldi r30, %3\n\t" \
|
||||
"ldi r31, 0\n\t" \
|
||||
"sts %1, %2\n\t" \
|
||||
"lpm %0, Z\n\t" \
|
||||
: "=r" (__result) \
|
||||
: "i" (_SFR_MEM_ADDR(__SPM_REG)), \
|
||||
"r" ((uint8_t)__BOOT_LOCK_BITS_SET), \
|
||||
"M" (address) \
|
||||
: "r0", "r30", "r31" \
|
||||
); \
|
||||
__result; \
|
||||
}))
|
||||
|
||||
/** \ingroup avr_boot
|
||||
\def boot_signature_byte_get(address)
|
||||
|
||||
Read the Signature Row byte at \c address. For some MCU types,
|
||||
this function can also retrieve the factory-stored oscillator
|
||||
calibration bytes.
|
||||
|
||||
Parameter \c address can be 0-0x1f as documented by the datasheet.
|
||||
\note The values are MCU type dependent.
|
||||
*/
|
||||
|
||||
#define __BOOT_SIGROW_READ (_BV(__SPM_ENABLE) | _BV(SIGRD))
|
||||
|
||||
#define boot_signature_byte_get_short(addr) \
|
||||
(__extension__({ \
|
||||
uint16_t __addr16 = (uint16_t)(addr); \
|
||||
uint8_t __result; \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"out %1, %2\n\t" \
|
||||
"lpm %0, Z" "\n\t" \
|
||||
: "=r" (__result) \
|
||||
: "i" (_SFR_IO_ADDR(__SPM_REG)), \
|
||||
"r" ((uint8_t) __BOOT_SIGROW_READ), \
|
||||
"z" (__addr16) \
|
||||
); \
|
||||
__result; \
|
||||
}))
|
||||
|
||||
#define boot_signature_byte_get(addr) \
|
||||
(__extension__({ \
|
||||
uint16_t __addr16 = (uint16_t)(addr); \
|
||||
uint8_t __result; \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"sts %1, %2\n\t" \
|
||||
"lpm %0, Z" "\n\t" \
|
||||
: "=r" (__result) \
|
||||
: "i" (_SFR_MEM_ADDR(__SPM_REG)), \
|
||||
"r" ((uint8_t) __BOOT_SIGROW_READ), \
|
||||
"z" (__addr16) \
|
||||
); \
|
||||
__result; \
|
||||
}))
|
||||
|
||||
/** \ingroup avr_boot
|
||||
\def boot_page_fill(address, data)
|
||||
|
||||
Fill the bootloader temporary page buffer for flash
|
||||
address with data word.
|
||||
|
||||
\note The address is a byte address. The data is a word. The AVR
|
||||
writes data to the buffer a word at a time, but addresses the buffer
|
||||
per byte! So, increment your address by 2 between calls, and send 2
|
||||
data bytes in a word format! The LSB of the data is written to the lower
|
||||
address; the MSB of the data is written to the higher address.*/
|
||||
|
||||
/** \ingroup avr_boot
|
||||
\def boot_page_erase(address)
|
||||
|
||||
Erase the flash page that contains address.
|
||||
|
||||
\note address is a byte address in flash, not a word address. */
|
||||
|
||||
/** \ingroup avr_boot
|
||||
\def boot_page_write(address)
|
||||
|
||||
Write the bootloader temporary page buffer
|
||||
to flash page that contains address.
|
||||
|
||||
\note address is a byte address in flash, not a word address. */
|
||||
|
||||
/** \ingroup avr_boot
|
||||
\def boot_rww_enable()
|
||||
|
||||
Enable the Read-While-Write memory section. */
|
||||
|
||||
/** \ingroup avr_boot
|
||||
\def boot_lock_bits_set(lock_bits)
|
||||
|
||||
Set the bootloader lock bits.
|
||||
|
||||
\param lock_bits A mask of which Boot Loader Lock Bits to set.
|
||||
|
||||
\note In this context, a 'set bit' will be written to a zero value.
|
||||
Note also that only BLBxx bits can be programmed by this command.
|
||||
|
||||
For example, to disallow the SPM instruction from writing to the Boot
|
||||
Loader memory section of flash, you would use this macro as such:
|
||||
|
||||
\code
|
||||
boot_lock_bits_set (_BV (BLB11));
|
||||
\endcode
|
||||
|
||||
\note Like any lock bits, the Boot Loader Lock Bits, once set,
|
||||
cannot be cleared again except by a chip erase which will in turn
|
||||
also erase the boot loader itself. */
|
||||
|
||||
/* Normal versions of the macros use 16-bit addresses.
|
||||
Extended versions of the macros use 32-bit addresses.
|
||||
Alternate versions of the macros use 16-bit addresses and require special
|
||||
instruction sequences after LPM.
|
||||
|
||||
FLASHEND is defined in the ioXXXX.h file.
|
||||
USHRT_MAX is defined in <limits.h>. */
|
||||
|
||||
#if defined(__AVR_ATmega161__) || defined(__AVR_ATmega163__) \
|
||||
|| defined(__AVR_ATmega323__)
|
||||
|
||||
/* Alternate: ATmega161/163/323 and 16 bit address */
|
||||
#define boot_page_fill(address, data) __boot_page_fill_alternate(address, data)
|
||||
#define boot_page_erase(address) __boot_page_erase_alternate(address)
|
||||
#define boot_page_write(address) __boot_page_write_alternate(address)
|
||||
#define boot_rww_enable() __boot_rww_enable_alternate()
|
||||
#define boot_lock_bits_set(lock_bits) __boot_lock_bits_set_alternate(lock_bits)
|
||||
|
||||
#elif (FLASHEND > USHRT_MAX)
|
||||
|
||||
/* Extended: >16 bit address */
|
||||
#define boot_page_fill(address, data) __boot_page_fill_extended_short(address, data)
|
||||
#define boot_page_erase(address) __boot_page_erase_extended_short(address)
|
||||
#define boot_page_write(address) __boot_page_write_extended_short(address)
|
||||
#define boot_rww_enable() __boot_rww_enable_short()
|
||||
#define boot_lock_bits_set(lock_bits) __boot_lock_bits_set_short(lock_bits)
|
||||
|
||||
#else
|
||||
|
||||
/* Normal: 16 bit address */
|
||||
#define boot_page_fill(address, data) __boot_page_fill_short(address, data)
|
||||
#define boot_page_erase(address) __boot_page_erase_short(address)
|
||||
#define boot_page_write(address) __boot_page_write_short(address)
|
||||
#define boot_rww_enable() __boot_rww_enable_short()
|
||||
#define boot_lock_bits_set(lock_bits) __boot_lock_bits_set_short(lock_bits)
|
||||
|
||||
#endif
|
||||
|
||||
/** \ingroup avr_boot
|
||||
|
||||
Same as boot_page_fill() except it waits for eeprom and spm operations to
|
||||
complete before filling the page. */
|
||||
|
||||
#define boot_page_fill_safe(address, data) \
|
||||
do { \
|
||||
boot_spm_busy_wait(); \
|
||||
eeprom_busy_wait(); \
|
||||
boot_page_fill(address, data); \
|
||||
} while (0)
|
||||
|
||||
/** \ingroup avr_boot
|
||||
|
||||
Same as boot_page_erase() except it waits for eeprom and spm operations to
|
||||
complete before erasing the page. */
|
||||
|
||||
#define boot_page_erase_safe(address) \
|
||||
do { \
|
||||
boot_spm_busy_wait(); \
|
||||
eeprom_busy_wait(); \
|
||||
boot_page_erase (address); \
|
||||
} while (0)
|
||||
|
||||
/** \ingroup avr_boot
|
||||
|
||||
Same as boot_page_write() except it waits for eeprom and spm operations to
|
||||
complete before writing the page. */
|
||||
|
||||
#define boot_page_write_safe(address) \
|
||||
do { \
|
||||
boot_spm_busy_wait(); \
|
||||
eeprom_busy_wait(); \
|
||||
boot_page_write (address); \
|
||||
} while (0)
|
||||
|
||||
/** \ingroup avr_boot
|
||||
|
||||
Same as boot_rww_enable() except waits for eeprom and spm operations to
|
||||
complete before enabling the RWW mameory. */
|
||||
|
||||
#define boot_rww_enable_safe() \
|
||||
do { \
|
||||
boot_spm_busy_wait(); \
|
||||
eeprom_busy_wait(); \
|
||||
boot_rww_enable(); \
|
||||
} while (0)
|
||||
|
||||
/** \ingroup avr_boot
|
||||
|
||||
Same as boot_lock_bits_set() except waits for eeprom and spm operations to
|
||||
complete before setting the lock bits. */
|
||||
|
||||
#define boot_lock_bits_set_safe(lock_bits) \
|
||||
do { \
|
||||
boot_spm_busy_wait(); \
|
||||
eeprom_busy_wait(); \
|
||||
boot_lock_bits_set (lock_bits); \
|
||||
} while (0)
|
||||
|
||||
#endif /* _AVR_BOOT_H_ */
|
@ -1,891 +0,0 @@
|
||||
/**********************************************************/
|
||||
/* Optiboot bootloader for Arduino */
|
||||
/* */
|
||||
/* http://optiboot.googlecode.com */
|
||||
/* */
|
||||
/* Arduino-maintained version : See README.TXT */
|
||||
/* http://code.google.com/p/arduino/ */
|
||||
/* It is the intent that changes not relevant to the */
|
||||
/* Arduino production envionment get moved from the */
|
||||
/* optiboot project to the arduino project in "lumps." */
|
||||
/* */
|
||||
/* Heavily optimised bootloader that is faster and */
|
||||
/* smaller than the Arduino standard bootloader */
|
||||
/* */
|
||||
/* Enhancements: */
|
||||
/* Fits in 512 bytes, saving 1.5K of code space */
|
||||
/* Background page erasing speeds up programming */
|
||||
/* Higher baud rate speeds up programming */
|
||||
/* Written almost entirely in C */
|
||||
/* Customisable timeout with accurate timeconstant */
|
||||
/* Optional virtual UART. No hardware UART required. */
|
||||
/* Optional virtual boot partition for devices without. */
|
||||
/* */
|
||||
/* What you lose: */
|
||||
/* Implements a skeleton STK500 protocol which is */
|
||||
/* missing several features including EEPROM */
|
||||
/* programming and non-page-aligned writes */
|
||||
/* High baud rate breaks compatibility with standard */
|
||||
/* Arduino flash settings */
|
||||
/* */
|
||||
/* Fully supported: */
|
||||
/* ATmega168 based devices (Diecimila etc) */
|
||||
/* ATmega328P based devices (Duemilanove etc) */
|
||||
/* */
|
||||
/* Beta test (believed working.) */
|
||||
/* ATmega8 based devices (Arduino legacy) */
|
||||
/* ATmega328 non-picopower devices */
|
||||
/* ATmega644P based devices (Sanguino) */
|
||||
/* ATmega1284P based devices */
|
||||
/* */
|
||||
/* Alpha test */
|
||||
/* ATmega1280 based devices (Arduino Mega) */
|
||||
/* */
|
||||
/* Work in progress: */
|
||||
/* ATtiny84 based devices (Luminet) */
|
||||
/* */
|
||||
/* Does not support: */
|
||||
/* USB based devices (eg. Teensy) */
|
||||
/* */
|
||||
/* Assumptions: */
|
||||
/* The code makes several assumptions that reduce the */
|
||||
/* code size. They are all true after a hardware reset, */
|
||||
/* but may not be true if the bootloader is called by */
|
||||
/* other means or on other hardware. */
|
||||
/* No interrupts can occur */
|
||||
/* UART and Timer 1 are set to their reset state */
|
||||
/* SP points to RAMEND */
|
||||
/* */
|
||||
/* Code builds on code, libraries and optimisations from: */
|
||||
/* stk500boot.c by Jason P. Kyle */
|
||||
/* Arduino bootloader http://arduino.cc */
|
||||
/* Spiff's 1K bootloader http://spiffie.org/know/arduino_1k_bootloader/bootloader.shtml */
|
||||
/* avr-libc project http://nongnu.org/avr-libc */
|
||||
/* Adaboot http://www.ladyada.net/library/arduino/bootloader.html */
|
||||
/* AVR305 Atmel Application Note */
|
||||
/* */
|
||||
/* This program is free software; you can redistribute it */
|
||||
/* and/or modify it under the terms of the GNU General */
|
||||
/* Public License as published by the Free Software */
|
||||
/* Foundation; either version 2 of the License, or */
|
||||
/* (at your option) any later version. */
|
||||
/* */
|
||||
/* This program is distributed in the hope that it will */
|
||||
/* be useful, but WITHOUT ANY WARRANTY; without even the */
|
||||
/* implied warranty of MERCHANTABILITY or FITNESS FOR A */
|
||||
/* PARTICULAR PURPOSE. See the GNU General Public */
|
||||
/* License for more details. */
|
||||
/* */
|
||||
/* You should have received a copy of the GNU General */
|
||||
/* Public License along with this program; if not, write */
|
||||
/* to the Free Software Foundation, Inc., */
|
||||
/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
/* */
|
||||
/* Licence can be viewed at */
|
||||
/* http://www.fsf.org/licenses/gpl.txt */
|
||||
/* */
|
||||
/**********************************************************/
|
||||
|
||||
|
||||
/**********************************************************/
|
||||
/* */
|
||||
/* Optional defines: */
|
||||
/* */
|
||||
/**********************************************************/
|
||||
/* */
|
||||
/* BIG_BOOT: */
|
||||
/* Build a 1k bootloader, not 512 bytes. This turns on */
|
||||
/* extra functionality. */
|
||||
/* */
|
||||
/* BAUD_RATE: */
|
||||
/* Set bootloader baud rate. */
|
||||
/* */
|
||||
/* LUDICROUS_SPEED: */
|
||||
/* 230400 baud :-) */
|
||||
/* */
|
||||
/* SOFT_UART: */
|
||||
/* Use AVR305 soft-UART instead of hardware UART. */
|
||||
/* */
|
||||
/* LED_START_FLASHES: */
|
||||
/* Number of LED flashes on bootup. */
|
||||
/* */
|
||||
/* LED_DATA_FLASH: */
|
||||
/* Flash LED when transferring data. For boards without */
|
||||
/* TX or RX LEDs, or for people who like blinky lights. */
|
||||
/* */
|
||||
/* SUPPORT_EEPROM: */
|
||||
/* Support reading and writing from EEPROM. This is not */
|
||||
/* used by Arduino, so off by default. */
|
||||
/* */
|
||||
/* TIMEOUT_MS: */
|
||||
/* Bootloader timeout period, in milliseconds. */
|
||||
/* 500,1000,2000,4000,8000 supported. */
|
||||
/* */
|
||||
/* UART: */
|
||||
/* UART number (0..n) for devices with more than */
|
||||
/* one hardware uart (644P, 1284P, etc) */
|
||||
/* */
|
||||
/**********************************************************/
|
||||
|
||||
/**********************************************************/
|
||||
/* Version Numbers! */
|
||||
/* */
|
||||
/* Arduino Optiboot now includes this Version number in */
|
||||
/* the source and object code. */
|
||||
/* */
|
||||
/* Version 3 was released as zip from the optiboot */
|
||||
/* repository and was distributed with Arduino 0022. */
|
||||
/* Version 4 starts with the arduino repository commit */
|
||||
/* that brought the arduino repository up-to-date with */
|
||||
/* the optiboot source tree changes since v3. */
|
||||
/* */
|
||||
/**********************************************************/
|
||||
|
||||
/**********************************************************/
|
||||
/* Edit History: */
|
||||
/* */
|
||||
/* Nov 2012 */
|
||||
/* Specific version for 9x voice module */
|
||||
/* by Mike Blandford */
|
||||
/* Mar 2012 */
|
||||
/* 4.5 WestfW: add infrastructure for non-zero UARTS. */
|
||||
/* 4.5 WestfW: fix SIGNATURE_2 for m644 (bad in avr-libc) */
|
||||
/* Jan 2012: */
|
||||
/* 4.5 WestfW: fix NRWW value for m1284. */
|
||||
/* 4.4 WestfW: use attribute OS_main instead of naked for */
|
||||
/* main(). This allows optimizations that we */
|
||||
/* count on, which are prohibited in naked */
|
||||
/* functions due to PR42240. (keeps us less */
|
||||
/* than 512 bytes when compiler is gcc4.5 */
|
||||
/* (code from 4.3.2 remains the same.) */
|
||||
/* 4.4 WestfW and Maniacbug: Add m1284 support. This */
|
||||
/* does not change the 328 binary, so the */
|
||||
/* version number didn't change either. (?) */
|
||||
/* June 2011: */
|
||||
/* 4.4 WestfW: remove automatic soft_uart detect (didn't */
|
||||
/* know what it was doing or why.) Added a */
|
||||
/* check of the calculated BRG value instead. */
|
||||
/* Version stays 4.4; existing binaries are */
|
||||
/* not changed. */
|
||||
/* 4.4 WestfW: add initialization of address to keep */
|
||||
/* the compiler happy. Change SC'ed targets. */
|
||||
/* Return the SW version via READ PARAM */
|
||||
/* 4.3 WestfW: catch framing errors in getch(), so that */
|
||||
/* AVRISP works without HW kludges. */
|
||||
/* http://code.google.com/p/arduino/issues/detail?id=368n*/
|
||||
/* 4.2 WestfW: reduce code size, fix timeouts, change */
|
||||
/* verifySpace to use WDT instead of appstart */
|
||||
/* 4.1 WestfW: put version number in binary. */
|
||||
/**********************************************************/
|
||||
|
||||
#define OPTIBOOT_MAJVER 4
|
||||
#define OPTIBOOT_MINVER 5
|
||||
|
||||
#define MULTI_CALLED 1
|
||||
|
||||
#define MAKESTR(a) #a
|
||||
#define MAKEVER(a, b) MAKESTR(a*256+b)
|
||||
|
||||
//asm(" .section .version\n"
|
||||
// "optiboot_version: .word " MAKEVER(OPTIBOOT_MAJVER, OPTIBOOT_MINVER) "\n"
|
||||
// " .section .text\n");
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <avr/io.h>
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
// <avr/boot.h> uses sts instructions, but this version uses out instructions
|
||||
// This saves cycles and program memory.
|
||||
#include "boot.h"
|
||||
|
||||
|
||||
// We don't use <avr/wdt.h> as those routines have interrupt overhead we don't need.
|
||||
|
||||
#include "pin_defs.h"
|
||||
#include "stk500.h"
|
||||
|
||||
#ifndef LED_START_FLASHES
|
||||
#define LED_START_FLASHES 0
|
||||
#endif
|
||||
|
||||
#ifdef LUDICROUS_SPEED
|
||||
#define BAUD_RATE 230400L
|
||||
#endif
|
||||
|
||||
/* set the UART baud rate defaults */
|
||||
#ifndef BAUD_RATE
|
||||
#if F_CPU >= 8000000L
|
||||
#define BAUD_RATE 38400L // Highest rate Avrdude win32 will support
|
||||
#elsif F_CPU >= 1000000L
|
||||
#define BAUD_RATE 9600L // 19200 also supported, but with significant error
|
||||
#elsif F_CPU >= 128000L
|
||||
#define BAUD_RATE 4800L // Good for 128kHz internal RC
|
||||
#else
|
||||
#define BAUD_RATE 1200L // Good even at 32768Hz
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef UART
|
||||
#define UART 0
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
/* Switch in soft UART for hard baud rates */
|
||||
/*
|
||||
* I don't understand what this was supposed to accomplish, where the
|
||||
* constant "280" came from, or why automatically (and perhaps unexpectedly)
|
||||
* switching to a soft uart is a good thing, so I'm undoing this in favor
|
||||
* of a range check using the same calc used to config the BRG...
|
||||
*/
|
||||
#if (F_CPU/BAUD_RATE) > 280 // > 57600 for 16MHz
|
||||
#ifndef SOFT_UART
|
||||
#define SOFT_UART
|
||||
#endif
|
||||
#endif
|
||||
#else // 0
|
||||
#if (F_CPU + BAUD_RATE * 4L) / (BAUD_RATE * 8L) - 1 > 250
|
||||
#error Unachievable baud rate (too slow) BAUD_RATE
|
||||
#endif // baud rate slow check
|
||||
#if (F_CPU + BAUD_RATE * 4L) / (BAUD_RATE * 8L) - 1 < 3
|
||||
#error Unachievable baud rate (too fast) BAUD_RATE
|
||||
#endif // baud rate fastn check
|
||||
#endif
|
||||
|
||||
/* Watchdog settings */
|
||||
#define WATCHDOG_OFF (0)
|
||||
#define WATCHDOG_16MS (_BV(WDE))
|
||||
#define WATCHDOG_32MS (_BV(WDP0) | _BV(WDE))
|
||||
#define WATCHDOG_64MS (_BV(WDP1) | _BV(WDE))
|
||||
#define WATCHDOG_125MS (_BV(WDP1) | _BV(WDP0) | _BV(WDE))
|
||||
#define WATCHDOG_250MS (_BV(WDP2) | _BV(WDE))
|
||||
#define WATCHDOG_500MS (_BV(WDP2) | _BV(WDP0) | _BV(WDE))
|
||||
#define WATCHDOG_1S (_BV(WDP2) | _BV(WDP1) | _BV(WDE))
|
||||
#define WATCHDOG_2S (_BV(WDP2) | _BV(WDP1) | _BV(WDP0) | _BV(WDE))
|
||||
#ifndef __AVR_ATmega8__
|
||||
#define WATCHDOG_4S (_BV(WDP3) | _BV(WDE))
|
||||
#define WATCHDOG_8S (_BV(WDP3) | _BV(WDP0) | _BV(WDE))
|
||||
#endif
|
||||
|
||||
/* Function Prototypes */
|
||||
/* The main function is in init9, which removes the interrupt vector table */
|
||||
/* we don't need. It is also 'naked', which means the compiler does not */
|
||||
/* generate any entry or exit code itself. */
|
||||
int main(void) __attribute__ ((OS_main)) __attribute__ ((noreturn)) __attribute__ ((section (".init9")));
|
||||
void putch(char);
|
||||
uint8_t getch(void);
|
||||
static inline void getNch(uint8_t); /* "static inline" is a compiler hint to reduce code size */
|
||||
void verifySpace();
|
||||
#if LED_START_FLASHES > 0
|
||||
static inline void flash_led(uint8_t);
|
||||
#endif
|
||||
uint8_t getLen();
|
||||
//static inline void watchdogReset();
|
||||
void watchdogConfig(uint8_t x);
|
||||
#ifdef SOFT_UART
|
||||
void uartDelay() __attribute__ ((naked));
|
||||
#endif
|
||||
static void appStart() ; // __attribute__ ((naked));
|
||||
|
||||
/*
|
||||
* NRWW memory
|
||||
* Addresses below NRWW (Non-Read-While-Write) can be programmed while
|
||||
* continuing to run code from flash, slightly speeding up programming
|
||||
* time. Beware that Atmel data sheets specify this as a WORD address,
|
||||
* while optiboot will be comparing against a 16-bit byte address. This
|
||||
* means that on a part with 128kB of memory, the upper part of the lower
|
||||
* 64k will get NRWW processing as well, even though it doesn't need it.
|
||||
* That's OK. In fact, you can disable the overlapping processing for
|
||||
* a part entirely by setting NRWWSTART to zero. This reduces code
|
||||
* space a bit, at the expense of being slightly slower, overall.
|
||||
*
|
||||
* RAMSTART should be self-explanatory. It's bigger on parts with a
|
||||
* lot of peripheral registers.
|
||||
*/
|
||||
#if defined(__AVR_ATmega168__)
|
||||
#define RAMSTART (0x100)
|
||||
#define NRWWSTART (0x3800)
|
||||
#elif defined(__AVR_ATmega328P__)
|
||||
#define RAMSTART (0x100)
|
||||
#define NRWWSTART (0x7000)
|
||||
#elif defined(__AVR_ATmega328__)
|
||||
#define RAMSTART (0x100)
|
||||
#define NRWWSTART (0x7000)
|
||||
#elif defined (__AVR_ATmega644P__)
|
||||
#define RAMSTART (0x100)
|
||||
#define NRWWSTART (0xE000)
|
||||
// correct for a bug in avr-libc
|
||||
#undef SIGNATURE_2
|
||||
#define SIGNATURE_2 0x0A
|
||||
#elif defined (__AVR_ATmega1284P__)
|
||||
#define RAMSTART (0x100)
|
||||
#define NRWWSTART (0xE000)
|
||||
#elif defined(__AVR_ATtiny84__)
|
||||
#define RAMSTART (0x100)
|
||||
#define NRWWSTART (0x0000)
|
||||
#elif defined(__AVR_ATmega1280__)
|
||||
#define RAMSTART (0x200)
|
||||
#define NRWWSTART (0xE000)
|
||||
#elif defined(__AVR_ATmega8__) || defined(__AVR_ATmega88__)
|
||||
#define RAMSTART (0x100)
|
||||
#define NRWWSTART (0x1800)
|
||||
#endif
|
||||
|
||||
/* C zero initialises all global variables. However, that requires */
|
||||
/* These definitions are NOT zero initialised, but that doesn't matter */
|
||||
/* This allows us to drop the zero init code, saving us memory */
|
||||
#define buff ((uint8_t*)(RAMSTART))
|
||||
#ifdef VIRTUAL_BOOT_PARTITION
|
||||
#define rstVect (*(uint16_t*)(RAMSTART+SPM_PAGESIZE*2+4))
|
||||
#define wdtVect (*(uint16_t*)(RAMSTART+SPM_PAGESIZE*2+6))
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Handle devices with up to 4 uarts (eg m1280.) Rather inelegantly.
|
||||
* Note that mega8 still needs special handling, because ubrr is handled
|
||||
* differently.
|
||||
*/
|
||||
#if UART == 0
|
||||
# define UART_SRA UCSR0A
|
||||
# define UART_SRB UCSR0B
|
||||
# define UART_SRC UCSR0C
|
||||
# define UART_SRL UBRR0L
|
||||
# define UART_UDR UDR0
|
||||
#elif UART == 1
|
||||
# define UART_SRA UCSR1A
|
||||
# define UART_SRB UCSR1B
|
||||
# define UART_SRC UCSR1C
|
||||
# define UART_SRL UBRR1L
|
||||
# define UART_UDR UDR1
|
||||
#elif UART == 2
|
||||
# define UART_SRA UCSR2A
|
||||
# define UART_SRB UCSR2B
|
||||
# define UART_SRC UCSR2C
|
||||
# define UART_SRL UBRR2L
|
||||
# define UART_UDR UDR2
|
||||
#elif UART == 3
|
||||
# define UART_SRA UCSR3A
|
||||
# define UART_SRB UCSR3B
|
||||
# define UART_SRC UCSR3C
|
||||
# define UART_SRL UBRR3L
|
||||
# define UART_UDR UDR3
|
||||
#endif
|
||||
|
||||
/* main program starts here */
|
||||
int main(void) {
|
||||
uint8_t ch;
|
||||
|
||||
/*
|
||||
* Making these local and in registers prevents the need for initializing
|
||||
* them, and also saves space because code no longer stores to memory.
|
||||
* (initializing address keeps the compiler happy, but isn't really
|
||||
* necessary, and uses 4 bytes of flash.)
|
||||
*/
|
||||
register uint16_t address = 0;
|
||||
|
||||
// After the zero init loop, this is the first code to run.
|
||||
//
|
||||
// This code makes the following assumptions:
|
||||
// No interrupts will execute
|
||||
// SP points to RAMEND
|
||||
// r1 contains zero
|
||||
//
|
||||
// If not, uncomment the following instructions:
|
||||
// cli();
|
||||
asm volatile ("clr __zero_reg__");
|
||||
#ifdef __AVR_ATmega8__
|
||||
SP=RAMEND; // This is done by hardware reset
|
||||
#endif
|
||||
|
||||
// Adaboot no-wait mod
|
||||
ch = MCUSR;
|
||||
MCUSR = 0;
|
||||
|
||||
// Here, if power on, wait 0.5 secs, then check for
|
||||
// serial Rx signal low, if so, stay in bootloader
|
||||
// else go to application
|
||||
|
||||
PORTD = 0xFF ;
|
||||
PORTB = 0x3C ;
|
||||
PORTC = 1 ;
|
||||
|
||||
if (ch & (_BV(PORF) | (_BV(EXTRF)) ) )
|
||||
{
|
||||
#ifdef MULTI_CALLED
|
||||
#if F_CPU == 12000000L
|
||||
TCNT1H = 256 - 8 ;
|
||||
#else
|
||||
#if F_CPU == 16000000L
|
||||
TCNT1H = 256 - 6 ;
|
||||
#else
|
||||
TCNT1H = 256 - 127 ;
|
||||
#endif
|
||||
TCNT1L = 0 ;
|
||||
#endif
|
||||
#else
|
||||
#if F_CPU == 12000000L
|
||||
TCNT1 = 65535-5859 ;
|
||||
#else
|
||||
#if F_CPU == 16000000L
|
||||
TCNT1 = 65535-7813 ;
|
||||
#else
|
||||
TCNT1 = 65535-32767 ;
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
TCCR1B = _BV(CS12) | _BV(CS10); // div 1024
|
||||
TIFR1 = _BV(TOV1);
|
||||
while(!(TIFR1 & _BV(TOV1)))
|
||||
;
|
||||
TCCR1B = 0 ; // Stop timer
|
||||
uint8_t x ;
|
||||
x = PINB & 0x3C ;
|
||||
x |= PINC & 1 ;
|
||||
if ( x != 0x1D )
|
||||
{
|
||||
appStart() ; // Power on, go to voice application
|
||||
// if loaded
|
||||
}
|
||||
}
|
||||
|
||||
#if LED_START_FLASHES > 0
|
||||
// Set up Timer 1 for timeout counter
|
||||
TCCR1B = _BV(CS12) | _BV(CS10); // div 1024
|
||||
#endif
|
||||
|
||||
#ifndef SOFT_UART
|
||||
UART_SRA = _BV(U2X0); //Double speed mode USART0
|
||||
UART_SRB = _BV(RXEN0) | _BV(TXEN0);
|
||||
UART_SRC = _BV(UCSZ00) | _BV(UCSZ01);
|
||||
// UART_SRL = (uint8_t)( (F_CPU + BAUD_RATE * 4L) / (BAUD_RATE * 8L) - 1 );
|
||||
// Baudrate of 57600
|
||||
#if F_CPU == 12000000L
|
||||
UART_SRL = 25 ;
|
||||
#else
|
||||
#if F_CPU == 16000000L
|
||||
UART_SRL = 33 ;
|
||||
#else
|
||||
#ERROR Baud rate not available
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
// Set up watchdog to trigger after 500ms
|
||||
|
||||
|
||||
// watchdogConfig(WATCHDOG_1S);
|
||||
|
||||
/* Set LED pin as output */
|
||||
LED_DDR |= _BV(LED);
|
||||
|
||||
#ifdef SOFT_UART
|
||||
/* Set TX pin as output */
|
||||
UART_DDR |= _BV(UART_TX_BIT);
|
||||
#endif
|
||||
|
||||
#if LED_START_FLASHES > 0
|
||||
/* Flash onboard LED to signal entering of bootloader */
|
||||
flash_led(LED_START_FLASHES * 2);
|
||||
#endif
|
||||
|
||||
/* Forever loop */
|
||||
for (;;)
|
||||
{
|
||||
/* get character from UART */
|
||||
ch = getch();
|
||||
|
||||
if(ch == STK_GET_PARAMETER)
|
||||
{
|
||||
GPIOR0 = getch();
|
||||
verifySpace();
|
||||
if (GPIOR0 == 0x82)
|
||||
{
|
||||
/*
|
||||
* Send optiboot version as "minor SW version"
|
||||
*/
|
||||
putch(OPTIBOOT_MINVER);
|
||||
}
|
||||
else if (GPIOR0 == 0x81)
|
||||
{
|
||||
putch(OPTIBOOT_MAJVER);
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* GET PARAMETER returns a generic 0x03 reply for
|
||||
* other parameters - enough to keep Avrdude happy
|
||||
*/
|
||||
putch(0x03);
|
||||
}
|
||||
}
|
||||
else if(ch == STK_SET_DEVICE) {
|
||||
// SET DEVICE is ignored
|
||||
getNch(20);
|
||||
}
|
||||
else if(ch == STK_SET_DEVICE_EXT)
|
||||
{
|
||||
// SET DEVICE EXT is ignored
|
||||
getNch(5);
|
||||
}
|
||||
else if(ch == STK_LOAD_ADDRESS)
|
||||
{
|
||||
// LOAD ADDRESS
|
||||
uint16_t newAddress;
|
||||
newAddress = getch() ;
|
||||
newAddress = (newAddress & 0xff) | (getch() << 8);
|
||||
#ifdef RAMPZ
|
||||
// Transfer top bit to RAMPZ
|
||||
RAMPZ = (newAddress & 0x8000) ? 1 : 0;
|
||||
#endif
|
||||
newAddress += newAddress; // Convert from word address to byte address
|
||||
address = newAddress;
|
||||
verifySpace();
|
||||
}
|
||||
else if(ch == STK_UNIVERSAL)
|
||||
{
|
||||
// UNIVERSAL command is ignored
|
||||
getNch(4);
|
||||
putch(0x00);
|
||||
}
|
||||
/* Write memory, length is big endian and is in bytes */
|
||||
else if(ch == STK_PROG_PAGE)
|
||||
{
|
||||
// PROGRAM PAGE - we support flash programming only, not EEPROM
|
||||
uint8_t *bufPtr;
|
||||
uint16_t addrPtr;
|
||||
register uint8_t length;
|
||||
|
||||
getch(); /* getlen() */
|
||||
length = getch();
|
||||
getch();
|
||||
|
||||
// If we are in RWW section, immediately start page erase
|
||||
if (address < NRWWSTART) __boot_page_erase_short((uint16_t)(void*)address);
|
||||
|
||||
// While that is going on, read in page contents
|
||||
bufPtr = buff;
|
||||
do *bufPtr++ = getch();
|
||||
while (--length);
|
||||
|
||||
// If we are in NRWW section, page erase has to be delayed until now.
|
||||
// Todo: Take RAMPZ into account
|
||||
#ifdef MULTI_CALLED
|
||||
if (address < 0x7E00)
|
||||
#endif
|
||||
{
|
||||
if (address >= NRWWSTART) __boot_page_erase_short((uint16_t)(void*)address);
|
||||
}
|
||||
// Read command terminator, start reply
|
||||
verifySpace();
|
||||
|
||||
// If only a partial page is to be programmed, the erase might not be complete.
|
||||
// So check that here
|
||||
#ifdef MULTI_CALLED
|
||||
if (address < 0x7E00)
|
||||
#endif
|
||||
{
|
||||
boot_spm_busy_wait();
|
||||
|
||||
#ifdef VIRTUAL_BOOT_PARTITION
|
||||
if ((uint16_t)(void*)address == 0) {
|
||||
// This is the reset vector page. We need to live-patch the code so the
|
||||
// bootloader runs.
|
||||
//
|
||||
// Move RESET vector to WDT vector
|
||||
uint16_t vect = buff[0] | (buff[1]<<8);
|
||||
rstVect = vect;
|
||||
wdtVect = buff[8] | (buff[9]<<8);
|
||||
vect -= 4; // Instruction is a relative jump (rjmp), so recalculate.
|
||||
buff[8] = vect & 0xff;
|
||||
buff[9] = vect >> 8;
|
||||
|
||||
// Add jump to bootloader at RESET vector
|
||||
buff[0] = 0x7f;
|
||||
buff[1] = 0xce; // rjmp 0x1d00 instruction
|
||||
}
|
||||
#endif
|
||||
|
||||
// Copy buffer into programming buffer
|
||||
bufPtr = buff;
|
||||
addrPtr = (uint16_t)(void*)address;
|
||||
ch = SPM_PAGESIZE / 2;
|
||||
do {
|
||||
uint16_t a;
|
||||
// a = *bufPtr++;
|
||||
// a |= (*bufPtr++) << 8;
|
||||
|
||||
a = *((uint16_t *)bufPtr) ;
|
||||
bufPtr += 2 ;
|
||||
|
||||
__boot_page_fill_short((uint16_t)(void*)addrPtr,a);
|
||||
addrPtr += 2;
|
||||
} while (--ch);
|
||||
|
||||
// Write from programming buffer
|
||||
__boot_page_write_short((uint16_t)(void*)address);
|
||||
boot_spm_busy_wait();
|
||||
|
||||
#if defined(RWWSRE)
|
||||
// Reenable read access to flash
|
||||
boot_rww_enable();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
/* Read memory block mode, length is big endian. */
|
||||
else if(ch == STK_READ_PAGE)
|
||||
{
|
||||
register uint8_t length;
|
||||
// READ PAGE - we only read flash
|
||||
getch(); /* getlen() */
|
||||
length = getch();
|
||||
getch();
|
||||
|
||||
verifySpace();
|
||||
#ifdef VIRTUAL_BOOT_PARTITION
|
||||
do {
|
||||
// Undo vector patch in bottom page so verify passes
|
||||
if (address == 0) ch=rstVect & 0xff;
|
||||
else if (address == 1) ch=rstVect >> 8;
|
||||
else if (address == 8) ch=wdtVect & 0xff;
|
||||
else if (address == 9) ch=wdtVect >> 8;
|
||||
else ch = pgm_read_byte_near(address);
|
||||
address++;
|
||||
putch(ch);
|
||||
} while (--length);
|
||||
#else
|
||||
#ifdef RAMPZ
|
||||
// Since RAMPZ should already be set, we need to use EPLM directly.
|
||||
// do putch(pgm_read_byte_near(address++));
|
||||
// while (--length);
|
||||
do {
|
||||
uint8_t result;
|
||||
__asm__ ("elpm %0,Z\n":"=r"(result):"z"(address));
|
||||
putch(result);
|
||||
address++;
|
||||
}
|
||||
while (--length);
|
||||
#else
|
||||
do putch(pgm_read_byte_near(address++));
|
||||
while (--length);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Get device signature bytes */
|
||||
else if(ch == STK_READ_SIGN)
|
||||
{
|
||||
// READ SIGN - return what Avrdude wants to hear
|
||||
verifySpace();
|
||||
putch(SIGNATURE_0);
|
||||
putch(SIGNATURE_1);
|
||||
putch(SIGNATURE_2);
|
||||
}
|
||||
else if (ch == STK_LEAVE_PROGMODE) { /* 'Q' */
|
||||
// Adaboot no-wait mod
|
||||
|
||||
// watchdogConfig(WATCHDOG_16MS);
|
||||
|
||||
verifySpace();
|
||||
#ifdef MULTI_CALLED
|
||||
putch(STK_OK);
|
||||
while (!(UART_SRA & _BV(TXC0)));
|
||||
appStart() ;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
// This covers the response to commands like STK_ENTER_PROGMODE
|
||||
verifySpace();
|
||||
}
|
||||
putch(STK_OK);
|
||||
}
|
||||
}
|
||||
|
||||
void putch(char ch) {
|
||||
#ifndef SOFT_UART
|
||||
while (!(UART_SRA & _BV(UDRE0)));
|
||||
UART_UDR = ch;
|
||||
#else
|
||||
__asm__ __volatile__ (
|
||||
" com %[ch]\n" // ones complement, carry set
|
||||
" sec\n"
|
||||
"1: brcc 2f\n"
|
||||
" cbi %[uartPort],%[uartBit]\n"
|
||||
" rjmp 3f\n"
|
||||
"2: sbi %[uartPort],%[uartBit]\n"
|
||||
" nop\n"
|
||||
"3: rcall uartDelay\n"
|
||||
" rcall uartDelay\n"
|
||||
" lsr %[ch]\n"
|
||||
" dec %[bitcnt]\n"
|
||||
" brne 1b\n"
|
||||
:
|
||||
:
|
||||
[bitcnt] "d" (10),
|
||||
[ch] "r" (ch),
|
||||
[uartPort] "I" (_SFR_IO_ADDR(UART_PORT)),
|
||||
[uartBit] "I" (UART_TX_BIT)
|
||||
:
|
||||
"r25"
|
||||
);
|
||||
#endif
|
||||
}
|
||||
|
||||
uint8_t getch(void) {
|
||||
uint8_t ch;
|
||||
|
||||
#ifdef LED_DATA_FLASH
|
||||
#ifdef __AVR_ATmega8__
|
||||
LED_PORT ^= _BV(LED);
|
||||
#else
|
||||
LED_PIN |= _BV(LED);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef SOFT_UART
|
||||
__asm__ __volatile__ (
|
||||
"1: sbic %[uartPin],%[uartBit]\n" // Wait for start edge
|
||||
" rjmp 1b\n"
|
||||
" rcall uartDelay\n" // Get to middle of start bit
|
||||
"2: rcall uartDelay\n" // Wait 1 bit period
|
||||
" rcall uartDelay\n" // Wait 1 bit period
|
||||
" clc\n"
|
||||
" sbic %[uartPin],%[uartBit]\n"
|
||||
" sec\n"
|
||||
" dec %[bitCnt]\n"
|
||||
" breq 3f\n"
|
||||
" ror %[ch]\n"
|
||||
" rjmp 2b\n"
|
||||
"3:\n"
|
||||
:
|
||||
[ch] "=r" (ch)
|
||||
:
|
||||
[bitCnt] "d" (9),
|
||||
[uartPin] "I" (_SFR_IO_ADDR(UART_PIN)),
|
||||
[uartBit] "I" (UART_RX_BIT)
|
||||
:
|
||||
"r25"
|
||||
);
|
||||
#else
|
||||
while(!(UART_SRA & _BV(RXC0)))
|
||||
|
||||
// watchdogReset()
|
||||
|
||||
;
|
||||
// if (!(UART_SRA & _BV(FE0))) {
|
||||
/*
|
||||
* A Framing Error indicates (probably) that something is talking
|
||||
* to us at the wrong bit rate. Assume that this is because it
|
||||
* expects to be talking to the application, and DON'T reset the
|
||||
* watchdog. This should cause the bootloader to abort and run
|
||||
* the application "soon", if it keeps happening. (Note that we
|
||||
* don't care that an invalid char is returned...)
|
||||
*/
|
||||
// watchdogReset();
|
||||
// }
|
||||
|
||||
ch = UART_UDR;
|
||||
#endif
|
||||
|
||||
#ifdef LED_DATA_FLASH
|
||||
#ifdef __AVR_ATmega8__
|
||||
LED_PORT ^= _BV(LED);
|
||||
#else
|
||||
LED_PIN |= _BV(LED);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return ch;
|
||||
}
|
||||
|
||||
#ifdef SOFT_UART
|
||||
// AVR305 equation: #define UART_B_VALUE (((F_CPU/BAUD_RATE)-23)/6)
|
||||
// Adding 3 to numerator simulates nearest rounding for more accurate baud rates
|
||||
#define UART_B_VALUE (((F_CPU/BAUD_RATE)-20)/6)
|
||||
#if UART_B_VALUE > 255
|
||||
#error Baud rate too slow for soft UART
|
||||
#endif
|
||||
|
||||
void uartDelay() {
|
||||
__asm__ __volatile__ (
|
||||
"ldi r25,%[count]\n"
|
||||
"1:dec r25\n"
|
||||
"brne 1b\n"
|
||||
"ret\n"
|
||||
::[count] "M" (UART_B_VALUE)
|
||||
);
|
||||
}
|
||||
#endif
|
||||
|
||||
void getNch(uint8_t count) {
|
||||
do getch(); while (--count);
|
||||
verifySpace();
|
||||
}
|
||||
|
||||
void verifySpace()
|
||||
{
|
||||
if ( getch() != CRC_EOP) {
|
||||
|
||||
putch(STK_NOSYNC);
|
||||
// watchdogConfig(WATCHDOG_16MS); // shorten WD timeout
|
||||
//
|
||||
// while (1) // and busy-loop so that WD causes
|
||||
// ; // a reset and app start.
|
||||
}
|
||||
putch(STK_INSYNC);
|
||||
}
|
||||
|
||||
#if LED_START_FLASHES > 0
|
||||
void flash_led(uint8_t count) {
|
||||
do {
|
||||
TCNT1 = -(F_CPU/(1024*16));
|
||||
TIFR1 = _BV(TOV1);
|
||||
while(!(TIFR1 & _BV(TOV1)));
|
||||
//#ifdef __AVR_ATmega8__
|
||||
LED_PORT ^= _BV(LED);
|
||||
//#else
|
||||
// LED_PIN |= _BV(LED);
|
||||
//#endif
|
||||
watchdogReset();
|
||||
} while (--count);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Watchdog functions. These are only safe with interrupts turned off.
|
||||
void watchdogReset() {
|
||||
__asm__ __volatile__ (
|
||||
"wdr\n"
|
||||
);
|
||||
}
|
||||
|
||||
void watchdogConfig(uint8_t x) {
|
||||
WDTCSR = _BV(WDCE) | _BV(WDE);
|
||||
WDTCSR = x;
|
||||
}
|
||||
|
||||
void appStart()
|
||||
{
|
||||
// watchdogConfig(WATCHDOG_OFF);
|
||||
// __asm__ __volatile__ (
|
||||
//#ifdef VIRTUAL_BOOT_PARTITION
|
||||
// // Jump to WDT vector
|
||||
// "ldi r30,4\n"
|
||||
// "clr r31\n"
|
||||
//#else
|
||||
// // Jump to RST vector
|
||||
// "clr r30\n"
|
||||
// "clr r31\n"
|
||||
//#endif
|
||||
// "ijmp\n"
|
||||
// );
|
||||
|
||||
register void (*p)() ;
|
||||
p = 0 ;
|
||||
|
||||
if ( pgm_read_byte( (uint16_t)p ) != 0xFF )
|
||||
{
|
||||
(*p)() ;
|
||||
}
|
||||
}
|
||||
|
@ -1,80 +0,0 @@
|
||||
#if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328__) || defined(__AVR_ATmega88) || defined(__AVR_ATmega8__) || defined(__AVR_ATmega88__)
|
||||
/* Onboard LED is connected to pin PB5 in Arduino NG, Diecimila, and Duemilanove */
|
||||
#define LED_DDR DDRB
|
||||
#define LED_PORT PORTB
|
||||
#define LED_PIN PINB
|
||||
#define LED PINB5
|
||||
|
||||
/* Ports for soft UART */
|
||||
#ifdef SOFT_UART
|
||||
#define UART_PORT PORTD
|
||||
#define UART_PIN PIND
|
||||
#define UART_DDR DDRD
|
||||
#define UART_TX_BIT 1
|
||||
#define UART_RX_BIT 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(__AVR_ATmega8__)
|
||||
//Name conversion R.Wiersma
|
||||
#define UCSR0A UCSRA
|
||||
#define UDR0 UDR
|
||||
#define UDRE0 UDRE
|
||||
#define RXC0 RXC
|
||||
#define FE0 FE
|
||||
#define TIFR1 TIFR
|
||||
#define WDTCSR WDTCR
|
||||
#endif
|
||||
|
||||
/* Luminet support */
|
||||
#if defined(__AVR_ATtiny84__)
|
||||
/* Red LED is connected to pin PA4 */
|
||||
#define LED_DDR DDRA
|
||||
#define LED_PORT PORTA
|
||||
#define LED_PIN PINA
|
||||
#define LED PINA4
|
||||
/* Ports for soft UART - left port only for now. TX/RX on PA2/PA3 */
|
||||
#ifdef SOFT_UART
|
||||
#define UART_PORT PORTA
|
||||
#define UART_PIN PINA
|
||||
#define UART_DDR DDRA
|
||||
#define UART_TX_BIT 2
|
||||
#define UART_RX_BIT 3
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Sanguino support */
|
||||
#if defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__)
|
||||
/* Onboard LED is connected to pin PB0 on Sanguino */
|
||||
#define LED_DDR DDRB
|
||||
#define LED_PORT PORTB
|
||||
#define LED_PIN PINB
|
||||
#define LED PINB0
|
||||
|
||||
/* Ports for soft UART */
|
||||
#ifdef SOFT_UART
|
||||
#define UART_PORT PORTD
|
||||
#define UART_PIN PIND
|
||||
#define UART_DDR DDRD
|
||||
#define UART_TX_BIT 1
|
||||
#define UART_RX_BIT 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Mega support */
|
||||
#if defined(__AVR_ATmega1280__)
|
||||
/* Onboard LED is connected to pin PB7 on Arduino Mega */
|
||||
#define LED_DDR DDRB
|
||||
#define LED_PORT PORTB
|
||||
#define LED_PIN PINB
|
||||
#define LED PINB7
|
||||
|
||||
/* Ports for soft UART */
|
||||
#ifdef SOFT_UART
|
||||
#define UART_PORT PORTE
|
||||
#define UART_PIN PINE
|
||||
#define UART_DDR DDRE
|
||||
#define UART_TX_BIT 1
|
||||
#define UART_RX_BIT 0
|
||||
#endif
|
||||
#endif
|
@ -1,39 +0,0 @@
|
||||
/* STK500 constants list, from AVRDUDE */
|
||||
#define STK_OK 0x10
|
||||
#define STK_FAILED 0x11 // Not used
|
||||
#define STK_UNKNOWN 0x12 // Not used
|
||||
#define STK_NODEVICE 0x13 // Not used
|
||||
#define STK_INSYNC 0x14 // ' '
|
||||
#define STK_NOSYNC 0x15 // Not used
|
||||
#define ADC_CHANNEL_ERROR 0x16 // Not used
|
||||
#define ADC_MEASURE_OK 0x17 // Not used
|
||||
#define PWM_CHANNEL_ERROR 0x18 // Not used
|
||||
#define PWM_ADJUST_OK 0x19 // Not used
|
||||
#define CRC_EOP 0x20 // 'SPACE'
|
||||
#define STK_GET_SYNC 0x30 // '0'
|
||||
#define STK_GET_SIGN_ON 0x31 // '1'
|
||||
#define STK_SET_PARAMETER 0x40 // '@'
|
||||
#define STK_GET_PARAMETER 0x41 // 'A'
|
||||
#define STK_SET_DEVICE 0x42 // 'B'
|
||||
#define STK_SET_DEVICE_EXT 0x45 // 'E'
|
||||
#define STK_ENTER_PROGMODE 0x50 // 'P'
|
||||
#define STK_LEAVE_PROGMODE 0x51 // 'Q'
|
||||
#define STK_CHIP_ERASE 0x52 // 'R'
|
||||
#define STK_CHECK_AUTOINC 0x53 // 'S'
|
||||
#define STK_LOAD_ADDRESS 0x55 // 'U'
|
||||
#define STK_UNIVERSAL 0x56 // 'V'
|
||||
#define STK_PROG_FLASH 0x60 // '`'
|
||||
#define STK_PROG_DATA 0x61 // 'a'
|
||||
#define STK_PROG_FUSE 0x62 // 'b'
|
||||
#define STK_PROG_LOCK 0x63 // 'c'
|
||||
#define STK_PROG_PAGE 0x64 // 'd'
|
||||
#define STK_PROG_FUSE_EXT 0x65 // 'e'
|
||||
#define STK_READ_FLASH 0x70 // 'p'
|
||||
#define STK_READ_DATA 0x71 // 'q'
|
||||
#define STK_READ_FUSE 0x72 // 'r'
|
||||
#define STK_READ_LOCK 0x73 // 's'
|
||||
#define STK_READ_PAGE 0x74 // 't'
|
||||
#define STK_READ_SIGN 0x75 // 'u'
|
||||
#define STK_READ_OSCCAL 0x76 // 'v'
|
||||
#define STK_READ_FUSE_EXT 0x77 // 'w'
|
||||
#define STK_READ_OSCCAL_EXT 0x78 // 'x'
|
@ -1,5 +0,0 @@
|
||||
ATTRS{idProduct}=="1001", ATTRS{idVendor}=="0110", MODE="664", GROUP="plugdev"
|
||||
ATTRS{idProduct}=="1002", ATTRS{idVendor}=="0110", MODE="664", GROUP="plugdev"
|
||||
ATTRS{idProduct}=="0003", ATTRS{idVendor}=="1eaf", MODE="664", GROUP="plugdev" SYMLINK+="maple", ENV{ID_MM_DEVICE_IGNORE}="1"
|
||||
ATTRS{idProduct}=="0004", ATTRS{idVendor}=="1eaf", MODE="664", GROUP="plugdev" SYMLINK+="maple", ENV{ID_MM_DEVICE_IGNORE}="1"
|
||||
|
@ -1,11 +0,0 @@
|
||||
@echo off
|
||||
|
||||
echo Installing MULTI-Module DFU Bootloader Driver...
|
||||
"%~dp0wdi-simple" --vid 0x1EAF --pid 0x0003 --type 2 --name "MULTI-Module DFU Bootloader" --dest "%~dp0MULTI-DFU-Bootloader" -b
|
||||
echo.
|
||||
|
||||
echo Installing MULTI-Module USB Serial Driver...
|
||||
"%~dp0wdi-simple" --vid 0x1EAF --pid 0x0004 --type 3 --name "MULTI-Module USB Serial" --dest "%~dp0MULTI-USB-Serial" -b
|
||||
echo.
|
||||
|
||||
pause
|
@ -1,47 +0,0 @@
|
||||
:108000001F92CDB7DEB7CFD01124809178009FEFBB
|
||||
:1080100090937800837099F088EA91E680936808DD
|
||||
:108020009093690880E180934C0880914C0884FF0C
|
||||
:10803000FCCF109240088091680682FD8FD082E0CC
|
||||
:1080400080936106C12CD12C97D0813479F494D0DF
|
||||
:10805000898399D08981823811F485E005C08138FF
|
||||
:1080600011F484E001C083E080D075C0823411F443
|
||||
:1080700084E103C0853419F485E08CD06CC085356B
|
||||
:1080800059F47AD0C82E78D0D12CD82A8D2D881FBB
|
||||
:108090008827881F8BBF5EC0863521F484E07AD0A4
|
||||
:1080A00080E0E2CF843641F567D066D0F82E64D008
|
||||
:1080B000C601DCD000E010E25FD0F80181938F01AF
|
||||
:1080C000FE12FACF60D0D7FC46C0CBD0C601DAD0C2
|
||||
:1080D000760100E010E2F801619171918F01C70112
|
||||
:1080E000DBD0F2E0EF0EF11C011581E2180799F7E1
|
||||
:1080F000C601E0D0B6D02FC08437C1F43DD03CD00B
|
||||
:10810000F82E3AD040D0F601EC2CEF0C8F010F5F27
|
||||
:108110001F4F84912AD0E01207C0EFEFCE1ADE0A7B
|
||||
:10812000FA94CF0CD11C17C0F801F0CF853739F481
|
||||
:108130002AD08EE11AD085E918D082E495CF813516
|
||||
:1081400049F421D080E111D08091A10886FFFCCFB5
|
||||
:1081500005D001C018D080E108D076CFE0E0F0E093
|
||||
:1081600084918F3F09F0099408959091A10895FF9B
|
||||
:10817000FCCF8093A00808958091A10887FFFCCFD1
|
||||
:108180008091A0080895F8DF803211F085E1EDDFDD
|
||||
:1081900084E1EBCFCF93C82FEFDFC150E9F7CF9148
|
||||
:1081A000F2CFA895089583EC8093520080915000FF
|
||||
:1081B0008860809350008091510083FFFCCF82EC57
|
||||
:1081C0008093550080915000806180935000809191
|
||||
:1081D000510084FFFCCF88ED84BF1092400084BF23
|
||||
:1081E00024E02093400087E08093A20087E88093FA
|
||||
:1081F0008301109241081092420810924308109295
|
||||
:10820000440810924608109247088FEF9FEF809322
|
||||
:1082100066089093670810926008109261088BE0DE
|
||||
:1082200080934008209365062093620688E180933E
|
||||
:10823000720698E0909345069093410692E29093DF
|
||||
:10824000A6081092A7088093A4088091A3088F7CA9
|
||||
:1082500080618093A30883E08093A5088091A008A3
|
||||
:1082600008958091CF0187FDFCCF08958F939F9350
|
||||
:1082700082E2E0ECF1E08287FF91EF918DE984BF2B
|
||||
:10828000E8950895FC0186E28093CA0188ED84BFD9
|
||||
:1082900081E08093CB0108950F921F92FC01062E7E
|
||||
:1082A000172E83E28093CA018DE984BFE8951F9061
|
||||
:1082B0000F900895FC018EE28093CA018DE984BF7E
|
||||
:0482C000E8950895A0
|
||||
:040000030000800079
|
||||
:00000001FF
|
@ -1,503 +0,0 @@
|
||||
# Makefile for ATmegaBOOT
|
||||
# E.Lins, 18.7.2005
|
||||
# $Id$
|
||||
#
|
||||
# Instructions
|
||||
#
|
||||
# To make bootloader .hex file:
|
||||
# make diecimila
|
||||
# make lilypad
|
||||
# make ng
|
||||
# etc...
|
||||
#
|
||||
# To burn bootloader .hex file:
|
||||
# make diecimila_isp
|
||||
# make lilypad_isp
|
||||
# make ng_isp
|
||||
# etc...
|
||||
|
||||
# program name should not be changed...
|
||||
PROGRAM = optiboot
|
||||
|
||||
# The default behavior is to build using tools that are in the users
|
||||
# current path variables, but we can also build using an installed
|
||||
# Arduino user IDE setup, or the Arduino source tree.
|
||||
# Uncomment this next lines to build within the arduino environment,
|
||||
# using the arduino-included avrgcc toolset (mac and pc)
|
||||
# ENV ?= arduino
|
||||
# ENV ?= arduinodev
|
||||
# OS ?= macosx
|
||||
# OS ?= windows
|
||||
|
||||
|
||||
# enter the parameters for the avrdude isp tool -b19200
|
||||
#
|
||||
# These are the parameters for a usb-based STK500v2 programmer.
|
||||
# Exact type unknown. (historical Makefile values.)
|
||||
ISPTOOL = stk500v2
|
||||
ISPPORT = usb
|
||||
ISPSPEED = -b 57600
|
||||
#
|
||||
#
|
||||
# These are parameters for using an Arduino with the ArduinoISP sketch
|
||||
# as the programmer. On a mac, for a particular Uno as programmer.
|
||||
#ISPTOOL = stk500v1 -C /Applications/arduino/arduino-0022/hardware/tools/avr/etc/avrdude.conf
|
||||
#ISPPORT = /dev/tty.usbmodemfd3141
|
||||
#ISPSPEED = -b19200
|
||||
|
||||
MCU_TARGET = atmega168
|
||||
LDSECTIONS = -Wl,--section-start=.text=0x3e00 -Wl,--section-start=.version=0x3ffe
|
||||
|
||||
# Build environments
|
||||
# Start of some ugly makefile-isms to allow optiboot to be built
|
||||
# in several different environments. See the README.TXT file for
|
||||
# details.
|
||||
|
||||
# default
|
||||
fixpath = $(1)
|
||||
|
||||
ifeq ($(ENV), arduino)
|
||||
# For Arduino, we assume that we're connected to the optiboot directory
|
||||
# included with the arduino distribution, which means that the full set
|
||||
# of avr-tools are "right up there" in standard places.
|
||||
TOOLROOT = ../../../tools
|
||||
GCCROOT = $(TOOLROOT)/avr/bin/
|
||||
AVRDUDE_CONF = -C$(TOOLROOT)/avr/etc/avrdude.conf
|
||||
|
||||
ifeq ($(OS), windows)
|
||||
# On windows, SOME of the tool paths will need to have backslashes instead
|
||||
# of forward slashes (because they use windows cmd.exe for execution instead
|
||||
# of a unix/mingw shell?) We also have to ensure that a consistent shell
|
||||
# is used even if a unix shell is installed (ie as part of WINAVR)
|
||||
fixpath = $(subst /,\,$1)
|
||||
SHELL = cmd.exe
|
||||
endif
|
||||
|
||||
else ifeq ($(ENV), arduinodev)
|
||||
# Arduino IDE source code environment. Use the unpacked compilers created
|
||||
# by the build (you'll need to do "ant build" first.)
|
||||
ifeq ($(OS), macosx)
|
||||
TOOLROOT = ../../../../build/macosx/work/Arduino.app/Contents/Resources/Java/hardware/tools
|
||||
endif
|
||||
ifeq ($(OS), windows)
|
||||
TOOLROOT = ../../../../build/windows/work/hardware/tools
|
||||
endif
|
||||
|
||||
GCCROOT = $(TOOLROOT)/avr/bin/
|
||||
AVRDUDE_CONF = -C$(TOOLROOT)/avr/etc/avrdude.conf
|
||||
|
||||
else
|
||||
GCCROOT =
|
||||
AVRDUDE_CONF =
|
||||
endif
|
||||
#
|
||||
# End of build environment code.
|
||||
|
||||
|
||||
# the efuse should really be 0xf8; since, however, only the lower
|
||||
# three bits of that byte are used on the atmega168, avrdude gets
|
||||
# confused if you specify 1's for the higher bits, see:
|
||||
# http://tinker.it/now/2007/02/24/the-tale-of-avrdude-atmega168-and-extended-bits-fuses/
|
||||
#
|
||||
# similarly, the lock bits should be 0xff instead of 0x3f (to
|
||||
# unlock the bootloader section) and 0xcf instead of 0x2f (to
|
||||
# lock it), but since the high two bits of the lock byte are
|
||||
# unused, avrdude would get confused.
|
||||
|
||||
ISPFUSES = $(GCCROOT)avrdude $(AVRDUDE_CONF) -c $(ISPTOOL) \
|
||||
-p $(MCU_TARGET) -P $(ISPPORT) $(ISPSPEED) \
|
||||
-e -u -U lock:w:0x3f:m -U efuse:w:0x$(EFUSE):m \
|
||||
-U hfuse:w:0x$(HFUSE):m -U lfuse:w:0x$(LFUSE):m
|
||||
ISPFLASH = $(GCCROOT)avrdude $(AVRDUDE_CONF) -c $(ISPTOOL) \
|
||||
-p $(MCU_TARGET) -P $(ISPPORT) $(ISPSPEED) \
|
||||
-U flash:w:$(PROGRAM)_$(TARGET).hex -U lock:w:0x2f:m
|
||||
|
||||
STK500 = "C:\Program Files\Atmel\AVR Tools\STK500\Stk500.exe"
|
||||
STK500-1 = $(STK500) -e -d$(MCU_TARGET) -pf -vf -if$(PROGRAM)_$(TARGET).hex \
|
||||
-lFF -LFF -f$(HFUSE)$(LFUSE) -EF8 -ms -q -cUSB -I200kHz -s -wt
|
||||
STK500-2 = $(STK500) -d$(MCU_TARGET) -ms -q -lCF -LCF -cUSB -I200kHz -s -wt
|
||||
|
||||
OBJ = $(PROGRAM).o
|
||||
OPTIMIZE = -Os -fno-inline-small-functions -fno-split-wide-types
|
||||
# -mshort-calls
|
||||
|
||||
DEFS =
|
||||
LIBS =
|
||||
|
||||
CC = $(GCCROOT)avr-gcc
|
||||
|
||||
# Override is only needed by avr-lib build system.
|
||||
|
||||
override CFLAGS = -g -Wall $(OPTIMIZE) -mmcu=$(MCU_TARGET) -DF_CPU=$(AVR_FREQ) $(DEFS)
|
||||
override LDFLAGS = $(LDSECTIONS) -Wl,--relax -Wl,--gc-sections -nostartfiles -nostdlib
|
||||
|
||||
OBJCOPY = $(GCCROOT)avr-objcopy
|
||||
OBJDUMP = $(call fixpath,$(GCCROOT)avr-objdump)
|
||||
|
||||
SIZE = $(GCCROOT)avr-size
|
||||
|
||||
|
||||
|
||||
#Voice board test
|
||||
# ATmega328
|
||||
#
|
||||
#atmega328: TARGET = atmega328p
|
||||
#atmega328: MCU_TARGET = atmega328p
|
||||
#atmega328: CFLAGS += '-DLED_START_FLASHES=0' '-DBAUD_RATE=38400'
|
||||
#atmega328: AVR_FREQ = 12000000L
|
||||
#atmega328: LDSECTIONS = -Wl,--section-start=.text=0x7e00 -Wl,--section-start=.version=0x7ffe
|
||||
#atmega328: $(PROGRAM)_atmega328.hex
|
||||
#atmega328: $(PROGRAM)_atmega328.lst
|
||||
|
||||
xmega32D4: TARGET = atxmega32d4
|
||||
xmega32D4: MCU_TARGET = atxmega32d4
|
||||
xmega32D4: CFLAGS += '-DLED_START_FLASHES=0' '-DBAUD_RATE=57600'
|
||||
xmega32D4: AVR_FREQ = 32000000L
|
||||
xmega32D4: LDSECTIONS = -Wl,--section-start=.text=0x8000
|
||||
xmega32D4: $(PROGRAM)_xmega32d4.hex
|
||||
xmega32D4: $(PROGRAM)_xmega32d4.lst
|
||||
|
||||
atmega328: TARGET = atmega328
|
||||
atmega328: MCU_TARGET = atmega328p
|
||||
atmega328: CFLAGS += '-DLED_START_FLASHES=0' '-DBAUD_RATE=57600'
|
||||
atmega328: AVR_FREQ = 16000000L
|
||||
atmega328: LDSECTIONS = -Wl,--section-start=.text=0x7e00 -Wl,--section-start=.version=0x7ffe
|
||||
atmega328: $(PROGRAM)_atmega328_16.hex
|
||||
atmega328: $(PROGRAM)_atmega328_16.lst
|
||||
|
||||
|
||||
# Test platforms
|
||||
# Virtual boot block test
|
||||
virboot328: TARGET = atmega328
|
||||
virboot328: MCU_TARGET = atmega328p
|
||||
virboot328: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=38400' '-DVIRTUAL_BOOT'
|
||||
virboot328: AVR_FREQ = 16000000L
|
||||
virboot328: LDSECTIONS = -Wl,--section-start=.text=0x7e00 -Wl,--section-start=.version=0x7ffe
|
||||
virboot328: $(PROGRAM)_atmega328.hex
|
||||
virboot328: $(PROGRAM)_atmega328.lst
|
||||
|
||||
# 20MHz clocked platforms
|
||||
#
|
||||
# These are capable of 230400 baud, or 38400 baud on PC (Arduino Avrdude issue)
|
||||
#
|
||||
|
||||
pro20: TARGET = pro_20mhz
|
||||
pro20: MCU_TARGET = atmega168
|
||||
pro20: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=38400'
|
||||
pro20: AVR_FREQ = 20000000L
|
||||
pro20: $(PROGRAM)_pro_20mhz.hex
|
||||
pro20: $(PROGRAM)_pro_20mhz.lst
|
||||
|
||||
pro20_isp: pro20
|
||||
pro20_isp: TARGET = pro_20mhz
|
||||
# 2.7V brownout
|
||||
pro20_isp: HFUSE = DD
|
||||
# Full swing xtal (20MHz) 258CK/14CK+4.1ms
|
||||
pro20_isp: LFUSE = C6
|
||||
# 512 byte boot
|
||||
pro20_isp: EFUSE = 04
|
||||
pro20_isp: isp
|
||||
|
||||
# 16MHz clocked platforms
|
||||
#
|
||||
# These are capable of 230400 baud, or 38400 baud on PC (Arduino Avrdude issue)
|
||||
#
|
||||
|
||||
pro16: TARGET = pro_16MHz
|
||||
pro16: MCU_TARGET = atmega168
|
||||
pro16: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=38400'
|
||||
pro16: AVR_FREQ = 16000000L
|
||||
pro16: $(PROGRAM)_pro_16MHz.hex
|
||||
pro16: $(PROGRAM)_pro_16MHz.lst
|
||||
|
||||
pro16_isp: pro16
|
||||
pro16_isp: TARGET = pro_16MHz
|
||||
# 2.7V brownout
|
||||
pro16_isp: HFUSE = DD
|
||||
# Full swing xtal (20MHz) 258CK/14CK+4.1ms
|
||||
pro16_isp: LFUSE = C6
|
||||
# 512 byte boot
|
||||
pro16_isp: EFUSE = 04
|
||||
pro16_isp: isp
|
||||
|
||||
# Diecimila, Duemilanove with m168, and NG use identical bootloaders
|
||||
# Call it "atmega168" for generality and clarity, keep "diecimila" for
|
||||
# backward compatibility of makefile
|
||||
#
|
||||
atmega168: TARGET = atmega168
|
||||
atmega168: MCU_TARGET = atmega168
|
||||
atmega168: CFLAGS += '-DLED_START_FLASHES=0' '-DBAUD_RATE=38400'
|
||||
atmega168: AVR_FREQ = 12000000L
|
||||
atmega168: $(PROGRAM)_atmega168.hex
|
||||
atmega168: $(PROGRAM)_atmega168.lst
|
||||
|
||||
atmega168_isp: atmega168
|
||||
atmega168_isp: TARGET = atmega168
|
||||
# 2.7V brownout
|
||||
atmega168_isp: HFUSE = DD
|
||||
# Low power xtal (16MHz) 16KCK/14CK+65ms
|
||||
atmega168_isp: LFUSE = FF
|
||||
# 512 byte boot
|
||||
atmega168_isp: EFUSE = 04
|
||||
atmega168_isp: isp
|
||||
|
||||
diecimila: TARGET = diecimila
|
||||
diecimila: MCU_TARGET = atmega168
|
||||
diecimila: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=38400'
|
||||
diecimila: AVR_FREQ = 16000000L
|
||||
diecimila: $(PROGRAM)_diecimila.hex
|
||||
diecimila: $(PROGRAM)_diecimila.lst
|
||||
|
||||
diecimila_isp: diecimila
|
||||
diecimila_isp: TARGET = diecimila
|
||||
# 2.7V brownout
|
||||
diecimila_isp: HFUSE = DD
|
||||
# Low power xtal (16MHz) 16KCK/14CK+65ms
|
||||
diecimila_isp: LFUSE = FF
|
||||
# 512 byte boot
|
||||
diecimila_isp: EFUSE = 04
|
||||
diecimila_isp: isp
|
||||
|
||||
atmega328_isp: atmega328
|
||||
atmega328_isp: TARGET = atmega328
|
||||
atmega328_isp: MCU_TARGET = atmega328p
|
||||
# 512 byte boot, SPIEN
|
||||
atmega328_isp: HFUSE = DE
|
||||
# Low power xtal (16MHz) 16KCK/14CK+65ms
|
||||
atmega328_isp: LFUSE = FF
|
||||
# 2.7V brownout
|
||||
atmega328_isp: EFUSE = FD
|
||||
atmega328_isp: isp
|
||||
|
||||
atmega1284: TARGET = atmega1284p
|
||||
atmega1284: MCU_TARGET = atmega1284p
|
||||
atmega1284: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=38400' '-DBIGBOOT'
|
||||
atmega1284: AVR_FREQ = 16000000L
|
||||
atmega1284: LDSECTIONS = -Wl,--section-start=.text=0x1fc00 -Wl,--section-start=.version=0x1fffe
|
||||
atmega1284: $(PROGRAM)_atmega1284p.hex
|
||||
atmega1284: $(PROGRAM)_atmega1284p.lst
|
||||
|
||||
atmega1284_isp: atmega1284
|
||||
atmega1284_isp: TARGET = atmega1284p
|
||||
atmega1284_isp: MCU_TARGET = atmega1284p
|
||||
# 1024 byte boot
|
||||
atmega1284_isp: HFUSE = DE
|
||||
# Low power xtal (16MHz) 16KCK/14CK+65ms
|
||||
atmega1284_isp: LFUSE = FF
|
||||
# 2.7V brownout
|
||||
atmega1284_isp: EFUSE = FD
|
||||
atmega1284_isp: isp
|
||||
|
||||
# Sanguino has a minimum boot size of 1024 bytes, so enable extra functions
|
||||
#
|
||||
sanguino: TARGET = atmega644p
|
||||
sanguino: MCU_TARGET = atmega644p
|
||||
sanguino: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=38400' '-DBIGBOOT'
|
||||
sanguino: AVR_FREQ = 16000000L
|
||||
sanguino: LDSECTIONS = -Wl,--section-start=.text=0xfc00 -Wl,--section-start=.version=0xfffe
|
||||
sanguino: $(PROGRAM)_atmega644p.hex
|
||||
sanguino: $(PROGRAM)_atmega644p.lst
|
||||
|
||||
sanguino_isp: sanguino
|
||||
sanguino_isp: TARGET = atmega644p
|
||||
sanguino_isp: MCU_TARGET = atmega644p
|
||||
# 1024 byte boot
|
||||
sanguino_isp: HFUSE = DE
|
||||
# Low power xtal (16MHz) 16KCK/14CK+65ms
|
||||
sanguino_isp: LFUSE = FF
|
||||
# 2.7V brownout
|
||||
sanguino_isp: EFUSE = FD
|
||||
sanguino_isp: isp
|
||||
|
||||
# Mega has a minimum boot size of 1024 bytes, so enable extra functions
|
||||
#mega: TARGET = atmega1280
|
||||
mega1280: MCU_TARGET = atmega1280
|
||||
mega1280: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=38400' '-DBIGBOOT'
|
||||
mega1280: AVR_FREQ = 16000000L
|
||||
mega1280: LDSECTIONS = -Wl,--section-start=.text=0x1fc00 -Wl,--section-start=.version=0x1fffe
|
||||
mega1280: $(PROGRAM)_atmega1280.hex
|
||||
mega1280: $(PROGRAM)_atmega1280.lst
|
||||
|
||||
mega1280_isp: mega
|
||||
mega1280_isp: TARGET = atmega1280
|
||||
mega1280_isp: MCU_TARGET = atmega1280
|
||||
# 1024 byte boot
|
||||
mega1280_isp: HFUSE = DE
|
||||
# Low power xtal (16MHz) 16KCK/14CK+65ms
|
||||
mega1280_isp: LFUSE = FF
|
||||
# 2.7V brownout
|
||||
mega1280_isp: EFUSE = FD
|
||||
mega1280_isp: isp
|
||||
|
||||
# ATmega8
|
||||
#
|
||||
atmega8: TARGET = atmega8
|
||||
atmega8: MCU_TARGET = atmega8
|
||||
atmega8: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=38400'
|
||||
atmega8: AVR_FREQ = 16000000L
|
||||
atmega8: LDSECTIONS = -Wl,--section-start=.text=0x1e00 -Wl,--section-start=.version=0x1ffe
|
||||
atmega8: $(PROGRAM)_atmega8.hex
|
||||
atmega8: $(PROGRAM)_atmega8.lst
|
||||
|
||||
atmega8_isp: atmega8
|
||||
atmega8_isp: TARGET = atmega8
|
||||
atmega8_isp: MCU_TARGET = atmega8
|
||||
# SPIEN, CKOPT, Bootsize=512B
|
||||
atmega8_isp: HFUSE = CC
|
||||
# 2.7V brownout, Low power xtal (16MHz) 16KCK/14CK+65ms
|
||||
atmega8_isp: LFUSE = BF
|
||||
atmega8_isp: isp
|
||||
|
||||
# ATmega88
|
||||
#
|
||||
atmega88: TARGET = atmega88
|
||||
atmega88: MCU_TARGET = atmega88
|
||||
atmega88: CFLAGS += '-DLED_START_FLASHES=0' '-DBAUD_RATE=38400'
|
||||
atmega88: AVR_FREQ = 12000000L
|
||||
atmega88: LDSECTIONS = -Wl,--section-start=.text=0x1e00 -Wl,--section-start=.version=0x1ffe
|
||||
atmega88: $(PROGRAM)_atmega88.hex
|
||||
atmega88: $(PROGRAM)_atmega88.lst
|
||||
|
||||
atmega88_isp: atmega88
|
||||
atmega88_isp: TARGET = atmega88
|
||||
atmega88_isp: MCU_TARGET = atmega88
|
||||
# 2.7V brownout
|
||||
atmega88_isp: HFUSE = DD
|
||||
# Low power xtal (16MHz) 16KCK/14CK+65ms
|
||||
atemga88_isp: LFUSE = FF
|
||||
# 512 byte boot
|
||||
atmega88_isp: EFUSE = 04
|
||||
atmega88_isp: isp
|
||||
|
||||
|
||||
# 8MHz clocked platforms
|
||||
#
|
||||
# These are capable of 38400 baud
|
||||
#
|
||||
|
||||
lilypad: TARGET = lilypad
|
||||
lilypad: MCU_TARGET = atmega168
|
||||
lilypad: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=38400'
|
||||
lilypad: AVR_FREQ = 8000000L
|
||||
lilypad: $(PROGRAM)_lilypad.hex
|
||||
lilypad: $(PROGRAM)_lilypad.lst
|
||||
|
||||
lilypad_isp: lilypad
|
||||
lilypad_isp: TARGET = lilypad
|
||||
# 2.7V brownout
|
||||
lilypad_isp: HFUSE = DD
|
||||
# Internal 8MHz osc (8MHz) Slow rising power
|
||||
lilypad_isp: LFUSE = E2
|
||||
# 512 byte boot
|
||||
lilypad_isp: EFUSE = 04
|
||||
lilypad_isp: isp
|
||||
|
||||
lilypad_resonator: TARGET = lilypad_resonator
|
||||
lilypad_resonator: MCU_TARGET = atmega168
|
||||
lilypad_resonator: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=38400'
|
||||
lilypad_resonator: AVR_FREQ = 8000000L
|
||||
lilypad_resonator: $(PROGRAM)_lilypad_resonator.hex
|
||||
lilypad_resonator: $(PROGRAM)_lilypad_resonator.lst
|
||||
|
||||
lilypad_resonator_isp: lilypad_resonator
|
||||
lilypad_resonator_isp: TARGET = lilypad_resonator
|
||||
# 2.7V brownout
|
||||
lilypad_resonator_isp: HFUSE = DD
|
||||
# Full swing xtal (20MHz) 258CK/14CK+4.1ms
|
||||
lilypad_resonator_isp: LFUSE = C6
|
||||
# 512 byte boot
|
||||
lilypad_resonator_isp: EFUSE = 04
|
||||
lilypad_resonator_isp: isp
|
||||
|
||||
pro8: TARGET = pro_8MHz
|
||||
pro8: MCU_TARGET = atmega168
|
||||
pro8: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=38400'
|
||||
pro8: AVR_FREQ = 8000000L
|
||||
pro8: $(PROGRAM)_pro_8MHz.hex
|
||||
pro8: $(PROGRAM)_pro_8MHz.lst
|
||||
|
||||
pro8_isp: pro8
|
||||
pro8_isp: TARGET = pro_8MHz
|
||||
# 2.7V brownout
|
||||
pro8_isp: HFUSE = DD
|
||||
# Full swing xtal (20MHz) 258CK/14CK+4.1ms
|
||||
pro8_isp: LFUSE = C6
|
||||
# 512 byte boot
|
||||
pro8_isp: EFUSE = 04
|
||||
pro8_isp: isp
|
||||
|
||||
atmega328_pro8: TARGET = atmega328_pro_8MHz
|
||||
atmega328_pro8: MCU_TARGET = atmega328p
|
||||
atmega328_pro8: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=38400'
|
||||
atmega328_pro8: AVR_FREQ = 8000000L
|
||||
atmega328_pro8: LDSECTIONS = -Wl,--section-start=.text=0x7e00 -Wl,--section-start=.version=0x7ffe
|
||||
atmega328_pro8: $(PROGRAM)_atmega328_pro_8MHz.hex
|
||||
atmega328_pro8: $(PROGRAM)_atmega328_pro_8MHz.lst
|
||||
|
||||
atmega328_pro8_isp: atmega328_pro8
|
||||
atmega328_pro8_isp: TARGET = atmega328_pro_8MHz
|
||||
atmega328_pro8_isp: MCU_TARGET = atmega328p
|
||||
# 512 byte boot, SPIEN
|
||||
atmega328_pro8_isp: HFUSE = DE
|
||||
# Low power xtal (16MHz) 16KCK/14CK+65ms
|
||||
atmega328_pro8_isp: LFUSE = FF
|
||||
# 2.7V brownout
|
||||
atmega328_pro8_isp: EFUSE = DE
|
||||
atmega328_pro8_isp: isp
|
||||
|
||||
# 1MHz clocked platforms
|
||||
#
|
||||
# These are capable of 9600 baud
|
||||
#
|
||||
|
||||
luminet: TARGET = luminet
|
||||
luminet: MCU_TARGET = attiny84
|
||||
luminet: CFLAGS += '-DLED_START_FLASHES=3' '-DSOFT_UART' '-DBAUD_RATE=9600'
|
||||
luminet: CFLAGS += '-DVIRTUAL_BOOT_PARTITION'
|
||||
luminet: AVR_FREQ = 1000000L
|
||||
luminet: LDSECTIONS = -Wl,--section-start=.text=0x1d00 -Wl,--section-start=.version=0x1efe
|
||||
luminet: $(PROGRAM)_luminet.hex
|
||||
luminet: $(PROGRAM)_luminet.lst
|
||||
|
||||
luminet_isp: luminet
|
||||
luminet_isp: TARGET = luminet
|
||||
luminet_isp: MCU_TARGET = attiny84
|
||||
# Brownout disabled
|
||||
luminet_isp: HFUSE = DF
|
||||
# 1MHz internal oscillator, slowly rising power
|
||||
luminet_isp: LFUSE = 62
|
||||
# Self-programming enable
|
||||
luminet_isp: EFUSE = FE
|
||||
luminet_isp: isp
|
||||
|
||||
#
|
||||
# Generic build instructions
|
||||
#
|
||||
#
|
||||
|
||||
isp: $(TARGET)
|
||||
$(ISPFUSES)
|
||||
$(ISPFLASH)
|
||||
|
||||
isp-stk500: $(PROGRAM)_$(TARGET).hex
|
||||
$(STK500-1)
|
||||
$(STK500-2)
|
||||
|
||||
%.elf: $(OBJ)
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||
$(SIZE) $@
|
||||
|
||||
clean:
|
||||
rm -rf *.o *.elf *.lst *.map *.sym *.lss *.eep *.srec *.bin *.hex
|
||||
|
||||
%.lst: %.elf
|
||||
$(OBJDUMP) -h -S $< > $@
|
||||
|
||||
%.hex: %.elf
|
||||
$(OBJCOPY) -j .text -j .data -j .version --set-section-flags .version=alloc,load -O ihex $< $@
|
||||
|
||||
%.srec: %.elf
|
||||
$(OBJCOPY) -j .text -j .data -j .version --set-section-flags .version=alloc,load -O srec $< $@
|
||||
|
||||
%.bin: %.elf
|
||||
$(OBJCOPY) -j .text -j .data -j .version --set-section-flags .version=alloc,load -O binary $< $@
|
@ -1,980 +0,0 @@
|
||||
/**********************************************************/
|
||||
/* Optiboot bootloader for Xmega */
|
||||
/* */
|
||||
/* http://optiboot.googlecode.com */
|
||||
/* */
|
||||
/* Arduino-maintained version : See README.TXT */
|
||||
/* http://code.google.com/p/arduino/ */
|
||||
/* It is the intent that changes not relevant to the */
|
||||
/* Arduino production envionment get moved from the */
|
||||
/* optiboot project to the arduino project in "lumps." */
|
||||
/* */
|
||||
/* Heavily optimised bootloader that is faster and */
|
||||
/* smaller than the Arduino standard bootloader */
|
||||
/* */
|
||||
/* Enhancements: */
|
||||
/* Fits in 512 bytes, saving 1.5K of code space */
|
||||
/* Background page erasing speeds up programming */
|
||||
/* Higher baud rate speeds up programming */
|
||||
/* Written almost entirely in C */
|
||||
/* Customisable timeout with accurate timeconstant */
|
||||
/* Optional virtual UART. No hardware UART required. */
|
||||
/* Optional virtual boot partition for devices without. */
|
||||
/* */
|
||||
/* What you lose: */
|
||||
/* Implements a skeleton STK500 protocol which is */
|
||||
/* missing several features including EEPROM */
|
||||
/* programming and non-page-aligned writes */
|
||||
/* High baud rate breaks compatibility with standard */
|
||||
/* Arduino flash settings */
|
||||
/* */
|
||||
/* Fully supported: */
|
||||
/* ATmega168 based devices (Diecimila etc) */
|
||||
/* ATmega328P based devices (Duemilanove etc) */
|
||||
/* */
|
||||
/* Beta test (believed working.) */
|
||||
/* ATmega8 based devices (Arduino legacy) */
|
||||
/* ATmega328 non-picopower devices */
|
||||
/* ATmega644P based devices (Sanguino) */
|
||||
/* ATmega1284P based devices */
|
||||
/* */
|
||||
/* Alpha test */
|
||||
/* ATmega1280 based devices (Arduino Mega) */
|
||||
/* */
|
||||
/* Work in progress: */
|
||||
/* ATtiny84 based devices (Luminet) */
|
||||
/* */
|
||||
/* Does not support: */
|
||||
/* USB based devices (eg. Teensy) */
|
||||
/* */
|
||||
/* Assumptions: */
|
||||
/* The code makes several assumptions that reduce the */
|
||||
/* code size. They are all true after a hardware reset, */
|
||||
/* but may not be true if the bootloader is called by */
|
||||
/* other means or on other hardware. */
|
||||
/* No interrupts can occur */
|
||||
/* UART and Timer 1 are set to their reset state */
|
||||
/* SP points to RAMEND */
|
||||
/* */
|
||||
/* Code builds on code, libraries and optimisations from: */
|
||||
/* stk500boot.c by Jason P. Kyle */
|
||||
/* Arduino bootloader http://arduino.cc */
|
||||
/* Spiff's 1K bootloader http://spiffie.org/know/arduino_1k_bootloader/bootloader.shtml */
|
||||
/* avr-libc project http://nongnu.org/avr-libc */
|
||||
/* Adaboot http://www.ladyada.net/library/arduino/bootloader.html */
|
||||
/* AVR305 Atmel Application Note */
|
||||
/* */
|
||||
/* This program is free software; you can redistribute it */
|
||||
/* and/or modify it under the terms of the GNU General */
|
||||
/* Public License as published by the Free Software */
|
||||
/* Foundation; either version 2 of the License, or */
|
||||
/* (at your option) any later version. */
|
||||
/* */
|
||||
/* This program is distributed in the hope that it will */
|
||||
/* be useful, but WITHOUT ANY WARRANTY; without even the */
|
||||
/* implied warranty of MERCHANTABILITY or FITNESS FOR A */
|
||||
/* PARTICULAR PURPOSE. See the GNU General Public */
|
||||
/* License for more details. */
|
||||
/* */
|
||||
/* You should have received a copy of the GNU General */
|
||||
/* Public License along with this program; if not, write */
|
||||
/* to the Free Software Foundation, Inc., */
|
||||
/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
/* */
|
||||
/* Licence can be viewed at */
|
||||
/* http://www.fsf.org/licenses/gpl.txt */
|
||||
/* */
|
||||
/**********************************************************/
|
||||
|
||||
|
||||
/**********************************************************/
|
||||
/* */
|
||||
/* Optional defines: */
|
||||
/* */
|
||||
/**********************************************************/
|
||||
/* */
|
||||
/* BIG_BOOT: */
|
||||
/* Build a 1k bootloader, not 512 bytes. This turns on */
|
||||
/* extra functionality. */
|
||||
/* */
|
||||
/* BAUD_RATE: */
|
||||
/* Set bootloader baud rate. */
|
||||
/* */
|
||||
/* LUDICROUS_SPEED: */
|
||||
/* 230400 baud :-) */
|
||||
/* */
|
||||
/* SOFT_UART: */
|
||||
/* Use AVR305 soft-UART instead of hardware UART. */
|
||||
/* */
|
||||
/* LED_START_FLASHES: */
|
||||
/* Number of LED flashes on bootup. */
|
||||
/* */
|
||||
/* LED_DATA_FLASH: */
|
||||
/* Flash LED when transferring data. For boards without */
|
||||
/* TX or RX LEDs, or for people who like blinky lights. */
|
||||
/* */
|
||||
/* SUPPORT_EEPROM: */
|
||||
/* Support reading and writing from EEPROM. This is not */
|
||||
/* used by Arduino, so off by default. */
|
||||
/* */
|
||||
/* TIMEOUT_MS: */
|
||||
/* Bootloader timeout period, in milliseconds. */
|
||||
/* 500,1000,2000,4000,8000 supported. */
|
||||
/* */
|
||||
/* UART: */
|
||||
/* UART number (0..n) for devices with more than */
|
||||
/* one hardware uart (644P, 1284P, etc) */
|
||||
/* */
|
||||
/**********************************************************/
|
||||
|
||||
/**********************************************************/
|
||||
/* Version Numbers! */
|
||||
/* */
|
||||
/* Arduino Optiboot now includes this Version number in */
|
||||
/* the source and object code. */
|
||||
/* */
|
||||
/* Version 3 was released as zip from the optiboot */
|
||||
/* repository and was distributed with Arduino 0022. */
|
||||
/* Version 4 starts with the arduino repository commit */
|
||||
/* that brought the arduino repository up-to-date with */
|
||||
/* the optiboot source tree changes since v3. */
|
||||
/* */
|
||||
/**********************************************************/
|
||||
|
||||
/**********************************************************/
|
||||
/* Edit History: */
|
||||
/* */
|
||||
/* Nov 2012 */
|
||||
/* Specific version for 9x voice module */
|
||||
/* by Mike Blandford */
|
||||
/* Mar 2012 */
|
||||
/* 4.5 WestfW: add infrastructure for non-zero UARTS. */
|
||||
/* 4.5 WestfW: fix SIGNATURE_2 for m644 (bad in avr-libc) */
|
||||
/* Jan 2012: */
|
||||
/* 4.5 WestfW: fix NRWW value for m1284. */
|
||||
/* 4.4 WestfW: use attribute OS_main instead of naked for */
|
||||
/* main(). This allows optimizations that we */
|
||||
/* count on, which are prohibited in naked */
|
||||
/* functions due to PR42240. (keeps us less */
|
||||
/* than 512 bytes when compiler is gcc4.5 */
|
||||
/* (code from 4.3.2 remains the same.) */
|
||||
/* 4.4 WestfW and Maniacbug: Add m1284 support. This */
|
||||
/* does not change the 328 binary, so the */
|
||||
/* version number didn't change either. (?) */
|
||||
/* June 2011: */
|
||||
/* 4.4 WestfW: remove automatic soft_uart detect (didn't */
|
||||
/* know what it was doing or why.) Added a */
|
||||
/* check of the calculated BRG value instead. */
|
||||
/* Version stays 4.4; existing binaries are */
|
||||
/* not changed. */
|
||||
/* 4.4 WestfW: add initialization of address to keep */
|
||||
/* the compiler happy. Change SC'ed targets. */
|
||||
/* Return the SW version via READ PARAM */
|
||||
/* 4.3 WestfW: catch framing errors in getch(), so that */
|
||||
/* AVRISP works without HW kludges. */
|
||||
/* http://code.google.com/p/arduino/issues/detail?id=368n*/
|
||||
/* 4.2 WestfW: reduce code size, fix timeouts, change */
|
||||
/* verifySpace to use WDT instead of appstart */
|
||||
/* 4.1 WestfW: put version number in binary. */
|
||||
/**********************************************************/
|
||||
|
||||
#define OPTIBOOT_MAJVER 4
|
||||
#define OPTIBOOT_MINVER 5
|
||||
|
||||
#define MULTI_CALLED 1
|
||||
|
||||
#define MAKESTR(a) #a
|
||||
#define MAKEVER(a, b) MAKESTR(a*256+b)
|
||||
|
||||
// Page Size is 128 words (256 bytes)
|
||||
|
||||
//asm(" .section .version\n"
|
||||
// "optiboot_version: .word " MAKEVER(OPTIBOOT_MAJVER, OPTIBOOT_MINVER) "\n"
|
||||
// " .section .text\n");
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <avr/io.h>
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
// <avr/boot.h> uses sts instructions, but this version uses out instructions
|
||||
// This saves cycles and program memory.
|
||||
//#include "boot.h"
|
||||
|
||||
|
||||
// We don't use <avr/wdt.h> as those routines have interrupt overhead we don't need.
|
||||
|
||||
#include "pin_defs.h"
|
||||
#include "stk500.h"
|
||||
|
||||
#define BIND_pin 2 //PD2
|
||||
#define BIND_port PORTD
|
||||
#define IS_BIND_BUTTON_on ( (BIND_port.IN & _BV(BIND_pin)) == 0x00 )
|
||||
|
||||
#ifndef LED_START_FLASHES
|
||||
#define LED_START_FLASHES 0
|
||||
#endif
|
||||
|
||||
#ifdef LUDICROUS_SPEED
|
||||
#define BAUD_RATE 230400L
|
||||
#endif
|
||||
|
||||
/* set the UART baud rate defaults */
|
||||
#ifndef BAUD_RATE
|
||||
#if F_CPU >= 8000000L
|
||||
#define BAUD_RATE 38400L // Highest rate Avrdude win32 will support
|
||||
#elsif F_CPU >= 1000000L
|
||||
#define BAUD_RATE 9600L // 19200 also supported, but with significant error
|
||||
#elsif F_CPU >= 128000L
|
||||
#define BAUD_RATE 4800L // Good for 128kHz internal RC
|
||||
#else
|
||||
#define BAUD_RATE 1200L // Good even at 32768Hz
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef UART
|
||||
#define UART 0
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
/* Switch in soft UART for hard baud rates */
|
||||
/*
|
||||
* I don't understand what this was supposed to accomplish, where the
|
||||
* constant "280" came from, or why automatically (and perhaps unexpectedly)
|
||||
* switching to a soft uart is a good thing, so I'm undoing this in favor
|
||||
* of a range check using the same calc used to config the BRG...
|
||||
*/
|
||||
#if (F_CPU/BAUD_RATE) > 280 // > 57600 for 16MHz
|
||||
#ifndef SOFT_UART
|
||||
#define SOFT_UART
|
||||
#endif
|
||||
#endif
|
||||
#else // 0
|
||||
#if (F_CPU + BAUD_RATE * 4L) / (BAUD_RATE * 8L) - 1 > 250
|
||||
#error Unachievable baud rate (too slow) BAUD_RATE
|
||||
#endif // baud rate slow check
|
||||
#if (F_CPU + BAUD_RATE * 4L) / (BAUD_RATE * 8L) - 1 < 3
|
||||
#error Unachievable baud rate (too fast) BAUD_RATE
|
||||
#endif // baud rate fastn check
|
||||
#endif
|
||||
|
||||
/* Watchdog settings */
|
||||
#define WATCHDOG_OFF (0)
|
||||
#define WATCHDOG_16MS (_BV(WDE))
|
||||
#define WATCHDOG_32MS (_BV(WDP0) | _BV(WDE))
|
||||
#define WATCHDOG_64MS (_BV(WDP1) | _BV(WDE))
|
||||
#define WATCHDOG_125MS (_BV(WDP1) | _BV(WDP0) | _BV(WDE))
|
||||
#define WATCHDOG_250MS (_BV(WDP2) | _BV(WDE))
|
||||
#define WATCHDOG_500MS (_BV(WDP2) | _BV(WDP0) | _BV(WDE))
|
||||
#define WATCHDOG_1S (_BV(WDP2) | _BV(WDP1) | _BV(WDE))
|
||||
#define WATCHDOG_2S (_BV(WDP2) | _BV(WDP1) | _BV(WDP0) | _BV(WDE))
|
||||
#ifndef __AVR_ATmega8__
|
||||
#define WATCHDOG_4S (_BV(WDP3) | _BV(WDE))
|
||||
#define WATCHDOG_8S (_BV(WDP3) | _BV(WDP0) | _BV(WDE))
|
||||
#endif
|
||||
|
||||
/* Function Prototypes */
|
||||
/* The main function is in init9, which removes the interrupt vector table */
|
||||
/* we don't need. It is also 'naked', which means the compiler does not */
|
||||
/* generate any entry or exit code itself. */
|
||||
int main(void) __attribute__ ((OS_main)) __attribute__ ((noreturn)) __attribute__ ((section (".init9")));
|
||||
void putch(char);
|
||||
uint8_t getch(void);
|
||||
static inline void getNch(uint8_t); /* "static inline" is a compiler hint to reduce code size */
|
||||
void verifySpace();
|
||||
#if LED_START_FLASHES > 0
|
||||
static inline void flash_led(uint8_t);
|
||||
#endif
|
||||
uint8_t getLen();
|
||||
//static inline void watchdogReset();
|
||||
void watchdogConfig(uint8_t x);
|
||||
#ifdef SOFT_UART
|
||||
void uartDelay() __attribute__ ((naked));
|
||||
#endif
|
||||
static void appStart() ; // __attribute__ ((naked));
|
||||
void boot_spm_busy_wait() ;
|
||||
void __boot_page_erase_short( uint16_t address ) ;
|
||||
void __boot_page_fill_short( uint16_t address, uint16_t data) ;
|
||||
void __boot_page_write_short( uint16_t address) ;
|
||||
void __boot_erase_flash_buffer( uint16_t address ) ;
|
||||
void init() ;
|
||||
|
||||
/*
|
||||
* NRWW memory
|
||||
* Addresses below NRWW (Non-Read-While-Write) can be programmed while
|
||||
* continuing to run code from flash, slightly speeding up programming
|
||||
* time. Beware that Atmel data sheets specify this as a WORD address,
|
||||
* while optiboot will be comparing against a 16-bit byte address. This
|
||||
* means that on a part with 128kB of memory, the upper part of the lower
|
||||
* 64k will get NRWW processing as well, even though it doesn't need it.
|
||||
* That's OK. In fact, you can disable the overlapping processing for
|
||||
* a part entirely by setting NRWWSTART to zero. This reduces code
|
||||
* space a bit, at the expense of being slightly slower, overall.
|
||||
*
|
||||
* RAMSTART should be self-explanatory. It's bigger on parts with a
|
||||
* lot of peripheral registers.
|
||||
*/
|
||||
#if defined(__AVR_ATmega168__)
|
||||
#define RAMSTART (0x100)
|
||||
#define NRWWSTART (0x3800)
|
||||
#elif defined(__AVR_ATmega328P__)
|
||||
#define RAMSTART (0x100)
|
||||
#define NRWWSTART (0x7000)
|
||||
#elif defined(__AVR_ATmega328__)
|
||||
#define RAMSTART (0x100)
|
||||
#define NRWWSTART (0x7000)
|
||||
#elif defined (__AVR_ATmega644P__)
|
||||
#define RAMSTART (0x100)
|
||||
#define NRWWSTART (0xE000)
|
||||
// correct for a bug in avr-libc
|
||||
#undef SIGNATURE_2
|
||||
#define SIGNATURE_2 0x0A
|
||||
#elif defined (__AVR_ATmega1284P__)
|
||||
#define RAMSTART (0x100)
|
||||
#define NRWWSTART (0xE000)
|
||||
#elif defined(__AVR_ATtiny84__)
|
||||
#define RAMSTART (0x100)
|
||||
#define NRWWSTART (0x0000)
|
||||
#elif defined(__AVR_ATmega1280__)
|
||||
#define RAMSTART (0x200)
|
||||
#define NRWWSTART (0xE000)
|
||||
#elif defined(__AVR_ATmega8__) || defined(__AVR_ATmega88__)
|
||||
#define RAMSTART (0x100)
|
||||
#define NRWWSTART (0x1800)
|
||||
#endif
|
||||
|
||||
/* C zero initialises all global variables. However, that requires */
|
||||
/* These definitions are NOT zero initialised, but that doesn't matter */
|
||||
/* This allows us to drop the zero init code, saving us memory */
|
||||
#define buff ((uint8_t*)(RAMSTART))
|
||||
#ifdef VIRTUAL_BOOT_PARTITION
|
||||
#define rstVect (*(uint16_t*)(RAMSTART+SPM_PAGESIZE*2+4))
|
||||
#define wdtVect (*(uint16_t*)(RAMSTART+SPM_PAGESIZE*2+6))
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Handle devices with up to 4 uarts (eg m1280.) Rather inelegantly.
|
||||
* Note that mega8 still needs special handling, because ubrr is handled
|
||||
* differently.
|
||||
*/
|
||||
#if UART == 0
|
||||
# define UART_SRA UCSR0A
|
||||
# define UART_SRB UCSR0B
|
||||
# define UART_SRC UCSR0C
|
||||
# define UART_SRL UBRR0L
|
||||
# define UART_UDR UDR0
|
||||
#elif UART == 1
|
||||
# define UART_SRA UCSR1A
|
||||
# define UART_SRB UCSR1B
|
||||
# define UART_SRC UCSR1C
|
||||
# define UART_SRL UBRR1L
|
||||
# define UART_UDR UDR1
|
||||
#elif UART == 2
|
||||
# define UART_SRA UCSR2A
|
||||
# define UART_SRB UCSR2B
|
||||
# define UART_SRC UCSR2C
|
||||
# define UART_SRL UBRR2L
|
||||
# define UART_UDR UDR2
|
||||
#elif UART == 3
|
||||
# define UART_SRA UCSR3A
|
||||
# define UART_SRB UCSR3B
|
||||
# define UART_SRC UCSR3C
|
||||
# define UART_SRL UBRR3L
|
||||
# define UART_UDR UDR3
|
||||
#endif
|
||||
|
||||
|
||||
/* main program starts here */
|
||||
int main(void)
|
||||
{
|
||||
uint8_t ch;
|
||||
uint8_t byte ;
|
||||
|
||||
/*
|
||||
* Making these local and in registers prevents the need for initializing
|
||||
* them, and also saves space because code no longer stores to memory.
|
||||
* (initializing address keeps the compiler happy, but isn't really
|
||||
* necessary, and uses 4 bytes of flash.)
|
||||
*/
|
||||
register uint16_t address = 0;
|
||||
init() ;
|
||||
|
||||
// After the zero init loop, this is the first code to run.
|
||||
//
|
||||
// This code makes the following assumptions:
|
||||
// No interrupts will execute
|
||||
// SP points to RAMEND
|
||||
// r1 contains zero
|
||||
//
|
||||
// If not, uncomment the following instructions:
|
||||
// cli();
|
||||
asm volatile ("clr __zero_reg__");
|
||||
|
||||
ch = RST.STATUS ;
|
||||
RST.STATUS = 0xFF ; // Clear all flags
|
||||
|
||||
// Here, if power on, wait 0.1 secs, then check for
|
||||
// serial Rx signal low, if so, stay in bootloader
|
||||
// else go to application
|
||||
|
||||
if (ch & (RST_EXTRF_bm | RST_PORF_bm ) )
|
||||
{
|
||||
TCC1.CCA = 25000 ;
|
||||
TCC1.INTFLAGS = TC1_CCAIF_bm ;
|
||||
|
||||
while(!(TCC1.INTFLAGS & TC1_CCAIF_bm))
|
||||
;
|
||||
TCC1.CTRLA = 0 ; // Stop timer
|
||||
|
||||
uint8_t x ;
|
||||
x = PORTD.IN & 0x04 ;
|
||||
if ( x != 0 )
|
||||
{
|
||||
appStart() ; // Power on, go to app if loaded
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//#ifndef SOFT_UART
|
||||
// UART_SRA = _BV(U2X0); //Double speed mode USART0
|
||||
// UART_SRB = _BV(RXEN0) | _BV(TXEN0);
|
||||
// UART_SRC = _BV(UCSZ00) | _BV(UCSZ01);
|
||||
//// UART_SRL = (uint8_t)( (F_CPU + BAUD_RATE * 4L) / (BAUD_RATE * 8L) - 1 );
|
||||
//// Baudrate of 57600
|
||||
//#if F_CPU == 12000000L
|
||||
// UART_SRL = 25 ;
|
||||
//#else
|
||||
//#if F_CPU == 16000000L
|
||||
// UART_SRL = 33 ;
|
||||
//#else
|
||||
//#ERROR Baud rate not available
|
||||
//#endif
|
||||
//#endif
|
||||
|
||||
//#endif
|
||||
|
||||
// Set up watchdog to trigger after 500ms
|
||||
|
||||
|
||||
// watchdogConfig(WATCHDOG_1S);
|
||||
|
||||
/* Set LED pin as output */
|
||||
#define LED_pin 1 //PD1
|
||||
#define LED_port PORTD
|
||||
LED_port.DIRSET = _BV(LED_pin) ;
|
||||
|
||||
//#ifdef SOFT_UART
|
||||
// /* Set TX pin as output */
|
||||
// UART_DDR |= _BV(UART_TX_BIT);
|
||||
//#endif
|
||||
|
||||
//#if LED_START_FLASHES > 0
|
||||
// /* Flash onboard LED to signal entering of bootloader */
|
||||
// flash_led(LED_START_FLASHES * 2);
|
||||
//#endif
|
||||
|
||||
/* Forever loop */
|
||||
for (;;)
|
||||
{
|
||||
/* get character from UART */
|
||||
ch = getch();
|
||||
|
||||
if(ch == STK_GET_PARAMETER)
|
||||
{
|
||||
byte = getch();
|
||||
verifySpace();
|
||||
if ( byte == 0x82)
|
||||
{
|
||||
/*
|
||||
* Send optiboot version as "minor SW version"
|
||||
*/
|
||||
putch(OPTIBOOT_MINVER);
|
||||
}
|
||||
else if ( byte == 0x81)
|
||||
{
|
||||
putch(OPTIBOOT_MAJVER);
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* GET PARAMETER returns a generic 0x03 reply for
|
||||
* other parameters - enough to keep Avrdude happy
|
||||
*/
|
||||
putch(0x03);
|
||||
}
|
||||
}
|
||||
else if(ch == STK_SET_DEVICE) {
|
||||
// SET DEVICE is ignored
|
||||
getNch(20);
|
||||
}
|
||||
else if(ch == STK_SET_DEVICE_EXT)
|
||||
{
|
||||
// SET DEVICE EXT is ignored
|
||||
getNch(5);
|
||||
}
|
||||
else if(ch == STK_LOAD_ADDRESS)
|
||||
{
|
||||
// LOAD ADDRESS
|
||||
uint16_t newAddress;
|
||||
newAddress = getch() ;
|
||||
newAddress = (newAddress & 0xff) | (getch() << 8);
|
||||
#ifdef RAMPZ
|
||||
// Transfer top bit to RAMPZ
|
||||
RAMPZ = (newAddress & 0x8000) ? 1 : 0;
|
||||
#endif
|
||||
// newAddress += newAddress; // Convert from word address to byte address
|
||||
address = newAddress;
|
||||
verifySpace();
|
||||
}
|
||||
else if(ch == STK_UNIVERSAL)
|
||||
{
|
||||
// UNIVERSAL command is ignored
|
||||
getNch(4);
|
||||
putch(0x00);
|
||||
}
|
||||
/* Write memory, length is big endian and is in bytes */
|
||||
else if(ch == STK_PROG_PAGE)
|
||||
{
|
||||
// PROGRAM PAGE - we support flash programming only, not EEPROM
|
||||
uint8_t *bufPtr;
|
||||
uint16_t addrPtr;
|
||||
register uint8_t length;
|
||||
|
||||
getch(); /* getlen() */
|
||||
length = getch();
|
||||
getch();
|
||||
|
||||
// If we are in RWW section, immediately start page erase
|
||||
// if (address < NRWWSTART) __boot_page_erase_short((uint16_t)(void*)address);
|
||||
__boot_page_erase_short((uint16_t)(void*)address);
|
||||
|
||||
// While that is going on, read in page contents
|
||||
bufPtr = buff;
|
||||
do *bufPtr++ = getch();
|
||||
while (--length);
|
||||
|
||||
// If we are in NRWW section, page erase has to be delayed until now.
|
||||
// Todo: Take RAMPZ into account
|
||||
//#ifdef MULTI_CALLED
|
||||
// if (address < 0x7E00)
|
||||
//#endif
|
||||
// {
|
||||
// if (address >= NRWWSTART) __boot_page_erase_short((uint16_t)(void*)address);
|
||||
// }
|
||||
// Read command terminator, start reply
|
||||
verifySpace();
|
||||
|
||||
// If only a partial page is to be programmed, the erase might not be complete.
|
||||
// So check that here
|
||||
#ifdef MULTI_CALLED
|
||||
if (address < 0x8000)
|
||||
#endif
|
||||
{
|
||||
boot_spm_busy_wait();
|
||||
|
||||
#ifdef VIRTUAL_BOOT_PARTITION
|
||||
if ((uint16_t)(void*)address == 0) {
|
||||
// This is the reset vector page. We need to live-patch the code so the
|
||||
// bootloader runs.
|
||||
//
|
||||
// Move RESET vector to WDT vector
|
||||
uint16_t vect = buff[0] | (buff[1]<<8);
|
||||
rstVect = vect;
|
||||
wdtVect = buff[8] | (buff[9]<<8);
|
||||
vect -= 4; // Instruction is a relative jump (rjmp), so recalculate.
|
||||
buff[8] = vect & 0xff;
|
||||
buff[9] = vect >> 8;
|
||||
|
||||
// Add jump to bootloader at RESET vector
|
||||
buff[0] = 0x7f;
|
||||
buff[1] = 0xce; // rjmp 0x1d00 instruction
|
||||
}
|
||||
#endif
|
||||
|
||||
// Copy buffer into programming buffer
|
||||
bufPtr = buff;
|
||||
addrPtr = (uint16_t)(void*)address;
|
||||
ch = SPM_PAGESIZE / 2;
|
||||
__boot_erase_flash_buffer((uint16_t)(void*)addrPtr ) ;
|
||||
do {
|
||||
uint16_t a;
|
||||
// a = *bufPtr++;
|
||||
// a |= (*bufPtr++) << 8;
|
||||
|
||||
a = *((uint16_t *)bufPtr) ;
|
||||
bufPtr += 2 ;
|
||||
|
||||
__boot_page_fill_short((uint16_t)(void*)addrPtr,a);
|
||||
addrPtr += 2;
|
||||
} while (--ch);
|
||||
|
||||
// Write from programming buffer
|
||||
__boot_page_write_short((uint16_t)(void*)address);
|
||||
boot_spm_busy_wait();
|
||||
|
||||
#if defined(RWWSRE)
|
||||
// Reenable read access to flash
|
||||
boot_rww_enable();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
/* Read memory block mode, length is big endian. */
|
||||
else if(ch == STK_READ_PAGE)
|
||||
{
|
||||
register uint8_t length;
|
||||
// READ PAGE - we only read flash
|
||||
getch(); /* getlen() */
|
||||
length = getch();
|
||||
getch();
|
||||
|
||||
verifySpace();
|
||||
//#ifdef VIRTUAL_BOOT_PARTITION
|
||||
// do {
|
||||
// // Undo vector patch in bottom page so verify passes
|
||||
// if (address == 0) ch=rstVect & 0xff;
|
||||
// else if (address == 1) ch=rstVect >> 8;
|
||||
// else if (address == 8) ch=wdtVect & 0xff;
|
||||
// else if (address == 9) ch=wdtVect >> 8;
|
||||
// else ch = pgm_read_byte_near(address);
|
||||
// address++;
|
||||
// putch(ch);
|
||||
// } while (--length);
|
||||
//#else
|
||||
//#ifdef RAMPZ
|
||||
//// Since RAMPZ should already be set, we need to use EPLM directly.
|
||||
//// do putch(pgm_read_byte_near(address++));
|
||||
//// while (--length);
|
||||
// do {
|
||||
// uint8_t result;
|
||||
// __asm__ ("elpm %0,Z\n":"=r"(result):"z"(address));
|
||||
// putch(result);
|
||||
// address++;
|
||||
// }
|
||||
// while (--length);
|
||||
//#else
|
||||
do putch(pgm_read_byte_near(address++));
|
||||
while (--length);
|
||||
//#endif
|
||||
//#endif
|
||||
}
|
||||
|
||||
/* Get device signature bytes */
|
||||
else if(ch == STK_READ_SIGN)
|
||||
{
|
||||
// READ SIGN - return what Avrdude wants to hear
|
||||
verifySpace();
|
||||
putch(SIGNATURE_0);
|
||||
putch(SIGNATURE_1);
|
||||
putch(SIGNATURE_2);
|
||||
}
|
||||
else if (ch == STK_LEAVE_PROGMODE) { /* 'Q' */
|
||||
// Adaboot no-wait mod
|
||||
|
||||
// watchdogConfig(WATCHDOG_16MS);
|
||||
|
||||
verifySpace();
|
||||
#ifdef MULTI_CALLED
|
||||
putch(STK_OK);
|
||||
while(!(USARTC0.STATUS & USART_TXCIF_bm))
|
||||
;
|
||||
appStart() ;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
// This covers the response to commands like STK_ENTER_PROGMODE
|
||||
verifySpace();
|
||||
}
|
||||
putch(STK_OK);
|
||||
}
|
||||
}
|
||||
|
||||
void putch(char ch)
|
||||
{
|
||||
//#ifndef SOFT_UART
|
||||
while(!(USARTC0.STATUS & USART_DREIF_bm))
|
||||
;
|
||||
USARTC0.DATA = ch ;
|
||||
//#else
|
||||
// __asm__ __volatile__ (
|
||||
// " com %[ch]\n" // ones complement, carry set
|
||||
// " sec\n"
|
||||
// "1: brcc 2f\n"
|
||||
// " cbi %[uartPort],%[uartBit]\n"
|
||||
// " rjmp 3f\n"
|
||||
// "2: sbi %[uartPort],%[uartBit]\n"
|
||||
// " nop\n"
|
||||
// "3: rcall uartDelay\n"
|
||||
// " rcall uartDelay\n"
|
||||
// " lsr %[ch]\n"
|
||||
// " dec %[bitcnt]\n"
|
||||
// " brne 1b\n"
|
||||
// :
|
||||
// :
|
||||
// [bitcnt] "d" (10),
|
||||
// [ch] "r" (ch),
|
||||
// [uartPort] "I" (_SFR_IO_ADDR(UART_PORT)),
|
||||
// [uartBit] "I" (UART_TX_BIT)
|
||||
// :
|
||||
// "r25"
|
||||
// );
|
||||
//#endif
|
||||
}
|
||||
|
||||
uint8_t getch(void)
|
||||
{
|
||||
uint8_t ch;
|
||||
|
||||
//#ifdef LED_DATA_FLASH
|
||||
//#ifdef __AVR_ATmega8__
|
||||
// LED_PORT ^= _BV(LED);
|
||||
//#else
|
||||
// LED_PIN |= _BV(LED);
|
||||
//#endif
|
||||
//#endif
|
||||
|
||||
//#ifdef SOFT_UART
|
||||
// __asm__ __volatile__ (
|
||||
// "1: sbic %[uartPin],%[uartBit]\n" // Wait for start edge
|
||||
// " rjmp 1b\n"
|
||||
// " rcall uartDelay\n" // Get to middle of start bit
|
||||
// "2: rcall uartDelay\n" // Wait 1 bit period
|
||||
// " rcall uartDelay\n" // Wait 1 bit period
|
||||
// " clc\n"
|
||||
// " sbic %[uartPin],%[uartBit]\n"
|
||||
// " sec\n"
|
||||
// " dec %[bitCnt]\n"
|
||||
// " breq 3f\n"
|
||||
// " ror %[ch]\n"
|
||||
// " rjmp 2b\n"
|
||||
// "3:\n"
|
||||
// :
|
||||
// [ch] "=r" (ch)
|
||||
// :
|
||||
// [bitCnt] "d" (9),
|
||||
// [uartPin] "I" (_SFR_IO_ADDR(UART_PIN)),
|
||||
// [uartBit] "I" (UART_RX_BIT)
|
||||
// :
|
||||
// "r25"
|
||||
//);
|
||||
//#else
|
||||
while(!(USARTC0.STATUS & USART_RXCIF_bm))
|
||||
|
||||
// watchdogReset()
|
||||
|
||||
;
|
||||
// if (!(UART_SRA & _BV(FE0))) {
|
||||
/*
|
||||
* A Framing Error indicates (probably) that something is talking
|
||||
* to us at the wrong bit rate. Assume that this is because it
|
||||
* expects to be talking to the application, and DON'T reset the
|
||||
* watchdog. This should cause the bootloader to abort and run
|
||||
* the application "soon", if it keeps happening. (Note that we
|
||||
* don't care that an invalid char is returned...)
|
||||
*/
|
||||
// watchdogReset();
|
||||
// }
|
||||
|
||||
ch = USARTC0.DATA ;
|
||||
//#endif
|
||||
|
||||
//#ifdef LED_DATA_FLASH
|
||||
//#ifdef __AVR_ATmega8__
|
||||
// LED_PORT ^= _BV(LED);
|
||||
//#else
|
||||
// LED_PIN |= _BV(LED);
|
||||
//#endif
|
||||
//#endif
|
||||
|
||||
return ch;
|
||||
}
|
||||
|
||||
#ifdef SOFT_UART
|
||||
// AVR305 equation: #define UART_B_VALUE (((F_CPU/BAUD_RATE)-23)/6)
|
||||
// Adding 3 to numerator simulates nearest rounding for more accurate baud rates
|
||||
#define UART_B_VALUE (((F_CPU/BAUD_RATE)-20)/6)
|
||||
#if UART_B_VALUE > 255
|
||||
#error Baud rate too slow for soft UART
|
||||
#endif
|
||||
|
||||
void uartDelay() {
|
||||
__asm__ __volatile__ (
|
||||
"ldi r25,%[count]\n"
|
||||
"1:dec r25\n"
|
||||
"brne 1b\n"
|
||||
"ret\n"
|
||||
::[count] "M" (UART_B_VALUE)
|
||||
);
|
||||
}
|
||||
#endif
|
||||
|
||||
void getNch(uint8_t count) {
|
||||
do getch(); while (--count);
|
||||
verifySpace();
|
||||
}
|
||||
|
||||
void verifySpace()
|
||||
{
|
||||
if ( getch() != CRC_EOP) {
|
||||
|
||||
putch(STK_NOSYNC);
|
||||
// watchdogConfig(WATCHDOG_16MS); // shorten WD timeout
|
||||
//
|
||||
// while (1) // and busy-loop so that WD causes
|
||||
// ; // a reset and app start.
|
||||
}
|
||||
putch(STK_INSYNC);
|
||||
}
|
||||
|
||||
#if LED_START_FLASHES > 0
|
||||
void flash_led(uint8_t count) {
|
||||
do {
|
||||
TCNT1 = -(F_CPU/(1024*16));
|
||||
TIFR1 = _BV(TOV1);
|
||||
while(!(TIFR1 & _BV(TOV1)));
|
||||
//#ifdef __AVR_ATmega8__
|
||||
LED_PORT ^= _BV(LED);
|
||||
//#else
|
||||
// LED_PIN |= _BV(LED);
|
||||
//#endif
|
||||
watchdogReset();
|
||||
} while (--count);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Watchdog functions. These are only safe with interrupts turned off.
|
||||
void watchdogReset() {
|
||||
__asm__ __volatile__ (
|
||||
"wdr\n"
|
||||
);
|
||||
}
|
||||
|
||||
//void watchdogConfig(uint8_t x) {
|
||||
// WDTCSR = _BV(WDCE) | _BV(WDE);
|
||||
// WDTCSR = x;
|
||||
//}
|
||||
|
||||
void init()
|
||||
{
|
||||
// Enable external oscillator (16MHz)
|
||||
OSC.XOSCCTRL = OSC_FRQRANGE_12TO16_gc | OSC_XOSCSEL_XTAL_256CLK_gc ;
|
||||
OSC.CTRL |= OSC_XOSCEN_bm ;
|
||||
while( ( OSC.STATUS & OSC_XOSCRDY_bm ) == 0 )
|
||||
/* wait */ ;
|
||||
// Enable PLL (*2 = 32MHz)
|
||||
OSC.PLLCTRL = OSC_PLLSRC_XOSC_gc | 2 ;
|
||||
OSC.CTRL |= OSC_PLLEN_bm ;
|
||||
while( ( OSC.STATUS & OSC_PLLRDY_bm ) == 0 )
|
||||
/* wait */ ;
|
||||
// Switch to PLL clock
|
||||
CPU_CCP = 0xD8 ;
|
||||
CLK.CTRL = CLK_SCLKSEL_RC2M_gc ;
|
||||
CPU_CCP = 0xD8 ;
|
||||
CLK.CTRL = CLK_SCLKSEL_PLL_gc ;
|
||||
|
||||
PMIC.CTRL = 7 ; // Enable all interrupt levels
|
||||
|
||||
|
||||
// Timer1 config
|
||||
// TCC1 16-bit timer, clocked at 0.5uS
|
||||
EVSYS.CH3MUX = 0x80 + 0x07 ; // Prescaler of 128
|
||||
TCC1.CTRLB = 0; TCC1.CTRLC = 0; TCC1.CTRLD = 0; TCC1.CTRLE = 0;
|
||||
TCC1.INTCTRLA = 0 ;
|
||||
TCC1.INTCTRLB = 0 ;
|
||||
TCC1.PER = 0xFFFF ;
|
||||
TCC1.CNT = 0 ;
|
||||
TCC1.CTRLA = 0x0B ; // Event3 (prescale of 16)
|
||||
|
||||
PORTD.OUTSET = 0x04 ;
|
||||
PORTD.DIRCLR = 0x04 ;
|
||||
PORTD.PIN2CTRL = 0x18 ; // Pullup
|
||||
|
||||
PORTC.OUTSET = 0x08 ;
|
||||
PORTC.DIRSET = 0x08 ;
|
||||
|
||||
USARTC0.BAUDCTRLA = 34 ; // 57600
|
||||
USARTC0.BAUDCTRLB = 0 ;
|
||||
|
||||
USARTC0.CTRLB = 0x18 ; // Enable Tx and Rx
|
||||
USARTC0.CTRLA = (USARTC0.CTRLA & 0xCF) ;
|
||||
USARTC0.CTRLC = 0x03 ; // 8 bit, no parity, 1 stop
|
||||
USARTC0.DATA ;
|
||||
}
|
||||
|
||||
void boot_spm_busy_wait()
|
||||
{
|
||||
while(NVM.STATUS & NVM_NVMBUSY_bm)
|
||||
;
|
||||
}
|
||||
|
||||
#define A_NVM_CMD 0x1CA
|
||||
|
||||
void __boot_page_erase_short( uint16_t address )
|
||||
{
|
||||
asm( "push r24" ) ;
|
||||
asm( "push r25" ) ;
|
||||
NVM.CMD = NVM_CMD_ERASE_APP_PAGE_gc ;
|
||||
asm( "pop r31" ) ;
|
||||
asm( "pop r30" ) ;
|
||||
CCP = CCP_SPM_gc ;
|
||||
asm( "spm" ) ;
|
||||
}
|
||||
|
||||
void __boot_erase_flash_buffer( uint16_t address )
|
||||
{
|
||||
asm( "movw r30,r24" ) ;
|
||||
asm( "ldi r24,0x26" ) ;
|
||||
asm("sts 0x1CA,r24");
|
||||
CCP = CCP_IOREG_gc ;
|
||||
asm( "ldi r24,1" ) ;
|
||||
asm("sts 0x1CB,r24");
|
||||
}
|
||||
|
||||
void __boot_page_fill_short( uint16_t address, uint16_t data)
|
||||
{
|
||||
asm( "push r0" ) ;
|
||||
asm( "push r1" ) ;
|
||||
asm( "movw r30,r24" ) ;
|
||||
asm( "mov r0,r22" ) ;
|
||||
asm( "mov r1,r23" ) ;
|
||||
asm( "ldi r24,0x23" ) ;
|
||||
asm("sts 0x1CA,r24");
|
||||
CCP = CCP_SPM_gc ;
|
||||
asm( "spm" ) ;
|
||||
asm( "pop r1" ) ;
|
||||
asm( "pop r0" ) ;
|
||||
}
|
||||
|
||||
void __boot_page_write_short( uint16_t address)
|
||||
{
|
||||
asm( "movw r30,r24" ) ;
|
||||
asm( "ldi r24,0x2E" ) ;
|
||||
asm("sts 0x1CA,r24");
|
||||
CCP = CCP_SPM_gc ;
|
||||
asm( "spm" ) ;
|
||||
}
|
||||
|
||||
void appStart()
|
||||
{
|
||||
// watchdogConfig(WATCHDOG_OFF);
|
||||
// __asm__ __volatile__ (
|
||||
//#ifdef VIRTUAL_BOOT_PARTITION
|
||||
// // Jump to WDT vector
|
||||
// "ldi r30,4\n"
|
||||
// "clr r31\n"
|
||||
//#else
|
||||
// // Jump to RST vector
|
||||
// "clr r30\n"
|
||||
// "clr r31\n"
|
||||
//#endif
|
||||
// "ijmp\n"
|
||||
// );
|
||||
|
||||
register void (*p)() ;
|
||||
p = 0 ;
|
||||
|
||||
if ( pgm_read_byte( (uint16_t)p ) != 0xFF )
|
||||
{
|
||||
(*p)() ;
|
||||
}
|
||||
}
|
||||
|
@ -1,80 +0,0 @@
|
||||
#if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328__) || defined(__AVR_ATmega88) || defined(__AVR_ATmega8__) || defined(__AVR_ATmega88__)
|
||||
/* Onboard LED is connected to pin PB5 in Arduino NG, Diecimila, and Duemilanove */
|
||||
#define LED_DDR DDRB
|
||||
#define LED_PORT PORTB
|
||||
#define LED_PIN PINB
|
||||
#define LED PINB5
|
||||
|
||||
/* Ports for soft UART */
|
||||
#ifdef SOFT_UART
|
||||
#define UART_PORT PORTD
|
||||
#define UART_PIN PIND
|
||||
#define UART_DDR DDRD
|
||||
#define UART_TX_BIT 1
|
||||
#define UART_RX_BIT 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(__AVR_ATmega8__)
|
||||
//Name conversion R.Wiersma
|
||||
#define UCSR0A UCSRA
|
||||
#define UDR0 UDR
|
||||
#define UDRE0 UDRE
|
||||
#define RXC0 RXC
|
||||
#define FE0 FE
|
||||
#define TIFR1 TIFR
|
||||
#define WDTCSR WDTCR
|
||||
#endif
|
||||
|
||||
/* Luminet support */
|
||||
#if defined(__AVR_ATtiny84__)
|
||||
/* Red LED is connected to pin PA4 */
|
||||
#define LED_DDR DDRA
|
||||
#define LED_PORT PORTA
|
||||
#define LED_PIN PINA
|
||||
#define LED PINA4
|
||||
/* Ports for soft UART - left port only for now. TX/RX on PA2/PA3 */
|
||||
#ifdef SOFT_UART
|
||||
#define UART_PORT PORTA
|
||||
#define UART_PIN PINA
|
||||
#define UART_DDR DDRA
|
||||
#define UART_TX_BIT 2
|
||||
#define UART_RX_BIT 3
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Sanguino support */
|
||||
#if defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__)
|
||||
/* Onboard LED is connected to pin PB0 on Sanguino */
|
||||
#define LED_DDR DDRB
|
||||
#define LED_PORT PORTB
|
||||
#define LED_PIN PINB
|
||||
#define LED PINB0
|
||||
|
||||
/* Ports for soft UART */
|
||||
#ifdef SOFT_UART
|
||||
#define UART_PORT PORTD
|
||||
#define UART_PIN PIND
|
||||
#define UART_DDR DDRD
|
||||
#define UART_TX_BIT 1
|
||||
#define UART_RX_BIT 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Mega support */
|
||||
#if defined(__AVR_ATmega1280__)
|
||||
/* Onboard LED is connected to pin PB7 on Arduino Mega */
|
||||
#define LED_DDR DDRB
|
||||
#define LED_PORT PORTB
|
||||
#define LED_PIN PINB
|
||||
#define LED PINB7
|
||||
|
||||
/* Ports for soft UART */
|
||||
#ifdef SOFT_UART
|
||||
#define UART_PORT PORTE
|
||||
#define UART_PIN PINE
|
||||
#define UART_DDR DDRE
|
||||
#define UART_TX_BIT 1
|
||||
#define UART_RX_BIT 0
|
||||
#endif
|
||||
#endif
|
@ -1,39 +0,0 @@
|
||||
/* STK500 constants list, from AVRDUDE */
|
||||
#define STK_OK 0x10
|
||||
#define STK_FAILED 0x11 // Not used
|
||||
#define STK_UNKNOWN 0x12 // Not used
|
||||
#define STK_NODEVICE 0x13 // Not used
|
||||
#define STK_INSYNC 0x14 // ' '
|
||||
#define STK_NOSYNC 0x15 // Not used
|
||||
#define ADC_CHANNEL_ERROR 0x16 // Not used
|
||||
#define ADC_MEASURE_OK 0x17 // Not used
|
||||
#define PWM_CHANNEL_ERROR 0x18 // Not used
|
||||
#define PWM_ADJUST_OK 0x19 // Not used
|
||||
#define CRC_EOP 0x20 // 'SPACE'
|
||||
#define STK_GET_SYNC 0x30 // '0'
|
||||
#define STK_GET_SIGN_ON 0x31 // '1'
|
||||
#define STK_SET_PARAMETER 0x40 // '@'
|
||||
#define STK_GET_PARAMETER 0x41 // 'A'
|
||||
#define STK_SET_DEVICE 0x42 // 'B'
|
||||
#define STK_SET_DEVICE_EXT 0x45 // 'E'
|
||||
#define STK_ENTER_PROGMODE 0x50 // 'P'
|
||||
#define STK_LEAVE_PROGMODE 0x51 // 'Q'
|
||||
#define STK_CHIP_ERASE 0x52 // 'R'
|
||||
#define STK_CHECK_AUTOINC 0x53 // 'S'
|
||||
#define STK_LOAD_ADDRESS 0x55 // 'U'
|
||||
#define STK_UNIVERSAL 0x56 // 'V'
|
||||
#define STK_PROG_FLASH 0x60 // '`'
|
||||
#define STK_PROG_DATA 0x61 // 'a'
|
||||
#define STK_PROG_FUSE 0x62 // 'b'
|
||||
#define STK_PROG_LOCK 0x63 // 'c'
|
||||
#define STK_PROG_PAGE 0x64 // 'd'
|
||||
#define STK_PROG_FUSE_EXT 0x65 // 'e'
|
||||
#define STK_READ_FLASH 0x70 // 'p'
|
||||
#define STK_READ_DATA 0x71 // 'q'
|
||||
#define STK_READ_FUSE 0x72 // 'r'
|
||||
#define STK_READ_LOCK 0x73 // 's'
|
||||
#define STK_READ_PAGE 0x74 // 't'
|
||||
#define STK_READ_SIGN 0x75 // 'u'
|
||||
#define STK_READ_OSCCAL 0x76 // 'v'
|
||||
#define STK_READ_FUSE_EXT 0x77 // 'w'
|
||||
#define STK_READ_OSCCAL_EXT 0x78 // 'x'
|
@ -1,2 +0,0 @@
|
||||
## Page Moved
|
||||
Moved to [/docs/Arduino_IDE_Boards.md](/docs/Arduino_IDE_Boards.md).
|
@ -1 +0,0 @@
|
||||
[Source for the StmMultiBooloader](https://github.com/MikeBland/StmMultiBoot)
|
@ -1,2 +0,0 @@
|
||||
[Source for the StmMultiUSB=STM32duino-bootloader](https://github.com/rogerclarkmelbourne/STM32duino-bootloader)
|
||||
If you want the latest version, you should look for the file generic_boot20_pa1.bin.
|
@ -1,657 +0,0 @@
|
||||
{
|
||||
"packages": [{
|
||||
"name": "multi4in1",
|
||||
"maintainer": "Pascal Langer",
|
||||
"websiteURL": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module",
|
||||
"email": "pascal_langer@yahoo.fr",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"platforms": [
|
||||
{
|
||||
"name": "Multi 4-in-1 AVR Boards",
|
||||
"architecture": "avr",
|
||||
"version": "1.0.2",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_avr_board_v1.0.2.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_avr_board_v1.0.2.tar.gz",
|
||||
"checksum": "SHA-256:b7e2fda37186bf696b7a769b12317737d513181096b33d9ad321ec2fd47f3f80",
|
||||
"size": "164467",
|
||||
"boards": [
|
||||
{"name": "Multi 4-in-1 (Atmega328p, 3.3V, 16MHz)"},
|
||||
{"name": "Multi 4-in-1 (OrangeRX)"}
|
||||
],
|
||||
"toolsDependencies": []
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 AVR Boards",
|
||||
"architecture": "avr",
|
||||
"version": "1.0.3",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_avr_board_v1.0.3.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_avr_board_v1.0.3.tar.gz",
|
||||
"checksum": "SHA-256:7d4561eebe0d7f6422f06d5719a417e15fcc0aa9cdbfc1c48a57066ce768e33c",
|
||||
"size": "164483",
|
||||
"boards": [
|
||||
{"name": "Multi 4-in-1 (Atmega328p, 3.3V, 16MHz)"},
|
||||
{"name": "Multi 4-in-1 (OrangeRX)"}
|
||||
],
|
||||
"toolsDependencies": []
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 AVR Boards",
|
||||
"architecture": "avr",
|
||||
"version": "1.0.4",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_avr_board_v1.0.4.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_avr_board_v1.0.4.tar.gz",
|
||||
"checksum": "SHA-256:6c51a4eb09bcd074cc651dab3f2356ea3afd358f6330aba0d8bdfaa75f718dbb",
|
||||
"size": "167975",
|
||||
"boards": [
|
||||
{"name": "Multi 4-in-1 (Atmega328p, 3.3V, 16MHz)"},
|
||||
{"name": "Multi 4-in-1 (OrangeRX)"}
|
||||
],
|
||||
"toolsDependencies": []
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 AVR Boards",
|
||||
"architecture": "avr",
|
||||
"version": "1.0.5",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_avr_board_v1.0.5.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_avr_board_v1.0.5.tar.gz",
|
||||
"checksum": "SHA-256:0a4754d47cdbb49ca194b15835686331530ed9d36c0db093a29ae5f865e75421",
|
||||
"size": "169830",
|
||||
"boards": [
|
||||
{"name": "Multi 4-in-1 (Atmega328p, 3.3V, 16MHz)"},
|
||||
{"name": "Multi 4-in-1 (OrangeRX)"}
|
||||
],
|
||||
"toolsDependencies": []
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 AVR Boards",
|
||||
"architecture": "avr",
|
||||
"version": "1.0.6",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_avr_board_v1.0.6.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_avr_board_v1.0.6.tar.gz",
|
||||
"checksum": "SHA-256:4f4cf8820e30bf6c88f280514c67ee67b9dc6649f439597cfb8d0be3a5b13bf5",
|
||||
"size": "169819",
|
||||
"boards": [
|
||||
{"name": "Multi 4-in-1 (Atmega328p, 3.3V, 16MHz)"},
|
||||
{"name": "Multi 4-in-1 (OrangeRX)"}
|
||||
],
|
||||
"toolsDependencies": []
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 AVR Boards",
|
||||
"architecture": "avr",
|
||||
"version": "1.0.7",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_avr_board_v1.0.7.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_avr_board_v1.0.7.tar.gz",
|
||||
"checksum": "SHA-256:453c9999e433ed1bdda2ba2b12cb7cbba7b547591db969dc6b7efb941b61cf76",
|
||||
"size": "169825",
|
||||
"boards": [
|
||||
{"name": "Multi 4-in-1 (Atmega328p, 3.3V, 16MHz)"},
|
||||
{"name": "Multi 4-in-1 (OrangeRX)"}
|
||||
],
|
||||
"toolsDependencies": []
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 AVR Boards",
|
||||
"architecture": "avr",
|
||||
"version": "1.0.8",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_avr_board_v1.0.8.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_avr_board_v1.0.8.tar.gz",
|
||||
"checksum": "SHA-256:8e58b8733220d56155e10bf5bec0bfe6bf96f8460b3fd49a4b45c7f9fad776cb",
|
||||
"size": "293388",
|
||||
"boards": [
|
||||
{"name": "Multi 4-in-1 (Atmega328p, 3.3V, 16MHz)"},
|
||||
{"name": "Multi 4-in-1 (OrangeRX)"}
|
||||
],
|
||||
"toolsDependencies": []
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 AVR Boards",
|
||||
"architecture": "avr",
|
||||
"version": "1.0.9",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_avr_board_v1.0.9.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_avr_board_v1.0.9.tar.gz",
|
||||
"checksum": "SHA-256:269c4ddcb8018be2b31f5c9e9f0814d120af492e894b8d5098a814486d56faa5",
|
||||
"size": "318437",
|
||||
"boards": [
|
||||
{"name": "Multi 4-in-1 (Atmega328p, 3.3V, 16MHz)"},
|
||||
{"name": "Multi 4-in-1 (OrangeRX)"}
|
||||
],
|
||||
"toolsDependencies": []
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 AVR Boards",
|
||||
"architecture": "avr",
|
||||
"version": "1.1.0",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_avr_board_v1.1.0.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_avr_board_v1.1.0.tar.gz",
|
||||
"checksum": "SHA-256:7bacf2db754ceb890a203de5ce89d97aa787a9e6462debeb44cf04830859687a",
|
||||
"size": "326431",
|
||||
"boards": [
|
||||
{"name": "Multi 4-in-1 (Atmega328p, 3.3V, 16MHz)"},
|
||||
{"name": "Multi 4-in-1 (OrangeRX)"}
|
||||
],
|
||||
"toolsDependencies": []
|
||||
},
|
||||
{
|
||||
"name": "MULTI-Module AVR Boards",
|
||||
"architecture": "avr",
|
||||
"version": "1.1.1",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_avr_board_v1.1.1.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_avr_board_v1.1.1.tar.gz",
|
||||
"checksum": "SHA-256:02158258b4dbaca61bedbb6933336200d13b02ad0db981e2dda253682c482e99",
|
||||
"size": "324512",
|
||||
"boards": [
|
||||
{"name": "Multi 4-in-1 (Atmega328p, 3.3V, 16MHz)"},
|
||||
{"name": "Multi 4-in-1 (OrangeRX)"}
|
||||
],
|
||||
"toolsDependencies": []
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 STM32 Board",
|
||||
"architecture": "STM32F1",
|
||||
"version": "1.0.1",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_stm32_board_v1.0.1.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_stm32_board_v1.0.1.tar.gz",
|
||||
"checksum": "SHA-256:b522b5d3474308768c197a6897cad037fb54d6fac26c75678415a0908793bae3",
|
||||
"size": "10332875",
|
||||
"boards": [{
|
||||
"name": "Multi 4-in-1 (STM32F103C)"
|
||||
}],
|
||||
"toolsDependencies": [{
|
||||
"packager": "arduino",
|
||||
"name": "arm-none-eabi-gcc",
|
||||
"version": "4.8.3-2014q1"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 STM32 Board",
|
||||
"architecture": "STM32F1",
|
||||
"version": "1.0.2",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_stm32_board_v1.0.2.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_stm32_board_v1.0.2.tar.gz",
|
||||
"checksum": "SHA-256:26d21dbd2fe80680ac523b8bca24b3ecf2c2016bac626826d20b651e11278287",
|
||||
"size": "10318646",
|
||||
"boards": [{
|
||||
"name": "Multi 4-in-1 (STM32F103C)"
|
||||
}],
|
||||
"toolsDependencies": [{
|
||||
"packager": "arduino",
|
||||
"name": "arm-none-eabi-gcc",
|
||||
"version": "4.8.3-2014q1"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 STM32 Board",
|
||||
"architecture": "STM32F1",
|
||||
"version": "1.0.3",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_stm32_board_v1.0.3.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_stm32_board_v1.0.3.tar.gz",
|
||||
"checksum": "SHA-256:e48f1f30948b3f7be83e8b1fe2bb5c6b41be7c4d5da02503a0b4827c60926541",
|
||||
"size": "10309833",
|
||||
"boards": [{
|
||||
"name": "Multi 4-in-1 (STM32F103C)"
|
||||
}],
|
||||
"toolsDependencies": [{
|
||||
"packager": "arduino",
|
||||
"name": "arm-none-eabi-gcc",
|
||||
"version": "4.8.3-2014q1"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 STM32 Board",
|
||||
"architecture": "STM32F1",
|
||||
"version": "1.0.4",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_stm32_board_v1.0.4.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_stm32_board_v1.0.4.tar.gz",
|
||||
"checksum": "SHA-256:388a4dbcd567f9d41b82955e12e8a640d9696217081c0ee6ab8c58a25aedf70f",
|
||||
"size": "10307581",
|
||||
"boards": [{
|
||||
"name": "Multi 4-in-1 (STM32F103C)"
|
||||
}],
|
||||
"toolsDependencies": [{
|
||||
"packager": "arduino",
|
||||
"name": "arm-none-eabi-gcc",
|
||||
"version": "4.8.3-2014q1"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 STM32 Board",
|
||||
"architecture": "STM32F1",
|
||||
"version": "1.0.5",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_stm32_board_v1.0.5.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_stm32_board_v1.0.5.tar.gz",
|
||||
"checksum": "SHA-256:46d3b4e62fc46e6b8ca4f429974ffd2ee8cde9e29a6e0cda58f85044991a9c2b",
|
||||
"size": "10313436",
|
||||
"boards": [{
|
||||
"name": "Multi 4-in-1 (STM32F103C)"
|
||||
}],
|
||||
"toolsDependencies": [{
|
||||
"packager": "arduino",
|
||||
"name": "arm-none-eabi-gcc",
|
||||
"version": "4.8.3-2014q1"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 STM32 Board",
|
||||
"architecture": "STM32F1",
|
||||
"version": "1.0.6",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_stm32_board_v1.0.6.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_stm32_board_v1.0.6.tar.gz",
|
||||
"checksum": "SHA-256:ad7a330326069a5ffb2908495b288933f68517b1247cc6636b160eb483a58284",
|
||||
"size": "10319669",
|
||||
"boards": [{
|
||||
"name": "Multi 4-in-1 (STM32F103C)"
|
||||
}],
|
||||
"toolsDependencies": [{
|
||||
"packager": "arduino",
|
||||
"name": "arm-none-eabi-gcc",
|
||||
"version": "4.8.3-2014q1"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 STM32 Board",
|
||||
"architecture": "STM32F1",
|
||||
"version": "1.0.7",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_stm32_board_v1.0.7.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_stm32_board_v1.0.7.tar.gz",
|
||||
"checksum": "SHA-256:f73fded48beaee55e646a3cf36d24beeedc336873c7824683a4912f2aee9e350",
|
||||
"size": "10322111",
|
||||
"boards": [{
|
||||
"name": "Multi 4-in-1 (STM32F103C)"
|
||||
}],
|
||||
"toolsDependencies": [{
|
||||
"packager": "arduino",
|
||||
"name": "arm-none-eabi-gcc",
|
||||
"version": "4.8.3-2014q1"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 STM32 Board",
|
||||
"architecture": "STM32F1",
|
||||
"version": "1.0.8",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_stm32_board_v1.0.8.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_stm32_board_v1.0.8.tar.gz",
|
||||
"checksum": "SHA-256:f8100272ec615074cf7962c2c8331014ebda78f3e4c17172b88b6dd3d83c4331",
|
||||
"size": "10319134",
|
||||
"boards": [{
|
||||
"name": "Multi 4-in-1 (STM32F103C)"
|
||||
}],
|
||||
"toolsDependencies": [{
|
||||
"packager": "arduino",
|
||||
"name": "arm-none-eabi-gcc",
|
||||
"version": "4.8.3-2014q1"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 STM32 Board",
|
||||
"architecture": "STM32F1",
|
||||
"version": "1.0.9",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_stm32_board_v1.0.9.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_stm32_board_v1.0.9.tar.gz",
|
||||
"checksum": "SHA-256:c3621d1cf6580ca5c943a67dc14dc15a60e2797a4b985548abe1919486bf4a8b",
|
||||
"size": "10324251",
|
||||
"boards": [{
|
||||
"name": "Multi 4-in-1 (STM32F103C)"
|
||||
}],
|
||||
"toolsDependencies": [{
|
||||
"packager": "arduino",
|
||||
"name": "arm-none-eabi-gcc",
|
||||
"version": "4.8.3-2014q1"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 STM32 Board",
|
||||
"architecture": "STM32F1",
|
||||
"version": "1.1.0",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_stm32_board_v1.1.0.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_stm32_board_v1.1.0.tar.gz",
|
||||
"checksum": "SHA-256:919ece2021757686e6892679956dcb8a01c9308a152167d61d9204656b4ed7ee",
|
||||
"size": "10333612",
|
||||
"boards": [{
|
||||
"name": "Multi 4-in-1 (STM32F103C)"
|
||||
}],
|
||||
"toolsDependencies": [{
|
||||
"packager": "arduino",
|
||||
"name": "arm-none-eabi-gcc",
|
||||
"version": "4.8.3-2014q1"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 STM32 Board",
|
||||
"architecture": "STM32F1",
|
||||
"version": "1.1.1",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_stm32_board_v1.1.1.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_stm32_board_v1.1.1.tar.gz",
|
||||
"checksum": "SHA-256:549dbfa0f48f3e519a9efa96d03e8933cc72989c618826b2b570980d9c382979",
|
||||
"size": "10331547",
|
||||
"boards": [{
|
||||
"name": "Multi 4-in-1 (STM32F103C)"
|
||||
}],
|
||||
"toolsDependencies": [{
|
||||
"packager": "arduino",
|
||||
"name": "arm-none-eabi-gcc",
|
||||
"version": "4.8.3-2014q1"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 STM32 Board",
|
||||
"architecture": "STM32F1",
|
||||
"version": "1.1.2",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_stm32_board_v1.1.2.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_stm32_board_v1.1.2.tar.gz",
|
||||
"checksum": "SHA-256:debfdc14df3023045a2297bc99daf7104be75f21572fc5a4f57192ffae4028f0",
|
||||
"size": "10322776",
|
||||
"boards": [{
|
||||
"name": "Multi 4-in-1 (STM32F103C)"
|
||||
}],
|
||||
"toolsDependencies": [{
|
||||
"packager": "arduino",
|
||||
"name": "arm-none-eabi-gcc",
|
||||
"version": "4.8.3-2014q1"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 STM32 Board",
|
||||
"architecture": "STM32F1",
|
||||
"version": "1.1.3",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_stm32_board_v1.1.3.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_stm32_board_v1.1.3.tar.gz",
|
||||
"checksum": "SHA-256:6b9dceb033ccc31f37cebc4f025ddb862cd24a733e7c356ca2fa5719d595af89",
|
||||
"size": "10322145",
|
||||
"boards": [{
|
||||
"name": "Multi 4-in-1 (STM32F103C)"
|
||||
}],
|
||||
"toolsDependencies": [{
|
||||
"packager": "arduino",
|
||||
"name": "arm-none-eabi-gcc",
|
||||
"version": "4.8.3-2014q1"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 STM32 Board",
|
||||
"architecture": "STM32F1",
|
||||
"version": "1.1.4",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_stm32_board_v1.1.4.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_stm32_board_v1.1.4.tar.gz",
|
||||
"checksum": "SHA-256:16a83a3b4409cb55aead6593396979483996080634d214ae07c8a956db2480fb",
|
||||
"size": "10322152",
|
||||
"boards": [{
|
||||
"name": "Multi 4-in-1 (STM32F103C)"
|
||||
}],
|
||||
"toolsDependencies": [{
|
||||
"packager": "arduino",
|
||||
"name": "arm-none-eabi-gcc",
|
||||
"version": "4.8.3-2014q1"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 STM32 Board",
|
||||
"architecture": "STM32F1",
|
||||
"version": "1.1.5",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_stm32_board_v1.1.5.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_stm32_board_v1.1.5.tar.gz",
|
||||
"checksum": "SHA-256:2d45c95f59b4fb9fc7f7bf8caca2dd8c13b4258141c20db6169e0c7faf72e5e4",
|
||||
"size": "7930904",
|
||||
"boards": [{
|
||||
"name": "Multi 4-in-1 (STM32F103C)"
|
||||
}],
|
||||
"toolsDependencies": [{
|
||||
"packager": "arduino",
|
||||
"name": "arm-none-eabi-gcc",
|
||||
"version": "4.8.3-2014q1"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 STM32 Board",
|
||||
"architecture": "STM32F1",
|
||||
"version": "1.1.6",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_stm32_board_v1.1.6.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_stm32_board_v1.1.6.tar.gz",
|
||||
"checksum": "SHA-256:d2d1ef721bbcdc3c680c6f98b4b8ab394478ac0f82d67af2f6c389a4a30789f4",
|
||||
"size": "7962942",
|
||||
"boards": [{
|
||||
"name": "Multi 4-in-1 (STM32F103C)"
|
||||
}],
|
||||
"toolsDependencies": [{
|
||||
"packager": "arduino",
|
||||
"name": "arm-none-eabi-gcc",
|
||||
"version": "4.8.3-2014q1"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 STM32 Board",
|
||||
"architecture": "STM32F1",
|
||||
"version": "1.1.7",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_stm32_board_v1.1.7.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_stm32_board_v1.1.7.tar.gz",
|
||||
"checksum": "SHA-256:37cccde7eafad3d0587d28d13d5f8b2b3244bf7c83e6819b6cb08f4f468815e2",
|
||||
"size": "7966348",
|
||||
"boards": [{
|
||||
"name": "Multi 4-in-1 (STM32F103C)"
|
||||
}],
|
||||
"toolsDependencies": [{
|
||||
"packager": "arduino",
|
||||
"name": "arm-none-eabi-gcc",
|
||||
"version": "4.8.3-2014q1"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"name": "Multi X-in-1 STM32 Boards",
|
||||
"architecture": "STM32F1",
|
||||
"version": "1.1.8",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_stm32_board_v1.1.8.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_stm32_board_v1.1.8.tar.gz",
|
||||
"checksum": "SHA-256:e9ed8055ebf72abf37e60e1b8d1c6ee5472132ea7c0a3c4a63fbb8442613e4c2",
|
||||
"size": "7481800",
|
||||
"boards": [
|
||||
{"name": "Multi 4-in-1 (STM32F103C)"},
|
||||
{"name": "Multi 5-in-1 (Jumper T18 Internal)"}
|
||||
],
|
||||
"toolsDependencies": [{
|
||||
"packager": "arduino",
|
||||
"name": "arm-none-eabi-gcc",
|
||||
"version": "4.8.3-2014q1"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"name": "Multi X-in-1 STM32 Boards",
|
||||
"architecture": "STM32F1",
|
||||
"version": "1.2.0",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_stm32_board_v1.2.0.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_stm32_board_v1.2.0.tar.gz",
|
||||
"checksum": "SHA-256:754f08ca2a553701cc9112b645c079b6041107f1bf863648305e560c136a6ac5",
|
||||
"size": "7496214",
|
||||
"boards": [
|
||||
{"name": "Multi 4-in-1 (STM32F103C)"},
|
||||
{"name": "Multi 5-in-1 (Jumper T18 Internal)"}
|
||||
],
|
||||
"toolsDependencies": [{
|
||||
"packager": "arduino",
|
||||
"name": "arm-none-eabi-gcc",
|
||||
"version": "4.8.3-2014q1"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"name": "Multi X-in-1 STM32 Boards",
|
||||
"architecture": "STM32F1",
|
||||
"version": "1.2.1",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_stm32_board_v1.2.1.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_stm32_board_v1.2.1.tar.gz",
|
||||
"checksum": "SHA-256:c66d34afadc5b21e9e28c4d477fa03a6d55db0b74b59ff2dcb07b4d6ef06da1a",
|
||||
"size": "7496448",
|
||||
"boards": [
|
||||
{"name": "Multi 4-in-1 (STM32F103C)"},
|
||||
{"name": "Multi 5-in-1 (Jumper T18 Internal)"}
|
||||
],
|
||||
"toolsDependencies": [{
|
||||
"packager": "arduino",
|
||||
"name": "arm-none-eabi-gcc",
|
||||
"version": "4.8.3-2014q1"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"name": "MULTI-Module STM32 Boards",
|
||||
"architecture": "STM32F1",
|
||||
"version": "1.2.2",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_stm32_board_v1.2.2.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_stm32_board_v1.2.2.tar.gz",
|
||||
"checksum": "SHA-256:0fe4a8899438bbc31dc37714acca13968e43d75a47e59143343d83b634d2e47d",
|
||||
"size": "7485662",
|
||||
"boards": [
|
||||
{"name": "Multi X-in-1 STM32F103CB (128KB)"},
|
||||
{"name": "Multi X-in-1 STM32F103C8 (64KB)"},
|
||||
{"name": "Multi 5-in-1 (Jumper T18 Internal)"}
|
||||
],
|
||||
"toolsDependencies": [{
|
||||
"packager": "arduino",
|
||||
"name": "arm-none-eabi-gcc",
|
||||
"version": "4.8.3-2014q1"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 OrangeRX Board - DEPRECATED, USE MULTI 4-IN-1 AVR BOARDS PACKAGE INSTEAD",
|
||||
"architecture": "orangerx",
|
||||
"version": "1.0.1",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_orangerx_board_v1.0.1.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_orangerx_board_v1.0.1.tar.gz",
|
||||
"checksum": "SHA-256:7287ce61028b754bb8ff947317dd15773fc7eeecd752826c707fa356b9b36dc6",
|
||||
"size": "161615",
|
||||
"boards": [{
|
||||
"name": "Multi 4-in-1 (OrangeRX)"
|
||||
}],
|
||||
"toolsDependencies": []
|
||||
}
|
||||
],
|
||||
"tools": []
|
||||
}]
|
||||
}
|
@ -1,790 +0,0 @@
|
||||
local toolName = "TNS|DSM Forward Prog v0.56 (Color) |TNE"
|
||||
local VERSION = "v0.56"
|
||||
|
||||
---- #########################################################################
|
||||
---- # #
|
||||
---- # Copyright (C) OpenTX #
|
||||
-----# #
|
||||
---- # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html #
|
||||
---- # #
|
||||
---- # This program is free software; you can redistribute it and/or modify #
|
||||
---- # it under the terms of the GNU General Public License version 2 as #
|
||||
---- # published by the Free Software Foundation. #
|
||||
---- # #
|
||||
---- # This program is distributed in the hope that it will be useful #
|
||||
---- # but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
---- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
---- # GNU General Public License for more details. #
|
||||
---- # #
|
||||
---- #########################################################################
|
||||
------------------------------------------------------------------------------
|
||||
-- This script library is a rewrite of the original DSM forward programming Lua
|
||||
-- Script. The goal is to make it easier to understand, mantain, and to
|
||||
-- separate the GUI from the DSM Forward programming engine/logic
|
||||
-- in this way, GUIs can evolve independent. OpenTX Gui, EdgeTx GUI, Small Radios, etc.
|
||||
|
||||
-- Code is based on the code/work by: Pascal Langer (Author of the Multi-Module)
|
||||
-- Rewrite/Enhancements By: Francisco Arzu
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
local SIMULATION_ON = true -- false: dont show simulation menu, TRUE: show simulation menu
|
||||
local DEBUG_ON = 1 -- 0=NO DEBUG, 1=HIGH LEVEL 2=LOW LEVEL (Debug logged into the /LOGS/dsm.log)
|
||||
local USE_SPECKTRUM_COLORS = true -- true: Use spectrum colors, false: use theme colors (default on OpenTX)
|
||||
local DSMLIB_PATH = "/SCRIPTS/TOOLS/DSMLIB/"
|
||||
local IMAGE_PATH = DSMLIB_PATH .. "img/"
|
||||
|
||||
local Log = assert(loadScript(DSMLIB_PATH.."DsmLogLib.lua"), "Not-Found: DSMLIB/DsmLogLib.lua")()
|
||||
local menuLib = assert(loadScript(DSMLIB_PATH.."DsmMenuLib.lua"), "Not-Found: DSMLIB/DsmMenuLib.lua")(Log, DEBUG_ON)
|
||||
local modelLib = assert(loadScript(DSMLIB_PATH.."DsmModelLib.lua"), "Not-Found: DSMLIB/DsmModelLib.lua")(Log, DEBUG_ON)
|
||||
local menuProcessor = assert(loadScript(DSMLIB_PATH.."DsmMainMenuLib.lua"), "Not-Found: DSMLIB/DsmMainMenuLib.lua")(Log, menuLib, modelLib, DEBUG_ON, SIMULATION_ON)
|
||||
|
||||
local PHASE = menuLib.PHASE
|
||||
local LINE_TYPE = menuLib.LINE_TYPE
|
||||
local DISP_ATTR = menuLib.DISP_ATTR
|
||||
local DSM_Context = menuLib.DSM_Context
|
||||
|
||||
|
||||
local lastRefresh=0 -- Last time the screen was refreshed
|
||||
local REFRESH_GUI_MS = 300/10 -- 300ms.. Screen Refresh Rate.. to not waste CPU time (in 10ms units to be compatible with getTime())
|
||||
local originalValue = nil
|
||||
|
||||
local touchButtonArea = {}
|
||||
local EDIT_BUTTON = { DEFAULT=1001, DEC_10=1002, DEC_1=1003, INC_1=1004, INC_10=5, OK=1006, ESC=1007 }
|
||||
|
||||
local IS_EDGETX = false -- DEFAULT until Init changed it
|
||||
|
||||
local LCD_Y_MENU_TITLE = 20
|
||||
local LCD_W_MENU_TITLE = LCD_W-100
|
||||
|
||||
local LCD_X_LINE_MENU = 30
|
||||
local LCD_W_LINE_MENU = 350
|
||||
|
||||
local LCD_X_LINE_TITLE = 30
|
||||
local LCD_X_LINE_VALUE = 230
|
||||
local LCD_X_LINE_DEBUG = 390
|
||||
|
||||
|
||||
local LCD_Y_LINE_START = LCD_Y_MENU_TITLE + 30
|
||||
local LCD_Y_LINE_HEIGHT = 27
|
||||
|
||||
local LCD_Y_LOWER_BUTTONS = LCD_Y_LINE_START + 3 + (7 * LCD_Y_LINE_HEIGHT)
|
||||
|
||||
-- TOOL BG COLOR
|
||||
local LCD_TOOL_BGCOLOR = TEXT_BGCOLOR
|
||||
-- TOOL HEADER
|
||||
local LCD_TOOL_HDR_COLOR = MENU_TITLE_COLOR
|
||||
local LCD_TOOL_HDR_BGCOLOR = TITLE_BGCOLOR
|
||||
-- MENU HEADER
|
||||
local LCD_MENU_COLOR = MENU_TITLE_COLOR
|
||||
local LCD_MENU_BGCOLOR = MENU_TITLE_BGCOLOR
|
||||
-- LINE SELECTED
|
||||
local LCD_SELECTED_COLOR = TEXT_INVERTED_COLOR
|
||||
local LCD_SELECTED_BGCOLOR = TEXT_INVERTED_BGCOLOR
|
||||
local LCD_EDIT_BGCOLOR = MENU_TITLE_BGCOLOR -- WARNING_COLOR
|
||||
-- NORMAL TEXT
|
||||
local LCD_NORMAL_COLOR = TEXT_COLOR
|
||||
local LCD_DISABLE_COLOR = TEXT_DISABLE_COLOR
|
||||
local LCD_DEBUG_COLOR = LINE_COLOR
|
||||
-- NORMAL BOX FRAME COLOR
|
||||
local LCD_BOX_COLOR = TEXT_DISABLE_COLOR
|
||||
|
||||
|
||||
local warningScreenON = true
|
||||
|
||||
|
||||
--------------------- lcd.sizeText replacement -------------------------------------------------
|
||||
-- EdgeTx dont have lcd.sizeText, so we do an equivalent one using the string length and 5px per character
|
||||
local function my_lcd_sizeText(s)
|
||||
if (s==nil) then return 20 end
|
||||
-- return: If IS_EDGETX then lcd.sizeText() else string.len()
|
||||
return (IS_EDGETX and lcd.sizeText(s)) or (string.len(s)*10)
|
||||
end
|
||||
|
||||
|
||||
local function GUI_SwitchToRX()
|
||||
-- Force to refresh DSM Info in MODEL (dsmLib pointing to the setup Script)
|
||||
-- local dsmChannelInfo, description = modelLib.CreateDSMPortChannelInfo()
|
||||
|
||||
menuProcessor.done()
|
||||
Log.LOG_close() -- Reset the log
|
||||
Log.LOG_open()
|
||||
|
||||
menuProcessor = nil
|
||||
collectgarbage("collect")
|
||||
|
||||
modelLib.ReadTxModelData()
|
||||
modelLib.ST_LoadFileData()
|
||||
modelLib.CreateDSMPortChannelInfo()
|
||||
|
||||
local dsmLib = assert(loadScript(DSMLIB_PATH.."DsmFwPrgLib.lua"),"Not-Found: DSMLIB/DsmFwPrgLib.lua")
|
||||
menuProcessor = dsmLib(Log, menuLib, modelLib, DEBUG_ON)
|
||||
|
||||
dsmLib = nil
|
||||
collectgarbage("collect")
|
||||
|
||||
menuProcessor.init(toolName) -- Initialize Library
|
||||
DSM_Context.Refresh_Display = true
|
||||
end
|
||||
|
||||
local function GUI_SwitchToSIM()
|
||||
menuProcessor.done()
|
||||
Log.LOG_close()
|
||||
|
||||
menuProcessor = nil
|
||||
collectgarbage("collect")
|
||||
|
||||
local simLib = assert(loadScript(DSMLIB_PATH.."DsmSimMenuLib.lua"), "Not-Found: DSMLIB/DsmSimMenuLib.lua")
|
||||
menuProcessor = simLib(Log, menuLib, modelLib, DEBUG_ON)
|
||||
|
||||
simLib = nil
|
||||
collectgarbage("collect")
|
||||
|
||||
menuProcessor.init(toolName) -- Initialize Library
|
||||
DSM_Context.Refresh_Display = true
|
||||
end
|
||||
|
||||
local function GUI_SwitchToSetupMenu()
|
||||
menuProcessor.done()
|
||||
|
||||
menuProcessor = nil
|
||||
collectgarbage("collect")
|
||||
|
||||
local setupLib = assert(loadScript(DSMLIB_PATH.."DsmSetupMenuLib.lua"), "Not-Found: DSMLIB/DsmSetupMenuLib.lua")
|
||||
menuProcessor = setupLib(Log, menuLib, modelLib, DEBUG_ON, SIMULATION_ON)
|
||||
|
||||
setupLib = nil
|
||||
collectgarbage("collect")
|
||||
|
||||
menuProcessor.init(toolName) -- Initialize Library
|
||||
DSM_Context.Refresh_Display = true
|
||||
end
|
||||
|
||||
local function GUI_SwitchToMainMenu()
|
||||
print("SWITCHING TO MAIN MENU")
|
||||
menuProcessor.done()
|
||||
|
||||
menuProcessor = nil
|
||||
collectgarbage("collect")
|
||||
|
||||
local mainMenuLib = assert(loadScript(DSMLIB_PATH.."DsmMainMenuLib.lua"), "Not-Found: DSMLIB/DsmMainMenuLib.lua")
|
||||
menuProcessor = mainMenuLib(Log, menuLib, modelLib, DEBUG_ON, SIMULATION_ON)
|
||||
|
||||
mainMenuLib = nil
|
||||
collectgarbage("collect")
|
||||
|
||||
menuProcessor.init(toolName) -- Initialize Library
|
||||
DSM_Context.Refresh_Display = true
|
||||
end
|
||||
|
||||
|
||||
--------------------- Toucch Button Helpers ------------------------------------------------------------
|
||||
local function GUI_addTouchButton(x,y,w,h,line)
|
||||
-- Add new button info to end of the array
|
||||
touchButtonArea[#touchButtonArea+1] = {x=x, y=y, w=w, h=h, line=line}
|
||||
end
|
||||
|
||||
local function GUI_getTouchButton(x,y)
|
||||
for i = 1, #touchButtonArea do
|
||||
local button = touchButtonArea[i]
|
||||
-- is the coordinate inside the button area??
|
||||
if (x >= button.x and x <= (button.x+button.w) and y >= button.y and (y <= button.y+button.h)) then
|
||||
return button.line
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
local function GUI_clearTouchButtons()
|
||||
touchButtonArea = {}
|
||||
end
|
||||
|
||||
---------- Return Color to display Menu Lines ----------------------------------------------------------------
|
||||
local function GUI_GetTextColor(lineNum)
|
||||
local ctx = DSM_Context
|
||||
local txtColor = LCD_NORMAL_COLOR
|
||||
-- Gray Out any other line except the one been edited
|
||||
if (ctx.isEditing() and ctx.EditLine~=lineNum) then txtColor=LCD_DISABLE_COLOR end
|
||||
return txtColor
|
||||
end
|
||||
|
||||
local function GUI_GetFrameColor(lineNum) -- Frame Color for Value/Menu Boxes
|
||||
local ctx = DSM_Context
|
||||
local txtColor = LCD_BOX_COLOR
|
||||
-- Gray Out any other line except the one been edited
|
||||
if (ctx.EditLine~=lineNum) then txtColor=LCD_DISABLE_COLOR end
|
||||
return txtColor
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------------------------------
|
||||
-- Display Text inside a Rectangle. Inv: true means solid rectangle, false=only perimeter
|
||||
local function GUI_Display_Boxed_Text(lineNum,x,y,w,h,text,inv, isNumber)
|
||||
local ctx = DSM_Context
|
||||
local txtColor = GUI_GetTextColor(lineNum)
|
||||
local frameColor = GUI_GetFrameColor(lineNum)
|
||||
-- If editing this lineNum, chose EDIT Color, else SELECTED Color
|
||||
local selectedBGColor = (ctx.EditLine==lineNum and LCD_EDIT_BGCOLOR) or LCD_SELECTED_BGCOLOR
|
||||
|
||||
if (inv) then
|
||||
txtColor = LCD_SELECTED_COLOR
|
||||
lcd.drawFilledRectangle(x-5, y-2, w, h, selectedBGColor)
|
||||
else
|
||||
lcd.drawRectangle(x-5, y-2, w, h, frameColor)
|
||||
end
|
||||
if (isNumber) then
|
||||
lcd.drawNumber(x+w-10 , y, text, txtColor + RIGHT)
|
||||
else
|
||||
lcd.drawText(x , y, text, txtColor)
|
||||
end
|
||||
end
|
||||
|
||||
------ Display Pre/Next/Back buttons
|
||||
local function GUI_Diplay_Button(x,y,w,h,text,selected)
|
||||
GUI_Display_Boxed_Text(-1,x,y,w,h,text,selected, false)
|
||||
end
|
||||
|
||||
------ Display MENU type of lines (Navigation, SubHeaders, and plain text comments)
|
||||
local function GUI_Display_Line_Menu(lineNum,line,selected)
|
||||
-- Menu Lines can be navidation to other Menus (if Selectable)
|
||||
-- Or SubHeaders or Messages
|
||||
|
||||
local txtColor = GUI_GetTextColor(lineNum)
|
||||
local y = LCD_Y_LINE_START+(LCD_Y_LINE_HEIGHT*lineNum)
|
||||
local x = LCD_X_LINE_MENU
|
||||
|
||||
if menuLib.isSelectableLine(line) then -- Draw Selectable Menus in Boxes
|
||||
GUI_Display_Boxed_Text(lineNum,x, y, LCD_W_LINE_MENU, LCD_Y_LINE_HEIGHT, line.Text,selected, false)
|
||||
GUI_addTouchButton(x, y, LCD_W_LINE_MENU, LCD_Y_LINE_HEIGHT,lineNum)
|
||||
else
|
||||
-- Non Selectable Menu Lines, plain text
|
||||
-- Can be use for sub headers or just regular text lines (like warnings)
|
||||
|
||||
local bold = (menuLib.isDisplayAttr(line.TextAttr,DISP_ATTR._BOLD) and BOLD) or 0
|
||||
|
||||
if menuLib.isDisplayAttr(line.TextAttr,DISP_ATTR._RIGHT) then -- Right Align???
|
||||
local tw = my_lcd_sizeText(line.Text)+4
|
||||
x = LCD_X_LINE_VALUE - tw -- Right
|
||||
elseif menuLib.isDisplayAttr(line.TextAttr,DISP_ATTR._CENTER) then -- Center??
|
||||
local tw = my_lcd_sizeText(line.Text)
|
||||
x = x + (LCD_X_LINE_VALUE - LCD_X_LINE_MENU)/2 - tw/2 -- Center - 1/2 Text
|
||||
end
|
||||
|
||||
lcd.drawText(x, y, line.Text, txtColor + bold)
|
||||
end
|
||||
end
|
||||
|
||||
------ Display NAME : VALUES type of lines
|
||||
local function GUI_Display_Line_Value(lineNum, line, value, selected, editing)
|
||||
-- This Displays Name and Value Pairs
|
||||
local txtColor = GUI_GetTextColor(lineNum)
|
||||
local bold = 0
|
||||
local y = LCD_Y_LINE_START+(LCD_Y_LINE_HEIGHT*lineNum)
|
||||
local x = LCD_X_LINE_TITLE
|
||||
|
||||
---------- NAME Part
|
||||
local header = line.Text
|
||||
-- ONLY do this for Flight Mode (Right Align or Centered)
|
||||
if (menuLib.isFlightModeLine(line)) then
|
||||
-- Display Header + Value together
|
||||
header = menuLib.GetFlightModeValue(line)
|
||||
|
||||
-- Bold Text???
|
||||
bold = (menuLib.isDisplayAttr(line.TextAttr,DISP_ATTR._BOLD) and BOLD) or 0
|
||||
|
||||
if menuLib.isDisplayAttr(line.TextAttr,DISP_ATTR._RIGHT) then -- Right Align
|
||||
local tw = my_lcd_sizeText(header)+4
|
||||
x = LCD_X_LINE_VALUE - tw -- Right
|
||||
elseif menuLib.isDisplayAttr(line.TextAttr,DISP_ATTR._CENTER) then -- Centered
|
||||
local tw = my_lcd_sizeText(header)
|
||||
x = x + (LCD_X_LINE_VALUE - LCD_X_LINE_TITLE)/2 - tw/2 -- Center - 1/2 Text
|
||||
end
|
||||
else
|
||||
-- No Flight Mode, no effects here
|
||||
header = header .. ":"
|
||||
end
|
||||
|
||||
lcd.drawText(x, y, header, txtColor + bold) -- display Line Header
|
||||
|
||||
|
||||
--------- VALUE PART, Skip for Flight Mode since already show the value
|
||||
if (value==nil) then return end
|
||||
|
||||
if not menuLib.isFlightModeLine(line) then
|
||||
if menuLib.isSelectableLine(line) then
|
||||
--if (editing) then -- Any Special color/effect when editing??
|
||||
-- value = "["..value .. "]"
|
||||
--end
|
||||
-- Can select/edit value, Box it
|
||||
local tw = math.max(my_lcd_sizeText(value)+10,45) -- Width of the Text in the lcd
|
||||
GUI_Display_Boxed_Text(lineNum,LCD_X_LINE_VALUE,y,tw,LCD_Y_LINE_HEIGHT,value,selected, not menuLib.isListLine(line))
|
||||
GUI_addTouchButton(LCD_X_LINE_VALUE,y,tw,LCD_Y_LINE_HEIGHT,lineNum)
|
||||
|
||||
lcd.drawText(LCD_X_LINE_VALUE+tw+5, y, (line.Format or ""), txtColor + bold)
|
||||
else -- Not Editable, Plain Text
|
||||
lcd.drawText(LCD_X_LINE_VALUE, y, value, txtColor)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
local function GUI_Display_Menu(menu)
|
||||
local ctx = DSM_Context
|
||||
local w= LCD_W_MENU_TITLE
|
||||
|
||||
-- Center Header
|
||||
local tw = my_lcd_sizeText(menu.Text)
|
||||
local x = w/2 - tw/2 -- Center of Screen - Center of Text
|
||||
|
||||
lcd.drawFilledRectangle(0, LCD_Y_MENU_TITLE-2, w, LCD_Y_LINE_HEIGHT-2, LCD_MENU_BGCOLOR)
|
||||
lcd.drawText(x,LCD_Y_MENU_TITLE,menu.Text, LCD_MENU_COLOR + BOLD)
|
||||
|
||||
-- Back Button
|
||||
if menu.BackId ~= 0 then
|
||||
GUI_Diplay_Button(437-5,LCD_Y_MENU_TITLE+3,47,LCD_Y_LINE_HEIGHT,"Back",ctx.SelLine == menuLib.BACK_BUTTON)
|
||||
GUI_addTouchButton(437-5,LCD_Y_MENU_TITLE+3,47,LCD_Y_LINE_HEIGHT,menuLib.BACK_BUTTON)
|
||||
end
|
||||
-- Next Button
|
||||
if menu.NextId ~= 0 then
|
||||
GUI_Diplay_Button(437-5,LCD_Y_LOWER_BUTTONS,47,LCD_Y_LINE_HEIGHT,"Next",ctx.SelLine == menuLib.NEXT_BUTTON)
|
||||
GUI_addTouchButton(437-5,LCD_Y_LOWER_BUTTONS,47,LCD_Y_LINE_HEIGHT,menuLib.NEXT_BUTTON)
|
||||
end
|
||||
-- Prev Button
|
||||
if menu.PrevId ~= 0 then
|
||||
GUI_Diplay_Button(10,LCD_Y_LOWER_BUTTONS,47,LCD_Y_LINE_HEIGHT,"Prev",ctx.SelLine == menuLib.PREV_BUTTON)
|
||||
GUI_addTouchButton(10,LCD_Y_LOWER_BUTTONS,47,LCD_Y_LINE_HEIGHT,menuLib.PREV_BUTTON)
|
||||
end
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
-- Display the EDIT mode buttons when editing a value
|
||||
|
||||
local function GUI_Display_Edit_Buttons(line)
|
||||
GUI_clearTouchButtons() -- Only this buttons can be touched
|
||||
local x = 15 -- Inittial X position
|
||||
local w = 55 -- Width of the buttons
|
||||
|
||||
local showPrev = line.Val > line.Min
|
||||
local showNext = line.Val < line.Max
|
||||
|
||||
GUI_Diplay_Button(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT,"ESC",true)
|
||||
GUI_addTouchButton(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT,EDIT_BUTTON.ESC)
|
||||
|
||||
x=x+w+10
|
||||
GUI_Diplay_Button(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT," Def",true)
|
||||
GUI_addTouchButton(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT,EDIT_BUTTON.DEFAULT)
|
||||
|
||||
x=x+w+10
|
||||
if (not menuLib.isListLine(line)) then
|
||||
GUI_Diplay_Button(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT," << ",showPrev)
|
||||
GUI_addTouchButton(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT,EDIT_BUTTON.DEC_10)
|
||||
end
|
||||
|
||||
x=x+w+10
|
||||
GUI_Diplay_Button(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT," <",showPrev)
|
||||
GUI_addTouchButton(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT,EDIT_BUTTON.DEC_1)
|
||||
|
||||
x=x+w+10
|
||||
GUI_Diplay_Button(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT," >",showNext)
|
||||
GUI_addTouchButton(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT,EDIT_BUTTON.INC_1)
|
||||
|
||||
x=x+w+10
|
||||
if (not menuLib.isListLine(line)) then
|
||||
GUI_Diplay_Button(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT," >>",showNext)
|
||||
GUI_addTouchButton(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT,EDIT_BUTTON.INC_10)
|
||||
end
|
||||
|
||||
x=x+w+10
|
||||
GUI_Diplay_Button(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT," OK",true)
|
||||
GUI_addTouchButton(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT,EDIT_BUTTON.OK)
|
||||
|
||||
end
|
||||
|
||||
local function GUI_ShowBitmap(x,y,imgData)
|
||||
-- imgData format "bitmap.png|alt message"
|
||||
local f = string.gmatch(imgData, '([^%|]+)') -- Iterator over values split by '|'
|
||||
local imgName, imgMsg = f(), f()
|
||||
|
||||
lcd.drawText(x, y, imgMsg or "") -- Alternate Image MSG
|
||||
|
||||
local imgPath = IMAGE_PATH .. (imgName or "")
|
||||
local bitmap = Bitmap.open(imgPath)
|
||||
if (bitmap~=nil) then
|
||||
lcd.drawBitmap(bitmap, x,y+20)
|
||||
end
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
local function GUI_Display()
|
||||
local ctx = DSM_Context
|
||||
lcd.clear(LCD_TOOL_BGCOLOR)
|
||||
GUI_clearTouchButtons()
|
||||
|
||||
if LCD_W ~= 480 then
|
||||
-- Different Resolution.. Maybe just adjusting some of the constants will work, adjust it in DSM_Init??
|
||||
-- LCD_X_LINE_TITLE, LCD_Y_LINE_START, etc
|
||||
lcd.drawText(LCD_X_LINE_TITLE,100,"Only supported in Color Radios of 480 resolution", BLINK)
|
||||
return
|
||||
end
|
||||
|
||||
local header = "DSM Forward Programming "..VERSION.." "
|
||||
if ctx.Phase ~= PHASE.RX_VERSION then
|
||||
header = header .. ctx.RX.Name.." v"..ctx.RX.Version
|
||||
end
|
||||
|
||||
--Draw title
|
||||
lcd.drawFilledRectangle(0, 0, LCD_W, 17, LCD_TOOL_HDR_BGCOLOR)
|
||||
lcd.drawText(5, 0, header, LCD_TOOL_HDR_COLOR + SMLSIZE)
|
||||
|
||||
-- Getting RX Version
|
||||
if ctx.Phase == PHASE.RX_VERSION then
|
||||
if (ctx.isReset) then
|
||||
lcd.drawText(LCD_X_LINE_TITLE,100, menuLib.Get_Text(0x301), BLINK) -- Resetting...
|
||||
else
|
||||
lcd.drawText(LCD_X_LINE_TITLE,100,menuLib.Get_Text(0x300), BLINK) -- Not valid RX
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
|
||||
local menu = ctx.Menu
|
||||
if menu.Text == nil then return end
|
||||
|
||||
----- Draw RX Menu ---------
|
||||
GUI_Display_Menu(menu)
|
||||
|
||||
-- Sending TX Information???
|
||||
if (ctx.Phase==PHASE.MENU_REQ_TX_INFO) then
|
||||
--lcd.drawFilledRectangle(x-5, y-2, w, h, selectedBGColor)
|
||||
--lcd.drawRectangle(x-5, y-2, w, h, frameColor)
|
||||
lcd.drawText(LCD_X_LINE_TITLE,100, "Sending CH"..(ctx.CurLine+1)) -- Channel Info
|
||||
return
|
||||
end
|
||||
|
||||
for i = 0, menuLib.MAX_MENU_LINES do
|
||||
local line = ctx.MenuLines[i]
|
||||
|
||||
if line ~= nil and line.Type ~= 0 then
|
||||
if line.Type == LINE_TYPE.MENU then
|
||||
GUI_Display_Line_Menu(i, line, i == ctx.SelLine)
|
||||
else
|
||||
local value = nil
|
||||
if line.Val ~= nil then
|
||||
value = line.Val
|
||||
if menuLib.isListLine(line) then -- for Lists of Strings, get the text
|
||||
value = menuLib.Get_List_Text(line.Val + line.TextStart) -- TextStart is the initial offset for text
|
||||
-- Complentary IMAGE for this value to Display??
|
||||
local offset = 0
|
||||
if (line.Type==LINE_TYPE.LIST_MENU_ORI) then offset = offset + 0x100 end --FH6250 hack
|
||||
|
||||
local imgData = menuLib.Get_List_Text_Img(line.Val + line.TextStart + offset)
|
||||
|
||||
if (imgData and i == ctx.SelLine) then -- Optional Image and Msg for selected value
|
||||
GUI_ShowBitmap(LCD_X_LINE_TITLE,LCD_Y_LINE_START, imgData)
|
||||
end
|
||||
end
|
||||
end -- if Line[i]~=nil
|
||||
GUI_Display_Line_Value(i, line, value, i == ctx.SelLine, i == ctx.EditLine)
|
||||
end
|
||||
end -- if ~MENU
|
||||
end -- for
|
||||
|
||||
if IS_EDGETX and ctx.isEditing() then
|
||||
-- Display Touch button for Editing values
|
||||
GUI_Display_Edit_Buttons(ctx.MenuLines[ctx.EditLine])
|
||||
end
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function GUI_RotEncVal(line, dir) -- return encoder speed to inc or dec values
|
||||
|
||||
if menuLib.isListLine(line) then return dir end
|
||||
|
||||
local inc = 0
|
||||
local Speed = getRotEncSpeed()
|
||||
|
||||
if Speed == ROTENC_MIDSPEED then inc = (5 * dir)
|
||||
elseif Speed == ROTENC_HIGHSPEED then inc = (15 * dir)
|
||||
else inc = dir end
|
||||
|
||||
return inc
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------------
|
||||
-- Translate Tap/Touch of EDIT buttons to equivalent Key events
|
||||
local function GUI_Translate_Edit_Buttons(button)
|
||||
local event = EVT_TOUCH_TAP
|
||||
local editInc = nil
|
||||
|
||||
if (button==EDIT_BUTTON.ESC) then -- ESC
|
||||
event = EVT_VIRTUAL_EXIT
|
||||
elseif (button==EDIT_BUTTON.DEFAULT) then -- Default
|
||||
event = EVT_VIRTUAL_ENTER_LONG
|
||||
elseif (button==EDIT_BUTTON.DEC_10) then -- -10
|
||||
event = EVT_VIRTUAL_PREV
|
||||
editInc = -10
|
||||
elseif (button==EDIT_BUTTON.DEC_1) then -- -1
|
||||
event = EVT_VIRTUAL_PREV
|
||||
editInc = -1
|
||||
elseif (button==EDIT_BUTTON.INC_1) then -- +1
|
||||
event = EVT_VIRTUAL_NEXT
|
||||
editInc = 1
|
||||
elseif (button==EDIT_BUTTON.INC_10) then -- + 10
|
||||
event = EVT_VIRTUAL_NEXT
|
||||
editInc = 10
|
||||
elseif (button==EDIT_BUTTON.OK) then -- OK
|
||||
event = EVT_VIRTUAL_ENTER
|
||||
else
|
||||
|
||||
end
|
||||
|
||||
return event, editInc
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
-- Handle Events comming from the GUI
|
||||
local function GUI_HandleEvent(event, touchState)
|
||||
local ctx = DSM_Context
|
||||
local menu = ctx.Menu
|
||||
local menuLines = ctx.MenuLines
|
||||
local editInc = nil
|
||||
|
||||
if (IS_EDGETX) then
|
||||
if (event == EVT_TOUCH_TAP and ctx.isEditing()) then -- Touch and Editing
|
||||
local button = GUI_getTouchButton(touchState.x, touchState.y)
|
||||
if (button) then
|
||||
event, editInc = GUI_Translate_Edit_Buttons(button)
|
||||
end
|
||||
end
|
||||
|
||||
if (event == EVT_TOUCH_TAP or event == EVT_TOUCH_FIRST) and not ctx.isEditing() then -- Touch and NOT editing
|
||||
if (DEBUG_ON) then Log.LOG_write("%s: EVT_TOUCH_TAP %d,%d\n",menuLib.phase2String(ctx.Phase),touchState.x, touchState.y) end
|
||||
local button = GUI_getTouchButton(touchState.x, touchState.y)
|
||||
if button then
|
||||
-- Found a valid line
|
||||
ctx.SelLine = button
|
||||
ctx.Refresh_Display=true
|
||||
if event == EVT_TOUCH_TAP then -- EVT_TOUCH_FIRST only move focus
|
||||
event = EVT_VIRTUAL_ENTER
|
||||
end
|
||||
end
|
||||
end
|
||||
end -- IS_EDGETX
|
||||
|
||||
if event == EVT_VIRTUAL_EXIT then
|
||||
ctx.Refresh_Display=true
|
||||
if (DEBUG_ON) then Log.LOG_write("%s: EVT_VIRTUAL_EXIT\n",menuLib.phase2String(ctx.Phase)) end
|
||||
if ctx.Phase == PHASE.RX_VERSION then
|
||||
menuLib.ChangePhase(PHASE.EXIT_DONE) -- Just Exit the Script
|
||||
else
|
||||
if ctx.isEditing() then -- Editing a Line, need to restore original value
|
||||
local line = ctx.MenuLines[ctx.EditLine]
|
||||
line.Val = originalValue
|
||||
menuLib.Value_Write_Validate(line)
|
||||
elseif (menu.BackId > 0 ) then -- Back??
|
||||
ctx.SelLine = menuLib.BACK_BUTTON
|
||||
event = EVT_VIRTUAL_ENTER
|
||||
else
|
||||
menuLib.ChangePhase(PHASE.EXIT)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if ctx.Phase == PHASE.RX_VERSION then return end
|
||||
|
||||
if event == EVT_VIRTUAL_NEXT then
|
||||
ctx.Refresh_Display=true
|
||||
if (DEBUG_ON) then Log.LOG_write("%s: EVT_VIRTUAL_NEXT\n",menuLib.phase2String(ctx.Phase)) end
|
||||
if ctx.isEditing() then -- Editing a Line, need to inc the value
|
||||
local line=ctx.MenuLines[ctx.EditLine]
|
||||
menuLib.Value_Add(line, editInc or GUI_RotEncVal(line, 1))
|
||||
else -- not editing, move selected line to NEXT
|
||||
menuLib.MoveSelectionLine(1)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
if event == EVT_VIRTUAL_PREV then
|
||||
ctx.Refresh_Display=true
|
||||
if (DEBUG_ON) then Log.LOG_write("%s: EVT_VIRTUAL_PREV\n",menuLib.phase2String(ctx.Phase)) end
|
||||
if ctx.isEditing() then -- Editiing a line, need to dec the value
|
||||
local line=ctx.MenuLines[ctx.EditLine]
|
||||
menuLib.Value_Add(line, editInc or GUI_RotEncVal(line, -1))
|
||||
else -- not editing, move selected line to PREV
|
||||
menuLib.MoveSelectionLine(-1)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
if event == EVT_VIRTUAL_ENTER_LONG then
|
||||
ctx.Refresh_Display=true
|
||||
if (DEBUG_ON) then Log.LOG_write("%s: EVT_VIRTUAL_ENTER_LONG\n",menuLib.phase2String(ctx.Phase)) end
|
||||
if ctx.isEditing() then
|
||||
-- reset the value to default
|
||||
menuLib.Value_Default(menuLines[ctx.EditLine]) -- Update value in RX if needed
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
if event == EVT_VIRTUAL_ENTER then
|
||||
ctx.Refresh_Display=true
|
||||
if (DEBUG_ON) then Log.LOG_write("%s: EVT_VIRTUAL_ENTER, SelLine=%d\n",menuLib.phase2String(ctx.Phase), ctx.SelLine) end
|
||||
if ctx.SelLine == menuLib.BACK_BUTTON then -- Back
|
||||
if (menu.BackId==0xFFF9) then
|
||||
-- SPECIAL Main Menu
|
||||
GUI_SwitchToMainMenu()
|
||||
else
|
||||
menuLib.GotoMenu(menu.BackId,0x80)
|
||||
end
|
||||
elseif ctx.SelLine == menuLib.NEXT_BUTTON then -- Next
|
||||
menuLib.GotoMenu(menu.NextId,0x82)
|
||||
elseif ctx.SelLine == menuLib.PREV_BUTTON then -- Prev
|
||||
menuLib.GotoMenu(menu.PrevId,0x81)
|
||||
elseif menuLines[ctx.SelLine].ValId ~= 0 then -- Menu or Value
|
||||
|
||||
if menuLines[ctx.SelLine].Type == LINE_TYPE.MENU then -- Navigate to Menu
|
||||
if (menuLines[ctx.SelLine].ValId==0xFFF1) then
|
||||
-- SPECIAL Simulation menu to Simulator
|
||||
GUI_SwitchToSIM()
|
||||
elseif (menuLines[ctx.SelLine].ValId==0xFFF2) then
|
||||
-- SPECIAL Simulation menu to go to RX
|
||||
GUI_SwitchToRX()
|
||||
elseif (menuLines[ctx.SelLine].ValId==0xFFF3) then
|
||||
-- SPECIAL Settup Menu
|
||||
GUI_SwitchToSetupMenu()
|
||||
elseif (menuLines[ctx.SelLine].ValId==0xFFF9) then
|
||||
-- SPECIAL Settup Menu
|
||||
GUI_SwitchToMainMenu()
|
||||
else
|
||||
menuLib.GotoMenu(menuLines[ctx.SelLine].ValId, ctx.SelLine) -- ValId is the MenuId to navigate to
|
||||
end
|
||||
else -- Enter on a Value
|
||||
if ctx.isEditing() then -- already editing a Line????
|
||||
menuLib.Value_Write_Validate(menuLines[ctx.SelLine])
|
||||
else -- Edit the current value
|
||||
ctx.EditLine = ctx.SelLine
|
||||
originalValue = menuLines[ctx.SelLine].Val
|
||||
menuLib.ChangePhase(PHASE.VALUE_CHANGING_WAIT)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function init_colors()
|
||||
-- osName in OpenTX is nil, otherwise is EDGETX
|
||||
local ver, radio, maj, minor, rev, osname = getVersion()
|
||||
if (osname==nil) then osname = "OpenTX" end -- OTX 2.3.14 and below returns nil
|
||||
|
||||
IS_EDGETX = string.sub(osname,1,1) == 'E'
|
||||
|
||||
if (IS_EDGETX and USE_SPECKTRUM_COLORS) then
|
||||
-- SPECKTRUM COLORS (only works on EDGETX)
|
||||
LCD_TOOL_BGCOLOR = LIGHTWHITE
|
||||
-- TOOL HEADER
|
||||
LCD_TOOL_HDR_COLOR = WHITE
|
||||
LCD_TOOL_HDR_BGCOLOR = DARKBLUE
|
||||
-- MENU HEADER
|
||||
LCD_MENU_COLOR = WHITE
|
||||
LCD_MENU_BGCOLOR = DARKGREY
|
||||
-- LINE SELECTED
|
||||
LCD_SELECTED_COLOR = WHITE
|
||||
LCD_SELECTED_BGCOLOR = ORANGE
|
||||
LCD_EDIT_BGCOLOR = RED
|
||||
-- NORMAL TEXT
|
||||
LCD_NORMAL_COLOR = BLACK
|
||||
LCD_DISABLE_COLOR = LIGHTGREY
|
||||
LCD_DEBUG_COLOR = BLUE
|
||||
-- NORMAL BOX FRAME COLOR
|
||||
LCD_BOX_COLOR = LIGHTGREY
|
||||
end
|
||||
end
|
||||
|
||||
local function GUI_Warning(event,touchState)
|
||||
lcd.clear(LCD_TOOL_BGCOLOR)
|
||||
local header = "DSM Forward Programming "..VERSION.." "
|
||||
--Draw title
|
||||
lcd.drawFilledRectangle(0, 0, LCD_W, 17, LCD_TOOL_HDR_BGCOLOR)
|
||||
lcd.drawText(5, 0, header, LCD_TOOL_HDR_COLOR + SMLSIZE)
|
||||
|
||||
lcd.drawText(100,20,"INFO", BOLD)
|
||||
lcd.drawText(5,40,"DSM Forward programing shares TX Servo/Output settings", 0)
|
||||
lcd.drawText(5,60,"with the RX. Make sure you setup your plane first in ", 0)
|
||||
lcd.drawText(5,80,"the TX before your start Fwrd programming your RX.", 0)
|
||||
lcd.drawText(5,100,"Wing & Tail type can be configured using this tool.", 0)
|
||||
|
||||
lcd.drawText(5,150,"TX Gyro Servo settings are sent to the RX during 'Initial Setup'", 0)
|
||||
lcd.drawText(5,170,"as well as when using RX 'Relearn Servo Settings'", 0)
|
||||
lcd.drawText(5,200,"ALWAYS TEST Gyro reactions after this conditions before flying.", BOLD)
|
||||
|
||||
lcd.drawText(100,250," OK ", INVERS + BOLD)
|
||||
|
||||
if event == EVT_VIRTUAL_EXIT or event == EVT_VIRTUAL_ENTER or event == EVT_TOUCH_TAP then
|
||||
warningScreenON = false
|
||||
end
|
||||
|
||||
return 0
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
-- Init
|
||||
local function DSM_Init()
|
||||
Log.LOG_open()
|
||||
|
||||
init_colors()
|
||||
modelLib.ReadTxModelData()
|
||||
modelLib.ST_LoadFileData()
|
||||
modelLib.CreateDSMPortChannelInfo()
|
||||
|
||||
menuLib.Init()
|
||||
menuProcessor.init()
|
||||
return 0
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
-- Main
|
||||
local function DSM_Run(event,touchState)
|
||||
local ctx = DSM_Context
|
||||
|
||||
if event == nil then
|
||||
error("Cannot be run as a model script!")
|
||||
Log.LOG_close()
|
||||
return 2
|
||||
end
|
||||
|
||||
if (warningScreenON) then
|
||||
return GUI_Warning(event,touchState)
|
||||
end
|
||||
|
||||
GUI_HandleEvent(event,touchState)
|
||||
|
||||
local ret = menuProcessor.run() -- Handle Send and Receive DSM Forward Programming Messages
|
||||
|
||||
if ctx.Phase == PHASE.INIT then return 0 end
|
||||
|
||||
|
||||
local refreshInterval = REFRESH_GUI_MS
|
||||
|
||||
-- When using LCD BLINK attribute, we need faster refresh for BLINK to SHOW on LCD
|
||||
if (ctx.Phase == PHASE.RX_VERSION or ctx.Phase==PHASE.MENU_REQ_TX_INFO) then -- Requesting RX Message Version usea BLINK?
|
||||
ctx.Refresh_Display=true
|
||||
refreshInterval = 20 -- 200ms
|
||||
end
|
||||
|
||||
if (not IS_EDGETX) then -- OPENTX NEEDS REFRESH ON EVERY CYCLE
|
||||
GUI_Display()
|
||||
-- Refresh display only if needed and no faster than 300ms, utilize more CPU to speedup DSM communications
|
||||
elseif (ctx.Refresh_Display and (getTime()-lastRefresh) > refreshInterval) then --300ms from last refresh
|
||||
GUI_Display()
|
||||
ctx.Refresh_Display=false
|
||||
lastRefresh=getTime()
|
||||
end
|
||||
|
||||
if ctx.Phase == PHASE.EXIT_DONE then
|
||||
Log.LOG_close()
|
||||
return 2
|
||||
else
|
||||
return 0
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
return { init=DSM_Init, run=DSM_Run }
|
@ -1,951 +0,0 @@
|
||||
local toolName = "TNS|DSM Frwd Prog v0.56a (MIN-SETUP)|TNE"
|
||||
|
||||
---- #########################################################################
|
||||
---- # #
|
||||
---- # Copyright (C) OpenTX #
|
||||
-----# #
|
||||
---- # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html #
|
||||
---- # #
|
||||
---- # This program is free software; you can redistribute it and/or modify #
|
||||
---- # it under the terms of the GNU General Public License version 2 as #
|
||||
---- # published by the Free Software Foundation. #
|
||||
---- # #
|
||||
---- # This program is distributed in the hope that it will be useful #
|
||||
---- # but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
---- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
---- # GNU General Public License for more details. #
|
||||
---- # #
|
||||
---- #########################################################################
|
||||
|
||||
|
||||
local VERSION = "v0.56"
|
||||
local DSMLIB_PATH = "/SCRIPTS/TOOLS/DSMLIB/"
|
||||
local DATA_PATH = "/MODELS/DSMDATA"
|
||||
|
||||
local LOG_FILE = "/LOGS/dsm_min_log.txt"
|
||||
|
||||
-- Phase
|
||||
local PH_INIT = 0
|
||||
local PH_RX_VER, PH_TITLE = 1, 2
|
||||
local PH_VAL_CHANGING, PH_VAL_EDITING, PH_VAL_EDIT_END = 6, 7, 8
|
||||
local PH_WAIT_CMD, PH_EXIT_REQ, PH_EXIT_DONE = 9, 10, 11
|
||||
|
||||
-- Line Types
|
||||
local LT_MENU, LT_LIST_NC = 0x1C, 0x6C
|
||||
|
||||
local Phase = PH_INIT
|
||||
|
||||
local Text = {}
|
||||
local List_Text = {}
|
||||
local List_Text_Img = {}
|
||||
|
||||
local originalValue = 0
|
||||
|
||||
local ctx_SelLine = 0 -- Current Selected Line
|
||||
local ctx_EditLine = nil -- Current Editing Line
|
||||
|
||||
local Menu = { MenuId = 0, Text = "", TextId = 0, PrevId = 0, NextId = 0, BackId = 0 }
|
||||
local MenuLines = {}
|
||||
|
||||
local logFile = nil
|
||||
|
||||
local LCD_W_BUTTONS = 19
|
||||
local LCD_H_BUTTONS = 10
|
||||
|
||||
local LCD_X_MAX = 128
|
||||
local LCD_X_RIGHT_BUTTONS = LCD_X_MAX - LCD_W_BUTTONS - 1
|
||||
|
||||
local LCD_Y_LINE_HEIGHT = 7
|
||||
local LCD_Y_LOWER_BUTTONS = (8 * LCD_Y_LINE_HEIGHT) + 2
|
||||
|
||||
local TEXT_ATTR = SMLSIZE
|
||||
|
||||
local TX_CHANNELS = 12
|
||||
|
||||
local AT_PLANE = 0
|
||||
|
||||
local aircraft_type_text = {[0]="Plane","Heli","Glider","Drone"}
|
||||
|
||||
local WT_A1 = 0
|
||||
local WT_A2 = 1
|
||||
local WT_FLPR = 2
|
||||
local WT_A1_F1 = 3
|
||||
local WT_A2_F1 = 4
|
||||
local WT_A2_F2 = 5
|
||||
local WT_ELEVON_A = 6
|
||||
local WT_ELEVON_B = 7
|
||||
|
||||
local wing_type_text = {[0]="Normal","Dual Ail","Flapperon", "Ail + Flp","Dual Ail + Flp","Dual Ail/Flp","Elevon A","Elevon B"}
|
||||
|
||||
local TT_R1 = 0
|
||||
local TT_R1_E1 = 1
|
||||
local TT_R1_E2 = 2
|
||||
local TT_R2_E1 = 3
|
||||
local TT_R2_E2 = 4
|
||||
local TT_VT_A = 5
|
||||
local TT_VT_B = 6
|
||||
local TT_TLRN_A = 7
|
||||
local TT_TLRN_B = 8
|
||||
local TT_TLRN_A_R2 = 9
|
||||
local TT_TLRN_B_R2 = 10
|
||||
|
||||
local tail_type_text = {[0]="Rud Only","Normal","Rud + Dual Ele","Dual Rud + Elv","Dual Rud/Ele",
|
||||
"VTail A","VTail B","Taileron A","Taileron B",
|
||||
"Taileron A + Dual Rud","Taileron B + Dual Rud"
|
||||
}
|
||||
|
||||
local MT_NORMAL = 0
|
||||
local MT_REVERSE = 1
|
||||
|
||||
local P1 = 0
|
||||
local P2 = 1
|
||||
local P3 = 2
|
||||
local P4 = 3
|
||||
local P5 = 4
|
||||
local P6 = 5
|
||||
local P7 = 6
|
||||
local P8 = 7
|
||||
--local P9 = 8
|
||||
--local P10 = 9
|
||||
|
||||
local MV_AIRCRAFT_TYPE = 1001
|
||||
local MV_WING_TYPE = 1002
|
||||
local MV_TAIL_TYPE = 1003
|
||||
|
||||
local MV_CH_BASE = 1010
|
||||
local MV_CH_THR = 1010
|
||||
|
||||
local MV_CH_L_AIL = 1011
|
||||
local MV_CH_R_AIL = 1012
|
||||
local MV_CH_L_FLP = 1013
|
||||
local MV_CH_R_FLP = 1014
|
||||
|
||||
local MV_CH_L_RUD = 1015
|
||||
local MV_CH_R_RUD = 1016
|
||||
local MV_CH_L_ELE = 1017
|
||||
local MV_CH_R_ELE = 1018
|
||||
|
||||
local MV_PORT_BASE = 1020
|
||||
local MV_P1_MODE = 1020
|
||||
--local MV_P2_MODE = 1021
|
||||
--local MV_P3_MODE = 1022
|
||||
--local MV_P4_MODE = 1023
|
||||
--local MV_P5_MODE = 1024
|
||||
local MV_P6_MODE = 1025
|
||||
--local MV_P7_MODE = 1026
|
||||
--local MV_P8_MODE = 1027
|
||||
--local MV_P9_MODE = 1028
|
||||
--local MV_P10_MODE = 1029
|
||||
|
||||
local MV_DATA_END = 1040
|
||||
|
||||
-- MENU DATA Management
|
||||
local M_DB = {} -- Store the variables used in the Menus.
|
||||
|
||||
local lastGoodMenu=0
|
||||
|
||||
local currATyp = -1
|
||||
local currTTyp = -1
|
||||
local currWTyp = -1
|
||||
|
||||
local menuDataChanged = false
|
||||
|
||||
local MODEL = {
|
||||
modelName = "", -- The name of the model comming from OTX/ETX
|
||||
hashName = nil,
|
||||
modelOutputChannel = {}, -- Output information from OTX/ETX
|
||||
|
||||
TX_CH_TEXT= { },
|
||||
PORT_TEXT = { },
|
||||
|
||||
DSM_ChannelInfo = {} -- Data Created by DSM Configuration Script
|
||||
}
|
||||
|
||||
local function gc()
|
||||
collectgarbage("collect")
|
||||
end
|
||||
|
||||
--[[
|
||||
local function gcTable(t)
|
||||
if type(t)=="table" then
|
||||
for i,v in pairs(t) do
|
||||
if type(v) == "table" then
|
||||
gcTable(v)
|
||||
end
|
||||
t[i] = nil
|
||||
end
|
||||
end
|
||||
gc()
|
||||
return t
|
||||
end
|
||||
--]]
|
||||
|
||||
local function LOG_open()
|
||||
logFile = io.open(LOG_FILE, "w") -- Truncate Log File
|
||||
end
|
||||
|
||||
local function LOG_write(...)
|
||||
if (logFile == nil) then LOG_open() end
|
||||
local str = string.format(...)
|
||||
io.write(logFile, str)
|
||||
end
|
||||
|
||||
local function LOG_close()
|
||||
if (logFile ~= nil) then io.close(logFile) end
|
||||
end
|
||||
|
||||
-- Saves MENU_DATA to a file
|
||||
local function ST_SaveFileData()
|
||||
local fname = MODEL.hashName
|
||||
|
||||
print("Saving File:"..fname)
|
||||
local dataFile = assert(io.open(DATA_PATH .. "/" .. fname, "w"),"Please create "..DATA_PATH.." folder") -- write File
|
||||
|
||||
-- Foreach MENU_DATA with a value write Var_Id:Value into file
|
||||
for i = 0, MV_DATA_END do
|
||||
if (M_DB[i]~=nil) then
|
||||
io.write(dataFile,string.format("%s:%s\n",i,M_DB[i]))
|
||||
end
|
||||
end
|
||||
io.close(dataFile)
|
||||
end
|
||||
|
||||
local function tailTypeCompatible(a,b)
|
||||
|
||||
local function normalize(tt)
|
||||
if (tt==TT_TLRN_A or tt==TT_TLRN_B) then
|
||||
return TT_TLRN_A
|
||||
elseif (tt==TT_TLRN_A_R2 or tt==TT_TLRN_B_R2) then
|
||||
return TT_TLRN_A_R2
|
||||
elseif (tt==TT_VT_A or tt==TT_VT_B) then
|
||||
return TT_VT_A
|
||||
else
|
||||
return tt
|
||||
end
|
||||
end
|
||||
|
||||
return (normalize(a)==normalize(b))
|
||||
end
|
||||
|
||||
local function ST_PlaneWingInit(wingType)
|
||||
--print("Change Plane WingType:"..wing_type_text[wingType])
|
||||
|
||||
M_DB[MV_WING_TYPE] = wingType
|
||||
|
||||
-- Clear all Wing Data
|
||||
M_DB[MV_CH_L_AIL] = nil
|
||||
M_DB[MV_CH_R_AIL] = nil
|
||||
M_DB[MV_CH_L_FLP] = nil
|
||||
M_DB[MV_CH_R_FLP] = nil
|
||||
|
||||
M_DB[MV_CH_THR] = P1
|
||||
|
||||
-- Default Channel Assisgments for each Wing type
|
||||
|
||||
if (wingType==WT_A1) then
|
||||
M_DB[MV_CH_L_AIL] = P2
|
||||
elseif (wingType==WT_A2 or wingType==WT_FLPR) then
|
||||
M_DB[MV_CH_L_AIL] = P6
|
||||
M_DB[MV_CH_R_AIL] = P2
|
||||
elseif (wingType==WT_A1_F1) then
|
||||
M_DB[MV_CH_L_AIL] = P2
|
||||
M_DB[MV_CH_L_FLP] = P6
|
||||
elseif (wingType==WT_A2_F1) then
|
||||
M_DB[MV_CH_L_AIL] = P6
|
||||
M_DB[MV_CH_R_AIL] = P2
|
||||
M_DB[MV_CH_L_FLP] = P5
|
||||
elseif (wingType==WT_A2_F2) then
|
||||
M_DB[MV_CH_L_AIL] = P6
|
||||
M_DB[MV_CH_R_AIL] = P2
|
||||
M_DB[MV_CH_R_FLP] = P5
|
||||
M_DB[MV_CH_L_FLP] = P7
|
||||
elseif (wingType==WT_ELEVON_A) then
|
||||
M_DB[MV_CH_L_AIL] = P2
|
||||
M_DB[MV_CH_R_AIL] = P3
|
||||
elseif (wingType==WT_ELEVON_B) then
|
||||
M_DB[MV_CH_L_AIL] = P3
|
||||
M_DB[MV_CH_R_AIL] = P2
|
||||
else -- Assume normal
|
||||
print("ERROR: Invalid Wing Type")
|
||||
end
|
||||
end
|
||||
|
||||
local function ST_PlaneTailInit(tailType)
|
||||
if (M_DB[MV_WING_TYPE]==WT_ELEVON_A or
|
||||
M_DB[MV_WING_TYPE]==WT_ELEVON_B) then
|
||||
tailType = TT_R1 -- Delta only have ruder
|
||||
end
|
||||
|
||||
--print("Change Plane Tail Type:"..tail_type_text[tailType])
|
||||
|
||||
-- Clear all data for Tail
|
||||
M_DB[MV_TAIL_TYPE] = tailType
|
||||
M_DB[MV_CH_L_ELE] = nil
|
||||
M_DB[MV_CH_R_ELE] = nil
|
||||
M_DB[MV_CH_L_RUD] = nil
|
||||
M_DB[MV_CH_R_RUD] = nil
|
||||
|
||||
-- Setup Channels for different Tail types
|
||||
if (tailType == TT_R1) then
|
||||
M_DB[MV_CH_L_RUD] = P4
|
||||
elseif (tailType == TT_R1_E1) then
|
||||
M_DB[MV_CH_L_ELE] = P3
|
||||
M_DB[MV_CH_L_RUD] = P4
|
||||
elseif (tailType == TT_R1_E2) then
|
||||
M_DB[MV_CH_L_ELE] = P5
|
||||
M_DB[MV_CH_R_ELE] = P3
|
||||
M_DB[MV_CH_L_RUD] = P4
|
||||
elseif (tailType == TT_R2_E1) then
|
||||
M_DB[MV_CH_L_ELE] = P3
|
||||
M_DB[MV_CH_L_RUD] = P4
|
||||
M_DB[MV_CH_R_RUD] = P5
|
||||
elseif (tailType == TT_R2_E2) then
|
||||
M_DB[MV_CH_L_ELE] = P5
|
||||
M_DB[MV_CH_R_ELE] = P3
|
||||
M_DB[MV_CH_L_RUD] = P4
|
||||
M_DB[MV_CH_R_RUD] = P6
|
||||
elseif (tailType == TT_VT_A or tailType == TT_VT_B) then
|
||||
M_DB[MV_CH_L_ELE] = P3
|
||||
M_DB[MV_CH_R_ELE] = P4
|
||||
elseif (tailType == TT_TLRN_A or tailType == TT_TLRN_B or
|
||||
tailType == TT_TLRN_A_R2 or tailType == TT_TLRN_B_R2) then
|
||||
M_DB[MV_CH_L_RUD] = P4
|
||||
M_DB[MV_CH_L_ELE] = P5
|
||||
M_DB[MV_CH_R_ELE] = P3
|
||||
else -- Assume Normal
|
||||
print("ERROR:invalid Tail Type")
|
||||
end
|
||||
|
||||
if (tailType == TT_TLRN_A_R2 or tailType == TT_TLRN_B_R2) then
|
||||
M_DB[MV_CH_R_RUD] = P8
|
||||
end
|
||||
end
|
||||
|
||||
local function ST_AircraftInit(aircraftType)
|
||||
M_DB[MV_AIRCRAFT_TYPE] = aircraftType
|
||||
ST_PlaneWingInit(WT_A1)
|
||||
ST_PlaneTailInit(TT_R1_E1)
|
||||
end
|
||||
|
||||
|
||||
-- Setup Initial Default Data for the Menus
|
||||
local function ST_Default_Data()
|
||||
ST_AircraftInit(AT_PLANE)
|
||||
|
||||
for i=0,9 do
|
||||
M_DB[MV_P1_MODE+i] = MT_NORMAL + MODEL.modelOutputChannel[P1+i].revert
|
||||
end
|
||||
end
|
||||
|
||||
local function MenuLinePostProcessing(line)
|
||||
line.MenuId = Menu.MenuId
|
||||
|
||||
if line.Type == LT_MENU then
|
||||
-- nothing to do on menu entries
|
||||
line.Val=nil
|
||||
elseif line.Type == LT_LIST_NC then
|
||||
-- Normalize Min/Max to be relative to Zero
|
||||
line.TextStart = line.Min
|
||||
line.Def = line.Def - line.Min -- normalize default value
|
||||
line.Max = line.Max - line.Min -- normalize max index
|
||||
line.Min = 0 -- min index
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local function portUse(p)
|
||||
local out = nil
|
||||
if p==M_DB[MV_CH_THR] then out = "Thr"
|
||||
elseif p == M_DB[MV_CH_L_AIL] then
|
||||
out=(M_DB[MV_CH_R_AIL] and "Ail_L") or "Ail"
|
||||
elseif p == M_DB[MV_CH_R_AIL] then out="Ail_R"
|
||||
elseif p == M_DB[MV_CH_L_ELE] then
|
||||
out=(M_DB[MV_CH_R_ELE] and "Ele_L") or "Ele"
|
||||
elseif p == M_DB[MV_CH_R_ELE] then out="Ele_R"
|
||||
elseif p == M_DB[MV_CH_L_RUD] then
|
||||
out=(M_DB[MV_CH_R_RUD] and "Rud_L") or "Rud"
|
||||
elseif p == M_DB[MV_CH_R_RUD] then out="Rud-R"
|
||||
elseif p == M_DB[MV_CH_L_FLP] then
|
||||
out=(M_DB[MV_CH_R_FLP] and "Flp_L") or "Flp"
|
||||
elseif p == M_DB[MV_CH_R_FLP] then out="Flp_R"
|
||||
else
|
||||
out = ""
|
||||
end
|
||||
return out
|
||||
end
|
||||
|
||||
-- Creates the menus to Render with the GUI
|
||||
local function ST_LoadMenu(menuId)
|
||||
|
||||
local function Header(p)
|
||||
return MODEL.PORT_TEXT[p].." "..portUse(p)
|
||||
end
|
||||
|
||||
local function generateGyroReverse(menuId, P_BASE, V_BASE)
|
||||
for i=0,4 do
|
||||
MenuLines[i] = { Type = LT_LIST_NC, Text=Header(P_BASE+i), TextId = 0, ValId = V_BASE+i, Min=45, Max=46, Def=45, Val=M_DB[V_BASE+i] }
|
||||
end
|
||||
|
||||
MenuLines[5] = { Type = LT_MENU, Text="Only TAER affects AS3X/SAFE react dir", TextId = 0, ValId = menuId }
|
||||
MenuLines[6] = { Type = LT_MENU, Text="If changes, RX 'Relearn Servo'", TextId = 0, ValId = menuId }
|
||||
|
||||
ctx_SelLine = 0
|
||||
end
|
||||
|
||||
-- Begin
|
||||
for i = 0, 6 do -- clear menu
|
||||
MenuLines[i] = { MenuId = 0, lineNum = 0, Type = 0 }
|
||||
end
|
||||
|
||||
|
||||
if (menuId==0x1000) then -- MAIN MENU
|
||||
Menu = { MenuId = 0x1000, Text = "Save-Exit ("..MODEL.modelName..")", PrevId = 0, NextId = 0, BackId = 0, TextId=0 }
|
||||
|
||||
if (true) then
|
||||
MenuLines[4] = { Type = LT_MENU, Text="Save Changes", TextId = 0, ValId = 0x1005 }
|
||||
MenuLines[5] = { Type = LT_MENU, Text="Discard Changes", TextId = 0, ValId = 0xFFF9 }
|
||||
ctx_SelLine = 4
|
||||
end
|
||||
lastGoodMenu = menuId
|
||||
elseif (menuId==0x1001) then -- MODEL SETUP
|
||||
local backId = 0xFFF9 -- No changes, just exit
|
||||
local title = "Setup ("..MODEL.modelName..")"
|
||||
if (menuDataChanged) then
|
||||
backId = 0x1000 -- Go to Save menu
|
||||
title = title.." *"
|
||||
end
|
||||
Menu = { MenuId = 0x1001, Text = title, PrevId = 0, NextId = 0, BackId = backId, TextId=0 }
|
||||
MenuLines[0] = { Type = LT_MENU, Text = "Aircraft Setup", ValId = 0x1010,TextId=0 }
|
||||
MenuLines[1] = { Type = LT_MENU, Text = "Wing & Tail Channels ", ValId = 0x1020, TextId=0 }
|
||||
MenuLines[3] = { Type = LT_MENU, Text = "Gyro Channel Reverse", ValId = 0x1030, TextId=0 }
|
||||
MenuLines[5] = { Type = LT_MENU, Text = "WARNING: Changing of Aircraft", ValId = 0x1001, TextId=0 }
|
||||
MenuLines[6] = { Type = LT_MENU, Text = "deletes prev Ch/Port assgmt.", ValId = 0x1001, TextId=0 }
|
||||
|
||||
ctx_SelLine = 0
|
||||
lastGoodMenu = menuId
|
||||
elseif (menuId==0x1005) then
|
||||
ST_SaveFileData()
|
||||
menuDataChanged = false
|
||||
|
||||
local msg1 = "Data saved to: "
|
||||
local msg2 = " ../DSMLIB/"..MODEL.hashName
|
||||
|
||||
Menu = { MenuId = 0x1005, Text = "Config Saved", PrevId = 0, NextId = 0, BackId = 0, TextId=0 }
|
||||
MenuLines[2] = { Type = LT_MENU, Text=msg1, TextId = 0, ValId = 0x1005 }
|
||||
MenuLines[3] = { Type = LT_MENU, Text=msg2, TextId = 0, ValId = 0x1005 }
|
||||
MenuLines[6] = { Type = LT_MENU, Text="Complete", TextId = 0, ValId = 0xFFF9 }
|
||||
ctx_SelLine = 6
|
||||
lastGoodMenu = menuId
|
||||
elseif (menuId==0x1010) then
|
||||
Menu = { MenuId = 0x1010, Text = "Aircraft", PrevId = 0, NextId = 0x1011, BackId = 0x1001, TextId=0 }
|
||||
MenuLines[5] = { Type = LT_LIST_NC, Text="Aircraft Type", TextId = 0, ValId = MV_AIRCRAFT_TYPE, Min=15, Max=15, Def=15, Val=M_DB[MV_AIRCRAFT_TYPE] }
|
||||
ctx_SelLine = 5
|
||||
lastGoodMenu = menuId
|
||||
elseif (menuId==0x1011) then
|
||||
Menu = { MenuId = 0x1011, Text = "Model Type: "..aircraft_type_text[currATyp], PrevId = 0, NextId = 0x1020, BackId = 0x1010, TextId=0 }
|
||||
MenuLines[5] = { Type = LT_LIST_NC, Text="Wing Type", TextId = 0, ValId = MV_WING_TYPE, Min=20, Max=27, Def=20, Val=M_DB[MV_WING_TYPE] }
|
||||
MenuLines[6] = { Type = LT_LIST_NC, Text="Tail Type", TextId = 0, ValId = MV_TAIL_TYPE, Min=30, Max=40, Def=30, Val=M_DB[MV_TAIL_TYPE] }
|
||||
ctx_SelLine = 5
|
||||
lastGoodMenu = menuId
|
||||
elseif (menuId==0x1020) then
|
||||
------ WING SETUP -------
|
||||
local thr = M_DB[MV_CH_THR]
|
||||
local leftAil = M_DB[MV_CH_L_AIL]
|
||||
local rightAil = M_DB[MV_CH_R_AIL]
|
||||
local leftFlap = M_DB[MV_CH_L_FLP]
|
||||
local rightFlap = M_DB[MV_CH_R_FLP]
|
||||
|
||||
local thrText = "Thr"
|
||||
local leftAilText = "Left Ail"
|
||||
local rightAilText = "Right Ail"
|
||||
local leftFlapText = "Left Flap"
|
||||
local rightFlapText = "Right Flap"
|
||||
|
||||
if (rightAil==nil) then leftAilText = "Aileron" end
|
||||
if (rightFlap==nil) then leftFlapText = "Flap" end
|
||||
|
||||
local title = aircraft_type_text[currATyp].." Wing:"..wing_type_text[currWTyp]
|
||||
|
||||
Menu = { MenuId = 0x1020, Text = title, PrevId = 0, NextId = 0x1021, BackId = 0x1011, TextId=0 }
|
||||
|
||||
MenuLines[0] = { Type = LT_LIST_NC, Text=thrText, TextId = 0, ValId = MV_CH_THR, Min=0, Max=10, Def=0, Val= thr }
|
||||
|
||||
MenuLines[2] = { Type = LT_LIST_NC, Text=leftAilText, TextId = 0, ValId = MV_CH_L_AIL, Min=0, Max=9, Def=0, Val= leftAil }
|
||||
|
||||
if (rightAil) then
|
||||
MenuLines[3] = { Type = LT_LIST_NC, Text=rightAilText, TextId = 0, ValId = MV_CH_R_AIL, Min=0, Max=9, Def=0, Val= rightAil }
|
||||
end
|
||||
|
||||
if (leftFlap) then
|
||||
MenuLines[4] = { Type = LT_LIST_NC, Text=leftFlapText, TextId = 0, ValId = MV_CH_L_FLP, Min=0, Max=9, Def=0, Val= leftFlap }
|
||||
end
|
||||
if (rightFlap) then
|
||||
MenuLines[5] = { Type = LT_LIST_NC, Text=rightFlapText, TextId = 0, ValId = MV_CH_R_FLP, Min=0, Max=9, Def=0, Val= rightFlap }
|
||||
end
|
||||
|
||||
ctx_SelLine = 0
|
||||
lastGoodMenu = menuId
|
||||
|
||||
elseif (menuId==0x1021) then
|
||||
------ TAIL SETUP -------
|
||||
local leftRud = M_DB[MV_CH_L_RUD]
|
||||
local rightRud = M_DB[MV_CH_R_RUD]
|
||||
local leftEle = M_DB[MV_CH_L_ELE]
|
||||
local rightEle = M_DB[MV_CH_R_ELE]
|
||||
|
||||
local leftRudText = "Left Rud"
|
||||
local rightRudText = "Right Rud"
|
||||
|
||||
local leftElvText = "Left Ele"
|
||||
local rightElvText = "Right Ele"
|
||||
|
||||
if (rightRud==nil) then leftRudText = "Rud" end
|
||||
if (rightEle==nil) then leftElvText = "Ele" end
|
||||
|
||||
local title = aircraft_type_text[currATyp].." Tail:"..tail_type_text[currTTyp]
|
||||
|
||||
Menu = { MenuId = 0x1021, Text = title, PrevId = 0, NextId = 0x1001, BackId = 0x1020, TextId=0 }
|
||||
if (leftRud) then
|
||||
MenuLines[1] = { Type = LT_LIST_NC, Text=leftRudText, TextId = 0, ValId = MV_CH_L_RUD, Min=0, Max=9, Def=0, Val= leftRud}
|
||||
end
|
||||
|
||||
if (rightRud) then
|
||||
MenuLines[2] = { Type = LT_LIST_NC, Text=rightRudText, TextId = 0, ValId = MV_CH_R_RUD, Min=0, Max=9, Def=0, Val=rightRud }
|
||||
end
|
||||
|
||||
if (leftEle) then
|
||||
MenuLines[4] = { Type = LT_LIST_NC, Text=leftElvText, TextId = 0, ValId = MV_CH_L_ELE, Min=0, Max=9, Def=0, Val=leftEle }
|
||||
end
|
||||
|
||||
if (rightEle) then
|
||||
MenuLines[5] = { Type = LT_LIST_NC, Text=rightElvText, TextId = 0, ValId = MV_CH_R_ELE, Min=0, Max=9, Def=0, Val=rightEle }
|
||||
end
|
||||
|
||||
ctx_SelLine = 1
|
||||
lastGoodMenu = menuId
|
||||
|
||||
elseif (menuId==0x1030) then
|
||||
Menu = { MenuId = 0x1030, Text = "Gyro Reverse (Port 1-5)", PrevId = 0, NextId = 0x1031, BackId = 0x1001, TextId=0 }
|
||||
generateGyroReverse(menuId,P1,MV_P1_MODE)
|
||||
lastGoodMenu = menuId
|
||||
elseif (menuId==0x1031) then
|
||||
Menu = { MenuId = 0x1031, Text = "Gyro Reverse (Port 6-10)", PrevId = 0x1030, NextId = 0, BackId = 0x1001, TextId=0 }
|
||||
generateGyroReverse(menuId,P6,MV_P6_MODE)
|
||||
lastGoodMenu = menuId
|
||||
elseif (menuId==0xFFF9) then
|
||||
ChangePhase(PH_EXIT_DONE)
|
||||
return
|
||||
else
|
||||
Menu = { MenuId = 0x0002, Text = "NOT IMPLEMENTED", TextId = 0, PrevId = 0, NextId = 0, BackId = lastGoodMenu }
|
||||
ctx_SelLine = -1 -- BACK BUTTON
|
||||
end
|
||||
|
||||
for i = 0, 6 do
|
||||
if (MenuLines[i].Type > 0) then
|
||||
MenuLinePostProcessing(MenuLines[i])
|
||||
end
|
||||
end
|
||||
gc()
|
||||
end
|
||||
|
||||
-- Inital List and Image Text for this menus
|
||||
local function ST_Init_Text(rxId)
|
||||
-- Channel Names use the Port Text Retrived from OTX/ETX
|
||||
local p = 0
|
||||
|
||||
for i = 0, 9 do List_Text[i] = MODEL.PORT_TEXT[i] end
|
||||
List_Text[10] = "--"
|
||||
|
||||
-- Aircraft Type
|
||||
List_Text[15+AT_PLANE] = "Airplane";
|
||||
|
||||
-- Wing Types
|
||||
p = 20+WT_A1; List_Text[p] = "Single Ail"; --List_Text_Img[p] = "x.png|Single Aileron"
|
||||
p = 20+WT_A2; List_Text[p] = "Dual Ail"; --List_Text_Img[p] = "x.png|Dual Aileron"
|
||||
p = 20+WT_FLPR; List_Text[p] = "Flaperon"; --List_Text_Img[p] = "x.png|Flaperon"
|
||||
p = 20+WT_A1_F1; List_Text[p] = "Ail + Flap"; --List_Text_Img[p] = "x.png|Aileron + Flap"
|
||||
p = 20+WT_A2_F1; List_Text[p] = "Dual Ail + Flap"; --List_Text_Img[p] = "x.png|Dual Aileron + Flap"
|
||||
p = 20+WT_A2_F2; List_Text[p] = "Dual Ail + Dual Flap"; --List_Text_Img[p] = "x.png|Dual Aileron + Dual Flap"
|
||||
p = 20+WT_ELEVON_A; List_Text[p] = "Delta A"; --List_Text_Img[p] = "x.png|Delta/Elevon A"
|
||||
p = 20+WT_ELEVON_B; List_Text[p] = "Delta B"; --List_Text_Img[p] = "x.png|Delta/Elevon B"
|
||||
|
||||
-- Tail Types
|
||||
p = 30+TT_R1; List_Text[p] = "Rudder Only"; --List_Text_Img[p] = "x.png|Rudder Only"
|
||||
p = 30+TT_R1_E1; List_Text[p] = "Rud + Ele"; --List_Text_Img[p] = "x.png|Tail Normal"
|
||||
p = 30+TT_R1_E2; List_Text[p] = "Rud + Dual Ele"; --List_Text_Img[p] = "x.png|Rud + Dual Ele"
|
||||
p = 30+TT_R2_E1; List_Text[p] = "Dual Rud + Ele"; --List_Text_Img[p] = "x.png|Dual Rud + Ele"
|
||||
p = 30+TT_R2_E2; List_Text[p] = "Dual Rud + Dual Ele"; --List_Text_Img[p] = "x.png|Dual Rud + Dual Elev"
|
||||
p = 30+TT_VT_A; List_Text[p] = "V-Tail A"; --List_Text_Img[p] = "x.png|V-Tail A"
|
||||
p = 30+TT_VT_B; List_Text[p] = "V-Tail B"; --List_Text_Img[p] = "x.png|V-Tail B"
|
||||
p = 30+TT_TLRN_A; List_Text[p] = "Taileron A"; --List_Text_Img[p] = "x.png|Taileron A"
|
||||
p = 30+TT_TLRN_B; List_Text[p] = "Taileron B"; --List_Text_Img[p] = "x.png|Taileron B"
|
||||
p = 30+TT_TLRN_A_R2; List_Text[p] = "Taileron A + 2x Rud"; --List_Text_Img[p] = "x.png|Taileron A + Dual Rud"
|
||||
p = 30+TT_TLRN_B_R2; List_Text[p] = "Taileron B + 2x Rud"; --List_Text_Img[p] = "x.png|Taileron B + Dual Rud"
|
||||
|
||||
-- Servo Reverse
|
||||
List_Text[45+MT_NORMAL] = "Normal"
|
||||
List_Text[45+MT_REVERSE] = "Reverse"
|
||||
end
|
||||
|
||||
-- Initial Setup
|
||||
local function ST_Init()
|
||||
ST_Init_Text(0)
|
||||
gc()
|
||||
|
||||
-- Setup default Data if no data loaded
|
||||
menuDataChanged = false
|
||||
if (M_DB[MV_AIRCRAFT_TYPE]==nil) then
|
||||
ST_Default_Data()
|
||||
menuDataChanged = true
|
||||
end
|
||||
|
||||
currATyp = M_DB[MV_AIRCRAFT_TYPE]
|
||||
currWTyp = M_DB[MV_WING_TYPE]
|
||||
currTTyp = M_DB[MV_TAIL_TYPE]
|
||||
|
||||
Phase = PH_RX_VER
|
||||
end
|
||||
|
||||
----- Line Type
|
||||
|
||||
local function isSelectable(line)
|
||||
if (line.Type == LT_MENU and line.ValId == line.MenuId) then return false end -- Menu to same page
|
||||
if (line.Type ~= LT_MENU and line.Max == 0) then return false end -- Read only data line
|
||||
if (line.Type ~= 0 and line.TextId < 0x8000) then return true end -- Not Flight Mode
|
||||
return false;
|
||||
end
|
||||
|
||||
local function isListLine(line)
|
||||
return line.Type==LT_LIST_NC
|
||||
end
|
||||
|
||||
local function isEditing()
|
||||
return ctx_EditLine ~= nil
|
||||
end
|
||||
|
||||
-----------------------
|
||||
local function Get_Text(index)
|
||||
local out = Text[index] or string.format("Unknown_%X", index)
|
||||
return out
|
||||
end
|
||||
|
||||
local function Get_Text_Value(index)
|
||||
local out = List_Text[index] or Get_Text(index)
|
||||
return out
|
||||
end
|
||||
|
||||
function ChangePhase(newPhase)
|
||||
Phase = newPhase
|
||||
end
|
||||
|
||||
local function Value_Add(dir)
|
||||
local line = MenuLines[ctx_SelLine]
|
||||
local inc = dir
|
||||
|
||||
line.Val = line.Val + inc
|
||||
|
||||
if line.Val > line.Max then
|
||||
line.Val = line.Max
|
||||
elseif line.Val < line.Min then
|
||||
line.Val = line.Min
|
||||
end
|
||||
end
|
||||
--------------
|
||||
|
||||
local function GotoMenu(menuId, lastSelectedLine)
|
||||
Menu.MenuId = menuId
|
||||
ctx_SelLine = lastSelectedLine
|
||||
ChangePhase(PH_TITLE)
|
||||
end
|
||||
|
||||
local function DSM_HandleEvent(event)
|
||||
if event == EVT_VIRTUAL_EXIT then
|
||||
if Phase == PH_RX_VER then
|
||||
Phase = PH_EXIT_DONE -- Exit program
|
||||
else
|
||||
if isEditing() then -- Editing a Line, need to restore original value
|
||||
MenuLines[ctx_EditLine].Val = originalValue
|
||||
event = EVT_VIRTUAL_ENTER
|
||||
else
|
||||
if (Menu.BackId > 0 ) then -- Back??
|
||||
ctx_SelLine = -1 --Back Button
|
||||
event = EVT_VIRTUAL_ENTER
|
||||
else
|
||||
ChangePhase(PH_EXIT_REQ)
|
||||
end
|
||||
end
|
||||
end
|
||||
end -- Exit
|
||||
|
||||
if Phase == PH_RX_VER then return end -- nothing else to do
|
||||
|
||||
if event == EVT_VIRTUAL_NEXT then
|
||||
if isEditing() then -- Editting?
|
||||
Value_Add(1)
|
||||
else
|
||||
if ctx_SelLine < 7 then -- On a regular line
|
||||
local num = ctx_SelLine -- Find the prev selectable
|
||||
for i = ctx_SelLine + 1, 6, 1 do
|
||||
local line = MenuLines[i]
|
||||
if isSelectable(line) then
|
||||
ctx_SelLine = i
|
||||
break
|
||||
end
|
||||
end
|
||||
if num == ctx_SelLine then -- No Selectable Line
|
||||
if Menu.NextId ~= 0 then
|
||||
ctx_SelLine = 7 -- Next
|
||||
elseif Menu.PrevId ~= 0 then
|
||||
ctx_SelLine = 8 -- Prev
|
||||
end
|
||||
end
|
||||
elseif Menu.PrevId ~= 0 then
|
||||
ctx_SelLine = 8 -- Prev
|
||||
end
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
if event == EVT_VIRTUAL_PREV then
|
||||
if isEditing() then -- In Edit Mode
|
||||
Value_Add(-1)
|
||||
else
|
||||
if ctx_SelLine == 8 and Menu.NextId ~= 0 then
|
||||
ctx_SelLine = 7 -- Next
|
||||
elseif ctx_SelLine > 0 then
|
||||
if ctx_SelLine > 6 then
|
||||
ctx_SelLine = 7 --NEXT
|
||||
end
|
||||
local num = ctx_SelLine -- Find Prev Selectable line
|
||||
for i = ctx_SelLine - 1, 0, -1 do
|
||||
local line = MenuLines[i]
|
||||
if isSelectable(line) then
|
||||
ctx_SelLine = i
|
||||
break
|
||||
end
|
||||
end
|
||||
if num == ctx_SelLine then -- No Selectable Line
|
||||
if (Menu.BackId > 0) then
|
||||
ctx_SelLine = -1 -- Back
|
||||
end
|
||||
end
|
||||
else
|
||||
ctx_SelLine = -1 -- Back
|
||||
end
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
|
||||
if event == EVT_VIRTUAL_ENTER then
|
||||
if ctx_SelLine == -1 then -- Back
|
||||
GotoMenu(Menu.BackId, 0x80)
|
||||
elseif ctx_SelLine == 7 then -- Next
|
||||
GotoMenu(Menu.NextId, 0x82)
|
||||
elseif ctx_SelLine == 8 then -- Prev
|
||||
GotoMenu(Menu.PrevId, 0x81)
|
||||
elseif ctx_SelLine >= 0 and MenuLines[ctx_SelLine].Type == LT_MENU then
|
||||
GotoMenu(MenuLines[ctx_SelLine].ValId, ctx_SelLine) -- ValId is the next menu
|
||||
else
|
||||
-- value entry
|
||||
if isEditing() then
|
||||
ctx_EditLine = nil -- Done Editting
|
||||
ChangePhase(PH_VAL_EDIT_END)
|
||||
else -- Start Editing
|
||||
ctx_EditLine = ctx_SelLine
|
||||
originalValue = MenuLines[ctx_SelLine].Val
|
||||
ChangePhase(PH_VAL_EDITING)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function DSM_Send_Receive()
|
||||
|
||||
if Phase == PH_RX_VER then -- request RX version
|
||||
Phase = PH_TITLE
|
||||
Menu.MenuId = 0x01001
|
||||
Refresh_Display = true
|
||||
elseif Phase == PH_WAIT_CMD then
|
||||
|
||||
elseif Phase == PH_TITLE then -- request menu title
|
||||
ST_LoadMenu(Menu.MenuId)
|
||||
if (Phase~=PH_EXIT_DONE) then
|
||||
Phase = PH_WAIT_CMD
|
||||
end
|
||||
Refresh_Display = true
|
||||
elseif Phase == PH_VAL_EDIT_END then -- send value
|
||||
local line = MenuLines[ctx_SelLine] -- Updated Value of SELECTED line
|
||||
|
||||
-- Update the menu data from the line
|
||||
if (M_DB[line.ValId] ~= line.Val ) then
|
||||
M_DB[line.ValId] = line.Val
|
||||
print(string.format("MENU_DATA[%d/%s]=%d",line.ValId,line.Text, line.Val))
|
||||
menuDataChanged=true
|
||||
end
|
||||
|
||||
-- Did the Wing type change?
|
||||
local wt = M_DB[MV_WING_TYPE]
|
||||
if (currWTyp ~= wt) then
|
||||
currWTyp = wt
|
||||
ST_PlaneWingInit(currWTyp)
|
||||
|
||||
-- DELTA has only RUDER
|
||||
if (currWTyp==WT_ELEVON_A or currWTyp==WT_ELEVON_B) then
|
||||
M_DB[MV_TAIL_TYPE] = TT_R1
|
||||
end
|
||||
end
|
||||
|
||||
--- Did the tail changed?
|
||||
local tt = M_DB[MV_TAIL_TYPE]
|
||||
if (currTTyp ~= tt) then
|
||||
if (not tailTypeCompatible(currTTyp,tt)) then
|
||||
ST_PlaneTailInit(tt)
|
||||
end
|
||||
currTTyp = tt
|
||||
end
|
||||
|
||||
Phase = PH_WAIT_CMD
|
||||
elseif Phase == PH_EXIT_REQ then
|
||||
Phase=PH_EXIT_DONE
|
||||
end
|
||||
end
|
||||
|
||||
-----
|
||||
|
||||
local function showBitmap(x, y, imgDesc)
|
||||
local f = string.gmatch(imgDesc, '([^%|]+)') -- Iterator over values split by '|'
|
||||
local imgName, imgMsg = f(), f()
|
||||
|
||||
f = string.gmatch(imgMsg or "", '([^%:]+)') -- Iterator over values split by ':'
|
||||
local p1, p2 = f(), f()
|
||||
|
||||
lcd.drawText(x, y, p1 or "", TEXT_ATTR) -- Alternate Image MSG
|
||||
lcd.drawText(x, y + LCD_Y_LINE_HEIGHT, p2 or "", TEXT_ATTR) -- Alternate Image MSG
|
||||
gc()
|
||||
end
|
||||
|
||||
|
||||
local function drawButton(x, y, text, active)
|
||||
local attr = TEXT_ATTR
|
||||
if (active) then attr = attr + INVERS end
|
||||
lcd.drawText(x, y, text, attr)
|
||||
end
|
||||
|
||||
local function DSM_Display()
|
||||
lcd.clear()
|
||||
--Draw RX Menu
|
||||
if Phase == PH_RX_VER then
|
||||
return
|
||||
end
|
||||
|
||||
-- display Program version or RX version
|
||||
local msg = "FProg "..VERSION
|
||||
lcd.drawText(40, LCD_Y_LOWER_BUTTONS, msg, TEXT_ATTR)
|
||||
|
||||
if Menu.MenuId == 0 then return end; -- No Title yet
|
||||
|
||||
-- Got a Menu
|
||||
lcd.drawText(1, 0, Menu.Text, TEXT_ATTR + INVERS)
|
||||
|
||||
local y = LCD_Y_LINE_HEIGHT + 2
|
||||
for i = 0, 6 do
|
||||
local attrib = TEXT_ATTR
|
||||
if (i == ctx_SelLine) then attrib = attrib + INVERS end -- Selected Line
|
||||
|
||||
local line = MenuLines[i]
|
||||
|
||||
if line ~= nil and line.Type ~= 0 then
|
||||
local heading = line.Text
|
||||
|
||||
local text = nil
|
||||
if line.Type ~= LT_MENU then -- list/value
|
||||
if line.Val ~= nil then
|
||||
if isListLine(line) then
|
||||
local textId = line.Val + line.TextStart
|
||||
text = Get_Text_Value(textId)
|
||||
|
||||
--local imgDesc = List_Text_Img[textId]
|
||||
|
||||
--if (imgDesc and i == ctx_SelLine) then -- Optional Image and Msg for selected value
|
||||
-- showBitmap(1, 20, imgDesc)
|
||||
--end
|
||||
else
|
||||
text = line.Val
|
||||
end
|
||||
end -- if is Value
|
||||
|
||||
if (ctx_EditLine == i) then -- Editing a Line
|
||||
attrib = BLINK + INVERS + TEXT_ATTR
|
||||
end
|
||||
lcd.drawText(LCD_X_MAX, y, text or "--", attrib + RIGHT) -- display value
|
||||
--lcd.drawText(LCD_X_MAX, y, line.Format or "", TEXT_ATTR + RIGHT) -- display Format
|
||||
attrib = TEXT_ATTR
|
||||
end
|
||||
|
||||
lcd.drawText(1, y, heading, attrib) -- display text
|
||||
end
|
||||
y = y + LCD_Y_LINE_HEIGHT
|
||||
end -- for
|
||||
|
||||
if Menu.BackId~=0 then
|
||||
drawButton(LCD_X_RIGHT_BUTTONS, 0, "Back", ctx_SelLine == -1)
|
||||
end
|
||||
|
||||
if Menu.NextId~=0 then
|
||||
drawButton(LCD_X_RIGHT_BUTTONS, LCD_Y_LOWER_BUTTONS, "Next", ctx_SelLine == 7)
|
||||
end
|
||||
|
||||
if Menu.PrevId~=0 then
|
||||
drawButton(1, LCD_Y_LOWER_BUTTONS, "Prev", ctx_SelLine == 8)
|
||||
end
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
-- Init
|
||||
local function DSM_Init()
|
||||
--LOG_open()
|
||||
ST_Init()
|
||||
gc()
|
||||
|
||||
if (LCD_W > 128) then
|
||||
TEXT_ATTR = 0
|
||||
LCD_Y_LINE_HEIGHT = 25
|
||||
LCD_X_MAX = 300
|
||||
LCD_X_RIGHT_BUTTONS = LCD_X_MAX - 30
|
||||
|
||||
LCD_Y_LOWER_BUTTONS = (8 * LCD_Y_LINE_HEIGHT) + 2
|
||||
end
|
||||
|
||||
Phase = PH_RX_VER
|
||||
end
|
||||
|
||||
-- Main
|
||||
|
||||
local function DSM_Run(event)
|
||||
if event == nil then
|
||||
error("Cannot be run as a model script!")
|
||||
return 2
|
||||
end
|
||||
|
||||
DSM_Display()
|
||||
DSM_HandleEvent(event)
|
||||
DSM_Send_Receive()
|
||||
gc()
|
||||
|
||||
if Phase == PH_EXIT_DONE then
|
||||
LOG_close()
|
||||
return 2
|
||||
else
|
||||
return 0
|
||||
end
|
||||
end
|
||||
|
||||
---
|
||||
-- Load Model Config
|
||||
gc()
|
||||
local r = assert(loadScript(DSMLIB_PATH.."DsmMIN_P1.lua"), "Not-Found: DSMLIB/DsmMIN_P1.lua")
|
||||
(MODEL,M_DB, LOG_write)
|
||||
gc()
|
||||
----
|
||||
return { init = DSM_Init, run = DSM_Run }
|
@ -1,813 +0,0 @@
|
||||
---- #########################################################################
|
||||
---- # #
|
||||
---- # Copyright (C) OpenTX/EdgeTx #
|
||||
-----# #
|
||||
---- # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html #
|
||||
---- # #
|
||||
---- # This program is free software; you can redistribute it and/or modify #
|
||||
---- # it under the terms of the GNU General Public License version 2 as #
|
||||
---- # published by the Free Software Foundation. #
|
||||
---- # #
|
||||
---- # This program is distributed in the hope that it will be useful #
|
||||
---- # but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
---- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
---- # GNU General Public License for more details. #
|
||||
---- # #
|
||||
---- #########################################################################
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- This script library is a rewrite of the original DSM forward programming Lua
|
||||
-- Script. The goal is to make it easier to understand, mantain, and to
|
||||
-- separate the GUI from the DSM Forward programming engine/logic
|
||||
-- in this way, GUIs can evolve independent. OpenTX Gui, EdgeTx GUI, Small Radios, etc.
|
||||
|
||||
-- Code is based on the code/work by: Pascal Langer (Author of the Multi-Module)
|
||||
-- Rewrite/Enhancements By: Francisco Arzu
|
||||
--
|
||||
------------------------------------------------------------------------------
|
||||
--###############################################################################
|
||||
-- Multi buffer for DSM description
|
||||
-- Multi_Buffer[0..2]=="DSM" -> Lua script is running
|
||||
-- Multi_Buffer[3]==0x70+len -> TX to RX data ready to be sent
|
||||
-- Multi_Buffer[4..9]=6 bytes of TX to RX data
|
||||
-- Multi_Buffer[10..25]=16 bytes of RX to TX data
|
||||
--
|
||||
-- To start operation:
|
||||
-- Write 0x00 at address 3
|
||||
-- Write 0x00 at address 10
|
||||
-- Write "DSM" at address 0..2
|
||||
--###############################################################################
|
||||
|
||||
|
||||
local Log, menuLib, modelLib, DEBUG_ON = ... -- Get Debug_ON from parameters. -- 0=NO DEBUG, 1=HIGH LEVEL 2=MORE DETAILS
|
||||
local LIB_VERSION = "0.55"
|
||||
local MSG_FILE = "/SCRIPTS/TOOLS/DSMLIB/msg_fwdp_en.txt"
|
||||
|
||||
local PHASE = menuLib.PHASE
|
||||
local LINE_TYPE = menuLib.LINE_TYPE
|
||||
|
||||
local CH_TYPE = modelLib.CH_TYPE
|
||||
local CH_MIX_TYPE = modelLib.CH_MIX_TYPE
|
||||
|
||||
local DISP_ATTR = menuLib.DISP_ATTR
|
||||
local DSM_Context = menuLib.DSM_Context
|
||||
local MODEL = modelLib.MODEL
|
||||
|
||||
local MAX_MENU_LINES = menuLib.MAX_MENU_LINES
|
||||
local BACK_BUTTON = menuLib.BACK_BUTTON
|
||||
local NEXT_BUTTON = menuLib.NEXT_BUTTON
|
||||
local PREV_BUTTON = menuLib.PREV_BUTTON
|
||||
|
||||
|
||||
local SEND_TIMEOUT = 2000 / 10 -- Home many 10ms intervals to wait on sending data to tx to keep connection open (2s)
|
||||
local TXInactivityTime = 0 -- Next time to do heartbeat after inactivity
|
||||
local RXInactivityTime = 0 -- To check RX disconnection
|
||||
|
||||
|
||||
local TxInfo_Type = 0
|
||||
local TxInfo_Step = 0
|
||||
local Change_Step = 0
|
||||
|
||||
local IS_EDGETX = false
|
||||
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
|
||||
local function multiBuffer2String() -- used for debug
|
||||
local i
|
||||
local rxAnswer = "RX:"
|
||||
for i = 10, 25 do
|
||||
rxAnswer = rxAnswer .. string.format(" %02X", multiBuffer(i))
|
||||
end
|
||||
return rxAnswer
|
||||
end
|
||||
|
||||
---------------- DSM Values <-> Int16 Manipulation --------------------------------------------------------
|
||||
|
||||
local function int16_LSB(number) -- Less Significat byte
|
||||
local r,x = bit32.band(number, 0xFF)
|
||||
return r
|
||||
end
|
||||
|
||||
local function int16_MSB(number) -- Most signifcant byte
|
||||
return bit32.rshift(number, 8)
|
||||
end
|
||||
|
||||
local function Dsm_to_Int16(lsb, msb) -- Componse an Int16 value
|
||||
return bit32.lshift(msb, 8) + lsb
|
||||
end
|
||||
|
||||
local function Dsm_to_SInt16(lsb,msb) -- Componse a SIGNED Int16 value
|
||||
local value = bit32.lshift(msb, 8) + lsb
|
||||
if value >= 0x8000 then -- Negative value??
|
||||
return value - 0x10000
|
||||
end
|
||||
return value
|
||||
end
|
||||
|
||||
local function sInt16ToDsm(value) -- Convent to SIGNED DSM Value
|
||||
if value < 0 then
|
||||
value = 0x10000 + value
|
||||
end
|
||||
return value
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
local function DSM_send(...)
|
||||
local arg = { ... }
|
||||
|
||||
for i = 1, #arg do
|
||||
multiBuffer(3 + i, arg[i])
|
||||
end
|
||||
multiBuffer(3, 0x70 + #arg)
|
||||
|
||||
|
||||
if (DEBUG_ON > 1) then
|
||||
local str = ""
|
||||
for i = 1, #arg do
|
||||
str = str .. string.format("%02X ", arg[i])
|
||||
end
|
||||
LOG_write("DSM_SEND: [%s]\n", str)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------------------------
|
||||
local function DSM_StartConnection()
|
||||
if (DEBUG_ON) then Log.LOG_write("DSM_StartConnection()\n") end
|
||||
|
||||
--Set protocol to talk to
|
||||
multiBuffer( 0, string.byte('D') )
|
||||
--test if value has been written
|
||||
if multiBuffer( 0 ) ~= string.byte('D') then
|
||||
if (DEBUG_ON) then Log.LOG_write("Not Enouth memory\n") end
|
||||
error("Not enough memory!")
|
||||
return 2
|
||||
end
|
||||
--Init TX buffer
|
||||
multiBuffer( 3, 0x00 )
|
||||
--Init RX buffer
|
||||
multiBuffer( 10, 0x00 )
|
||||
--Init telemetry
|
||||
multiBuffer( 0, string.byte('D') )
|
||||
multiBuffer( 1, string.byte('S') )
|
||||
multiBuffer( 2, string.byte('M') )
|
||||
|
||||
return 0
|
||||
end
|
||||
|
||||
local function DSM_ReleaseConnection()
|
||||
if (DEBUG_ON) then Log.LOG_write("DSM_ReleaseConnection()\n") end
|
||||
multiBuffer(0, 0)
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------------------------------
|
||||
-- REEQUEST Messages to RX
|
||||
|
||||
local function DSM_sendHeartbeat()
|
||||
-- keep connection open
|
||||
if (DEBUG_ON) then Log.LOG_write("SEND DSM_sendHeartbeat()\n") end
|
||||
DSM_send(0x00, 0x04, 0x00, 0x00)
|
||||
end
|
||||
|
||||
local function DSM_getRxVerson()
|
||||
local TX_CAP=0x14 -- Capabilities??
|
||||
local TX_MAX_CH = modelLib.TX_CHANNELS - 6 --number of channels after 6 (6Ch=0, 10ch=4, etc)
|
||||
|
||||
if (DEBUG_ON) then Log.LOG_write("SEND DSM_getRxVersion(Ch:0x%X,Cap:0x%X)\n",TX_MAX_CH,TX_CAP) end
|
||||
DSM_send(0x11, 0x06, TX_MAX_CH, TX_CAP, 0x00, 0x00)
|
||||
end
|
||||
|
||||
local function DSM_getMainMenu()
|
||||
local TX_CAP=0x14 -- Capabilities??
|
||||
local TX_MAX_CH = modelLib.TX_CHANNELS - 6 --number of channels after 6 (6Ch=0, 10ch=4, etc)
|
||||
|
||||
if (DEBUG_ON) then Log.LOG_write("SEND DSM_getMainMenu(Ch:0x%X,Cap:0x%X) -- TX_Channels=%d\n",TX_MAX_CH,TX_CAP,TX_MAX_CH+6) end
|
||||
DSM_send(0x12, 0x06, TX_MAX_CH, TX_CAP, 0x00, 0x00) -- first menu only
|
||||
end
|
||||
|
||||
local function DSM_getMenu(menuId, latSelLine)
|
||||
if (DEBUG_ON) then Log.LOG_write("SEND DSM_getMenu(MenuId=0x%X LastSelectedLine=%s)\n", menuId, latSelLine) end
|
||||
DSM_send(0x16, 0x06, int16_MSB(menuId), int16_LSB(menuId), 0x00, latSelLine)
|
||||
end
|
||||
|
||||
local function DSM_getFirstMenuLine(menuId)
|
||||
if (DEBUG_ON) then Log.LOG_write("SEND DSM_getFirstMenuLine(MenuId=0x%X)\n", menuId) end
|
||||
DSM_send(0x13, 0x04, int16_MSB(menuId), int16_LSB(menuId)) -- line 0
|
||||
end
|
||||
|
||||
local function DSM_getNextMenuLine(menuId, curLine)
|
||||
if (DEBUG_ON) then Log.LOG_write("SEND DSM_getNextLine(MenuId=0x%X,LastLine=%s)\n", menuId, curLine) end
|
||||
DSM_send(0x14, 0x06, int16_MSB(menuId), int16_LSB(menuId), 0x00, curLine) -- line X
|
||||
end
|
||||
|
||||
local function DSM_getNextMenuValue(menuId, valId, text)
|
||||
if (DEBUG_ON) then Log.LOG_write("SEND DSM_getNextMenuValue(MenuId=0x%X, LastValueId=0x%X) Extra: Text=\"%s\"\n", menuId, valId,
|
||||
text)
|
||||
end
|
||||
DSM_send(0x15, 0x06, int16_MSB(menuId), int16_LSB(menuId), int16_MSB(valId), int16_LSB(valId)) -- line X
|
||||
end
|
||||
|
||||
local function DSM_updateMenuValue(valId, val, text, line)
|
||||
local value = sInt16ToDsm(val)
|
||||
if (DEBUG_ON) then Log.LOG_write("SEND DSM_updateValue(ValueId=0x%X,val=%d) Extra: Text=\"%s\" Value=%s\n", valId, val, text, menuLib.lineValue2String(line)) end
|
||||
DSM_send(0x18, 0x06, int16_MSB(valId), int16_LSB(valId), int16_MSB(value), int16_LSB(value)) -- send current value
|
||||
end
|
||||
|
||||
local function DSM_validateMenuValue(valId, text, line)
|
||||
if (DEBUG_ON) then Log.LOG_write("SEND DSM_validateValue(ValueId=0x%X) Extra: Text=\"%s\" Value=%s\n", valId, text, menuLib.lineValue2String(line)) end
|
||||
DSM_send(0x19, 0x04, int16_MSB(valId), int16_LSB(valId))
|
||||
end
|
||||
|
||||
local function DSM_editingValue(lineNum, text, line)
|
||||
if (DEBUG_ON) then Log.LOG_write("SEND DSM_editingValue(lineNo=0x%X) Extra: Text=\"%s\" Val=%s\n", lineNum, text, menuLib.lineValue2String(line)) end
|
||||
DSM_send(0x1A, 0x04, int16_MSB(lineNum), int16_LSB(lineNum))
|
||||
end
|
||||
|
||||
local function DSM_editingValueEnd(lineNum, text, line)
|
||||
if (DEBUG_ON) then Log.LOG_write("SEND DSM_editingValueEnd(lineNo=0x%X) Extra: Text=\"%s\" Value=%s\n", lineNum, text, menuLib.lineValue2String(line)) end
|
||||
DSM_send(0x1B, 0x04, int16_MSB(lineNum), int16_LSB(lineNum))
|
||||
end
|
||||
|
||||
-- Send the functionality of the RX channel Port (channel)
|
||||
local function DSM_sendTxChInfo_20(portNo)
|
||||
local b1,b2 = MODEL.DSM_ChannelInfo[portNo][0] or 0, MODEL.DSM_ChannelInfo[portNo][1] or 0
|
||||
|
||||
if (DEBUG_ON) then Log.LOG_write("CALL DSM_TxChInfo(#%d DATA= %02X %02X %02X %02X) %s\n", portNo,
|
||||
portNo, portNo, b1, b2, modelLib.channelType2String(b1,b2)) -- DATA part
|
||||
end
|
||||
DSM_send(0x20, 0x06, portNo, portNo, b1, b2)
|
||||
end
|
||||
|
||||
local function DSM_sendTxSubtrim_21(portNo)
|
||||
local usage = MODEL.DSM_ChannelInfo[portNo][1] or 0
|
||||
local leftTravel = math.abs(math.floor(MODEL.modelOutputChannel[portNo].min/10))
|
||||
local rightTravel = math.abs(math.floor(MODEL.modelOutputChannel[portNo].max/10))
|
||||
local subTrim = math.floor(MODEL.modelOutputChannel[portNo].offset/10)
|
||||
|
||||
-- Center at 100%: 142-1906 (0 8E 07 72)
|
||||
local left = 142
|
||||
local right = 1906
|
||||
|
||||
if (bit32.band(usage,CH_TYPE.THR)>0) then
|
||||
left = 0
|
||||
right = 2047
|
||||
end
|
||||
|
||||
left = math.floor (left - (leftTravel -100) *8.8 + subTrim*2)
|
||||
right = math.floor (right + (rightTravel -100) *8.8 + subTrim*2)
|
||||
|
||||
if (left<0) then left=0 end
|
||||
if (right>2027) then right=2047 end
|
||||
|
||||
local b1,b2,b3,b4 = int16_MSB(left), int16_LSB(left), int16_MSB(right), int16_LSB(right)
|
||||
|
||||
if (DEBUG_ON) then Log.LOG_write("CALL DSM_TxSubtrim(#%d DATA=%02X %02X %02X %02X) Range(%d - %d) ER L/R:(%d - %d)x8 ST:(%d)x2\n", portNo,
|
||||
b1,b2,b3,b4, left, right, leftTravel-100, rightTravel-100, subTrim) -- DATA part
|
||||
end
|
||||
DSM_send(0x21, 0x06, b1,b2,b3,b4) -- Port is not send anywhere, since the previous 0x20 type message have it.
|
||||
end
|
||||
|
||||
local function DSM_sendTxServoTravel_23(portNo)
|
||||
local leftTravel = math.abs(math.floor(MODEL.modelOutputChannel[portNo].min/10))
|
||||
local rightTravel = math.abs(math.floor(MODEL.modelOutputChannel[portNo].max/10))
|
||||
local debugInfo = string.format("Travel L/R (%d - %d)",leftTravel,rightTravel)
|
||||
|
||||
if (DEBUG_ON) then Log.LOG_write("CALL DSM_TxServoTravel(#%d DATA= %02X %02X %02X %02X) %s\n", portNo,
|
||||
0x00, leftTravel, 0x00, rightTravel, debugInfo) -- DATA part
|
||||
end
|
||||
DSM_send(0x23, 0x06, 0x00, leftTravel, 0x00, rightTravel)
|
||||
end
|
||||
|
||||
local function DSM_sentTxInfo(menuId,portNo)
|
||||
-- TxInfo_Type=0 : AR636B Main Menu (Send port/Channel info + SubTrim + Travel)
|
||||
-- TxInfo_Type=1 : AR630-637 Famly Main Menu (Only Send Port/Channel usage Msg 0x20)
|
||||
-- TxInfo_Type=1F : AR630-637 Initial Setup/Relearn Servo Settings (Send port/Channel info + SubTrim + Travel +0x24/Unknown)
|
||||
|
||||
if (TxInfo_Step == 0) then
|
||||
-- AR630 family: Both TxInfo_Type (ManinMenu=0x1, Other First Time Configuration = 0x1F)
|
||||
DSM_sendTxChInfo_20(portNo)
|
||||
|
||||
if (TxInfo_Type == 0x1F) then
|
||||
TxInfo_Step = 1
|
||||
end
|
||||
if (TxInfo_Type == 0x00) then
|
||||
TxInfo_Step = 2
|
||||
end
|
||||
elseif (TxInfo_Step == 1) then
|
||||
DSM_sendTxServoTravel_23(portNo)
|
||||
TxInfo_Step = 2
|
||||
elseif (TxInfo_Step == 2) then
|
||||
DSM_sendTxSubtrim_21(portNo)
|
||||
|
||||
if (TxInfo_Type == 0x00) then
|
||||
TxInfo_Step = 5 -- End Step
|
||||
else
|
||||
TxInfo_Step = 3
|
||||
end
|
||||
elseif (TxInfo_Step == 3) then
|
||||
-- 24,6: 0 83 5A B5
|
||||
if (DEBUG_ON) then Log.LOG_write("CALL DSM_TxInfo24(#%d DATA=0x24 0x06 %02X %02X %02X %02X)\n", portNo,
|
||||
0x00, 0x83, 0x5A, 0xB5) -- DATA part
|
||||
end
|
||||
DSM_send(0x24, 0x06, 0x00, 0x83, 0x5A, 0xB5) -- Still Uknown
|
||||
TxInfo_Step = 4
|
||||
|
||||
elseif (TxInfo_Step == 4) then
|
||||
-- 24,6: 6 80 25 4B
|
||||
if (DEBUG_ON) then Log.LOG_write("CALL DSM_TxInfo24(#%d DATA=0x24 0x06 %02X %02X %02X %02X)\n", portNo,
|
||||
0x06, 0x80, 0x25, 0x4B) -- DATA part
|
||||
end
|
||||
DSM_send(0x24, 0x06, 0x06, 0x80, 0x25, 0x4B) -- Still Uknown
|
||||
TxInfo_Step = 5
|
||||
elseif (TxInfo_Step == 5) then
|
||||
-- 22,4: 0 0
|
||||
if (DEBUG_ON) then Log.LOG_write("CALL DSM_TxInfo_End(#%d)\n", portNo)
|
||||
end
|
||||
DSM_send(0x22, 0x04, 0x00, 0x00)
|
||||
TxInfo_Step = 0
|
||||
end
|
||||
|
||||
if (TxInfo_Step > 0) then
|
||||
DSM_Context.SendDataToRX = 1 -- keep Transmitig
|
||||
end
|
||||
end
|
||||
|
||||
-----------------------------------------------------------------------------------------------------------
|
||||
|
||||
local function DSM_sendRequest()
|
||||
-- Send the proper Request message depending on the Phase
|
||||
|
||||
local ctx = DSM_Context
|
||||
if (DEBUG_ON) then Log.LOG_write("%3.3f %s: ", menuLib.getElapsedTime(), menuLib.phase2String(ctx.Phase)) end
|
||||
|
||||
if ctx.Phase == PHASE.RX_VERSION then -- request RX version
|
||||
DSM_getRxVerson()
|
||||
|
||||
elseif ctx.Phase == PHASE.WAIT_CMD then -- keep connection open
|
||||
DSM_sendHeartbeat()
|
||||
|
||||
elseif ctx.Phase == PHASE.MENU_TITLE then -- request menu title
|
||||
if ctx.Menu.MenuId == 0 then -- First time loading a menu ?
|
||||
DSM_getMainMenu()
|
||||
else
|
||||
DSM_getMenu(ctx.Menu.MenuId, ctx.SelLine)
|
||||
|
||||
if (ctx.Menu.MenuId == 0x0001) then -- Executed the Reset Menu??
|
||||
if (DEBUG_ON) then Log.LOG_write("RX Reset!!!\n") end
|
||||
-- Start again retriving RX info
|
||||
ctx.Menu.MenuId = 0
|
||||
ctx.isReset = true
|
||||
ctx.Phase = PHASE.RX_VERSION
|
||||
end
|
||||
end
|
||||
|
||||
elseif ctx.Phase == PHASE.MENU_REQ_TX_INFO then
|
||||
DSM_sentTxInfo(ctx.Menu.MenuId, ctx.CurLine)
|
||||
|
||||
elseif ctx.Phase == PHASE.MENU_LINES then -- request next menu lines
|
||||
if ctx.CurLine == -1 then -- No previous menu line loaded ?
|
||||
DSM_getFirstMenuLine(ctx.Menu.MenuId)
|
||||
else
|
||||
DSM_getNextMenuLine(ctx.Menu.MenuId, ctx.CurLine)
|
||||
end
|
||||
|
||||
elseif ctx.Phase == PHASE.MENU_VALUES then -- request menu values
|
||||
local line = ctx.MenuLines[ctx.CurLine]
|
||||
DSM_getNextMenuValue(ctx.Menu.MenuId, line.ValId, line.Text)
|
||||
|
||||
elseif ctx.Phase == PHASE.VALUE_CHANGING then -- send value
|
||||
local line = ctx.MenuLines[ctx.SelLine] -- Updated Value of SELECTED line
|
||||
|
||||
if (Change_Step==0) then
|
||||
DSM_updateMenuValue(line.ValId, line.Val, line.Text, line)
|
||||
|
||||
if line.Type == menuLib.LINE_TYPE.LIST_MENU then -- Validation on every Step??
|
||||
Change_Step=1; ctx.SendDataToRX=1 -- Send inmediatly after
|
||||
else
|
||||
ctx.Phase = PHASE.VALUE_CHANGING_WAIT
|
||||
end
|
||||
else
|
||||
DSM_validateMenuValue(line.ValId, line.Text, line)
|
||||
Change_Step=0
|
||||
ctx.Phase = PHASE.VALUE_CHANGING_WAIT
|
||||
end
|
||||
|
||||
elseif ctx.Phase == PHASE.VALUE_CHANGING_WAIT then
|
||||
local line = ctx.MenuLines[ctx.SelLine]
|
||||
DSM_editingValue(line.lineNum, line.Text, line)
|
||||
elseif ctx.Phase == PHASE.VALUE_CHANGE_END then -- send value
|
||||
local line = ctx.MenuLines[ctx.SelLine] -- Update Value of SELECTED line
|
||||
|
||||
if (Change_Step==0) then
|
||||
DSM_updateMenuValue(line.ValId, line.Val, line.Text, line)
|
||||
Change_Step=1; ctx.SendDataToRX=1 -- Send inmediatly after
|
||||
elseif (Change_Step==1) then
|
||||
DSM_validateMenuValue(line.ValId, line.Text, line)
|
||||
Change_Step=2; ctx.SendDataToRX=1 -- Send inmediatly after
|
||||
else
|
||||
DSM_editingValueEnd(line.lineNum, line.Text, line)
|
||||
Change_Step=0
|
||||
ctx.Phase = PHASE.WAIT_CMD
|
||||
end
|
||||
elseif ctx.Phase == PHASE.EXIT then
|
||||
if (DEBUG_ON) then Log.LOG_write("CALL DSM_TX_Exit()\n") end
|
||||
DSM_send(0x1F, 0x02, 0xFF, 0xFF) -- 0xAA
|
||||
end
|
||||
end
|
||||
|
||||
-----------------------------------------------------------------------------------------------------------
|
||||
-- Parsing Responses
|
||||
|
||||
local function DSM_parseRxVersion()
|
||||
--ex: 0x09 0x01 0x00 0x15 0x02 0x22 0x01 0x00 0x14 v2.22.1 00 14?? 8ch SAFE
|
||||
-- 0x09 0x01 0x00 0x18 0x05 0x06 0x34 0x00 0x12 v5.6.52 00 12??? 6ch FC6250
|
||||
local rxId = multiBuffer(13)
|
||||
DSM_Context.RX.Id = rxId
|
||||
DSM_Context.RX.Name = menuLib.Get_RxName(rxId)
|
||||
DSM_Context.RX.Version = multiBuffer(14) .. "." .. multiBuffer(15) .. "." .. multiBuffer(16)
|
||||
if (DEBUG_ON) then Log.LOG_write("RESPONSE Receiver=%s Version %s Cap:0x%02X\n",
|
||||
DSM_Context.RX.Name, DSM_Context.RX.Version, multiBuffer(18)) end
|
||||
end
|
||||
|
||||
local function DSM_parseMenu()
|
||||
--ex: 0x09 0x02 0x4F 0x10 0xA5 0x00 0x00 0x00 0x50 0x10 0x10 0x10 0x00 0x00 0x00 0x00
|
||||
-- MenuID TextID PrevID NextID BackID
|
||||
local ctx = DSM_Context
|
||||
local menu = ctx.Menu
|
||||
menu.MenuId = Dsm_to_Int16(multiBuffer(12), multiBuffer(13))
|
||||
menu.TextId = Dsm_to_Int16(multiBuffer(14), multiBuffer(15))
|
||||
menu.Text = menuLib.Get_Text(menu.TextId)
|
||||
menu.PrevId = Dsm_to_Int16(multiBuffer(16), multiBuffer(17))
|
||||
menu.NextId = Dsm_to_Int16(multiBuffer(18), multiBuffer(19))
|
||||
menu.BackId = Dsm_to_Int16(multiBuffer(20), multiBuffer(21))
|
||||
for i = 0, MAX_MENU_LINES do -- clear menu
|
||||
ctx.MenuLines[i] = { MenuId = 0, lineNum = 0, Type = 0, Text = "", TextId = 0, ValId = 0, Min=0, Max=0, Def=0, Val=nil }
|
||||
end
|
||||
ctx.CurLine = -1
|
||||
|
||||
menuLib.MenuPostProcessing(menu)
|
||||
|
||||
if (DEBUG_ON) then Log.LOG_write("RESPONSE Menu: %s\n", menuLib.menu2String(menu)) end
|
||||
return menu
|
||||
end
|
||||
|
||||
|
||||
local function DSM_parseMenuLine()
|
||||
--ex: 0x09 0x03 0x00 0x10 0x00 0x1C 0xF9 0x00 0x10 0x10 0x00 0x00 0x00 0x00 0x03 0x00
|
||||
--ex: 0x09 0x03 0x61 0x10 0x00 0x6C 0x50 0x00 0x00 0x10 0x36 0x00 0x49 0x00 0x36 0x00
|
||||
--ex: 0x09 0x03 0x65 0x10 0x00 0x0C 0x51 0x00 0x00 0x10 0x00 0x00 0xF4 0x00 0x2E 0x00
|
||||
-- MenuLSB MenuMSB line Type TextID NextLSB NextMSB Val_Min Val_Max Val_Def
|
||||
|
||||
local ctx = DSM_Context
|
||||
local i = multiBuffer(14)
|
||||
local type = multiBuffer(15)
|
||||
local line = ctx.MenuLines[i]
|
||||
|
||||
-- are we trying to override existing line
|
||||
if (line.Type > 0 and type == 0) then
|
||||
if (DEBUG_ON) then Log.LOG_write("RESPONSE MenuLine: ERROR. Trying to ZERO Override: %s\n", menuLib.menuLine2String(line)) end
|
||||
return ctx.MenuLines[ctx.CurLine]
|
||||
end
|
||||
|
||||
ctx.CurLine = i
|
||||
|
||||
line.lineNum = i
|
||||
line.MenuId = Dsm_to_Int16(multiBuffer(12), multiBuffer(13))
|
||||
line.Type = type
|
||||
line.TextId = Dsm_to_Int16(multiBuffer(16), multiBuffer(17))
|
||||
line.Text = nil -- Fill at Post processing
|
||||
line.ValId = Dsm_to_Int16(multiBuffer(18), multiBuffer(19))
|
||||
|
||||
-- Singed int values
|
||||
line.Min = Dsm_to_SInt16(multiBuffer(20), multiBuffer(21))
|
||||
line.Max = Dsm_to_SInt16(multiBuffer(22), multiBuffer(23))
|
||||
line.Def = Dsm_to_SInt16(multiBuffer(24), multiBuffer(25))
|
||||
|
||||
line.Val=nil
|
||||
|
||||
menuLib.MenuLinePostProcessing(line)
|
||||
|
||||
if (DEBUG_ON) then Log.LOG_write("RESPONSE MenuLine: %s\n", menuLib.menuLine2String(line)) end
|
||||
|
||||
if (line.MenuId~=ctx.Menu.MenuId) then
|
||||
-- Going Back too fast: Stil receiving lines from previous menu
|
||||
ctx.Menu.MenuId = line.MenuId
|
||||
Log.LOG_write("WARNING: Overriding current Menu from Line\n")
|
||||
end
|
||||
|
||||
return line
|
||||
end
|
||||
|
||||
local function DSM_parseMenuValue()
|
||||
--ex: 0x09 0x04 0x53 0x10 0x00 0x10 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
|
||||
--ex: 0x09 0x04 0x61 0x10 0x02 0x10 0x01 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
|
||||
-- MenuLSB MenuMSB ValLSB ValMSB V_LSB V_MSB
|
||||
|
||||
-- Identify the line and update the value
|
||||
local ctx = DSM_Context
|
||||
local menuId = Dsm_to_Int16(multiBuffer(12), multiBuffer(13))
|
||||
local valId = Dsm_to_Int16(multiBuffer(14), multiBuffer(15))
|
||||
local value = Dsm_to_SInt16(multiBuffer(16), multiBuffer(17)) --Signed int
|
||||
|
||||
local updatedLine = nil
|
||||
for i = 0, MAX_MENU_LINES do -- Find the menu line for this value
|
||||
local line = ctx.MenuLines[i]
|
||||
if line ~= nil and line.Type ~= 0 then
|
||||
if line.Type ~= LINE_TYPE.MENU and line.ValId == valId then -- identifier of ValueId stored in the line
|
||||
line.Val = value
|
||||
ctx.CurLine = i
|
||||
updatedLine = line
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if (updatedLine == nil) then
|
||||
if (DEBUG_ON) then Log.LOG_write("RESPONSE MenuValue: ERROR, Cant find Menu Line with MenuId=%X, ValID=%X to update\n", menuId, valId) end
|
||||
else
|
||||
if (DEBUG_ON) then Log.LOG_write("RESPONSE MenuValue: UPDATED: %s\n", menuLib.menuLine2String(updatedLine))
|
||||
end
|
||||
end
|
||||
return updatedLine ~= nil
|
||||
end
|
||||
|
||||
local function DSM_parseReqTxInfo()
|
||||
local portNo = multiBuffer(12)
|
||||
TxInfo_Type = multiBuffer(13)
|
||||
if (DEBUG_ON) then Log.LOG_write("RESPONSE ReqTXChannelInfo(#%d %s InfoType=0x%0X)\n",
|
||||
portNo, MODEL.PORT_TEXT[portNo], TxInfo_Type) end
|
||||
|
||||
TxInfo_Step = 0
|
||||
|
||||
return portNo
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
local function DSM_processResponse()
|
||||
local ctx = DSM_Context
|
||||
local cmd = multiBuffer(11) -- Response Command
|
||||
|
||||
if (DEBUG_ON > 1) then Log.LOG_write("%s: RESPONSE %s \n", menuLib.phase2String(ctx.Phase), multiBuffer2String()) end
|
||||
if (DEBUG_ON and cmd > 0x00) then Log.LOG_write("%3.3f %s: ", menuLib.getElapsedTime(), menuLib.phase2String(ctx.Phase)) end
|
||||
|
||||
if cmd == 0x01 then -- read version
|
||||
DSM_parseRxVersion()
|
||||
--Lib.Init_Text(DSM_Context.RX.Id)
|
||||
ctx.isReset = false -- no longer resetting
|
||||
ctx.Phase = PHASE.MENU_TITLE
|
||||
ctx.Menu.MenuId = 0
|
||||
|
||||
elseif cmd == 0x02 then -- read menu title
|
||||
local menu = DSM_parseMenu()
|
||||
|
||||
-- Update Selected Line navigation
|
||||
if menu.NextId ~= 0 then
|
||||
ctx.SelLine = NEXT_BUTTON -- highlight Next
|
||||
else
|
||||
ctx.SelLine = BACK_BUTTON -- highlight Back
|
||||
end
|
||||
|
||||
if (ctx.Menu.MenuId == 0x0001) then -- Still in RESETTING MENU???
|
||||
-- Star from Start
|
||||
if (DEBUG_ON) then Log.LOG_write("RX Reset: Still not done, restart again!!!\n") end
|
||||
ctx.Menu.MenuId = 0
|
||||
ctx.Phase = PHASE.RX_VERSION
|
||||
else
|
||||
ctx.Phase = PHASE.MENU_LINES
|
||||
end
|
||||
|
||||
|
||||
elseif cmd == 0x03 then -- menu lines
|
||||
local line = DSM_parseMenuLine()
|
||||
|
||||
-- Update Selected line navigation
|
||||
if (ctx.SelLine == BACK_BUTTON or ctx.SelLine == NEXT_BUTTON or ctx.SelLine == PREV_BUTTON)
|
||||
and menuLib.isSelectableLine(line) then -- Auto select the current line
|
||||
ctx.SelLine = line.lineNum
|
||||
end
|
||||
|
||||
ctx.Phase = PHASE.MENU_LINES
|
||||
|
||||
elseif cmd == 0x04 then -- read menu values
|
||||
if DSM_parseMenuValue() then
|
||||
ctx.Phase = PHASE.MENU_VALUES
|
||||
else
|
||||
ctx.Phase = PHASE.WAIT_CMD
|
||||
end
|
||||
|
||||
elseif cmd == 0x05 then -- Request TX Info
|
||||
local portNo = DSM_parseReqTxInfo()
|
||||
ctx.CurLine = portNo
|
||||
ctx.Phase = PHASE.MENU_REQ_TX_INFO
|
||||
|
||||
elseif cmd == 0xA7 then -- answer to EXIT command
|
||||
if (DEBUG_ON) then Log.LOG_write("RESPONSE RX Exit\n") end
|
||||
if (ctx.Phase==PHASE.EXIT) then -- Expected RX Exit
|
||||
ctx.Phase = PHASE.EXIT_DONE
|
||||
else -- UnExpected RX Exit
|
||||
DSM_ReleaseConnection()
|
||||
error("RX Connection Drop")
|
||||
end
|
||||
|
||||
elseif cmd == 0x00 then -- NULL response (or RX heartbeat)
|
||||
-- 09 00 01 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
-- 09 00 7E 00 20 9E 28 00 20 9E 28 00 20 8D 7E : After TX Heartbeat one of this (FC6250)
|
||||
-- 09 00 18 00 20 08 00 00 00 08 00 00 00 98 AE AR8360T
|
||||
if (DEBUG_ON) then Log.LOG_write("%3.3f %s: RESPONSE RX Heartbeat --Context: 0x%02X\n",
|
||||
menuLib.getElapsedTime(), menuLib.phase2String(ctx.Phase), multiBuffer(12)) end
|
||||
else
|
||||
if (DEBUG_ON) then Log.LOG_write("RESPONSE Unknown Command (0x%X) DATA=%s\n", cmd, multiBuffer2String()) end
|
||||
end
|
||||
|
||||
return cmd
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
local function DSM_Send_Receive()
|
||||
local ctx = DSM_Context
|
||||
|
||||
-- Receive part: Process incoming messages if there is nothing to send
|
||||
if ctx.SendDataToRX == 0 and multiBuffer(10) == 0x09 then
|
||||
local cmd = DSM_processResponse()
|
||||
|
||||
multiBuffer(10, 0x00) -- Clear Response Buffer to know that we are done with the response
|
||||
RXInactivityTime = getTime() + SEND_TIMEOUT*4 -- Reset RX Inactivity timeout
|
||||
|
||||
if (cmd > 0x00) then -- RX HeartBeat ??
|
||||
-- Only change to SEND mode if we received a valid response (Ignore heartbeat)
|
||||
ctx.SendDataToRX = 1
|
||||
ctx.Refresh_Display = true
|
||||
end
|
||||
else
|
||||
if (getTime() > RXInactivityTime and ctx.Phase ~= PHASE.RX_VERSION and ctx.Phase ~= PHASE.EXIT_DONE) then
|
||||
if (ctx.isEditing()) then -- If Editing, Extend Timeout
|
||||
RXInactivityTime = getTime() + SEND_TIMEOUT*4
|
||||
else
|
||||
if (DEBUG_ON) then Log.LOG_write("%3.3f %s: RX INACTIVITY TIMEOUT\n", menuLib.getElapsedTime(), menuLib.phase2String(ctx.Phase)) end
|
||||
DSM_ReleaseConnection()
|
||||
error("RX Disconnected")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-----TX Part --------------------------------------
|
||||
if ctx.SendDataToRX == 1 then -- Need to send a request
|
||||
ctx.SendDataToRX = 0
|
||||
DSM_sendRequest()
|
||||
TXInactivityTime = getTime() + SEND_TIMEOUT -- Reset Inactivity timeout
|
||||
else
|
||||
-- Check if enouth time has passed from last transmit/receive activity
|
||||
if getTime() > TXInactivityTime then
|
||||
ctx.SendDataToRX = 1 -- Switch to Send mode to send heartbeat
|
||||
ctx.Refresh_Display = true
|
||||
|
||||
-- Only change to WAIT_CMD if we are NOT wating for RX version
|
||||
if ctx.Phase ~= PHASE.RX_VERSION then
|
||||
-- Phase = If IsEditing then VALUE_CHANGING_WAIT else WAIT_CMD
|
||||
ctx.Phase = (ctx.isEditing() and PHASE.VALUE_CHANGING_WAIT) or PHASE.WAIT_CMD
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Init
|
||||
local function DSM_Init(toolName)
|
||||
local dateTime = getDateTime()
|
||||
local dateStr = dateTime.year.."-"..dateTime.mon.."-"..dateTime.day.." "..dateTime.hour..":"..dateTime.min
|
||||
|
||||
local ver, radio, maj, minor, rev, osname = getVersion()
|
||||
|
||||
if (osname==nil) then osname = "OpenTX" end -- OTX 2.3.14 and below returns nil
|
||||
|
||||
IS_EDGETX = string.sub(osname,1,1) == 'E'
|
||||
|
||||
if (DEBUG_ON) then
|
||||
Log.LOG_write("---------------DSM New Session %s ----------------\n", toolName, dateStr)
|
||||
Log.LOG_write("Radio Info: %s\n", radio .. " " .. (osname or "OpenTx") .. " " .. ver)
|
||||
Log.LOG_write("Date : %s\n", dateStr)
|
||||
Log.LOG_write("DsmLib Version : %s\n", LIB_VERSION)
|
||||
end
|
||||
end
|
||||
|
||||
local function DSM_Init_Text_Exceptions()
|
||||
-- Apply special restrictions to some Values
|
||||
|
||||
local function getTxChText(ch)
|
||||
return " ("..(MODEL.TX_CH_TEXT[ch] or "--")..")"
|
||||
end
|
||||
|
||||
local List_Values = menuLib.List_Values
|
||||
local List_Text = menuLib.List_Text
|
||||
local Text = menuLib.Text
|
||||
|
||||
Log.LOG_write("Initializing TEXT Exception\n")
|
||||
|
||||
-- Channel selection for SAFE MODE and GAINS on FC6250HX
|
||||
--List_Text[0x000C] = "Inhibit?" --?
|
||||
for i = 0, 7 do
|
||||
List_Text[0x000D + i] = "Ch"..(i+5) ..getTxChText(i+4)
|
||||
end -- Aux channels (Ch5 and Greater)
|
||||
|
||||
-- Servo Output values..
|
||||
local servoOutputValues = {0x0003,0x002D,0x002E,0x002F} --Inh (GAP), 5.5ms, 11ms, 22ms. Fixing L_m1 with 0..244 range!
|
||||
--List_Text[0x002D] = "5.5ms"
|
||||
--[0x002E] = "11ms"
|
||||
--List_Text[0x002F] = "22ms"
|
||||
|
||||
-- Gain Values
|
||||
local gainValues = {0x0032,0x0033,0x0034} -- 1X, 2X, 4X -- Fixing L_m1 with 0..244 range!
|
||||
--List_Text[0x0032] = "1 X"
|
||||
--[0x0033] = "2 X"
|
||||
-- List_Text[0x0034] = "4 X"
|
||||
|
||||
-- List of Channels for Safe, Gains, Panic, except FC6250HX that uses other range (0x00C..0x015)
|
||||
-- the valid range Starts with GEAR if enabled (Thr,Ail,Ele,Rud are not valid, the RX reject them )
|
||||
-- Valid Values: Inhibit? (GAP), Gear,Aux1..Aux7,X-Plus-1..XPlus-8
|
||||
local channelValues = {0x0035,0x0036,0x0037,0x0038,0x0039,0x003A,0x003B,0x003C,0x003D,0x003E,0x003F,
|
||||
0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047,0x0048,0x0049}
|
||||
|
||||
--List_Text[0x0035] = "Inhibit?"
|
||||
for i = 0, 11 do
|
||||
List_Text[0x0036 + i] = "Ch"..(i+1) .. getTxChText(i)
|
||||
end -- Channels on AR637T
|
||||
|
||||
for i = 1, 8 do -- 41..49
|
||||
List_Text[0x0041 + i] = "Ch"..(i+12)
|
||||
end
|
||||
|
||||
-- Flight mode channel selection
|
||||
--Text[0x0078] = "FM Channel"
|
||||
List_Values[0x0078]=channelValues
|
||||
|
||||
-- Gain channel selection
|
||||
--Text[0x0089] = "Gain Channel"
|
||||
List_Values[0x0089]=channelValues
|
||||
|
||||
-- Gain Sensitivity selection
|
||||
--Text[0x008A] = "Gain Sensitivity/r";
|
||||
List_Values[0x008A]=gainValues -- Right Alight, (L_M1 was wide open range 0->244)
|
||||
|
||||
-- Safe mode options, Ihnibit + this values
|
||||
local safeModeOptions = {0x0003,0x00B0,0x00B1} -- inh (gap), "Self-Level/Angle Dem, Envelope
|
||||
--List_Text[0x00B0] = "Self-Level/Angle Dem"
|
||||
--List_Text[0x00B1] = "Envelope"
|
||||
|
||||
--Text[0x00D2] = "Panic Channel"
|
||||
List_Values[0x00D2]=channelValues
|
||||
|
||||
--Inh, Self-Level/Angle Dem, Envelope -- (L_M was wide open range 0->244)
|
||||
--Text[0x01F8] = "Safe Mode";
|
||||
List_Values[0x01F8]=safeModeOptions
|
||||
end
|
||||
|
||||
-- Initial Setup
|
||||
local function FP_Init(toolname)
|
||||
DSM_Context.Phase = PHASE.INIT
|
||||
|
||||
DSM_Init(toolname)
|
||||
menuLib.clearAllText()
|
||||
end
|
||||
|
||||
local initStep=0
|
||||
local FileState = {}
|
||||
|
||||
local function Message_Init()
|
||||
lcd.clear()
|
||||
if (initStep == 0) then
|
||||
if (IS_EDGETX) then
|
||||
-- Load all messages at once
|
||||
menuLib.LoadTextFromFile(MSG_FILE,13)
|
||||
initStep=1
|
||||
|
||||
else
|
||||
-- load messages incrementally to avoid "CPU Limit"
|
||||
lcd.drawText(30, 50, "Loading Msg file: "..(FileState.lineNo or 0))
|
||||
if (menuLib.INC_LoadTextFromFile(MSG_FILE, FileState)==1) then
|
||||
initStep=1
|
||||
end
|
||||
end
|
||||
elseif (initStep == 1) then
|
||||
DSM_Init_Text_Exceptions()
|
||||
|
||||
DSM_Context.Phase = PHASE.RX_VERSION
|
||||
DSM_StartConnection()
|
||||
end
|
||||
end
|
||||
|
||||
local function FP_Run()
|
||||
if (DSM_Context.Phase==PHASE.INIT) then
|
||||
Message_Init()
|
||||
return 0
|
||||
end
|
||||
|
||||
return DSM_Send_Receive()
|
||||
end
|
||||
|
||||
local function FP_Done()
|
||||
local ctx = menuLib.DSM_Context
|
||||
ctx.Phase = PHASE.EXIT_DONE
|
||||
DSM_ReleaseConnection()
|
||||
end
|
||||
|
||||
return { init=FP_Init, run=FP_Run, done=FP_Done }
|
@ -1,33 +0,0 @@
|
||||
local LogLib = { }
|
||||
|
||||
local LOG_FILE = "/LOGS/dsm_log.txt"
|
||||
local logFile = nil
|
||||
local logCount=0
|
||||
|
||||
function LogLib.LOG_open()
|
||||
logFile = io.open(LOG_FILE, "w") -- Truncate Log File
|
||||
end
|
||||
|
||||
function LogLib.LOG_write(...)
|
||||
if (logFile==nil) then LogLib.LOG_open() end
|
||||
local str = string.format(...)
|
||||
|
||||
if (str==nil) then return end
|
||||
|
||||
io.write(logFile, str)
|
||||
|
||||
str = string.gsub(str,"\n"," ") -- Elimitate return from line, since print will do it
|
||||
print(str)
|
||||
|
||||
if (logCount > 10) then -- Close an re-open the file
|
||||
io.close(logFile)
|
||||
logFile = io.open(LOG_FILE, "a")
|
||||
logCount =0
|
||||
end
|
||||
end
|
||||
|
||||
function LogLib.LOG_close()
|
||||
if (logFile~=nil) then io.close(logFile) end
|
||||
end
|
||||
|
||||
return LogLib
|
@ -1,167 +0,0 @@
|
||||
local MODEL, M_DATA, LOG_write = ...
|
||||
|
||||
--[[
|
||||
local MODEL = {
|
||||
modelName = "", -- The name of the model comming from OTX/ETX
|
||||
hashName = "",
|
||||
modelOutputChannel = {}, -- Output information from OTX/ETX
|
||||
|
||||
TX_CH_TEXT= { [0]=""},
|
||||
PORT_TEXT = { [0]=""},
|
||||
|
||||
DSM_ChannelInfo = {} -- Data Created by DSM Configuration Script
|
||||
}
|
||||
|
||||
-- MENU DATA Management
|
||||
local M_DATA = {} -- Store the variables used in the Menus.
|
||||
|
||||
--]]
|
||||
|
||||
local DATA_PATH = "/MODELS/DSMDATA"
|
||||
local TX_CHANNELS = 12
|
||||
|
||||
local MV_DATA_END = 1040
|
||||
|
||||
|
||||
local function hashName(mName)
|
||||
local c=10000;
|
||||
|
||||
local prefix = string.gsub(mName,"%.","_") -- Change any "." to "_"
|
||||
prefix = string.gsub(prefix,"% ","_") -- Change any space to "_"
|
||||
prefix = string.sub(prefix,1,5) -- Take the first 5 characters
|
||||
|
||||
-- Simple Hash of the Model Name adding each character
|
||||
for i = 1, #mName do
|
||||
local ch = string.byte(mName,i,i)
|
||||
c=c+ch
|
||||
end
|
||||
|
||||
return (prefix .. c) -- Return Prefix + Hash
|
||||
end
|
||||
|
||||
-- Load Menu Data from a file
|
||||
local function ST_LoadFileData()
|
||||
local fname = hashName(MODEL.modelName)..".txt"
|
||||
MODEL.hashName = fname
|
||||
|
||||
-- Clear Menu Data
|
||||
for i = 0, MV_DATA_END do
|
||||
M_DATA[i]=nil
|
||||
end
|
||||
|
||||
print("Loading File:"..fname)
|
||||
|
||||
local dataFile = io.open(DATA_PATH .. "/".. fname, "r") -- read File
|
||||
-- cannot read file???
|
||||
if (dataFile==nil) then return 0 end
|
||||
|
||||
local line = io.read(dataFile, 5000)
|
||||
io.close(dataFile)
|
||||
|
||||
if #line == 0 then return 0 end -- No data??
|
||||
|
||||
-- Process the input, each line is "Var_Id : Value" format
|
||||
-- Store it into MANU_DATA
|
||||
local i=0
|
||||
for k, v in string.gmatch(line, "(%d+):(%d+)") do
|
||||
M_DATA[k+0]=v+0 -- do aritmentic to convert string to number
|
||||
i=i+1
|
||||
end
|
||||
|
||||
-- Return 0 if no lines processed, 1 otherwise
|
||||
if (i > 0) then return 1 else return 0 end
|
||||
end
|
||||
|
||||
local function getModuleChannelOrder(num)
|
||||
--Determine fist 4 channels order
|
||||
local ch_n={}
|
||||
local st_n = {[0]= "R", "E", "T", "A" }
|
||||
local c_ord=num -- ch order
|
||||
if (c_ord == -1) then
|
||||
ch_n[0] = st_n[3]
|
||||
ch_n[1] = st_n[1]
|
||||
ch_n[2] = st_n[2]
|
||||
ch_n[3] = st_n[0]
|
||||
else
|
||||
ch_n[bit32.band(c_ord,3)] = st_n[3]
|
||||
c_ord = math.floor(c_ord/4)
|
||||
ch_n[bit32.band(c_ord,3)] = st_n[1]
|
||||
c_ord = math.floor(c_ord/4)
|
||||
ch_n[bit32.band(c_ord,3)] = st_n[2]
|
||||
c_ord = math.floor(c_ord/4)
|
||||
ch_n[bit32.band(c_ord,3)] = st_n[0]
|
||||
end
|
||||
|
||||
local s = ""
|
||||
for i=0,3 do
|
||||
s=s..ch_n[i]
|
||||
end
|
||||
return s
|
||||
end
|
||||
|
||||
local function ReadTxModelData()
|
||||
local TRANSLATE_AETR_TO_TAER=false
|
||||
local table = model.getInfo() -- Get the model name
|
||||
MODEL.modelName = table.name
|
||||
|
||||
local module = model.getModule(0) -- Internal
|
||||
if (module==nil or module.Type~=6) then module = model.getModule(1) end -- External
|
||||
if (module~=nil) then
|
||||
if (module.Type==6 ) then -- MULTI-MODULE
|
||||
local chOrder = module.channelsOrder
|
||||
local s = getModuleChannelOrder(chOrder)
|
||||
LOG_write("MultiChannel Ch Order: [%s] %s\n",chOrder,s)
|
||||
|
||||
if (s=="AETR") then TRANSLATE_AETR_TO_TAER=true
|
||||
else TRANSLATE_AETR_TO_TAER=false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Read Ch1 to Ch10
|
||||
local i= 0
|
||||
for i = 0, TX_CHANNELS-1 do
|
||||
local ch = model.getOutput(i) -- Zero base
|
||||
if (ch~=nil) then
|
||||
MODEL.modelOutputChannel[i] = ch
|
||||
if (string.len(ch.name)==0) then
|
||||
ch.formatCh = string.format("TX:Ch%i",i+1)
|
||||
else
|
||||
ch.formatCh = string.format("TX:Ch%i/%s",i+1,ch.name or "--")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Translate AETR to TAER
|
||||
|
||||
if (TRANSLATE_AETR_TO_TAER) then
|
||||
LOG_write("Applying AETR -> TAER translation\n")
|
||||
local ail = MODEL.modelOutputChannel[0]
|
||||
local elv = MODEL.modelOutputChannel[1]
|
||||
local thr = MODEL.modelOutputChannel[2]
|
||||
|
||||
MODEL.modelOutputChannel[0] = thr
|
||||
MODEL.modelOutputChannel[1] = ail
|
||||
MODEL.modelOutputChannel[2] = elv
|
||||
end
|
||||
|
||||
-- Create the Port Text to be used
|
||||
LOG_write("Ports/Channels:\n")
|
||||
for i = 0, TX_CHANNELS-1 do
|
||||
local ch = MODEL.modelOutputChannel[i]
|
||||
if (ch~=nil) then
|
||||
MODEL.TX_CH_TEXT[i] = ch.formatCh
|
||||
MODEL.PORT_TEXT[i] = string.format("P%i (%s) ",i+1,MODEL.TX_CH_TEXT[i])
|
||||
LOG_write("Port%d %s [%d,%d] Rev=%d, Off=%d, ppmC=%d, syn=%d\n",i+1,MODEL.TX_CH_TEXT[i],math.floor(ch.min/10),math.floor(ch.max/10), ch.revert, ch.offset, ch.ppmCenter, ch.symetrical)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Main Program
|
||||
|
||||
LOG_write("Reading Model Info\n")
|
||||
ReadTxModelData()
|
||||
local r = ST_LoadFileData()
|
||||
return r
|
||||
|
||||
|
@ -1,282 +0,0 @@
|
||||
local MODEL, M_DATA, LOG_write = ...
|
||||
|
||||
--[[
|
||||
local MODEL = {
|
||||
modelName = "", -- The name of the model comming from OTX/ETX
|
||||
hashName = "",
|
||||
modelOutputChannel = {}, -- Output information from OTX/ETX
|
||||
|
||||
TX_CH_TEXT= { [0]=""},
|
||||
PORT_TEXT = { [0]=""},
|
||||
|
||||
DSM_ChannelInfo = {} -- Data Created by DSM Configuration Script
|
||||
}
|
||||
|
||||
-- MENU DATA Management
|
||||
local M_DATA = {} -- Store the variables used in the Menus.
|
||||
|
||||
--]]
|
||||
|
||||
|
||||
local TX_CHANNELS = 12
|
||||
|
||||
local AT_PLANE = 0
|
||||
|
||||
local aircraft_type_text = {[0]="Plane","Heli","Glider","Drone"}
|
||||
|
||||
--[[
|
||||
local WT_A1 = 0
|
||||
local WT_A2 = 1
|
||||
local WT_FLPR = 2
|
||||
local WT_A1_F1 = 3
|
||||
local WT_A2_F1 = 4
|
||||
local WT_A2_F2 = 5
|
||||
--]]
|
||||
local WT_ELEVON_A = 6
|
||||
local WT_ELEVON_B = 7
|
||||
|
||||
local wing_type_text = {[0]="Normal","Dual Ail","Flapperon", "Ail + Flp","Dual Ail + Flp","Dual Ail/Flp","Elevon A","Elevon B"}
|
||||
|
||||
--[[
|
||||
local TT_R1 = 0
|
||||
local TT_R1_E1 = 1
|
||||
local TT_R1_E2 = 2
|
||||
local TT_R2_E1 = 3
|
||||
local TT_R2_E2 = 4
|
||||
--]]
|
||||
|
||||
local TT_VT_A = 5
|
||||
local TT_VT_B = 6
|
||||
local TT_TLRN_A = 7
|
||||
local TT_TLRN_B = 8
|
||||
local TT_TLRN_A_R2 = 9
|
||||
local TT_TLRN_B_R2 = 10
|
||||
|
||||
local tail_type_text = {[0]="Rud Only","Normal","Rud + Dual Ele","Dual Rud + Elv","Dual Rud/Ele",
|
||||
"VTail A","VTail B","Taileron A","Taileron B","Taileron A + Dual Rud","Taileron B + Dual Rud"}
|
||||
|
||||
|
||||
local MV_AIRCRAFT_TYPE = 1001
|
||||
local MV_WING_TYPE = 1002
|
||||
local MV_TAIL_TYPE = 1003
|
||||
|
||||
local MV_CH_BASE = 1010
|
||||
local MV_CH_THR = 1010
|
||||
local MV_CH_L_AIL = 1011
|
||||
local MV_CH_R_AIL = 1012
|
||||
local MV_CH_L_FLP = 1013
|
||||
local MV_CH_R_FLP = 1014
|
||||
|
||||
local MV_CH_L_RUD = 1015
|
||||
local MV_CH_R_RUD = 1016
|
||||
local MV_CH_L_ELE = 1017
|
||||
local MV_CH_R_ELE = 1018
|
||||
|
||||
local MV_PORT_BASE = 1020
|
||||
|
||||
local MV_DATA_END = 1040
|
||||
|
||||
--Channel Types --
|
||||
local CT_NONE = 0x00
|
||||
local CT_AIL = 0x01
|
||||
local CT_ELE = 0x02
|
||||
local CT_RUD = 0x04
|
||||
local CT_REVERSE = 0x20
|
||||
local CT_THR = 0x40
|
||||
local CT_SLAVE = 0x80
|
||||
|
||||
-- Seems like Reverse Mix is complement of the 3 bits
|
||||
local CMT_NORM = 0x00 -- 0000
|
||||
local CMT_AIL = 0x10 -- 0001 Taileron
|
||||
local CMT_ELE = 0x20 -- 0010 For VTIAL and Delta-ELEVON
|
||||
local CMT_RUD = 0x30 -- 0011 For VTIAL
|
||||
local CMT_RUD_REV = 0x40 -- 0100 For VTIAL
|
||||
local CMT_ELE_REV = 0x50 -- 0101 For VTIAL and Delta-ELEVON A
|
||||
local CMT_AIL_REV = 0x60 -- 0110 Taileron
|
||||
local CMT_NORM_REV = 0x70 -- 0111
|
||||
|
||||
local MT_NORMAL = 0
|
||||
local MT_REVERSE = 1
|
||||
|
||||
local function channelType2String(byte1, byte2)
|
||||
local s = ""
|
||||
|
||||
if (byte2==0) then return s end;
|
||||
|
||||
if (bit32.band(byte2,CT_AIL)>0) then s=s.."Ail" end
|
||||
if (bit32.band(byte2,CT_ELE)>0) then s=s.."Ele" end
|
||||
if (bit32.band(byte2,CT_RUD)>0) then s=s.."Rud" end
|
||||
if (bit32.band(byte2,CT_THR)>0) then s=s.."Thr" end
|
||||
|
||||
if (bit32.band(byte2,CT_REVERSE)>0) then s=s.."-" end
|
||||
|
||||
if (bit32.band(byte2,CT_SLAVE)>0) then s=s.." Slv" end
|
||||
|
||||
if (byte1==CMT_NORM) then s=s.." "
|
||||
elseif (byte1==CMT_AIL) then s=s.." M_Ail"
|
||||
elseif (byte1==CMT_ELE) then s=s.." M_Ele"
|
||||
elseif (byte1==CMT_RUD) then s=s.." M_Rud"
|
||||
elseif (byte1==CMT_RUD_REV) then s=s.." M_Rud-"
|
||||
elseif (byte1==CMT_ELE_REV) then s=s.." M_Ele-"
|
||||
elseif (byte1==CMT_AIL_REV) then s=s.." M_Ail-"
|
||||
elseif (byte1==CMT_NORM_REV) then s=s.." M-"
|
||||
end
|
||||
|
||||
return s;
|
||||
end
|
||||
|
||||
-- This Creates the Servo Settings that will be used to pass to
|
||||
-- Forward programming
|
||||
local function CreateDSMPortChannelInfo()
|
||||
local function ApplyWingMixA(b2)
|
||||
-- ELEVON
|
||||
if (b2==CT_AIL+CT_ELE) then return CMT_ELE end; -- 0x03
|
||||
if (b2==CT_AIL+CT_ELE+CT_SLAVE) then return CMT_NORM end; -- 0x83
|
||||
end
|
||||
|
||||
local function ApplyWingMixB(b2)
|
||||
-- ELEVON
|
||||
if (b2==CT_AIL+CT_ELE) then return CMT_NORM end; -- 0x03
|
||||
if (b2==CT_AIL+CT_ELE+CT_SLAVE) then return CMT_ELE end; -- 0x83
|
||||
end
|
||||
|
||||
local function ApplyTailMixA(b2)
|
||||
-- VTAIL
|
||||
-- Default normal/reverse behaviour
|
||||
if (b2==CT_RUD+CT_ELE) then return CMT_NORM end; -- 0x06
|
||||
if (b2==CT_RUD+CT_ELE+CT_SLAVE) then return CMT_ELE end; -- 0x86
|
||||
|
||||
--TAILERON
|
||||
-- Default normal/reverse behaviour
|
||||
if (b2==CT_AIL+CT_ELE) then return CMT_NORM end; -- 0x03
|
||||
if (b2==CT_AIL+CT_ELE+CT_SLAVE) then return CMT_AIL end; -- 0x83
|
||||
end
|
||||
|
||||
local function ApplyTailMixB(b2)
|
||||
-- VTAIL
|
||||
-- Default normal/reverse behaviour
|
||||
if (b2==CT_RUD+CT_ELE) then return CMT_NORM end; -- 0x06
|
||||
if (b2==CT_RUD+CT_ELE+CT_SLAVE) then return CMT_RUD end; -- 0x86
|
||||
|
||||
--TAILERON
|
||||
if (b2==CT_AIL+CT_ELE) then return CMT_AIL end; -- 0x03
|
||||
if (b2==CT_AIL+CT_ELE+CT_SLAVE) then return CMT_NORM end; -- 0x83
|
||||
end
|
||||
|
||||
local function reverseMix(b)
|
||||
if (b==CMT_NORM) then return CMT_NORM_REV end;
|
||||
if (b==CMT_AIL) then return CMT_AIL_REV end;
|
||||
if (b==CMT_ELE) then return CMT_ELE_REV end;
|
||||
if (b==CMT_RUD) then return CMT_RUD_REV end;
|
||||
return b
|
||||
end
|
||||
|
||||
local DSM_Ch = MODEL.DSM_ChannelInfo
|
||||
|
||||
for i=0, TX_CHANNELS-1 do
|
||||
DSM_Ch[i] = {[0]= CMT_NORM, CT_NONE, nil} -- Initialize with no special function
|
||||
end
|
||||
|
||||
--local aircraftType = M_DATA[MV_AIRCRAFT_TYPE]
|
||||
local wingType = M_DATA[MV_WING_TYPE]
|
||||
local tailType = M_DATA[MV_TAIL_TYPE]
|
||||
|
||||
local thrCh = M_DATA[MV_CH_THR]
|
||||
local lAilCh = M_DATA[MV_CH_L_AIL]
|
||||
local rAilCh = M_DATA[MV_CH_R_AIL]
|
||||
|
||||
local lElevCh = M_DATA[MV_CH_L_ELE]
|
||||
local rElevCh = M_DATA[MV_CH_R_ELE]
|
||||
|
||||
local lRudCh = M_DATA[MV_CH_L_RUD]
|
||||
local rRudCh = M_DATA[MV_CH_R_RUD]
|
||||
|
||||
-- Channels in menu vars are Zero base, Channel info is 1 based
|
||||
|
||||
-- THR
|
||||
if (thrCh~=nil and thrCh < 10) then DSM_Ch[thrCh][1]= CT_THR end
|
||||
|
||||
-- AIL (Left and Right)
|
||||
if (lAilCh~=nil) then DSM_Ch[lAilCh][1] = CT_AIL end
|
||||
if (rAilCh~=nil) then DSM_Ch[rAilCh][1] = CT_AIL+CT_SLAVE end
|
||||
-- ELE (Left and Right)
|
||||
if (lElevCh~=nil) then DSM_Ch[lElevCh][1] = CT_ELE end
|
||||
if (rElevCh~=nil) then DSM_Ch[rElevCh][1] = CT_ELE+CT_SLAVE end
|
||||
-- RUD (Left and Right)
|
||||
if (lRudCh~=nil) then DSM_Ch[lRudCh][1] = CT_RUD end
|
||||
if (rRudCh~=nil) then DSM_Ch[rRudCh][1] = CT_RUD+CT_SLAVE end
|
||||
|
||||
-- VTAIL: RUD + ELE
|
||||
if (tailType==TT_VT_A) then
|
||||
DSM_Ch[lElevCh][1] = CT_RUD+CT_ELE
|
||||
DSM_Ch[rElevCh][1] = CT_RUD+CT_ELE+CT_SLAVE
|
||||
elseif (tailType==TT_VT_B) then
|
||||
DSM_Ch[lElevCh][1] = CT_RUD+CT_ELE+CT_SLAVE
|
||||
DSM_Ch[rElevCh][1] = CT_RUD+CT_ELE
|
||||
end
|
||||
|
||||
-- TAILERRON: 2-ELE + AIL
|
||||
if (tailType==TT_TLRN_A or tailType==TT_TLRN_A_R2) then
|
||||
DSM_Ch[lElevCh][1] = CT_AIL+CT_ELE
|
||||
DSM_Ch[rElevCh][1] = CT_AIL+CT_ELE+CT_SLAVE
|
||||
elseif (tailType==TT_TLRN_B or tailType==TT_TLRN_B_R2) then
|
||||
DSM_Ch[lElevCh][1] = CT_AIL+CT_ELE+CT_SLAVE
|
||||
DSM_Ch[rElevCh][1] = CT_AIL+CT_ELE
|
||||
end
|
||||
|
||||
---- ELEVON : AIL + ELE
|
||||
if (wingType==WT_ELEVON_A) then
|
||||
DSM_Ch[lAilCh][1] = CT_AIL+CT_ELE
|
||||
DSM_Ch[rAilCh][1] = CT_AIL+CT_ELE+CT_SLAVE
|
||||
elseif (wingType==WT_ELEVON_B) then
|
||||
DSM_Ch[lAilCh][1] = CT_AIL+CT_ELE+CT_SLAVE
|
||||
DSM_Ch[rAilCh][1] = CT_AIL+CT_ELE
|
||||
end
|
||||
|
||||
------MIXES ---------
|
||||
|
||||
-- TAIL Mixes (Elevator and VTail)
|
||||
if (tailType==TT_VT_A or tailType==TT_TLRN_A or tailType==TT_TLRN_A_R2) then
|
||||
DSM_Ch[lElevCh][0] = ApplyTailMixA(DSM_Ch[lElevCh][1])
|
||||
DSM_Ch[rElevCh][0] = ApplyTailMixA(DSM_Ch[rElevCh][1])
|
||||
elseif (tailType==TT_VT_B or tailType==TT_TLRN_B or tailType==TT_TLRN_B_R2) then
|
||||
DSM_Ch[lElevCh][0] = ApplyTailMixB(DSM_Ch[lElevCh][1])
|
||||
DSM_Ch[rElevCh][0] = ApplyTailMixB(DSM_Ch[rElevCh][1])
|
||||
end
|
||||
|
||||
---- ELEVON : AIL + ELE
|
||||
if (wingType==WT_ELEVON_A) then
|
||||
DSM_Ch[lAilCh][0] = ApplyWingMixA(DSM_Ch[lAilCh][1])
|
||||
DSM_Ch[rAilCh][0] = ApplyWingMixA(DSM_Ch[rAilCh][1])
|
||||
elseif (wingType==WT_ELEVON_B) then
|
||||
DSM_Ch[lAilCh][0] = ApplyWingMixB(DSM_Ch[lAilCh][1])
|
||||
DSM_Ch[rAilCh][0] = ApplyWingMixB(DSM_Ch[rAilCh][1])
|
||||
end
|
||||
|
||||
-- Apply Gyro Reverse as needed for each channel as long as it is used
|
||||
for i=0, TX_CHANNELS-1 do
|
||||
if (M_DATA[MV_PORT_BASE+i]==MT_REVERSE and DSM_Ch[i][1]>0) then
|
||||
DSM_Ch[i][0]=reverseMix(DSM_Ch[i][0])
|
||||
DSM_Ch[i][1]=DSM_Ch[i][1]+CT_REVERSE
|
||||
end
|
||||
end
|
||||
|
||||
-- Show how it looks
|
||||
for i=0, 9 do
|
||||
local b1,b2 = DSM_Ch[i][0], DSM_Ch[i][1]
|
||||
local s1 = channelType2String(b1,b2)
|
||||
local s = string.format("%s (%02X %02X) %s\n", MODEL.PORT_TEXT[i],
|
||||
b1, b2,s1)
|
||||
DSM_Ch[i][2]=s1
|
||||
LOG_write(s)
|
||||
end
|
||||
|
||||
--MODEL.AirWingTailDesc = string.format("Aircraft(%s) Wing(%s) Tail(%s)",aircraft_type_text[aircraftType],wing_type_text[wingType],tail_type_text[tailType])
|
||||
end
|
||||
|
||||
-- Main Program
|
||||
|
||||
LOG_write("Creating DSMPort Info\n")
|
||||
CreateDSMPortChannelInfo()
|
||||
|
||||
|
@ -1,90 +0,0 @@
|
||||
local Log, menuLib, modelLib, DEBUG_ON, SIMULATION_ON = ... -- Get DebugON from parameters
|
||||
local MAIN_MENU_LIB_VERSION = "0.56"
|
||||
local MODEL = modelLib.MODEL
|
||||
|
||||
local PHASE = menuLib.PHASE
|
||||
local LINE_TYPE = menuLib.LINE_TYPE
|
||||
|
||||
local lastGoodMenu=0
|
||||
|
||||
-- Creates the menus to Render with the GUI
|
||||
local function ST_LoadMenu(menuId)
|
||||
local ctx = menuLib.DSM_Context
|
||||
menuLib.clearMenuLines()
|
||||
|
||||
if (menuId==0x1000) then -- MAIN MENU
|
||||
ctx.Menu = { MenuId = 0x1000, Text = "Main Menu ("..MODEL.modelName..")", PrevId = 0, NextId = 0, BackId = 0, TextId=0 }
|
||||
ctx.MenuLines[0] = { Type = LINE_TYPE.MENU, Text = "Model Setup", ValId = 0xFFF3,TextId=0 }
|
||||
|
||||
if (SIMULATION_ON) then
|
||||
ctx.MenuLines[4] = { Type = LINE_TYPE.MENU, Text = "RX Simulator (GUI dev only)", ValId = 0xFFF1, TextId=0 } -- Menu 0xFFF2 to SIMULATOR
|
||||
end
|
||||
ctx.MenuLines[6] = { Type = LINE_TYPE.MENU, Text = "Forward Programming RX", ValId = 0xFFF2, TextId=0 } -- Menu 0xFFF2 to Real RX
|
||||
ctx.SelLine = 6
|
||||
|
||||
lastGoodMenu = menuId
|
||||
else
|
||||
--print("NOT IMPLEMENTED")
|
||||
ctx.Menu = { MenuId = 0x0002, Text = "NOT IMPLEMENTED", TextId = 0, PrevId = 0, NextId = 0, BackId = lastGoodMenu }
|
||||
ctx.SelLine = menuLib.BACK_BUTTON
|
||||
end
|
||||
|
||||
menuLib.PostProcessMenu()
|
||||
end
|
||||
|
||||
local function Main_Send_Receive()
|
||||
local ctx = menuLib.DSM_Context
|
||||
|
||||
if ctx.Phase == PHASE.RX_VERSION then -- Just Init RX Version
|
||||
ctx.RX.Name = "Main Menu"
|
||||
ctx.RX.Version = MAIN_MENU_LIB_VERSION
|
||||
ctx.Phase = PHASE.MENU_TITLE
|
||||
ctx.Menu.MenuId = 0
|
||||
|
||||
ctx.Refresh_Display = true
|
||||
elseif ctx.Phase == PHASE.WAIT_CMD then
|
||||
|
||||
elseif ctx.Phase == PHASE.MENU_TITLE then -- request menu title
|
||||
if ctx.Menu.MenuId == 0 then -- First time loading a menu ?
|
||||
ST_LoadMenu(0x01000)
|
||||
else
|
||||
ST_LoadMenu(ctx.Menu.MenuId)
|
||||
end
|
||||
ctx.Phase = PHASE.WAIT_CMD
|
||||
ctx.Refresh_Display = true
|
||||
|
||||
elseif ctx.Phase == PHASE.VALUE_CHANGING then -- send value
|
||||
local line = ctx.MenuLines[ctx.SelLine] -- Updated Value of SELECTED line
|
||||
--if (DEBUG_ON) then Log.LOG_write("%3.3f %s: ", menuLib.getElapsedTime(), menuLib.phase2String(ctx.Phase)) end
|
||||
--if (DEBUG_ON) then Log.LOG_write("SEND SIM_updateMenuValue(ValueId=0x%X Text=\"%s\" Value=%s)\n", line.ValId, line.Text, menuLib.lineValue2String(line)) end
|
||||
ctx.Phase = PHASE.VALUE_CHANGING_WAIT
|
||||
|
||||
elseif ctx.Phase == PHASE.VALUE_CHANGING_WAIT then
|
||||
local line = ctx.MenuLines[ctx.SelLine]
|
||||
|
||||
elseif ctx.Phase == PHASE.VALUE_CHANGE_END then -- send value
|
||||
local line = ctx.MenuLines[ctx.SelLine] -- Updated Value of SELECTED line
|
||||
--if (DEBUG_ON) then Log.LOG_write("%3.3f %s: ", menuLib.getElapsedTime(), menuLib.phase2String(ctx.Phase)) end
|
||||
--if (DEBUG_ON) then Log.LOG_write("SEND SIM_updateMenuValue(ValueId=0x%X Text=\"%s\" Value=%s)\n", line.ValId, line.Text, menuLib.lineValue2String(line)) end
|
||||
--if (DEBUG_ON) then Log.LOG_write("SEND SIM_validateMenuValue(ValueId=0x%X Text=\"%s\" Value=%s)\n", line.ValId, line.Text, menuLib.lineValue2String(line)) end
|
||||
ctx.Phase = PHASE.WAIT_CMD
|
||||
|
||||
elseif ctx.Phase == PHASE.EXIT then
|
||||
ctx.Phase=PHASE.EXIT_DONE
|
||||
return 1
|
||||
end
|
||||
|
||||
return 0
|
||||
end
|
||||
|
||||
local function Main_Init()
|
||||
local ctx = menuLib.DSM_Context
|
||||
ctx.Phase = PHASE.RX_VERSION
|
||||
end
|
||||
|
||||
local function Main_Done()
|
||||
local ctx = menuLib.DSM_Context
|
||||
ctx.Phase = PHASE.EXIT_DONE
|
||||
end
|
||||
|
||||
return { init=Main_Init, run=Main_Send_Receive, done=Main_Done }
|
@ -1,788 +0,0 @@
|
||||
--- #########################################################################
|
||||
---- # #
|
||||
---- # Copyright (C) OpenTX/EdgeTx #
|
||||
-----# #
|
||||
---- # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html #
|
||||
---- # #
|
||||
---- # This program is free software; you can redistribute it and/or modify #
|
||||
---- # it under the terms of the GNU General Public License version 2 as #
|
||||
---- # published by the Free Software Foundation. #
|
||||
---- # #
|
||||
---- # This program is distributed in the hope that it will be useful #
|
||||
---- # but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
---- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
---- # GNU General Public License for more details. #
|
||||
---- # #
|
||||
---- #########################################################################
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- This script library is a rewrite of the original DSM forward programming Lua
|
||||
-- Script. The goal is to make it easier to understand, mantain, and to
|
||||
-- separate the GUI from the DSM Forward programming engine/logic
|
||||
-- in this way, GUIs can evolve independent. OpenTX Gui, EdgeTx GUI, Small Radios, etc.
|
||||
|
||||
-- Code is based on the code/work by: Pascal Langer (Author of the Multi-Module)
|
||||
-- Rewrite/Enhancements By: Francisco Arzu
|
||||
|
||||
local Log, DEBUG_ON = ... -- Parameters
|
||||
|
||||
|
||||
local MenuLib = { }
|
||||
|
||||
local PHASE = {
|
||||
INIT = 0,
|
||||
RX_VERSION = 1,
|
||||
WAIT_CMD = 2,
|
||||
MENU_TITLE = 3,
|
||||
MENU_REQ_TX_INFO = 4,
|
||||
MENU_LINES = 5,
|
||||
MENU_VALUES = 6,
|
||||
VALUE_CHANGING = 7,
|
||||
VALUE_CHANGING_WAIT = 8,
|
||||
VALUE_CHANGE_END = 9,
|
||||
EXIT = 10,
|
||||
EXIT_DONE = 11
|
||||
}
|
||||
|
||||
local LINE_TYPE = {
|
||||
MENU = 0x1C,
|
||||
LIST_MENU = 0x0C, -- List: INC Change + Validate
|
||||
LIST_MENU_NC = 0x6C, -- List: No Incremental Change
|
||||
LIST_MENU_NC2 = 0x6D, -- List: No Incremental Change (Frame Rate Herz)
|
||||
LIST_MENU_TOG = 0x4C, -- List: Incremental Change, sometimes bolean/Toggle menu (if only 2 values)
|
||||
LIST_MENU_ORI = 0xCC, -- List: Incremental Change, Orientation Heli
|
||||
|
||||
VALUE_NUM_I8_NC = 0x60, -- 8 bit number, no incremental change
|
||||
VALUE_PERCENT = 0xC0, -- 8 bit number, Signed, percent
|
||||
VALUE_DEGREES = 0xE0, -- 8 bit number, Signed, Degress
|
||||
VALUE_NUM_I8 = 0x40, -- 8 bit number
|
||||
VALUE_NUM_I16 = 0x41, -- 16 Bit number
|
||||
VALUE_NUM_SI16 = 0xC1, -- 16 bit number, Signed
|
||||
|
||||
LT_EMPTY = 0x00
|
||||
}
|
||||
|
||||
-- Bug in Lua compiler, confusing with global BOLD and RIGHT
|
||||
local DISP_ATTR = {
|
||||
_BOLD = 0x01, _RIGHT=0x02, _CENTER=0x04, PERCENT = 0x10, DEGREES=0x20, FORCED_MENU = 0x40
|
||||
}
|
||||
|
||||
--RX IDs--
|
||||
local RX = {
|
||||
AR636B = 0x0001,
|
||||
SPM4651T = 0x0014,
|
||||
AR637T = 0x0015,
|
||||
AR637TA = 0x0016,
|
||||
FC6250HX = 0x0018,
|
||||
AR630 = 0x0019,
|
||||
AR8360T = 0x001A,
|
||||
AR10360T = 0x001C,
|
||||
AR631 = 0x001E
|
||||
}
|
||||
|
||||
local DSM_Context = {
|
||||
Phase = PHASE.INIT,
|
||||
Menu = { MenuId = 0, Text = "", TextId = 0, PrevId = 0, NextId = 0, BackId = 0 },
|
||||
MenuLines = {},
|
||||
RX = { Id=0, Name = "", Version = "" },
|
||||
Refresh_Display = true,
|
||||
SendDataToRX = 1,
|
||||
|
||||
SelLine = 0, -- Current Selected Line
|
||||
EditLine = nil, -- Current Editing Line
|
||||
CurLine = -1, -- Current Line Requested/Parsed via h message protocol
|
||||
isReset = false -- false when starting from scracts, true when starting from Reset
|
||||
}
|
||||
|
||||
function DSM_Context.isEditing() return DSM_Context.EditLine~=nil end
|
||||
|
||||
local MAX_MENU_LINES = 6
|
||||
local BACK_BUTTON = -1 -- Tread it as a display line #-1
|
||||
local NEXT_BUTTON = MAX_MENU_LINES + 1 -- Tread it as a display line #7
|
||||
local PREV_BUTTON = MAX_MENU_LINES + 2 -- Tread it as a display line #7
|
||||
|
||||
-- Text Arrays for Display Text and Debuging
|
||||
local PhaseText = {}
|
||||
local LineTypeText = {}
|
||||
|
||||
local Text = {} -- Text for Menu and Menu Lines (Headers only)
|
||||
local List_Text = {} -- Messages for List Options (values only)
|
||||
local List_Text_Img = {} -- If the Text has Attached Images
|
||||
local List_Values = {} -- Additiona restrictions on List Values when non contiguos (L_M1 lines has this problem)
|
||||
local Flight_Mode = {[0]="Fligh Mode"}
|
||||
local RxName = {}
|
||||
|
||||
local StartTime = 0
|
||||
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
-- Get Elapsed Time since we started running the Script. Return a float in format: Seconds.Milliseconds
|
||||
function MenuLib.getElapsedTime()
|
||||
local t = getTime()
|
||||
if (StartTime == 0) then StartTime = t end
|
||||
|
||||
return ((t - StartTime) * 10) / 1000
|
||||
end
|
||||
|
||||
------------- Line Type helper functions ------------------------------------------------------------------
|
||||
|
||||
-- Check if the text are Flight modes, who will be treated different for Display
|
||||
function MenuLib.isFlightModeLine(line)
|
||||
return (line.TextId >= 0x8000 and line.TextId <= 0x8003)
|
||||
end
|
||||
|
||||
function MenuLib.isSelectableLine(line) -- is the display line Selectable??
|
||||
-- values who are not selectable
|
||||
if (line.Type == 0) then return false end -- Empty Line
|
||||
if (line.Type == LINE_TYPE.MENU and line.ValId == line.MenuId and bit32.band(line.TextAttr, DISP_ATTR.FORCED_MENU)==0) then return false end -- Menu that navigates to Itself?
|
||||
if (line.Min==0 and line.Max==0 and line.Def==0) then return false end -- Values with no Range are only for display
|
||||
if (line.Type == LINE_TYPE.VALUE_NUM_I8_NC and MenuLib.isFlightModeLine(line)) then return false end -- Flight mode is not Selectable
|
||||
return true
|
||||
end
|
||||
|
||||
function MenuLib.isEditableLine(line) -- is the display line editable??
|
||||
-- values who are not editable
|
||||
if (line.Type == 0 or line.Type == LINE_TYPE.MENU) then return false end -- Menus are not editable
|
||||
if (line.Min==0 and line.Max==0 and line.Def==0) then return false end -- Values with no Range are only for display
|
||||
if (line.Type == LINE_TYPE.VALUE_NUM_I8_NC and MenuLib.isFlightModeLine(line)) then return false end -- Flight mode is not Editable
|
||||
-- any other is Editable
|
||||
return true
|
||||
end
|
||||
|
||||
function MenuLib.isListLine(line) -- is it a List of options??
|
||||
if (line.Type == LINE_TYPE.LIST_MENU_NC or line.Type == LINE_TYPE.LIST_MENU or
|
||||
line.Type == LINE_TYPE.LIST_MENU_TOG or line.Type == LINE_TYPE.LIST_MENU_NC2 or
|
||||
line.Type == LINE_TYPE.LIST_MENU_ORI) then return true end
|
||||
return false
|
||||
end
|
||||
|
||||
function MenuLib.isPercentValueLineByMinMax(line)
|
||||
return
|
||||
(line.Min == 0 and line.Max == 100) or ( line.Min == -100 and line.Max == 100) or
|
||||
( line.Min == 0 and line.Max == 150) or ( line.Min == -150 and line.Max == 150)
|
||||
end
|
||||
|
||||
function MenuLib.isPercentValueLine(line) -- is it a Percent value??
|
||||
if (line.Type == LINE_TYPE.VALUE_PERCENT) then return true end
|
||||
return false
|
||||
end
|
||||
|
||||
function MenuLib.isNumberValueLine(line) -- is it a number ??
|
||||
if (MenuLib.isListLine(line) or line.Type == LINE_TYPE.MENU or line.Type == 0) then return false
|
||||
else return true end
|
||||
end
|
||||
|
||||
function MenuLib.isIncrementalValueUpdate(line)
|
||||
if (line.Type == LINE_TYPE.LIST_MENU_NC or line.Type == LINE_TYPE.LIST_MENU_NC2 or
|
||||
line.Type == LINE_TYPE.VALUE_NUM_I8_NC or line.Type == LINE_TYPE.VALUE_DEGREES) then return false end
|
||||
return true
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
function MenuLib.Get_Text(index)
|
||||
if (index >= 0x8000) then
|
||||
return Flight_Mode[0]
|
||||
end
|
||||
|
||||
local out = Text[index] -- Find in regular header first
|
||||
if out== nil then
|
||||
out = List_Text[index] -- Try list values, don't think is necesary, but just playing Safe
|
||||
end
|
||||
if out == nil then -- unknown...
|
||||
out = "Unknown_" .. string.format("%X", index)
|
||||
end
|
||||
return out
|
||||
end
|
||||
|
||||
function MenuLib.Get_List_Text(index)
|
||||
local out = List_Text[index] -- Try to find the message in List_Text
|
||||
if out == nil then
|
||||
out = Text[index] -- Try list headers, don't think is necesary, but just playing Safe
|
||||
end
|
||||
if out == nil then -- unknown...
|
||||
out = "UnknownLT_" .. string.format("%X", index)
|
||||
end
|
||||
return out
|
||||
end
|
||||
|
||||
function MenuLib.Get_List_Text_Img(index)
|
||||
local out = List_Text_Img[index]
|
||||
return out
|
||||
end
|
||||
|
||||
function MenuLib.Get_List_Values(index)
|
||||
local out = List_Values[index]
|
||||
return out
|
||||
end
|
||||
|
||||
function MenuLib.Get_RxName(index)
|
||||
local out = RxName[index]
|
||||
return out or ("RX_" .. string.format("%X", index))
|
||||
end
|
||||
|
||||
----------- Debugging 2-String functions -------------------------------------------------------------------
|
||||
|
||||
function MenuLib.phase2String(index)
|
||||
local out = PhaseText[index]
|
||||
return out or ("Phase_" .. string.format("%X", index))
|
||||
end
|
||||
|
||||
function MenuLib.lineType2String(index)
|
||||
local out = LineTypeText[index]
|
||||
return out or ("LT_" .. string.format("%X", index or 0xFF))
|
||||
end
|
||||
|
||||
function MenuLib.lineValue2String(l)
|
||||
if (DEBUG_ON == 0) then
|
||||
return ""
|
||||
end
|
||||
if (l ~= nil and l.Val ~= nil) then
|
||||
local value = l.Val
|
||||
if MenuLib.isListLine(l) then
|
||||
value = value .. "|\"" .. MenuLib.Get_List_Text(l.Val + l.TextStart) .. "\""
|
||||
else
|
||||
value = value..(l.Format or "")
|
||||
end
|
||||
return value
|
||||
end
|
||||
return "nil"
|
||||
end
|
||||
|
||||
function MenuLib.menu2String(m)
|
||||
local txt = "Menu[]"
|
||||
if (m ~= nil) then
|
||||
txt = string.format("M[Id=0x%X P=0x%X N=0x%X B=0x%X Text=\"%s\"[0x%X]]",
|
||||
m.MenuId, m.PrevId, m.NextId, m.BackId, m.Text, m.TextId)
|
||||
end
|
||||
return txt
|
||||
end
|
||||
|
||||
function MenuLib.menuLine2String(l)
|
||||
local txt = "Line[]"
|
||||
if (l ~= nil) then
|
||||
local value = ""
|
||||
local range = ""
|
||||
if l.Type~=LINE_TYPE.MENU then
|
||||
value = "Val="..MenuLib.lineValue2String(l)
|
||||
if MenuLib.isListLine(l) then
|
||||
range = string.format("NL=(%s->%s,%s,S=%s) ",l.Min, l.Max, l.Def, l.TextStart )
|
||||
range = range .. (l.MinMaxOrig or "")
|
||||
else
|
||||
range = string.format("[%s->%s,%s]",l.Min, l.Max, l.Def)
|
||||
end
|
||||
end
|
||||
|
||||
txt = string.format("L[#%s T=%s VId=0x%X Text=\"%s\"[0x%X] %s %s MId=0x%X A=0x%X]",
|
||||
l.lineNum, MenuLib.lineType2String(l.Type), l.ValId,
|
||||
l.Text, l.TextId,
|
||||
value,
|
||||
range,
|
||||
l.MenuId,
|
||||
l.TextAttr
|
||||
)
|
||||
end
|
||||
return txt
|
||||
end
|
||||
|
||||
-----------------------------------------------------------------------------------------------------------
|
||||
-- Post Procssing Line from Raw values receive by RX or Simulation
|
||||
|
||||
function MenuLib.isDisplayAttr(attr, bit)
|
||||
return (bit32.band(attr,bit)>0)
|
||||
end
|
||||
|
||||
function MenuLib.ExtractDisplayAttr(text1, attr)
|
||||
local text = text1, pos;
|
||||
|
||||
for i=1,2 do
|
||||
text, pos = string.gsub(text, "/c$", "")
|
||||
if (pos>0) then -- CENTER
|
||||
attr = bit32.bor(attr, DISP_ATTR._CENTER)
|
||||
end
|
||||
|
||||
text, pos = string.gsub(text, "/r$", "")
|
||||
if (pos>0) then -- RIGHT
|
||||
attr = bit32.bor(attr, DISP_ATTR._RIGHT)
|
||||
end
|
||||
|
||||
text, pos = string.gsub(text, "/p$", "")
|
||||
if (pos>0) then -- Percent TEXT
|
||||
attr = bit32.bor(attr, DISP_ATTR.PERCENT)
|
||||
end
|
||||
|
||||
text, pos = string.gsub(text, "/b$", "")
|
||||
if (pos>0) then -- BOLD TEXT
|
||||
attr = bit32.bor(attr, DISP_ATTR._BOLD)
|
||||
end
|
||||
|
||||
text, pos = string.gsub(text, "/m$", "")
|
||||
if (pos>0) then -- FORCED MENU Button
|
||||
attr = bit32.bor(attr, DISP_ATTR.FORCED_MENU)
|
||||
end
|
||||
end
|
||||
|
||||
return text, attr
|
||||
end
|
||||
|
||||
function MenuLib.MenuPostProcessing(menu)
|
||||
menu.Text, menu.TextAttr = MenuLib.ExtractDisplayAttr(menu.Text,menu.TextAttr or 0)
|
||||
end
|
||||
|
||||
function MenuLib.MenuLinePostProcessing(line)
|
||||
if (line.Text==nil) then
|
||||
line.Text = MenuLib.Get_Text(line.TextId) -- Get Textual Line headeing text
|
||||
end
|
||||
|
||||
-- Text formatting options
|
||||
line.Text, line.TextAttr = MenuLib.ExtractDisplayAttr(line.Text,line.TextAttr or 0)
|
||||
|
||||
if line.Type == LINE_TYPE.MENU then
|
||||
-- nothing to do on menu entries
|
||||
line.Val=nil
|
||||
elseif MenuLib.isListLine(line) then
|
||||
-- Original Range for Debugging
|
||||
line.MinMaxOrig = "[" .. line.Min .. "->" .. line.Max .. "," .. line.Def .. "]"
|
||||
|
||||
-- Normalize Min/Max to be relative to Zero
|
||||
line.TextStart = line.Min
|
||||
line.Def = line.Def - line.Min -- normalize default value
|
||||
line.Max = line.Max - line.Min -- normalize max index
|
||||
line.Min = 0 -- min index
|
||||
else -- default to numerical value
|
||||
if MenuLib.isPercentValueLine(line) or MenuLib.isPercentValueLineByMinMax(line) then
|
||||
-- either explicit Percent or NO-Change value, but range is %Percent
|
||||
line.Format ="%"
|
||||
line.TextAttr = bit32.bor(line.TextAttr,DISP_ATTR.PERCENT)
|
||||
elseif (line.Type == LINE_TYPE.VALUE_DEGREES) then
|
||||
line.Format ="o"
|
||||
line.TextAttr = bit32.bor(line.TextAttr,DISP_ATTR.DEGREES)
|
||||
end
|
||||
end
|
||||
|
||||
line.MinMaxDebug = MenuLib.lineType2String(line.Type).." "..(line.MinMaxOrig or "")
|
||||
end
|
||||
|
||||
|
||||
function MenuLib.ChangePhase(newPhase)
|
||||
DSM_Context.Phase = newPhase
|
||||
DSM_Context.SendDataToRX = 1
|
||||
end
|
||||
|
||||
function MenuLib.Value_Add(line, inc)
|
||||
if (DEBUG_ON) then Log.LOG_write("%3.3f %s: DSM_Value_Add(%s,%s)\n",
|
||||
MenuLib.getElapsedTime(), MenuLib.phase2String(DSM_Context.Phase), inc, MenuLib.menuLine2String(line)) end
|
||||
|
||||
local skipIncrement = false
|
||||
local values = nil
|
||||
local origVal = line.Val
|
||||
|
||||
-- Use local validation for LIST_MENU1 when the range is wide open
|
||||
-- Also use if for some LIST_MENU0 that the Range seems incorrect
|
||||
if (MenuLib.isListLine(line)) then -- and line.Type==LINE_TYPE.LIST_MENU1 and line.Min==0 and line.Max==244) then
|
||||
values = MenuLib.Get_List_Values(line.TextId)
|
||||
end
|
||||
|
||||
|
||||
if (values~=nil) then -- Inc/Dec based on a list of predefined Values Local to Script (values not contiguous),
|
||||
-- locate current value in values array
|
||||
-- Values are Zero normalized to the Start of the List (line.TextStart)
|
||||
for i = 1, #values do
|
||||
if ((values[i]-line.TextStart)==origVal) then
|
||||
skipIncrement = true
|
||||
if (inc==-1 and i > 1) then -- PREV
|
||||
line.Val = values[i-1]-line.TextStart
|
||||
elseif (inc==1 and i < #values) then -- NEXT
|
||||
line.Val = values[i+1]-line.TextStart
|
||||
end
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if not skipIncrement then
|
||||
-- Do it Sequentially
|
||||
line.Val = line.Val + inc
|
||||
|
||||
if line.Val > line.Max then
|
||||
line.Val = line.Max
|
||||
elseif line.Val < line.Min then
|
||||
line.Val = line.Min
|
||||
end
|
||||
end
|
||||
|
||||
if (origVal~=line.Val and MenuLib.isIncrementalValueUpdate(line)) then
|
||||
-- Update RX value on every change
|
||||
MenuLib.ChangePhase(PHASE.VALUE_CHANGING)
|
||||
end
|
||||
end
|
||||
|
||||
function MenuLib.Value_Default(line)
|
||||
local origVal = line.Val
|
||||
if (DEBUG_ON) then Log.LOG_write("%3.3f %s: DSM_Value_Default(%s)\n",
|
||||
MenuLib.getElapsedTime(), MenuLib.phase2String(DSM_Context.Phase), MenuLib.menuLine2String(line)) end
|
||||
|
||||
line.Val = line.Def
|
||||
if (origVal~=line.Val and MenuLib.isIncrementalValueUpdate(line)) then
|
||||
-- Update RX value on every change
|
||||
MenuLib.ChangePhase(PHASE.VALUE_CHANGING)
|
||||
end
|
||||
end
|
||||
|
||||
function MenuLib.Value_Write_Validate(line)
|
||||
if (DEBUG_ON) then Log.LOG_write("%3.3f %s: DSM_Value_Write_Validate(%s)\n",
|
||||
MenuLib.getElapsedTime(), MenuLib.phase2String(DSM_Context.Phase), MenuLib.menuLine2String(line)) end
|
||||
|
||||
MenuLib.ChangePhase(PHASE.VALUE_CHANGE_END) -- Update + Validate value in RX
|
||||
DSM_Context.EditLine = nil -- Exit Edit Mode (By clearing the line editing)
|
||||
end
|
||||
|
||||
function MenuLib.GotoMenu(menuId, lastSelectedLine)
|
||||
if (DEBUG_ON) then Log.LOG_write("%3.3f %s: DSM_GotoMenu(0x%X,LastSelectedLine=%d)\n",
|
||||
MenuLib.getElapsedTime(), MenuLib.phase2String(DSM_Context.Phase), menuId, lastSelectedLine) end
|
||||
|
||||
DSM_Context.Menu.MenuId = menuId
|
||||
DSM_Context.SelLine = lastSelectedLine
|
||||
-- Request to load the menu Again
|
||||
MenuLib.ChangePhase(PHASE.MENU_TITLE)
|
||||
end
|
||||
|
||||
function MenuLib.MoveSelectionLine(dir)
|
||||
local ctx = DSM_Context
|
||||
local menu = ctx.Menu
|
||||
local menuLines = ctx.MenuLines
|
||||
|
||||
if (dir == 1) then -- NEXT
|
||||
if ctx.SelLine <= MAX_MENU_LINES then
|
||||
local num = ctx.SelLine
|
||||
for i = ctx.SelLine + 1, MAX_MENU_LINES, 1 do
|
||||
if MenuLib.isSelectableLine(menuLines[i]) then
|
||||
ctx.SelLine = i
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if num == ctx.SelLine then
|
||||
if menu.NextId ~= 0 then -- Next
|
||||
ctx.SelLine = NEXT_BUTTON
|
||||
elseif menu.PrevId ~= 0 then -- Prev
|
||||
ctx.SelLine = PREV_BUTTON
|
||||
end
|
||||
end
|
||||
elseif menu.PrevId ~= 0 then -- Prev
|
||||
ctx.SelLine = PREV_BUTTON
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
if (dir == -1) then -- PREV
|
||||
if ctx.SelLine == PREV_BUTTON and menu.NextId ~= 0 then
|
||||
ctx.SelLine = NEXT_BUTTON
|
||||
elseif ctx.SelLine > 0 then
|
||||
if ctx.SelLine > MAX_MENU_LINES then
|
||||
ctx.SelLine = NEXT_BUTTON
|
||||
end
|
||||
local num = ctx.SelLine
|
||||
for i = ctx.SelLine - 1, 0, -1 do
|
||||
if MenuLib.isSelectableLine(menuLines[i]) then
|
||||
ctx.SelLine = i
|
||||
break
|
||||
end
|
||||
end
|
||||
if num == ctx.SelLine then -- can't find previous selectable line, then SELECT Back
|
||||
if (menu.BackId ~= 0) then ctx.SelLine = BACK_BUTTON end
|
||||
end
|
||||
else
|
||||
if (menu.BackId ~= 0) then ctx.SelLine = BACK_BUTTON end -- Back
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- Clear each line of the menu
|
||||
function MenuLib.clearMenuLines()
|
||||
local ctx = DSM_Context
|
||||
for i = 0, MAX_MENU_LINES do -- clear menu
|
||||
ctx.MenuLines[i] = { MenuId = 0, lineNum = 0, Type = 0, Text = "", TextId = 0, ValId = 0, Min=0, Max=0, Def=0, TextStart=0, Val=nil }
|
||||
end
|
||||
end
|
||||
|
||||
-- Post processing needed for each menu
|
||||
function MenuLib.PostProcessMenu()
|
||||
local ctx = DSM_Context
|
||||
|
||||
if (ctx.Menu.Text==nil) then
|
||||
ctx.Menu.Text = MenuLib.Get_Text(ctx.Menu.TextId)
|
||||
MenuLib.MenuPostProcessing (ctx.Menu)
|
||||
end
|
||||
|
||||
--if (DEBUG_ON) then Log.LOG_write("SIM RESPONSE Menu: %s\n", MenuLib.menu2String(ctx.Menu)) end
|
||||
|
||||
for i = 0, MenuLib.MAX_MENU_LINES do -- clear menu
|
||||
local line = ctx.MenuLines[i]
|
||||
if (line.Type~=0) then
|
||||
line.MenuId = ctx.Menu.MenuId
|
||||
line.lineNum = i
|
||||
MenuLib.MenuLinePostProcessing(line) -- Do the same post processing as if they come from the RX
|
||||
--if (DEBUG_ON) then Log.LOG_write("SIM RESPONSE MenuLine: %s\n", MenuLib.menuLine2String(line)) end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
function MenuLib.GetFlightModeValue(line)
|
||||
local ret = line.Text.." "
|
||||
local val = line.Val
|
||||
|
||||
if (val==nil) then return ret.."--" end
|
||||
|
||||
-- Adjust the displayed value for Flight mode line as needed
|
||||
if (DSM_Context.RX.Id == RX.FC6250HX) then
|
||||
-- Helicopter Flights modes
|
||||
if (val==0) then ret = ret .. "1 / HOLD"
|
||||
elseif (val==1) then ret = ret .. "2 / Normal"
|
||||
elseif (val==2) then ret = ret .. "3 / Stunt 1"
|
||||
elseif (val==3) then ret = ret .. "4 / Stunt 2"
|
||||
elseif (val==4) then ret = ret .. "5 / Panic"
|
||||
else
|
||||
ret = ret .. " " .. (val + 1)
|
||||
end
|
||||
else
|
||||
-- No adjustment needed
|
||||
if (val==190) then
|
||||
ret=ret.."Err:Out of Range"
|
||||
else
|
||||
ret=ret..(val + 1)
|
||||
end
|
||||
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
function MenuLib.Init()
|
||||
print("MenuLib.Init()")
|
||||
-- Phase Names
|
||||
PhaseText[PHASE.INIT] = "INIT"
|
||||
PhaseText[PHASE.RX_VERSION] = "RX_VERSION"
|
||||
PhaseText[PHASE.WAIT_CMD] = "WAIT_CMD"
|
||||
PhaseText[PHASE.MENU_TITLE] = "MENU_TITLE"
|
||||
PhaseText[PHASE.MENU_REQ_TX_INFO] = "MENU_REQ_TX_INFO"
|
||||
PhaseText[PHASE.MENU_LINES] = "MENU_LINES"
|
||||
PhaseText[PHASE.MENU_VALUES] = "MENU_VALUES"
|
||||
PhaseText[PHASE.VALUE_CHANGING] = "VALUE_CHANGING"
|
||||
PhaseText[PHASE.VALUE_CHANGING_WAIT] = "VALUE_EDITING"
|
||||
PhaseText[PHASE.VALUE_CHANGE_END] = "VALUE_CHANGE_END"
|
||||
PhaseText[PHASE.EXIT] = "EXIT"
|
||||
PhaseText[PHASE.EXIT_DONE] = "EXIT_DONE"
|
||||
|
||||
|
||||
-- Line Types
|
||||
LineTypeText[LINE_TYPE.MENU] = "M"
|
||||
LineTypeText[LINE_TYPE.LIST_MENU_NC] = "LM_nc"
|
||||
LineTypeText[LINE_TYPE.LIST_MENU] = "LM"
|
||||
LineTypeText[LINE_TYPE.LIST_MENU_TOG] = "LM_tog"
|
||||
LineTypeText[LINE_TYPE.LIST_MENU_NC2] = "LM_nc2"
|
||||
LineTypeText[LINE_TYPE.LIST_MENU_ORI] = "LM_ori"
|
||||
LineTypeText[LINE_TYPE.VALUE_NUM_I8_NC] = "V_nc"
|
||||
LineTypeText[LINE_TYPE.VALUE_PERCENT] = "V_%"
|
||||
LineTypeText[LINE_TYPE.VALUE_DEGREES] = "V_de"
|
||||
LineTypeText[LINE_TYPE.VALUE_NUM_I8] = "V_i8"
|
||||
LineTypeText[LINE_TYPE.VALUE_NUM_I16] = "V_i16"
|
||||
LineTypeText[LINE_TYPE.VALUE_NUM_SI16] = "V_s16"
|
||||
LineTypeText[LINE_TYPE.LT_EMPTY] = "Z"
|
||||
|
||||
DSM_Context.Phase = PHASE.RX_VERSION
|
||||
end
|
||||
|
||||
function MenuLib.clearAllText()
|
||||
local function clearTable(t)
|
||||
for i, v in ipairs(t) do t[i] = nil end
|
||||
end
|
||||
|
||||
clearTable(Text)
|
||||
clearTable(List_Text)
|
||||
clearTable(List_Text_Img)
|
||||
clearTable(List_Values)
|
||||
end
|
||||
|
||||
function MenuLib.LoadTextFromFile(fileName, mem)
|
||||
local function rtrim(s)
|
||||
local n = string.len(s)
|
||||
while n > 0 and string.find(s, "^%s", n) do n = n - 1 end
|
||||
return string.sub(s, 1, n)
|
||||
end
|
||||
|
||||
--print(string.format("Loading messages from [%s]",fileName))
|
||||
local dataFile = io.open(fileName, "r") -- read File
|
||||
-- cannot read file???
|
||||
assert(dataFile, "Cannot load Message file:" .. fileName)
|
||||
|
||||
local data = io.read(dataFile, mem * 1024) -- read up to 10k characters (newline char also counts!)
|
||||
io.close(dataFile)
|
||||
|
||||
collectgarbage("collect")
|
||||
|
||||
local lineNo = 0
|
||||
for line in string.gmatch(data, "[^\r\n]+") do
|
||||
lineNo = lineNo + 1
|
||||
--print(string.format("Line [%d]: %s",lineNo,line))
|
||||
|
||||
-- Remove Comments
|
||||
local s = string.find(line, "--", 1, true)
|
||||
if (s ~= nil) then
|
||||
line = string.sub(line, 1, s - 1)
|
||||
end
|
||||
|
||||
line = rtrim(line)
|
||||
|
||||
if (string.len(line) > 0) then
|
||||
local a, b, c = string.match(line, "%s*(%a*)%s*|%s*(%w*)%s*|(.*)%s*")
|
||||
--print(string.format("[%s] [%s] [%s]",a,b,c))
|
||||
if (a ~= nil) then
|
||||
local index = tonumber(b)
|
||||
|
||||
if (index == nil) then
|
||||
assert(false, string.format("%s:%d: Invalid Hex num [%s]", fileName, lineNo, b))
|
||||
elseif (a == "T") then
|
||||
Text[index] = c
|
||||
elseif (a == "LT") then
|
||||
List_Text[index] = c
|
||||
elseif (a == "LI") then
|
||||
List_Text_Img[index] = c
|
||||
elseif (a == "FM") then
|
||||
Flight_Mode[0] = c
|
||||
elseif (a == "RX") then
|
||||
RxName[index] = c
|
||||
else
|
||||
assert(false, string.format("%s:%d: Invalid Line Type [%s]", fileName, lineNo, a))
|
||||
end
|
||||
end
|
||||
end
|
||||
if (lineNo % 50 == 0) then
|
||||
collectgarbage("collect")
|
||||
end
|
||||
end -- For
|
||||
|
||||
--print(string.format("Loaded [%d] messages",lineNo))
|
||||
data = nil
|
||||
end
|
||||
|
||||
function MenuLib.INC_LoadTextFromFile(fileName, FileState)
|
||||
-----------------------
|
||||
local function rtrim(s)
|
||||
local n = string.len(s)
|
||||
while n > 0 and string.find(s, "^%s", n) do n = n - 1 end
|
||||
return string.sub(s, 1, n)
|
||||
end
|
||||
|
||||
local function GetTextInfoFromFile(pos)
|
||||
local dataFile = io.open(fileName, "r")
|
||||
io.seek(dataFile,pos)
|
||||
local buff = io.read(dataFile, 100)
|
||||
io.close(dataFile)
|
||||
|
||||
local line=""
|
||||
local index=""
|
||||
local type=""
|
||||
|
||||
local pipe=0
|
||||
local comment=0
|
||||
local newPos = pos
|
||||
|
||||
-- Parse the line:
|
||||
-- Format: TT|0x999|Text -- Comment
|
||||
for i=1,#buff do
|
||||
newPos=newPos+1
|
||||
local ch = string.sub(buff,i,i)
|
||||
|
||||
if (pipe < 2 and ch=="|") then pipe=pipe+1 -- Count pipes pos (Type | Index | .....)
|
||||
elseif (ch=="\r") then -- Ignore CR
|
||||
elseif (ch=="\n") then break -- LF, end of line
|
||||
elseif (ch=="-") then -- March comments
|
||||
comment=comment+1
|
||||
if (comment==2) then pipe=6 end -- Comment part of line
|
||||
else
|
||||
-- regular char
|
||||
comment=0
|
||||
if (pipe==0) then type=type..ch -- in TT (Type)
|
||||
elseif (pipe==1) then index=index..ch -- in Index
|
||||
elseif (pipe<6) then line=line..ch end -- in Text
|
||||
end -- Regular char
|
||||
end -- For
|
||||
|
||||
return type, index, rtrim(line), newPos
|
||||
end
|
||||
|
||||
-----------------------------------------------------------
|
||||
|
||||
if (FileState.state==nil) then -- Initial State
|
||||
FileState.state=1
|
||||
FileState.lineNo=0
|
||||
FileState.filePos=0
|
||||
end
|
||||
|
||||
if FileState.state==1 then
|
||||
for l=1,10 do -- do 10 lines at a time
|
||||
local type, sIndex, text
|
||||
local lineStart = FileState.filePos
|
||||
|
||||
type, sIndex, text, FileState.filePos = GetTextInfoFromFile(FileState.filePos)
|
||||
|
||||
--print(string.format("T=%s, I=%s, T=%s LS=%d, FP=%d",type,sIndex,text,lineStart, FileState.filePos))
|
||||
|
||||
if (lineStart==FileState.filePos) then -- EOF
|
||||
FileState.state=2 --EOF State
|
||||
return 1
|
||||
end
|
||||
FileState.lineNo = FileState.lineNo + 1
|
||||
|
||||
type = rtrim(type)
|
||||
|
||||
if (string.len(type) > 0 and string.len(sIndex) > 0) then
|
||||
local index = tonumber(sIndex)
|
||||
|
||||
if (index == nil) then
|
||||
assert(false, string.format("%s:%d: Invalid Hex num [%s]", fileName, FileState.lineNo, sIndex))
|
||||
elseif (type == "T") then
|
||||
Text[index] = text
|
||||
elseif (type == "LT") then
|
||||
List_Text[index] = text
|
||||
elseif (type == "LI") then
|
||||
List_Text_Img[index] = text
|
||||
elseif (type == "FM") then
|
||||
Flight_Mode[0] = text
|
||||
elseif (type == "RX") then
|
||||
RxName[index] = text
|
||||
else
|
||||
assert(false, string.format("%s:%d: Invalid Line Type [%s]", fileName, FileState.lineNo, type))
|
||||
end
|
||||
end
|
||||
end -- for
|
||||
end -- if
|
||||
|
||||
return 0
|
||||
end
|
||||
|
||||
|
||||
-- Export some Constants and Variables
|
||||
MenuLib.PHASE = PHASE
|
||||
MenuLib.LINE_TYPE = LINE_TYPE
|
||||
MenuLib.DISP_ATTR = DISP_ATTR
|
||||
MenuLib.RX = RX
|
||||
|
||||
MenuLib.MAX_MENU_LINES = MAX_MENU_LINES
|
||||
MenuLib.BACK_BUTTON = BACK_BUTTON
|
||||
MenuLib.NEXT_BUTTON = NEXT_BUTTON
|
||||
MenuLib.PREV_BUTTON = PREV_BUTTON
|
||||
|
||||
MenuLib.DSM_Context = DSM_Context
|
||||
|
||||
MenuLib.Text = Text
|
||||
MenuLib.List_Text = List_Text
|
||||
MenuLib.List_Text_Img = List_Text_Img
|
||||
MenuLib.List_Values = List_Values
|
||||
|
||||
MenuLib.LOG_open = Log.LOG_open
|
||||
MenuLib.LOG_write = Log.LOG_write
|
||||
MenuLib.LOG_Close = Log.LOG_close
|
||||
|
||||
|
||||
return MenuLib
|
@ -1,789 +0,0 @@
|
||||
|
||||
local Log, DEBUG_ON = ...
|
||||
|
||||
local DATA_PATH = "/MODELS/DSMDATA" -- Path to store model settings files
|
||||
local TX_CHANNELS = 12
|
||||
|
||||
-- MODEL information from ETX/OTX
|
||||
local ModelLib = {}
|
||||
|
||||
local MODEL = {
|
||||
modelName = "", -- The name of the model comming from OTX/ETX
|
||||
modelOutputChannel = {}, -- Output information from OTX/ETX
|
||||
AirWingTailDesc = "",
|
||||
|
||||
TX_CH_TEXT = {},
|
||||
PORT_TEXT = {},
|
||||
DSM_ChannelInfo = {} -- Data Created by DSM Configuration Script
|
||||
}
|
||||
|
||||
--Channel Types --
|
||||
local CH_TYPE = {
|
||||
NONE = 0x00,
|
||||
AIL = 0x01,
|
||||
ELE = 0x02,
|
||||
RUD = 0x04,
|
||||
|
||||
REVERSE = 0x20,
|
||||
THR = 0x40,
|
||||
SLAVE = 0x80,
|
||||
}
|
||||
|
||||
-- Seems like Reverse Mix is complement of the 3 bits
|
||||
local CH_MIX_TYPE = {
|
||||
MIX_NORM = 0x00, -- 0000
|
||||
MIX_AIL = 0x10, -- 0001 Taileron
|
||||
MIX_ELE = 0x20, -- 0010 For VTIAL and Delta-ELEVON
|
||||
MIX_RUD = 0x30, -- 0011 For VTIAL
|
||||
|
||||
MIX_RUD_REV = 0x40, -- 0100 For VTIAL
|
||||
MIX_ELE_REV = 0x50, -- 0101 For VTIAL and Delta-ELEVON A
|
||||
MIX_AIL_REV = 0x60, -- 0110 Taileron
|
||||
MIX_NORM_REV = 0x70 -- 0111
|
||||
}
|
||||
|
||||
local AIRCRAFT_TYPE = {
|
||||
PLANE = 0,
|
||||
HELI = 1,
|
||||
GLIDER = 2,
|
||||
DRONE = 3
|
||||
}
|
||||
local aircraft_type_text = {[0]="Plane","Heli","Glider","Drone"}
|
||||
|
||||
local WING_TYPE = {
|
||||
AIL_1 = 0, --1
|
||||
AIL_2 = 1, --2
|
||||
FLAPERON = 2, --2
|
||||
AIL_1_FLP_1 = 3, --2
|
||||
AIL_2_FLP_1 = 4, --3
|
||||
AIL_2_FLP_2 = 5, --4
|
||||
ELEVON_A = 6, --2
|
||||
ELEVON_B = 7 --2
|
||||
}
|
||||
|
||||
local wing_type_text = {[0]="Normal","Dual Ail","Flapperon", "Ail + Flp","Dual Ail + Flp","Dual Ail/Flp","Elevon A","Elevon B"}
|
||||
|
||||
local TAIL_TYPE = {
|
||||
RUD_1 = 0, -- 1
|
||||
RUD_1_ELEV_1 = 1, -- 2
|
||||
RUD_1_ELEV_2 = 2, -- 3
|
||||
RUD_2_ELEV_1 = 3, -- 3
|
||||
RUD_2_ELEV_2 = 4, -- 4
|
||||
VTAIL_A = 5, -- 2
|
||||
VTAIL_B = 6, -- 2
|
||||
TRAILERON_A = 7, -- 3
|
||||
TRAILERON_B = 8, -- 3
|
||||
TRAILERON_A_R2 = 9, -- 3
|
||||
TRAILERON_B_R2 = 10 -- 3
|
||||
}
|
||||
local tail_type_text = {[0]="Rud Only","Normal","Rud + Dual Ele","Dual Rud + Elv","Dual Rud/Ele",
|
||||
"VTail A","VTail B","Taileron A","Taileron B","Taileron A + 2x Rud","Taileron B + 2x Rud"}
|
||||
|
||||
local CH_MODE_TYPE = {
|
||||
NORMAL = 0,
|
||||
REVERSE = 1,
|
||||
USE_TX = 3
|
||||
}
|
||||
|
||||
local PORT = {
|
||||
PORT1 = 0,
|
||||
PORT2 = 1,
|
||||
PORT3 = 2,
|
||||
PORT4 = 3,
|
||||
PORT5 = 4,
|
||||
PORT6 = 5,
|
||||
PORT7 = 6,
|
||||
PORT8 = 7,
|
||||
PORT9 = 8,
|
||||
PORT10 = 9,
|
||||
PORT11 = 10,
|
||||
PORT12 = 11
|
||||
}
|
||||
|
||||
local MEMU_VAR = {
|
||||
AIRCRAFT_TYPE = 1001,
|
||||
WING_TYPE = 1002,
|
||||
TAIL_TYPE = 1003,
|
||||
|
||||
CH_BASE = 1010,
|
||||
CH_THR = 1010,
|
||||
|
||||
CH_L_AIL = 1011,
|
||||
CH_R_AIL = 1012,
|
||||
CH_L_FLP = 1013,
|
||||
CH_R_FLP = 1014,
|
||||
|
||||
CH_L_RUD = 1015,
|
||||
CH_R_RUD = 1016,
|
||||
CH_L_ELE = 1017,
|
||||
CH_R_ELE = 1018,
|
||||
|
||||
PORT_BASE = 1020,
|
||||
PORT1_MODE = 1020,
|
||||
PORT2_MODE = 1021,
|
||||
PORT3_MODE = 1022,
|
||||
PORT4_MODE = 1023,
|
||||
PORT5_MODE = 1024,
|
||||
PORT6_MODE = 1025,
|
||||
PORT7_MODE = 1026,
|
||||
PORT8_MODE = 1027,
|
||||
PORT9_MODE = 1028,
|
||||
PORT10_MODE = 1029,
|
||||
PORT11_MODE = 1030,
|
||||
PORT12_MODE = 1031,
|
||||
|
||||
DATA_END = 1040
|
||||
}
|
||||
|
||||
|
||||
-- MENU DATA Management
|
||||
local MENU_DATA = {} -- Store the variables used in the Menus.
|
||||
|
||||
|
||||
---- DSM_ChannelInfo ---------------------------------
|
||||
-- First byte describe Special Mixing (Vtail/Elevon = 0x20)
|
||||
--VTAIL
|
||||
--(0x00 0x06) CH_TYPE.ELE+CH_TYPE.RUD (0x02+0x04 = 0x06)
|
||||
--(0x20 0x86) CH_TYPE.ELE+CH_TYPE.RUD+CH_TYPE.SLAVE (0x02+0x04+0x80 = 0x86)
|
||||
|
||||
-- The 2nd byte describes the functionality of the port
|
||||
--
|
||||
-- Single Example: CH_TYPE.AIL (0x01) Aileron
|
||||
-- Reverse Example: CH_TYPE.AIL+CH_TYPE.REVERSE (0x01+0x20=0x21) Reverse Aileron
|
||||
-- Slave Example: CH_TYPE.AIL+CH_TYPE.SLAVE (0x01+0x80) -- 2nd servo Aileron
|
||||
|
||||
-- Elevon Example: CH_TYPE.AIL+CH_TYPE.ELE (0x01+0x02 = 0x03) -- Elevon
|
||||
-- Elevon Example: CH_TYPE.AIL+CH_TYPE.ELE+CH_TYPE.SLAVE (0x01+0x02+0x80 = 0x83) -- Slave Elevon
|
||||
|
||||
-- RudElv (VTail) Example: CH_TYPE.ELE+CH_TYPE.RUD (0x02+0x04 = 0x06) -- Rudevator
|
||||
-- RudElv (VTail) Example: CH_TYPE.ELE+CH_TYPE.RUD+CH_TYPE.SLAVE (0x02+0x04+0x80 = 0x86) -- Rudevator Slave
|
||||
|
||||
-- DEFAULT Simple Plane Port configuration (The Configuration tool will overrride this)
|
||||
MODEL.DSM_ChannelInfo= {[0]= -- Start array at position 0
|
||||
{[0]= CH_MIX_TYPE.MIX_NORM, CH_TYPE.THR}, -- Ch1 Thr (0x40)
|
||||
{[0]= CH_MIX_TYPE.MIX_NORM, CH_TYPE.AIL}, -- Ch2 Ail (0x01)
|
||||
{[0]= CH_MIX_TYPE.MIX_NORM, CH_TYPE.ELE}, -- Ch2 ElE (0x02)
|
||||
{[0]= CH_MIX_TYPE.MIX_NORM, CH_TYPE.RUD}, -- Ch4 Rud (0x04)
|
||||
{[0]= CH_MIX_TYPE.MIX_NORM, CH_TYPE.NONE}, -- Ch5 Gear (0x00)
|
||||
{[0]= CH_MIX_TYPE.MIX_NORM, CH_TYPE.NONE}, -- Ch6 Aux1 (0x00)
|
||||
{[0]= CH_MIX_TYPE.MIX_NORM, CH_TYPE.NONE}, -- Ch7 Aux2 (0x00)
|
||||
{[0]= CH_MIX_TYPE.MIX_NORM, CH_TYPE.NONE}, -- Ch8 Aux3 (0x00)
|
||||
{[0]= CH_MIX_TYPE.MIX_NORM, CH_TYPE.NONE}, -- Ch9 Aux4 (0x00)
|
||||
{[0]= CH_MIX_TYPE.MIX_NORM, CH_TYPE.NONE}, -- Ch10 Aux5 (0x00)
|
||||
{[0]= CH_MIX_TYPE.MIX_NORM, CH_TYPE.NONE}, -- Ch11 Aux6 (0x00)
|
||||
{[0]= CH_MIX_TYPE.MIX_NORM, CH_TYPE.NONE} -- Ch12 Aux7 (0x00)
|
||||
}
|
||||
|
||||
function ModelLib.printChannelSummary(a,w,t)
|
||||
-- Summary
|
||||
print("CHANNEL INFORMATION")
|
||||
print("Aircraft:".. (aircraft_type_text[MENU_DATA[MEMU_VAR.AIRCRAFT_TYPE]] or "--"))
|
||||
print("Wing Type:".. (wing_type_text[MENU_DATA[MEMU_VAR.WING_TYPE]] or "--"))
|
||||
print("Tail Type:".. (tail_type_text[MENU_DATA[MEMU_VAR.TAIL_TYPE]] or "--"))
|
||||
print("Thr:".. (MODEL.PORT_TEXT[(MENU_DATA[MEMU_VAR.CH_THR] or 30)] or "--")) -- use fake ch30 for non existing channels
|
||||
print("LAil:".. (MODEL.PORT_TEXT[(MENU_DATA[MEMU_VAR.CH_L_AIL] or 30)] or "--"))
|
||||
print("RAil:".. (MODEL.PORT_TEXT[(MENU_DATA[MEMU_VAR.CH_R_AIL] or 30)] or "--"))
|
||||
print("LFlp:".. (MODEL.PORT_TEXT[(MENU_DATA[MEMU_VAR.CH_L_FLP] or 30)] or "--"))
|
||||
print("RFlp:".. (MODEL.PORT_TEXT[(MENU_DATA[MEMU_VAR.CH_R_FLP] or 30)] or "--"))
|
||||
print("LEle:".. (MODEL.PORT_TEXT[(MENU_DATA[MEMU_VAR.CH_L_ELE] or 30)] or "--"))
|
||||
print("REle:".. (MODEL.PORT_TEXT[(MENU_DATA[MEMU_VAR.CH_R_ELE] or 30)] or "--"))
|
||||
print("LRud:".. (MODEL.PORT_TEXT[(MENU_DATA[MEMU_VAR.CH_L_RUD] or 30)] or "--"))
|
||||
print("RRud:".. (MODEL.PORT_TEXT[(MENU_DATA[MEMU_VAR.CH_R_RUD] or 30)] or "--"))
|
||||
end
|
||||
|
||||
function ModelLib.printServoReverseInfo()
|
||||
print("SERVO Normal/Reverse INFORMATION")
|
||||
for i=0, TX_CHANNELS-1 do
|
||||
local s="--"
|
||||
if (MENU_DATA[MEMU_VAR.PORT1_MODE+i] or 0) == 0 then s="NORMAL" else s="REVERSE" end
|
||||
print(string.format("Port%d: %s", i+1, s))
|
||||
end
|
||||
end
|
||||
|
||||
function ModelLib.channelType2String(byte1, byte2)
|
||||
local s = ""
|
||||
|
||||
if (byte2==0) then return s end;
|
||||
|
||||
if (bit32.band(byte2,CH_TYPE.AIL)>0) then s=s.."Ail" end
|
||||
if (bit32.band(byte2,CH_TYPE.ELE)>0) then s=s.."Ele" end
|
||||
if (bit32.band(byte2,CH_TYPE.RUD)>0) then s=s.."Rud" end
|
||||
if (bit32.band(byte2,CH_TYPE.THR)>0) then s=s.."Thr" end
|
||||
|
||||
if (bit32.band(byte2,CH_TYPE.REVERSE)>0) then s=s.."-" end
|
||||
|
||||
if (bit32.band(byte2,CH_TYPE.SLAVE)>0) then s=s.." Slv" end
|
||||
|
||||
if (byte1==CH_MIX_TYPE.MIX_NORM) then s=s.." "
|
||||
elseif (byte1==CH_MIX_TYPE.MIX_AIL) then s=s.." M_Ail"
|
||||
elseif (byte1==CH_MIX_TYPE.MIX_ELE) then s=s.." M_Ele"
|
||||
elseif (byte1==CH_MIX_TYPE.MIX_RUD) then s=s.." M_Rud"
|
||||
elseif (byte1==CH_MIX_TYPE.MIX_RUD_REV) then s=s.." M_Rud-"
|
||||
elseif (byte1==CH_MIX_TYPE.MIX_ELE_REV) then s=s.." M_Ele-"
|
||||
elseif (byte1==CH_MIX_TYPE.MIX_AIL_REV) then s=s.." M_Ail-"
|
||||
elseif (byte1==CH_MIX_TYPE.MIX_NORM_REV) then s=s.." M-"
|
||||
end
|
||||
|
||||
return s;
|
||||
end
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------------------------
|
||||
-- Read the model information from OTX/ETX
|
||||
|
||||
local function getModuleChannelOrder(num)
|
||||
--Determine fist 4 channels order
|
||||
local channel_names={}
|
||||
local stick_names = {[0]= "R", "E", "T", "A" }
|
||||
local ch_order=num
|
||||
if (ch_order == -1) then
|
||||
channel_names[0] = stick_names[3]
|
||||
channel_names[1] = stick_names[1]
|
||||
channel_names[2] = stick_names[2]
|
||||
channel_names[3] = stick_names[0]
|
||||
else
|
||||
channel_names[bit32.band(ch_order,3)] = stick_names[3]
|
||||
ch_order = math.floor(ch_order/4)
|
||||
channel_names[bit32.band(ch_order,3)] = stick_names[1]
|
||||
ch_order = math.floor(ch_order/4)
|
||||
channel_names[bit32.band(ch_order,3)] = stick_names[2]
|
||||
ch_order = math.floor(ch_order/4)
|
||||
channel_names[bit32.band(ch_order,3)] = stick_names[0]
|
||||
end
|
||||
|
||||
local s = ""
|
||||
for i=0,3 do
|
||||
s=s..channel_names[i]
|
||||
end
|
||||
return s
|
||||
end
|
||||
|
||||
function ModelLib.ReadTxModelData()
|
||||
local TRANSLATE_AETR_TO_TAER=false
|
||||
local table = model.getInfo() -- Get the model name
|
||||
MODEL.modelName = table.name
|
||||
|
||||
local module = model.getModule(0) -- Internal
|
||||
if (module==nil or module.Type~=6) then module = model.getModule(1) end -- External
|
||||
if (module~=nil) then
|
||||
if (module.Type==6 ) then -- MULTI-MODULE
|
||||
local chOrder = module.channelsOrder
|
||||
local s = getModuleChannelOrder(chOrder)
|
||||
Log.LOG_write("MultiChannel Ch Order: [%s] %s\n",chOrder,s)
|
||||
|
||||
if (s=="AETR") then TRANSLATE_AETR_TO_TAER=true
|
||||
else TRANSLATE_AETR_TO_TAER=false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Log.LOG_write("MODEL NAME = %s\n",MODEL.modelName)
|
||||
|
||||
-- Read Ch1 to Ch10
|
||||
local i= 0
|
||||
for i = 0, TX_CHANNELS-1 do
|
||||
local ch = model.getOutput(i) -- Zero base
|
||||
if (ch~=nil) then
|
||||
MODEL.modelOutputChannel[i] = ch
|
||||
if (string.len(ch.name)==0) then
|
||||
ch.formatCh = string.format("TX:Ch%i",i+1)
|
||||
else
|
||||
ch.formatCh = string.format("TX:Ch%i/%s",i+1,ch.name or "--")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Translate AETR to TAER
|
||||
-- TODO: Check if there is a way to know how to the TX is configured, since if it is
|
||||
-- already TAER, is not needed
|
||||
|
||||
if (TRANSLATE_AETR_TO_TAER) then
|
||||
Log.LOG_write("Applying AETR -> TAER translation\n")
|
||||
local ail = MODEL.modelOutputChannel[0]
|
||||
local elv = MODEL.modelOutputChannel[1]
|
||||
local thr = MODEL.modelOutputChannel[2]
|
||||
|
||||
MODEL.modelOutputChannel[0] = thr
|
||||
MODEL.modelOutputChannel[1] = ail
|
||||
MODEL.modelOutputChannel[2] = elv
|
||||
end
|
||||
|
||||
-- Create the Port Text to be used
|
||||
Log.LOG_write("Ports/Channels:\n")
|
||||
for i = 0, TX_CHANNELS-1 do
|
||||
local ch = MODEL.modelOutputChannel[i]
|
||||
if (ch~=nil) then
|
||||
MODEL.TX_CH_TEXT[i] = ch.formatCh
|
||||
MODEL.PORT_TEXT[i] = string.format("P%i (%s) ",i+1,MODEL.TX_CH_TEXT[i])
|
||||
|
||||
Log.LOG_write("Port%d %s [%d,%d] Rev=%d, Off=%d, ppmC=%d, syn=%d\n",i+1,MODEL.TX_CH_TEXT[i],math.floor(ch.min/10),math.floor(ch.max/10), ch.revert, ch.offset, ch.ppmCenter, ch.symetrical)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
----------------------- FILE MANAGEMENT ---------------------------------------------
|
||||
-- Create a fairly unique name for a model..combination of name and a hash
|
||||
-- TODO: Check with ETX why we can't get the filename used to store the model info
|
||||
-- Improvement request??
|
||||
|
||||
function ModelLib.hashName(mName)
|
||||
local c=10000;
|
||||
|
||||
local prefix = string.gsub(mName,"%.","_") -- Change any "." to "_"
|
||||
prefix = string.gsub(prefix,"% ","_") -- Change any space to "_"
|
||||
prefix = string.sub(prefix,1,5) -- Take the first 5 characters
|
||||
|
||||
-- Simple Hash of the Model Name adding each character
|
||||
for i = 1, #mName do
|
||||
local ch = string.byte(mName,i,i)
|
||||
c=c+ch
|
||||
end
|
||||
|
||||
return (prefix .. c) -- Return Prefix + Hash
|
||||
end
|
||||
|
||||
-- Load Menu Data from a file
|
||||
function ModelLib.ST_LoadFileData()
|
||||
local fname = ModelLib.hashName(MODEL.modelName)..".txt"
|
||||
|
||||
-- Clear Menu Data
|
||||
for i = 0, MEMU_VAR.DATA_END do
|
||||
MENU_DATA[i]=nil
|
||||
end
|
||||
|
||||
print("Loading File:"..fname)
|
||||
|
||||
local dataFile = io.open(DATA_PATH .. "/".. fname, "r") -- read File
|
||||
-- cannot read file???
|
||||
if (dataFile==nil) then return 0 end
|
||||
|
||||
local line = io.read(dataFile, 5000)
|
||||
io.close(dataFile)
|
||||
|
||||
if #line == 0 then return 0 end -- No data??
|
||||
|
||||
-- Process the input, each line is "Var_Id : Value" format
|
||||
-- Store it into MANU_DATA
|
||||
local i=0
|
||||
for k, v in string.gmatch(line, "(%d+):(%d+)") do
|
||||
--print(string.format("Read MENU_DATA[%d]:[%d]",k, v))
|
||||
MENU_DATA[k+0]=v+0 -- do aritmentic to convert string to number
|
||||
i=i+1
|
||||
end
|
||||
|
||||
local currAircraftType = MENU_DATA[MEMU_VAR.AIRCRAFT_TYPE]
|
||||
local currWingType = MENU_DATA[MEMU_VAR.WING_TYPE]
|
||||
local currTailType = MENU_DATA[MEMU_VAR.TAIL_TYPE]
|
||||
|
||||
print("Validation")
|
||||
print(string.format("AIRCRAFT_TYPE(%d)=%s", MEMU_VAR.AIRCRAFT_TYPE,aircraft_type_text[currAircraftType]))
|
||||
print(string.format("WING_TYPE(%d)=%s", MEMU_VAR.WING_TYPE, wing_type_text[currWingType]))
|
||||
print(string.format("TAIL_TYPE(%d)=%s", MEMU_VAR.TAIL_TYPE, tail_type_text[currTailType]))
|
||||
|
||||
ModelLib.printChannelSummary()
|
||||
ModelLib.printServoReverseInfo()
|
||||
|
||||
-- Return 0 if no lines processed, 1 otherwise
|
||||
if (i > 0) then return 1 else return 0 end
|
||||
end
|
||||
|
||||
-- Saves MENU_DATA to a file
|
||||
function ModelLib.ST_SaveFileData()
|
||||
local fname = ModelLib.hashName(MODEL.modelName)..".txt"
|
||||
|
||||
print("Saving File:"..fname)
|
||||
local dataFile = assert(io.open(DATA_PATH .. "/" .. fname, "w"),"Please create "..DATA_PATH.." folder") -- write File
|
||||
|
||||
-- Foreach MENU_DATA with a value write Var_Id:Value into file
|
||||
for i = 0, MEMU_VAR.DATA_END do
|
||||
if (MENU_DATA[i]~=nil) then
|
||||
--print(string.format("Write MENU_DATA[%s] : %s",i,MENU_DATA[i]))
|
||||
io.write(dataFile,string.format("%s:%s\n",i,MENU_DATA[i]))
|
||||
end
|
||||
end
|
||||
io.close(dataFile)
|
||||
end
|
||||
|
||||
-- This Creates the Servo Settings that will be used to pass to
|
||||
-- Forward programming
|
||||
function ModelLib.CreateDSMPortChannelInfo()
|
||||
local function ApplyWingMixA(b2)
|
||||
-- ELEVON
|
||||
if (b2==CH_TYPE.AIL+CH_TYPE.ELE) then return CH_MIX_TYPE.MIX_ELE end; -- 0x03
|
||||
if (b2==CH_TYPE.AIL+CH_TYPE.ELE+CH_TYPE.SLAVE) then return CH_MIX_TYPE.MIX_NORM end; -- 0x83
|
||||
end
|
||||
|
||||
local function ApplyWingMixB(b2)
|
||||
-- ELEVON
|
||||
if (b2==CH_TYPE.AIL+CH_TYPE.ELE) then return CH_MIX_TYPE.MIX_NORM end; -- 0x03
|
||||
if (b2==CH_TYPE.AIL+CH_TYPE.ELE+CH_TYPE.SLAVE) then return CH_MIX_TYPE.MIX_ELE end; -- 0x83
|
||||
end
|
||||
|
||||
local function ApplyTailMixA(b2)
|
||||
-- VTAIL
|
||||
-- Default normal/reverse behaviour
|
||||
if (b2==CH_TYPE.RUD+CH_TYPE.ELE) then return CH_MIX_TYPE.MIX_NORM end; -- 0x06
|
||||
if (b2==CH_TYPE.RUD+CH_TYPE.ELE+CH_TYPE.SLAVE) then return CH_MIX_TYPE.MIX_ELE end; -- 0x86
|
||||
|
||||
--TAILERON
|
||||
-- Default normal/reverse behaviour
|
||||
if (b2==CH_TYPE.AIL+CH_TYPE.ELE) then return CH_MIX_TYPE.MIX_NORM end; -- 0x03
|
||||
if (b2==CH_TYPE.AIL+CH_TYPE.ELE+CH_TYPE.SLAVE) then return CH_MIX_TYPE.MIX_AIL end; -- 0x83
|
||||
end
|
||||
|
||||
local function ApplyTailMixB(b2)
|
||||
-- VTAIL
|
||||
-- Default normal/reverse behaviour
|
||||
if (b2==CH_TYPE.RUD+CH_TYPE.ELE) then return CH_MIX_TYPE.MIX_NORM end; -- 0x06
|
||||
if (b2==CH_TYPE.RUD+CH_TYPE.ELE+CH_TYPE.SLAVE) then return CH_MIX_TYPE.MIX_RUD end; -- 0x86
|
||||
|
||||
--TAILERON
|
||||
if (b2==CH_TYPE.AIL+CH_TYPE.ELE) then return CH_MIX_TYPE.MIX_AIL end; -- 0x03
|
||||
if (b2==CH_TYPE.AIL+CH_TYPE.ELE+CH_TYPE.SLAVE) then return CH_MIX_TYPE.MIX_NORM end; -- 0x83
|
||||
end
|
||||
|
||||
local function reverseMix(b)
|
||||
if (b==CH_MIX_TYPE.MIX_NORM) then return CH_MIX_TYPE.MIX_NORM_REV end;
|
||||
if (b==CH_MIX_TYPE.MIX_AIL) then return CH_MIX_TYPE.MIX_AIL_REV end;
|
||||
if (b==CH_MIX_TYPE.MIX_ELE) then return CH_MIX_TYPE.MIX_ELE_REV end;
|
||||
if (b==CH_MIX_TYPE.MIX_RUD) then return CH_MIX_TYPE.MIX_RUD_REV end;
|
||||
return b
|
||||
end
|
||||
|
||||
|
||||
|
||||
local DSM_ChannelInfo = MODEL.DSM_ChannelInfo
|
||||
|
||||
for i=0, TX_CHANNELS-1 do
|
||||
DSM_ChannelInfo[i] = {[0]= CH_MIX_TYPE.MIX_NORM, CH_TYPE.NONE} -- Initialize with no special function
|
||||
end
|
||||
|
||||
local aircraftType = MENU_DATA[MEMU_VAR.AIRCRAFT_TYPE]
|
||||
local wingType = MENU_DATA[MEMU_VAR.WING_TYPE]
|
||||
local tailType = MENU_DATA[MEMU_VAR.TAIL_TYPE]
|
||||
|
||||
local thrCh = MENU_DATA[MEMU_VAR.CH_THR]
|
||||
local lAilCh = MENU_DATA[MEMU_VAR.CH_L_AIL]
|
||||
local rAilCh = MENU_DATA[MEMU_VAR.CH_R_AIL]
|
||||
local lflapCh = MENU_DATA[MEMU_VAR.CH_L_FLP]
|
||||
local rflapCh = MENU_DATA[MEMU_VAR.CH_R_FLP]
|
||||
|
||||
local lElevCh = MENU_DATA[MEMU_VAR.CH_L_ELE]
|
||||
local rElevCh = MENU_DATA[MEMU_VAR.CH_R_ELE]
|
||||
|
||||
local lRudCh = MENU_DATA[MEMU_VAR.CH_L_RUD]
|
||||
local rRudCh = MENU_DATA[MEMU_VAR.CH_R_RUD]
|
||||
|
||||
-- Channels in menu vars are Zero base, Channel info is 1 based
|
||||
|
||||
-- THR
|
||||
if (thrCh~=nil and thrCh < 10) then DSM_ChannelInfo[thrCh][1]= CH_TYPE.THR end
|
||||
|
||||
-- AIL (Left and Right)
|
||||
if (lAilCh~=nil) then DSM_ChannelInfo[lAilCh][1] = CH_TYPE.AIL end
|
||||
if (rAilCh~=nil) then DSM_ChannelInfo[rAilCh][1] = CH_TYPE.AIL+CH_TYPE.SLAVE end
|
||||
-- ELE (Left and Right)
|
||||
if (lElevCh~=nil) then DSM_ChannelInfo[lElevCh][1] = CH_TYPE.ELE end
|
||||
if (rElevCh~=nil) then DSM_ChannelInfo[rElevCh][1] = CH_TYPE.ELE+CH_TYPE.SLAVE end
|
||||
-- RUD (Left and Right)
|
||||
if (lRudCh~=nil) then DSM_ChannelInfo[lRudCh][1] = CH_TYPE.RUD end
|
||||
if (rRudCh~=nil) then DSM_ChannelInfo[rRudCh][1] = CH_TYPE.RUD+CH_TYPE.SLAVE end
|
||||
|
||||
-- VTAIL: RUD + ELE
|
||||
if (tailType==TAIL_TYPE.VTAIL_A or tailType==TAIL_TYPE.VTAIL_B) then
|
||||
DSM_ChannelInfo[lElevCh][1] = CH_TYPE.RUD+CH_TYPE.ELE
|
||||
DSM_ChannelInfo[rElevCh][1] = CH_TYPE.RUD+CH_TYPE.ELE+CH_TYPE.SLAVE
|
||||
end
|
||||
|
||||
-- TAILERRON: 2-ELE + AIL
|
||||
if (tailType==TAIL_TYPE.TRAILERON_A or tailType==TAIL_TYPE.TRAILERON_A_R2 or
|
||||
tailType==TAIL_TYPE.TRAILERON_B or tailType==TAIL_TYPE.TRAILERON_B_R2) then
|
||||
DSM_ChannelInfo[lElevCh][1] = CH_TYPE.AIL+CH_TYPE.ELE
|
||||
DSM_ChannelInfo[rElevCh][1] = CH_TYPE.AIL+CH_TYPE.ELE+CH_TYPE.SLAVE
|
||||
end
|
||||
|
||||
---- ELEVON : AIL + ELE
|
||||
if (wingType==WING_TYPE.ELEVON_A or wingType==WING_TYPE.ELEVON_B) then
|
||||
DSM_ChannelInfo[lAilCh][1] = CH_TYPE.AIL+CH_TYPE.ELE
|
||||
DSM_ChannelInfo[rAilCh][1] = CH_TYPE.AIL+CH_TYPE.ELE+CH_TYPE.SLAVE
|
||||
end
|
||||
|
||||
------MIXES ---------
|
||||
|
||||
-- TAIL Mixes (Elevator and VTail)
|
||||
if (tailType==TAIL_TYPE.VTAIL_A or tailType==TAIL_TYPE.TRAILERON_A or tailType==TAIL_TYPE.TRAILERON_A_R2) then
|
||||
DSM_ChannelInfo[lElevCh][0] = ApplyTailMixA(DSM_ChannelInfo[lElevCh][1])
|
||||
DSM_ChannelInfo[rElevCh][0] = ApplyTailMixA(DSM_ChannelInfo[rElevCh][1])
|
||||
elseif (tailType==TAIL_TYPE.VTAIL_B or tailType==TAIL_TYPE.TRAILERON_B or tailType==TAIL_TYPE.TRAILERON_B_R2) then
|
||||
DSM_ChannelInfo[lElevCh][0] = ApplyTailMixA(DSM_ChannelInfo[lElevCh][1])
|
||||
DSM_ChannelInfo[rElevCh][0] = ApplyTailMixA(DSM_ChannelInfo[rElevCh][1])
|
||||
end
|
||||
|
||||
---- Wing Mixes
|
||||
if (wingType==WING_TYPE.ELEVON_A) then
|
||||
DSM_ChannelInfo[lAilCh][0] = ApplyWingMixA(DSM_ChannelInfo[lAilCh][1])
|
||||
DSM_ChannelInfo[rAilCh][0] = ApplyWingMixA(DSM_ChannelInfo[rAilCh][1])
|
||||
elseif (wingType==WING_TYPE.ELEVON_B) then
|
||||
DSM_ChannelInfo[lAilCh][0] = ApplyWingMixB(DSM_ChannelInfo[lAilCh][1])
|
||||
DSM_ChannelInfo[rAilCh][0] = ApplyWingMixB(DSM_ChannelInfo[rAilCh][1])
|
||||
end
|
||||
|
||||
-- Apply Gyro Reverse as needed for each channel as long as it is used
|
||||
for i=0, TX_CHANNELS-1 do
|
||||
if (MENU_DATA[MEMU_VAR.PORT_BASE+i]==CH_MODE_TYPE.REVERSE and DSM_ChannelInfo[i][1]>0) then
|
||||
DSM_ChannelInfo[i][0]=reverseMix(DSM_ChannelInfo[i][0])
|
||||
DSM_ChannelInfo[i][1]=DSM_ChannelInfo[i][1]+CH_TYPE.REVERSE
|
||||
end
|
||||
end
|
||||
|
||||
-- Show how it looks
|
||||
for i=0, 9 do
|
||||
local b1,b2 = DSM_ChannelInfo[i][0], DSM_ChannelInfo[i][1]
|
||||
print(string.format("%s (%02X %02X) %s", MODEL.PORT_TEXT[i],
|
||||
b1, b2, ModelLib.channelType2String(b1,b2)))
|
||||
end
|
||||
|
||||
MODEL.AirWingTailDesc = string.format("Aircraft(%s) Wing(%s) Tail(%s)",aircraft_type_text[aircraftType],wing_type_text[wingType],tail_type_text[tailType])
|
||||
end
|
||||
|
||||
function ModelLib.ST_PlaneWingInit(wingType)
|
||||
print("Change Plane WingType:"..wing_type_text[wingType])
|
||||
|
||||
MENU_DATA[MEMU_VAR.WING_TYPE] = wingType
|
||||
|
||||
-- Clear all Wing Data
|
||||
MENU_DATA[MEMU_VAR.CH_L_AIL] = nil
|
||||
MENU_DATA[MEMU_VAR.CH_R_AIL] = nil
|
||||
MENU_DATA[MEMU_VAR.CH_L_FLP] = nil
|
||||
MENU_DATA[MEMU_VAR.CH_R_FLP] = nil
|
||||
|
||||
MENU_DATA[MEMU_VAR.CH_THR] = PORT.PORT1
|
||||
|
||||
-- Default Channel Assisgments for each Wing type
|
||||
|
||||
if (wingType==WING_TYPE.AIL_1) then
|
||||
MENU_DATA[MEMU_VAR.CH_L_AIL] = PORT.PORT2
|
||||
elseif (wingType==WING_TYPE.AIL_2) then
|
||||
MENU_DATA[MEMU_VAR.CH_L_AIL] = PORT.PORT6
|
||||
MENU_DATA[MEMU_VAR.CH_R_AIL] = PORT.PORT2
|
||||
elseif (wingType==WING_TYPE.FLAPERON) then
|
||||
MENU_DATA[MEMU_VAR.CH_L_AIL] = PORT.PORT6
|
||||
MENU_DATA[MEMU_VAR.CH_R_AIL] = PORT.PORT2
|
||||
elseif (wingType==WING_TYPE.AIL_1_FLP_1) then
|
||||
MENU_DATA[MEMU_VAR.CH_L_AIL] = PORT.PORT2
|
||||
MENU_DATA[MEMU_VAR.CH_L_FLP] = PORT.PORT6
|
||||
elseif (wingType==WING_TYPE.AIL_2_FLP_1) then
|
||||
MENU_DATA[MEMU_VAR.CH_L_AIL] = PORT.PORT6
|
||||
MENU_DATA[MEMU_VAR.CH_R_AIL] = PORT.PORT2
|
||||
MENU_DATA[MEMU_VAR.CH_L_FLP] = PORT.PORT5
|
||||
elseif (wingType==WING_TYPE.AIL_2_FLP_2) then
|
||||
MENU_DATA[MEMU_VAR.CH_L_AIL] = PORT.PORT6
|
||||
MENU_DATA[MEMU_VAR.CH_R_AIL] = PORT.PORT2
|
||||
MENU_DATA[MEMU_VAR.CH_R_FLP] = PORT.PORT5
|
||||
MENU_DATA[MEMU_VAR.CH_L_FLP] = PORT.PORT7
|
||||
elseif (wingType==WING_TYPE.ELEVON_A) then
|
||||
MENU_DATA[MEMU_VAR.CH_L_AIL] = PORT.PORT2
|
||||
MENU_DATA[MEMU_VAR.CH_R_AIL] = PORT.PORT3
|
||||
elseif (wingType==WING_TYPE.ELEVON_B) then
|
||||
MENU_DATA[MEMU_VAR.CH_L_AIL] = PORT.PORT3
|
||||
MENU_DATA[MEMU_VAR.CH_R_AIL] = PORT.PORT2
|
||||
else -- Assume normal
|
||||
print("ERROR: Invalid Wing Type")
|
||||
end
|
||||
|
||||
|
||||
ModelLib.printChannelSummary()
|
||||
end
|
||||
|
||||
function ModelLib.ST_PlaneTailInit(tailType)
|
||||
if (MENU_DATA[MEMU_VAR.WING_TYPE]==WING_TYPE.ELEVON_A or
|
||||
MENU_DATA[MEMU_VAR.WING_TYPE]==WING_TYPE.ELEVON_B) then
|
||||
tailType = TAIL_TYPE.RUD_1 -- Delta only have ruder
|
||||
end
|
||||
|
||||
print("Change Plane Tail Type:"..tail_type_text[tailType])
|
||||
|
||||
-- Clear all data for Tail
|
||||
MENU_DATA[MEMU_VAR.TAIL_TYPE] = tailType
|
||||
MENU_DATA[MEMU_VAR.CH_L_ELE] = nil
|
||||
MENU_DATA[MEMU_VAR.CH_R_ELE] = nil
|
||||
MENU_DATA[MEMU_VAR.CH_L_RUD] = nil
|
||||
MENU_DATA[MEMU_VAR.CH_R_RUD] = nil
|
||||
|
||||
-- Setup Channels for different Tail types
|
||||
if (tailType == TAIL_TYPE.RUD_1) then
|
||||
MENU_DATA[MEMU_VAR.CH_L_RUD] = PORT.PORT4
|
||||
elseif (tailType == TAIL_TYPE.RUD_1_ELEV_1) then
|
||||
MENU_DATA[MEMU_VAR.CH_L_ELE] = PORT.PORT3
|
||||
MENU_DATA[MEMU_VAR.CH_L_RUD] = PORT.PORT4
|
||||
elseif (tailType == TAIL_TYPE.RUD_1_ELEV_2) then
|
||||
MENU_DATA[MEMU_VAR.CH_L_ELE] = PORT.PORT5
|
||||
MENU_DATA[MEMU_VAR.CH_R_ELE] = PORT.PORT3
|
||||
MENU_DATA[MEMU_VAR.CH_L_RUD] = PORT.PORT4
|
||||
elseif (tailType == TAIL_TYPE.RUD_2_ELEV_1) then
|
||||
MENU_DATA[MEMU_VAR.CH_L_ELE] = PORT.PORT3
|
||||
MENU_DATA[MEMU_VAR.CH_L_RUD] = PORT.PORT4
|
||||
MENU_DATA[MEMU_VAR.CH_R_RUD] = PORT.PORT5
|
||||
elseif (tailType == TAIL_TYPE.RUD_2_ELEV_2) then
|
||||
MENU_DATA[MEMU_VAR.CH_L_ELE] = PORT.PORT5
|
||||
MENU_DATA[MEMU_VAR.CH_R_ELE] = PORT.PORT3
|
||||
MENU_DATA[MEMU_VAR.CH_L_RUD] = PORT.PORT4
|
||||
MENU_DATA[MEMU_VAR.CH_R_RUD] = PORT.PORT6
|
||||
elseif (tailType == TAIL_TYPE.VTAIL_A or tailType == TAIL_TYPE.VTAIL_B) then
|
||||
MENU_DATA[MEMU_VAR.CH_L_ELE] = PORT.PORT4
|
||||
MENU_DATA[MEMU_VAR.CH_R_ELE] = PORT.PORT3
|
||||
elseif (tailType == TAIL_TYPE.TRAILERON_A or tailType==TAIL_TYPE.TRAILERON_A_R2 or
|
||||
tailType == TAIL_TYPE.TRAILERON_B or tailType==TAIL_TYPE.TRAILERON_B_R2) then
|
||||
MENU_DATA[MEMU_VAR.CH_L_RUD] = PORT.PORT4
|
||||
MENU_DATA[MEMU_VAR.CH_L_ELE] = PORT.PORT5
|
||||
MENU_DATA[MEMU_VAR.CH_R_ELE] = PORT.PORT3
|
||||
else -- Assume Normal
|
||||
print("ERROR:invalid Tail Type")
|
||||
end
|
||||
|
||||
if (tailType == TAIL_TYPE.TRAILERON_A_R2 or tailType==TAIL_TYPE.TRAILERON_B_R2) then
|
||||
MENU_DATA[MEMU_VAR.CH_R_RUD] = PORT.PORT7
|
||||
end
|
||||
|
||||
ModelLib.printChannelSummary()
|
||||
end
|
||||
|
||||
function ModelLib.ST_GliderWingInit(wingType)
|
||||
print("Change Glider WingType:"..wing_type_text[wingType])
|
||||
|
||||
MENU_DATA[MEMU_VAR.WING_TYPE] = wingType
|
||||
|
||||
-- Clear all Wing Data
|
||||
MENU_DATA[MEMU_VAR.CH_L_AIL] = nil
|
||||
MENU_DATA[MEMU_VAR.CH_R_AIL] = nil
|
||||
MENU_DATA[MEMU_VAR.CH_L_FLP] = nil
|
||||
MENU_DATA[MEMU_VAR.CH_R_FLP] = nil
|
||||
MENU_DATA[MEMU_VAR.CH_THR] = PORT.PORT6
|
||||
|
||||
-- Default Channel Assisgments for each Wing type
|
||||
|
||||
if (wingType==WING_TYPE.AIL_1) then
|
||||
MENU_DATA[MEMU_VAR.CH_L_AIL] = PORT.PORT1
|
||||
elseif (wingType==WING_TYPE.AIL_2) then
|
||||
MENU_DATA[MEMU_VAR.CH_L_AIL] = PORT.PORT1
|
||||
MENU_DATA[MEMU_VAR.CH_R_AIL] = PORT.PORT2
|
||||
elseif (wingType==WING_TYPE.AIL_2_FLP_1) then
|
||||
MENU_DATA[MEMU_VAR.CH_L_AIL] = PORT.PORT1
|
||||
MENU_DATA[MEMU_VAR.CH_R_AIL] = PORT.PORT2
|
||||
MENU_DATA[MEMU_VAR.CH_L_FLP] = PORT.PORT5
|
||||
elseif (wingType==WING_TYPE.AIL_2_FLP_2) then
|
||||
MENU_DATA[MEMU_VAR.CH_L_AIL] = PORT.PORT1
|
||||
MENU_DATA[MEMU_VAR.CH_R_AIL] = PORT.PORT2
|
||||
MENU_DATA[MEMU_VAR.CH_L_FLP] = PORT.PORT5
|
||||
MENU_DATA[MEMU_VAR.CH_R_FLP] = PORT.PORT6
|
||||
MENU_DATA[MEMU_VAR.CH_THR] = PORT.PORT7
|
||||
elseif (wingType==WING_TYPE.ELEVON_A) then
|
||||
MENU_DATA[MEMU_VAR.CH_L_AIL] = PORT.PORT1
|
||||
MENU_DATA[MEMU_VAR.CH_R_AIL] = PORT.PORT2
|
||||
elseif (wingType==WING_TYPE.ELEVON_B) then
|
||||
MENU_DATA[MEMU_VAR.CH_L_AIL] = PORT.PORT2
|
||||
MENU_DATA[MEMU_VAR.CH_R_AIL] = PORT.PORT1
|
||||
else -- Assume normal
|
||||
print("ERROR: Invalid Wing Type")
|
||||
end
|
||||
|
||||
ModelLib.printChannelSummary()
|
||||
end
|
||||
|
||||
function ModelLib.ST_GliderTailInit(tailType)
|
||||
if (MENU_DATA[MEMU_VAR.WING_TYPE]==WING_TYPE.ELEVON_A) then
|
||||
tailType = TAIL_TYPE.RUD_1 -- Delta only have ruder
|
||||
end
|
||||
|
||||
print("Change Glider Tail Type:"..tail_type_text[tailType])
|
||||
|
||||
-- Clear all data for Tail
|
||||
MENU_DATA[MEMU_VAR.TAIL_TYPE] = tailType
|
||||
MENU_DATA[MEMU_VAR.CH_L_ELE] = nil
|
||||
MENU_DATA[MEMU_VAR.CH_R_ELE] = nil
|
||||
MENU_DATA[MEMU_VAR.CH_L_RUD] = nil
|
||||
MENU_DATA[MEMU_VAR.CH_R_RUD] = nil
|
||||
|
||||
-- Setup Channels for different Tail types
|
||||
if (tailType == TAIL_TYPE.RUD_1) then
|
||||
MENU_DATA[MEMU_VAR.CH_L_RUD] = PORT.PORT4
|
||||
elseif (tailType == TAIL_TYPE.RUD_1_ELEV_1) then
|
||||
MENU_DATA[MEMU_VAR.CH_L_ELE] = PORT.PORT3
|
||||
MENU_DATA[MEMU_VAR.CH_L_RUD] = PORT.PORT4
|
||||
elseif (tailType == TAIL_TYPE.VTAIL_A) then
|
||||
MENU_DATA[MEMU_VAR.CH_L_ELE] = PORT.PORT4
|
||||
MENU_DATA[MEMU_VAR.CH_R_ELE] = PORT.PORT3
|
||||
elseif (tailType == TAIL_TYPE.VTAIL_B) then
|
||||
MENU_DATA[MEMU_VAR.CH_L_ELE] = PORT.PORT3
|
||||
MENU_DATA[MEMU_VAR.CH_R_ELE] = PORT.PORT4
|
||||
else -- Assume Normal
|
||||
print("ERROR: Invalid Tail Type")
|
||||
end
|
||||
|
||||
ModelLib.printChannelSummary()
|
||||
end
|
||||
|
||||
|
||||
function ModelLib.ST_AircraftInit(aircraftType)
|
||||
MENU_DATA[MEMU_VAR.AIRCRAFT_TYPE] = aircraftType
|
||||
|
||||
print("Change Aircraft:".. aircraft_type_text[aircraftType])
|
||||
|
||||
-- Setup Default Aircraft Wing/Tail
|
||||
if (aircraftType==AIRCRAFT_TYPE.PLANE) then
|
||||
ModelLib.ST_PlaneWingInit(WING_TYPE.AIL_1)
|
||||
ModelLib.ST_PlaneTailInit(TAIL_TYPE.RUD_1_ELEV_1)
|
||||
elseif (aircraftType==AIRCRAFT_TYPE.GLIDER) then
|
||||
ModelLib.ST_GliderWingInit(WING_TYPE.AIL_1)
|
||||
ModelLib.ST_GliderTailInit(TAIL_TYPE.RUD_1_ELEV_1)
|
||||
else
|
||||
ModelLib.ST_PlaneWingInit(WING_TYPE.AIL_1)
|
||||
ModelLib.ST_PlaneTailInit(TAIL_TYPE.RUD_1_ELEV_1)
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
|
||||
-- Setup Initial Default Data for the Menus
|
||||
function ModelLib.ST_Default_Data()
|
||||
print("Initializing Menu DATA")
|
||||
ModelLib.ST_AircraftInit(AIRCRAFT_TYPE.PLANE)
|
||||
|
||||
print("Initializing Servo Reverse from TX output settings")
|
||||
|
||||
MENU_DATA[MEMU_VAR.PORT1_MODE] = CH_MODE_TYPE.NORMAL + MODEL.modelOutputChannel[PORT.PORT1].revert
|
||||
MENU_DATA[MEMU_VAR.PORT2_MODE] = CH_MODE_TYPE.NORMAL + MODEL.modelOutputChannel[PORT.PORT2].revert
|
||||
MENU_DATA[MEMU_VAR.PORT3_MODE] = CH_MODE_TYPE.NORMAL + MODEL.modelOutputChannel[PORT.PORT3].revert
|
||||
MENU_DATA[MEMU_VAR.PORT4_MODE] = CH_MODE_TYPE.NORMAL + MODEL.modelOutputChannel[PORT.PORT4].revert
|
||||
MENU_DATA[MEMU_VAR.PORT5_MODE] = CH_MODE_TYPE.NORMAL + MODEL.modelOutputChannel[PORT.PORT5].revert
|
||||
MENU_DATA[MEMU_VAR.PORT6_MODE] = CH_MODE_TYPE.NORMAL + MODEL.modelOutputChannel[PORT.PORT6].revert
|
||||
MENU_DATA[MEMU_VAR.PORT7_MODE] = CH_MODE_TYPE.NORMAL + MODEL.modelOutputChannel[PORT.PORT7].revert
|
||||
MENU_DATA[MEMU_VAR.PORT8_MODE] = CH_MODE_TYPE.NORMAL + MODEL.modelOutputChannel[PORT.PORT8].revert
|
||||
MENU_DATA[MEMU_VAR.PORT9_MODE] = CH_MODE_TYPE.NORMAL + MODEL.modelOutputChannel[PORT.PORT9].revert
|
||||
MENU_DATA[MEMU_VAR.PORT10_MODE] = CH_MODE_TYPE.NORMAL + MODEL.modelOutputChannel[PORT.PORT10].revert
|
||||
|
||||
ModelLib.printServoReverseInfo()
|
||||
|
||||
end
|
||||
|
||||
|
||||
ModelLib.TX_CHANNELS = TX_CHANNELS
|
||||
ModelLib.MODEL = MODEL
|
||||
ModelLib.CH_TYPE = CH_TYPE
|
||||
ModelLib.CH_MODE_TYPE = CH_MODE_TYPE
|
||||
ModelLib.AIRCRAFT_TYPE = AIRCRAFT_TYPE
|
||||
ModelLib.WING_TYPE = WING_TYPE
|
||||
ModelLib.TAIL_TYPE = TAIL_TYPE
|
||||
ModelLib.MENU_DATA = MENU_DATA
|
||||
ModelLib.MEMU_VAR = MEMU_VAR
|
||||
ModelLib.PORT = PORT
|
||||
ModelLib.DATA_PATH = DATA_PATH
|
||||
|
||||
ModelLib.aircraft_type_text = aircraft_type_text
|
||||
ModelLib.wing_type_text = wing_type_text
|
||||
ModelLib.tail_type_text = tail_type_text
|
||||
|
||||
|
||||
return ModelLib
|
||||
|
@ -1,467 +0,0 @@
|
||||
---- #########################################################################
|
||||
---- # #
|
||||
---- # Copyright (C) OpenTX #
|
||||
-----# #
|
||||
---- # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html #
|
||||
---- # #
|
||||
---- # This program is free software; you can redistribute it and/or modify #
|
||||
---- # it under the terms of the GNU General Public License version 2 as #
|
||||
---- # published by the Free Software Foundation. #
|
||||
---- # #
|
||||
---- # This program is distributed in the hope that it will be useful #
|
||||
---- # but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
---- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
---- # GNU General Public License for more details. #
|
||||
---- # #
|
||||
---- #########################################################################
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- This scrip does the airplane Setup similar to how a a Spektrum radio does
|
||||
-- it. You can select the plane type, the Wing type, etc.
|
||||
-- This settings are needed for ForwardProgramming to send the TX aircraft
|
||||
-- configuration to the RX when in Initial Setup
|
||||
-- Author: Francisco Arzu
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
local Log, menuLib, modelLib, DEBUG_ON, SIMULATION_ON = ... -- Get DebugON from parameters
|
||||
local SETUP_LIB_VERSION = "0.56"
|
||||
|
||||
local DATA_PATH = modelLib.DATA_PATH
|
||||
|
||||
local PHASE = menuLib.PHASE
|
||||
local LINE_TYPE = menuLib.LINE_TYPE
|
||||
|
||||
local MODEL = modelLib.MODEL
|
||||
|
||||
local AIRCRAFT_TYPE = modelLib.AIRCRAFT_TYPE
|
||||
local WING_TYPE = modelLib.WING_TYPE
|
||||
local TAIL_TYPE = modelLib.TAIL_TYPE
|
||||
local CH_MODE_TYPE = modelLib.CH_MODE_TYPE
|
||||
local PORT = modelLib.PORT
|
||||
local MEMU_VAR = modelLib.MEMU_VAR
|
||||
local MENU_DATA = modelLib.MENU_DATA
|
||||
|
||||
local SetupLib = {}
|
||||
|
||||
local lastGoodMenu=0
|
||||
|
||||
------------------- Model Setup Helper functions ----------------------
|
||||
local currAircraftType = -1 -- Current AircraftType selected, and to detect change
|
||||
local currTailType = -1 -- Current WingType selected, and to detect change
|
||||
local currWingType = -1 -- Current TailType selected, and to detect change
|
||||
|
||||
local menuDataChanged = false -- Flag to notify if any data has changed
|
||||
|
||||
|
||||
local function tailTypeCompatible(a,b)
|
||||
|
||||
local function normalize(tt)
|
||||
if (tt==TAIL_TYPE.TRAILERON_A or tt==TAIL_TYPE.TRAILERON_B) then
|
||||
return TAIL_TYPE.TRAILERON_A
|
||||
elseif (tt==TAIL_TYPE.TRAILERON_A_R2 or tt==TAIL_TYPE.TRAILERON_B_R2) then
|
||||
return TAIL_TYPE.TRAILERON_A_R2
|
||||
elseif (tt==TAIL_TYPE.VTAIL_A or tt==TAIL_TYPE.VTAIL_B) then
|
||||
return TAIL_TYPE.VTAIL_A
|
||||
else
|
||||
return tt
|
||||
end
|
||||
end
|
||||
|
||||
return (normalize(a)==normalize(b))
|
||||
end
|
||||
|
||||
|
||||
-- Creates the menus to Render with the GUI
|
||||
local function ST_LoadMenu(menuId)
|
||||
local ctx = menuLib.DSM_Context
|
||||
|
||||
local function portUse(p)
|
||||
local out = ""
|
||||
if p==MENU_DATA[MEMU_VAR.CH_THR] then out = "Thr"
|
||||
elseif p == MENU_DATA[MEMU_VAR.CH_L_AIL] then
|
||||
out=(MENU_DATA[MEMU_VAR.CH_R_AIL] and "Ail_L") or "Ail"
|
||||
elseif p == MENU_DATA[MEMU_VAR.CH_R_AIL] then out="Ail_R"
|
||||
elseif p == MENU_DATA[MEMU_VAR.CH_L_ELE] then
|
||||
out=(MENU_DATA[MEMU_VAR.CH_R_ELE] and "Ele_L") or "Ele"
|
||||
elseif p == MENU_DATA[MEMU_VAR.CH_R_ELE] then out="Ele_R"
|
||||
elseif p == MENU_DATA[MEMU_VAR.CH_L_RUD] then
|
||||
out=(MENU_DATA[MEMU_VAR.CH_R_RUD] and "Rud_L") or "Rud"
|
||||
elseif p == MENU_DATA[MEMU_VAR.CH_R_RUD] then out="Rud_R"
|
||||
elseif p == MENU_DATA[MEMU_VAR.CH_L_FLP] then
|
||||
out=(MENU_DATA[MEMU_VAR.CH_R_FLP] and "Flp_L") or "Flp"
|
||||
elseif p == MENU_DATA[MEMU_VAR.CH_R_FLP] then out="Flp_R"
|
||||
end
|
||||
return out
|
||||
end
|
||||
|
||||
local function formatTXRevert(port)
|
||||
local out = " " .. modelLib.channelType2String(MODEL.DSM_ChannelInfo[port][0], MODEL.DSM_ChannelInfo[port][1]);
|
||||
return out
|
||||
end
|
||||
|
||||
local function Header(p)
|
||||
return MODEL.PORT_TEXT[p].." "..portUse(p)
|
||||
end
|
||||
|
||||
menuLib.clearMenuLines()
|
||||
|
||||
|
||||
if (menuId==0x1000) then -- MAIN MENU
|
||||
ctx.Menu = { MenuId = 0x1000, Text = "Save-Exit ("..MODEL.modelName..")", PrevId = 0, NextId = 0, BackId = 0, TextId=0 }
|
||||
|
||||
if (true) then
|
||||
ctx.MenuLines[4] = { Type = LINE_TYPE.MENU, Text="Save Changes", TextId = 0, ValId = 0x1005 }
|
||||
ctx.MenuLines[5] = { Type = LINE_TYPE.MENU, Text="Discard Changes", TextId = 0, ValId = 0x1006 }
|
||||
ctx.SelLine = 4
|
||||
end
|
||||
lastGoodMenu = menuId
|
||||
elseif (menuId==0x1001) then -- MODEL SETUP
|
||||
local backId = 0xFFF9 -- No changes, just exit
|
||||
local title = "Model Setup ("..MODEL.modelName..")"
|
||||
if (menuDataChanged) then
|
||||
backId = 0x1000 -- Go to Save menu
|
||||
title = title.." *"
|
||||
end
|
||||
ctx.Menu = { MenuId = 0x1001, Text = title, PrevId = 0, NextId = 0, BackId = backId, TextId=0 }
|
||||
ctx.MenuLines[0] = { Type = LINE_TYPE.MENU, Text = "Aircraft Type Setup", ValId = 0x1010,TextId=0 }
|
||||
ctx.MenuLines[1] = { Type = LINE_TYPE.MENU, Text = "Wing & Tail Channels ", ValId = 0x1020, TextId=0 }
|
||||
ctx.MenuLines[3] = { Type = LINE_TYPE.MENU, Text = "Gyro Channel Reverse", ValId = 0x1030, TextId=0 }
|
||||
ctx.MenuLines[5] = { Type = LINE_TYPE.MENU, Text = "WARNING: Changing of Aircraft or Wing will", ValId = 0x1001, TextId=0 }
|
||||
ctx.MenuLines[6] = { Type = LINE_TYPE.MENU, Text = "delete previous Channel/Port assigments.", ValId = 0x1001, TextId=0 }
|
||||
|
||||
ctx.SelLine = 0
|
||||
lastGoodMenu = menuId
|
||||
elseif (menuId==0x1005) then
|
||||
modelLib.printChannelSummary()
|
||||
modelLib.ST_SaveFileData()
|
||||
menuDataChanged = false
|
||||
|
||||
|
||||
local msg1 = "Data saved to: "
|
||||
local msg2 = " "..DATA_PATH.."/"..modelLib.hashName(MODEL.modelName)..".txt"
|
||||
|
||||
ctx.Menu = { MenuId = 0x1005, Text = "Config Saved", PrevId = 0, NextId = 0, BackId = 0, TextId=0 }
|
||||
ctx.MenuLines[2] = { Type = LINE_TYPE.MENU, Text=msg1, TextId = 0, ValId = 0x1005 }
|
||||
ctx.MenuLines[3] = { Type = LINE_TYPE.MENU, Text=msg2, TextId = 0, ValId = 0x1005 }
|
||||
ctx.MenuLines[6] = { Type = LINE_TYPE.MENU, Text="Complete", TextId = 0, ValId = 0xFFF9 }
|
||||
ctx.SelLine = 6
|
||||
lastGoodMenu = menuId
|
||||
elseif (menuId==0x1006) then
|
||||
modelLib.ST_LoadFileData()
|
||||
menuDataChanged = false
|
||||
currAircraftType = MENU_DATA[MEMU_VAR.AIRCRAFT_TYPE]
|
||||
currWingType = MENU_DATA[MEMU_VAR.WING_TYPE]
|
||||
currTailType = MENU_DATA[MEMU_VAR.TAIL_TYPE]
|
||||
|
||||
local msg1 = "Data restored from: "
|
||||
local msg2 = " "..DATA_PATH.."/"..modelLib.hashName(MODEL.modelName)..".txt"
|
||||
|
||||
ctx.Menu = { MenuId = 0x1006, Text = "Discart Changes", PrevId = 0, NextId = 0, BackId = 0, TextId=0 }
|
||||
ctx.MenuLines[2] = { Type = LINE_TYPE.MENU, Text=msg1, TextId = 0, ValId = 0x1006 }
|
||||
ctx.MenuLines[3] = { Type = LINE_TYPE.MENU, Text=msg2, TextId = 0, ValId = 0x1006 }
|
||||
ctx.MenuLines[6] = { Type = LINE_TYPE.MENU, Text="Complete", TextId = 0, ValId = 0xFFF9 }
|
||||
ctx.SelLine = 6
|
||||
lastGoodMenu = menuId
|
||||
elseif (menuId==0x1010) then
|
||||
modelLib.printChannelSummary()
|
||||
ctx.Menu = { MenuId = 0x1010, Text = "Aircraft Type", PrevId = 0, NextId = 0x1011, BackId = 0x1001, TextId=0 }
|
||||
ctx.MenuLines[5] = { Type = LINE_TYPE.LIST_MENU_NC, Text="Aircraft Type", TextId = 0, ValId = MEMU_VAR.AIRCRAFT_TYPE, Min=50, Max=53, Def=50, Val=MENU_DATA[MEMU_VAR.AIRCRAFT_TYPE] }
|
||||
ctx.SelLine = 5
|
||||
lastGoodMenu = menuId
|
||||
elseif (menuId==0x1011) then
|
||||
ctx.Menu = { MenuId = 0x1011, Text = "Model Type:"..modelLib.aircraft_type_text[currAircraftType], PrevId = 0, NextId = 0x1020, BackId = 0x1010, TextId=0 }
|
||||
ctx.MenuLines[5] = { Type = LINE_TYPE.LIST_MENU_NC, Text="Wing Type", TextId = 0, ValId = MEMU_VAR.WING_TYPE, Min=100, Max=107, Def=100, Val=MENU_DATA[MEMU_VAR.WING_TYPE] }
|
||||
ctx.MenuLines[6] = { Type = LINE_TYPE.LIST_MENU_NC, Text="Tail Type", TextId = 0, ValId = MEMU_VAR.TAIL_TYPE, Min=200, Max=210, Def=200, Val=MENU_DATA[MEMU_VAR.TAIL_TYPE] }
|
||||
ctx.SelLine = 5
|
||||
lastGoodMenu = menuId
|
||||
elseif (menuId==0x1020) then
|
||||
------ WING SETUP -------
|
||||
local thr = MENU_DATA[MEMU_VAR.CH_THR]
|
||||
local leftAil = MENU_DATA[MEMU_VAR.CH_L_AIL]
|
||||
local rightAil = MENU_DATA[MEMU_VAR.CH_R_AIL]
|
||||
local leftFlap = MENU_DATA[MEMU_VAR.CH_L_FLP]
|
||||
local rightFlap = MENU_DATA[MEMU_VAR.CH_R_FLP]
|
||||
|
||||
local thrText = "Thr"
|
||||
local leftAilText = "Left Aileron"
|
||||
local rightAilText = "Right Aileron"
|
||||
local leftFlapText = "Left Flap"
|
||||
local rightFlapText = "Right Flap"
|
||||
|
||||
if (rightAil==nil) then leftAilText = "Aileron" end
|
||||
if (rightFlap==nil) then leftFlapText = "Flap" end
|
||||
|
||||
local title = modelLib.aircraft_type_text[currAircraftType].." Wing:"..modelLib.wing_type_text[currWingType]
|
||||
|
||||
ctx.Menu = { MenuId = 0x1020, Text = title, PrevId = 0, NextId = 0x1021, BackId = 0x1011, TextId=0 }
|
||||
|
||||
ctx.MenuLines[0] = { Type = LINE_TYPE.LIST_MENU_NC, Text=thrText, TextId = 0, ValId = MEMU_VAR.CH_THR, Min=0, Max=10, Def=0, Val= thr }
|
||||
|
||||
ctx.MenuLines[2] = { Type = LINE_TYPE.LIST_MENU_NC, Text=leftAilText, TextId = 0, ValId = MEMU_VAR.CH_L_AIL, Min=0, Max=9, Def=0, Val= leftAil }
|
||||
|
||||
if (rightAil~=nil) then
|
||||
ctx.MenuLines[3] = { Type = LINE_TYPE.LIST_MENU_NC, Text=rightAilText, TextId = 0, ValId = MEMU_VAR.CH_R_AIL, Min=0, Max=9, Def=0, Val= rightAil }
|
||||
end
|
||||
|
||||
if (leftFlap~=nil) then
|
||||
ctx.MenuLines[4] = { Type = LINE_TYPE.LIST_MENU_NC, Text=leftFlapText, TextId = 0, ValId = MEMU_VAR.CH_L_FLP, Min=0, Max=9, Def=0, Val= leftFlap }
|
||||
end
|
||||
if (rightFlap~=nil) then
|
||||
ctx.MenuLines[5] = { Type = LINE_TYPE.LIST_MENU_NC, Text=rightFlapText, TextId = 0, ValId = MEMU_VAR.CH_R_FLP, Min=0, Max=9, Def=0, Val= rightFlap }
|
||||
end
|
||||
|
||||
ctx.SelLine = 0
|
||||
lastGoodMenu = menuId
|
||||
|
||||
elseif (menuId==0x1021) then
|
||||
------ TAIL SETUP -------
|
||||
local leftRud = MENU_DATA[MEMU_VAR.CH_L_RUD]
|
||||
local rightRud = MENU_DATA[MEMU_VAR.CH_R_RUD]
|
||||
local leftEle = MENU_DATA[MEMU_VAR.CH_L_ELE]
|
||||
local rightEle = MENU_DATA[MEMU_VAR.CH_R_ELE]
|
||||
|
||||
local leftRudText = "Left Rudder"
|
||||
local rightRudText = "Right Rudder"
|
||||
|
||||
local leftElvText = "Left Elevator"
|
||||
local rightElvText = "Right Elevator"
|
||||
|
||||
if (rightRud==nil) then leftRudText = "Rudder" end
|
||||
if (rightEle==nil) then leftElvText = "Elevator" end
|
||||
|
||||
local title = modelLib.aircraft_type_text[currAircraftType].." Tail:"..modelLib.tail_type_text[currTailType]
|
||||
|
||||
ctx.Menu = { MenuId = 0x1021, Text = title, PrevId = 0, NextId = 0x1001, BackId = 0x1020, TextId=0 }
|
||||
if (leftRud~=nil) then
|
||||
ctx.MenuLines[1] = { Type = LINE_TYPE.LIST_MENU_NC, Text=leftRudText, TextId = 0, ValId = MEMU_VAR.CH_L_RUD, Min=0, Max=9, Def=0, Val= leftRud}
|
||||
end
|
||||
|
||||
if (rightRud~=nil) then
|
||||
ctx.MenuLines[2] = { Type = LINE_TYPE.LIST_MENU_NC, Text=rightRudText, TextId = 0, ValId = MEMU_VAR.CH_R_RUD, Min=0, Max=9, Def=0, Val=rightRud }
|
||||
end
|
||||
|
||||
if (leftEle~=nil) then
|
||||
ctx.MenuLines[4] = { Type = LINE_TYPE.LIST_MENU_NC, Text=leftElvText, TextId = 0, ValId = MEMU_VAR.CH_L_ELE, Min=0, Max=9, Def=0, Val=leftEle }
|
||||
end
|
||||
|
||||
if (rightEle~=nil) then
|
||||
ctx.MenuLines[5] = { Type = LINE_TYPE.LIST_MENU_NC, Text=rightElvText, TextId = 0, ValId = MEMU_VAR.CH_R_ELE, Min=0, Max=9, Def=0, Val=rightEle }
|
||||
end
|
||||
|
||||
ctx.SelLine = 1
|
||||
lastGoodMenu = menuId
|
||||
|
||||
elseif (menuId==0x1030) then
|
||||
modelLib.CreateDSMPortChannelInfo()
|
||||
modelLib.printChannelSummary()
|
||||
|
||||
ctx.Menu = { MenuId = 0x1030, Text = "Gyro Channel Reverse (Port 1-5)", PrevId = 0, NextId = 0x1031, BackId = 0x1001, TextId=0 }
|
||||
ctx.MenuLines[0] = { Type = LINE_TYPE.LIST_MENU_NC, Text=Header(PORT.PORT1), TextId = 0, ValId = MEMU_VAR.PORT1_MODE, Min=300, Max=301, Def=300, Val=MENU_DATA[MEMU_VAR.PORT1_MODE], Format = formatTXRevert(PORT.PORT1) }
|
||||
ctx.MenuLines[1] = { Type = LINE_TYPE.LIST_MENU_NC, Text=Header(PORT.PORT2), TextId = 0, ValId = MEMU_VAR.PORT2_MODE, Min=300, Max=301, Def=300, Val=MENU_DATA[MEMU_VAR.PORT2_MODE], Format = formatTXRevert(PORT.PORT2) }
|
||||
ctx.MenuLines[2] = { Type = LINE_TYPE.LIST_MENU_NC, Text=Header(PORT.PORT3), TextId = 0, ValId = MEMU_VAR.PORT3_MODE, Min=300, Max=301, Def=300, Val=MENU_DATA[MEMU_VAR.PORT3_MODE], Format = formatTXRevert(PORT.PORT3) }
|
||||
ctx.MenuLines[3] = { Type = LINE_TYPE.LIST_MENU_NC, Text=Header(PORT.PORT4), TextId = 0, ValId = MEMU_VAR.PORT4_MODE, Min=300, Max=301, Def=300, Val=MENU_DATA[MEMU_VAR.PORT4_MODE], Format = formatTXRevert(PORT.PORT4) }
|
||||
ctx.MenuLines[4] = { Type = LINE_TYPE.LIST_MENU_NC, Text=Header(PORT.PORT5), TextId = 0, ValId = MEMU_VAR.PORT5_MODE, Min=300, Max=301, Def=300, Val=MENU_DATA[MEMU_VAR.PORT5_MODE], Format = formatTXRevert(PORT.PORT5) }
|
||||
|
||||
ctx.MenuLines[5] = { Type = LINE_TYPE.MENU, Text="Only Thr/Ail/Rud/Ele. This affects AS3X/SAFE reaction dir./b", TextId = 0, ValId = 0x1030 }
|
||||
ctx.MenuLines[6] = { Type = LINE_TYPE.MENU, Text="Any changes, use RX 'Relearn Servo Settings'/b", TextId = 0, ValId = 0x1030 }
|
||||
|
||||
ctx.SelLine = 0
|
||||
lastGoodMenu = menuId
|
||||
elseif (menuId==0x1031) then
|
||||
modelLib.CreateDSMPortChannelInfo()
|
||||
modelLib.printChannelSummary()
|
||||
ctx.Menu = { MenuId = 0x1031, Text = "Gyro Channel Reverse (Port 6-10)", PrevId = 0x1030, NextId = 0, BackId = 0x1001, TextId=0 }
|
||||
ctx.MenuLines[0] = { Type = LINE_TYPE.LIST_MENU_NC, Text=Header(PORT.PORT6), TextId = 0, ValId = MEMU_VAR.PORT6_MODE, Min=300, Max=301, Def=300, Val=MENU_DATA[MEMU_VAR.PORT6_MODE], Format = formatTXRevert(PORT.PORT6) }
|
||||
ctx.MenuLines[1] = { Type = LINE_TYPE.LIST_MENU_NC, Text=Header(PORT.PORT7), TextId = 0, ValId = MEMU_VAR.PORT7_MODE, Min=300, Max=301, Def=300, Val=MENU_DATA[MEMU_VAR.PORT7_MODE], Format = formatTXRevert(PORT.PORT7) }
|
||||
ctx.MenuLines[2] = { Type = LINE_TYPE.LIST_MENU_NC, Text=Header(PORT.PORT8), TextId = 0, ValId = MEMU_VAR.PORT8_MODE, Min=300, Max=301, Def=300, Val=MENU_DATA[MEMU_VAR.PORT8_MODE], Format = formatTXRevert(PORT.PORT8) }
|
||||
ctx.MenuLines[3] = { Type = LINE_TYPE.LIST_MENU_NC, Text=Header(PORT.PORT9), TextId = 0, ValId = MEMU_VAR.PORT9_MODE, Min=300, Max=301, Def=300, Val=MENU_DATA[MEMU_VAR.PORT9_MODE], Format = formatTXRevert(PORT.PORT9) }
|
||||
ctx.MenuLines[4] = { Type = LINE_TYPE.LIST_MENU_NC, Text=Header(PORT.PORT10), TextId = 0, ValId = MEMU_VAR.PORT10_MODE, Min=300, Max=301, Def=300, Val=MENU_DATA[MEMU_VAR.PORT10_MODE], Format = formatTXRevert(PORT.PORT10) }
|
||||
|
||||
ctx.MenuLines[5] = { Type = LINE_TYPE.MENU, Text="Only Thr/Ail/Rud/Ele. This affects AS3X/SAFE reaction dir./b", TextId = 0, ValId = 0x1031 }
|
||||
ctx.MenuLines[6] = { Type = LINE_TYPE.MENU, Text="Any changes, use RX 'Relearn Servo Settings'/b", TextId = 0, ValId = 0x1031 }
|
||||
|
||||
ctx.SelLine = 0
|
||||
lastGoodMenu = menuId
|
||||
else
|
||||
print("NOT IMPLEMENTED")
|
||||
ctx.Menu = { MenuId = 0x0002, Text = "NOT IMPLEMENTED", TextId = 0, PrevId = 0, NextId = 0, BackId = lastGoodMenu }
|
||||
ctx.SelLine = menuLib.BACK_BUTTON
|
||||
end
|
||||
|
||||
menuLib.PostProcessMenu()
|
||||
end
|
||||
|
||||
-- ST_SendReceive
|
||||
-- Main state machine for the Setup menu
|
||||
|
||||
local function ST_SendReceive()
|
||||
local ctx = menuLib.DSM_Context
|
||||
--if (DEBUG_ON>1) then Log.LOG_write("%3.3f %s: ", menuLib.getElapsedTime(), menuLib.phase2String(ctx.Phase)) end
|
||||
|
||||
if ctx.Phase == PHASE.RX_VERSION then -- request RX version
|
||||
ctx.RX.Name = "MODEL SETUP"
|
||||
ctx.RX.Version = SETUP_LIB_VERSION
|
||||
ctx.Phase = PHASE.MENU_TITLE
|
||||
ctx.Menu.MenuId = 0x01001
|
||||
|
||||
ctx.Refresh_Display = true
|
||||
|
||||
|
||||
elseif ctx.Phase == PHASE.WAIT_CMD then
|
||||
|
||||
elseif ctx.Phase == PHASE.MENU_TITLE then -- request menu title
|
||||
ST_LoadMenu(ctx.Menu.MenuId)
|
||||
ctx.Phase = PHASE.WAIT_CMD
|
||||
ctx.Refresh_Display = true
|
||||
|
||||
elseif ctx.Phase == PHASE.VALUE_CHANGING then -- send value
|
||||
local line = ctx.MenuLines[ctx.SelLine] -- Updated Value of SELECTED line
|
||||
|
||||
if (MENU_DATA[line.ValId] ~= line.Val ) then
|
||||
MENU_DATA[line.ValId] = line.Val
|
||||
print(string.format("MENU_DATA[%d/%s]=%d",line.ValId,line.Text, line.Val))
|
||||
menuDataChanged=true
|
||||
end
|
||||
|
||||
ctx.Phase = PHASE.VALUE_CHANGING_WAIT
|
||||
|
||||
elseif ctx.Phase == PHASE.VALUE_CHANGING_WAIT then
|
||||
local line = ctx.MenuLines[ctx.SelLine]
|
||||
|
||||
elseif ctx.Phase == PHASE.VALUE_CHANGE_END then -- send value
|
||||
local line = ctx.MenuLines[ctx.SelLine] -- Updated Value of SELECTED line
|
||||
|
||||
-- Update the menu data from the line
|
||||
if (MENU_DATA[line.ValId] ~= line.Val ) then
|
||||
MENU_DATA[line.ValId] = line.Val
|
||||
print(string.format("MENU_DATA[%d/%s]=%d",line.ValId,line.Text, line.Val))
|
||||
menuDataChanged=true
|
||||
end
|
||||
|
||||
-- Did the aircraft type change?
|
||||
if (currAircraftType ~= MENU_DATA[MEMU_VAR.AIRCRAFT_TYPE]) then
|
||||
currAircraftType = MENU_DATA[MEMU_VAR.AIRCRAFT_TYPE]
|
||||
modelLib.ST_AircraftInit(currAircraftType)
|
||||
currWingType = MENU_DATA[MEMU_VAR.WING_TYPE]
|
||||
currTailType = MENU_DATA[MEMU_VAR.TAIL_TYPE]
|
||||
end
|
||||
|
||||
-- Did the Wing type change?
|
||||
if (currWingType ~= MENU_DATA[MEMU_VAR.WING_TYPE]) then
|
||||
if (currAircraftType==AIRCRAFT_TYPE.GLIDER) then
|
||||
currWingType = MENU_DATA[MEMU_VAR.WING_TYPE]
|
||||
modelLib.ST_GliderWingInit(currWingType)
|
||||
else
|
||||
currWingType = MENU_DATA[MEMU_VAR.WING_TYPE]
|
||||
modelLib.ST_PlaneWingInit(currWingType)
|
||||
|
||||
end
|
||||
|
||||
-- DELTA has only RUDER
|
||||
if ((currWingType==WING_TYPE.ELEVON_A or currWingType==WING_TYPE.ELEVON_B) and TAIL_TYPE~=TAIL_TYPE.RUD_1) then
|
||||
MENU_DATA[MEMU_VAR.TAIL_TYPE] = TAIL_TYPE.RUD_1
|
||||
end
|
||||
end
|
||||
|
||||
--- Did the tail changed?
|
||||
local ntt = MENU_DATA[MEMU_VAR.TAIL_TYPE]
|
||||
if (currTailType ~= ntt) then
|
||||
if (currAircraftType==AIRCRAFT_TYPE.GLIDER) then
|
||||
currTailType = ntt
|
||||
modelLib.ST_GliderTailInit(currTailType)
|
||||
else
|
||||
if (not tailTypeCompatible(currTailType,ntt)) then
|
||||
modelLib.ST_PlaneTailInit(ntt)
|
||||
end
|
||||
currTailType = ntt
|
||||
end
|
||||
end
|
||||
|
||||
ctx.Phase = PHASE.WAIT_CMD
|
||||
elseif ctx.Phase == PHASE.EXIT then
|
||||
ctx.Phase=PHASE.EXIT_DONE
|
||||
end
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Inital List and Image Text for this menus
|
||||
local function ST_Init_Text(rxId)
|
||||
menuLib.clearAllText()
|
||||
|
||||
local List_Values = menuLib.List_Values
|
||||
local List_Text = menuLib.List_Text
|
||||
local Text = menuLib.Text
|
||||
local List_Text_Img = menuLib.List_Text_Img
|
||||
|
||||
-- Channel Names use the Port Text Retrived from OTX/ETX
|
||||
for i = 0, 9 do List_Text[i] = MODEL.PORT_TEXT[i] end
|
||||
List_Text[10]="--"
|
||||
|
||||
-- Aircraft Type
|
||||
List_Text[50+AIRCRAFT_TYPE.PLANE] = "Airplane"; --List_Text_Img[50+AIRCRAFT_TYPE.PLANE] = "at_plane.png|Airplane"
|
||||
List_Text[50+AIRCRAFT_TYPE.GLIDER] = "Glider (Partial work)"; --List_Text_Img[50+AIRCRAFT_TYPE.GLIDER] = "at_glider.png|Glider"
|
||||
List_Text[50+AIRCRAFT_TYPE.HELI] = "Helicopter (Not done)"; --List_Text_Img[50+AIRCRAFT_TYPE.HELI] = "at_heli.png|Helicopter"
|
||||
List_Text[50+AIRCRAFT_TYPE.DRONE] = "Drone (not done)"; --List_Text_Img[50+AIRCRAFT_TYPE.DRONE] = "at_drone.png|Drone"
|
||||
|
||||
-- Wing Types
|
||||
List_Text[100+WING_TYPE.AIL_1] = "Single Ail"; List_Text_Img[100+WING_TYPE.AIL_1] = "wt_1ail.png|Single Aileron"
|
||||
List_Text[100+WING_TYPE.AIL_2] = "Dual Ail"; List_Text_Img[100+WING_TYPE.AIL_2] = "wt_2ail.png|Dual Aileron"
|
||||
List_Text[100+WING_TYPE.FLAPERON] = "Flaperon"; List_Text_Img[100+WING_TYPE.FLAPERON] = "wt_flaperon.png|Flaperon"
|
||||
List_Text[100+WING_TYPE.AIL_1_FLP_1] = "Ail + Flap"; List_Text_Img[100+WING_TYPE.AIL_1_FLP_1] = "wt_1ail_1flp.png|Aileron + Flap"
|
||||
List_Text[100+WING_TYPE.AIL_2_FLP_1] = "Dual Ail + Flap"; List_Text_Img[100+WING_TYPE.AIL_2_FLP_1] = "wt_2ail_1flp.png|Dual Aileron + Flap"
|
||||
List_Text[100+WING_TYPE.AIL_2_FLP_2] = "Dual Ail + Dual Flap"; List_Text_Img[100+WING_TYPE.AIL_2_FLP_2] = "wt_2ail_2flp.png|Dual Aileron + Dual Flap"
|
||||
List_Text[100+WING_TYPE.ELEVON_A] = "Delta/Elevon A"; List_Text_Img[100+WING_TYPE.ELEVON_A] = "wt_elevon.png|Delta/Elevon A"
|
||||
List_Text[100+WING_TYPE.ELEVON_B] = "Delta/Elevon B"; List_Text_Img[100+WING_TYPE.ELEVON_B] = "wt_elevon.png|Delta/Elevon B"
|
||||
|
||||
-- Tail Types
|
||||
List_Text[200+TAIL_TYPE.RUD_1] = "Rudder Only"; List_Text_Img[200+TAIL_TYPE.RUD_1] = "tt_1rud.png|Rudder Only"
|
||||
List_Text[200+TAIL_TYPE.RUD_1_ELEV_1] = "Rud + Ele"; List_Text_Img[200+TAIL_TYPE.RUD_1_ELEV_1] = "tt_1rud_1ele.png|Tail Normal"
|
||||
List_Text[200+TAIL_TYPE.RUD_1_ELEV_2] = "Rud + Dual Ele"; List_Text_Img[200+TAIL_TYPE.RUD_1_ELEV_2] = "tt_1rud_2ele.png|Rud + Dual Elev"
|
||||
List_Text[200+TAIL_TYPE.RUD_2_ELEV_1] = "Dual Rud + Ele"; List_Text_Img[200+TAIL_TYPE.RUD_2_ELEV_1] = "tt_2rud_1ele.png|Dual Rud + Elev"
|
||||
List_Text[200+TAIL_TYPE.RUD_2_ELEV_2] = "Dual Rud + Dual Ele"; List_Text_Img[200+TAIL_TYPE.RUD_2_ELEV_2] = "tt_2rud_2ele.png|Dual Rud + Dual Elev"
|
||||
List_Text[200+TAIL_TYPE.VTAIL_A] = "V-Tail A"; List_Text_Img[200+TAIL_TYPE.VTAIL_A] = "tt_vtail.png|V-Tail A"
|
||||
List_Text[200+TAIL_TYPE.VTAIL_B] = "V-Tail B"; List_Text_Img[200+TAIL_TYPE.VTAIL_B] = "tt_vtail.png|V-Tail B"
|
||||
List_Text[200+TAIL_TYPE.TRAILERON_A] = "Taileron A"; List_Text_Img[200+TAIL_TYPE.TRAILERON_A] = "tt_taileron.png|Taileron A"
|
||||
List_Text[200+TAIL_TYPE.TRAILERON_B] = "Taileron B"; List_Text_Img[200+TAIL_TYPE.TRAILERON_B] = "tt_taileron.png|Taileron B"
|
||||
List_Text[200+TAIL_TYPE.TRAILERON_A_R2] = "Taileron A + 2x Rud"; List_Text_Img[200+TAIL_TYPE.TRAILERON_A_R2] = "tt_taileron2.png|Taileron A + Dual Rud"
|
||||
List_Text[200+TAIL_TYPE.TRAILERON_B_R2] = "Taileron B + 2x Rud"; List_Text_Img[200+TAIL_TYPE.TRAILERON_B_R2] = "tt_taileron2.png|Taileron B + Dual Rud"
|
||||
|
||||
|
||||
-- Servo Reverse
|
||||
if (LCD_W > 128) then
|
||||
List_Text[300+CH_MODE_TYPE.NORMAL] = "Normal "
|
||||
List_Text[300+CH_MODE_TYPE.REVERSE] = "Reverse"
|
||||
else
|
||||
List_Text[300+CH_MODE_TYPE.NORMAL] = "Nor"
|
||||
List_Text[300+CH_MODE_TYPE.REVERSE] = "Rev"
|
||||
end
|
||||
end
|
||||
|
||||
-- Initial Setup
|
||||
local function ST_Init()
|
||||
-- Initialize text (use RX_ID 0)
|
||||
ST_Init_Text(0)
|
||||
|
||||
-- Setup default Data, and load a file if exist
|
||||
--modelLib.ST_Default_Data()
|
||||
if (modelLib.ST_LoadFileData()==0) then -- Did not load a file
|
||||
modelLib.ST_Default_Data()
|
||||
modelLib.ST_SaveFileData() -- Save Defaults
|
||||
end
|
||||
menuDataChanged = false
|
||||
currAircraftType = MENU_DATA[MEMU_VAR.AIRCRAFT_TYPE]
|
||||
currWingType = MENU_DATA[MEMU_VAR.WING_TYPE]
|
||||
currTailType = MENU_DATA[MEMU_VAR.TAIL_TYPE]
|
||||
|
||||
local ctx = menuLib.DSM_Context
|
||||
ctx.Phase = PHASE.RX_VERSION
|
||||
end
|
||||
|
||||
local function ST_Done()
|
||||
local ctx = menuLib.DSM_Context
|
||||
ctx.Phase = PHASE.EXIT_DONE
|
||||
end
|
||||
|
||||
|
||||
return { init=ST_Init, run=ST_SendReceive, done=ST_Done }
|
@ -1,10 +0,0 @@
|
||||
-- OVERRIDES Messges for MIN 128x64 screns
|
||||
-- FORMAT <LineType>|<Msg#>|<Text>
|
||||
-- Line Type: Text for Menus (T), List_Text Options (LT), List_Text_Image (LI), Flight Mode (FM), RX Name (RX)
|
||||
-- IMPORTANT: NO EMPTY LINES
|
||||
--
|
||||
T |0x0097|DONT USE: Factory Reset
|
||||
T |0x0098|DONT USE: Factory Reset
|
||||
T |0x00A5|DONT USE: First Time Setup
|
||||
T |0x0190|DONT USE: Relearn Servo Settings
|
||||
T |0x020D|DONT USE: First Time SAFE Setup
|
Before Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 862 B |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 866 B |
Before Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 880 B |
Before Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 863 B |
Before Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 3.0 KiB |
Before Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 2.6 KiB |
Before Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 2.9 KiB |
Before Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 2.6 KiB |
Before Width: | Height: | Size: 2.6 KiB |
Before Width: | Height: | Size: 2.6 KiB |
Before Width: | Height: | Size: 2.5 KiB |
Before Width: | Height: | Size: 2.6 KiB |
Before Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 2.6 KiB |
Before Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 2.6 KiB |
Before Width: | Height: | Size: 2.9 KiB |
Before Width: | Height: | Size: 2.5 KiB |
Before Width: | Height: | Size: 2.5 KiB |
Before Width: | Height: | Size: 2.5 KiB |
Before Width: | Height: | Size: 2.9 KiB |
Before Width: | Height: | Size: 2.5 KiB |
Before Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 728 B |
Before Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 721 B |
Before Width: | Height: | Size: 803 B |
Before Width: | Height: | Size: 679 B |
Before Width: | Height: | Size: 755 B |
Before Width: | Height: | Size: 817 B |
Before Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 679 B |
@ -1,437 +0,0 @@
|
||||
-- FORMAT <LineType>|<Msg#>|<Text>
|
||||
-- Line Type: Text for Menus (T), List_Text Options (LT), List_Text_Image (LI), Flight Mode (FM), RX Name (RX)
|
||||
-- NO EMPTY LINES
|
||||
-- Formmatting at end of line: /c=Center, /r=Right, /b=Bold, /m=menu
|
||||
LT|0x0001|Off
|
||||
LT|0x0002|On
|
||||
-- Ihn/Act List Options
|
||||
LT|0x0003|Inh
|
||||
LT|0x0004|Act
|
||||
--
|
||||
-- Channel selection for SAFE MODE and GAINS on FC6250HX
|
||||
LT|0x000C|Inh
|
||||
LT|0x000D|Ch5
|
||||
LT|0x000E|Ch6
|
||||
LT|0x000F|Ch7
|
||||
LT|0x0010|Ch8
|
||||
LT|0x0011|Ch9
|
||||
LT|0x0012|Ch10
|
||||
LT|0x0013|Ch11
|
||||
LT|0x0014|Ch12
|
||||
--
|
||||
-- Servo Output values
|
||||
LT|0x002D|5.5ms
|
||||
LT|0x002E|11ms
|
||||
LT|0x002F|22ms
|
||||
--
|
||||
-- Gain Multiplier Values
|
||||
LT|0x0032|1 X
|
||||
LT|0x0033|2 X
|
||||
LT|0x0034|4 X
|
||||
--
|
||||
LT|0x0035|Inh
|
||||
LT|0x0036|Thr
|
||||
LT|0x0037|Ail
|
||||
LT|0x0038|Ele
|
||||
LT|0x0039|Rud
|
||||
LT|0x003A|Ch5
|
||||
LT|0x003B|Ch6
|
||||
LT|0x003C|Ch7
|
||||
LT|0x003D|Ch8
|
||||
LT|0x003E|Ch9
|
||||
LT|0x003F|Ch10
|
||||
LT|0x0040|Ch11
|
||||
LT|0x0041|Ch12
|
||||
LT|0x0042|Ch13
|
||||
LT|0x0043|Ch14
|
||||
LT|0x0044|Ch15
|
||||
LT|0x0045|Ch16
|
||||
LT|0x0046|Ch17
|
||||
LT|0x0047|Ch18
|
||||
LT|0x0048|Ch19
|
||||
LT|0x0049|Ch20
|
||||
--
|
||||
T |0x0040|Roll
|
||||
T |0x0041|Pitch
|
||||
T |0x0042|Yaw
|
||||
T |0x0043|Gain/c/b
|
||||
T |0x0045|Differential
|
||||
T |0x0046|Priority
|
||||
T |0x0049|Output Setup
|
||||
T |0x004A|Failsafe
|
||||
T |0x004B|Main Menu
|
||||
T |0x004E|Position
|
||||
--
|
||||
T |0x0050|Outputs
|
||||
T |0x0051|Output Channel 1
|
||||
T |0x0052|Output Channel 2
|
||||
T |0x0053|Output Channel 3
|
||||
T |0x0054|Output Channel 4
|
||||
T |0x0055|Output Channel 5
|
||||
T |0x0056|Output Channel 6
|
||||
T |0x0057|Output Channel 7
|
||||
T |0x0058|Output Channel 8
|
||||
T |0x0059|Output Channel 9
|
||||
T |0x005A|Output Channel 10
|
||||
--
|
||||
-- FailSafe Options
|
||||
--LT|0x005E|Inh
|
||||
LT|0x005F|Hold Last
|
||||
LT|0x0060|Preset
|
||||
--LT|0x0061|Custom
|
||||
--
|
||||
T |0x0071|Proportional
|
||||
T |0x0072|Integral
|
||||
T |0x0073|Derivate
|
||||
T |0x0078|FM Channel
|
||||
T |0x007F|Attitude Gain
|
||||
--
|
||||
T |0x0080|Orientation
|
||||
T |0x0082|Heading
|
||||
T |0x0085|Frame Rate
|
||||
T |0x0086|System Setup
|
||||
T |0x0087|F-Mode Setup
|
||||
T |0x0088|Enabled F-Modes
|
||||
T |0x0089|Gain Channel
|
||||
T |0x008A|Gain Sensitivity/r -- Right Align
|
||||
T |0x008B|Panic
|
||||
T |0x008E|Panic Delay
|
||||
--
|
||||
LT|0x0187|No Freq --???? unset Freq
|
||||
LT|0x0088|70hz
|
||||
LT|0x0089|90hz
|
||||
LT|0x008A|200hz
|
||||
LT|0x008B|333hz
|
||||
LT|0x008C|490hz
|
||||
LT|0x008D|560hz
|
||||
LT|0x008E|Normal
|
||||
LT|0x008F|Reversed
|
||||
|
||||
-- FC6250HX: Callibration
|
||||
T |0x0090|Apply
|
||||
T |0x0091|Begin
|
||||
T |0x0092|Start
|
||||
T |0x0093|Complete
|
||||
T |0x0094|Done
|
||||
--
|
||||
-- FC6250HX: Swashplate Type
|
||||
--
|
||||
LT|0x0090|Normal
|
||||
LI|0x0090|h_swp_norm.png|Normal
|
||||
LT|0x0091|3 Servos 120 Y
|
||||
LI|0x0091|h_swp_3_120.png|3 Servos 120 Y
|
||||
LT|0x0092|3 Servos 120 Y-Inv
|
||||
LI|0x0092|h_swp_3_120inv.png|3 Servos 120 Y-Inv
|
||||
LT|0x0093|3 Servos 135 Y
|
||||
LI|0x0093|h_swp_3_135.png|3 Servos 135 Y
|
||||
LT|0x0094|3 Servos 135 Y-Inv
|
||||
LI|0x0094|h_swp_3_135inv.png|3 Servos 135 Y-Inv
|
||||
LT|0x0095|3 Servos 140 Y
|
||||
LI|0x0095|h_swp_3_140.png|3 Servos 140 Y
|
||||
LT|0x0096|3 Servos 140 Y-Inv
|
||||
LI|0x0096|h_swp_3_140inv.png|3 Servos 140 Y-Inv
|
||||
LT|0x0097|3 Servos 90 T
|
||||
LI|0x0097|h_swp_3_90.png|3 Servos 90 T
|
||||
LT|0x0098|3 Servos 90 T-Inv
|
||||
LI|0x0098|h_swp_3_90inv.png|3 Servos 90 T-Inv
|
||||
--
|
||||
T |0x0097|Factory Reset
|
||||
T |0x0098|Factory Reset
|
||||
T |0x0099|Advanced Setup
|
||||
T |0x009A|Capture Failsafe Positions
|
||||
T |0x009C|Custom Failsafe
|
||||
--
|
||||
T |0x009F|Save Settings -- Save & Reboot RX
|
||||
--
|
||||
T |0x00A5|First Time Setup
|
||||
T |0x00AA|Capture Gyro Gains
|
||||
T |0x00AD|Gain Channel Select
|
||||
T |0x00AF|Dynamic
|
||||
LT|0x00B0|Self-Level
|
||||
LT|0x00B1|Envelope
|
||||
--
|
||||
-- Flight Modes List Options
|
||||
LT|0x00B5|Inh
|
||||
LT|0x00B6|FM1
|
||||
LT|0x00B7|FM2
|
||||
LT|0x00B8|FM3
|
||||
LT|0x00B9|FM4
|
||||
LT|0x00BA|FM5
|
||||
LT|0x00BB|FM6
|
||||
LT|0x00BC|FM7
|
||||
LT|0x00BD|FM8
|
||||
LT|0x00BE|FM9
|
||||
LT|0x00BF|FM10
|
||||
--
|
||||
T |0x00BE|Unknown_BE -- Used in Reset menu (0x0001) while the RX is rebooting
|
||||
--
|
||||
T |0x00C7|Calibrate Sensor
|
||||
T |0x00C8|Sensor is Calibrating.. Wait
|
||||
T |0x00CA|SAFE & Panic Mode Setup
|
||||
--
|
||||
T |0x00CD|Level model & capt attitude/m -- SPECIAL MENU to itself who is not a comment
|
||||
T |0x00CE|Error TX Conf
|
||||
T |0x00CF|Invalid TX Ch Conf 1
|
||||
T |0x00D0|Invalid TX Ch Conf 2
|
||||
--
|
||||
-- RX Orientations for AR631/AR637, Optionally attach an Image + Alt Text to display
|
||||
LT|0x00CB|Pos 1
|
||||
LI|0x00CB|rx_pos_1.png|Pilot View: RX Label Up, Pins Back
|
||||
LT|0x00CC|Pos 2
|
||||
LI|0x00CC|rx_pos_2.png|Pilot View: RX Label Left, Pins Back
|
||||
LT|0x00CD|Pos 3
|
||||
LI|0x00CD|rx_pos_3.png|Pilot View: RX Label Down, Pins Back
|
||||
LT|0x00CE|Pos 4
|
||||
LI|0x00CE|rx_pos_4.png|Pilot View: RX Label Right, Pins Back
|
||||
LT|0x00CF|Pos 5
|
||||
LI|0x00CF|rx_pos_5.png|Pilot View: RX Label UP, Pins to Front
|
||||
LT|0x00D0|Pos 6
|
||||
LI|0x00D0|rx_pos_6.png|Pilot View: RX Label Left, Pins Front
|
||||
LT|0x00D1|Pos 7
|
||||
LI|0x00D1|rx_pos_7.png|Pilot View: RX Label Down, Pins Front
|
||||
LT|0x00D2|Pos 8
|
||||
LI|0x00D2|rx_pos_8.png|Pilot View: RX Label Right, Pins Front
|
||||
LT|0x00D3|Pos 9
|
||||
LI|0x00D3|rx_pos_9.png|Pilot View: RX Label Up, Pins Left
|
||||
LT|0x00D4|Pos 10
|
||||
LI|0x00D4|rx_pos_10.png|Pilot View: RX Label Back, Pins Left
|
||||
LT|0x00D5|Pos 11
|
||||
LI|0x00D5|rx_pos_11.png|Pilot View: RX Label Down, Pins Left
|
||||
LT|0x00D6|Pos 12
|
||||
LI|0x00D6|rx_pos_12.png|Pilot View: RX Label Front, Pins Left
|
||||
LT|0x00D7|Pos 13
|
||||
LI|0x00D7|rx_pos_13.png|Pilot View: RX Label Up, Pins Right
|
||||
LT|0x00D8|Pos 14
|
||||
LI|0x00D8|rx_pos_14.png|Pilot View: RX Label Back, Pins Right
|
||||
LT|0x00D9|Pos 15
|
||||
LI|0x00D9|rx_pos_15.png|Pilot View: RX Label Down, Pins Right
|
||||
LT|0x00DA|Pos 16
|
||||
LI|0x00DA|rx_pos_16.png|Pilot View: RX Label Front, Pins Right
|
||||
LT|0x00DB|Pos 17
|
||||
LI|0x00DB|rx_pos_17.png|Pilot View: RX Label Back, Pins Down
|
||||
LT|0x00DC|Pos 18
|
||||
LI|0x00DC|rx_pos_18.png|Pilot View: RX Label Left, Pins Down
|
||||
LT|0x00DD|Pos 19
|
||||
LI|0x00DD|rx_pos_19.png|Pilot View: RX Label Front, Pins Down
|
||||
LT|0x00DE|Pos 20
|
||||
LI|0x00DE|rx_pos_20.png|Pilot View: RX Label Right, Pins Down
|
||||
LT|0x00DF|Pos 21
|
||||
LI|0x00DF|rx_pos_21.png|Pilot View: RX Label Back, Pins Up
|
||||
LT|0x00E0|Pos 22
|
||||
LI|0x00E0|rx_pos_22.png|Pilot View: RX Label Left, Pins Up
|
||||
LT|0x00E1|Pos 23
|
||||
LI|0x00E1|rx_pos_23.png|Pilot View: RX Label Front, Pins Up
|
||||
LT|0x00E2|Pos 24
|
||||
LI|0x00E2|rx_pos_24.png|Pilot View: RX Label Right, Pins Up
|
||||
LT|0x00E3|Pos Invalid
|
||||
LI|0x00E3|rx_pos_25.png|Cannot detect orientation of RX
|
||||
--
|
||||
-- RX Orientations images for FC5250 (HACK add 0x100 internally to differenciate for helis)
|
||||
LI|0x01CB|h_rx_pos_1.png|Pilot View: RX Label Up, Pins Front
|
||||
LI|0x01CC|h_rx_pos_2.png|Pilot View: RX Label Left, Pins Front
|
||||
LI|0x01CD|h_rx_pos_3.png|Pilot View: RX Label Down, Pins Front
|
||||
LI|0x01CE|h_rx_pos_4.png|Pilot View: RX Label Right, Pins Front
|
||||
LI|0x01CF|h_rx_pos_5.png|Pilot View: RX Label UP, Pins to Back
|
||||
LI|0x01D0|h_rx_pos_6.png|Pilot View: RX Label Left, Pins Back
|
||||
LI|0x01D1|h_rx_pos_7.png|Pilot View: RX Label Down, Pins Back
|
||||
LI|0x01D2|h_rx_pos_8.png|Pilot View: RX Label Right, Pins Back
|
||||
--
|
||||
T |0x00D1|Receiver will Reboot/b
|
||||
T |0x00D2|Panic Channel
|
||||
T |0x00D3|Swashplate
|
||||
T |0x00D5|Agility
|
||||
T |0x00D8|Stop
|
||||
T |0x00DA|SAFE/c/b -- Center + Bold
|
||||
T |0x00DB|Stability
|
||||
T |0x00DC|@ per sec
|
||||
T |0x00DD|Tail rotor
|
||||
T |0x00DE|Setup
|
||||
T |0x00DF|AFR
|
||||
T |0x00E0|Collective
|
||||
T |0x00E1|Subtrim
|
||||
T |0x00E2|Phasing
|
||||
T |0x00E3|Pre-Comp
|
||||
T |0x00E4|E-Ring
|
||||
T |0x00E5|Swash Type
|
||||
T |0x00E6|Travel
|
||||
T |0x00E7|Left
|
||||
T |0x00E8|Right
|
||||
T |0x00EA|Low Throttle
|
||||
--
|
||||
T |0x00F2|Governor
|
||||
T |0x00F4|Soft Start
|
||||
--
|
||||
LT|0x00F2|Fixed
|
||||
LT|0x00F3|Adjustable
|
||||
LT|0x00F4|Inh
|
||||
LT|0x00F5|Nitro
|
||||
--
|
||||
T |0x00F6|Direction
|
||||
T |0x00F8|Settings -- ?? validate on a Spektrum radio
|
||||
T |0x00F9|Gyro settings
|
||||
T |0x00FE|Stick Priority/c/b
|
||||
--
|
||||
T |0x0100|Make sure the model has been
|
||||
T |0x0101|configured, including wing type,
|
||||
T |0x0102|reversing, travel, trimmed, etc.
|
||||
T |0x0103|before continuing setup.
|
||||
T |0x0104|
|
||||
T |0x0105| -- Blank
|
||||
--
|
||||
T |0x0106|Any wing type, channel assignment,
|
||||
T |0x0107|subtrim, or servo reversing changes
|
||||
T |0x0108|require running through initial
|
||||
T |0x0109|setup again.
|
||||
T |0x010A|
|
||||
T |0x010B|
|
||||
--
|
||||
T |0x0190|Relearn Servo Settings
|
||||
T |0x019C|Enter Receiver Bind Mode
|
||||
T |0x01AA|Offset
|
||||
T |0x01D7|SAFE Select Channel
|
||||
T |0x01DC|AS3X/c/b -- Center + Bold
|
||||
T |0x01DD|AS3X Settings
|
||||
T |0x01DE|AS3X Gains
|
||||
T |0x01E0|Rate Gains/c/b
|
||||
T |0x01E2|SAFE Settings
|
||||
T |0x01E3|SAFE Gains
|
||||
T |0x01E6|Attitude Trim/c/b
|
||||
T |0x01E7|Envelope
|
||||
T |0x01E9|Roll Right
|
||||
T |0x01EA|Roll Left
|
||||
T |0x01EB|Pitch Down
|
||||
T |0x01EC|Pitch Up
|
||||
T |0x01EE|Thr to Pitch
|
||||
T |0x01EF|Low Thr to Pitch/c/b
|
||||
T |0x01F0|High Thr to Pitch/c/b
|
||||
T |0x01F1|Filter
|
||||
T |0x01F3|Threshold
|
||||
T |0x01F4|Angle
|
||||
T |0x01F6|Failsafe Angles/c/b
|
||||
T |0x01F8|Safe Mode
|
||||
T |0x01F9|SAFE Select
|
||||
T |0x01FC|Panic F-Mode
|
||||
T |0x01FD|FailSafe Flight Mode -- Safe Flight Mode
|
||||
T |0x0201|Throttle
|
||||
T |0x0204|Hover
|
||||
T |0x0208|Decay
|
||||
T |0x0209|Save to Backup
|
||||
T |0x020A|Restore from Backup
|
||||
T |0x020D|First Time SAFE Setup
|
||||
--
|
||||
-- First time safe setup Page 3 :
|
||||
T |0x020E|AS3X gains must be tuned
|
||||
T |0x020F|and active in SAFE Flight Modes
|
||||
T |0x0210|to help reduce wobble.
|
||||
T |0x0211|
|
||||
T |0x0212|
|
||||
T |0x0213| -- Blank
|
||||
--
|
||||
-- AS3X orientation Setting menu (Level)
|
||||
T |0x021A|Set the model level,
|
||||
T |0x021B|and press Continue.
|
||||
T |0x021C|
|
||||
T |0x021D| -- Blank
|
||||
--
|
||||
-- AS3X orientation Setting menu (Nose down)
|
||||
T |0x021F|Set the model on its nose,
|
||||
T |0x0220|and press Continue. If the
|
||||
T |0x0221|orientation on the next
|
||||
T |0x0222|screen is wrong go back
|
||||
T |0x0223|and try again.
|
||||
T |0x0224|Continue
|
||||
--
|
||||
T |0x0226|Angle Limits/c/b
|
||||
T |0x0227|Other settings
|
||||
T |0x0229|Set Orientation Manually
|
||||
--
|
||||
-- Factory Default Warning
|
||||
T |0x022B|WARNING!
|
||||
T |0x022C|This will reset the
|
||||
T |0x022D|configuration to factory
|
||||
T |0x022E|defaults. This does not
|
||||
T |0x022F|affect the backup config.
|
||||
T |0x0230| -- Blank
|
||||
--
|
||||
-- Backup Warning
|
||||
T |0x0231|This will overwrite the
|
||||
T |0x0232|backup memory with your
|
||||
T |0x0233|current configuartion.
|
||||
T |0x0234|
|
||||
T |0x0235| -- Blank
|
||||
--
|
||||
-- Restore from Backup Warning
|
||||
T |0x0236|This will overwrite the
|
||||
T |0x0237|current config with
|
||||
T |0x0238|that which is in
|
||||
T |0x0239|the backup memory.
|
||||
T |0x023A| -- Blank
|
||||
--
|
||||
-- Utilities Copy flight modes
|
||||
T |0x023D|Copy F-Mode Settings
|
||||
T |0x023E|Source F-Mode
|
||||
T |0x023F|Target F-Mode
|
||||
--
|
||||
T |0x0240|Utilities
|
||||
--
|
||||
-- Gain Capture Page
|
||||
T |0x024C|Gains will be captured on
|
||||
T |0x024D|Captured gains will be
|
||||
T |0x024E|Gains on
|
||||
T |0x024F|were captured and changed
|
||||
T |0x0250|from Adjustable to Fixed
|
||||
--
|
||||
-- Utilities, Copy flight mode (Copy Confirmation, oveerriding FM)
|
||||
T |0x0251|Are you sure you want to ovewrite the "Target"
|
||||
T |0x0252|with the "Source" ?
|
||||
T |0x0253| -- Blank
|
||||
--
|
||||
T |0x0254|Pos = Up, Neg = Down
|
||||
--
|
||||
-- First time safe setup Page 1 (maybe ask to select Flight Mode cannel)
|
||||
T |0x0255|Before setting up SAFE
|
||||
T |0x0256|a Flight Mode channel
|
||||
T |0x0257|most be configured.
|
||||
--
|
||||
-- First time safe setup Page 2 (something related for flight mode)
|
||||
T |0x025A|Select the desired flight mode
|
||||
T |0x025B|switch position to adjust settings
|
||||
T |0x025C|for each flight mode
|
||||
T |0x025D|
|
||||
T |0x025E| -- Blank
|
||||
--
|
||||
-- Utilities, Copy flight mode (Confirm)
|
||||
T |0x0259|YES
|
||||
T |0x0260|WARNING: "Target"
|
||||
T |0x0261|F-Mode will be overwritten
|
||||
T |0x0262|by "Source"
|
||||
--
|
||||
T |0x0263|Fixed/Adjustable Gains/c/b
|
||||
T |0x0266|Heading Gain/c/b
|
||||
T |0x0267|Pos = Nose Up/Roll Right
|
||||
T |0x0268|Neg = Nose Down/Roll Left
|
||||
T |0x0269|SAFE - Thr to Pitch
|
||||
T |0x026A|Use CAUTION for Yaw gain!/b
|
||||
--
|
||||
T |0x026B|Head Speed
|
||||
T |0x026C|Pinion
|
||||
T |0x026D|Main Gear
|
||||
T |0x026F|RPM Sensor
|
||||
T |0x0272|Show Advanced Menus
|
||||
--
|
||||
T |0x0300|No compatible DSM RX...
|
||||
T |0x0301|Waiting for RX to Restart
|
||||
--
|
||||
FM|0x8000|Flight Mode/c/b
|
||||
--
|
||||
RX|0x0001|AR636
|
||||
RX|0x0014|SPM4651T
|
||||
RX|0x0015|AR637T
|
||||
RX|0x0016|AR637TA
|
||||
RX|0x0018|FC6250HX
|
||||
RX|0x0019|AR630
|
||||
RX|0x001A|AR8360T
|
||||
RX|0x001B|AR8020T
|
||||
RX|0x001C|AR10360T
|
||||
RX|0x001E|AR631
|
||||
|
@ -1,22 +0,0 @@
|
||||
# Credits
|
||||
Code is based on the code/work by: Pascal Langer (Author of the Multi-Module)
|
||||
Rewrite/Enhancements by: Francisco Arzu
|
||||
|
||||
Thanks to all the people volunteered to test it.
|
||||
|
||||
Release Notes for
|
||||
|
||||
## COLOR Radios
|
||||
Read more [Color radios](./readme_color.md)
|
||||
|
||||

|
||||

|
||||
|
||||
## Black & White Radios (Small Screens)
|
||||
Read more [black & whire radios](./readme_bw.md)
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||
|
@ -1,181 +0,0 @@
|
||||
# Credits
|
||||
Code is based on the code/work by: Pascal Langer (Author of the Multi-Module)
|
||||
Rewrite/Enhancements by: Francisco Arzu
|
||||
|
||||
Thanks to all the people volunteered to test it.
|
||||
|
||||
# Introduction (v0.56 Black & White Small Radios)
|
||||
|
||||
!!!!!NEW!!!!!!: Finally was able to create the Plane Setup for Smaller Radios
|
||||
There is still significant memory limitations in some of this radios, so the Setup and FP was split in two files.
|
||||
The file 'DSM FwdPrg_56_STUP.lua' is the new one to create the planes setup that works together with 'DSM FwdPrg_56_MIN.lua'
|
||||
|
||||
# How to Use it
|
||||
|
||||
Step #1: Make sure that the /MODELS/DSMDATA folder exist.
|
||||
|
||||
Step #2: Run the "DSM FwdPrg_56_STUP" first to setup the plane wing, tail and channels to use for each surface. At the end it will ask you to "save" the configuration. That saves a file in the /MODELS/DSMDATA folder.
|
||||
|
||||

|
||||

|
||||

|
||||
|
||||
Why the RX needs to know the Plane Setup?? The AS3X/Gyro and SAFE needs to know what surfaces to move to do the proper correction in flight. It needs to know what channels are you using for ailerons, elevarors and rudders (could be 1 or 2 of each). Also if you have special Wing like a delta wing, the elevator and aileron functions are on the same channels.. same with V-Trails, Ruder/Elevator are combined. All this information is shared with the RX during "First Time Setup" as well as "Relearn Servo Setting". Older version of 0.55 MIN hardcoded this info to be a plain 4-ch regular plane, thats why we discourage to use those function.
|
||||
|
||||
|
||||
Step #3: Run the "DSM FwdPrg_56_MIN". It uses the model configuration created in step #2 to properly tell the receiver the plane configuration for initial setup. If you get "Cannot load model config", that means that the file was not created on step #2. Once it shows the intial forward programming page for your receiver, usuall "Gyro Settings and Other Settings". You can properly setup the a plane from initial setup... if you are not familiar with this step, view some of the videos. There are already multiple videos showing how to do it EdgeTX color version, or the Spektrum official videos, the menus are the same.
|
||||
|
||||
|
||||
## Dealing with Low memory
|
||||
On my FrSky QX7 (Probably the one with the lower memory compared to Radiomaster Boxter and maybe Zorro), it will give you "not enouth memory"
|
||||
the very first time you try to run it since is compiling + running. Try to run them at least 2 times again, this times wll just run (not compile).
|
||||
In some ocations that keeps giving memory problems, i have to restart the radio, and try to run it right after restart.
|
||||
|
||||
After it runs fine, and you try to run it the 2nd time and gives "not enouth memory", you have restart the radio.. for me this is random..
|
||||
sometimes i can run it many times consecutively.. but once it gives memory error, have to restart to be able to run again.
|
||||
Once it starts, it should work find after... is the statup who loads what it needs to memory.
|
||||
|
||||
I am running EdgeTX 2.9.2 (there was some memory cleanup in 2.9.0, and 2.9.1 to get a bit more memory)
|
||||
I left version 0.55 in the files, since it uses less memory, it can change the mayority of FP parameters, but cannot setup plane or Relearn Servo Settings
|
||||
(don't execute the menus who say 'DON'T USE!!').. v0.55 and v0.56 MINs can co-exist.
|
||||
|
||||
Video of how to deal with memory:
|
||||
https://www.youtube.com/watch?v=kG3RfVa_brU
|
||||
|
||||
# Deployment
|
||||
|
||||
Uncompress the Zip file (ZIP version) into your local computer.
|
||||
In another window, open your TX SDCard and go to `/SCRIPTS/TOOLS`.
|
||||
|
||||
When upgrading from a previous version of this tool, delete your `/SCRIPTS/TOOLS/DSMLIB` before copying the new one (if you customized the menu messages, inside `DSMLIB` do a backup of the message files first)
|
||||
|
||||
1. The zip file has the same structure as your SDCard. If you want to copy all the content of the zip file into your SDCard, it will create all the directories and files in the right place.
|
||||
|
||||
For the MINimalistic version, Your TX SDCard should looks like this:
|
||||
|
||||
/SCRIPTS/TOOLS
|
||||
DSM FwdPrg_56_MIN.lua -- Minimalistic version for radios with LOW memory (Can setup planes)
|
||||
DSM FwdPrg_56_STUP.lua -- `NEW!` Setup plane for minimalistic version (LOW Memory radios)
|
||||
DSM FwdPrg_55_MIN.lua -- Uses less memory than v56, but cannot do initial setup of the plane
|
||||
|
||||
/SCRIPTS/TOOLS/DSMLIB/ -- (ALL CAPITALS) Libraries ane extra files
|
||||
DsmFwPrgMIN_P1.lua -- Part1 of extra files for Min
|
||||
DsmFwPrgMIN_P2.lua -- Part2 of extra files for Min
|
||||
msg_fwdp_en.txt -- Menu messages in English (common for all radios)
|
||||
MIN_msg_fwdp_en.txt -- Menu messages in English (overrides for 128x164 resolution)
|
||||
|
||||
### Other Directories/Files
|
||||
|
||||
/LOGS/dsm_log.txt --Readable log of the last RX/TX session, usefull for debugging problems
|
||||
|
||||
# NOTE for FC6250HX FC+RX version
|
||||
For the full size FC6250HX, Only use V0.55 or newer.
|
||||
|
||||
DO NOT use previous versions to do the Setup -> Gyro Settings -> Orientation. The problem was that it did not have the orientation messages.. and you are were choosing blind. The calibration will never stop until you place the RX in the right orientation, even after restarting the RX (if flashing red, is not in the right orientation.. if flashshing white is in the right orientation). If you run into this problem, and lights are blinking red, rotate the FC on the longer axis until you get white blinking.. keep it stable, will blink white faster andlet calibration finishes.. after that is back to normal.
|
||||
|
||||
OpenTX: When you enter "forward programming" you will hear "Telemetry lost" and "Telemetry recovered".. The FC led will blink white, but when exit FP, will blink red...is not problem.. but will need to be power cycled to get blinking green again.. i think is something related to temporarilly loosing the connection with the radio..researching the OpenTX code since it only happens with this helis FC.
|
||||
|
||||
# Common Questions
|
||||
1. `RX not accepting channels higher than Ch6 for Flight-mode o Gains:`
|
||||
- All Spektrum RX are 20 channels internally, even if it only has 6 external Ch/Ports to connect servos.
|
||||
|
||||
- Make sure that when you bind your RX, you select the proper range of channels to use.. By default, ch1-ch8.
|
||||
|
||||
- You have to mapped a Switch/Slider to the channel, togling/moving will select the channel on the menu field.
|
||||
|
||||
- The RX validates the channels, and it does not detect signal on a channel, it will not allow to select it..that is why is important to move the switch/slider, so that the RX knows that is a valid channel.
|
||||
|
||||
|
||||
# Changes and fixes
|
||||
|
||||
v0.56:
|
||||
1. Fix Tail-Type "Taileron" functionality that was not working. Also validated V-Tail and Delta wings.
|
||||
2. Added Taileron and two Rudder config (Many Freewing Jets like F18,F16, etc)
|
||||
3. Gyro-Reverse Screen now shows what is the channel/port used for (Ail, Ele, Rud, etc)
|
||||
4. COLOR ONLY: Gyro-Reverse Screen now shows what information that shared with the RX about each channel (Role, Slave, Reverse).
|
||||
5. NEW!! Initial version of Plane Setup for B&W radios
|
||||
|
||||
V0.55:
|
||||
1. Finally found where the TX reports to the RX how many channels is transmiting. The TX now reports itself as a 12ch radio instead of 6h. (DSM Multi-Module limit). This fixes a few things:
|
||||
|
||||
a. Many places where you have to select channels > CH6 for Flight-Mode, Gains, Panic now works properly with the scroller. The radio is still validating that you are not selecting an invalid channel. For example, if you have an additional AIL on CH6, it will not allow you to use CH6 for FM or Gains.. it just move to the next valid one.
|
||||
|
||||
b. When setting up AIL/ELE on channels greater than CH6, on previous versions SAFE/AS3X was not moving them.. now they work up correctly. Set them up in the first in CH1-CH10. Why CH10?? Thats what fits on the reverse screen, otherwise, have to add more screens.
|
||||
|
||||
c. Some individual Gain channels was not allowing to setup on CH greater than CH6. Now is fixed.
|
||||
|
||||
2. User Interface:
|
||||
a. `RTN` Key now works as `Back` when the screen has a `Back`. Makes it easy for navigation.. Presing `RTN` on the main screen exists the tool.
|
||||
b. Much faster refresh of the menus. Optimize the process of send/recive menu data from the RX.
|
||||
|
||||
3. Support for FC6250HX (the one with separate RX).. Setup Swashplate type, RX orientation works properly.. This are menu options that the smaller version that comes in the
|
||||
Blade 230S did not have.
|
||||
|
||||
V0.54 Beta:
|
||||
- First version for the small screens, and limited memory. Only can change existing values, it cannot setup a brand new plane or new RX from Zero
|
||||
- Fix problem on editing the SAFE Mode Attitude Trim
|
||||
- First version with externalize merges, so that it can be translated to other languages
|
||||
|
||||
# Tested Radios and RXs
|
||||
- Radio: FrSky QX7: Due to limited memory, could be that the first time is does not start (not enouth memory to compile+run), but try again after a fresh TX restart.
|
||||
|
||||
- AR631/AR637xx
|
||||
- FC6250HX (Blade 230S V2 Helicopter)
|
||||
- FC6250HX (Separate RX.. use only V55 or newer of this tool)
|
||||
- AR636 (Blade 230S V1 Heli firmware 4.40)
|
||||
|
||||
Please report if you have tested it with other receivers to allow us to update the documentation. Code should work up to 10 channels for the main surfaces (Ail/Ele/etc). All Spektrum RX are internally 20 channels, so you can use Ch7 for Flight Mode even if your RX is only 6 channels (See common Questions)
|
||||
|
||||
# Messages Displayed in the GUI
|
||||
|
||||
If in a screen you get text that looks like `Unknown_XX` (ex: Unknown_D3), that message has not been setup in the script in english. If you can determine what the proper message is, you can send us a message to be added to the library.
|
||||
The `XX` represents a Hex Number (0..9,A..F) message ID.
|
||||
|
||||
If you want to fix it in your local copy, all messages are in the file `SCRIPT\TOOS\DSMLIB\msg_fwdp_en.txt`. (english version)
|
||||
|
||||
Example::
|
||||
|
||||
T |0x0080|Orientation
|
||||
T |0x0082|Heading
|
||||
T |0x0085|Frame Rate
|
||||
T |0x0086|System Setup
|
||||
T |0x0087|F-Mode Setup
|
||||
T |0x0088|Enabled F-Modes
|
||||
T |0x0089|Gain Channel
|
||||
T |0x008A|Gain Sensitivity/r -- Right Align
|
||||
T |0x008B|Panic
|
||||
T |0x008E|Panic Delay
|
||||
|
||||
For example, if you get `Unknown_9D` in the GUI and your now that it should say **NEW Text**, you can edit the lua script to look like this:
|
||||
T |0x009D|NEW Text -- NEW Text added for AR98xx
|
||||
|
||||
# Local Language Support
|
||||
Some settings that can change (top of Lua file):
|
||||
`local LANGUAGE = "en"`
|
||||
|
||||
If you want to translate the menu messages to another language (like french), copy the file `msg_fwdp_en.txt` into `msg_fwdp_fr.txt`, translate it, and change the language in the lua file to `"fr"`.
|
||||
|
||||
|
||||
# LOG File
|
||||
|
||||
The log file of the last use of the script is located at `/LOGS/dsm_log.txt`. **It is overridden on every start to avoid filling up the SD card**. So if you want to keep it, copy or rename it before starting the script again. (it can be renamed in the TX by browsing the SD card)
|
||||
|
||||
The log is human readable, and can help use debug problems remotrly
|
||||
|
||||
|
||||
# Validation of data by the RX
|
||||
|
||||
When you change a value in the GUI, the RX validates that the value is valid. This applies to channels as well as values.
|
||||
|
||||
|
||||
---
|
||||
# Version 0.54
|
||||
First version for Small Radios
|
||||
|
||||
### Known Problems:
|
||||
- Currently cannot setup a plane from scratch.. (Working on it).
|
||||
- The first time you run it, it will give you "not enouth memory", but should work the 2nd time after the first compilation (creation of .luac). After that, it should start right away.
|
||||
|
||||
# Version 0.2
|
||||
Original Version from Pascal Langer
|
||||
|
@ -1,284 +0,0 @@
|
||||
# Credits
|
||||
Code is based on the code/work by: Pascal Langer (Author of the Multi-Module)
|
||||
Rewrite/Enhancements by: Francisco Arzu
|
||||
|
||||
Thanks to all the people volunteered to test it.
|
||||
|
||||
# Introduction (v0.56)
|
||||
|
||||
NOTE: Unless you use special tail types, probably not worth the upgrade. The changes are mostly cosmetic on the Gyro Reverse page to show extra information.
|
||||
|
||||
In 0.56, focused on validating and fixing the Wing and Tail type special mixing. Vtail/Delta was working but Taileron was not. The Gyro Reverse screen now show what type of servo information is sharing with the TX. This affects the Gyro AS3X and SAFE behaviour, you still needs to set your TX with the proper mixes to do V-Tail/Taileron/etc.
|
||||
|
||||
- The first is the "Role" of the port (`Ail/Ele/Rud/Thr`). Combination is posible for for special types of wing/tails: Vtail:`EleRud`, Delta & Taileron: `AilEle`.
|
||||
- The `-` (Minus) is Reverse.
|
||||
- Information is if it the Master or Slave (Master is implicit)
|
||||
- The type of mix applied: for V-Tail, the left/right Elevators (`EleRud`) uses `M_Rud` (Mix Rudder), For Delta, the left/right Ailerons (`AilEle`) uses `M_Ele` (Mix Elevator), and finally the Tailerons, the the left/right Elevators (`AilEle`) uses `M_Ail` (Mix Aileron). Looks like the Mixes are for the entire RX and only needs to be set in one of the ports, The difference between the "A" and "B" configuration is just if the mix is set on the Master or Slave port (like Taileron_A or Taileron_B) and affects the direction.. sometimes you have to try both. Start by setting the right direction for the primary roll, and then use the A/B configurations. For exmaple, in Taileron, the primary roll is Elevators, the secondary roll is Aileron (Mix Aileron). Below is a Taileron example: Two independent Elevators and 2 independent ailerons.
|
||||
|
||||

|
||||

|
||||
|
||||
|
||||
With spektrum constantly updating its firmware, you only need to update the message file if you see in the screen any message "Unknown_xyz".
|
||||
|
||||
|
||||
This script library enhances the original DSM Forward Programming tool. DSM Forward Programming is needed to setup many of the new Spektrum Receivers with Gyro AS3X/SAFE features. For the Gyro (/Safe) to correct the plane in flight, it needs to move the right surfaces therefore the RX needs to know the configuration of the plane (Wing Type, Tail Type, Mixers, Servo Assignments, Servo Reverse). That info tells the RX where the aileron(s) are (one or two), where the elevator(s) are (one or two), V-Tail, Delta Wing, etc.
|
||||
|
||||
Since EdgeTx/OpenTx doesn’t have an equivalent setup that is stored in the radio, we have to create our own version. This info is stored inside the `/MODELS/DSMDATA` directory/folder (which needs to be created by manually).
|
||||
|
||||
During `"Gyro Settings->initial setup"`, the RX asks the TX for model information behind the scenes. After setup, `"Gyro Settings->System Tools-> Relearn Servo Settings"` requests the TX servo configuration and stores it in the RX.
|
||||
|
||||
# Deployment
|
||||
|
||||
When upgrading from a previous version of this tool, delete your /SCRIPTS/TOOLS/DSMLIB before copying the new one (if you customized your images, inside "DSMLIB/img" do a backup first). Also you can delete the previous DSM_FwdProg*.* from /SCRIPTS/TOOLS.
|
||||
|
||||
Uncompress the Zip file (ZIP version) into your local computer.
|
||||
In another window, open your TX SDCard.
|
||||
|
||||
1. The zip file has the same structure as your SDCard. If you want to copy all the content of the zip file into your SDCard top level folder, it will create all the directories and files in the right place.
|
||||
2. Make sure to check that `/MODELS/DSMDATA` is there. The script will complain at startup if it does not exist. Here the script saves the Spektrun settings for each of your models.
|
||||
|
||||
Your TX SDCard should looks like this:
|
||||
|
||||
/SCRIPTS/TOOLS/ -- you only need one of the 3 to save some space in your TOOLS screen
|
||||
DSM FwdPrg_56_Color.lua -- Color and touch radios
|
||||
|
||||
|
||||
/SCRIPTS/TOOLS/DSMLIB/ -- (ALL CAPITALS) Libraries ane extra files
|
||||
DsmFwPrgLib.lua -- DSM Protocol Message and Menu engine
|
||||
DsmFwPrgSIMLib.lua -- Simulation of AR631, FC6250HX (For GUI development)
|
||||
SetupLib.lua -- Model Setup Screens
|
||||
msg_fwdp_en.txt -- `NEW!` Messages for forward programing externalized. To support other langs (english)
|
||||
... a few other files
|
||||
|
||||
/SCRIPTS/TOOLS/DSMLIB/img -- Images for RX orientations
|
||||
|
||||
Other Directories
|
||||
|
||||
/MODELS/DSMDATA --(ALL CAPITALS) Data of model config (Wing Type, Servo Assignments)
|
||||
/LOGS/dsm_log.txt --Readable log of the last RX/TX session, usefull for debugging problems
|
||||
|
||||
# NOTE for FC6250HX FC+RX version
|
||||
For the full size FC6250HX, Only use V0.55 or newer.
|
||||
|
||||
DO NOT use previous versions to do the Setup -> Gyro Settings -> Orientation. The problem was that it did not have the orientation messages.. and you are were choosing blind. The calibration will never stop until you place the RX in the right orientation, even after restarting the RX (if flashing red, is not in the right orientation.. if flashshing white is in the right orientation). If you run into this problem, and lights are blinking red, rotate the FC on the longer axis until you get white blinking.. keep it stable, will blink white faster andlet calibration finishes.. after that is back to normal.
|
||||
|
||||
OpenTX: When you enter "forward programming" you will hear "Telemetry lost" and "Telemetry recovered".. The FC led will blink white, but when exit FP, will blink red...is not problem.. but will need to be power cycled to get blinking green again.. i think is something related to temporarilly loosing the connection with the radio..researching the OpenTX code since it only happens with this helis FC.
|
||||
|
||||
# Common Questions
|
||||
1. `RX not accepting channels higher than Ch6 for Flight-mode o Gains:`
|
||||
- V0.55 and newer: Problem solved.. Should allow you to select up to 12ch with the switch technique or with the scroller.
|
||||
|
||||
- V0.53/0.54: The RX is listening to channel changes for this options. Configure the Switch to the channel, togling once the switch will select the channel on the menu field.
|
||||
|
||||
2. `Only able to switch to Fligh-mode 2 and 3, but not 1:`
|
||||
Check that the module "Enable max throw" is OFF in you Multi-Module settings (where you do BIND), otherwise the TX signals will be out of range.
|
||||
The multi-module is already adjusting the TX/FrSky servo range internally to match Spektrum.
|
||||
|
||||
3. `Why Ch1 says Ch1 (TX:Ch3/Thr)?`:
|
||||
Radios with Multi-Module are usually configured to work the standard AETR convention. Spektrum uses TAER. The multi-module does the conversion when transmitting the signals. So `Spektrum Ch1 (Throttle)` really comes from the `TX Ch3`. We show both information (+name from the TX output). If your multi-module/radio is setup as TAER, the script will not do the re-arrangement.
|
||||
|
||||
4. `If i change the model name, the original model settings are lost.` This is correct, the model name is used to generate the file name (inside /MODEL/DSMDATA) who stores the model configuration. Currently EdgeTx and OpenTX has differt features where i could get either the Model Name or the YAML file where the EdgeTX model configuration is stored.. to keep the code compatible, the model name is used.
|
||||
|
||||
5. `Reversing a channel in my TX do not reverse the AS3X/SAFE reaction.` Correct, the chanel stick direction and the Gyro direction are two separate things.
|
||||
|
||||
5.1: First, you have setup your model so that the sticks and switches moves the surfaces in the right direction.
|
||||
|
||||
5.2: Go to the script, `Model Setup` and setup your wing type, tail type, and select the channel assigment for each surface. Leave the servo settings the same as the values in the TX to start.
|
||||
|
||||
5.3: Go to `Forward programming->Gyro Setting->Initial Setup` (New/factory reset), or `Forward programming->Gyro Setting->System Setup->Relearn Servo Settings` (not new). This will load your current Gyro servo settings into the plane's RX. This moves the current servo TX settings to the RX, so it is now in a known state.
|
||||
|
||||
5.4: Verify that the AS3X and SAFE reacts in the proper direction. You can use the Flight mode configured as "Safe Mode: Auto-Level" to see if it moves the surfaces in the right direction.
|
||||
|
||||
5.5: If a surface don't move in the right direction, go to the `Model Setup->Gyro Channel Reverse` to reverse the Gyro on the channels needed, and do again the `Forward programming->Gyro Setting->System Setup->Relearn Servo Settings` to tranfer the new settings to the RX.
|
||||
|
||||
5.6: Specktrum TX always passes the TX servo reverse as the Gyro Reverse, but on many OpenTX/EdgeTX radios, the Rud/Ail are usually reversed by default compared to Specktrum. So far i don't think that i can use this as a rule, that is why the `Gyro Channel Reverse` page exist.
|
||||
|
||||
|
||||
|
||||
---
|
||||
---
|
||||
|
||||
# Changes and fixes
|
||||
V0.56:
|
||||
|
||||
1. Fix Tail-Type "Taileron" functionality that was not working. Also validated V-Tail and Delta wings.
|
||||
2. Added Taileron and two Rudder config (Many Freewing Jets like F18,F16, etc)
|
||||
3. Gyro-Reverse Screen now shows what is the channel/port used for (Ail, Ele, Rud, etc)
|
||||
4. COLOR ONLY: Gyro-Reverse Screen now shows what information that shared with the RX about each channel (Role, Slave, Reverse).
|
||||
5. NEW!! Initial version of Plane Setup for B&W radios
|
||||
|
||||
V0.55a:
|
||||
1. Fix loading external messages file for OpenTX.
|
||||
|
||||
V0.55:
|
||||
1. Finally found where the TX reports to the RX how many channels is transmiting. The TX now reports itself as a 12ch radio instead of 6h. (DSM Multi-Module limit). This fixes a few things:
|
||||
|
||||
|
||||
a. Many places where you have to select channels > CH6 for Flight-Mode, Gains, Panic now works properly with the scroller. The radio is still validating that you are not selecting an invalid channel. For example, if you have an additional AIL on CH6, it will not allow you to use CH6 for FM or Gains.. it just move to the next valid one.
|
||||
|
||||
b. When setting up AIL/ELE on channels greater than CH6, on previous versions SAFE/AS3X was not moving them.. now they work up correctly. Set them up in the first in CH1-CH10. Why CH10?? Thats what fits on the reverse screen, otherwise, have to add more screens.
|
||||
|
||||
c. Some individual Gain channels was not allowing to setup on CH greater than CH6. Now is fixed.
|
||||
|
||||
2. User Interface:
|
||||
a. `RTN` Key now works as `Back` when the screen has a `Back`. Makes it easy for navigation.. Presing `RTN` on the main screen exists the tool.
|
||||
b. Much faster refresh of the menus. Optimize the process of send/recive menu data from the RX.
|
||||
|
||||
3. The TX now comunicates the SubTrim positions to the RX during `Relearn Servo Setting`. This changes the center of movement to one side or another. Really not much difference with small amounts of subtrim, previous versions where asuming subtrim of 0. When you have an extreame subtrim to one side, it was not moving simetrically.
|
||||
|
||||
4. Support for FC6250HX (the one with separate RX).. Setup Swashplate type, RX orientation works properly.. This are menu options that the smaller version that comes in the
|
||||
Blade 230S did not have.
|
||||
|
||||
|
||||
V0.54:
|
||||
1. Fix a problem in the Attitude Trim page (`Gyro Settings->System Setup->SAFE/Panic Setup->Attitude Trim`). It was not saving the values after exiting the menu. This is to change what SAFE considers "Level" flying.
|
||||
2. Wings 2-Ail 2-Flaps had a bug on the 2nd flap.
|
||||
3. New Minimalistic script (`DsmFwdPrg_05_MIN.lua`): For radios with very low memory (FrSky QX7, RM Zorro, others). It can only change existing settings, but does not have the Plane Setup menus to setup a completly new plane. In some radios, the very first time it runs (compile + run), it might give you a `not enouth memory` error.. try to run it again.
|
||||
4. External menu message file (DSMLIB/msg_fwdp_en.txt and MIN_msg_fwdp_en.txt). Intial work to do localization and different languages.
|
||||
|
||||
V0.53:
|
||||
1. Improved channel selection (Flight mode, Panic Channel, Gains Channel). Now during editing a channel, you can select any channel (>Ch4). Also, of you toggle the switch/channel it will populate the screen.
|
||||
2. Support for smaller screens (128x64) in B&W. The problem with this older radios is memory. In some, it does not have enouth memory to load the additional DSMLIB libraries.
|
||||
3. Fix formatting problem with some TX channel names who could affect the screen.. for example, rud channel should show "Ch4/rud", but shows "Ch4ud" because /r is for right justify formatting on messages. Now the formatting is only if it appears at the end of the message.
|
||||
|
||||
V0.52:
|
||||
1. Menus to be able to configure Plane in a similar way as Spektrum Radio (v0.52)
|
||||
2. Make "Gyro Settings"->"Initial Setup" works (Tested on AR631,AR637xx with PLANE type of aircraft)
|
||||
3. Properly reset and restart after initial configuration and SAFE changes.
|
||||
4. Write Log of the conversation between RX/TX. To be used for debugging a problem is reported.
|
||||
5. Provide a simulation of RX to do GUI development in Companion, and understand patterns of how the data is organized.
|
||||
|
||||
|
||||
# Tested Hardware
|
||||
- AR631/AR637xx
|
||||
- FC6250HX (Blade 230S V2 Helicopter; FC+RX in one, mini version)
|
||||
- FC6250HX (Separate RX.. use only V55 or newer of this tool)
|
||||
- AR636 (Blade 230S V1 Heli firmware 4.40)
|
||||
|
||||
- Radiomaster TX16S (All versions)
|
||||
|
||||
Please report if you have tested it with other receivers to allow us to update the documentation. Code should work up to 10 channels for the main surfaces (Ail/Ele/etc). All Spektrum RX are internally 20 channels, so you can use Ch7 for Flight Mode even if your RX is only 6 channels (See common Questions)
|
||||
|
||||
|
||||
# Messages Displayed in the GUI
|
||||
|
||||
If in a screen you get text that looks like `Unknown_XX` (ex: Unknown_D3), that message has not been setup in the script in english. If you can determine what the proper message is, you can send us a message to be added to the library.
|
||||
The `XX` represents a Hex Number (0..9,A..F) message ID.
|
||||
|
||||
|
||||
### Version 0.53 and older:
|
||||
If you want to fix it in your local copy, all messages are towards the end in the file `SCRIPT\TOOS\DSMLIB\DsmFwPrgLib.lua`. Messages for Headers are stored in `Text` and messages for Options are stored in `List_Text`. Lua scripts are text files, and can be edited with Notepad or equivalent.
|
||||
|
||||
Portion of DsmFwPrgLib.lua:
|
||||
|
||||
Text[0x0097] = "Factory Reset"
|
||||
Text[0x0098] = "Factory Reset" -- FC6250HX: Title
|
||||
Text[0x0099] = "Advanced Setup"
|
||||
Text[0x009A] = "Capture Failsafe Positions"
|
||||
Text[0x009C] = "Custom Failsafe"
|
||||
|
||||
Text[0x009F] = "Save & Reset RX" -- TODO: Find the Proper Spektrum Value ??
|
||||
|
||||
Text[0x00A5] = "First Time Setup"
|
||||
Text[0x00AA] = "Capture Gyro Gains"
|
||||
Text[0x00AD] = "Gain Channel Select"
|
||||
|
||||
-- Safe mode options, Inhibit + the values
|
||||
local safeModeOptions = {0x0003,0x00B0,0x00B1} -- inh (gap), "Self-Level/Angle Dem, Envelope
|
||||
List_Text[0x00B0] = "Self-Level/Angle Dem"
|
||||
List_Text[0x00B1] = "Envelope"
|
||||
|
||||
For example, if you get `Unknown_9D` in the GUI and your now that it should say **NEW Text**, you can edit the lua script to look like this:
|
||||
|
||||
Text[0x009A] = "Capture Failsafe Positions"
|
||||
Text[0x009C] = "Custom Failsafe"
|
||||
|
||||
Text[0x009D] = "NEW Text" -- NEW Text added for AR98xx
|
||||
|
||||
Text[0x009F] = "Save & Reset RX" -- TODO: Find the proper Spektrum text
|
||||
|
||||
### Version 0.54 and newer:
|
||||
The menu messages are stored in DSMLIB/msg_fwdp_en.txt (For english). Just add the message there. MIN_msg_fwdp_en.txt has shorter messages overrides for screens who are smaller (for minimalistic 128x64 version). The reference to the message file is at the file `/DSMLIB/DsmFwPrgLib.lua` if you want to change to use another language.
|
||||
|
||||
T |0x0097|Factory Reset
|
||||
LT|0x00B0|Self-Level/Angle Dem
|
||||
LT|0x00B1|Envelope
|
||||
|
||||
|
||||
# LOG File
|
||||
|
||||
The log file of the last use of the script is located at `/LOGS/dsm_log.txt`. **It is overridden on every start to avoid filling up the SD card**. So if you want to keep it, copy or rename it before starting the script again. (it can be renamed in the TX by browsing the SD card)
|
||||
|
||||
The log is human readable. The first number is the number of seconds since the start, and then what is the current state of the Library, and what has been sent and received. The info in the log can be easily used to create a new simulation for that RX in the future.
|
||||
|
||||
Example Log:
|
||||
|
||||
5.340 WAIT_CMD: DSM_GotoMenu(0x1010,LastSelectedLine=0)
|
||||
5.350 MENU_TITLE: SEND DSM_getMenu(MenuId=0x1010 LastSelectedLine=0)
|
||||
5.440 MENU_TITLE: RESPONSE Menu: M[Id=0x1010 P=0x0 N=0x0 B=0x1000 Text="Gyro settings"[0xF9]]
|
||||
5.490 MENU_LINES: SEND DSM_getFirstMenuLine(MenuId=0x1010)
|
||||
5.590 MENU_LINES: RESPONSE MenuLine: L[#0 T=M VId=0x1011 Text="AS3X Settings"[0x1DD] MId=0x1010 ]
|
||||
5.640 MENU_LINES: SEND DSM_getNextLine(MenuId=0x1010,LastLine=0)
|
||||
5.740 MENU_LINES: RESPONSE MenuLine: L[#1 T=M VId=0x1019 Text="SAFE Settings"[0x1E2] MId=0x1010 ]
|
||||
5.790 MENU_LINES: SEND DSM_getNextLine(MenuId=0x1010,LastLine=1)
|
||||
5.850 MENU_LINES: RESPONSE MenuLine: L[#2 T=M VId=0x1021 Text="F-Mode Setup"[0x87] MId=0x1010 ]
|
||||
5.910 MENU_LINES: SEND DSM_getNextLine(MenuId=0x1010,LastLine=2)
|
||||
5.970 MENU_LINES: RESPONSE MenuLine: L[#3 T=M VId=0x1022 Text="System Setup"[0x86] MId=0x1010 ]
|
||||
6.020 MENU_LINES: SEND DSM_getNextLine(MenuId=0x1010,LastLine=3
|
||||
|
||||
# Validation of data by the RX
|
||||
|
||||
The RX validates the data. if you change to an invalid channel or do a invalid number range, the RX will change it at the end of editing the field.
|
||||
|
||||
---
|
||||
# Version 0.53
|
||||
- Improve Channel selection in menus
|
||||
- Support smaller screens 128x64 in the black/white mode.
|
||||
|
||||
# Version 0.52
|
||||
- Fix Reversing of Servos
|
||||
- Properly detect Multimodule Ch settings AETR
|
||||
---
|
||||
|
||||
# Version 0.51 (volunteer testing version, not for production)
|
||||
- New Screens to Configure Model (Wing Type/Tail Tail, etc)
|
||||
- Finally got understanding that the previous unknown 0x05 lines are to send Model/Servo data to RX.
|
||||
- Fix use of AR636B (Firmware version 4.40.0 for Blade 230 heli, is the only one with Forward Programming)
|
||||
- Aircraft types: Tested With Plane type only.. Glider and other in progress
|
||||
|
||||
### Known Problems:
|
||||
- 4-Servo Wing type (Dual Ail/Tail) in planes give conflicting servo assignments by defaults.. Solution choose your own Ch.
|
||||
- Glider, Heli, Drone: Still in development. In glider, only a few wing type works.. needs to restrict menu options for the only valid one.
|
||||
|
||||
|
||||
# Version 0.5
|
||||
|
||||
- Make the code more readable and understandable
|
||||
- Separate the DSM Forwards Programming logic from the GUI
|
||||
- Log the communication with the RX on a /LOGS/dsm_log.txt to allow to debug it easier
|
||||
and see the exchange of data between the RX/TX
|
||||
- Created a black/white Text only version with only Key/Roller Inputs
|
||||
- Created a nicer GUI for EdgeTX touch screen color Radios
|
||||
- RX simulation for GUI development: turn on `SIMULATION_ON=true` in the beginning of the lua file
|
||||
- Test it on AR631, AR637xx, FC6250HX (Helicopter)
|
||||
|
||||
### Some settings that can change (top of Lua file):
|
||||
SIMULATION_ON = false -- FALSE: hide similation menu (DEFAULT), TRUE: show RX simulation menu
|
||||
DEBUG_ON = 1 -- 0=NO DEBUG, 1=HIGH LEVEL 2=LOW LEVEL (Debug logged into the /LOGS/dsm_log.txt)
|
||||
USE_SPECKTRUM_COLORS = true -- true: Use spectrum colors, false: use theme colors (default on OpenTX, OpenTX handle colors different)
|
||||
|
||||
|
||||
### Known Problems:
|
||||
1. **Incorrect List Value Options:** Some Menu List line (`LINE_TYPE.LIST_MENU1` or `L_m1` in logs), the range (min/max) of valid values seems to be incorrect, but the RX corrects the values.
|
||||
in the MINimalistic version, the RX is doing all the range validation, and will show invalid options temporarilly. In an Spektrum radio, it happens so fast, that you don't notice it, but in LUA scripts who are slower, you can see it in the screen.
|
||||
In the COLOR version, The code has hardcoded the valid ranges to avoid this problem.
|
||||
|
||||
2. Glider/Heli/Drone wing types not ready.
|
||||
|
||||
For Helicopter, use airplane normal wing and normal tail
|
||||
|
||||
|
||||
# Version 0.2
|
||||
Original Version from Pascal Langer
|
||||
|
@ -1,683 +0,0 @@
|
||||
local toolName = "TNS|DSM AR636 Telemetry|TNE"
|
||||
---- ######################################################################### #
|
||||
---- # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html #
|
||||
---- # #
|
||||
---- # This program is free software; you can redistribute it and/or modify #
|
||||
---- # it under the terms of the GNU General Public License version 2 as #
|
||||
---- # published by the Free Software Foundation. #
|
||||
---- # #
|
||||
---- # This program is distributed in the hope that it will be useful #
|
||||
---- # but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
---- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
---- # GNU General Public License for more details. #
|
||||
---- # #
|
||||
---- #########################################################################
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Developer: Francisco Arzu
|
||||
-- Original idea taken from DsmPID.lua.. don't know who is the author
|
||||
--
|
||||
|
||||
local DEBUG_ON = false
|
||||
--
|
||||
|
||||
local TEXT_SIZE = 0 -- NORMAL
|
||||
local X_COL1_HEADER = 6
|
||||
local X_COL1_DATA = 60
|
||||
local X_COL2_HEADER = 170
|
||||
local X_COL2_DATA = 220
|
||||
local Y_LINE_HEIGHT = 20
|
||||
local Y_HEADER = 0
|
||||
local Y_DATA = Y_HEADER + Y_LINE_HEIGHT*2
|
||||
local X_DATA_LEN = 80
|
||||
local X_DATA_SPACE = 5
|
||||
|
||||
|
||||
local function getPage(iParam)
|
||||
-- get page from 0-based index
|
||||
-- {0,1,2,3}: cyclic (1), {4,5,6,7}: tail (2)
|
||||
local res = (math.floor(iParam/4)==0) and 0 or 1
|
||||
return res
|
||||
end
|
||||
|
||||
local function round(v)
|
||||
-- round float
|
||||
local factor = 100
|
||||
return math.floor(v * factor + 0.5) / factor
|
||||
end
|
||||
|
||||
|
||||
local function readValue(sensor)
|
||||
-- read from sensor, round and return
|
||||
local v = getValue(sensor)
|
||||
--v = round(v)
|
||||
return v
|
||||
end
|
||||
|
||||
local function readValueById(sensor)
|
||||
local i = getFieldInfo(sensor)
|
||||
if (i==nil) then return nil end
|
||||
|
||||
local v = getValue(i.id)
|
||||
return v
|
||||
end
|
||||
|
||||
|
||||
|
||||
local function readBatValue(sensor)
|
||||
-- read from sensor, round and return
|
||||
local v = getValue(sensor)
|
||||
if (v==nil) then return "--" end
|
||||
|
||||
return string.format("%2.2f",v)
|
||||
end
|
||||
|
||||
local function readActiveParamValue(sensor)
|
||||
-- read and return a validated active parameter value
|
||||
local v = getValue(sensor)
|
||||
if (v<1 or v>8) then
|
||||
return -1
|
||||
end
|
||||
return v
|
||||
end
|
||||
|
||||
|
||||
local function drawPIDScreen()
|
||||
-- draw labels and params on screen
|
||||
|
||||
local pageId = getValue("FLss")
|
||||
|
||||
lcd.clear()
|
||||
-- if active gain does not validate then assume
|
||||
-- Gain Adjustment Mode is disabled
|
||||
if not (pageId==4401 or pageId==4402) then
|
||||
lcd.drawText(0,0,"BLADE Gain Adjustment", TEXT_SIZE +INVERS)
|
||||
lcd.drawText(X_COL1_HEADER,Y_LINE_HEIGHT*1,"Enter Gain Adjustment Mode",TEXT_SIZE)
|
||||
lcd.drawText(X_COL1_HEADER,Y_LINE_HEIGHT*2,"Stk: Low/R + Low/R + Panic (3 sec)",TEXT_SIZE)
|
||||
lcd.drawText(X_COL1_HEADER,Y_LINE_HEIGHT*4,"Op: Right Stk: Up/Down to select, Left/Right change value",TEXT_SIZE)
|
||||
lcd.drawText(X_COL1_HEADER,Y_LINE_HEIGHT*5,"Panic to exit",TEXT_SIZE)
|
||||
return
|
||||
end
|
||||
|
||||
local activePage = (pageId % 100)-1 --Last 2 digits, make it zero base
|
||||
|
||||
lcd.drawText (X_COL1_HEADER, Y_HEADER, "Cyclic (0-200)", TEXT_SIZE + INVERS)
|
||||
lcd.drawText (X_COL2_HEADER, Y_HEADER, "Tail (0-200)", TEXT_SIZE + INVERS)
|
||||
|
||||
|
||||
|
||||
local p = readValue("FdeA")
|
||||
local i = readValue("FdeB")
|
||||
local d = readValue("FdeL")
|
||||
local r = readValue("FdeR")
|
||||
|
||||
local titles = {[0]="P:", "I:", "D:", "Resp:", "P:","I:","D:", "Filt:"}
|
||||
local values = {[0]=p,i,d,r,p,i,d,r}
|
||||
|
||||
local activeParam = readActiveParamValue("Hold")-1
|
||||
|
||||
for iParam=0,7 do
|
||||
-- highlight selected parameter
|
||||
local attr = (activeParam==iParam) and INVERS or 0
|
||||
-- circular index (per page)
|
||||
local perPageIndx = (iParam % 4)
|
||||
|
||||
-- set y draw coord
|
||||
local y = (perPageIndx+1)*Y_LINE_HEIGHT+Y_DATA
|
||||
|
||||
-- check if displaying cyclic params.
|
||||
local isCyclicPage = (getPage(iParam)==0)
|
||||
|
||||
-- labels
|
||||
local x = isCyclicPage and X_COL1_HEADER or X_COL2_HEADER
|
||||
-- labels are P,I,D for both pages except for last param
|
||||
local val = titles[iParam]
|
||||
lcd.drawText (x, y, val, TEXT_SIZE)
|
||||
|
||||
-- gains
|
||||
-- set all params for non-active page to '--' rather than 'last value'
|
||||
val = (getPage(iParam)==activePage) and values[iParam] or '--'
|
||||
x = isCyclicPage and X_COL1_DATA or X_COL2_DATA
|
||||
|
||||
if (val~=16384) then -- Active value
|
||||
lcd.drawText (x, y, val, attr + TEXT_SIZE)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local function drawFlightLogScreen()
|
||||
-- draw labels and params on screen
|
||||
local h = getValue("Hold")
|
||||
local activeParam = h-1 -- H
|
||||
|
||||
lcd.clear()
|
||||
lcd.drawText (X_COL1_HEADER, Y_HEADER, "Flight Log", TEXT_SIZE + INVERS)
|
||||
|
||||
-- read and return parameters
|
||||
local a = getValue("FdeA")
|
||||
local b = getValue("FdeB")
|
||||
local l = getValue("FdeL")
|
||||
local r = getValue("FdeR")
|
||||
local f = getValue("FLss")
|
||||
|
||||
local titles = {[0]="A:", "B:", "L:", "R:", "F:", "H:"}
|
||||
local values = {[0]=a,b,l,r,f,h}
|
||||
|
||||
local y = Y_LINE_HEIGHT+Y_DATA
|
||||
|
||||
for iParam=0,3 do -- A,B,L,R
|
||||
-- highlight selected parameter (rund)
|
||||
local attr = ((activeParam%4)==iParam) and INVERS or 0
|
||||
-- labels
|
||||
local x = X_COL1_HEADER
|
||||
local val = titles[iParam]
|
||||
lcd.drawText (x, y, val, TEXT_SIZE)
|
||||
|
||||
-- Values
|
||||
val = values[iParam]
|
||||
x = X_COL1_DATA + X_DATA_LEN
|
||||
if (val~=16384) then -- Active value
|
||||
lcd.drawText (x, y, val, attr + TEXT_SIZE + RIGHT)
|
||||
end
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
end
|
||||
|
||||
y = Y_LINE_HEIGHT+Y_DATA
|
||||
for iParam=4,5 do -- F, H
|
||||
-- labels
|
||||
local x = X_COL2_HEADER
|
||||
local val = titles[iParam]
|
||||
lcd.drawText (x, y, val, TEXT_SIZE + BOLD)
|
||||
|
||||
-- Values
|
||||
val = values[iParam]
|
||||
x = X_COL2_DATA + X_DATA_LEN
|
||||
lcd.drawText (x, y, val, TEXT_SIZE + RIGHT + BOLD)
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
end
|
||||
|
||||
-- Bat
|
||||
y = y + Y_LINE_HEIGHT
|
||||
local bat = readBatValue("A2") or "--"
|
||||
lcd.drawText (X_COL2_HEADER, y, "Bat:", TEXT_SIZE)
|
||||
lcd.drawText (X_COL2_DATA + X_DATA_LEN, y, bat, TEXT_SIZE + RIGHT)
|
||||
lcd.drawText (X_COL2_DATA + X_DATA_LEN + X_DATA_SPACE, y, "v", TEXT_SIZE)
|
||||
|
||||
end
|
||||
|
||||
local function servoAdjustScreen()
|
||||
-- draw labels and params on screen
|
||||
local pageId = getValue("FLss") -- FLss
|
||||
local activeParam = getValue("Hold")-1 -- Hold
|
||||
|
||||
lcd.clear()
|
||||
lcd.drawText (0, Y_HEADER, "BLADE Servo SubTrim", TEXT_SIZE + INVERS)
|
||||
|
||||
if pageId~=1234 then
|
||||
lcd.drawText(X_COL1_HEADER,Y_LINE_HEIGHT*1,"Enter Servo Adjustment Mode",TEXT_SIZE)
|
||||
lcd.drawText(X_COL1_HEADER,Y_LINE_HEIGHT*2,"Stk: Low/L + Low/R + Panic (3 sec)",TEXT_SIZE)
|
||||
lcd.drawText(X_COL1_HEADER,Y_LINE_HEIGHT*4,"Op: R Stk: Up/Down to select, Left/Right change value",TEXT_SIZE)
|
||||
lcd.drawText(X_COL1_HEADER,Y_LINE_HEIGHT*5,"Panic to exit",TEXT_SIZE)
|
||||
return
|
||||
end
|
||||
|
||||
local a = getValue("FdeA")
|
||||
local b = getValue("FdeB")
|
||||
local l = getValue("FdeL")
|
||||
|
||||
local titles = {[0]="Servo1:", "Servo2:", "Servo3:"}
|
||||
local values = {[0]=a,b,l}
|
||||
|
||||
for iParam=0,#values do -- S1,S2,S3
|
||||
-- highlight selected parameter
|
||||
local attr = (activeParam==iParam) and INVERS or 0
|
||||
|
||||
-- set y draw coord
|
||||
local y = (iParam+1)*Y_LINE_HEIGHT+Y_HEADER
|
||||
|
||||
-- labels
|
||||
local x = X_COL1_HEADER
|
||||
local val = titles[iParam]
|
||||
lcd.drawText (x, y, val, TEXT_SIZE)
|
||||
|
||||
val = values[iParam]
|
||||
x = X_COL1_DATA
|
||||
if (val~=16384) then -- Active value
|
||||
lcd.drawText (x, y, val, attr + TEXT_SIZE)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function Unsigned_to_SInt16(value)
|
||||
if value >= 0x8000 then -- Negative value??
|
||||
return value - 0x10000
|
||||
end
|
||||
return value
|
||||
end
|
||||
|
||||
local function getDegreesValue(sensor)
|
||||
local i = getFieldInfo(sensor)
|
||||
if (i==nil) then return "-unk-" end
|
||||
|
||||
local v = getValue(i.id)
|
||||
if v==nil then return "---" end
|
||||
local vs = Unsigned_to_SInt16(v)
|
||||
|
||||
return string.format("%0.1f o",vs/10)
|
||||
end
|
||||
|
||||
|
||||
local function getDecHexValue(sensor)
|
||||
local i = getFieldInfo(sensor)
|
||||
if (i==nil) then return "-unk-" end
|
||||
|
||||
local v = getValue(i.id)
|
||||
if v==nil then return "---" end
|
||||
local vs = Unsigned_to_SInt16(v)
|
||||
|
||||
return string.format("%d (0x%04X)",vs,v)
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
local function drawVersionScreen()
|
||||
local paramV = getValue("FdeA")
|
||||
local B = getValue("FdeB")
|
||||
local rxId = getValue("FdeL")
|
||||
local firmware = getValue("FLss")
|
||||
local prodId = getValue("Hold")
|
||||
local bat = readBatValue("A2")
|
||||
|
||||
lcd.clear()
|
||||
lcd.drawText (0, Y_HEADER, "BLADE Version", TEXT_SIZE + INVERS)
|
||||
|
||||
--Product ID
|
||||
local val = "ID_".. prodId
|
||||
|
||||
if (prodId==243) then val = "Blade 230 V1"
|
||||
elseif (prodId==250) then val = "Blade 230 V2 (not Smart)"
|
||||
elseif (prodId==149) then val = "Blade 250 CFX"
|
||||
end
|
||||
|
||||
local y = Y_DATA
|
||||
local x_data1 = X_COL1_DATA+X_DATA_LEN
|
||||
lcd.drawText (X_COL1_HEADER, y, "Prod:", TEXT_SIZE)
|
||||
lcd.drawText (x_data1, y, val, TEXT_SIZE)
|
||||
|
||||
-- RX
|
||||
val = "ID_"..rxId
|
||||
if (rxId==1) then val = "AR636"
|
||||
end
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText (X_COL1_HEADER, y, "RX:", TEXT_SIZE)
|
||||
lcd.drawText (x_data1, y, val, TEXT_SIZE)
|
||||
|
||||
-- Firmware
|
||||
val = string.format("%0.2f",firmware/100)
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText (X_COL1_HEADER, y, "Firmware:", TEXT_SIZE)
|
||||
lcd.drawText (x_data1, y, val, TEXT_SIZE)
|
||||
|
||||
-- ParamV
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText (X_COL1_HEADER, y, "Params:", TEXT_SIZE)
|
||||
lcd.drawText (x_data1, y, paramV, TEXT_SIZE)
|
||||
|
||||
-- Bat
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText (X_COL1_HEADER, y, "Bat:", TEXT_SIZE)
|
||||
lcd.drawText (x_data1, y, bat, TEXT_SIZE)
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText(X_COL1_HEADER,y,"Press Panic for 3s",TEXT_SIZE)
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText(X_COL1_HEADER,y,"Usually Panic is Ch7 on a switch and Revesed",TEXT_SIZE)
|
||||
|
||||
end
|
||||
|
||||
local function parseFlightMode(v)
|
||||
-- FlightMode (Hex: MMSGG) MM=Flight Mode, S=Status (0= off, 1=init, 2=Hold, 3=Running) GG=???
|
||||
if v==nil then return "---" end
|
||||
local fm = bit32.rshift(v, 12)
|
||||
local status = bit32.band(bit32.rshift(v, 8),0xF)
|
||||
|
||||
local res = " "..fm.." "
|
||||
|
||||
if (fm==0) then res = res .. " NORMAL"
|
||||
elseif (fm==1) then res = res .. " INTERMEDIATE"
|
||||
elseif (fm==2) then res = res .. " ADVANCED"
|
||||
elseif (fm==5) then res = res .. " PANIC"
|
||||
end
|
||||
|
||||
if (status==2) then res=res .. " HOLD" end
|
||||
|
||||
if (DEBUG_ON) then
|
||||
res = res .. string.format(" (0x%04X)",v)
|
||||
end
|
||||
|
||||
return res
|
||||
end
|
||||
|
||||
|
||||
local function drawAlpha6Monitor()
|
||||
lcd.clear()
|
||||
|
||||
local RxStatus = readValueById("2402") -- FlightMode (Hex: MMSGG) MM=Flight Mode, S=Status (0=init, 2=Ready, 3=Sensor Fault) GG=???
|
||||
|
||||
local ARoll = getDegreesValue("2406") --Att Roll
|
||||
local APitch = getDegreesValue("2408") --Att Pitch
|
||||
local AYaw = getDegreesValue("240B") --Att Yaw
|
||||
|
||||
|
||||
lcd.drawText (0,0, "BLADE Alpha6 Monitor", TEXT_SIZE+INVERS)
|
||||
|
||||
local y = Y_DATA
|
||||
local x_data1 = X_COL1_DATA+X_DATA_LEN
|
||||
local x_data2 = X_COL1_DATA+X_DATA_LEN*2
|
||||
local x_data3 = X_COL1_DATA+X_DATA_LEN*3
|
||||
|
||||
-- Flight Mode
|
||||
lcd.drawText (0,y, "F-Mode:"..parseFlightMode(RxStatus), TEXT_SIZE)
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText (x_data1,y, "Attitude", TEXT_SIZE+BOLD + RIGHT)
|
||||
lcd.drawText (x_data2,y, "Gyro", TEXT_SIZE+BOLD + RIGHT)
|
||||
lcd.drawText (x_data3,y, "Gain", TEXT_SIZE+BOLD + RIGHT)
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText (X_COL1_HEADER,y, "Rol:", TEXT_SIZE)
|
||||
lcd.drawText (x_data1,y, ARoll, TEXT_SIZE + RIGHT)
|
||||
lcd.drawText (x_data2,y, "-", TEXT_SIZE + RIGHT)
|
||||
lcd.drawText (x_data3,y, "-", TEXT_SIZE + RIGHT)
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText (X_COL1_HEADER,y, "Pitch:", TEXT_SIZE)
|
||||
lcd.drawText (x_data1,y, APitch, TEXT_SIZE + RIGHT)
|
||||
lcd.drawText (x_data2,y, "-", TEXT_SIZE + RIGHT)
|
||||
lcd.drawText (x_data3,y, "-", TEXT_SIZE + RIGHT)
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText (X_COL1_HEADER,y, "Yaw:", TEXT_SIZE)
|
||||
lcd.drawText (x_data1,y, AYaw, TEXT_SIZE + RIGHT)
|
||||
lcd.drawText (x_data2,y, "-", TEXT_SIZE + RIGHT)
|
||||
lcd.drawText (x_data3,y, "-", TEXT_SIZE + RIGHT)
|
||||
|
||||
y = y + Y_LINE_HEIGHT + Y_LINE_HEIGHT
|
||||
lcd.drawText (0,y, "Bat: "..readBatValue("A2").." v", TEXT_SIZE)
|
||||
|
||||
|
||||
-- Debug Values
|
||||
if (DEBUG_ON) then
|
||||
local s2400 = getDecHexValue("2400")
|
||||
local s2402 = getDecHexValue("2402")
|
||||
local s2404 = getDecHexValue("2404")
|
||||
|
||||
local s240D = getDecHexValue("240D")
|
||||
|
||||
local s1G00 = getDecHexValue("1G00")
|
||||
local s1G02 = getDecHexValue("1G02")
|
||||
local s1G04 = getDecHexValue("1G04")
|
||||
local s1G06 = getDecHexValue("1G06")
|
||||
local s1G08 = getDecHexValue("1G08")
|
||||
local s1G0B = getDecHexValue("1G0B")
|
||||
local s1G0D = getDecHexValue("1G0D")
|
||||
|
||||
local titles = {[0]=
|
||||
"2400","2402/FM-S-?",
|
||||
"2404","240D",
|
||||
"1G00","1G02","1G04",
|
||||
"1G06","1G08","1G0B","1G0D"}
|
||||
|
||||
local values = {[0]=
|
||||
s2400,s2402,s2404,s240D,
|
||||
s1G00,s1G02,s1G04,
|
||||
s1G06,s1G08,s1G0B,s1G0D}
|
||||
|
||||
|
||||
-- draw labels and params on screen
|
||||
|
||||
y = Y_LINE_HEIGHT*2 + Y_HEADER
|
||||
for iParam=0,#titles do -- ??
|
||||
-- labels
|
||||
local x = X_COL1_HEADER+220
|
||||
local val = titles[iParam]
|
||||
lcd.drawText (x, y, val, TEXT_SIZE)
|
||||
|
||||
val = values[iParam]
|
||||
x = X_COL1_DATA+250
|
||||
lcd.drawText (x, y, val, TEXT_SIZE)
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function readAlpha3arameters()
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
local function drawAS3XMonitor()
|
||||
lcd.clear()
|
||||
local s1G00 = getDecHexValue("1G00")
|
||||
local s1G02 = getDecHexValue("1G02")
|
||||
local s1G04 = getDecHexValue("1G04")
|
||||
local s1G06 = getDecHexValue("1G06")
|
||||
local s1G08 = getDecHexValue("1G08")
|
||||
local s1G0B = getDecHexValue("1G0B")
|
||||
local s1G0D = getDecHexValue("1G0D")
|
||||
|
||||
local s6C00 = getDecHexValue("6C00")
|
||||
local s6C02 = getDecHexValue("6C02")
|
||||
local s6C04 = getDecHexValue("6C04")
|
||||
|
||||
|
||||
|
||||
local RRoll = bit32.rshift(getValue("1G00") or 0,8)
|
||||
local RPitch = bit32.band(getValue("1G00") or 0,0xFF)
|
||||
local RYaw = bit32.rshift(getValue("1G02") or 0,8)
|
||||
|
||||
local HRoll = bit32.band(getValue("1G02") or 0,0xFF)
|
||||
local HPitch = bit32.rshift(getValue("1G04") or 0,8)
|
||||
local HYaw = bit32.band(getValue("1G04") or 0,0xFF)
|
||||
|
||||
local ARoll = bit32.rshift(getValue("1G06") or 0,8)
|
||||
local APitch = bit32.band(getValue("1G06") or 0,0xFF)
|
||||
local AYaw = bit32.rshift(getValue("1G08") or 0,8)
|
||||
|
||||
|
||||
lcd.drawText (0,0, "Plane AR636 AS3X Gains", TEXT_SIZE+INVERS)
|
||||
|
||||
local y = Y_DATA
|
||||
local x_data1 = X_COL1_DATA+X_DATA_LEN
|
||||
local x_data2 = X_COL1_DATA+X_DATA_LEN*2
|
||||
local x_data3 = X_COL1_DATA+X_DATA_LEN*3.1
|
||||
|
||||
-- Flight Mode
|
||||
--lcd.drawText (0,y, "F-Mode: "..(nil or "--"), TEXT_SIZE)
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText (x_data1,y, "Rate", TEXT_SIZE+BOLD + RIGHT)
|
||||
lcd.drawText (x_data2,y, "Head", TEXT_SIZE+BOLD + RIGHT)
|
||||
lcd.drawText (x_data3+X_DATA_SPACE*3,y, "Actual", TEXT_SIZE+BOLD + RIGHT)
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText (X_COL1_HEADER,y, "Roll %:", TEXT_SIZE)
|
||||
lcd.drawText (x_data1,y, RRoll, TEXT_SIZE + RIGHT)
|
||||
lcd.drawText (x_data2,y, HRoll, TEXT_SIZE + RIGHT)
|
||||
lcd.drawText (x_data3,y, ARoll, TEXT_SIZE + RIGHT)
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText (X_COL1_HEADER,y, "Pitch %:", TEXT_SIZE)
|
||||
lcd.drawText (x_data1,y, RPitch, TEXT_SIZE + RIGHT)
|
||||
lcd.drawText (x_data2,y, HPitch, TEXT_SIZE + RIGHT)
|
||||
lcd.drawText (x_data3,y, APitch, TEXT_SIZE + RIGHT)
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText (X_COL1_HEADER,y, "Yaw %:", TEXT_SIZE)
|
||||
lcd.drawText (x_data1,y, RYaw, TEXT_SIZE + RIGHT)
|
||||
lcd.drawText (x_data2,y, HYaw, TEXT_SIZE + RIGHT)
|
||||
lcd.drawText (x_data3,y, AYaw, TEXT_SIZE + RIGHT)
|
||||
|
||||
|
||||
-- Debug Values
|
||||
if (DEBUG_ON) then
|
||||
local Alpha3Tags = {[0]=
|
||||
"1G00/RA+RE","1G02/RY+HA","1G04R HP+HY","1G06/AR+AP","1G08/AY+?","1G0B","1G0D","6C00","6C02","6C04"}
|
||||
|
||||
local params = {[0]=
|
||||
s1G00,s1G02,s1G04,s1G06,s1G08,s1G0B,s1G0D,s6C00,s6C02,s6C04 }
|
||||
|
||||
y = Y_LINE_HEIGHT*2 + Y_HEADER
|
||||
for iParam=0,#Alpha3Tags do -- ??
|
||||
-- labels
|
||||
local x = X_COL1_HEADER+220
|
||||
local val = Alpha3Tags[iParam]
|
||||
lcd.drawText (x, y, val, TEXT_SIZE)
|
||||
|
||||
val = params[iParam]
|
||||
x = X_COL1_DATA+250
|
||||
lcd.drawText (x, y, val, TEXT_SIZE)
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function openTelemetryRaw(i2cId)
|
||||
--Init telemetry (Spectrun Telemetry Raw STR)
|
||||
multiBuffer( 0, string.byte('S') )
|
||||
multiBuffer( 1, string.byte('T') )
|
||||
multiBuffer( 2, string.byte('R') )
|
||||
multiBuffer( 3, i2cId ) -- Monitor this teemetry data
|
||||
multiBuffer( 4, 0 ) -- Allow to get Data
|
||||
end
|
||||
|
||||
local function closeTelemetryRaw()
|
||||
multiBuffer(0, 0) -- Destroy the STR header
|
||||
multiBuffer(3, 0) -- Not requesting any Telementry ID
|
||||
end
|
||||
|
||||
local lineText = {nil}
|
||||
local I2C_TEXT_GEN = 0x0C
|
||||
|
||||
local function drawTextGen(event)
|
||||
if (multiBuffer(0)~=string.byte('S')) then -- First time run???
|
||||
openTelemetryRaw(I2C_TEXT_GEN) -- I2C_ID for TEXT_GEN
|
||||
lineText = {nil}
|
||||
end
|
||||
|
||||
-- Proces TEXT GEN Telementry message
|
||||
if multiBuffer( 4 ) == I2C_TEXT_GEN then -- Specktrum Telemetry ID of data received
|
||||
local instanceNo = multiBuffer( 5 )
|
||||
local lineNo = multiBuffer( 6 )
|
||||
local line = ""
|
||||
for i=0,13 do
|
||||
line = line .. string.char(multiBuffer( 7 + i ))
|
||||
end
|
||||
|
||||
multiBuffer( 4, 0 ) -- Clear Semaphore, to notify that we fully process the current message
|
||||
lineText[lineNo]=line
|
||||
end
|
||||
|
||||
lcd.clear()
|
||||
-- Header
|
||||
if (lineText[0]) then
|
||||
lcd.drawText (X_COL1_HEADER,0, " "..lineText[0].." ", TEXT_SIZE + BOLD + INVERS)
|
||||
else
|
||||
lcd.drawText (X_COL1_HEADER,0, "TextGen", TEXT_SIZE+INVERS)
|
||||
end
|
||||
|
||||
-- Menu lines
|
||||
local y = Y_DATA
|
||||
for i=1,8 do
|
||||
if (lineText[i]) then
|
||||
lcd.drawText (X_COL1_HEADER,y, lineText[i], TEXT_SIZE)
|
||||
end
|
||||
y = y + Y_LINE_HEIGHT
|
||||
end
|
||||
|
||||
if event == EVT_VIRTUAL_EXIT then -- Exit?? Clear menu data
|
||||
closeTelemetryRaw()
|
||||
end
|
||||
end
|
||||
|
||||
local telPage = 1
|
||||
local telPageSelected = 0
|
||||
local pageTitle = {[0]="Main", "Blade Version", "Blade Servo Adjust","Blade Gyro Adjust", "Blade Alpha6 Monitor", "Plane AS3X Monitor", "TextGen", "Flight Log"}
|
||||
|
||||
local function drawMainScreen(event)
|
||||
lcd.clear()
|
||||
lcd.drawText (X_COL1_HEADER, Y_HEADER, "Main Telemetry (AR636)", TEXT_SIZE + INVERS)
|
||||
|
||||
for iParam=1,#pageTitle do
|
||||
-- highlight selected parameter
|
||||
local attr = (telPage==iParam) and INVERS or 0
|
||||
|
||||
-- set y draw coord
|
||||
local y = (iParam-1)*Y_LINE_HEIGHT+Y_DATA
|
||||
|
||||
-- labels
|
||||
local x = X_COL1_HEADER
|
||||
local val = pageTitle[iParam]
|
||||
lcd.drawText (x, y, val, attr + TEXT_SIZE)
|
||||
end
|
||||
|
||||
if event == EVT_VIRTUAL_PREV then
|
||||
if (telPage>1) then telPage = telPage - 1 end
|
||||
elseif event == EVT_VIRTUAL_NEXT then
|
||||
if (telPage<#pageTitle) then telPage = telPage + 1 end
|
||||
elseif event == EVT_VIRTUAL_ENTER then
|
||||
telPageSelected = telPage
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local pageDraw = {[0]=drawMainScreen, drawVersionScreen, servoAdjustScreen,drawPIDScreen, drawAlpha6Monitor, drawAS3XMonitor, drawTextGen, drawFlightLogScreen}
|
||||
|
||||
local function run_func(event)
|
||||
if event == nil then
|
||||
error("Cannot be run as a model script!")
|
||||
return 2
|
||||
end
|
||||
|
||||
-- draw specific page
|
||||
pageDraw[telPageSelected](event)
|
||||
|
||||
if event == EVT_VIRTUAL_EXIT then
|
||||
if (telPageSelected==0) then return 1 end -- on Main?? Exit Script
|
||||
telPageSelected = 0 -- any page, return to Main
|
||||
end
|
||||
|
||||
return 0
|
||||
end
|
||||
|
||||
local function init_func()
|
||||
|
||||
if (LCD_W <= 128 or LCD_H <=64) then -- Smaller Screens
|
||||
TEXT_SIZE = SMLSIZE
|
||||
X_COL1_HEADER = 0
|
||||
X_COL1_DATA = 20
|
||||
|
||||
X_COL2_HEADER = 60
|
||||
X_COL2_DATA = 90
|
||||
|
||||
X_DATA_LEN = 28
|
||||
X_DATA_SPACE = 1
|
||||
|
||||
|
||||
Y_LINE_HEIGHT = 8
|
||||
Y_DATA = Y_HEADER + Y_LINE_HEIGHT
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
return { run=run_func, init=init_func }
|
@ -1,603 +0,0 @@
|
||||
local toolName = "TNS|DSM Smart RX Telemetry|TNE"
|
||||
---- ######################################################################### #
|
||||
---- # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html #
|
||||
---- # #
|
||||
---- # This program is free software; you can redistribute it and/or modify #
|
||||
---- # it under the terms of the GNU General Public License version 2 as #
|
||||
---- # published by the Free Software Foundation. #
|
||||
---- # #
|
||||
---- # This program is distributed in the hope that it will be useful #
|
||||
---- # but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
---- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
---- # GNU General Public License for more details. #
|
||||
---- # #
|
||||
---- #########################################################################
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Developer: Francisco Arzu
|
||||
|
||||
|
||||
local DEBUG_ON = false
|
||||
--
|
||||
|
||||
local TEXT_SIZE = 0 -- NORMAL
|
||||
local X_COL1_HEADER = 6
|
||||
local X_COL1_DATA = 60
|
||||
local X_COL2_HEADER = 170
|
||||
local X_COL2_DATA = 220
|
||||
local Y_LINE_HEIGHT = 20
|
||||
local Y_HEADER = 0
|
||||
local Y_DATA = Y_HEADER + Y_LINE_HEIGHT*2
|
||||
local X_DATA_LEN = 80
|
||||
local X_DATA_SPACE = 5
|
||||
|
||||
|
||||
|
||||
|
||||
local function getPage(iParam)
|
||||
-- get page from 0-based index
|
||||
-- {0,1,2,3}: cyclic (1), {4,5,6,7}: tail (2)
|
||||
local res = (math.floor(iParam/4)==0) and 0 or 1
|
||||
return res
|
||||
end
|
||||
|
||||
local function round(v)
|
||||
-- round float
|
||||
local factor = 100
|
||||
return math.floor(v * factor + 0.5) / factor
|
||||
end
|
||||
|
||||
|
||||
local function readValue(sensor)
|
||||
-- read from sensor, round and return
|
||||
local v = getValue(sensor)
|
||||
--v = round(v)
|
||||
return v
|
||||
end
|
||||
|
||||
local function readValueById(sensor)
|
||||
local i = getFieldInfo(sensor)
|
||||
if (i==nil) then return nil end
|
||||
|
||||
local v = getValue(i.id)
|
||||
return v
|
||||
end
|
||||
|
||||
|
||||
|
||||
local function readBatValue(sensor)
|
||||
-- read from sensor, round and return
|
||||
local v = getValue(sensor)
|
||||
if (v==nil) then return v end
|
||||
|
||||
return string.format("%2.2f",v)
|
||||
end
|
||||
|
||||
local function readActiveParamValue(sensor)
|
||||
-- read and return a validated active parameter value
|
||||
local v = getValue(sensor)
|
||||
if (v<1 or v>8) then
|
||||
return -1
|
||||
end
|
||||
return v
|
||||
end
|
||||
|
||||
|
||||
|
||||
local function drawFlightLogScreen(event)
|
||||
-- draw labels and params on screen
|
||||
local h = getValue("Hold")
|
||||
local activeParam = h-1 -- H
|
||||
|
||||
lcd.clear()
|
||||
lcd.drawText (X_COL1_HEADER, Y_HEADER, "Flight Log", TEXT_SIZE + INVERS)
|
||||
|
||||
-- read and return parameters
|
||||
local a = getValue("FdeA")
|
||||
local b = getValue("FdeB")
|
||||
local l = getValue("FdeL")
|
||||
local r = getValue("FdeR")
|
||||
local f = getValue("FLss")
|
||||
|
||||
local titles = {[0]="A:", "B:", "L:", "R:", "F:", "H:"}
|
||||
local values = {[0]=a,b,l,r,f,h}
|
||||
|
||||
local y = Y_LINE_HEIGHT+Y_DATA
|
||||
|
||||
for iParam=0,3 do -- A,B,L,R
|
||||
-- highlight selected parameter (rund)
|
||||
local attr = ((activeParam%4)==iParam) and INVERS or 0
|
||||
-- labels
|
||||
local x = X_COL1_HEADER
|
||||
local val = titles[iParam]
|
||||
lcd.drawText (x, y, val, TEXT_SIZE)
|
||||
|
||||
-- Values
|
||||
val = values[iParam]
|
||||
x = X_COL1_DATA + X_DATA_LEN
|
||||
if (val~=16384) then -- Active value
|
||||
lcd.drawText (x, y, val, attr + TEXT_SIZE + RIGHT)
|
||||
end
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
end
|
||||
|
||||
y = Y_LINE_HEIGHT+Y_DATA
|
||||
for iParam=4,5 do -- F, H
|
||||
-- labels
|
||||
local x = X_COL2_HEADER
|
||||
local val = titles[iParam]
|
||||
lcd.drawText (x, y, val, TEXT_SIZE + BOLD)
|
||||
|
||||
-- Values
|
||||
val = values[iParam]
|
||||
x = X_COL2_DATA + X_DATA_LEN
|
||||
lcd.drawText (x, y, val, TEXT_SIZE + RIGHT + BOLD)
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
end
|
||||
|
||||
-- Bat
|
||||
y = y + Y_LINE_HEIGHT
|
||||
local bat = readBatValue("A2") or "--"
|
||||
lcd.drawText (X_COL2_HEADER, y, "Bat:", TEXT_SIZE)
|
||||
lcd.drawText (X_COL2_DATA + X_DATA_LEN, y, bat, TEXT_SIZE + RIGHT)
|
||||
lcd.drawText (X_COL2_DATA + X_DATA_LEN + X_DATA_SPACE, y, "v", TEXT_SIZE)
|
||||
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
local function Unsigned_to_SInt16(value)
|
||||
if value >= 0x8000 then -- Negative value??
|
||||
return value - 0x10000
|
||||
end
|
||||
return value
|
||||
end
|
||||
|
||||
local function getDegreesValue(sensor)
|
||||
local i = getFieldInfo(sensor)
|
||||
if (i==nil) then return "-unk-" end
|
||||
|
||||
local v = getValue(i.id)
|
||||
if v==nil then return "---" end
|
||||
local vs = Unsigned_to_SInt16(v)
|
||||
|
||||
return string.format("%0.1f o",vs/10)
|
||||
end
|
||||
|
||||
|
||||
local function getDecHexValue(sensor)
|
||||
local i = getFieldInfo(sensor)
|
||||
if (i==nil) then return "-unk-" end
|
||||
|
||||
local v = getValue(i.id)
|
||||
if v==nil then return "---" end
|
||||
local vs = Unsigned_to_SInt16(v)
|
||||
|
||||
return string.format("%d (0x%04X)",vs,v)
|
||||
end
|
||||
|
||||
local as3xData = {[0]=0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
|
||||
local function drawAS3XSettings(event, page)
|
||||
local s0500 = getDecHexValue("0500")
|
||||
local s0502 = getDecHexValue("0502")
|
||||
local s0504 = getDecHexValue("0504")
|
||||
local s0506 = getDecHexValue("0506")
|
||||
local s0508 = getDecHexValue("0508")
|
||||
local s050B = getDecHexValue("050B")
|
||||
local s050D = getDecHexValue("050D")
|
||||
|
||||
local d0500 = readValueById("0500") or 0
|
||||
local flags = bit32.rshift(d0500,8)
|
||||
local state = bit32.band(d0500,0xFF)
|
||||
|
||||
local flagsMsg=""
|
||||
-- flags bits: Safe Envelop, ?, Angle Demand, Stab
|
||||
if (bit32.band(flags,0x1)~=0) then flagsMsg=flagsMsg.."AS3X Stab" end
|
||||
-- This one, only one should show
|
||||
if (bit32.band(flags,0x2)~=0) then flagsMsg=flagsMsg..", Angle Demand"
|
||||
elseif (bit32.band(flags,0x8)~=0) then flagsMsg=flagsMsg..", Safe Envelope"
|
||||
elseif (bit32.band(flags,0x4)~=0) then flagsMsg=flagsMsg..", AS3X Heading" end
|
||||
|
||||
local d0502 = readValueById("0502") or 0 -- 0x?F?S
|
||||
local fm = bit32.band(bit32.rshift(d0502,8),0xF) -- 0,1,2
|
||||
|
||||
local axis = bit32.band(d0502,0xF) -- 0=Gains,1=Headings,2=Angle Limits (cointinus iterating to provide all values)
|
||||
|
||||
local d0504 = readValueById("0504") or 0
|
||||
local d0506 = readValueById("0506") or 0
|
||||
local d0508 = readValueById("0508") or 0
|
||||
|
||||
local d0 = bit32.rshift(d0504,8)
|
||||
local d1 = bit32.band(d0504,0xFF)
|
||||
local d2 = bit32.rshift(d0506,8)
|
||||
local d3 = bit32.band(d0506,0xFF)
|
||||
local d4 = bit32.rshift(d0508,8)
|
||||
local d5 = bit32.band(d0508,0xFF)
|
||||
|
||||
--axis: 0=Gains+Headings (RG,PG,YG,RH,PH,YH), 1=Safe Gains (R,P,Y),2=Angle Limits(L,R,U,D)
|
||||
--Constantly changing from 0..2 to represent different data, thats why we have to store the values
|
||||
--in a script/global variable, and not local to the function
|
||||
local s = axis*6
|
||||
as3xData[s+0] = d0
|
||||
as3xData[s+1] = d1
|
||||
as3xData[s+2] = d2
|
||||
as3xData[s+3] = d3
|
||||
as3xData[s+4] = d4
|
||||
as3xData[s+5] = d5
|
||||
|
||||
|
||||
lcd.clear()
|
||||
lcd.drawText (0,0, "AS3X/SAFE Settings", TEXT_SIZE + INVERS)
|
||||
|
||||
local y = Y_DATA
|
||||
-- Flight Mode
|
||||
lcd.drawText (X_COL1_HEADER,y, "FM: "..(fm+1), TEXT_SIZE)
|
||||
lcd.drawText (X_COL1_DATA+X_DATA_LEN*0.3,y, "Flags: "..flags, TEXT_SIZE)
|
||||
lcd.drawText (X_COL2_HEADER+X_DATA_LEN*0.3,y, "State: "..state, TEXT_SIZE)
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText (X_COL1_HEADER,y, flagsMsg, TEXT_SIZE)
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
|
||||
if (page==1) then
|
||||
lcd.drawText (X_COL1_HEADER+X_DATA_LEN*0.3,y, "AS3X Gains", TEXT_SIZE+BOLD)
|
||||
lcd.drawText (X_COL2_HEADER+X_DATA_LEN*0.3,y, "AS3X Headings", TEXT_SIZE+BOLD)
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText (X_COL1_HEADER,y, "Roll:", TEXT_SIZE)
|
||||
lcd.drawText (X_COL1_DATA+X_DATA_LEN,y, as3xData[0], TEXT_SIZE + RIGHT) -- Roll G
|
||||
lcd.drawText (X_COL2_DATA+X_DATA_LEN,y, as3xData[3], TEXT_SIZE + RIGHT) -- Roll H
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText (X_COL1_HEADER,y, "Pitch:", TEXT_SIZE)
|
||||
lcd.drawText (X_COL1_DATA+X_DATA_LEN,y,as3xData[1], TEXT_SIZE + RIGHT) -- Pitch G
|
||||
lcd.drawText (X_COL2_DATA+X_DATA_LEN,y, as3xData[4], TEXT_SIZE + RIGHT) -- Pitch H
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText (X_COL1_HEADER,y, "Yaw:", TEXT_SIZE)
|
||||
lcd.drawText (X_COL1_DATA+X_DATA_LEN,y, as3xData[2], TEXT_SIZE + RIGHT) -- Yaw G
|
||||
lcd.drawText (X_COL2_DATA+X_DATA_LEN,y, as3xData[5], TEXT_SIZE + RIGHT) -- Yaw H
|
||||
end
|
||||
|
||||
|
||||
if (page==2) then
|
||||
local x_data1 = X_COL1_DATA+X_DATA_LEN
|
||||
local x_data2 = X_COL2_HEADER+X_DATA_LEN*1.6
|
||||
|
||||
lcd.drawText (X_COL1_HEADER+X_DATA_LEN*0.3,y, "SAFE Gains", TEXT_SIZE+BOLD)
|
||||
lcd.drawText (X_COL2_HEADER+X_DATA_LEN*0.1,y, "Angle Limits", TEXT_SIZE+BOLD)
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText (X_COL1_HEADER,y, "Roll:", TEXT_SIZE)
|
||||
lcd.drawText (x_data1,y, as3xData[6], TEXT_SIZE + RIGHT)
|
||||
|
||||
lcd.drawText (X_COL2_HEADER,y, "Roll R:", TEXT_SIZE)
|
||||
lcd.drawText (x_data2,y, as3xData[12], TEXT_SIZE + RIGHT)
|
||||
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText (X_COL1_HEADER,y, "Pitch:", TEXT_SIZE)
|
||||
lcd.drawText (x_data1,y,as3xData[7], TEXT_SIZE + RIGHT)
|
||||
|
||||
lcd.drawText (X_COL2_HEADER,y, "Roll L:", TEXT_SIZE)
|
||||
lcd.drawText (x_data2,y,as3xData[13], TEXT_SIZE + RIGHT)
|
||||
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText (X_COL1_HEADER,y, "Yaw:", TEXT_SIZE)
|
||||
lcd.drawText (x_data1,y, as3xData[8], TEXT_SIZE + RIGHT)
|
||||
|
||||
lcd.drawText (X_COL2_HEADER,y, "Pitch U:", TEXT_SIZE)
|
||||
lcd.drawText (x_data2,y, as3xData[14], TEXT_SIZE + RIGHT)
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText (X_COL2_HEADER,y, "Pitch D:", TEXT_SIZE)
|
||||
lcd.drawText (x_data2,y, as3xData[15], TEXT_SIZE + RIGHT)
|
||||
end
|
||||
|
||||
-- Debug Values
|
||||
if (DEBUG_ON) then
|
||||
local titles = {[0]=
|
||||
"0500","0502","0504","0506","0508","050B","050D"}
|
||||
|
||||
local values = {[0]=
|
||||
s0500,s0502,s0504,s0506,s0508,s050B,s050D }
|
||||
|
||||
y = Y_LINE_HEIGHT*2 + Y_HEADER
|
||||
for iParam=0,#titles do -- ??
|
||||
-- labels
|
||||
local x = X_COL1_HEADER+250
|
||||
local val = titles[iParam]
|
||||
lcd.drawText (x, y, val, TEXT_SIZE)
|
||||
|
||||
val = values[iParam] or "--"
|
||||
x = X_COL1_DATA+250
|
||||
lcd.drawText (x, y, val, TEXT_SIZE)
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function drawAS3XSettingsP1(event)
|
||||
drawAS3XSettings(event, 1)
|
||||
end
|
||||
|
||||
local function drawAS3XSettingsP2(event)
|
||||
drawAS3XSettings(event, 2)
|
||||
end
|
||||
|
||||
|
||||
local function doFloat(v)
|
||||
if v==nil then return 0.0 end
|
||||
|
||||
local vs = string.format("%1.2f",v)
|
||||
|
||||
return vs + 0.0
|
||||
end
|
||||
|
||||
|
||||
local ESC_Title={[0]="","RPM:","Volts:","Motor:","Mot Out:","Throttle:","FET Temp:", "BEC V:", "BEC T:", "BEC A:"}
|
||||
local ESC_uom={[0]="","","V","A","%","%","C", "V","C","A"}
|
||||
local ESC_Status={[0]=0,0,0,0,0,0,0,0,0,0,0}
|
||||
local ESC_Min={[0]=0,0,0,0,0,0,0,0,0,0,0}
|
||||
local ESC_Max={[0]=0,0,0,0,0,0,0,0,0,0,0}
|
||||
|
||||
local function drawESCStatus(event)
|
||||
lcd.clear()
|
||||
ESC_Status[1] = getValue("Erpm") -- RPM
|
||||
ESC_Status[2] = doFloat(getValue("EVIN")) -- Volts
|
||||
ESC_Status[3] = doFloat(getValue("ECUR")) -- Current
|
||||
ESC_Status[4] = doFloat(getValue("EOUT")) -- % Output
|
||||
ESC_Status[5] = doFloat(getValue("ETHR")) -- Throttle % (EOUT)
|
||||
ESC_Status[6] = getValue("TFET") -- Temp FET
|
||||
|
||||
ESC_Status[7] = doFloat(getValue("VBEC")) -- Volts BEC
|
||||
ESC_Status[8] = getValue("TBEC") -- Temp BEC
|
||||
ESC_Status[9] = doFloat(getValue("CBEC")) -- Current BEC
|
||||
|
||||
for i=1,9 do
|
||||
if (ESC_Status~=nil) then
|
||||
if (ESC_Min[i]==0) then
|
||||
ESC_Min[i]=ESC_Status[i]
|
||||
else
|
||||
ESC_Min[i] = math.min(ESC_Min[i],ESC_Status[i])
|
||||
end
|
||||
|
||||
ESC_Max[i] = math.max(ESC_Max[i],ESC_Status[i])
|
||||
end
|
||||
end
|
||||
|
||||
lcd.drawText (0,0, "ESC", TEXT_SIZE+INVERS)
|
||||
|
||||
local y = 0
|
||||
local x_data = X_COL1_DATA+X_DATA_LEN*1.5
|
||||
local x_data2 = X_COL2_DATA+X_DATA_LEN*0.5
|
||||
local x_data3 = x_data2 + X_DATA_LEN*0.8
|
||||
|
||||
|
||||
lcd.drawText (x_data,y , "Status", TEXT_SIZE+BOLD+RIGHT)
|
||||
lcd.drawText (x_data2,y, "Min", TEXT_SIZE+BOLD+RIGHT)
|
||||
lcd.drawText (x_data3,y, "Max", TEXT_SIZE+BOLD+RIGHT)
|
||||
|
||||
y = Y_DATA
|
||||
for i=1,9 do
|
||||
lcd.drawText (X_COL1_HEADER,y, ESC_Title[i], TEXT_SIZE + BOLD)
|
||||
|
||||
lcd.drawText (x_data,y, ESC_Status[i] or "--", TEXT_SIZE + RIGHT)
|
||||
lcd.drawText (x_data + X_DATA_SPACE,y, ESC_uom[i], TEXT_SIZE)
|
||||
|
||||
lcd.drawText (x_data2,y, ESC_Min[i] or "--", TEXT_SIZE + RIGHT)
|
||||
lcd.drawText (x_data3,y, ESC_Max[i] or "--", TEXT_SIZE + RIGHT)
|
||||
y = y + Y_LINE_HEIGHT
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local function drawBATStatus(event)
|
||||
local Title={[0]="","Bat:","Temp:","Rem :","Curr:","Used:","Imbal:","Cycles:", "RX:", "BCpT?:"}
|
||||
local uom={[0]="","V","C","%","mAh","mAh","mV","", "V",""}
|
||||
local Values={[0]=0,0,0,0,0,0,0,0,0,0,0}
|
||||
local CellValues={[0]=0,0,0,0,0,0,0,0,0,0,0}
|
||||
|
||||
lcd.clear()
|
||||
|
||||
local ESC_Volts = getValue("EVIN") or 0 -- Volts
|
||||
local ESC_Current = getValue("ECUR") or 0 -- Current
|
||||
|
||||
Values[1] = 0 -- compute later
|
||||
Values[2] = getValue("BTmp") -- Current (C)
|
||||
Values[3] = nil -- Remaining???
|
||||
Values[4] = getValue("BCur") -- Current (mAh)
|
||||
Values[5] = getValue("BUse") -- Current Used (mAh)
|
||||
Values[6] = getValue("CLMa") -- 0.0 (mV) Imbalance
|
||||
Values[7] = getValue("Cycl") -- Cycles
|
||||
Values[8] = readBatValue("A2") -- v
|
||||
Values[9] = getValue("BCpT") -- Current (mAh) ????
|
||||
|
||||
|
||||
--- Total Voltange Calculation
|
||||
local VTotal=0
|
||||
for i=1,10 do
|
||||
CellValues[i] = getValue("Cel"..i)
|
||||
VTotal = VTotal + CellValues[i]
|
||||
end
|
||||
|
||||
if (VTotal==0) then -- No Inteligent Battery,use intelligent ESC if any
|
||||
VTotal = ESC_Volts
|
||||
Values[4] = string.format("%d",ESC_Current * 1000)
|
||||
end
|
||||
|
||||
Values[1] = string.format("%2.2f",VTotal)
|
||||
|
||||
--- SCREEN
|
||||
|
||||
lcd.drawText (X_COL1_HEADER,0, "Battery Stats", TEXT_SIZE+INVERS)
|
||||
|
||||
|
||||
|
||||
local y = Y_DATA
|
||||
local x_data = X_COL1_DATA+X_DATA_LEN+X_DATA_SPACE*3
|
||||
for i=2,9 do
|
||||
lcd.drawText (X_COL1_HEADER, y, Title[i], TEXT_SIZE + BOLD)
|
||||
lcd.drawText (x_data, y, Values[i] or "--", TEXT_SIZE + RIGHT)
|
||||
lcd.drawText (x_data+X_DATA_SPACE, y, uom[i], TEXT_SIZE)
|
||||
y = y + Y_LINE_HEIGHT
|
||||
end
|
||||
|
||||
y = Y_DATA
|
||||
x_data = X_COL2_DATA+X_DATA_LEN+X_DATA_SPACE*5
|
||||
for i=1,8 do
|
||||
if ((CellValues[i] or 0) > 0) then
|
||||
lcd.drawText (X_COL2_HEADER+X_DATA_LEN/2,y, "Cel "..i..":", TEXT_SIZE + BOLD)
|
||||
lcd.drawText (x_data,y, string.format("%2.2f",CellValues[i] or 0), TEXT_SIZE + RIGHT)
|
||||
lcd.drawText (x_data+X_DATA_SPACE,y, "v", TEXT_SIZE)
|
||||
end
|
||||
y = y + Y_LINE_HEIGHT
|
||||
end
|
||||
|
||||
lcd.drawText (X_COL2_HEADER+X_DATA_LEN/2,0, Title[1], TEXT_SIZE + INVERS + BOLD)
|
||||
lcd.drawText (x_data,0, string.format("%2.2f",Values[1] or 0), TEXT_SIZE + INVERS+ RIGHT)
|
||||
lcd.drawText (x_data+X_DATA_SPACE, 0, uom[1], TEXT_SIZE + INVERS)
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
local function openTelemetryRaw(i2cId)
|
||||
--Init telemetry (Spectrun Telemetry Raw STR)
|
||||
multiBuffer( 0, string.byte('S') )
|
||||
multiBuffer( 1, string.byte('T') )
|
||||
multiBuffer( 2, string.byte('R') )
|
||||
multiBuffer( 3, i2cId ) -- Monitor this teemetry data
|
||||
multiBuffer( 4, 0 ) -- Allow to get Data
|
||||
end
|
||||
|
||||
local function closeTelemetryRaw()
|
||||
multiBuffer(0, 0) -- Destroy the STR header
|
||||
multiBuffer(3, 0) -- Not requesting any Telementry ID
|
||||
end
|
||||
|
||||
local lineText = {nil}
|
||||
local I2C_TEXT_GEN = 0x0C
|
||||
local function drawTextGen(event)
|
||||
if (multiBuffer(0)~=string.byte('S')) then -- First time run???
|
||||
openTelemetryRaw(I2C_TEXT_GEN) -- I2C_ID for TEXT_GEN
|
||||
lineText = {nil}
|
||||
end
|
||||
|
||||
-- Proces TEXT GEN Telementry message
|
||||
if multiBuffer( 4 ) == I2C_TEXT_GEN then -- Specktrum Telemetry ID of data received
|
||||
local instanceNo = multiBuffer( 5 )
|
||||
local lineNo = multiBuffer( 6 )
|
||||
|
||||
local line = ""
|
||||
for i=0,13 do
|
||||
line = line .. string.char(multiBuffer( 7 + i ))
|
||||
end
|
||||
|
||||
multiBuffer( 4, 0 ) -- Clear Semaphore, to notify that we fully process the current message
|
||||
lineText[lineNo]=line
|
||||
end
|
||||
|
||||
lcd.clear()
|
||||
-- Header
|
||||
if (lineText[0]) then
|
||||
lcd.drawText (X_COL1_HEADER,0, " "..lineText[0].." ", TEXT_SIZE + BOLD + INVERS)
|
||||
else
|
||||
lcd.drawText (X_COL1_HEADER,0, "TextGen", TEXT_SIZE+INVERS)
|
||||
end
|
||||
|
||||
-- Menu lines
|
||||
local y = Y_DATA
|
||||
for i=1,8 do
|
||||
if (lineText[i]) then
|
||||
lcd.drawText (X_COL1_HEADER,y, lineText[i], TEXT_SIZE)
|
||||
end
|
||||
y = y + Y_LINE_HEIGHT
|
||||
end
|
||||
|
||||
if event == EVT_VIRTUAL_EXIT then -- Exit?? Clear menu data
|
||||
closeTelemetryRaw()
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local telPage = 1
|
||||
local telPageSelected = 0
|
||||
local pageTitle = {[0]="Main", "AS3X Settings", "SAFE Settings", "ESC Status", "Battery Status","TextGen","Flight Log"}
|
||||
|
||||
local function drawMainScreen(event)
|
||||
lcd.clear()
|
||||
lcd.drawText (X_COL1_HEADER, Y_HEADER, "Main Telemetry (Smart RXs)", TEXT_SIZE + INVERS)
|
||||
|
||||
for iParam=1,#pageTitle do
|
||||
-- highlight selected parameter
|
||||
local attr = (telPage==iParam) and INVERS or 0
|
||||
|
||||
-- set y draw coord
|
||||
local y = (iParam)*Y_LINE_HEIGHT+Y_DATA
|
||||
|
||||
-- labels
|
||||
local x = X_COL1_HEADER
|
||||
local val = pageTitle[iParam]
|
||||
lcd.drawText (x, y, val, attr + TEXT_SIZE)
|
||||
end
|
||||
|
||||
if event == EVT_VIRTUAL_PREV then
|
||||
if (telPage>1) then telPage = telPage - 1 end
|
||||
elseif event == EVT_VIRTUAL_NEXT then
|
||||
if (telPage<#pageTitle) then telPage = telPage + 1 end
|
||||
elseif event == EVT_VIRTUAL_ENTER then
|
||||
telPageSelected = telPage
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local pageDraw = {[0]=drawMainScreen, drawAS3XSettingsP1, drawAS3XSettingsP2, drawESCStatus, drawBATStatus, drawTextGen, drawFlightLogScreen}
|
||||
|
||||
local function run_func(event)
|
||||
if event == nil then
|
||||
error("Cannot be run as a model script!")
|
||||
return 2
|
||||
end
|
||||
|
||||
-- draw specific page
|
||||
pageDraw[telPageSelected](event)
|
||||
|
||||
if event == EVT_VIRTUAL_EXIT then
|
||||
if (telPageSelected==0) then return 1 end -- on Main?? Exit Script
|
||||
telPageSelected = 0 -- any page, return to Main
|
||||
end
|
||||
|
||||
return 0
|
||||
end
|
||||
|
||||
local function init_func()
|
||||
|
||||
if (LCD_W <= 128 or LCD_H <=64) then -- Smaller Screens
|
||||
TEXT_SIZE = SMLSIZE
|
||||
X_COL1_HEADER = 0
|
||||
X_COL1_DATA = 20
|
||||
|
||||
X_COL2_HEADER = 60
|
||||
X_COL2_DATA = 90
|
||||
|
||||
X_DATA_LEN = 28
|
||||
X_DATA_SPACE = 1
|
||||
|
||||
|
||||
Y_LINE_HEIGHT = 8
|
||||
Y_DATA = Y_HEADER + Y_LINE_HEIGHT
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
return { run=run_func, init=init_func }
|